Jump to content

Recommended Posts

Posted

In javascript you can get all the pixel colours of a large image in and instant with canvas.getImageData

but for autoit pixelgetcolor only returns a single pixel hence i have to use a loop to get all pixelcolors of an image but it can take quite a long time if the image is large enough.

Are there any ways to get array of pixelcolour of an image quickly?

Posted (edited)
2 hours ago, cyxstudio said:

get array of pixelcolour of an image

#include <ScreenCapture.au3>

$hBitmap = _ScreenCapture_Capture()

Global $tSize = _WinAPI_GetBitmapDimension($hBitmap), _
$iWidth = $tSize.X, $iHeight = $tSize.Y, $iIndex, _
$iSize = $iWidth * $iHeight, $aPixels[$iHeight][$iWidth], _
$tBits = DllStructCreate("dword[" & $iSize & "]")
_WinAPI_GetBitmapBits($hBitmap, 4 * $iSize, DllStructGetPtr($tBits))
_WinAPI_DeleteObject($hBitmap)
For $i = 0 To $iHeight - 1
  For $j = 0 To $iWidth - 1
    $iIndex += 1
    $aPixels[$i][$j] = DllStructGetData($tBits, 1, $iIndex)
  Next
Next

;~ #include <Array.au3>
;~ _ArrayDisplay($aPixels)

 

Edited by InnI
Posted (edited)

@cyxstudio & @InnI

I would not recommend using _WinAPI_GetBitmapBits.  GetBitMapBits() is not impossible to use, but a lot harder because you need to "figure out" the format of the pixel information returned and extract the desired information.  There are lots of possible formats, it would be a pain.  Better use _WinAPI_GetDIBits.  GetDIBits will converts the pixel information from the stored format to any format you want.

But the best tool IMO remains GDI+.

 

Edited by Nine
Posted (edited)

Hi,

the question is, why does anyone need an "AutoIt-Array of Pixels", every bitmap IS an array of width x height "pixels". 

So reading

$aPixels[$i][$j] = DllStructGetData($tBits, 1, $iIndex)

causes me physical pain...the slowest and wasteful memory method to "store" a bitmap...which is by the way loaded in RAM at this time...

Not that i prefer _GDIPlus_BitmapLockBits to get a pointer to a bitmap or CreateDIBSection (which gives you pointer/handle/DC...) but once you got the pointer, you can easily catch the color of the x- and y-koordinates by simply addressing it. 

$color = DllStructGetData($tBits, 1, ($Width*$y + $x)   ;x and y are the koordinates (0-based) of the "pixel" in the bitmap

 

Yes, AutoIt is very slow with calculations within nested loops, but dllstructgetdata() is as fast as $aPixels[$i][$j].

Very much faster are all native String-Functions in AutoIt. You can use them to find or manipulate "colors" in a bitmap:

$tBits = DllStructCreate("char[" & $iSize*4 & "]")  ;every ARGB is a "word" of 4 char

 gives you access to a "string". So a "pixelsearch" is easily and superfast done with a StringInstr()...

 

Edited by AndyG
Posted
1 hour ago, AndyG said:

Very much faster are all native String-Functions in AutoIt. You can use them to find or manipulate "colors" in a bitmap:


$tBits = DllStructCreate("char[" & $iSize*4 & "]")  ;every ARGB is a "word" of 4 char

 gives you access to a "string". So a "pixelsearch" is easily and superfast done with a StringInstr()...

Hmmm, I am kind of skeptical.  You seem to pretend that we could use struct as an input to standard function of autoit like StringInStr().  Make my day, show me an example...

Posted
12 hours ago, Nine said:

show me an example

Get an array of pixels of a certain color

#include <ScreenCapture.au3>
#include <Array.au3>

$iColor = 0xFF0000 ; red

$hBitmap = _ScreenCapture_Capture()
Global $iIndex, $tSize = _WinAPI_GetBitmapDimension($hBitmap), _
$iWidth = $tSize.X, $iHeight = $tSize.Y, $iSize = $iWidth * $iHeight, _
$aPixels[$iSize + 1][2]

; DllStructGetData test
$iTime = TimerInit()
$tBits = DllStructCreate("dword[" & $iSize & "]")
_WinAPI_GetBitmapBits($hBitmap, $iSize * 4, DllStructGetPtr($tBits))
For $i = 0 To $iHeight - 1
  For $j = 0 To $iWidth - 1
    $iIndex += 1
    If BitAND(DllStructGetData($tBits, 1, $iIndex), 0x00FFFFFF) = $iColor Then
      $aPixels[0][0] += 1
      $aPixels[$aPixels[0][0]][0] = $j
      $aPixels[$aPixels[0][0]][1] = $i
    EndIf
  Next
Next
ReDim $aPixels[$aPixels[0][0] + 1][2]
ConsoleWrite("DllStructGetData: " & Round(TimerDiff($iTime)) & "ms" & @CRLF)
_ArrayDisplay($aPixels)

; StringInStr test
$iTime = TimerInit()
$tBits = DllStructCreate('byte[' & $iSize * 4 & ']')
_WinAPI_GetBitmapBits($hBitmap, $iSize * 4, DllStructGetPtr($tBits))
$sText = StringTrimLeft(DllStructGetData($tBits, 1), 2)
$iStep = $iWidth * 8
Dim $aPixels[$iSize + 1][2], $aLines[$iHeight], $c = 0
For $i = 1 To StringLen($sText) Step $iStep
  $aLines[$c] = StringMid($sText, $i, $iStep)
  $c += 1
Next
Dim $iPos, $iStart, $iLen = StringLen($aLines[0])
$iColor = StringRegExpReplace(Hex($iColor, 6), "(.{2})(.{2})(.{2})", "$3$2$1")
For $i = 0 To $iHeight - 1
  $iStart = 1
  While $iStart <= $iLen
    $iPos = StringInStr($aLines[$i], $iColor, 1, 1, $iStart)
    If $iPos Then
      If Mod($iPos - 1, 8) Then
        $iStart = $iPos + 2
        ContinueLoop
      EndIf
      $aPixels[0][0] += 1
      $aPixels[$aPixels[0][0]][0] = ($iPos - 1) / 8
      $aPixels[$aPixels[0][0]][1] = $i
      $iStart = $iPos + 8
    Else
      ExitLoop
    EndIf
  WEnd
Next
ReDim $aPixels[$aPixels[0][0] + 1][2]
ConsoleWrite("StringInStr: " & Round(TimerDiff($iTime)) & "ms" & @CRLF)
_ArrayDisplay($aPixels)

_WinAPI_DeleteObject($hBitmap)

 

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
  • Recently Browsing   0 members

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