_GDIPlus_ImageCalcDif

  • Moin,

    Die folgende Funktion ermittelt den Unterschied zwischen 2 Bildern oder Bildausschnitten.
    Es wird Pixelweise vorgegangen und jweils Abs(R1 - R2) + Abs(G1 - G2) + ... = Dif für jeden Pixel berechnet und aufaddiert. Anschließend wird noch durch die Anzahl Pixel geteilt um eine "Abweichung pro Pixel" herauszubekommen.

    Aus der Methode folgt:
    - Minimalabweichung ist 0 (Beide Bilder sind absolut identisch)
    - Maximalabweichung ist 255 * 3 = 765 (Jeder Pixel von Bild1 ist Schwarz, wenn er bei Bild2 weiß ist, und umgekehrt. Gilt auch für z.B. ein SWSWSW Muster bei Bild1 und ein WSWSWS Muster bei Bild2)
    - Es können nur Bilder bzw Bildausschnitte gleicher Größe verglichen werden.

    Ich weiß nicht ob das irgendwer gebrauchen kann, aber hier ist es :)

    Anhang enthält:
    - Skript mit Funktion sowie Testskript
    - 2 Bilder die ich aus Google geklaut habe

    Edit 02.11.2025:
    AutoIt 3.3.18.0 hat irgendwas an der Calling Convention für DllCallAddress geändert. Void als Returntype wird wohl nicht mehr supported. Daher gibts hier ein Update das "mit der 3.3.18.0" funktioniert (bei mir jedenfalls).

    lg
    M

  • Einwandfrei! :thumbup:
    Daraus könnte man bestimmt ein feines "Finde doppelte Bilder"-Programm/Script basteln 8o

  • Und ich hatte schon Angst vor deinem Kommentar, weil ich kein SSE benutzt habe

    DAS hebe ich mir für später auf! 8o

    Egal, hauptsache es funktioniert! :thumbup:
    Obwohl SSE gerade bei den 4x32Bit (oder besser 16x8Bit) -Befehlen vieles an Arbeit sparen würde! Du könntest 4 Pixel laden, und mit einem Befehl 16 Bytes bearbeiten.
    Da lob ich mir den "neuen" AssembleIt-Debugger, der stellt die Registerinhalte sehr schön dar.

  • Gibts eigentlich sowas wie paddb auch für 32Bit Register ? (damit könnte man einen kompletten Pixel parallel bearbeiten und könnte sich die shifts und subs schenken).
    Es wäre mir lieber, wenn man "abstrakt" folgendes: SUMABS(Pixel1 - Pixel2) anstatt die 8 Byte Brocken einzeln abzufertigen...

  • Ich empfehle für SSE das hier: http://lars.nocrew.org/computers/processors/x86-64/26568.pdf

    "Richtig" in einem PDF-Viewer angezeigt, sucht man links die Befehle durch, welche mit Erklärung und DARSTELLUNG ALS BILD (wieso bekommt INTEL so etwas nicht hin?) rechts dargestellt werden!Zwischenablage01.jpg

    Der ASM-Code in Scite läuft automatisch mit dem Debugger mit, d.h. Scite springt zum nächsten _asmdbg_(), sobald der "Next"-Button im Debuggerfenster angeklickt wird.

  • Nachdem ich aus diesem Forum schon manche hilfreiche Anregung bezogen habe, bin ich nun mit meinem Latein am Ende und habe mich angemeldet, um eine Frage loszuwerden, auf die ich alleine beim besten Willen keine Antwort finde. Und ich hoffe mal, dass es trotz des Alters der letzten Antwort in diesem Thread sinnvoll ist, kein neues Thema zu erstellen.

    Also: Vor ein paar Jahren, noch unter Windows 7, habe ich mal ausgiebig mit der UDF '_GDIPlus_ImageCalcDif.au3' herumgespielt und fand die Funktion famos schnell. Das damals begonnene Projekt, die Ähnlichkeit aneinandergrenzender Bildkacheln zu testen, wollte ich jetzt, unter Windows 11, mal wieder aufgreifen. Leider scheint die Funktion nun aber kein sinnvolles Ergebnis mehr zu liefern - oder ich habe ein mächtiges Brett vor dem Kopf (ist natürlich auch schon vorgekommen).

    Wenn ich unter Autoit 3.3.16.1 die mit der UDF mitgelieferte Datei 'Test.au3' unverändert ausführe, bekomme ich folgende Werte für $fDif:

    Beispiel 1: 163.63

    Beispiel 2: 660.27

    Ersetze ich die mit der UDF mitgelieferte Datei '2.png' durch eine Kopie von '1.png', so dass beide Bilder absolut identisch sind, bekomme ich folgende Werte für $fDif:

    Beispiel 1: 18.02 (sollte doch '0' sein)

    Beispiel 2: 1

    Ersetze ich '1.png' und '2.png' durch Kopien eines vollständig mit Schwarz gefüllten png-Bildes von 512 x 512 Pixeln erhalte ich:

    Beispiel 1: 23.75

    Beispiel 2: 622.6

    So wie ich es verstehe, sollte der Abweichungswert im letztgenannten Fall beide Male Null sein, da die Bilder identisch sind und sich auch die verglichenen Bereiche nicht unterscheiden.

    Bin etwas ratlos und hoffe inständig, dass ich nicht fürchterlich auf dem Schlauch stehe und etwas übersehe, das ganz offensichtlich ist.

  • Hast Du schon mal die Bildgröße der Kopien kontrolliert. Kopie auf Systemebene oder aus Bildbearbeitung?

    By

    Peter

    Hinweise auf Suchmaschinen finde ich überflüssig - wer fragt hat es nicht gefunden oder nicht verstanden. Die Antwort gibt sich oftmals schneller als der Hinweis auf Dr. Goggle & Co.

    Ab 19-10-22 ergänzt um:

    Die Welt wird nicht bedroht von den Menschen, die böse sind, sondern von denen, die das Böse zulassen. (Frei nach Albert Einstein)

  • Moin Zusammen,

    das Ergebnis "0" erhält man nicht einmal, wenn man zwei Mal dieselbe PNG-Datei lädt.

    Das Ergebnis "1" kommt aus SetError(1), bei mir bei der Prüfung ob die Abweichung größer als "765" ist.

    Was da nicht stimmt, kann ich nicht sagen, weil ich den Assembler-Teil nicht prüfen kann.

    Bei mir läuft AutoIt 3.3.18.0 (32 Bit) auf Win 11 (64-Bit).

  • Das beruhigt mich etwas, daher hier nur zur Ergänzung:
    die Kopien habe ich auf Systemebene erstellt. D. h., Original und Kopie sind bitgenau gleich, was ich vorsorglich auch überprüft habe. Überdies habe ich bei den komplett mit RGB 0-0-0 gefüllten PNG-Dateien auch noch die Farben zählen lassen, das Ergebnis war '1'.
    Für mein drittes Beispiel habe ich beide im UDF-Paket enthaltenen Dateien ('1.png' und '2.png') durch die komplett einfarbig schwarze PNG-Datei mit 512 x 512 Pixeln ersetzt. Die dann bei der Ausführung von 'Test.au3' entstehenden Dateien 'Ausschnitt1.png' und 'Ausschnitt2.png' von jeweils 100 x 100 Pixeln sind im meinem dritten Beispiel daher auch wieder bitgenau gleich.

  • wenn es nicht auf Geschwindigkeit ankommt dann geht das auch rein mit GDI+

    MfG Schnuffel

    "Sarkasmus ist die niedrigste Form des Witzes, aber die höchste Form der Intelligenz."
    Val McDermid

    über mich...

    ich habe meine Erfahrungen hauptsächlich gesammelt in (grobe Übersicht):

    - RibbonBar Automation
    - MySQL Nutzung
    - GUIs in vielerlei Ausprägung
    - Nutzung von Powershell / Batch in AutoIt
    - Windows Automatisierung

    außerhalb von AutoIt:

    - Sprachen: PS, Batch, php, html(5), javascript, (perl eingeschränkt), vbs
    - Powershell (AD, WPF inkl. Multi-Threading, ...)
    - Deployment-Automatisierung ohne SCCM
    - Office-Nutzung mit COM-Object (AutoIt, PowerShell)
    - ActiveDirectory und alles was damit zusammenhängt
    - Hyper-V Clustering (Converged / Hyper Converged)
    - Serverhardware (Konfiguration, Aufbau, Architektur, Betrieb)

    Lieblingsthema:

    günstige Automatisierung von Vorgängen, für die andere Firmen viel Geld nehmen

    more to come ...

  • Moin,

    bei mir bekomme ich folgendes, wenn ich die mitgelieferten Daten verwende:
    Die verglichenen Bilder haben eine Differenz von 145.62 Farbtönen pro Pixel.
    Die verglichenen Bildstellen haben eine Differenz von 37.67 Farbtönen pro Pixel.

    wenn ich 2 identische Bilder reinstecke (also z.B. 1.png durch eine Kopie von 2.png ersetze) bekomme ich:
    Die verglichenen Bilder haben eine Differenz von 0 Farbtönen pro Pixel.
    Die verglichenen Bildstellen haben eine Differenz von 62.63 Farbtönen pro Pixel.

    Was genau der Erwartung entspricht. AutoIt 3.3.16.1, 32Bit

    Ich vermute, dass du die 64Bit Version verwendest und der ASM Code ist für 32Bit zusammengesetzt worden

    Edit zur Version von Schnuffel:
    Die (u)Int32 Zahlen einfach so voneinander abzuziehen und nicht in ARGB zu zerlegen ist sehr mutig :D

    Edit2: Könnt ihr die betreffenden Beispielbilder hochladen? Ich kann das Problem bei mir nicht reproduzieren...

    Edit3: OOOOOOH. Tatsächlich. Mit AutoIt 3.3.18.0 (habe mal eben geupdated) sind die Ergebnisse komplett für die Tonne...

    Identische Bilder ergeben bei mir:
    Die verglichenen Bilder haben eine Differenz von 21.05 Farbtönen pro Pixel.
    Die verglichenen Bildstellen haben eine Differenz von 1 Farbtönen pro Pixel.
    Noch schlimmer ist, dass es nicht deterministisch ist was vermuten lässt dass irgendwo nicht initialisierter oder out of bounds speicher gelesen wird.

    Edit 4: Hier ist ein "Fix" der aber nicht das eigentliche Problem löst. Analog zu Schnuffel kann man es auch problemlos ohne ASM machen. Dann wird es aber ziemlich langsam...


    lg
    Mars

  • getreu dem Motto: "Mut zur Lücke" :rofl:

    MfG Schnuffel

    "Sarkasmus ist die niedrigste Form des Witzes, aber die höchste Form der Intelligenz."
    Val McDermid

    über mich...

    ich habe meine Erfahrungen hauptsächlich gesammelt in (grobe Übersicht):

    - RibbonBar Automation
    - MySQL Nutzung
    - GUIs in vielerlei Ausprägung
    - Nutzung von Powershell / Batch in AutoIt
    - Windows Automatisierung

    außerhalb von AutoIt:

    - Sprachen: PS, Batch, php, html(5), javascript, (perl eingeschränkt), vbs
    - Powershell (AD, WPF inkl. Multi-Threading, ...)
    - Deployment-Automatisierung ohne SCCM
    - Office-Nutzung mit COM-Object (AutoIt, PowerShell)
    - ActiveDirectory und alles was damit zusammenhängt
    - Hyper-V Clustering (Converged / Hyper Converged)
    - Serverhardware (Konfiguration, Aufbau, Architektur, Betrieb)

    Lieblingsthema:

    günstige Automatisierung von Vorgängen, für die andere Firmen viel Geld nehmen

    more to come ...

  • Da wurde in der 3.3.18.0 wieder irgendwas im Hintergrund an der Calling Convention geändert (nice... Ich dachte immer Konventionen wären da um sie nicht zu ändern. Das sind bestimmt diese Optimierungen :D). Sowas ähnliches ist schonmal passiert (vor >10 Jahren) wo plötzlich sämtlicher ASM Code nicht mehr gelaufen ist...

    Naja, jedenfalls kann man offensichtlich nicht mehr
    DllCallAddress('none', $pOP_ImageCalcDif, 'ptr', $v1.PTR, 'ptr', $v2.PTR, 'ptr', DllStructGetPtr($vDIFF))
    schreiben, weil "none" als Returnwert wohl irgendwo hintenrum undefined behavior verursacht.

    Der "wahre" fix ist also folgendes:
    DllCallAddress('int', $pOP_ImageCalcDif, 'ptr', $v1.PTR, 'ptr', $v2.PTR, 'ptr', DllStructGetPtr($vDIFF))
    wobei man eax einfach ignoriert, weil man den Returnwert ja nicht braucht.

    Tja, da gibts wohl keine Funktionen mit "void" Returnwert mehr. Kamma nix machen.
    Ich lad das mal als "fix" hoch und schreibe 3.3.18.0+ als Version dran. In der Annahme, dass nicht nochmal irgendwas an Stellen gedreht wird an denen man niemals nie nicht überhaupt gar nicht drehen sollte.

    lg
    Mars

  • ich vermute dahinter: 3.3.18.0 (September 07, 2025) (Release)

    ScriptBreaking change:

    Added #3891: DllCall() performance optimisation.

    MfG Schnuffel

    "Sarkasmus ist die niedrigste Form des Witzes, aber die höchste Form der Intelligenz."
    Val McDermid

    über mich...

    ich habe meine Erfahrungen hauptsächlich gesammelt in (grobe Übersicht):

    - RibbonBar Automation
    - MySQL Nutzung
    - GUIs in vielerlei Ausprägung
    - Nutzung von Powershell / Batch in AutoIt
    - Windows Automatisierung

    außerhalb von AutoIt:

    - Sprachen: PS, Batch, php, html(5), javascript, (perl eingeschränkt), vbs
    - Powershell (AD, WPF inkl. Multi-Threading, ...)
    - Deployment-Automatisierung ohne SCCM
    - Office-Nutzung mit COM-Object (AutoIt, PowerShell)
    - ActiveDirectory und alles was damit zusammenhängt
    - Hyper-V Clustering (Converged / Hyper Converged)
    - Serverhardware (Konfiguration, Aufbau, Architektur, Betrieb)

    Lieblingsthema:

    günstige Automatisierung von Vorgängen, für die andere Firmen viel Geld nehmen

    more to come ...

  • ich vermute dahinter: 3.3.18.0 (September 07, 2025) (Release)

    ScriptBreaking change:

    Added #3891: DllCall() performance optimisation.

    Bleibt die Frage warum eine Performance Optimierung "script breaking" ist. Im changelog steht auch nicht "script breaking", außer ich übersehe da etwas...

  • Grandios! "Script-Breaking" hinschreiben aber sich zum Inhalt komplett ausschweigen. "Internal optimisation" und fertig.

    Kein Mensch kann damit abschätzen in welchen Fällen es knallen wird. Sorry aber das ist wirklich wirklich unterirdisch unprofessionell.

    Edit: Ich rudere Mal ein Stück verbal zurück, da ich in dem Zusammenhang auch nichts von Script Breaking lese bislang.

  • Moin, sorry, ich war wohl noch schläfrig. Das war Unsinn!

    Spoiler anzeigen

    Tja, da gibts wohl keine Funktionen mit "void" Returnwert mehr. Kamma nix machen.

    Das müsste man noch mal intensiv testen. Fakt ist, dass Dein DllCall einen Floatingpoint-Wert zurückgeben soll, und das ist eben nicht "NONE".

    Zitat
    NONEno value (only valid for return type - equivalent to void in C)
    Zitat

    void (C++) | Microsoft Learn

    When used as a function return type, the void keyword specifies that the function doesn't return a value.

    Man könnte deshalb auch meinen, dass Du ursprünglich einen falschen Return-Typ gewählt hast. Wie die returnierten Daten entstehen, bleibt dennoch ein Rätsel.

    Einmal editiert, zuletzt von Velted (3. November 2025 um 10:33)

  • Hallo,
    auch ohne die hier erörterten Details der Programmierung, die jenseits meines Horizontes liegen, ist die Sache für mich nur noch rätselhafter geworden:
    Ich habe nämlich unter Windows 11 durchaus die 32-Bit-Version von Autoit 3.3.16.1 verwendet. Um meinen Test aus Post #7 problemlos wiederholen zu können, habe ich nun die Datei 'Test.au3' aus dem UDF-Paket etwas modifiziert: Statt der Konsolen-Ausgabe erfolgt die Ausgabe der Ähnlichkeitswerte ($fDif) in Messageboxen und der Test wird dreimal nacheinander mit unterschiedlichen Varianten ausgeführt (Originaldateien, Datei 2 ist eine Kopie von Originaldatei 1, beide Dateien sind Kopien von Black_512.png).
    Für den Fall, dass es jemand ausprobieren möchte, habe ich die geänderte 'Test.au3' und die Datei 'Black_512.png' hier als 'ImageDiffMod.zip' hochgeladen. Man muss dann nur die beiden im Zip enthaltenen Dateien in das Verzeichnis kopieren, in dem sich die entpackte '_GDIPlus_ImageCalcDif.au3' befindet und kann den Test aus Post #7 wiederholen. ImageDiffMod.zip

    Um sicherzugehen, dass die 32-Bit-Version von Autoit verwendet wird, habe ich die modifierte 'Test.au3' aus dem Skriptverzeichnis heraus wie folgt aufgerufen:
    "C:\Program Files (x86)\AutoIt3\AutoIt3.exe" Test.au3
    Dabei erhalte ich die gleichen Ergebnisse wie in Post #7 und zwar unter Win 11 auf einem AMD Ryzen 5700 G.
    Da Mars jedoch (Post #12) unter AutoIt 3.3.16.1, 32Bit und vermutlich ebenfalls auf einem 64-Bit-System mit der alten UDF die von ihm erwarteten Ergebnisse erzielt hat, habe ich den Test noch auf meinem Audio-PC (Win 10-64, Intel Pentium N5000) unter Autoit 3.3.16.1 durchgeführt und wieder die Ergebnisse wie in Post #7 erhalten. Das gilt auch für die Konsolenausgabe mit der Original-'Test.au3'. Ich kann mir kaum vorstellen, dass diese beiden klaglos funktionierenden PCs irgendeine Eigentümlichkeit aufweisen, die zu falschen Ergebnissen führt (und ja, Virenscan ohne Befund, "sfc /scannow" findet keine korrupten Dateien). Auf jeden Fall wäre es schön, wenn noch ein paar Leute mehr den Test durchführen könnten.

    Zu guter Letzt habe ich noch die portable Version von Autoit 3.3.18.0 heruntergeladen und den Test damit und mit der für Autoit 3.3.18.0 angepassten '_GDIPlus_ImageCalcDif.au3' gemacht:
    D:\Temp\Autoit18\AutoIt3.exe Test.au3
    Hier gibt es folgende Ergebnisse:
    Runde 1: 158.51 , 483.32
    Runde 2: 12.9 , 663.52
    Runde 3: 17 , 445,65
    Auch hier kein Unterschied zum Win 10-Rechner.
    Ach ja, mit den Befehlszeilen
    "C:\Program Files (x86)\AutoIt3\AutoIt3_x64.exe" Test.au3 (Autoit 3.3.16.1, alte UDF)
    D:\Temp\Autoit18\AutoIt3_x64.exe Test.au3 (Autoit 3.3.18.0, neue UDF)
    bekomme ich nicht einmal die Message-Boxen angezeigt.
    Bin ratlos :/.

    Gruß
    Reinhard

  • Moin Reinhard,

    hast Du mit der neuen Version der Funktion (Zeile 5) aus _GDIPlus_ImageCalcDif_3.3.18.0.zip getestet?

    Code
    Func __I2D_BufferCalcDif($v1, $v2) ; Rocket Science
    	Local $iPX = $v1.WIDTH * $v1.HEIGHT
    	Local $vDIFF = DllStructCreate('int')
    	DllStructSetData($vDIFF, 1, $iPX)
    	DllCallAddress('int', $pOP_ImageCalcDif, 'ptr', $v1.PTR, 'ptr', $v2.PTR, 'ptr', DllStructGetPtr($vDIFF)) ; <<<<<<<<<<<<<<<
    ;~ 	_ASM_Call($iOP_ImageCalcDif, $v1.PTR, $v2.PTR, DllStructGetPtr($vDIFF))
    	Local $nDif = DllStructGetData($vDIFF, 1) / $iPX
    	Return ($nDif > 765 Or $nDif < 0) ? SetError(1) : $nDif
    EndFunc

    Und, wenn Du versuchst, mit 64-Bit AutoIt 32-BIT Maschinencode (Assembler) auszuführen, wäre es sehr sehr zufällig, wenn das nicht abstürzt.