Sign in to follow this  
Followers 0
emog

PixelGetColor problems - Painfully slow in Vista-64bit

7 posts in this topic

#1 ·  Posted (edited)

Hi guys, I'm using PixelGetColor to scan an image into a long array of coloured pixels.

Problem is it's lightning fast on Windows XP 32-bit, takes about two seconds to read a 64x64 image (4096 pixels total), however running the same script on Vista takes nearly a full minute. Unfortunately now I need to scale things up by scanning much larger images, so the performance loss is really hitting hard.

Unfortunately I don't have XP on this system any more. However I keep a very tight ship on this Vista system, with no unnecessary programs/widgets installed nor running in the background.

Really simple script:

$numberofpixels = ($xmax - $xmin) * ($ymax - $ymin) 
Global $pixelarray[$numberofpixels]
$arraycounter = 0
For $yaxis = $ymin to $ymax Step 1
        For $xaxis = $xmin to $xmax Step 1
            $pixelarray[$arraycounter] = PixelGetColor($xaxis, $yaxis)
            $arraycounter = $arraycounter + 1
        Next
    Next
msgbox(0, "Script", "Finished")

... it just reads the pixels of an image left to right, line by line, storing all the pixel colour data in an array.

Anything I can do? Disabling Aero/transparency in Vista doesn't speed things up, either.

Much appreciated,

eMog.

Edited by emog

Share this post


Link to post
Share on other sites



theres other way to get the entire raw data... imagine that windows always keep the bitmap data on the memory because is too fast... there are functions that extract that data whitout rescaning the screen for it... take a look at this that i wrote... you will get the idea... all the credits are for the people who wrote the functions...

#include <misc.au3>
#include <WindowsConstants.au3>
#include <winapi.au3>
#include <Array.au3>
#include <GUIConstantsEx.au3>
#include <ScreenCapture.au3>
HotKeySet("{esc}", "_exit")
Global $pos
$Gui = GUICreate("selection tool", 300, 50, -1, -1)
$bnSelect = GUICtrlCreateButton("start select", 0, 0, 100, 50)
$bnShowRaw = GUICtrlCreateButton("ShowRawData", 100, 0, 100, 50)
GUICtrlSetState($bnShowRaw, $GUI_DISABLE)
$bnShowFromRD = GUICtrlCreateButton("ShowScrenfromRD", 200, 0, 100, 50)
GUICtrlSetState($bnShowFromRD, $GUI_DISABLE)
GUISetState()
While 1
    $nmsg = GUIGetMsg()
    Switch $nmsg
        Case -3
            _exit()
        Case $bnSelect
            $sel = _drawbox()
            If IsArray($sel) Then
                GUICtrlSetState($bnShowRaw, $GUI_ENABLE)
            EndIf
        Case $bnShowRaw
            $begin1 = TimerInit()
            $rawdata = _Getrawdata($sel[4])
            If Not @error Then
                ConsoleWrite("Time in ms to do all the work = " & TimerDiff($begin1) & @CRLF)
                GUICtrlSetState($bnShowFromRD, $GUI_ENABLE)
                _arraydisplay($rawdata)
            EndIf
        Case $bnShowFromRD
            $ShowGUI = GUICreate("screen show", $sel[2], $sel[3], $sel[0], $sel[1], $WS_POPUP)
            $graph = GUICtrlCreateGraphic(0, 0, $sel[2], $sel[3])
            _printrawdata($rawdata, $graph)
            GUISetState(@SW_SHOW, $ShowGUI)
            GUICtrlSetState($graph, $GUI_SHOW)
            MsgBox(0, "tip", "Press ´BackSpace´key to close Show window")
            Do
                Sleep(50)
            Until _IsPressed("08") ; BackSpace
            GUIDelete($ShowGUI)
    EndSwitch
WEnd
Func _Exit()
    Exit
EndFunc   ;==>_Exit
Func _drawbox()
    $hGui = GUICreate("selectionbox", @DesktopWidth, @DesktopHeight, 0, 0, $WS_POPUP, $WS_EX_TOPMOST)
    GUISetBkColor(0x000000, $hGui)
    WinSetTrans($hGui, "", 20)
    GUISetState()
    GUISetCursor(3)
    $DLL = DllOpen("user32.dll")
    While Not _IsPressed("01", $DLL)
        $pos = MouseGetPos()
        Sleep(10)
    WEnd
    $iX = $pos[0]
    $iW = 0
    $iY = $pos[1]
    $iH = 0
    While _IsPressed(01, $DLL)
        $pos2 = MouseGetPos()
        Select
            Case $pos2[0] < $pos[0]
                $iX = $pos2[0]
                $iW = $pos[0] - $pos2[0]
            Case $pos[0] < $pos2[0]
                $iX = $pos[0]
                $iW = $pos2[0] - $pos[0]
        EndSelect
        Select
            Case $pos2[1] < $pos[1]
                $iY = $pos2[1]
                $iH = $pos[1] - $pos2[1]
            Case $pos[1] < $pos2[1]
                $iY = $pos[1]
                $iH = $pos2[1] - $pos[1]
        EndSelect
        _GUICreateInvRect($hGui, $iX, $iY, $iW, $iH)
    WEnd
    GUIDelete($hGui)
    DllClose($DLL)
    $begin = TimerInit()
    $hBMP = _ScreenCapture_Capture("", $iX, $iY, $iW + $iX, $iH + $iY)
    ConsoleWrite("Time in ms. to take a screen from a " & $iW & "X" & $iH & " Area = " & TimerDiff($begin) & @CRLF)
    Local $selectedpos[5] = [$iX, $iY, $iW, $iH, $hBMP]
    Return $selectedpos
EndFunc   ;==>_drawbox

Func _GUICreateInvRect($hWnd, $iX, $iY, $iW, $iH)
    $hMask_1 = _WinAPI_CreateRectRgn(0, 0, @DesktopWidth, $iY)
    $hMask_2 = _WinAPI_CreateRectRgn(0, 0, $iX, @DesktopHeight)
    $hMask_3 = _WinAPI_CreateRectRgn($iX + $iW, 0, @DesktopWidth, @DesktopHeight)
    $hMask_4 = _WinAPI_CreateRectRgn(0, $iY + $iH, @DesktopWidth, @DesktopHeight)
    _WinAPI_CombineRgn($hMask_1, $hMask_1, $hMask_2, 2)
    _WinAPI_CombineRgn($hMask_1, $hMask_1, $hMask_3, 2)
    _WinAPI_CombineRgn($hMask_1, $hMask_1, $hMask_4, 2)
    _WinAPI_DeleteObject($hMask_2)
    _WinAPI_DeleteObject($hMask_3)
    _WinAPI_DeleteObject($hMask_4)
    _WinAPI_SetWindowRgn($hWnd, $hMask_1, 1)
EndFunc   ;==>_GUICreateInvRect
Func _Getrawdata($hBMP) ; Credits to Malkey http://www.autoitscript.com/forum/index.php?app=forums&module=forums&section=findpost&pid=718522
    _GDIPlus_Startup()
    $hBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hBMP)
    $width = _GDIPlus_ImageGetWidth($hBitmap)
    $height = _GDIPlus_ImageGetHeight($hBitmap)
    Local $aSize = DllCall('gdi32.dll', 'int', 'GetBitmapBits', 'ptr', $hBMP, 'int', 0, 'ptr', 0)
    If Not @error Then
        $tBits = DllStructCreate('byte[' & $aSize[0] & ']')
        $begin = TimerInit()
        DllCall('gdi32.dll', 'int', 'GetBitmapBits', 'ptr', $hBMP, 'int', $aSize[0], 'ptr', DllStructGetPtr($tBits))
        $sHex = Hex(DllStructGetData($tBits, 1))
        ConsoleWrite("Time in ms. to get the rawdata and save it in a variable = " & TimerDiff($begin) & @CRLF)
        $begin = TimerInit()
        $sHex = StringRegExpReplace($sHex, "([[:xdigit:]]{6})(FF)", "\1 ")
        Local $pix[$height][$width], $aTemp
        $aArr = StringRegExp($sHex, "(.{" & ($width * 7) & "})", 3)
        ConsoleWrite("Time in ms to preparate the rawdata to be indexed in an array = " & TimerDiff($begin) & @CRLF)
        $porcent = $height*$width/100
        ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $porcent = ' & $porcent & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
        $begin = TimerInit()
        local $a = 1
        For $width = 0 To UBound($aArr) - 1
            $aTemp = StringRegExp($aArr[$width] & " ", "(.{6}) ", 3)
            For $height = 0 To UBound($aTemp) - 1
                $pix[$width][$height] = StringRegExpReplace($aTemp[$height], "(.{2})(.{2})(.{2})", "\3\2\1") ; To RGB format
            Next
        Next
        ConsoleWrite("Time in ms to put the entire raw in an array = " & TimerDiff($begin) & @CRLF)
    Else
        SetError(@error)
        Return ""
    EndIf
    _GDIPlus_BitmapDispose($hBitmap)
    _WinAPI_DeleteObject($hBMP)
    _GDIPlus_Shutdown()
    Return $pix
EndFunc   ;==>_Getrawdata
Func _printrawdata($ArBMPRawdata, $hgraphic)
    $begin = TimerInit()
    For $x = 0 To UBound($ArBMPRawdata) - 1
        For $y = 0 To UBound($ArBMPRawdata, 2) - 1
            $color = "0x" & $ArBMPRawdata[$x][$y]
            GUICtrlSetGraphic($hgraphic, $GUI_GR_COLOR, $color)
            GUICtrlSetGraphic($hgraphic, $GUI_GR_PIXEL, $y, $x) ; :S
            GUICtrlSetState($graph, $GUI_SHOW)
        Next
    Next
    ConsoleWrite("Time in ms to print from the rawdata using GuictrlsetGraphics = " & TimerDiff($begin) & @CRLF)
EndFunc   ;==>_printrawdata

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

Many thanks for your time but my level of coding is near enough absolute beginner and unfortunately I can't even begin to follow the above, my apologies. Seems like using a sledgehammer to crack a nut. I really don't require a GUI or any fancy mouse selection tool or similar as the screen co-ordinates and data display (tooltip, msgbox and _arraydisplay) are all taken care of with my existing code.

Thanks.

Edited by emog

Share this post


Link to post
Share on other sites

What i want to say is that are APIs that get the PixelInfo of Any area you want... the method Using for next loops and PixelGetColor always is a little slow.... theres a lot of post asking for the same on the forum i get the method that i show you avobe from one of those... if as you said you dont want to complicate anymore you can try the that is a lot more faster and simple usage...

Share this post


Link to post
Share on other sites

The only thing I have ever seen slow that down is Aeroglass, and since you have disabled it, I cant see whay its so slow.

Thats assuming of course that your logic is sound and you are not getting more pixels than you need.


AutoIt Absolute Beginners    Require a serial    Pause Script    Video Tutorials by Morthawt   ipify 

Monkey's are, like, natures humans.

Share this post


Link to post
Share on other sites

Hello.

I also have this problem and I slove it by changing the background of the OS to a simple one.

Good luck.

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  
Followers 0