Jump to content

Image compare - get % of difference


Recommended Posts

Can somebody provide me a solution to compare 2 images and then to see how much is the difference between them in %?

I found this:

 

But I cannot make it to work. I put in folder a.jpg and b.jpg but the $compare[0] and $compare[1] is -1.#IND

I use the following script:

;~ #include <_PixelGetColor.au3>
#include <GDIPlus.au3>
#include <inet.au3>
#include <array.au3>
$hDll = DllOpen("gdi32.dll")
_GDIPlus_Startup()

Global $image1, $image2

$f1 = binary("/a.jpg") ;image 1
$f2 = binary("/b.jpg") ;image 2 brighter

Msgbox(0, "", $f1)
Msgbox(0, "", $f2)


;here we use the default step options
$t1 = TimerInit()
$image1 = _Capturepixels($f1) ;get image 1 pixel
_arraydisplay($image1, "fdsfds")


$t1 = TimerInit()
$image2 = _CapturePixels($f2) ;get image 2 pixels
_arraydisplay($image2, "fdsfds")

$timer = TimerInit()
$compare = _datacompare($image1[0], $image2[0]);compare them
ConsoleWrite($compare[0]&'% Different(Localized) '&$compare[1]&'% Different(Global)'&@CRLF&'Took '&(TimerDiff($timer)/1000)&' seconds. Default Step'&@CRLF)
Msgbox(0, "diferenta locala", $compare[0])
Msgbox(0, "diferenta globala", $compare[1])
Msgbox(0, "timp", (TimerDiff($timer)/1000))

;here we double them, notice the preformance increase
$t1 = TimerInit()
$image1 = _Capturepixels($f1, 4, 8) ;get image 1 pixels
ConsoleWrite(TimerDiff($t1)/1000 &' Double Step'&@CRLF)
$t1 = TimerInit()
$image2 = _CapturePixels($f2,4 , 8) ;get image 2 pixels
ConsoleWrite(TimerDiff($t1)/1000& ' Double Step'&@CRLF)
$timer = TimerInit()
$compare = _datacompare($image1[0], $image2[0])
ConsoleWrite($compare[0]&'% Different(Localized) '&$compare[1]&'% Different(Global)'&@CRLF&'Took '&(TimerDiff($timer)/1000)&' seconds. Default Step'&@CRLF)
sleep(5000)


;~ $t1 = TimerInit()
;~ $diffarray = _mapchange($image1[0], $image2[0], $image1[1], $image1[2]) ;compare two images for difference
;~ ConsoleWrite(TimerDiff($t1)/1000& ' _mapchange'&@CRLF)
;~ $t1 = TimerInit()
;~ $image = _toimage($diffarray) ;here we turn the array of colors back into an image
;~ ConsoleWrite(TimerDiff($t1)/1000& ' _toimage'&@CRLF)
;~ _GDIPlus_ImageSaveToFile($image, @scriptdir&'\test.jpg') ;write it to a file
;~ shellexecute(@scriptdir&'\test.jpg')


#cs
Function _datacompare($data1, $data2, [$declimal])
    -$data1: A string of data, any length.
    -$data2: A string of data, must be the same length as $data1
    -$decimal: 1=Binary 9=Base-10, 15=Base-16, 31=Base-32

    Note: If you just want to compare two sets of binary data
    you probably want to use base-16. Unless you are sure your
    binary is in 1's and 0's.

    Returns: An array containing two floats. The first
    value is the localized change, and the second is the global change
#ce
func _datacompare($data1, $data2, $decimal=15)
    Local $difference
$data1 = StringSplit($data1, "")
$data2 = StringSplit($data2, "")
$difference = 0
$found = 0
for $i=1 to $data1[0]
if $data1[$i] <> $data2[$i] Then
    $temp = Abs(_tonum($data1[$i]) - _tonum($data2[$i]))
    $difference += $temp
    $found +=1
EndIf
Next
dim $ret[2]
$ret[0] = ((($difference/$found))/$decimal)*100
$ret[1] = ((($difference/$data1[0]))/$decimal)*100
Return $ret
EndFunc

#cs
Function: _mapchange($base, $new, $x, $y, [$decimal])
    $base: Base data to compare from
    $new: Data to compare
    $x: Width of output data (should be returned by capturepixels)
    $y: Height of outout data (should be returned by capturepixels)
    $decimal: Decimal system, you shouldn't change this

    Note: Use _toimage on data returned by this function to visually see
    a image of the change. (The lighter the color the more change the occured)

    Returns an 2D array of data. Each value of the array represents
    one pixel of the image. Each value is a percent between 0-100
    representing the change that occured in that pixel
#ce
func _mapchange($base, $new, $y, $x, $decimal = 10)
    Local $difference, $xx = 0, $yy = 0
    dim $result[1][$x+1]
    $t1 = TimerInit()
$data1 = _StringequalSplit($base, 8)
$data2 = _StringequalSplit($new, 8)
$difference = 0
for $i=1 to UBound($data1)-1
    if $xx > $x Then
        $xx=0
        $yy+=1
        ConsoleWrite($yy&'/'&$y&' ('&($yy/$y)*100&') '&@CRLF)
        redim $result[$yy+1][$x+1]
    EndIf
    if $data1[$i] <> $data2[$i] Then
    $values1 = StringSplit($data1[$i], "")
    $values2 = stringSplit($data2[$i], "")
    $diff = ""
    for $ix=1 to $values1[0]
    $diff += round((Abs(_tonum($values1[$ix]) - _tonum($values2[$ix]))/$decimal)*100)
    Next
    $diff = Round($diff/$values1[0])
    $result[$yy][$xx] = $diff
    Else
    $result[$yy][$xx] = 0
    EndIf
    $xx += 1
Next
return $result
EndFunc


#cs
Function _tonum($info)
    -$info: A single digit or carachter.

    Returns: A 0-based value.
#ce
func _tonum($info)
if $info+0 > 0 Then Return $info
$info = StringLower($info)
$return = asc($info)-87
switch $return
    Case -39
        Return 0
    Case Else
        Return $return
EndSwitch
EndFunc

#cs
Function _CapturePixels($data, [[$stepy], $stepx])
    -$data: Binary Data
    -$stepy: How often to skip a row of pixelxs. 1 = Never
    -$stepx: How often to skip a single pixel. 1 = Nevere
    Note: Use higher steps for larger images and lower steps
    for smaller images.
#ce
Func _CapturePixels($data, $stepy = 2, $stepx = 2)
    $ret = ""
    $HBITMAP2 = _GDIPlus_BitmapCreateFromMemory($data)
    $y=_GDIPlus_ImageGetWidth($HBITMAP2)
    $x=_GDIPlus_ImageGetHeight($HBITMAP2)

    For $iY = 0 To $x step $stepy
        For $iX = 0 To $y step $stepx
            $rety = StringRight(hex(_GDIPlus_BitmapGetPixel($hBitmap2, $ix, $iy)),8) ;get current pixel color
            $ret &= $rety
;~          ConsoleWrite($iy&'/'&$x&' '&$rety&@CRLF)
            Next
    Next


       ;For $x = 0 To _GDIPlus_ImageGetWidth($HBITMAP2)
       ;  For $y = 0 To _GDIPlus_ImageGetHeight($HBITMAP2)
       ;      $ret &= _PixelGetColor_GetPixel($vDC, $x, $y, $hDll)
      ;   Next
     ;Next
    _WinAPI_DeleteObject($HBITMAP2)
    dim $retx[3]
    $retx[0] = $ret
    $retx[1] = $x/$stepx
    $retx[2] = $y/$stepy
    Return $retx
EndFunc   ;==>Capturepixels

Func _toimage($colors)
    _GDIPlus_Startup()
    Local $hBitmap = _GDIPlus_BitmapCreateFromScan0(UBound($colors, 2), UBound($colors, 1)) ;create an empty bitmap
    Local $hBmpCtxt = _GDIPlus_ImageGetGraphicsContext($hBitmap) ;get the graphics context of the bitmap
    _GDIPlus_GraphicsSetSmoothingMode($hBmpCtxt, $GDIP_SMOOTHINGMODE_HIGHQUALITY)
    _GDIPlus_GraphicsClear($hBmpCtxt, 0x00000000) ;clear bitmap with color white

    for $i=0 to UBound($colors)-1
        for $i2=0 to UBound($colors,2 )-1
;~          if $colors[$i][$i2] > 30 Then
;~          ConsoleWrite($i&","&$i2&' - '&$colors[$i][$i2]&@CRLF)
        _GDIPlus_BitmapSetPixel($hBitmap, $i2, $i, $colors[$i][$i2]&'0')
;~      ConsoleWrite($i2&','&$i&' '&$colors[$i][$i2]&@CRLF)
;~          EndIf
        Next
    Next

    return $hBitmap ;return bitmap
    ;cleanup GDI+ resources
    _GDIPlus_GraphicsDispose($hBmpCtxt)
EndFunc   ;==>Example

Func _StringEqualSplit($sString, $iNumChars)
    If (Not IsString($sString)) Or $sString = "" Then Return SetError(1, 0, 0)
    If (Not IsInt($iNumChars)) Or $iNumChars < 1 Then Return SetError(2, 0, 0)
    Return StringRegExp($sString, "(?s).{1," & $iNumChars & "}", 3)
EndFunc

 

 

 

 

I also found  another script but here I only see what is the difference between 2 image, I dont get the difference in %.

#include <GDIPlus.au3>
#include <GDIPlusConstants.au3>
#include <StructureConstants.au3>
#include <WinAPI.au3>
; quick and dirty....
Global $stride, $ptr, $pixeldata
global $bitmapfile1, $width1, $height1, $stride1, $pbitmap1
global $bitmapfile2, $width2, $height2, $stride2, $pbitmap2
local  $numberdiff  = 0  ;number of differences between the 2 pics


$pic1 = "1.bmp" ;the image....24bit per pixel, could be a JPG
$pic2 = "3.bmp"
$pic3 = "dif.bmp"  ;a bitmapfile with the differences

_GDIPlus_Startup()
$pixelstruct1   = getbmpdata($pic1, $width1, $height1, $stride1, $pbitmap1)  ;get all data from the 2 files
$pixelstruct2   = getbmpdata($pic2, $width2, $height2, $stride2, $pbitmap2)

$lenght         = DllStructGetSize($pixelstruct1) ;get lenght of bitmapdata
$pixelstruct3   = dllstructcreate("ubyte["&$lenght&"]")
;compare
 for $i=1 to $lenght
    ; consolewrite (dllstructgetdata($pixelstruct1,1,$i)&"   "&dllstructgetdata($pixelstruct1,1,$i)&@crlf)
    $diff=dllstructgetdata($pixelstruct1,1,$i)-dllstructgetdata($pixelstruct2,1,$i)  ;difference"colour" between the bytes
    if $diff<>0 Then        ;bytes are different
        $numberdiff+=1      ;count
        dllstructsetdata($pixelstruct3,1,$diff,$i)  ;write the difference into the difference-file, bottom-up isnt funny but we´ll mirror it later :o)
    endif
next


$head=DllStructcreate("ubyte[54]")
;lets create a bitmapfile with the given data
$Bmpheader = DllStructCreate("align 1;char BM[2];uint Size;uint res;uint Offset;uint BMHI;uint Width;uint Height;short Planes;short BPP;uint BIcomp;int SizeImg;uint reshor;uint resver;uint col;uint colused", dllstructgetptr($head)) ;struct of bytes = header of bitmap #1
;fill struct(bitmapheader) with data
DllStructSetData($bmpheader,"BM","BM")
DllStructSetData($bmpheader,"Size",54+$lenght)
DllStructSetData($bmpheader,"Offset",54)
DllStructSetData($bmpheader,"BMHI",40)
DllStructSetData($bmpheader,"Width",$width1)
DllStructSetData($bmpheader,"Height",-$height1)  ;negativ because "bottom up"
DllStructSetData($bmpheader,"Planes",1)
DllStructSetData($bmpheader,"BPP",24)
DllStructSetData($bmpheader,"BIcomp",0)
DllStructSetData($bmpheader,"SizeImg",$lenght)

$header     = dllstructgetdata($head,1) ;headerdata
ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $header = ' & $header & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
$pixeldata  = stringtrimleft(DllStructGetData($pixelstruct3, 1),2) ;pixeldata
$bitmap     = $header&$pixeldata  ;all together is the bitmap-file

$filehandle = FileOpen($pic3, 18) ;write file
FileWrite($filehandle,BinaryToString($bitmap))
FileClose($filehandle)

_GDIPlus_ImageDispose($pBitmap1)  ;not in the function, because ImageDispose destroys the struct
_GDIPlus_ImageDispose($pBitmap2)


;lets have a look what we have done...
GUICreate("Difference pixel",800,500)
GUICtrlCreatePic($pic1, 10, 10, 170, 170 / $width1 * $height1)
GUICtrlCreatePic($pic2, 200, 10, 170, 170 / $width2* $height2)
GUICtrlCreatePic($pic3, 400, 10, 170, 170 / $width2* $height2)
GUISetState()

Do
Until GUIGetMsg() = -3

Func getbmpdata($bmpfile, ByRef $width, ByRef $height, ByRef $stride, Byref $pbitmap) ;returns a struct with the data of the pixel
    $pbitmap = _GDIPlus_BitmapCreateFromFile($bmpfile)
    ;_GDIPlus_BitmapLockBits gibt $tagGDIPBITMAPDATA-Struktur zurück
    $BitmapData = _GDIPlus_BitmapLockBits($pBitmap, 0, 0, _GDIPlus_ImageGetWidth($pBitmap), _GDIPlus_ImageGetHeight($pBitmap), $GDIP_ILMREAD, $GDIP_PXF24RGB)
    If @error Then MsgBox(0, "", "Error locking region " & @error)
    $stride = DllStructGetData($BitmapData, "Stride");Stride - Offset, in bytes, between consecutive scan lines of the bitmap. If the stride is positive, the bitmap is top-down. If the stride is negative, the bitmap is bottom-up.
    $width = DllStructGetData($BitmapData, "Width");Image width - Number of pixels in one scan line of the bitmap.
    $height = DllStructGetData($BitmapData, "Height");Image height - Number of scan lines in the bitmap.
    ;$pixelFormat = DllStructGetData($BitmapData, "PixelFormat");Pixel format - Integer that specifies the pixel format of the bitmap
    $Scan0 = DllStructGetData($BitmapData, "Scan0");Scan0 - Pointer to the first (index 0) scan line of the bitmap.
    $pixeldata = DllStructCreate("ubyte[" & (Abs($stride) * ($height)) & "]", $Scan0)
    $BMPData = DllStructGetData($pixeldata, 1)
    _WinAPI_DeleteObject($pbitmap)
      _GDIPlus_BitmapUnlockBits($pBitmap, $BmpData)
    ;_GDIPlus_ImageDispose($pBitmap) ;destroys the pixeldatastruct, have to be done at end of the script!
    return $pixeldata
EndFunc   ;==>getbmpdata

 

 

Can somebody help me please?

Link to comment
Share on other sites

If you follow the link to the other thread you will see there a function called _GDIPlus_ImageCompare($hImage1, $hImage2, $bFastCmp = True).

If you call that function call it with $bFastCmp = False.

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Link to comment
Share on other sites

@UEZ

 

Sorry but I dont understand.

Do you mean that the code from

will help me to compare 2 pictures and get the difference in % between them??

If not, i repeat that I dont use  _GDIPlus_ImageCompare in my first script.

Link to comment
Share on other sites

Now I understand, but I tried the code comparing bb.jpg and cc.jpg from script directory and the message box is empty.

I did something wrong?

 

#include <GDIPlus.au3>

Global $hImage1 = ("/bb.jpg")
Global $hImage2 = ("/cc.jpg")




MsgBox(0, "fdsfds", _GDIPlus_ImageCompare($hImage1, $hImage2))



Func _GDIPlus_ImageCompare($hImage1, $hImage2, $bFastCmp = False)
    Local Const $iW = _GDIPlus_ImageGetWidth($hImage1), $iH = _GDIPlus_ImageGetHeight($hImage1)
    If ($iW <> _GDIPlus_ImageGetWidth($hImage2)) Then Return SetError(1, 0, 0)
    If ($iH <> _GDIPlus_ImageGetHeight($hImage2)) Then Return SetError(2, 0, 0)
    Local $t = TimerInit()
    Local $tBitmapData1 = _GDIPlus_BitmapLockBits($hImage1, 0, 0, $iW, $iH, $GDIP_ILMREAD, $GDIP_PXF32ARGB)
    Local $tBitmapData2 = _GDIPlus_BitmapLockBits($hImage2, 0, 0, $iW, $iH, $GDIP_ILMREAD, $GDIP_PXF32ARGB)

    Local $iScan1 = DllStructGetData($tBitmapData1, "Scan0")
    Local $tPixel1 = DllStructCreate("int[" & $iW * $iH & "];", $iScan1)
    Local $iStride = Abs(DllStructGetData($tBitmapData1, "Stride"))

    Local $iScan2 = DllStructGetData($tBitmapData2, "Scan0")
    Local $tPixel2 = DllStructCreate("int[" & $iW * $iH & "];", $iScan2)

    If $bFastCmp Then
        $iResult = DllCall("msvcrt.dll", "int:cdecl", "memcmp", "ptr", $iScan1, "ptr", $iScan2, "int", ($iH - 1) * $iStride + ($iW - 1) * 4)[0]
    Else
        Local $iX, $iY, $iRowOffset, $iPixel1, $iPixel2, $aDiff[$iW * $iH + 1][3], $c = 1
        For $iY = 0 To $iH - 1
            $iRowOffset = $iY * $iW + 1
            For $iX = 0 To $iW - 1
                $iPixel1 = DllStructGetData($tPixel1, 1, $iRowOffset + $iX) ;get pixel color
                $iPixel2 = DllStructGetData($tPixel2, 1, $iRowOffset + $iX) ;get pixel color
                If $iPixel1 <> $iPixel2 Then
                    $aDiff[$c][0] = $iX & ", " & $iY
                    $aDiff[$c][1] = "0x" & Hex($iPixel1, 8)
                    $aDiff[$c][2] = "0x" & Hex($iPixel2, 8)
                    $c += 1
                EndIf
            Next
        Next
        $aDiff[0][0] = TimerDiff($t)
        $aDiff[0][1] = $iW
        $aDiff[0][2] = $iH
    EndIf

    _GDIPlus_BitmapUnlockBits($hImage1, $tBitmapData1)
    _GDIPlus_BitmapUnlockBits($hImage2, $tBitmapData2)

    If $bFastCmp Then Return SetError(0, Int(TimerDiff($t)), $iResult = 0)

    ReDim $aDiff[$c][3]
    Return $aDiff
EndFunc

 

Link to comment
Share on other sites

Yes, $hImage1 and $hImage2 must be GDI+ image handles not a path.

Use something like this here:

_GDIPlus_Startup()

Global $hImage1 = _GDIPlus_ImageLoadFromFile("/bb.jpg")
Global $hImage2 = _GDIPlus_ImageLoadFromFile("/cc.jpg")

Check out the correct path to the images!

Edited by UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...