# PixelSearch a region for a cluster of pixels.

## Recommended Posts

• Moderators

On a topic here: http://www.autoitscript.com/forum/index.php?showtopic=95554

I was trying to understand what the OP was trying to do, I think I may have still missed the boat with him, but this function came out of it (so most of this is a simple copy and paste).

Things to know.

• You must send an array of colors, these colors will be left to right, top to bottom (and must be the same ubound as the width*height).

So if I have a 2 pixel width, and a 2 pixel height area I want to search, and for this example, my starting point is 0 for both x and y.

My color array is [0xFF0000, 0x00FF00, 0x0000FF, 0x00FFFF]

x-0, y-0 = 0xFF0000

x-1, y-0 = 0x00FF00

x-0, y-1 = 0x0000FF

x-1, y-1 = 0x00FFFF

In that example you see how you would set your array up (zero based array).

• Shade variation must also be an array. The ubound must be the same as the ubound of the color array (width of pixel search * height of pixel search).

You can do different shade variations for each pixel. My example will just show a constant variation of 3 for simplicity.

• The parameters:

x-start = the x starting position of the total search area

y-start = the y starting position of the total search area

x-end = the x ending position of the total search area

y-end = the y ending position of the total search area

width = total number of pixels to search (left to right) once first pixel color is found

height = total number of pixels to search (top to bottom) once the first pixel color is found

colors = array of colors to search in specific order (explained above) one the match is found [0] is used for the first search pattern

shade = array of shade variations for each position found [0] is used for the first search pattern

step = number of steps to make like pixelsearch main function, this is only used in the main search for patterns, once a match on the first color is found, the rest of the search is step 1

hwnd = handle to window if you want to use one

quick match = If you only want the first match, set to true, and the array [n][n] will hold your values, otherwise default is to return all matches

• The return is a two dimensional array:

[0][0] = total number of matches found

[n][0] = x starting position the match was found

[n][1] = y starting position the match was found

• Errors:

1 = the color variable sent was either not an array or the ubound did not match the total value of the width*height

2 = the shade variable sent was either not an array or the ubound did not match the total value of the width*height

3 = No match found

Guess I could have written a header, just didn't feel like it.

```; Example
#include <array.au3>

; Array of colors UBound must match number of pixels searching
Local \$a_clr[9] = [0xFF4AA5, 0xFF4AA5, 0xFF4AA5, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFF4AA5, 0xFF4AA5]
; Array of variations UBound must match number of pixels searching
Local \$a_vrn[9] = [3,3,3,3,3,3,3,3,3]

Local \$a_found = _Pixel_Region_FindMatch(0, 0, 1678, 945, 3, 3, \$a_clr, \$a_vrn)
If @error Then
MsgBox(0, "Error", "Error was: " & @error)
Else
_ArrayDisplay(\$a_found)
EndIf

Func _Pixel_Region_FindMatch(\$i_x, \$i_y, \$i_x_end, \$i_y_end, \$i_width, \$i_height, \$a_colors, \$a_shade, \$i_step = 1, \$h_wnd = 0, \$f_quick_match = False)
Local \$i_total = \$i_width * \$i_height
Local \$a_col = \$a_colors, \$a_var = \$a_shade
\$i_width -= 1
\$i_height -= 1

If (IsArray(\$a_colors) = 0) Or (UBound(\$a_colors) <> \$i_total) Then Return SetError(1, 0, 0)
If (IsArray(\$a_shade) = 0) Or (UBound(\$a_shade) <> \$i_total) Then Return SetError(2, 0, 0)

Local \$i_c, \$i_c_n, \$i_x_c, \$i_y_c
Local \$a_found, \$i_y_n, \$i_x_n, \$i_c_n, \$i_match
Local \$a_ret[((Abs(\$i_x_end - \$i_x) + 1) * (Abs(\$i_y_end - \$i_y) + 1)) + 1][2]

; Simple search
For \$i_y_c = \$i_y To \$i_y_end Step \$i_step
\$i_x_c = \$i_x
While 1
\$a_found = PixelSearch(\$i_x_c, \$i_y_c, \$i_x_end, \$i_y_c, \$a_colors[0], \$a_shade[0], \$i_step, \$h_wnd)
If @error Then ExitLoop

If (\$a_found[0] + \$i_width > \$i_x_end) Then ExitLoop
If (\$a_found[1] + \$i_height > \$i_y_end) Then ExitLoop

\$i_match = 0
For \$i_y_n = \$a_found[1] To \$i_height + \$a_found[1]
For \$i_x_n = \$a_found[0] To \$i_width + \$a_found[0]
PixelSearch(\$i_x_n, \$i_y_n, \$i_x_n, \$i_y_n, \$a_colors[\$i_match], \$a_shade[\$i_match], 1, \$h_wnd)
If @error Then ExitLoop 2
\$i_match += 1
If \$i_match = \$i_total Then
\$i_c += 1
\$a_ret[\$i_c][0] = \$a_found[0]
\$a_ret[\$i_c][1] = \$a_found[1]
If \$f_quick_match Then ExitLoop 4
EndIf
Next
Next

\$i_x_c = \$a_found[0] + 1
WEnd
Next

If \$i_c = 0 Then Return SetError(3, 0, 0)
ReDim \$a_ret[\$i_c + 1][2]
\$a_ret[0][0] = \$i_c
Return \$a_ret
EndFunc```
The example above found all the "@" symbols in scite for me (obviously the unique search was only for that symbol).

I expected this to be to slow to use.

I was pleasantly dissapointed there!

Searching a 1678x945 area, the example provided found 7 "@" symbols in scite in 250 ms, 10 in 350 ms. Should give you ideas on how fast/slow it is.

Also, this is a simple helper function if you want to use it, will get all the pixel colors and positions in a 2D-3 index array (Used it to help with the color array).

```; Should only be used for small regions, didn't feel like writing out bitblt method
Func _Pixel_GetRegion(\$i_x_start, \$i_y_start, \$i_x_end, \$i_y_end, \$i_step = 1, \$h_wnd = 0)
Local \$a_ret[((Abs(\$i_x_end - \$i_x_start) + 1) * (Abs(\$i_y_end - \$i_y_start) + 1)) + 1][3], \$i_c = 0
For \$i_y = \$i_y_start To \$i_y_end Step \$i_step
For \$i_x = \$i_x_start To \$i_x_end Step \$i_step
\$i_c += 1
\$a_ret[\$i_c][0] = \$i_x
\$a_ret[\$i_c][1] = \$i_y
\$a_ret[\$i_c][2] = PixelGetColor(\$i_x, \$i_y, \$h_wnd)
Next
Next
ReDim \$a_ret[\$i_c + 1][3]
\$a_ret[0][0] = \$i_c
Return \$a_ret
EndFunc```
Edited by SmOke_N

Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.

##### Share on other sites

• 4 months later...

On a topic here: http://www.autoitscript.com/forum/index.php?showtopic=95554

I was trying to understand what the OP was trying to do, I think I may have still missed the boat with him, but this function came out of it (so most of this is a simple copy and paste).

Things to know.

[*]You must send an array of colors, these colors will be left to right, top to bottom (and must be the same ubound as the width*height).

So if I have a 2 pixel width, and a 2 pixel height area I want to search, and for this example, my starting point is 0 for both x and y.

Smoke,

This is pretty good - I tested this as a replacement for a version I wrote that does basically the same thing, and yours seems faster, although I'm not sure that it correctly handles cases where there are false matches earlier on the same horizontal line?

In any case, there's one major problem with searching like this: if you're searching for a moving object, e.g. a sprite, the search can easily fail if the object was moving up the screen.

i.e. at time t, the pixel pattern is on line 201. You search line 200 and find no match.

At time t+k, the pixel pattern has moved up to line 200. You search 201 (and onwards) and find no match. Search ends having missed the object.

It's basically a concurrency problem... so I guess the solution to this is to save a snapshot of the search area to a buffer and search that, so that searching is atomic. Any tips on how to do this gracefully and still be able to use the nice API like PixelSearch and PixelChecksum?

Maybe you could draw a snapshot of the region to another window somewhere (perhaps even outside visible screen bounds) and search that normally, but it's a bit smelly.

##### Share on other sites

_ScreenCapture_Capture gets a region of the screen, using Manadar's pixel from memory UDF you could search it, combine Smoke_N's technique with those two, and you've neatly bypassed the concurrency issue. Performance will depend on how you put it together, but I don't see any problems. I'll take a whack at putting it together.

Very cool, Smoke!

##### Share on other sites

• 1 month later...

On a topic here: http://www.autoitscript.com/forum/index.php?showtopic=95554

I was trying to understand what the OP was trying to do, I think I may have still missed the boat with him, but this function came out of it (so most of this is a simple copy and paste).

Things to know.

• You must send an array of colors, these colors will be left to right, top to bottom (and must be the same ubound as the width*height).

So if I have a 2 pixel width, and a 2 pixel height area I want to search, and for this example, my starting point is 0 for both x and y.

My color array is [0xFF0000, 0x00FF00, 0x0000FF, 0x00FFFF]

x-0, y-0 = 0xFF0000

x-1, y-0 = 0x00FF00

x-0, y-1 = 0x0000FF

x-1, y-1 = 0x00FFFF

In that example you see how you would set your array up (zero based array).

• Shade variation must also be an array. The ubound must be the same as the ubound of the color array (width of pixel search * height of pixel search).

You can do different shade variations for each pixel. My example will just show a constant variation of 3 for simplicity.

• The parameters:

x-start = the x starting position of the total search area

y-start = the y starting position of the total search area

x-end = the x ending position of the total search area

y-end = the y ending position of the total search area

width = total number of pixels to search (left to right) once first pixel color is found

height = total number of pixels to search (top to bottom) once the first pixel color is found

colors = array of colors to search in specific order (explained above) one the match is found [0] is used for the first search pattern

shade = array of shade variations for each position found [0] is used for the first search pattern

step = number of steps to make like pixelsearch main function, this is only used in the main search for patterns, once a match on the first color is found, the rest of the search is step 1

hwnd = handle to window if you want to use one

quick match = If you only want the first match, set to true, and the array [n][n] will hold your values, otherwise default is to return all matches

• The return is a two dimensional array:

[0][0] = total number of matches found

[n][0] = x starting position the match was found

[n][1] = y starting position the match was found

• Errors:

1 = the color variable sent was either not an array or the ubound did not match the total value of the width*height

2 = the shade variable sent was either not an array or the ubound did not match the total value of the width*height

3 = No match found

Guess I could have written a header, just didn't feel like it.

```; Example
#include <array.au3>

; Array of colors UBound must match number of pixels searching
Local \$a_clr[9] = [0xFF4AA5, 0xFF4AA5, 0xFF4AA5, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFF4AA5, 0xFF4AA5]
; Array of variations UBound must match number of pixels searching
Local \$a_vrn[9] = [3,3,3,3,3,3,3,3,3]

Local \$a_found = _Pixel_Region_FindMatch(0, 0, 1678, 945, 3, 3, \$a_clr, \$a_vrn)
If @error Then
MsgBox(0, "Error", "Error was: " & @error)
Else
_ArrayDisplay(\$a_found)
EndIf

Func _Pixel_Region_FindMatch(\$i_x, \$i_y, \$i_x_end, \$i_y_end, \$i_width, \$i_height, \$a_colors, \$a_shade, \$i_step = 1, \$h_wnd = 0, \$f_quick_match = False)
Local \$i_total = \$i_width * \$i_height
Local \$a_col = \$a_colors, \$a_var = \$a_shade
\$i_width -= 1
\$i_height -= 1

If (IsArray(\$a_colors) = 0) Or (UBound(\$a_colors) <> \$i_total) Then Return SetError(1, 0, 0)
If (IsArray(\$a_shade) = 0) Or (UBound(\$a_shade) <> \$i_total) Then Return SetError(2, 0, 0)

Local \$i_c, \$i_c_n, \$i_x_c, \$i_y_c
Local \$a_found, \$i_y_n, \$i_x_n, \$i_c_n, \$i_match
Local \$a_ret[((Abs(\$i_x_end - \$i_x) + 1) * (Abs(\$i_y_end - \$i_y) + 1)) + 1][2]

; Simple search
For \$i_y_c = \$i_y To \$i_y_end Step \$i_step
\$i_x_c = \$i_x
While 1
\$a_found = PixelSearch(\$i_x_c, \$i_y_c, \$i_x_end, \$i_y_c, \$a_colors[0], \$a_shade[0], \$i_step, \$h_wnd)
If @error Then ExitLoop

If (\$a_found[0] + \$i_width > \$i_x_end) Then ExitLoop
If (\$a_found[1] + \$i_height > \$i_y_end) Then ExitLoop

\$i_match = 0
For \$i_y_n = \$a_found[1] To \$i_height + \$a_found[1]
For \$i_x_n = \$a_found[0] To \$i_width + \$a_found[0]
PixelSearch(\$i_x_n, \$i_y_n, \$i_x_n, \$i_y_n, \$a_colors[\$i_match], \$a_shade[\$i_match], 1, \$h_wnd)
If @error Then ExitLoop 2
\$i_match += 1
If \$i_match = \$i_total Then
\$i_c += 1
\$a_ret[\$i_c][0] = \$a_found[0]
\$a_ret[\$i_c][1] = \$a_found[1]
If \$f_quick_match Then ExitLoop 4
EndIf
Next
Next

\$i_x_c = \$a_found[0] + 1
WEnd
Next

If \$i_c = 0 Then Return SetError(3, 0, 0)
ReDim \$a_ret[\$i_c + 1][2]
\$a_ret[0][0] = \$i_c
Return \$a_ret
EndFunc```
The example above found all the "@" symbols in scite for me (obviously the unique search was only for that symbol).

I expected this to be to slow to use.

I was pleasantly dissapointed there!

Searching a 1678x945 area, the example provided found 7 "@" symbols in scite in 250 ms, 10 in 350 ms. Should give you ideas on how fast/slow it is.

Also, this is a simple helper function if you want to use it, will get all the pixel colors and positions in a 2D-3 index array (Used it to help with the color array).

```; Should only be used for small regions, didn't feel like writing out bitblt method
Func _Pixel_GetRegion(\$i_x_start, \$i_y_start, \$i_x_end, \$i_y_end, \$i_step = 1, \$h_wnd = 0)
Local \$a_ret[((Abs(\$i_x_end - \$i_x_start) + 1) * (Abs(\$i_y_end - \$i_y_start) + 1)) + 1][3], \$i_c = 0
For \$i_y = \$i_y_start To \$i_y_end Step \$i_step
For \$i_x = \$i_x_start To \$i_x_end Step \$i_step
\$i_c += 1
\$a_ret[\$i_c][0] = \$i_x
\$a_ret[\$i_c][1] = \$i_y
\$a_ret[\$i_c][2] = PixelGetColor(\$i_x, \$i_y, \$h_wnd)
Next
Next
ReDim \$a_ret[\$i_c + 1][3]
\$a_ret[0][0] = \$i_c
Return \$a_ret
EndFunc```

Noob question:How would you get the actual coords in a variable, like the PixelSearch function?

##### Share on other sites

• 1 month later...

Hmm how i can use this to click on one of these pixels?

Need code example

This world is crazy

##### Share on other sites

how come when i run this script i get a msgbox with Error was:3

##### Share on other sites

how come when i run this script i get a msgbox with Error was:3

Errors:

1 = the color variable sent was either not an array or the ubound did not match the total value of the width*height

2 = the shade variable sent was either not an array or the ubound did not match the total value of the width*height

3 = No match found

This world is crazy

##### Share on other sites

well why didnt it find any thing?

## 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

• ### Recently Browsing   0 members

• No registered users viewing this page.
×

• Wiki

• Back

• #### Beta

• Git
• FAQ
×
• Create New...