Jump to content
Sign in to follow this  
IchBistTod

find the color of every pixel in an image

Recommended Posts

IchBistTod

I want to find the color of every pixel in and image and make it into a matrix like below

00FF00|00FF00|

00FF00|00FF00|

thats would be a 2x2 pixel green image.

the source code should explain the format it needs to be in.

the problem with the method I have is that it take 30 mins, and is HIGHLY inaccurate, which is not acceptable as the algorithms I am using are created to compare two images to find the differences, meaning if the same image can have two different matricies it destroys the point of the program. So far this method had only brought 55% accuracy max(with the same exact image scanned twice then compared) and is usually at around 10%.

getting this color info is the only problem standing in my way of completing my application.

any help would be appreciated.

current code:

#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>

#Region ### START Koda GUI section ### Form=
;GUICreate(".", 0, 0, 1, 1)
;WinSetOnTop(".", "", 1)
;GUISetState()
$Form1 = GUICreate("IS", 652, 443, 192, 124)
$Pic1 = GUICtrlCreatePic("select.jpg", 16, 32, 300, 300, BitOR($SS_NOTIFY,$WS_GROUP,$WS_CLIPSIBLINGS))
$Pic2 = GUICtrlCreatePic("select.jpg", 335, 32, 300, 300, BitOR($SS_NOTIFY,$WS_GROUP,$WS_CLIPSIBLINGS))

$compare = GUICtrlCreateButton("scan", 288, 360, 75, 25, 0)
GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###


While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit
        case $Pic1
            GUICtrlSetImage($Pic1, FileOpenDialog("select an image", @WorkingDir, "All Files(*.*)"))
case $Pic2
            GUICtrlSetImage($Pic2, FileOpenDialog("select an image", @WorkingDir, "All Files(*.*)"))
        case $compare
            $win = WinGetPos($Form1)
            Dim $string = "[300x300|]"&@CRLF
            $timer = TimerInit()
            for $i=32+$win[1] to 32+300+$win[1]-1
                for $ix = 16+$win[0] to 300+16+$win[0]-1
                $string &= hex(PixelGetColor($ix, $i))&"|"
                Next

                $string &= @CRLF
            Next
            ConsoleWrite(TimerDiff($timer)&@CRLF)
            FileWrite("pic.temp.IS", $string)

    EndSwitch
WEnd

if you for some reason need the compare funcs just pm me.

Edited by IchBistTod

[center][/center][center]=][u][/u][/center][center][/center]

Share this post


Link to post
Share on other sites
Authenticity

If you want to get the pixels of each image to compare them later for equality, you can do something like:

#include <GDIPlus.au3>
#include <GUIConstantsEx.au3>
#include <Icons.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
_GDIPlus_Startup()

Local $Form1, $Pic1, $Pic2, $compare
Local $sFilename1, $sFilename2

$Form1 = GUICreate("IS", 652, 443, 192, 124)
$Pic1 = GUICtrlCreateLabel("select.jpg", 16, 32, 300, 300, BitOR($SS_NOTIFY, $WS_GROUP, $WS_CLIPSIBLINGS))
$Pic2 = GUICtrlCreateLabel("select.jpg", 335, 32, 300, 300, BitOR($SS_NOTIFY, $WS_GROUP, $WS_CLIPSIBLINGS))

$compare = GUICtrlCreateButton("scan", 288, 360, 75, 25, 0)
GUISetState()

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            _GDIPlus_Shutdown()
            Exit
        Case $Pic1
            $sFilename1 = FileOpenDialog("select an image", @WorkingDir, "Images (*.bmp;*.dib;*.jpg;*.jpeg;*.jpe;*.jfif;*.gif;*.tif;*.tiff;*.png;*.ico)", 5)
            If $sFilename1 <> "" Then _SetImage($Pic1, $sFilename1)
        Case $Pic2
            $sFilename2 =  FileOpenDialog("select an image", @WorkingDir, "Images (*.bmp;*.dib;*.jpg;*.jpeg;*.jpe;*.jfif;*.gif;*.tif;*.tiff;*.png;*.ico)", 5)
            If $sFilename2 <> "" Then _SetImage($Pic2, $sFilename2)
        Case $compare
;~          $win = WinGetPos($Form1)
;~          Dim $string = "[300x300|]" & @CRLF
;~          $timer = TimerInit()
;~          For $i = 32 + $win[1] To 32 + 300 + $win[1] - 1
;~              For $ix = 16 + $win[0] To 300 + 16 + $win[0] - 1
;~                  $string &= Hex(PixelGetColor($ix, $i)) & "|"
;~              Next

;~              $string &= @CRLF
;~          Next
;~          ConsoleWrite(TimerDiff($timer) & @CRLF)
;~          FileWrite("pic.temp.IS", $string)
            If $sFilename1 <> "" And $sFilename2 <> "" Then
                If _CompareImages($sFilename1, $sFilename2) Then
                    ConsoleWrite("+Images are same" & @CRLF)
                Else
                    ConsoleWrite("!Image are different" & @CRLF)
                EndIf
            EndIf
    EndSwitch
WEnd

Func _CompareImages($sImage1, $sImage2)
    Local $hImage1, $hImage2, $iBmp1, $iBmp2, $iW1, $iW2, $iH1, $iH2
    Local $tBD1, $tBD2, $iWidth1, $iWidth2, $iHeight1, $iHeight2, $iStride1, $iStride2, $iFmt1, $iFmt2
    Local $pData1, $pData2
    Local $tPixels1, $tPixels2, $xBytes1, $xBytes2
    Local $fResult = False

    If $sImage1 = $sImage2 Then Return True

    $hImage1 = _GDIPlus_ImageLoadFromFile($sImage1)
    If @error Then Return SetError(1, 0, 0)
    $hImage2 = _GDIPlus_ImageLoadFromFile($sImage2)
    If @error Then Return SetError(2, 0, 0)

    $iW1 = _GDIPlus_ImageGetWidth($hImage1)
    $iH1 = _GDIPlus_ImageGetHeight($hImage1)
    $iW2 = _GDIPlus_ImageGetWidth($hImage2)
    $iH2 = _GDIPlus_ImageGetHeight($hImage2)

    If $iW1 <> $iW2 Or $iH1 <> $iH2 Then Return False

    $hBmp1 = _GDIPlus_BitmapCloneArea($hImage1, 0, 0, $iW1, $iH1, $GDIP_PXF32ARGB)
    $hBmp2 = _GDIPlus_BitmapCloneArea($hImage2, 0, 0, $iW2, $iH2, $GDIP_PXF32ARGB)

    $tBD1 = _GDIPlus_BitmapLockBits($hBmp1, 0, 0, $iW1, $iH1, BitOR($GDIP_ILMREAD, $GDIP_ILMWRITE), $GDIP_PXF32ARGB)
    $tBD2 = _GDIPlus_BitmapLockBits($hBmp2, 0, 0, $iW2, $iH2, BitOR($GDIP_ILMREAD, $GDIP_ILMWRITE), $GDIP_PXF32ARGB)

    $iWidth1 = DllStructGetData($tBD1, 1)
    $iHeight1 = DllStructGetData($tBD1, 2)
    $iStride1 = DllStructGetData($tBD1, 3)
    $iFmt1 = DllStructGetData($tBD1, 4)
    $pData1 = DllStructGetData($tBD1, 5)

    $iWidth2 = DllStructGetData($tBD2, 1)
    $iHeight2 = DllStructGetData($tBD2, 2)
    $iStride2 = DllStructGetData($tBD2, 3)
    $iFmt2 = DllStructGetData($tBD2, 4)
    $pData2 = DllStructGetData($tBD2, 5)

    $tPixels1 = DllStructCreate("byte[" & $iWidth1 * $iHeight1 * 4 & "]", $pData1)
    $tPixels2 = DllStructCreate("byte[" & $iWidth2 * $iHeight2 * 4 & "]", $pData2)

    $xBytes1 = DllStructGetData($tPixels1, 1)
    $xBytes2 = DllStructGetData($tPixels2, 1)

    If $xBytes1 = $xBytes2 Then $fResult = True

    _GDIPlus_BitmapUnlockBits($hBmp1, $tBD2)
    _GDIPlus_BitmapUnlockBits($hBmp1, $tBD1)
    
    _WinAPI_DeleteObject($hBmp2)
    _WinAPI_DeleteObject($hBmp1)
    
    _GDIPlus_ImageDispose($hImage2)
    _GDIPlus_ImageDispose($hImage1)
    Return $fResult
EndFunc

If you want the pixels as a single dimension array you can take $xBytes1 and using StringRegExp() you can split the binary string each 8 characters. Turning the binary data to an array in the size of the image, for example $avArray[800][480] requires to go get the data as an array first, then using a nested loop from 0 to $iW, 0 to $iH you can build the array.

Share this post


Link to post
Share on other sites
IchBistTod

I just want it in the format i used above..... a textual matrix representation that is later turned into a two dimensional matrix with this function

func _ReadISFile($file)
    $timer = TimerInit()
    $data = FileRead($file)

    $darray = StringSplit(StringReplace($data, @CR, ""), @LF, 2)
    $demensions = _StringBetween($darray[0], "[", "|")
$demensions = StringSplit($demensions[0], "x",2)
    Dim $ismatrix[$demensions[0]+1][$demensions[1]+1]
    for $i=1 to $demensions[0]
        $dm=StringSplit($darray[$i], "|")
        for $ix=1 to $demensions[0]
            $ismatrix[$i][$ix] =  $dm[$ix]
        Next
    Next
        ConsoleWrite(TimerDiff($timer)&@CRLF)
    Return $ismatrix
EndFunc

Also I thank you for this help, but I have no experience with regular expressions, or how to work with this data could you perhaps provide code of how to do this, then I can study it and learn from it? (what i want is each pixels data stored in an element of a matrix, each row being a Y coordinate and each column being a X coordinate)

example:

X1  X2
Y1 00FF00|00FF00|
Y2 00FF00|00FF00|

and the IS format for this would be

[2x2|]
00FF00|00FF00|
00FF00|00FF00|

two matrices are compared by this function:

func _MatrixCompare($array1, $array2, $size, $decimal)
    $timer = TimerInit()
    local $match = 0
    $size = StringSplit($size, "x", 2)
    for $i=1 to $size[0]
        for $i2 = 1 to $size[1]
            if $array1[$i][$i2] = $array2[$i][$i2] Then
                $match +=1
            EndIf
        Next
    Next
    $total = $size[0]*$size[1]
    $return = ($match/$total)*100
    if StringInStr($return, ".") Then
    $returnx = StringSplit($return, ".")
    $return = $returnx[1]&"."&StringLeft($returnx[2], $decimal)
EndIf
    ConsoleWrite(TimerDiff($timer)&@CRLF)
    Return $return
EndFunc

this returns an exact percentage two matrices match.

so this is why i want each pixel color as one element of the matrix to compare pixel by pixel and get a difference percentage by using my functions to compare textual representations of the image.

thanks for your help so far.

Edited by IchBistTod

[center][/center][center]=][u][/u][/center][center][/center]

Share this post


Link to post
Share on other sites
Authenticity

#include <GDIPlus.au3>

_GetImagePixels(@ScriptDir & "\1.jpg", @ScriptDir & "\Test.txt")

Func _GetImagePixels($sImage, $sOutputFile)
    Local $hImage, $hBmp, $iW, $iH
    Local $tBD, $iWidth, $iHeight, $iStride, $iFmt
    Local $pData, $tPixels, $xBytes
    Local $avPixels, $hFile
    
    $hFile = FileOpen($sOutputFile, 2)
    If @error Then Return SetError(1, 1, 0)
    
    _GDIPlus_Startup()

    $hImage = _GDIPlus_ImageLoadFromFile($sImage)
    If @error Then Return SetError(1, 2, 0)

    $iW = _GDIPlus_ImageGetWidth($hImage)
    $iH = _GDIPlus_ImageGetHeight($hImage)
    $hBmp = _GDIPlus_BitmapCloneArea($hImage, 0, 0, $iW, $iH, $GDIP_PXF32ARGB)
    $tBD = _GDIPlus_BitmapLockBits($hBmp, 0, 0, $iW, $iH, BitOR($GDIP_ILMREAD, $GDIP_ILMWRITE), $GDIP_PXF32ARGB)

    $iWidth = DllStructGetData($tBD, 1)
    $iHeight = DllStructGetData($tBD, 2)
    $iStride = DllStructGetData($tBD, 3)
    $iFmt = DllStructGetData($tBD, 4)
    $pData = DllStructGetData($tBD, 5)

    $tPixels = DllStructCreate("byte[" & $iW * $iH * 4 & "]", $pData)
    $xBytes = DllStructGetData($tPixels, 1)
    
    $sData = StringTrimRight(StringRegExpReplace(StringTrimLeft($xBytes, 2), "(.{" & 8 * $iWidth & "})", "\1@"), 1)
    $avData = StringSplit($sData, "@")
    
    FileWrite($hFile, StringRegExpReplace($avData[1], "(.{8})(?!$)", "\1|"))
    For $i = 2 To $avData[0]
        FileWrite($hFile, @CRLF & StringRegExpReplace($avData[1], "(.{8})(?!$)", "\1|"))
    Next
    FileClose($hFile)

    _GDIPlus_BitmapUnlockBits($hBmp, $tBD)
    _WinAPI_DeleteObject($hBmp)
    _GDIPlus_ImageDispose($hImage)
    _GDIPlus_Shutdown()
EndFunc

The pixel colors are saved as "BBGGRRAA" so you may want to use Binary(Dec($Pixel)) to get the correct "AARRGGBB" pixel value.

Share this post


Link to post
Share on other sites
AndyG

Hi, this is a "relative" fast function.

A 1680x1050 Bitmap takes about 12 Seconds to store the hexnumbers of the pixels to an array.

#include <GUIConstantsEx.au3>
#include <WinAPI.au3>
#include <GDIPlus.au3>
#include <GDIPlusConstants.au3>
#include <StructureConstants.au3>
#include <Array.au3>


$bitmapfile = "pic2.jpg"   ;some image
;$bitmapfile = "testfullscreen.bmp"  ;1680x1050

$t = TimerInit()
$array = _allpixel2array($bitmapfile) ;write pixelcolours from an image-file into an array
$m = TimerDiff($t)
ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $m = ' & $m & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console


;****************Example: write the array into a window (setpixel)*******************

$hGUI = GUICreate("GDI+", 300, 300); @DesktopWidth, @DesktopHeight)
$hWnd = WinGetHandle("GDI+")
GUISetState()
_GDIPlus_Startup()
$hGraphic = _GDIPlus_GraphicsCreateFromHWND($hWnd)

For $x = 1 To UBound($array, 1) - 1
    For $y = 0 To UBound($array, 2) - 1
        $col = "0xFF" & StringMid($array[$x][$y], 5, 2) & StringMid($array[$x][$y], 3, 2) & StringMid($array[$x][$y], 1, 2)  ;BGR to RGB
        $hPen = _GDIPlus_PenCreate($col)    ;
        _GDIPlus_GraphicsDrawEllipse($hGraphic, $y, $x, 1, 1, $hPen)
    Next
Next

Do
Until GUIGetMsg() = $GUI_EVENT_CLOSE

; Ressourcen freigeben
_GDIPlus_GraphicsDispose($hGraphic)
_GDIPlus_Shutdown()




Func _allpixel2array($bmpfile) ;returns a 2d array with the colours BGR
    _GDIPlus_Startup()
    $pBitmap = _GDIPlus_BitmapCreateFromFile($bmpfile)
    If @error Then MsgBox(0, "", "Fehler BitmapCreateFromFile")
    ;_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("byte[" & (Abs($stride) * ($Height)) & "]", $Scan0)
    $BMPDataStart = StringTrimLeft(DllStructGetData($pixeldata, 1), 2) ;string im Struct-format, d.h. Byte+nulByte, in dem die pixeldaten im BGR-Format stehen
    ;    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $BMPDataStart = ' & StringLeft($BMPDataStart, 100) & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console

    Dim $array[$Height + 1][$Width + 1]

    For $y = 0 To $Height - 1 ;to 1 step -1   ;bottomup bitmap, first line in image is last line in data
        For $i = 0 To $stride * 2 Step 6 ;every 3 byte are one pixel
            $array[$y + 1][$i / 6] = StringMid($BMPDataStart, ($y * $stride * 2) + $i + 1, 6)
            ;ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $array[$y][$i / 6] = ' & $array[$y][$i / 6] & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
        Next
    Next
    ;    _arraydisplay($array)
    $BMPDataStart = ""
    $pixeldata = 0
    _GDIPlus_BitmapUnlockBits($pBitmap, $BitmapData)
    _GDIPlus_ImageDispose($pBitmap)
    _WinAPI_DeleteObject($pBitmap)
    _GDIPlus_Shutdown()
    Return $array
EndFunc   ;==>_allpixel2array2
i hope it helps  little bit.....

Share this post


Link to post
Share on other sites
IchBistTod

#include <GDIPlus.au3>

_GetImagePixels(@ScriptDir & "\1.jpg", @ScriptDir & "\Test.txt")

Func _GetImagePixels($sImage, $sOutputFile)
    Local $hImage, $hBmp, $iW, $iH
    Local $tBD, $iWidth, $iHeight, $iStride, $iFmt
    Local $pData, $tPixels, $xBytes
    Local $avPixels, $hFile
    
    $hFile = FileOpen($sOutputFile, 2)
    If @error Then Return SetError(1, 1, 0)
    
    _GDIPlus_Startup()

    $hImage = _GDIPlus_ImageLoadFromFile($sImage)
    If @error Then Return SetError(1, 2, 0)

    $iW = _GDIPlus_ImageGetWidth($hImage)
    $iH = _GDIPlus_ImageGetHeight($hImage)
    $hBmp = _GDIPlus_BitmapCloneArea($hImage, 0, 0, $iW, $iH, $GDIP_PXF32ARGB)
    $tBD = _GDIPlus_BitmapLockBits($hBmp, 0, 0, $iW, $iH, BitOR($GDIP_ILMREAD, $GDIP_ILMWRITE), $GDIP_PXF32ARGB)

    $iWidth = DllStructGetData($tBD, 1)
    $iHeight = DllStructGetData($tBD, 2)
    $iStride = DllStructGetData($tBD, 3)
    $iFmt = DllStructGetData($tBD, 4)
    $pData = DllStructGetData($tBD, 5)

    $tPixels = DllStructCreate("byte[" & $iW * $iH * 4 & "]", $pData)
    $xBytes = DllStructGetData($tPixels, 1)
    
    $sData = StringTrimRight(StringRegExpReplace(StringTrimLeft($xBytes, 2), "(.{" & 8 * $iWidth & "})", "\1@"), 1)
    $avData = StringSplit($sData, "@")
    
    FileWrite($hFile, StringRegExpReplace($avData[1], "(.{8})(?!$)", "\1|"))
    For $i = 2 To $avData[0]
        FileWrite($hFile, @CRLF & StringRegExpReplace($avData[1], "(.{8})(?!$)", "\1|"))
    Next
    FileClose($hFile)

    _GDIPlus_BitmapUnlockBits($hBmp, $tBD)
    _WinAPI_DeleteObject($hBmp)
    _GDIPlus_ImageDispose($hImage)
    _GDIPlus_Shutdown()
EndFunc

The pixel colors are saved as "BBGGRRAA" so you may want to use Binary(Dec($Pixel)) to get the correct "AARRGGBB" pixel value.

This was easier to modify to my needs and seems to be quite fast, however is there a way to "shrink" an image to a smaller resolution, for say smaller scan time, or if there are two different sized images, so the largest could be shrunk to the smallest or vice versa (whichever would be more accurate)

Hi, this is a "relative" fast function.

A 1680x1050 Bitmap takes about 12 Seconds to store the hexnumbers of the pixels to an array.

#include <GUIConstantsEx.au3>
#include <WinAPI.au3>
#include <GDIPlus.au3>
#include <GDIPlusConstants.au3>
#include <StructureConstants.au3>
#include <Array.au3>


$bitmapfile = "pic2.jpg"   ;some image
;$bitmapfile = "testfullscreen.bmp"  ;1680x1050

$t = TimerInit()
$array = _allpixel2array($bitmapfile) ;write pixelcolours from an image-file into an array
$m = TimerDiff($t)
ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $m = ' & $m & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console


;****************Example: write the array into a window (setpixel)*******************

$hGUI = GUICreate("GDI+", 300, 300); @DesktopWidth, @DesktopHeight)
$hWnd = WinGetHandle("GDI+")
GUISetState()
_GDIPlus_Startup()
$hGraphic = _GDIPlus_GraphicsCreateFromHWND($hWnd)

For $x = 1 To UBound($array, 1) - 1
    For $y = 0 To UBound($array, 2) - 1
        $col = "0xFF" & StringMid($array[$x][$y], 5, 2) & StringMid($array[$x][$y], 3, 2) & StringMid($array[$x][$y], 1, 2)  ;BGR to RGB
        $hPen = _GDIPlus_PenCreate($col)    ;
        _GDIPlus_GraphicsDrawEllipse($hGraphic, $y, $x, 1, 1, $hPen)
    Next
Next

Do
Until GUIGetMsg() = $GUI_EVENT_CLOSE

; Ressourcen freigeben
_GDIPlus_GraphicsDispose($hGraphic)
_GDIPlus_Shutdown()




Func _allpixel2array($bmpfile) ;returns a 2d array with the colours BGR
    _GDIPlus_Startup()
    $pBitmap = _GDIPlus_BitmapCreateFromFile($bmpfile)
    If @error Then MsgBox(0, "", "Fehler BitmapCreateFromFile")
    ;_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("byte[" & (Abs($stride) * ($Height)) & "]", $Scan0)
    $BMPDataStart = StringTrimLeft(DllStructGetData($pixeldata, 1), 2) ;string im Struct-format, d.h. Byte+nulByte, in dem die pixeldaten im BGR-Format stehen
    ;   ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $BMPDataStart = ' & StringLeft($BMPDataStart, 100) & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console

    Dim $array[$Height + 1][$Width + 1]

    For $y = 0 To $Height - 1 ;to 1 step -1   ;bottomup bitmap, first line in image is last line in data
        For $i = 0 To $stride * 2 Step 6 ;every 3 byte are one pixel
            $array[$y + 1][$i / 6] = StringMid($BMPDataStart, ($y * $stride * 2) + $i + 1, 6)
            ;ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $array[$y][$i / 6] = ' & $array[$y][$i / 6] & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
        Next
    Next
    ;   _arraydisplay($array)
    $BMPDataStart = ""
    $pixeldata = 0
    _GDIPlus_BitmapUnlockBits($pBitmap, $BitmapData)
    _GDIPlus_ImageDispose($pBitmap)
    _WinAPI_DeleteObject($pBitmap)
    _GDIPlus_Shutdown()
    Return $array
EndFunc   ;==>_allpixel2array2
i hope it helps little bit.....

This was very useful too, however I wanted to be able to store the data in files for later use by my IS read function, although your example of how to draw the image back out was very nice.

thank you all for your help


[center][/center][center]=][u][/u][/center][center][/center]

Share this post


Link to post
Share on other sites
laffo16

#include <GDIPlus.au3>

_GetImagePixels(@ScriptDir & "\image.bmp", @ScriptDir & "\Test.txt")
MsgBox(0, "", "pause to check if file is locked")

Func _GetImagePixels($sImage, $sOutputFile)
    Local $hImage, $hBmp, $iW, $iH
    Local $tBD, $iWidth, $iHeight, $iStride, $iFmt
    Local $pData, $tPixels, $xBytes
    Local $avPixels, $hFile
    
    $hFile = FileOpen($sOutputFile, 2)
    If @error Then Return SetError(1, 1, 0)
    
    _GDIPlus_Startup()

    $hImage = _GDIPlus_ImageLoadFromFile($sImage)
    If @error Then Return SetError(1, 2, 0)

    $iW = _GDIPlus_ImageGetWidth($hImage)
    $iH = _GDIPlus_ImageGetHeight($hImage)
    $hBmp = _GDIPlus_BitmapCloneArea($hImage, 0, 0, $iW, $iH, $GDIP_PXF32ARGB)
    $tBD = _GDIPlus_BitmapLockBits($hBmp, 0, 0, $iW, $iH, BitOR($GDIP_ILMREAD, $GDIP_ILMWRITE), $GDIP_PXF32ARGB)

    $iWidth = DllStructGetData($tBD, 1)
    $iHeight = DllStructGetData($tBD, 2)
    $iStride = DllStructGetData($tBD, 3)
    $iFmt = DllStructGetData($tBD, 4)
    $pData = DllStructGetData($tBD, 5)

    $tPixels = DllStructCreate("byte[" & $iW * $iH * 4 & "]", $pData)
    $xBytes = DllStructGetData($tPixels, 1)
    
    $sData = StringTrimRight(StringRegExpReplace(StringTrimLeft($xBytes, 2), "(.{" & 8 * $iWidth & "})", "\1@"), 1)
    $avData = StringSplit($sData, "@")
    
    FileWrite($hFile, StringRegExpReplace($avData[1], "(.{8})(?!$)", "\1|"))
    For $i = 2 To $avData[0]
        FileWrite($hFile, @CRLF & StringRegExpReplace($avData[1], "(.{8})(?!$)", "\1|"))
    Next
    FileClose($hFile)

    _GDIPlus_BitmapUnlockBits($hBmp, $tBD)
    _WinAPI_DeleteObject($hBmp)
    _GDIPlus_ImageDispose($hImage)
    _GDIPlus_Shutdown()
EndFunc

The bmp file seems to be locked after it is accessed with _GetImagePixels(), can anyone see any fault with the clean up mechanism which may cause the bmp to be locked? sorry im just no good with GDI stuff, i'll keep trying, pls reply if you understand the problem.

edit: you must dispose of the BitmapCloneArea also, _GDIPlus_ImageDispose($hBmp) to release the image

Edited by laffo16

Share this post


Link to post
Share on other sites
Malkey

#include <GDIPlus.au3>

_GetImagePixels(@ScriptDir & "\image.bmp", @ScriptDir & "\Test.txt")
MsgBox(0, "", "pause to check if file is locked")

Func _GetImagePixels($sImage, $sOutputFile)
 Local $hImage, $hBmp, $iW, $iH
 Local $tBD, $iWidth, $iHeight, $iStride, $iFmt
 Local $pData, $tPixels, $xBytes
 Local $avPixels, $hFile
 
 $hFile = FileOpen($sOutputFile, 2)
 If @error Then Return SetError(1, 1, 0)
 
 _GDIPlus_Startup()

 $hImage = _GDIPlus_ImageLoadFromFile($sImage)
 If @error Then Return SetError(1, 2, 0)

 $iW = _GDIPlus_ImageGetWidth($hImage)
 $iH = _GDIPlus_ImageGetHeight($hImage)
 $hBmp = _GDIPlus_BitmapCloneArea($hImage, 0, 0, $iW, $iH, $GDIP_PXF32ARGB)
 $tBD = _GDIPlus_BitmapLockBits($hBmp, 0, 0, $iW, $iH, BitOR($GDIP_ILMREAD, $GDIP_ILMWRITE), $GDIP_PXF32ARGB)

 $iWidth = DllStructGetData($tBD, 1)
 $iHeight = DllStructGetData($tBD, 2)
 $iStride = DllStructGetData($tBD, 3)
 $iFmt = DllStructGetData($tBD, 4)
 $pData = DllStructGetData($tBD, 5)

 $tPixels = DllStructCreate("byte[" & $iW * $iH * 4 & "]", $pData)
 $xBytes = DllStructGetData($tPixels, 1)
 
 $sData = StringTrimRight(StringRegExpReplace(StringTrimLeft($xBytes, 2), "(.{" & 8 * $iWidth & "})", "\1@"), 1)
 $avData = StringSplit($sData, "@")
 
 FileWrite($hFile, StringRegExpReplace($avData[1], "(.{8})(?!$)", "\1|"))
 For $i = 2 To $avData[0]
 FileWrite($hFile, @CRLF & StringRegExpReplace($avData[1], "(.{8})(?!$)", "\1|"))
 Next
 FileClose($hFile)

 _GDIPlus_BitmapUnlockBits($hBmp, $tBD)
 _WinAPI_DeleteObject($hBmp)
 _GDIPlus_ImageDispose($hImage)
 _GDIPlus_Shutdown()
EndFunc

The bmp file seems to be locked after it is accessed with _GetImagePixels(), can anyone see any fault with the clean up mechanism which may cause the bmp to be locked? sorry im just no good with GDI stuff, i'll keep trying, pls reply if you understand the problem.

edit: you must dispose of the BitmapCloneArea also, _GDIPlus_ImageDispose($hBmp) to release the image

Within your script replace
$sData = StringTrimRight(StringRegExpReplace(StringTrimLeft($xBytes, 2), "(.{" & 8 * $iWidth & "})", "\1@"), 1)

with

$sData = StringTrimRight(StringRegExpReplace(StringTrimLeft($xBytes, 2), "(.{8})", "\1@"), 1)

When you are finished with the bitmap object created with _GDIPlus_BitmapCloneArea(), you should release the bitmap object with either _GDIPlus_BitmapDispose (), or _GDIPlus_ImageDispose(). These two functions have the same workings.

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  

×