Jump to content
Sign in to follow this  
Hawkwing

"read" picture to array

Recommended Posts

Hawkwing

Is there a way to "read" a picture and have a 2d array with the colors of each pixel?


The Wheel of Time turns, and Ages come and pass, leaving memories that become legend. Legend fades to myth, and even myth is long forgotten when the Age that gave it birth comes again.

Share this post


Link to post
Share on other sites
Manjish

I might have an idea as to how u can do this..

Put $x and $y in nestled for loops.. increment them from 1 to max x and y cordinate of pic..

Use pixelgetcolor and save it in a 2d array as $avArray[$x][$y]..

Don't have the time to write and test.. But I have a good feeling that this might work!! If it doesn't, sorry!!


[font="Garamond"]Manjish Naik[/font]Engineer, Global Services - QPSHoneywell Automation India LimitedE-mail - Manjish.Naik@honeywell.com

Share this post


Link to post
Share on other sites
Malkey

Is there a way to "read" a picture and have a 2d array with the colors of each pixel?

Personally, I would avoid creating arrays like the plague, and get any required info from the pixels with regular expressions.

;
;Ref:-  [url="http://www.autoitscript.com/forum/index.php?s=&showtopic=86773&view=findpost&p=622869"]http://www.autoitscript.com/forum/index....=&showtopic=86773&view=findpost&p=622869[/url]
#include <WinAPI.au3>
#include <GDIPlus.au3>
#include <Array.au3>

Dim $pixels, $iTotalReplace, $Count = 0
Local $Path = FileOpenDialog("Choose Image File", @ScriptDir & "", "Images (*.gif;*.png;*.jpg;*.bmp)| All (*.*)")
If $Path <> "" Then
    _GDIPlus_Startup()
    $hImage = _GDIPlus_ImageLoadFromFile($Path)
    $width = _GDIPlus_ImageGetWidth($hImage)
    $height = _GDIPlus_ImageGetHeight($hImage)
    $hBmp = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage)
    $aSize = DllCall('gdi32.dll', 'int', 'GetBitmapBits', 'ptr', $hBmp, 'int', 0, 'ptr', 0)
    If $aSize[0] Then
        $tBits = DllStructCreate('byte[' & $aSize[0] & ']')
        DllCall('gdi32.dll', 'int', 'GetBitmapBits', 'ptr', $hBmp, 'int', $aSize[0], 'ptr', DllStructGetPtr($tBits))
        $sHex = Hex(DllStructGetData($tBits, 1))
        $sHex = StringRegExpReplace($sHex, "([[:xdigit:]]{6})(FF)", "\1 ")
        Local $pix[$height][$width], $aTemp
        Local $aArr = StringRegExp($sHex, "(.{" & ($width * 7) & "})", 3)
        ;_ArrayDisplay($aArr)
        For $x = 0 To UBound($aArr) - 1
            $aTemp = StringRegExp($aArr[$x] & " ", "(.{6}) ", 3)
            For $y = 0 To UBound($aTemp) - 1
                $pix[$x][$y] = StringRegExpReplace($aTemp[$y], "(.{2})(.{2})(.{2})", "\3\2\1") ; To RGB format
            Next
        Next
    EndIf

    _ArrayDisplay($pix, $width & "x" & $height & $Path)
    _WinAPI_DeleteObject($hBmp)
    _GDIPlus_ImageDispose($hImage)
    _GDIPlus_Shutdown()
EndIf
;

Share this post


Link to post
Share on other sites
Hawkwing

Personally, I would avoid creating arrays like the plague, and get any required info from the pixels with regular expressions.

;
;Ref:-  [url="http://www.autoitscript.com/forum/index.php?s=&showtopic=86773&view=findpost&p=622869"]http://www.autoitscript.com/forum/index....=&showtopic=86773&view=findpost&p=622869[/url]
#include <WinAPI.au3>
#include <GDIPlus.au3>
#include <Array.au3>

Dim $pixels, $iTotalReplace, $Count = 0
Local $Path = FileOpenDialog("Choose Image File", @ScriptDir & "", "Images (*.gif;*.png;*.jpg;*.bmp)| All (*.*)")
If $Path <> "" Then
    _GDIPlus_Startup()
    $hImage = _GDIPlus_ImageLoadFromFile($Path)
    $width = _GDIPlus_ImageGetWidth($hImage)
    $height = _GDIPlus_ImageGetHeight($hImage)
    $hBmp = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage)
    $aSize = DllCall('gdi32.dll', 'int', 'GetBitmapBits', 'ptr', $hBmp, 'int', 0, 'ptr', 0)
    If $aSize[0] Then
        $tBits = DllStructCreate('byte[' & $aSize[0] & ']')
        DllCall('gdi32.dll', 'int', 'GetBitmapBits', 'ptr', $hBmp, 'int', $aSize[0], 'ptr', DllStructGetPtr($tBits))
        $sHex = Hex(DllStructGetData($tBits, 1))
        $sHex = StringRegExpReplace($sHex, "([[:xdigit:]]{6})(FF)", "\1 ")
        Local $pix[$height][$width], $aTemp
        Local $aArr = StringRegExp($sHex, "(.{" & ($width * 7) & "})", 3)
        ;_ArrayDisplay($aArr)
        For $x = 0 To UBound($aArr) - 1
            $aTemp = StringRegExp($aArr[$x] & " ", "(.{6}) ", 3)
            For $y = 0 To UBound($aTemp) - 1
                $pix[$x][$y] = StringRegExpReplace($aTemp[$y], "(.{2})(.{2})(.{2})", "\3\2\1") ; To RGB format
            Next
        Next
    EndIf

    _ArrayDisplay($pix, $width & "x" & $height & $Path)
    _WinAPI_DeleteObject($hBmp)
    _GDIPlus_ImageDispose($hImage)
    _GDIPlus_Shutdown()
EndIf
;

Thanks Malcy! Works great! And it's a lot faster than the link Andreik posted.

The Wheel of Time turns, and Ages come and pass, leaving memories that become legend. Legend fades to myth, and even myth is long forgotten when the Age that gave it birth comes again.

Share this post


Link to post
Share on other sites
Hawkwing

Now, how would I edit certain pixels in a picture? (wasn't sure whether or not to start a new topic >_< )


The Wheel of Time turns, and Ages come and pass, leaving memories that become legend. Legend fades to myth, and even myth is long forgotten when the Age that gave it birth comes again.

Share this post


Link to post
Share on other sites
smashly

Hi,

Here's a copy and pasted from an example I've recently submitted for the GDI+ UDF, maybe you can use it to work out what your after.

It's not as speedy as using Malcy's method or using LockBits/UnlockBits methods,

but it's just an example for use of Get and Set Pixels using GDI+

#AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6

#include <GuiConstantsEx.au3>
#include <GDIPlus.au3>

Opt('MustDeclareVars', 1)

_Main()

Func _Main()
    Local $sRegPath, $sImagePath, $hImage, $iW, $iH, $hBitmap, $iFirstPixel
    Local $iNewPixel, $iX, $iY, $iGetPixel, $iCnt, $hGui, $hGraphic

    ; Get the path of the image
    $sRegPath = "HKLM\SOFTWARE\AutoIt v3\AutoIt"
    If StringInStr("X64IA64", @OSArch) Then $sRegPath = StringReplace($sRegPath, "SOFTWARE", "SOFTWARE\Wow6432Node")
    $sImagePath = RegRead($sRegPath, "InstallDir") & "\Examples\GUI\logo4.gif"

    ; Start GDIPlus
    _GDIPlus_Startup()

    ; Load image
    $hImage = _GDIPlus_ImageLoadFromFile($sImagePath)

    ; Get the very first pixel of the loaded image to later swap with a new pixel color.
    $iFirstPixel = _GDIPlus_BitmapGetPixel($hImage, 0, 0)

    ; Get the width and height of the loaded image.
    $iW = _GDIPlus_ImageGetWidth($hImage)
    $iH = _GDIPlus_ImageGetHeight($hImage)

    ; Clone the loaded image and use it to set new pixel colors
    $hBitmap = _GDIPlus_BitmapCloneArea($hImage, 0, 0, $iW, $iH)

    ; New pixel color to set on the clone image (Red)
    $iNewPixel = 0xFFFF0000

    ; Progress bar so you can see how it's going.
    ProgressOn("Progres of GDIPlus Get & Set Pixel", "Geting && Setting Pixels...")

    ; Loop through the pixels of the loaded image.
    For $iY = 0 To $iH - 1
        For $iX = 0 To $iW - 1

            ; Get each pixel in the loaded image
            $iGetPixel = _GDIPlus_BitmapGetPixel($hImage, $iX, $iY)

            ; If the current pixel is the same as the first pixel set a new pixel color to the clone.
            If $iGetPixel = $iFirstPixel Then _GDIPlus_BitmapSetPixel($hBitmap, $iX, $iY, $iNewPixel)

            ; Update the progress bar.
            $iCnt += 1
            ProgressSet((100 / ($iW * $iH)) * $iCnt, "Got Pixel X,Y,Color: " & $iX & "," & $iY & ",0x" & Hex($iGetPixel))
        Next
    Next

    ; Turn off the progress bar
    ProgressOff()

    ; Create a Gui to show the before and after pixels
    $hGui = GUICreate("GDI+", $iW * 2, $iH + 33)
    GUICtrlCreateLabel("Before (Get Pixel)", 0, 0, $iW, 16)
    GUICtrlSetColor(-1, BitAND($iFirstPixel, 0xFFFFFF))
    GUICtrlCreateLabel("After (Set Pixel)", $iW, 0, $iW, 16)
    GUICtrlSetColor(-1, BitAND($iNewPixel, 0xFFFFFF))
    GUICtrlCreateLabel("Image Path: " & $sImagePath, 0, $iH + 17, $iW * 2, 16)
    GUISetState()
    Sleep(100)

    ; Draw the images on the Gui
    $hGraphic = _GDIPlus_GraphicsCreateFromHWND($hGui)
    _GDIPlus_GraphicsDrawImage($hGraphic, $hImage, 0, 16)
    _GDIPlus_GraphicsDrawImage($hGraphic, $hBitmap, $iW, 16)

    ; Clean up resources
    _GDIPlus_BitmapDispose($hBitmap)
    _GDIPlus_ImageDispose($hImage)
    _GDIPlus_GraphicsDispose($hGraphic)

    ; Shutdown GDIPlus
    _GDIPlus_Shutdown()

    ; Loop until user exits
    Do
    Until GUIGetMsg() = $GUI_EVENT_CLOSE
EndFunc   ;==>_Main

; #FUNCTION# ====================================================================================================================
; Name...........: _GDIPlus_BitmapGetPixel
; Description ...: Get a specfied size thumbnail image objedt from an existing image objedt.
; Syntax.........: _GDIPlus_BitmapGetPixel($hBitmap, $iX, $iY)
; Parameters ....: $hBitmap   - Handle to a bitmap object.
;                  $iX        - Integer that specifies the x coordinate of the pixel to get.
;                  $iY        - Integer that specifies the y coordinate of the pixel to get.
; Return values .: Success    - ARGB color of the pixel
;                  Failure    - -1 and @error is set
; Author ........: Smashly
; Modified.......:
; Remarks .......:
; Related .......:
; Link ..........; @@MsdnLink@@ GdipBitmapGetPixel
; Example .......; Yes
; ===============================================================================================================================
Func _GDIPlus_BitmapGetPixel($hBitmap, $iX, $iY)
    Local $aResult

    $aResult = DllCall($ghGDIPDll, "int", "GdipBitmapGetPixel", "hwnd", $hBitmap, "int", $iX, "int", $iY, "int*", 0)
    If @error Then Return SetError(@error, @extended, -1)
    Return SetError($aResult[0], 0, $aResult[4])
EndFunc   ;==>_GDIPlus_BitmapGetPixel

; #FUNCTION# ====================================================================================================================
; Name...........: _GDIPlus_BitmapSetPixel
; Description ...: sets the color of a specified pixel in a bitmap object.
; Syntax.........: _GDIPlus_BitmapSetPixel($hBitmap, $iX, $iY, $iARGB)
; Parameters ....: $hBitmap   - Handle to a bitmap object.
;                  $iX        - Integer that specifies the x coordinate of the pixel to set.
;                  $iY        - Integer that specifies the y coordinate of the pixel to set.
;                  $iARGB     - ARGB color to set the pixel.
; Return values .: Success    - True
;                  Failure    - False and @error is set
; Author ........: Smashly
; Modified.......:
; Remarks .......:
; Related .......:
; Link ..........; @@MsdnLink@@ GdipBitmapSetPixel
; Example .......; Yes
; ===============================================================================================================================
Func _GDIPlus_BitmapSetPixel($hBitmap, $iX, $iY, $iARGB)
    Local $aResult

    $aResult = DllCall($ghGDIPDll, "int", "GdipBitmapSetPixel", "hwnd", $hBitmap, "int", $iX, "int", $iY, "int", $iARGB)
    If @error Then Return SetError(@error, @extended, False)
    Return SetError($aResult[0], 0, $aResult[0] = 0)
EndFunc   ;==>_GDIPlus_BitmapSetPixel

Cheers

Share this post


Link to post
Share on other sites
Hawkwing

Thanks :(

I'm not that experienced with anything to do with images, so the GDIplus functions where all a bit confusing >_<


The Wheel of Time turns, and Ages come and pass, leaving memories that become legend. Legend fades to myth, and even myth is long forgotten when the Age that gave it birth comes again.

Share this post


Link to post
Share on other sites
smashly

Thanks :(

I'm not that experienced with anything to do with images, so the GDIplus functions where all a bit confusing >_<

Your welcome,

Either way when it comes to images and pixel manipulation you have a couple/few current day native windows choices of gdi.

I use both gdi32 and gdiplus together.

But either methods can be confusing when learning how to use them.

gdi32 is older and seems to work quicker but lacks some current day functions that gdiplus offers.

GDIPlus does offer some neat graphic features but seems more resource demanding and at times a little slower (to me anyway).

But I do prefer to work with gdiplus as it's quite easy to use most of the functions once you get past the learning curve.

Also AutoIt help file has a lot of examples on how to use gdiplus.

When you look in the help file for gdi32 functions you'd be looking at _WinAPI functions..

But when you look in the help file for examples on how to use those functions there isn't much to look at..lol

But once again it doesn't take much to poke around the forums and net for abundant examples of use.

I think it all boils down to to the users learning curve and ease of use.

Cheers

Share this post


Link to post
Share on other sites
Malkey

Following on from my Post#4 this thread, there is an example.

;
#include <WinAPI.au3>
#include <GDIPlus.au3>
#include <Array.au3>

Dim $pixels, $iTotalReplace, $Count = 0
Local $Path = FileOpenDialog("Choose Image File", @ScriptDir & "", "Images (*.gif;*.png;*.jpg;*.bmp)| All (*.*)")
If $Path <> "" Then
    _GDIPlus_Startup()
    $hImage = _GDIPlus_ImageLoadFromFile($Path)
    $width = _GDIPlus_ImageGetWidth($hImage)
    $height = _GDIPlus_ImageGetHeight($hImage)
    $hBmp = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage)
    $aSize = DllCall('gdi32.dll', 'int', 'GetBitmapBits', 'ptr', $hBmp, 'int', 0, 'ptr', 0)
    If $aSize[0] Then
        $tBits = DllStructCreate('byte[' & $aSize[0] & ']')
        DllCall('gdi32.dll', 'int', 'GetBitmapBits', 'ptr', $hBmp, 'int', $aSize[0], 'ptr', DllStructGetPtr($tBits))
        $sHex = StringTrimLeft(DllStructGetData($tBits, 1), 2)
        ;ConsoleWrite($sHex & @CRLF)

        ; Manipulate the string, $sHex, anyway you like.
        ;Note; each pixel has format of BBGGRRAA hex format i.e. Blue, Green, Red, Alpha(transparency)
        ; eg. 00FF00FF would be fully opaque green.   0000FFFF would be fully opaque red.
        $sHex = StringRegExpReplace($sHex, "([[:xdigit:]]{8})", "\1 "); Works better with a space between pixels.
        ;ConsoleWrite($sHex & @CRLF)

        ;$sHex = StringRegExpReplace($sHex, "(.{2})(.{2})(.{2})(.{2}) ", "\3\2\1\4") ; swap red and blue colour channels

        ;===== Either this (captures 4 per pixel) =======
        ;$sHex = StringRegExpReplace($sHex, "(?i)([A-F][a-f0-9])(.{2})(.{2})(.{2}) ", "00\2${3}FF ") ;
        ;ConsoleWrite("Percentage of pixels with Blue channel >= 0xA0 in image = " & Round(@extended * 100 / ($width * $height * 4), 2) & "%" & @CRLF)
        ;OR this (captures 2 per pixel)
        $sHex = StringRegExpReplace($sHex, "(?i)([A-F][a-f0-9])(.{6}) ", "00\2 ") 
        ConsoleWrite("Percentage of pixels with Blue channel >= 0xA0 in image = " & Round(@extended * 100 / ($width * $height * 2), 2) & "%" & @CRLF)
        ; =========================

    EndIf

    DllStructSetData($tBits, 1, "0x" & StringStripWS($sHex, 8))
    DllCall("gdi32", "int", "SetBitmapBits", "ptr", $hBmp, 'int', $aSize[0], 'ptr', DllStructGetPtr($tBits))

    $hImageNew = _GDIPlus_BitmapCreateFromHBITMAP($hBmp)
    _GDIPlus_ImageSaveToFile($hImageNew, @DesktopCommonDir & "\Test.png")
    ShellExecute(@DesktopCommonDir & "\Test.png")

    _WinAPI_DeleteObject($hImageNew)
    _WinAPI_DeleteObject($hBmp)
    _GDIPlus_ImageDispose($hImage)
    _GDIPlus_Shutdown()
EndIf
;

This uses 'GetBitmapBits' to get the pixels, and uses "SetBitmapBits" to write the pixels back. These are both export functions from the 'gdi32.dll' file. And therefore, the Alpha channel (transparency) changes of the pixels will not show. For transparency changes _GDIPLUS_ LockBits/UnlockBits method works.

Then, with either method, the string containing all the pixels can be modified, or information about the pixels can be gathered using string functions.

I have found using string functions are much faster than creating an array then using the array then writing the array back to a string.

By commenting out and un-commenting in the script, there are two similar ways to obtain the percentage of pixels with a blue colour channel >= 0xA0 in image, and:

A method to swap red and blue colour channels of each pixel of the image.

smashly

I agree with all you wrote Post#9.

insightful.

Share this post


Link to post
Share on other sites
monoscout999

Personally, I would avoid creating arrays like the plague, and get any required info from the pixels with regular expressions.

;
;Ref:-  [url="http://www.autoitscript.com/forum/index.php?s=&showtopic=86773&view=findpost&p=622869"]http://www.autoitscript.com/forum/index....=&showtopic=86773&view=findpost&p=622869[/url]
#include <WinAPI.au3>
#include <GDIPlus.au3>
#include <Array.au3>

Dim $pixels, $iTotalReplace, $Count = 0
Local $Path = FileOpenDialog("Choose Image File", @ScriptDir & "", "Images (*.gif;*.png;*.jpg;*.bmp)| All (*.*)")
If $Path <> "" Then
    _GDIPlus_Startup()
    $hImage = _GDIPlus_ImageLoadFromFile($Path)
    $width = _GDIPlus_ImageGetWidth($hImage)
    $height = _GDIPlus_ImageGetHeight($hImage)
    $hBmp = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage)
    $aSize = DllCall('gdi32.dll', 'int', 'GetBitmapBits', 'ptr', $hBmp, 'int', 0, 'ptr', 0)
    If $aSize[0] Then
        $tBits = DllStructCreate('byte[' & $aSize[0] & ']')
        DllCall('gdi32.dll', 'int', 'GetBitmapBits', 'ptr', $hBmp, 'int', $aSize[0], 'ptr', DllStructGetPtr($tBits))
        $sHex = Hex(DllStructGetData($tBits, 1))
        $sHex = StringRegExpReplace($sHex, "([[:xdigit:]]{6})(FF)", "\1 ")
        Local $pix[$height][$width], $aTemp
        Local $aArr = StringRegExp($sHex, "(.{" & ($width * 7) & "})", 3)
        ;_ArrayDisplay($aArr)
        For $x = 0 To UBound($aArr) - 1
            $aTemp = StringRegExp($aArr[$x] & " ", "(.{6}) ", 3)
            For $y = 0 To UBound($aTemp) - 1
                $pix[$x][$y] = StringRegExpReplace($aTemp[$y], "(.{2})(.{2})(.{2})", "\3\2\1") ; To RGB format
            Next
        Next
    EndIf

    _ArrayDisplay($pix, $width & "x" & $height & $Path)
    _WinAPI_DeleteObject($hBmp)
    _GDIPlus_ImageDispose($hImage)
    _GDIPlus_Shutdown()
EndIf
;

What a great job... i must say that is a little disapointing when i spend 2 hours of my life tryng to make something well at the end someone do the same job but better than you ever can..... -.- ..

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  

×

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.