Jump to content

bitmap array


Recommended Posts

i dont know what you want to do, but writing "pixel" into an array to compare 2 Pic´s to get the difference is one of the slowest things ever....

A much faster way to compare two Bitmaps is shown  here (Pictures needed are in the first post of the thread)

A very fast way to compare is using _WinApi_BitBlt(). The Example shows the result of blitting two pics with the several $iROP-Parameter

#include <GDIPlus.au3>
#include <WinAPI.au3>
#include <WindowsConstants.au3>
#include <StructureConstants.au3>
#include <GDIConstants.au3>
;#include <Misc.au3>
_GDIPlus_Startup() ;no manipulating with gdi+ in this script, but it´s easy to load files other than bmp...

$picfile1 = "earth1.jpg" ;get them from here http://www.autoitscript.com/forum/index.php?showtopic=106815&view=findpost&p=753759
$picfile2 = "earth2.jpg"

$hgui = GUICreate("Example for comparing 2 pic´s with _winapi_bitblt()", 500, 200) ;create a gui
$lsource1 = GUICtrlCreateLabel($picfile1, 10, 35, 100, 30) ; some labels and a button...
$lsource2 = GUICtrlCreateLabel($picfile2, 150, 35, 100, 30)
$lresult = GUICtrlCreateLabel("Result", 350, 35, 200, 30)
$lblittingtime = GUICtrlCreateLabel("Blitting", 10, 165, 300, 30)
$lmethod = GUICtrlCreateLabel("Combine the two pics with iROP-Method #", 10, 10, 250, 20)
$button = GUICtrlCreateButton("Next iROP", 350, 5, 100) ;button to choose the next method to combine 2 pics

;$hGUI1 = GUICreate("DESTINATION", 100, 100, 0, 0)  ;we could save the destination into an other window or into a file
;$pic1=GUICtrlCreatePic($picfile1,10,60,200,200)   ;we dont need that, we could "blit" the pics into the window....
;$pic2=GUICtrlCreatePic($picfile2,250,60,200,200)

$hdc_gui = _WinAPI_GetDC($hgui) ;device context of the window
GUISetState(@SW_SHOW, $hgui)

;get a DeviceContext from the bitmap-file, if alphachannel is not needed, 24Bit saves 25% ram and is faster when searching or manipulating pixels^^
Local $pointer1, $pointer2 ;no need for them in this script, but the variables are used ByRef
$hdc_pic1 = _getdcfromfile32($picfile1, $pointer1) ;pointer is the pointer to the bitmapdata, if you want to manipulate pixels
$hdc_pic2 = _getdcfromfile32($picfile2, $pointer2) ;pointer is the pointer to the bitmapdata, if you want to manipulate pixels

_WinAPI_BitBlt($hdc_gui, 10, 60, 100, 100, $hdc_pic1, 0, 0, $SRCCOPY) ;"copy" the pic into the gui, remember, we don´t need the gui to manipulate the pics
_WinAPI_BitBlt($hdc_gui, 150, 60, 100, 100, $hdc_pic2, 0, 0, $SRCCOPY)

;because we don´t want to destroy the pics (overwrite), we "paint" into a Buffer, so we have to create a new bitmap
Local $pointer_buffer ;we dont need this variable in this script, pointer to the pixeldata ;this variable is used ByRef
Local $hbmp_buffer ;no need to do something with gdi+ , but this variable is used ByRef
Local $iwidth_buffer = 100 ;size of the buffer, we need width and height of the pics, but i am lazy...
Local $iheight_buffer = 100 ;...could get them with _GDIPlus_ImageGetWidth()....but lazyness^^
$hdc_buffer = _CreateNewBmp32($iwidth_buffer, $iheight_buffer, $pointer_buffer, $hbmp_buffer) ;returns all what you need, a DC, a pointer to the 32Bit-"pixels", and a handle to use with gdi+

Dim $iRop[20] ;see the helpfile for _winapi_bitblt
$iRop[0] = $BLACKNESS ;- Füllt das Ziel-Rechteck mit der Farbe, die mit dem Paletten-Index 0 verknüpft ist
$iRop[1] = $CAPTUREBLT ;- Inkludiert jegliche Fenster, die das eigene Fenster überlagern in das resultierende Bild
$iRop[2] = $DSTINVERT ;- Invertiert die Farben des Ziel-Rechtecks (umkehren)
$iRop[3] = $MERGECOPY ;- Mischt die Farben des Quell-Rechtecks mit dem in hDest aktuell gewähltem Füllmuster (Brush), unterVerwendung des AND Operators.
$iRop[4] = $MERGEPAINT ;- Mischt die invertierten Farben des Quell-Rechtecks mit den Farben des Ziel-Rechtecks unter Verwendung des OR Operators.
$iRop[5] = $NOMIRRORBITMAP ;- Verhindert das spiegeln der Bitmap
$iRop[6] = $NOTSRCCOPY ;- Kopiert das invertierte Quell-Rechteck ins Ziel-Rechteck
$iRop[7] = $NOTSRCERASE ;- Kombiniert die Farben des Quell- und Ziel-Rechtecks unter Verwendung des OR Operators undinvertiert dann die daraus resultierenden Farben.
$iRop[8] = $PATCOPY ;- Kopiert das in hdcDest gewählte Füllmuster in die Ziel-Bitmap
$iRop[9] = $PATINVERT ;- Kombiniert die Farben des Quell-Rechtecks mit dem in hDest aktuell gewähltem Füllmuster, mit den Farben desZiel-Rechtecks unter Verwendung des XOR Operators.
$iRop[10] = $PATPAINT ;- Kombiniert die Farben des in hDest aktuell gewähltem Füllmusters, mit den Farben desinvertiertem Quell-Rechtecks unter Verwendung des OR Operators. Das Resultat dieser Operation wird wiederum mit den Farbendes Ziel-Rechtecks kombiniert, unter Verwendung des OR Operators.
$iRop[11] = $SRCAND ;- Kombiniert die Farben des Quell- und Ziel-Rechtecks unter Verwendung des AND Operators
$iRop[12] = $SRCCOPY ;- Kopiert das Quell-Rechteck direkt ins Ziel-Rechteck
$iRop[13] = $SRCERASE ;- Kombiniert die invertierten Farben des Ziel-Rechtecks mit den Farben des Quell-Rechtecks unter Verwendung des AND Operators.
$iRop[14] = $SRCINVERT ;- Kombiniert die Farben des Quell- und Ziel-Rechtecks unter Verwendung des XOR Operators
$iRop[15] = $SRCPAINT ;- Kombiniert die Farben des Quell- und Ziel-Rechtecks unter Verwendung des OR Operators
$iRop[16] = $WHITENESS ;- Füllt das Ziel-Rechteck mit der Farbe, die mit dem Index 1 in der PhysikalischenPalette verknüpft ist.

While 1
    For $i = 0 To 16 ;from the first iROP to the last
        _WinAPI_BitBlt($hdc_gui, 10, 60, 100, 100, $hdc_pic1, 0, 0, $SRCCOPY) ;"copy" the pic into the gui,
        _WinAPI_BitBlt($hdc_gui, 150, 60, 100, 100, $hdc_pic2, 0, 0, $SRCCOPY) ;someone could move the window or minimize it

        GUICtrlSetData($lmethod, "Combine the two pics with iROP-Method #" & $i) ;set label
        $t = TimerInit() ;save timestamp
        ;we want to combine the two pics with each of the $iROP-methods
        _WinAPI_BitBlt($hdc_buffer, 0, 0, 200, 200, $hdc_pic1, 0, 0, $SRCCOPY) ;copy the pic1 into the buffer
        _WinAPI_BitBlt($hdc_buffer, 0, 0, 200, 200, $hdc_pic2, 0, 0, $iRop[$i]) ;use a method to combine pic1 with pic2
        ;at this time, "comparing" is done! Because we have all the data, i.e. pointer to the "pixeldata" we could count different pixels (because they are not black) or something else
        ;blitting is done awsome fast(depending on CPU and bus), lets see how fast it is..
        $m = TimerDiff($t)
        GUICtrlSetData($lblittingtime, StringFormat("Time to blt the two pics: %.4f milliseconds", $m)) ;set label
        _WinAPI_BitBlt($hdc_gui, 350, 60, 100, 100, $hdc_buffer, 0, 0, $SRCCOPY) ;copies the buffer into the window to show what we have done

        Do ;exit or button pressed?
            $msg = GUIGetMsg()
            If $msg = -3 Then _Exit() ;end of program
        Until $msg = $button ;if button pressed, move on...
    Next
WEnd

Func _exit()
    _DeleteBitmap32($hdc_pic1, $pointer1, 0)
    _DeleteBitmap32($hdc_pic2, $pointer2, 0)
    _DeleteBitmap32($hdc_buffer, $pointer_buffer, $hbmp_buffer)
    _GDIPlus_Shutdown()
    Exit
EndFunc   ;==>_exit



;~ filedelete("ergebnis.jpg")
;~ $t=timerinit()
;~     Local $hCDC = _WinAPI_CreateCompatibleDC($hpic1dc)
;~     Local $hBMP = _WinAPI_CreateCompatibleBitmap($hpic1dc, 100, 100)
;~     ;ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $hpic1dc = ' & $hpic1dc & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
;~     _WinAPI_SelectObject($hCDC, $hBMP)
;~     _WinAPI_BitBlt($hCDC, 0, 0, 100,100, $hpic1dc, 0,0, $SRCCOPY)
;~     _WinAPI_ReleaseDC($hgui1, $hpic1dc)
;~     _WinAPI_DeleteDC($hCDC)
;~     _ScreenCapture_SaveImage("ergebnis.jpg", $hBMP)
;~ $m=timerdiff($t)
;~ ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $m = ' & $m & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console

;~ shellexecute("ergebnis.jpg")

;~ _GDIPlus_GraphicsDispose($hGraphic1)
;~ _GDIPlus_GraphicsDispose($hGraphic2)
;~ _GDIPlus_ImageDispose($himg1)
;~ _GDIPlus_ImageDispose($hBild)
;~ _GDIPlus_GraphicsReleaseDC($hGraphic1,$hpic1dc)
;~ _GDIPlus_GraphicsReleaseDC($hGraphic2,$hSrcDC)
;~ _GDIPlus_Shutdown()




Func _getDCfromfile32($bmpfile, ByRef $ptr) ;ptr to bitmapdata, it is possible to manipulate one pixel if needed

    Local $hbitmap = _GDIPlus_BitmapCreateFromFile($bmpfile)
    Local $hbmp = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hbitmap)
    Local $iwidth = _GDIPlus_ImageGetWidth($hbitmap)
    Local $iheight = _GDIPlus_ImageGetHeight($hbitmap)
    Local $ibitcount = 32 ;if alpha is not needed, 24Bit saves 25% of space

    Local $tBMI = DllStructCreate($tagBITMAPINFO)
    DllStructSetData($tBMI, "Size", DllStructGetSize($tBMI) - 4)
    DllStructSetData($tBMI, "Width", $iwidth)
    DllStructSetData($tBMI, "Height", -$iheight)
    DllStructSetData($tBMI, "Planes", 1)
    DllStructSetData($tBMI, "BitCount", $ibitcount)
    Local $hdc = _WinAPI_GetDC(0)
    Local $hcdc = _WinAPI_CreateCompatibleDC($hdc)
    Local $adib = DllCall('gdi32.dll', 'ptr', 'CreateDIBSection', 'ptr', 0, 'ptr', DllStructGetPtr($tBMI), 'uint', $DIB_RGB_COLORS, 'ptr*', 0, 'ptr', 0, 'uint', 0)
    ; select object
    _WinAPI_SelectObject($hcdc, $adib[0])
    ; copy the content of the bitmap into the buffer ...
    _WinAPI_GetDIBits($hdc, $hbmp, 0, $iheight, $adib[4], DllStructGetPtr($tBMI), $DIB_RGB_COLORS)
    ; create the a dllstruct with the pointer $aDIB[4]
    Local $stride = 3 * $iwidth + Mod($iwidth, 4) ;number of bytes in one line (filled with some bytes, because it must be a multiple of four!)
    Local $tBits = DllStructCreate('byte[' & $stride * $iheight & ']', $adib[4])
    $ptr = DllStructGetPtr($tBits)
    _GDIPlus_BitmapDispose($hbitmap)
    _WinAPI_DeleteObject($adib[0])
    Return $hcdc ;MemoryDC of bitmap
EndFunc   ;==>_getDCfromfile32


Func _CreateNewBmp32($iwidth, $iheight, ByRef $ptr, ByRef $hbmp) ;erstellt leere 32-bit-Bitmap; Rückgabe $HDC und $ptr und handle auf die Bitmapdaten
    Local $hcdc = _WinAPI_CreateCompatibleDC(0) ;Desktop-Kompatiblen DeviceContext erstellen lassen
    Local $tBMI = DllStructCreate($tagBITMAPINFO) ;Struktur der Bitmapinfo erstellen und Daten eintragen
    DllStructSetData($tBMI, "Size", DllStructGetSize($tBMI) - 4);Structgröße abzüglich der Daten für die Palette
    DllStructSetData($tBMI, "Width", $iwidth)
    DllStructSetData($tBMI, "Height", -$iheight) ;minus =standard = bottomup
    DllStructSetData($tBMI, "Planes", 1)
    DllStructSetData($tBMI, "BitCount", 32) ;32 Bit = 4 Bytes => AABBGGRR
    Local $adib = DllCall('gdi32.dll', 'ptr', 'CreateDIBSection', 'hwnd', 0, 'ptr', DllStructGetPtr($tBMI), 'uint', $DIB_RGB_COLORS, 'ptr*', 0, 'ptr', 0, 'uint', 0)
    $hbmp = $adib[0] ;hbitmap handle auf die Bitmap, auch per GDI+ zu verwenden
    $ptr = $adib[4] ;pointer auf den Anfang der Bitmapdaten, vom Assembler verwendet
    ;_arraydisplay($adib)
    _WinAPI_SelectObject($hcdc, $hbmp) ;objekt hbitmap in DC
    Return $hcdc ;DC der Bitmap zurückgeben
EndFunc   ;==>_CreateNewBmp32

Func _DeleteBitmap32($DC, $ptr, $hbmp)
    _WinAPI_DeleteDC($DC)
    _WinAPI_DeleteObject($hbmp)
    $ptr = 0
EndFunc   ;==>_DeleteBitmap32
if someone wants to know if 2 pics are different, there are 2 ways:

- compare each pixel of the two pics, if there is a difference between 2 pixels, pics are not the same. Comparing pixels need some time.....see link above or use something like prospeed.dll

- bitblt them with $SRCINVERT-parameter (XOR transferes same pixel to black), copy the result into a string and use the awesome fast AutoIt-stringfunctions . Example:(yes i know that comparing "files" is not very useful, but with only a few changes it´s possible to compare bitmaps  from memory, f.e. for motion detection)

#include <GDIPlus.au3>
#include <WinAPI.au3>
#include <WindowsConstants.au3>
#include <StructureConstants.au3>
#include <GDIConstants.au3>
#include <ScreenCapture.au3>


_GDIPlus_Startup() ;no manipulating with gdi+ in this script, but it´s easy to load files other than bmp...

$picfile1 = "earth1.jpg" ;get them from here http://www.autoitscript.com/forum/index.php?showtopic=106815&view=findpost&p=753759
$picfile2 = "earth2.jpg" ;or use your own

;example of very big pictures
;~ _ScreenCapture_Capture("fullscreen1.jpg") ;makes fullscreenshot
;~ $picfile1 = "fullscreen1.jpg"
;~ $picfile2 = "fullscreen1.jpg" ;shows, that the 2 pics are the same

$t = TimerInit() ;save timestamp

;get a DeviceContext from the bitmap-file, if alphachannel is not needed, 24Bit saves 25% ram and is faster when searching or manipulating pixels^^
Local $pointer1, $pointer2 ;we don´t need them in this script, the variables are used ByRef
Local $struct1, $struct2 ;struct is need to copy Data into string, will be returned ByRef from the following function
Local $width1, $height1, $width2, $height2 ;size of the pics, will be returned ByRef from the following function
$hdc_pic1 = _getdcfromfile24_struct($picfile1, $pointer1, $struct1, $width1, $height1) ;get DC ,pointer is the pointer to the bitmapdata, if you want to manipulate pixels
$hdc_pic2 = _getdcfromfile24_struct($picfile2, $pointer2, $struct2, $width2, $height2) ;get DC ,pointer is the pointer to the bitmapdata, if you want to manipulate pixels

_WinAPI_BitBlt($hdc_pic1, 0, 0, $width1, $height2, $hdc_pic2, 0, 0, $SRCINVERT) ;XOR the 2 pics, compare is done, result is in pic1, XOR sets the same pixel to black

;because we have the struct (where are the bitmapdata-"pixels" inside), it is easy to copy the bitmapdata into a string
$bmpstring = BinaryToString(DllStructGetData($struct1, 1)) ;makes string of RGB-Bytes
StringReplace($bmpstring, Chr(0), "", 0, 1) ;count every black pixel in @extended, yeah, i like stringfunctions :o)
$same = @extended ;number of same bytes
$m = TimerDiff($t) ;difference between timestamp
If $same = StringLen($bmpstring) Then
    MsgBox(0, "Compared " & StringLen($bmpstring) & " Bytes", "Pics are the same" & @CRLF & StringFormat("%.3f Milliseconds", $m))
Else
    MsgBox(0, "Compared " & StringLen($bmpstring) & " Bytes", "Pics are different" & @CRLF & StringFormat("%.3f Milliseconds", $m) & @CRLF & StringFormat("%.0f% are different", 100 - ($same * 100 / StringLen($bmpstring))))
EndIf

_exit()





Func _exit()
    _DeleteBitmap32($hdc_pic1, $pointer1, 0)
    _DeleteBitmap32($hdc_pic2, $pointer2, 0)
    _GDIPlus_Shutdown()
    Exit
EndFunc   ;==>_exit


Func _getDCfromfile24_struct($bmpfile, ByRef $ptr, ByRef $tbits, ByRef $iwidth, ByRef $iheight) ;ptr to bitmapdata, it is possible to manipulate one pixel if needed, and struct
    Local $hbitmap = _GDIPlus_BitmapCreateFromFile($bmpfile)
    Local $hbmp = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hbitmap)
    $iwidth = _GDIPlus_ImageGetWidth($hbitmap)
    $iheight = _GDIPlus_ImageGetHeight($hbitmap)
    Local $ibitcount = 24 ;if alpha is not needed, 24Bit saves 25% of space

    Local $tBMI = DllStructCreate($tagBITMAPINFO)
    DllStructSetData($tBMI, "Size", DllStructGetSize($tBMI) - 4)
    DllStructSetData($tBMI, "Width", $iwidth)
    DllStructSetData($tBMI, "Height", -$iheight)
    DllStructSetData($tBMI, "Planes", 1)
    DllStructSetData($tBMI, "BitCount", $ibitcount)
    Local $hdc = _WinAPI_GetDC(0)
    Local $hcdc = _WinAPI_CreateCompatibleDC($hdc)
    Local $adib = DllCall('gdi32.dll', 'ptr', 'CreateDIBSection', 'ptr', 0, 'ptr', DllStructGetPtr($tBMI), 'uint', $DIB_RGB_COLORS, 'ptr*', 0, 'ptr', 0, 'uint', 0)
    ; select object
    _WinAPI_SelectObject($hcdc, $adib[0])
    ; copy the content of the bitmap into the buffer ...
    _WinAPI_GetDIBits($hdc, $hbmp, 0, $iheight, $adib[4], DllStructGetPtr($tBMI), $DIB_RGB_COLORS)
    ; create the a dllstruct with the pointer $aDIB[4]
    Local $stride = 3 * $iwidth + Mod($iwidth, 4) ;number of bytes in one line (filled with some bytes, because it must be a multiple of four!)
    $tbits = DllStructCreate('byte[' & $stride * $iheight & ']', $adib[4])
    $ptr = DllStructGetPtr($tbits)
    _GDIPlus_BitmapDispose($hbitmap)
    _WinAPI_DeleteObject($adib[0])
    Return $hcdc ;MemoryDC of bitmap
EndFunc   ;==>_getDCfromfile24_struct

Func _DeleteBitmap32($DC, $ptr, $hbmp)
    _WinAPI_DeleteDC($DC)
    _WinAPI_DeleteObject($hbmp)
    $ptr = 0
EndFunc   ;==>_DeleteBitmap32
//EDIT

with help of some CPU-Mnemonics, comparing is really fast (tested XP32, Errorhandling is on your own....)

_WinAPI_BitBlt($hdc_pic1, 0, 0, $width1, $height2, $hdc_pic2, 0, 0, $SRCINVERT) ;XOR the 2 pics, compare is done, result is in pic1, XOR sets the same pixel to black

$tCodeBuffer = DllStructCreate("byte[30]") ;Memory for bytecode
DllStructSetData($tCodeBuffer, 1, "0x5589E58B7D088B4D0CB800000000F3AF89C85DC3")  ;a little assemblercode which compares a part of the memory with 0
$a = DllCall("user32.dll", "int", "CallWindowProcW", "ptr", DllStructGetPtr($tCodeBuffer),"ptr",dllstructgetptr($struct1),"int",DllStructGetSize($struct1)/4, "int", 0,"int",0);bytecode aufrufen, rückgabe in a[0]
if $a[0]=0 then 
        ;pics are the same
    Else
        ;pics are different
endif

 

Edited by AndyG
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...