Jump to content

PixelGetColor speed issues


Xibalba
 Share

Recommended Posts

This script takes a total of ~6 seconds for me, each test taking ~1 sec:

Global $wnd=WinGetHandle("[ACTIVE]")
Global $total_time
Global $result



$n1 = 60000
$start_time = TimerInit()
For $i = 1 To $n1
  PixelGetColor(1, 1)
Next
$time1=int(TimerDiff($start_time))
$total_time += $time1
$result &= "1. PixelGetColor: same screen pixel, omitting handle parameter: " & $time1 & " ms" & @LF

Sleep(30)

$start_time = TimerInit()
For $x = 0 To 299
  For $y = 0 To 199
    PixelGetColor($x, $y)
  Next
Next
$time1=int(TimerDiff($start_time))
$total_time += $time1
$result &= "2. PixelGetColor: screen rectangle 300x200 pixels, omitting handle parameter: " & $time1 & " ms" & @LF

Sleep(30)

$n1 = 60000
$start_time = TimerInit()
For $i = 1 To $n1
  PixelGetColor(1, 1, "")
Next
$time1=int(TimerDiff($start_time))
$total_time += $time1
$result &= "3. PixelGetColor: same screen pixel, using parameter "": " & $time1 & " ms" & @LF

Sleep(30)

$start_time = TimerInit()
For $x = 0 To 299
  For $y = 0 To 199
    PixelGetColor($x, $y)
  Next
Next
$time1=int(TimerDiff($start_time))
$total_time += $time1
$result &= "4. PixelGetColor: screen rectangle 300x200 pixels, using parameter "": " & $time1 & " ms" & @LF

Sleep(30)

$n1 = 60000
$start_time = TimerInit()
For $i = 1 To $n1
  PixelGetColor(1, 1, $wnd)
Next
$time1=int(TimerDiff($start_time))
$total_time += $time1
$result &= "5. PixelGetColor: same screen pixel, using parameter [Active]: " & $time1 & " ms" & @LF

Sleep(30)

$start_time = TimerInit()
For $x = 0 To 299
  For $y = 0 To 199
    PixelGetColor($x, $y, $wnd)
  Next
Next
$time1=int(TimerDiff($start_time))
$total_time += $time1
$result &= "6. PixelGetColor: screen rectangle 300x200 pixels, using parameter [Active]: " & $time1 & " ms" & @LF

$result &= @LF
$result &= "Total time: " & $total_time & " ms" ; exluding sleep's


MsgBox(0, "mBox", $result)
  • What results do you get? (XP users particulary of interest)
  • Is my numbers normal/expected?
  • Is there any way to speed this up (staying with default functions)?

 

I've been looking for alternatives and one seems to be _GDIPlus_BitmapLockBits with a simple example available >here.

That example makes my AutoIt crash completely though (even with handle "" specified). >Another example also crashes for me, so I'm a bit lost.

Does the GDIPlus example(s) work for you?

I'd love to stay with PixelGetColor for now, if possible.

Any help greatly appreciated.

Machine:

WinXP Pro SP3

GPU 1GB GeForce

3 GB RAM

1600x1200x32

Window Classic theme

AutoIt v3.3.10.2

Link to comment
Share on other sites

I know you say you want to stay with the basic functions, but you should take a look at FastFind project in the example scripts

 

From FastFrench's description:

"- For even more performance, you can capture the content of a screen memory (SnapShot, takes about the same time as or PixelSearch PixelGetColor) then do all the research you want in this snapshots (very fast functions : nearly 1000 times as fast as the native PixelGetColor)."

Link to comment
Share on other sites

I know you say you want to stay with the basic functions, but you should take a look at FastFind project in the example scripts

 

From FastFrench's description:

"- For even more performance, you can capture the content of a screen memory (SnapShot, takes about the same time as or PixelSearch PixelGetColor) then do all the research you want in this snapshots (very fast functions : nearly 1000 times as fast as the native PixelGetColor)."

 

Yes, FastFind and _GDIPlus_BitmapLockBits are the two alternatives I've found so far.

I took the liberty to refine my benchmark script and also include FastFind (Advanced Pixel Search Library)

.

I don't know why the test results from my benchmark is a dissapointment compared to the benchmark included in FastFind v2.2, but my script shows that:

  • Using the wrapper (which works), performance is decreased by ~25%.
  • Using DLLCall directly (which doesn't seem to work, se below), performance is increased by ~25%.

 

In Test #5 and #6, the DllCall() returns an empty string - "" - for every call (pixel). Not sure why. Isn't this supposed to be the way it should be used?

;PixelGetColor vs FFGetPixel v1.0.au3

#include "FastFind.au3"
FFSetDebugMode(0) ; No debugging = fastest possible

Global $array1[30000]
Global Const $n1 = 30000
Global $array2[200][150]
Global $total_time
Global $resultStr

Func ClearArray1()
  For $i = 0 To UBound($array1) - 1
    $array1[$i] = ""
  Next
EndFunc

Func ClearArray2()
  For $i = 0 To UBound($array2, 1) - 1
    For $j = 0 To UBound($array2, 2) - 1
      $array2[$i][$j] = ""
    Next
  Next
EndFunc


; 1
$start_time = TimerInit()
For $i = 1 To $n1
  $array1[$i-1] = PixelGetColor(1, 1)
Next
$time1=int(TimerDiff($start_time))
$total_time += $time1
$resultStr &= "1. Native PixelGetColor: Top-left single screen pixel (" & $n1 & " calls): " & $time1 & " ms" & @LF

Sleep(30)
ClearArray1()

; 2
$start_time = TimerInit()
For $x = 0 To 199 ; or 299 / 199 for 60,000
  For $y = 0 To 149
    $array2[$x][$y] = PixelGetColor($x, $y)
  Next
Next
$time1=int(TimerDiff($start_time))
$total_time += $time1
$resultStr &= "2. Native PixelGetColor: Top-left screen rectangle (200x150 pixels): " & $time1 & " ms" & @LF

Sleep(30)
ClearArray2()

; 3
$start_time = TimerInit()
FFSnapShot() ; To keep it simple, a FullScreen capture here
For $i = 1 To $n1
  $array1[$i-1] = FFGetPixel(1, 1)
Next
$time1=int(TimerDiff($start_time))
$total_time += $time1
$resultStr &= "3. FFGetPixel (via Wrapper): Top-left single screen pixel (" & $n1 & " calls): " & $time1 & " ms" & @LF

Sleep(30)
ClearArray1()

; 4
$start_time = TimerInit()
For $x = 0 To 199
  For $y = 0 To 149
    $array2[$x][$y] = FFGetPixel($x, $y)
  Next
Next
$time1=int(TimerDiff($start_time))
$total_time += $time1
$resultStr &= "4. FFGetPixel (via Wrapper): Top-left screen rectangle (200x150 pixels): " & $time1 & " ms" & @LF

Sleep(30)
ClearArray2()

; 5
$start_time = TimerInit()
FFSnapShot() ; To keep it simple, a FullScreen capture here
For $i = 1 To $n1
  $array1[$i-1] = DllCall($FFDllHandle, "int", "FFGetPixel", "int", 1, "int", 1, "int", $FFLastSnap)
Next
$time1=int(TimerDiff($start_time))
$total_time += $time1
$resultStr &= "5. FFGetPixel (direct DLL): Top-left single screen pixel (" & $n1 & " calls): " & $time1 & " ms" & @LF

Sleep(30)
ClearArray1()

; 6
$start_time = TimerInit()
FFSnapShot() ; To keep it simple, a FullScreen capture here
For $x = 0 To 199
  For $y = 0 To 149
    $array2[$x][$y] = DllCall($FFDllHandle, "int", "FFGetPixel", "int", $x, "int", $y, "int", $FFLastSnap)
  Next
Next
$time1=int(TimerDiff($start_time))
$total_time += $time1
$resultStr &= "6. FFGetPixel (direct DLL): Top-left screen rectangle (200x150 pixels): " & $time1 & " ms" & @LF



; View results
$resultStr &= @LF
$resultStr &= "Total time: " & $total_time & " ms" ; excluding sleep's

MsgBox(0, "mBox", $resultStr)

I'd love to include _GDIPlus_BitmapLockBits in this benchmark script, but as mentioned in the first post - the _GDIPlus_BitmapLockBits() function call crashes completely for me.

Link to comment
Share on other sites

  • Moderators

Xibalba,

 

the _GDIPlus_BitmapLockBits() function call crashes completely

There is a typographical error in a GDI function which we have only just noticed - perhaps this is the source of your crash. Open the GDIPlus.au3 file and in the BitmapFromMemory function look for the string "GlobalUnlbck" - change it to "GlobalUnlock".

Please let me know if that stopped the crash. :)

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

Xibalba,

 

There is a typographical error in a GDI function which we have only just noticed - perhaps this is the source of your crash. Open the GDIPlus.au3 file and in the BitmapFromMemory function look for the string "GlobalUnlbck" - change it to "GlobalUnlock".

Please let me know if that stopped the crash. :)

M23

Hello,

No such typo in my GDIPlus.au3 file.

I suppose you mean this function?

Func _GDIPlus_BitmapCreateFromMemory($bImage, $hHBITMAP = False)
    If Not IsBinary($bImage) Then Return SetError(1, 0, 0)
    Local $aResult = 0
    Local Const $memBitmap = Binary($bImage) ;load image saved in variable (memory) and convert it to binary
    Local Const $iLen = BinaryLen($memBitmap) ;get binary length of the image
    Local Const $GMEM_MOVEABLE = 0x0002
    $aResult = DllCall("kernel32.dll", "handle", "GlobalAlloc", "uint", $GMEM_MOVEABLE, "ulong_ptr", $iLen) ;allocates movable memory ($GMEM_MOVEABLE = 0x0002)
    If @error Then Return SetError(4, 0, 0)
    Local Const $hData = $aResult[0]
    $aResult = DllCall("kernel32.dll", "ptr", "GlobalLock", "handle", $hData)
    If @error Then Return SetError(5, 0, 0)
    Local $tMem = DllStructCreate("byte[" & $iLen & "]", $aResult[0]) ;create struct
    DllStructSetData($tMem, 1, $memBitmap) ;fill struct with image data
    DllCall("kernel32.dll", "bool", "GlobalUnlock", "handle", $hData) ;decrements the lock count associated with a memory object that was allocated with GMEM_MOVEABLE
    If @error Then Return SetError(6, 0, 0)
    Local Const $hStream = _WinAPI_CreateStreamOnHGlobal($hData) ;creates a stream object that uses an HGLOBAL memory handle to store the stream contents
    If @error Then Return SetError(2, 0, 0)
    Local Const $hBitmap = _GDIPlus_BitmapCreateFromStream($hStream) ;creates a Bitmap object based on an IStream COM interface
    If @error Then Return SetError(3, 0, 0)
    DllCall("oleaut32.dll", "long", "DispCallFunc", "ptr", $hStream, "ulong_ptr", 8 * (1 + @AutoItX64), "uint", 4, "ushort", 23, "uint", 0, "ptr", 0, "ptr", 0, "str", "") ;release memory from $hStream to avoid memory leak
    If $hHBITMAP Then
        Local Const $hHBmp = __GDIPlus_BitmapCreateDIBFromBitmap($hBitmap) ;supports GDI transparent color format
        _GDIPlus_BitmapDispose($hBitmap)
        Return $hHBmp
    EndIf
    Return $hBitmap
EndFunc   ;==>_GDIPlus_BitmapCreateFromMemory

"GlobalUnlbck" doesn't exist anywhere in GDIPlus.au3 file for me.

v3.3.10.2

Link to comment
Share on other sites

  • Moderators

Xibalba,

Must just be in the Beta then - sorry to have raised your hopes without return. ;)

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

Also, can someone help me with a simple script to use the GDIPlus equivalent to PixelGetColor (DllStructGetData($BitmapData, "Scan0")?).

Just a x,y check of what is currently visible on my screen (and not a specific handle! - what happens if we try to use "" anyway?).

What functions do I use? And how?

_GDIPlus_BitmapCreateFromMemory?
_GDIPlus_BitmapCreateFromGraphics?
_GDIPlus_BitmapCreateFromScan0?

Most examples in the forums are, as said, crashing for me, so a minimal script to test would be awesome (to at least get closer to understand why it's crashing)

Link to comment
Share on other sites

My endgame is live Picture- and Video-analysis and manipulation - so speed is of most importance.

Rest assured though, it's not against any of the forum rules.

If anyone know the GDIPlus equivalent to PixelGetColor(), with a minimalistic example using what is currently shown on the screen, I'd be very grateful.

Thx

Edited by Xibalba
Link to comment
Share on other sites

This is my result from your test, FF is clearly working for me, did you put the dlls in your script directory?

1. Native PixelGetColor: Top-left single screen pixel (30000 calls): 542230 ms
2. Native PixelGetColor: Top-left screen rectangle (200x150 pixels): 501217 ms
3. FFGetPixel (via Wrapper): Top-left single screen pixel (30000 calls): 797 ms
4. FFGetPixel (via Wrapper): Top-left screen rectangle (200x150 pixels): 744 ms
5. FFGetPixel (direct DLL): Top-left single screen pixel (30000 calls): 497 ms
6. FFGetPixel (direct DLL): Top-left screen rectangle (200x150 pixels): 494 ms

Total time: 1045979 ms

Laptop:

Intel Core Duo

Nvidia Quadro NVS 160M

4gb RAM

Windows 7 (32 bit)

Link to comment
Share on other sites

This is my result from your test, FF is clearly working for me, did you put the dlls in your script directory?

1. Native PixelGetColor: Top-left single screen pixel (30000 calls): 542230 ms

2. Native PixelGetColor: Top-left screen rectangle (200x150 pixels): 501217 ms

3. FFGetPixel (via Wrapper): Top-left single screen pixel (30000 calls): 797 ms

4. FFGetPixel (via Wrapper): Top-left screen rectangle (200x150 pixels): 744 ms

5. FFGetPixel (direct DLL): Top-left single screen pixel (30000 calls): 497 ms

6. FFGetPixel (direct DLL): Top-left screen rectangle (200x150 pixels): 494 ms

Total time: 1045979 ms

Laptop:

Intel Core Duo

Nvidia Quadro NVS 160M

4gb RAM

Windows 7 (32 bit)

 

Thanks a lot for testing. My numbers:

1. Native PixelGetColor: Top-left single screen pixel (30000 calls): 496 ms
2. Native PixelGetColor: Top-left screen rectangle (200x150 pixels): 489 ms
3. FFGetPixel (via Wrapper): Top-left single screen pixel (30000 calls): 640 ms
4. FFGetPixel (via Wrapper): Top-left screen rectangle (200x150 pixels): 632 ms
5. FFGetPixel (direct DLL): Top-left single screen pixel (30000 calls): 415 ms
6. FFGetPixel (direct DLL): Top-left screen rectangle (200x150 pixels): 421 ms

Total time: 3093 ms

Of course I have the DLL files =) Your 1 & 2 results seems awfully slow?

Link to comment
Share on other sites

My laptop is pretty old.. I decided to test it on my computer at home to see if it was faster, but no.. To me your 1 & 2 results seem super fast, maybe the function was optimized in AutoIt? Im using version 3.3.8.1

Results:

1. Native PixelGetColor: Top-left single screen pixel (30000 calls): 547799 ms
2. Native PixelGetColor: Top-left screen rectangle (200x150 pixels): 542538 ms
3. FFGetPixel (via Wrapper): Top-left single screen pixel (30000 calls): 395 ms
4. FFGetPixel (via Wrapper): Top-left screen rectangle (200x150 pixels): 331 ms
5. FFGetPixel (direct DLL): Top-left single screen pixel (30000 calls): 255 ms
6. FFGetPixel (direct DLL): Top-left screen rectangle (200x150 pixels): 259 ms

Computer:

Intel Core i7-3770

AMD Radeon HD7800

8gb RAM

Windows 8 (64 bit)

Link to comment
Share on other sites

My laptop is pretty old.. I decided to test it on my computer at home to see if it was faster, but no.. To me your 1 & 2 results seem super fast, maybe the function was optimized in AutoIt? Im using version 3.3.8.1

Results:

1. Native PixelGetColor: Top-left single screen pixel (30000 calls): 547799 ms

2. Native PixelGetColor: Top-left screen rectangle (200x150 pixels): 542538 ms

3. FFGetPixel (via Wrapper): Top-left single screen pixel (30000 calls): 395 ms

4. FFGetPixel (via Wrapper): Top-left screen rectangle (200x150 pixels): 331 ms

5. FFGetPixel (direct DLL): Top-left single screen pixel (30000 calls): 255 ms

6. FFGetPixel (direct DLL): Top-left screen rectangle (200x150 pixels): 259 ms

Computer:

Intel Core i7-3770

AMD Radeon HD7800

8gb RAM

Windows 8 (64 bit)

 

You probably need to disable DWM/Aero, which should speed things up.

Link to comment
Share on other sites

You are right. I disabled the UxSms service and tried again on my laptop. It speed up the native function, but seems to be inconsistent.. Might have been that before also, just notice alot higher execution time for the FF functions so i tried one more run.. First time the function #5 was fastest, second run fucntion #1 was fastest.

Run 1:

1. Native PixelGetColor: Top-left single screen pixel (30000 calls): 1935 ms
2. Native PixelGetColor: Top-left screen rectangle (200x150 pixels): 2982 ms
3. FFGetPixel (via Wrapper): Top-left single screen pixel (30000 calls): 3579 ms
4. FFGetPixel (via Wrapper): Top-left screen rectangle (200x150 pixels): 3545 ms
5. FFGetPixel (direct DLL): Top-left single screen pixel (30000 calls): 1392 ms
6. FFGetPixel (direct DLL): Top-left screen rectangle (200x150 pixels): 1464 ms

Run 2:

1. Native PixelGetColor: Top-left single screen pixel (30000 calls): 753 ms
2. Native PixelGetColor: Top-left screen rectangle (200x150 pixels): 811 ms
3. FFGetPixel (via Wrapper): Top-left single screen pixel (30000 calls): 2651 ms
4. FFGetPixel (via Wrapper): Top-left screen rectangle (200x150 pixels): 2842 ms
5. FFGetPixel (direct DLL): Top-left single screen pixel (30000 calls): 998 ms
6. FFGetPixel (direct DLL): Top-left screen rectangle (200x150 pixels): 1263 ms

Link to comment
Share on other sites

My endgame is live Picture- and Video-analysis and manipulation - so speed is of most importance.

Rest assured though, it's not against any of the forum rules.

If anyone know the GDIPlus equivalent to PixelGetColor(), with a minimalistic example using what is currently shown on the screen, I'd be very grateful.

Thx

Sorry, but can you provide the name of the application you are using? You haven't told us anything we didn't already know already. If anything giving the name of the app may provide helpful information and may provide a much better approach than pixel searching.

Link to comment
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
 Share

×
×
  • Create New...