ImageCompare - unklare Abweichungen

  • Allgemein

Es gibt 10 Antworten in diesem Thema. Der letzte Beitrag () ist von vblind.

    ImageCompare - unklare Abweichungen

    Moin zusammen!

    Ich habe mich ein wenig mit Objekterkennung auseinandergesetzt (setzen wollen) und stehe nun vor einem Problem, dass vermutlich eher mathematisch als codetechnisch fehlerbehaftet ist.
    In meinem Test habe ich ein (Video) Videobild von meiner Webcam. Nach Klick auf den Referenz Image Button wird ein Screenshot erstellt und in die PictureBox (Referenz) gespeichert. Klick auf den Abweichungs-Button führt einen Vergleich aus. Die Funktion dafür habe ich dem Board entnommen (auch andere Methoden versucht).
    Das Problem sieht man auf dem Screenshot:



    (Klick aufs Image für Vollbilddarstellung)

    Der erste Screen zeigt die Abweichung von 2 (eigentlich) identischen Bildern. Ich habe versucht die Abweichungen (Helligkeit usw.) so gering wie möglich zu halten. Knapp 26% Abweichung vom Originalbild (viel zu viel!). Das darunterliegende Image zeigt die Rekursion zweier maximal verschiedener Bilder. Dort soll die Abweichung rund 33% betragen.

    Stimmt doch vorne und hinten nicht, dass der prozentuale Unterschied dieser Bilder nur knapp 5% auseinander liegen soll.
    Hat jemand eine Methode die nach Fuzzylogik arbeitet?

    Any ideas?
    Besten Dank

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „vblind“ ()

    Hm, in der Tat ..

    Zum Vergleich:
    Genutzt wird die Bitmap.LockBits-Methode, anschließend werden die RGB-Werte per Marshal.Copy in ein Bytearray kopiert. Dasselbe passiert mit dem zweiten Bitmap und die Arrays werden verglichen. Motiondetection realisieren

    Quellcode

    1. Public Shared Function Compare(ByVal bmp1 As Bitmap, ByVal bmp2 As Bitmap, ByVal faktor As Integer) As FastPixelCompareResult
    2. Dim bmpdata1 As Imaging.BitmapData = bmp1.LockBits(New Rectangle(0, 0, bmp1.Width, bmp1.Height), Imaging.ImageLockMode.ReadOnly, Imaging.PixelFormat.Format24bppRgb)
    3. Dim bmpdata2 As Imaging.BitmapData = bmp2.LockBits(New Rectangle(0, 0, bmp2.Width, bmp2.Height), Imaging.ImageLockMode.ReadOnly, Imaging.PixelFormat.Format24bppRgb)
    4. Dim p1 As IntPtr = bmpdata1.Scan0
    5. Dim p2 As IntPtr = bmpdata2.Scan0
    6. Dim buffer1(bmp1.Height * bmpdata1.Width) As Byte
    7. Dim buffer2(bmp2.Height * bmpdata2.Width) As Byte
    8. System.Runtime.InteropServices.Marshal.Copy(p1, buffer1, 0, buffer1.Length)
    9. System.Runtime.InteropServices.Marshal.Copy(p2, buffer2, 0, buffer2.Length)
    10. bmp1.UnlockBits(bmpdata1)
    11. bmp2.UnlockBits(bmpdata2)
    12. Dim result As New FastPixelCompareResult With {.TotalValuesCompared = buffer1.Length + buffer2.Length}
    13. Dim diff As Int32 = 0
    14. For i As Integer = 0 To If(buffer1.Length > buffer2.Length, buffer2.Length - 1, buffer1.Length - 1)
    15. diff += If(buffer1(i) > buffer2(i) - faktor And buffer1(i) < buffer2(i) + faktor, 0, 1)
    16. Next
    17. result.TotalDifference = diff
    18. Dim pxs As Integer = If(bmp1.Width > bmp2.Width, bmp2.Width, bmp1.Width) * If(bmp1.Height > bmp2.Height, bmp2.Height, bmp1.Height)
    19. result.DifferenceInPercent = (100 / pxs) * (diff / 3)
    20. Return result
    21. End Function

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „vblind“ ()

    Du musst einen Schwellenwert festlegen, ab wann ein Pixel wirklich "verschieden" ist. Außerdem empfiehlt es sich ggf nicht einzelne Pixel zu vergleichen, sondern komplette Bereiche. Evtl sollte man vorher auch die Bildinformationen reduzieren (zb Farben raus) bzw anpassen (Kontrast verstärken, Helligkeit normieren)
    Dank dir für die Antwort!
    Ich habe bereits diverses ausprobiert.
    U.a. habe ich mit ImageMagick (convert.exe) experimentiert, dass Image in verschiedenen Formaten und Auflösungen getestet, sowie die Farbtiefen (32 Bit Truecolor bis runter 8 Bit Monochrome) geändert. Kein wirklicher Unterschied. Zudem möchte ich die Prüfung nachher idealerweise in Echtzeit durchführen. Müsste ich vorher erst konvertieren, speichern, laden usw. wäre dies kaum noch realisierbar.
    Auch habe ich versucht Pixelblöcke von je 10x10 Bildpunkten zusammenzufassen, auch mit mehr oder minder keinem (oder mässigen) Erfolg. Den besagten Schwellenwert würdest du wie/wo definieren (du meinst einen Schwellenwert innerhalb der For-Schleife, oder)? Gibt es da Erfahrungswerte?

    Hast du vielleicht zu deinen Tipps noch irgendeinen Referenzlink oder eine andere Convertroutine in der Tasche mit der ich es versuchen könnte?

    vblind schrieb:

    Genutzt wird die Bitmap.LockBits-Methode, anschließend werden die RGB-Werte per Marshal.Copy in ein Bytearray kopiert
    Nun, schneller geht es nicht wenn man es in VB.NET realisiert, C# ist geringfügig schneller, C++ um einges mehr.

    Eine Möglichkeit für einen Schwellenwert wären die Abweichungen in den Farbwerten, eine Art Varianz. Hier ein Beispiel rauskopiert aus einem meiner Sourcen:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. '------------------------------------------
    2. '-- createRGBVariation ---
    3. '------------------------------------------
    4. Private Sub createRGBVariation(ByVal nColor As Integer, ByRef rgb As rgbQuad, ByRef rgbLow As rgbQuad, ByRef rgbHigh As rgbQuad, ByVal nVar As Integer)
    5. ' split search colour (RBG) into components
    6. rgb.alpha = CByte((nColor >> 24) And 255)
    7. rgb.red = CByte((nColor >> 16) And 255)
    8. rgb.green = CByte((nColor >> 8) And 255)
    9. rgb.blue = CByte(nColor And 255)
    10. ' special case nVar=0
    11. If nVar = 0 Then rgbLow = rgb : rgbHigh = rgb : Return
    12. ' variation boundaries
    13. If (nVar > rgb.red) Then rgbLow.red = 0 Else rgbLow.red = CByte(rgb.red - nVar)
    14. If (nVar + rgb.red > 255) Then rgbHigh.red = 255 Else rgbHigh.red = CByte(nVar + rgb.red)
    15. If (nVar > rgb.green) Then rgbLow.green = 0 Else rgbLow.green = CByte(rgb.green - nVar)
    16. If (nVar + rgb.green > 255) Then rgbHigh.green = 255 Else rgbHigh.green = CByte(nVar + rgb.green)
    17. If (nVar > rgb.blue) Then rgbLow.blue = 0 Else rgbLow.blue = CByte(rgb.blue - nVar)
    18. If (nVar + rgb.blue > 255) Then rgbHigh.blue = 255 Else rgbHigh.blue = CByte(nVar + rgb.blue)
    19. End Sub


    Das definiert aber nur die Ähnlichkeit der Bilder ohne MotionCompensation.
    Ah, fein! Danke damit werde ich es mal versuchen.
    Kannst du mir ein paar empirische Werte empfehlen? Gibts da irgendwelchen brauchbaren Schwellenwerte?
    Wie genau müsste das optimierte Ergebnis sein? Wie fein kann ich Bildabstufungen erkennen/tracken?

    vblind schrieb:

    Gibts da irgendwelchen brauchbaren Schwellenwerte?

    Das kommt auf die Aufnahmen Deiner Webcam an, ich weiss nicht wie gross die Abweichungen bei den verschiedenen Aufnahmen liegen: das musst Du wohl leider selber rausfinden. Wie gesagt berücksichtigt dieser Schwellenwert nur Abweichungen in den Farbwerten, es wird davon ausgegangen dass die Bilder sonst in den Ausschnitten identisch sind.

    Die "Varianz" (nicht identisch mit der Definition aus der Statistik) besagt nur, dass die die Rot / Grün/ Blau Werte eines Pixels um jeweils den gleichen maximalen Wert X abweichen dürfen. Alpha wurde nicht berücksichtigt, geht aber genauso.

    Performance ist dafür aber sehr gut, wenn man über das Byte-Array iteriert.

    Edit: picoflop's Link sieht ausgesprochen gut aus, werde ich bei Gelegenheit ausprobieren
    Besten Dank soweit.. ich hab jetzt ja erstmal allerhand mit dem ich basteln kann!
    Die AForge.NET Framworksache sieht wirklich nett aus, vielleicht fange ich einfach nochmal neu an und versuche es damit.
    Zusammengefasst meint ihr also schon, dass man sich aus den Routinen eine brauchbare Erkennungsrate basteln kann?

    offtopic: Btw. wenn die erste Hürde genommen ist, gehts ans eingemachte. Ich möchte am Ende ja Objektverfolgung/Tracking damit durchführen. Bei der o.g. Funktion wird ja letztlich nur eine Differenz erreichnet. Ich kann also im besten Fall nur sagen ob es eine Bildbewegung gegeben hat. Wenn ich das Objekt aber nun verfolgen möchte? Habt ihr einen Infolink in dem es speziell um die Verfolgung (Objektfixierung) geht?

    edit: Der Wahnsinn:



    Bleibt ansich nur noch die Frage, warum ich mir vorher ein abgewürgt habe.. :P
    Ich danke Euch!

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „vblind“ ()

    @ picoflop
    Jetzt muss ich doch mal anmerken, dass ich schon ein paar Jahre aus der Uni raus bin.. aber extra nochmal in den Tiefen des Dungeons (auch: Keller) gebuddelt und mein altes typensp. Formelbuch gesucht habe:

    Rekursive Definitionen eignen sich dazu, den Wert einer mathematischen Funktion auf den Wert derselben Funktion an einer kleineren Stelle zurückzuführen.
    Dann klär mich doch mal auf, was an einem Bildvergleich mit fester Vergleichsvariablen und Selbstaufruf nicht rekursiv sein sollte?
    Da es keine Schleife ist, ging ich von nicht-iterativ aus.. ergo rekursiv > Rekursion ^^

    Wie auch immer.. die Logik hab ich vll. im Hörsaar gelassen und will hier gerade Hirnschmalz verkaufen, aber es nagt an mir :huh:

    edit: Ok, geschenkt. Du hast recht.. die Einsicht kam spät ^^ Die obere Funktion ist rein Array/Schleife > iterativ..
    Dennoch benutze ich eine Rekursion (Füllroutine). Sagen wir unentschieden ^^

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „vblind“ ()