Jump to content
Sign in to follow this  
MasonMill

bitmap array

Recommended Posts

MasonMill

Hey guys,

Whats he best and most quickly computed way of creating an array of a bitmap image? like a 2D matrix. How would i set it up? Just need pointedin the right direction, thanks for the help!

-Mason

Share this post


Link to post
Share on other sites
MasonMill

Awesome, how can i display the matrices so i can compare different ones? Everyone keeps telling me consolewrite but i cant ever figure out how to view it.

Share this post


Link to post
Share on other sites
MasonMill

sweet, thanks!

Share this post


Link to post
Share on other sites
AndyG

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

Share this post


Link to post
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
Sign in to follow this  

×