Jump to content
Sign in to follow this  
jebus495

Finding images inside others.

Recommended Posts

jebus495

Is there a way I could store (not automatically. This is something I would do before even running the script. I would make up a bunch of reference images) the words Enhanced Effect as shown in the image above in an image file and then have autoit attempt to find a match to that exact pattern in another image?

The thing that comes to mind immediately is the factor of other colors floating around the text. Is it at all possible with a screen capture function to ONLY capture pixels that are 0x000000 in color?

I'm not sure I have explained what I need to do sufficiently.

Edited by jebus495

Share this post


Link to post
Share on other sites
jvanegmond

There's no reason why this couldn't work. Using only the AutoIt function PixelGetColor you can write a function to compare images yourself.

Here's a few steps to get you started:

1) Create an (2-dimensional) array and fill it with the colors of the pixels you want to read

2) Remove all unwanted colors from the array, leaving only the black colors

3) Open up another image, and read that image into an array too, using the same method used in step 1 and step 2

4) Iterate through both of the arrays, and see if the arrays are an exact or approximate match.

What you're looking for is a simplified character recognition. It's one of the more difficult things to do in programming..

Edit: And when searching for something completely different, I came across this: http://www.autoitscript.com/forum/index.php?showtopic=66545

It may not be working, but it's example code and deserves a mentioning.

Edited by Manadar

Share this post


Link to post
Share on other sites
jebus495

There's no reason why this couldn't work. Using only the AutoIt function PixelGetColor you can write a function to compare images yourself.

Here's a few steps to get you started:

1) Create an (2-dimensional) array and fill it with the colors of the pixels you want to read

2) Remove all unwanted colors from the array, leaving only the black colors

3) Open up another image, and read that image into an array too, using the same method used in step 1 and step 2

4) Iterate through both of the arrays, and see if the arrays are an exact or approximate match.

What you're looking for is a simplified character recognition. It's one of the more difficult things to do in programming..

Edit: And when searching for something completely different, I came across this: http://www.autoitscript.com/forum/index.php?showtopic=66545

It may not be working, but it's example code and deserves a mentioning.

Would this truly be exceedingly difficult or would it just be immensely time consuming?

I'm pretty new to autoit and programming in general. I don't know how to use or work with arrays so that's probably a good start.

Before I head out and start reading any suggestions on any guides or anything?

@edit: I was looking at that thread after searching and before I posted. I'm gonna read that post to the ground before I start attempting this.

Share this post


Link to post
Share on other sites
jvanegmond

Alright, that's not exactly great example code but I guess it will. It's hard to find any free example code that does image reading..

The only tip I have left is .. Don't actually convert the actual screen of what you want to read into a file first, and then read from the file, that is slow and inaccurate sometimes. Preferably just read directly from the screen.

I was working on OCR myself, and here's an example of how it was half way through: http://www.autoitscript.com/forum/index.ph...st&p=604073

Share this post


Link to post
Share on other sites
jebus495

Ok.

1) Create an (2-dimensional) array and fill it with the colors of the pixels you want to read

This I think I can handle.

2) Remove all unwanted colors from the array, leaving only the black colors

Not sure how to go about this but I expect it won't be hard to figure out.

3) Open up another image, and read that image into an array too, using the same method used in step 1 and step 2

Getting pretty lost.

4) Iterate through both of the arrays, and see if the arrays are an exact or approximate match.

Pretty sure I'm not gonna get that one unless I stumble onto something almost exactly like what I need.

=S

Share this post


Link to post
Share on other sites
jvanegmond

Alright, if you have any more troubles or worries, just post back and we'll see what we can do.

Share this post


Link to post
Share on other sites
Leopardfist

Ok.

1) Create an (2-dimensional) array and fill it with the colors of the pixels you want to read

This I think I can handle.

;Not using full code, just what is relevant, you can find includes and such in the help file.

Local $NumofPixelsHigh = 10;you will need to use the window info tool to establish size of image you want to use.
Local $NumofPixelsWide = 50;Same as above
Local $Coord[2] = 100, 50;Top left corner of image
Local $Target[$NumofPixelsHigh][$NumofPixelsWide], $Current[$NumofPixelsHigh][$NumofPixelsWide]
Local $I, $A, $B = 0

For $I = 0 to $NumofPixelsHigh
For $A = 0 to $NumofPixelsWide
$Target[$I][$A] = Pixelgetcolor($Coord[0]+$A, $Coord[1]+$I)
If $Target[$I][$A] = "0x000000" then 
$Target[$I][$A] = 1
Else
$Target[$I][$A] = 0
EndIf;This gets the color value, then checks to see if it is black, if it is we assign a 1 value, if not we assign a 0 value.
Next
Next

;We now have our target array, now you set up your script to run the same type code to look for the same image during the
;game. I am not sure how you want to set it to check, but I will set it for every 10 seconds ro so as an example.

While 1

For $I = 0 to $NumofPixelsHigh
For $A = 0 to $NumofPixelsWide
$Current[$I][$A] = Pixelgetcolor($Coord[0]+$A, $Coord[1]+$I)
If $Current[$I][$A] = "0x000000" then 
$Current[$I][$A] = 1
Else
$Current[$I][$A] = 0
EndIf
Next
Next;Same exact code with current replacing target.

;Now we compare the two structures, keep in mind, we ONLY want to compare the BLACK pixels from target image, the 
;new image MIGHT have black that the target doesnt, this does not necessarily null the comparison, because it may not 
;be text

For $I = 0 to $NumofPixelsHigh
For $A = 0 to $NumofPixelsWide
If $Target[$I][$A] = 1 AND $Current[$I][$A] <> 1 then
$B = 0
ExitLoop 2;This exits the check due to a non match.
Else 
$B = 1
EndIf
Next
Next

If $B = 1;then we have a match, do whatever you want - B would only be 1 if it went thru the entire loop without a mismatch. 

Sleep(10000);that ten second pause :)

WEnd

That is fairly simple version but can give you an idea of how to do it. I am sure there are errors in it, I just did it from memory without the use of any reference as I am at work.

EDIT: Messed up the coord[0]+$A and coord[1]+$I, so they are fixed now :)

Edited by Leopardfist

Share this post


Link to post
Share on other sites
junkew

1. With the previous given link http://www.autoitscript.com/forum/index.php?showtopic=66545

2. And converting to 0 and 1 link in http://www.autoitscript.com/forum/index.ph...mp;#entry627591

you should be able to create a black and white comparison.

3. http://www.autoitscript.com/forum/index.ph...&pid=628547 probably easier to create a B/W string that way

When I find time I will include this logic in the first reference as a way how to handle black foreground text only (some kind of transparency trick).

Sample code to get the B/W pixels save the png picture in temp folder with name enhanced.png

Opt('MustDeclareVars', 1)
;http://www.autoitscript.com/forum/index.php?showtopic=86773&hl=
;White = R > 0x80, G > 0x80, B > 0x80
;#include <GUIConstants.au3>
#include <GDIPlus.au3>
#include <ScreenCapture.au3>
#include <string.au3>

; ** Example start **
Global Const $Bitmap1Filename = @TempDir & "\enhanced.png"

Dim $BMP1Data = "", $BMP1Width = 0, $BMP1Height = 0, $BMP1LineWidth = 0
Dim $imgBytes, $image, $t

; Initialize GDI+ library
_GDIPlus_Startup()

; Load the bitmap to search in
GetImage($Bitmap1Filename, $BMP1Data, $BMP1Width, $BMP1Height, $BMP1LineWidth, 3)

_GDIPlus_Shutdown()

$BMP1Data = BinaryToString($BMP1Data)

dumpBlackWhite("test", $BMP1Data, $BMP1Height, $BMP1LineWidth)

;** Example end **

Func GetImage($BMPFile, ByRef $BMPDataStart, ByRef $Width, ByRef $Height, ByRef $Stride, $imgBytes = 3)
    Local $Scan0, $pixelData, $hbScreen, $pBitmap, $pBitmapCap, $handle, $bitmapdata, $pixelFormat

; Load the bitmap to search in
    If $BMPFile = "SCREEN" Then
        $hbScreen = _ScreenCapture_Capture("", 0, 0, -1, -1, False)
        $pBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hbScreen); returns memory bitmap
    Else
    ;try to get a handle
        $handle = WinGetHandle($BMPFile)
        If @error Then
        ;Assume its an unknown handle so correct filename should be given
            $pBitmap = _GDIPlus_BitmapCreateFromFile($BMPFile)
        Else
            $hbScreen = _ScreenCapture_CaptureWnd("", $handle, 0, 0, -1, -1, False)
            $pBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hbScreen); returns memory bitmap
        EndIf
    EndIf
    
;Get $tagGDIPBITMAPDATA structure
;~  ConsoleWrite("Bitmap Width:    " & _GDIPlus_ImageGetWidth($pBitmap) & @CRLF )
;~  ConsoleWrite("Bitmap Height:      " & _GDIPlus_ImageGetHeight($pBitmap) & @CRLF)

;~  24 bits (3 bytes) or 16 bits (2 bytes) comparison
    If ($imgBytes = 2) Then
        $BitmapData = _GDIPlus_BitmapLockBits($pBitmap, 0, 0, _GDIPlus_ImageGetWidth($pBitmap), _GDIPlus_ImageGetHeight($pBitmap), $GDIP_ILMREAD, $GDIP_PXF16RGB555)
    Else
        $BitmapData = _GDIPlus_BitmapLockBits($pBitmap, 0, 0, _GDIPlus_ImageGetWidth($pBitmap), _GDIPlus_ImageGetHeight($pBitmap), $GDIP_ILMREAD, $GDIP_PXF24RGB)
    EndIf
    
    If @error Then MsgBox(0, "", "Error locking region " & @error)
    
    $Stride = DllStructGetData($BitmapData, "Stride");Stride - Offset, in bytes, between consecutive scan lines of the bitmap. If the stride is positive, the bitmap is top-down. If the stride is negative, the bitmap is bottom-up.
    $Width = DllStructGetData($BitmapData, "Width");Image width - Number of pixels in one scan line of the bitmap.
    $Height = DllStructGetData($BitmapData, "Height");Image height - Number of scan lines in the bitmap.
    $pixelFormat = DllStructGetData($BitmapData, "PixelFormat");Pixel format - Integer that specifies the pixel format of the bitmap
    $Scan0 = DllStructGetData($BitmapData, "Scan0");Scan0 - Pointer to the first (index 0) scan line of the bitmap.
    
    $pixelData = DllStructCreate("ubyte lData[" & (Abs($Stride) * $Height - 1) & "]", $Scan0)
    $BMPDataStart = $BMPDataStart & DllStructGetData($pixelData, "lData")
    
    _GDIPlus_BitmapUnlockBits($pBitmap, $BitmapData)
    _GDIPlus_ImageDispose($pBitmap)
    _WinAPI_DeleteObject($pBitmap)

EndFunc  ;==>GetImage

Func dumpBlackWhite($sFname, $bmData, $h, $w)
    Local $i, $j, $tLine, $hexBytes
    Local $newLine, $newline2
    local $R, $G, $B
    local $whiteString= " "
    local $blackString= "1"

    For $i = 0 To $h - 1
        $tLine = StringMid($bmData, 1+($i * $w), $w)
        consolewrite(StringFormat("%06s:", 1 + ($i * $w)) )
        $newLine="" 
        for $j=0 to ($w / 3)
            $HexBytes=_StringToHex(stringmid($tLine, 1+($j * 3), 3)) 
            if $hexbytes="000000" Then
                $HexBytes = $BlackString
            else 
                $HexBytes = $whiteString 
            endif

            $newLine=$newline & $hexbytes
        next

        ConsoleWrite($newline & @CRLF)
    Next
EndFunc  ;==>dumpBlackWhite

From that step onwards OCR could become a "small" step

1. Have a snapshot of the area to OCR and call it $Bitmap1

2. Split it in segmented areas

3. Create a new bitmap devicecontext and do a drawtext for each character and look if it exists in segmented areas

Edited by junkew

Share this post


Link to post
Share on other sites
jebus495

CODE
;Not using full code, just what is relevant, you can find includes and such in the help file.

Local $NumofPixelsHigh = 10;you will need to use the window info tool to establish size of image you want to use.

Local $NumofPixelsWide = 50;Same as above

Local $Coord[2] = 100, 50;Top left corner of image

Local $Target[$NumofPixelsHigh][$NumofPixelsWide], $Current[$NumofPixelsHigh][$NumofPixelsWide]

Local $I, $A, $B = 0

For $I = 0 to $NumofPixelsHigh

For $A = 0 to $NumofPixelsWide

$Target[$I][$A] = Pixelgetcolor($Coord[0]+$A, $Coord[1]+$I)

If $Target[$I][$A] = "0x000000" then

$Target[$I][$A] = 1

Else

$Target[$I][$A] = 0

EndIf;This gets the color value, then checks to see if it is black, if it is we assign a 1 value, if not we assign a 0 value.

Next

Next

;We now have our target array, now you set up your script to run the same type code to look for the same image during the

;game. I am not sure how you want to set it to check, but I will set it for every 10 seconds ro so as an example.

While 1

For $I = 0 to $NumofPixelsHigh

For $A = 0 to $NumofPixelsWide

$Current[$I][$A] = Pixelgetcolor($Coord[0]+$A, $Coord[1]+$I)

If $Current[$I][$A] = "0x000000" then

$Current[$I][$A] = 1

Else

$Current[$I][$A] = 0

EndIf

Next

Next;Same exact code with current replacing target.

;Now we compare the two structures, keep in mind, we ONLY want to compare the BLACK pixels from target image, the

;new image MIGHT have black that the target doesnt, this does not necessarily null the comparison, because it may not

;be text

For $I = 0 to $NumofPixelsHigh

For $A = 0 to $NumofPixelsWide

If $Target[$I][$A] = 1 AND $Current[$I][$A] <> 1 then

$B = 0

ExitLoop 2;This exits the check due to a non match.

Else

$B = 1

EndIf

Next

Next

If $B = 1;then we have a match, do whatever you want - B would only be 1 if it went thru the entire loop without a mismatch.

Sleep(10000);that ten second pause :)

WEnd

That is fairly simple version but can give you an idea of how to do it. I am sure there are errors in it, I just did it from memory without the use of any reference as I am at work.

EDIT: Messed up the coord[0]+$A and coord[1]+$I, so they are fixed now :lmao:

Took me a bit to get my head around arrays.

This script looks like it is almost exactly what I want but I keep getting errors.

Local $Coord[2] = 100, 50 gets the error missing subscript dimensions in "dim" statement

I did my best to find a way to fix it but I ended up causing more problems. :think:

Share this post


Link to post
Share on other sites
Authenticity

Local $Coord[2] = [100, 50]

Share this post


Link to post
Share on other sites
jebus495

oooh ty.

C:\Documen... ...ndom.au3 (12) : ==> Array variable has incorrect number of subscripts or subscript dimension range exceeded.:

$Target[$I][$A] = Pixelgetcolor($Coord[0]+$A, $Coord[1]+$I)

^ ERROR

I'm guessing this is just a problem with the way the array(s) was/were declared? =S

Share this post


Link to post
Share on other sites
Authenticity

Perhaps, it's the values of $I or $A or both that exceeding the array's subscripts range. Try to use ReDim in cases that you want to re-reference the array in different way or to increase it.

For example, Dim $Arr[5][2], ..., ReDim $Arr[2][5] or ReDim $Arr[5][10]. Keep in mind that improper use of ReDim can easily give you unwanted effects or run-time errors.

Edit: typo, as usual.

Edited by Authenticity

Share this post


Link to post
Share on other sites
Leopardfist

OK, sorry for all the errors hehe, I told ya I did it from memory with no reference. I think I know what is wrong with what you have now, don't worry about using the redim function, just change it like below. And you will have to change all other For loops to match to prevent the array from erroring out.

For $I = 0 to $NumofPixelsHigh

For $A = 0 to $NumofPixelsWide

For $I = 0 to $NumofPixelsHigh - 1

For $A = 0 to $NumofPixelsWide - 1

That should fix the dimension brekaing :). What was happening is it was counting from 0 to the max number, for example we declared our array Local[50] but it starts with local[0] so the biggest is local[49]. Our for loop went from 0 to 50, so adding the -1 should fix that problem.

Another problem that I see right away (because it is right below it hehe) is this line.

$Target[$I][$A] = Pixelgetcolor($Coord[0]+$A, $Coord[1]+$I)

If $Target[$I][$A] = "0x000000" then

That is gonna prevent your script from working. Pixelgetcolor returns a decimal value, so you need to make it a hex value. Now I havent used this is so lo0ng I do not remember the way it returns, so play around with it to test your target color value. If you want you can even change the "0x000000" to the decimal value for black. If Hex($Target[$I][$A] returns a value like 000000 without the 0x in front, you will have to work that into your script. Essentially you wanna check every pixel to see if it is black, then if it is have it switch the specific array value to 1, if not to 0. Then you can compare your arrays at the end to see if they match.

$Target[$I][$A] = Pixelgetcolor($Coord[0]+$A, $Coord[1]+$I)

If Hex($Target[$I][$A]) = "0x000000" then

That MIGHT fix it if the HEX() returns with the 0x, and the value is a string which it really must be hehe, if it has the 0x. But for some reason my memory of years past is telling me it does NOT return the 0x. If it doesn't you will have to add that in. I think with autoit you dont have to worry about converting the numeric 000000 part to string to concatenate it to the 0x000000 part, if you had any expectations of printing it or recording it to a file or something. I dont think you will get an error if you concatenate a string with a numeric. It's been a long time since I got down and dirty with autoit, so they may have changed that.

Fix those and run it, and list your next errors hehe, I'm sure there are more. I will try to help you fix em.

Share this post


Link to post
Share on other sites
jebus495

I didn't change the Hex thing but when I changed the array like you said it ran through flawlessly.

Now what I want to do is to be able to store multiple array of 1's and 0's to look for a match.

For example if it finds this pattern of 1's and 0's...

100010011111
100010000100
111110000100
100010000100
100010011111

...anywhere it searches I want it to do one thing and if it doesn't find a match I want it do carry on.

I can just use mspaint to find the black pixel patterns of the words I want it to find (they never change) but I am still lost on how to make a script to compare preset values to something it's "looking at".

This script is really close I think but I don't know if I can handle it.

Share this post


Link to post
Share on other sites
Leopardfist

Well, I don't know what you are trying to work with, most sites that use image verification... the characters in the image change size, rotate, swap from cursive to print and capitals to lower case. This really makes doing what you want to do very very difficult. However, if you are working on a site that is consistent and doesn't do that, I would say it is doable. I would think of it as each letter requires it's own construct (array), and once you can define every character all you have to do is pixelsearch the image for the first black pixel, then pixel search the letter dimension from the top left pixel and compare to your construct.

This is way more work than I am willing to do code wise, but that is the route I would go if in fact the characters never change size or position within the image.

Share this post


Link to post
Share on other sites
Drew

That's D2Jsp's Ladder Slasher if I'm not mistaken.

Getting caught doing this = Ban stick :).

Share this post


Link to post
Share on other sites
jebus495

Well, I don't know what you are trying to work with, most sites that use image verification... the characters in the image change size, rotate, swap from cursive to print and capitals to lower case. This really makes doing what you want to do very very difficult. However, if you are working on a site that is consistent and doesn't do that, I would say it is doable. I would think of it as each letter requires it's own construct (array), and once you can define every character all you have to do is pixelsearch the image for the first black pixel, then pixel search the letter dimension from the top left pixel and compare to your construct.

This is way more work than I am willing to do code wise, but that is the route I would go if in fact the characters never change size or position within the image.

In fact the structure of entire words I am looking for will always be the same. Only their position in the area I am looking will change.

So all I would need to do is look in a newly received array for another array. I know _arraysearch can look for a single value in an array but is there a way to see if an array contains any of a series of preset arrays?

I was hoping this wouldn't be too difficult because of the nature of the words only containing black pixels and nothing around it is black.

Share this post


Link to post
Share on other sites
jvanegmond

To simplify the process of comparing an array, I put every character (seperated by 3 non-black columns of pixels) into its own array. Then I trim the excessive whitespace (0 values ) of that array, and then I can compare it to a stored value much more easily. I'll show you how first, step by step, and then with complete code. Note that the code is a little bit buggy, since I just randomly threw it together, but it does work.

Splitting up each character into its own array is quite tricky. I think that was one of the parts I had a lot of problem with. Anyway, what I do is the following: I constantly read pixels into an array. I go through each column of pixels (already simplified into black (1) and non-black (0)) and count the number of black pixels. When it finds no black pixels at three times after eachother, then it stops putting pixels into the current array, and creates a new array for it to read into. This process is repeated until you end up with a lot of arrays, one array for each character. For actual code look in the total example.

Now, you go through each character and you trim off the excess non-black. That's what the Func _PixelArrayTrimEmptyField($pPixels) does. It just trims off all the 0 around the 1 in a 2 dimensional array, and returns a new array that has black on the outsides.

Ok, so now we've got an array for each character. We've trimmed this array down so that we can easily compare it to other arrays that hold. Let's compare the arrays. That's exactly what the Func _CompareArray($pPixel1, $pPixel2, $pAccuracy = 0.95) does. It compares arrays based on a percentage of accuracy. If the arrays match is greater than the required accuracy it returns a value that is true, otherwise it returns a value that is false.

And if you're wondering how to store the characters in your script, this is how I've done it. It is quite efficient and AutoIt interprets it fast, so there's no need for long "Loading character defitions..." messages later on in your project. This for example is the capital letter M:

Dim $_Char_M_Capital[8][10] = [[1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1],[0,0,1,1,0,0,0,0,0,0], [0,0,0,1,1,0,0,0,0,0],[0,0,0,1,1,0,0,0,0,0], [0,0,1,1,0,0,0,0,0,0],[1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1]]

There's actually a function that turns 2 dimensional arrays into strings like that, which I had to write ... I've called it Func _ToDefinition($pPixels) and it returns a string just like the one above.

Anyway, sorry for the BIG BIG BIG read. Here's the code, enjoy!

#include <Color.au3>
#include <Array.au3>
#include <Math.au3>

#include-once

AutoItSetOption("WinTitleMatchMode", 4)

;#include "RuneOCR.au3"

Dim $_Char_M_Capital[8][10] = [[1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1],[0,0,1,1,0,0,0,0,0,0],[0,0,0,1,1,0,0,0,0,0],[0,0,0,1,1,0,0,0,0,0],[0,0,1,1,0,0,0,0,0,0],[1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1]]
Dim $_Char_i_Lower[2][7] = [[1,0,1,1,1,1,1],[1,0,1,1,1,1,1]]
Dim $_Char_n_Lower[6][6] = [[1,1,1,1,1,1],[1,1,1,1,1,1],[1,1,0,0,0,0],[1,0,0,0,0,0],[1,1,1,1,1,1],[0,1,1,1,1,1]]
Dim $_Char_e_Lower[6][6] = [[0,1,1,1,1,0],[1,1,1,1,1,1],[1,0,0,1,0,1],[1,0,0,1,0,1],[1,1,1,1,0,1],[0,1,1,0,0,1]]

Dim $Characters[4][2] = [ [$_Char_M_Capital, "M"] , _
[$_Char_i_Lower, "i"] , _
[$_Char_n_Lower, "n"] , _
[$_Char_e_Lower, "e"] ]

Sleep(3000)
_Main()

Func _Main()
    Local $nWidth = 77
    Local $nHeight = 19
    Local $aStorage[$nWidth][$nHeight]
    
    Dim $m[2] = [262, 213]
    
    For $x = 0 to $nWidth-1
        For $y = 0 to $nHeight-1
            $aStorage[$x][$y] = PixelGetColor($m[0] + $x+1,$m[1] + $y+1)
        Next
    Next

    Local $nResult = _PixelArrayToText($aStorage)
    
    MsgBox(0, "", $nResult)
EndFunc

Func _PixelArrayToText($pStorage)
    Local $lReturn = ""
    
    Local $lPixels = _PixelSearchInArray($pStorage, 30)
    
    ;Local $lTrimPixels = _PixelArrayTrimEmptyField($lPixels)
    Local $lTrimPixels = $lPixels
    
    ;_ArrayDisplay($lTrimPixels,Default,Default,1)
    
    Local $i = 0
    While 1
        Local $lThisChar = _PixelArraySplit($lTrimPixels,$i)
        If @error Then ExitLoop
        
        $lThisChar = _PixelArrayTrimEmptyField($lThisChar)
        
        For $n = 0 to UBound($Characters)-1
            If ( _CompareArray($Characters[$n][0], $lThisChar) ) Then
                $lReturn &= $Characters[$n][1]
            EndIf
        Next
        
        ;InputBox( "", "", _ToDefinition( $lThisChar ) )
        
        ;MsgBox(0, $i, _CalculateChecksum($lThisChar) )
        
        $i += 1
    WEnd
    
    Return $lReturn
EndFunc

Func _CompareArray($pPixel1, $pPixel2, $pAccuracy = 0.95)
    Local $minX = _Min(UBound($pPixel1,1), UBound($pPixel2,1))
    Local $minY = _Min(UBound($pPixel1,2), UBound($pPixel2,2))
    
    Local $iDiff = 0
    Local $iTotal = ($minX) * ($minY)
    
    For $x = 0 to $minX-1
        For $y = 0 to $minY-1
            If ( $pPixel1[$x][$y] <> $pPixel2[$x][$y] ) Then
                $iDiff += 1
            EndIf
        Next
    Next
    
    $a = ( $iDiff / $iTotal )
    If ( $a < (1-$pAccuracy) ) Then ; Returns true based on a 90% match
        Return 1
    Else
        Return 0
    EndIf
EndFunc

Func _ToDefinition($pPixels)
    
    ;_ArrayDisplay($pPixels,Default,Default,1)
    
    Local $lReturn = "Dim $char[" & UBound($pPixels,1) & "][" & UBound($pPixels,2) & "] = ["
    
    For $x = 0 to UBound($pPixels,1)-1
        $lReturn &= "["
        For $y = 0 to UBound($pPixels,2)-1
            If ($pPixels[$x][$y]) Then
                $lReturn &= "1,"
            Else
                $lReturn &= "0,"
            EndIf
        Next
        $lReturn = StringTrimRight($lReturn,1)
        $lReturn &= "],"
    Next
    
    $lReturn = StringTrimRight($lReturn,1)
    $lReturn &= "]"
    
    Return $lReturn
    
EndFunc

Func _PixelArraySplit($pPixels,$pSplit)
    Local $thisChar = 0
    Local $prevEmpty = True
    Local $startX = -1
    Local $stopX = -1
    Local $a = 0
    
    For $x = 0 to UBound($pPixels,1)-1
        If ( _PixelColIsEmpty($pPixels,$x) ) Then
            If ( $prevEmpty == False ) Then
                $stopX = $x
                If ( $thisChar == $pSplit ) Then
                    $a = 1
                    ExitLoop
                Else
                    $thisChar += 1
                EndIf
            EndIf
            $prevEmpty = True
        Else
            If ( $prevEmpty == True ) Then
                $startX = $x
            EndIf
            $prevEmpty = False
        EndIf
    Next
    
    If ( $a == 0 ) Then
        Return SetError(1,0,0)
    EndIf
    
    $stopX -= 1
    Local $lReturn[Abs($startX-$stopX)][UBound($pPixels,2)]
    
    For $x = $startX to $stopX
        ReDim $lReturn[$x-$startX+1][UBound($pPixels,2)]
        
        For $y = 0 to UBound($pPixels,2)-1
            $lReturn[$x-$startX][$y] = $pPixels[$x][$y]
        Next
    Next
    
    Return $lReturn
EndFunc

Func _PixelColIsEmpty($pPixels,$x)
    For $y = 0 to UBound($pPixels,2)-1
        If ( $pPixels[$x][$y] ) Then
            Return 0
        EndIf
    Next
    Return 1
EndFunc

Func _PixelArrayTrimEmptyField($pPixels)
    Local $lowX = 100000
    Local $highX = 0
    Local $lowY = 100000
    Local $highY = 0
    
    For $x = 0 to UBound($pPixels,1)-1
        For $y = 0 to UBound($pPixels,2)-1
            If ( $pPixels[$x][$y] == 1 ) Then
                
                If ( $lowX > $x ) Then
                    $lowX = $x
                EndIf
                If ( $highX < $x ) Then
                    $highX = $x
                EndIf
                
                If ( $lowY > $y ) Then
                    $lowY = $y
                EndIf
                If ( $highY < $y ) Then
                    $highY = $y
                EndIf
                
            EndIf
        Next
    Next
    
    Local $lDiffX = Abs( $lowX - $highX )
    Local $lDiffY = Abs( $lowY - $highY )
    
    Local $lReturn[$lDiffX+1][$lDiffY+1]
    
    For $x = $lowX to $highX
        For $y = $lowY to $highY
            $lReturn[$x-$lowX][$y-$lowY] = $pPixels[$x][$y]
        Next
    Next
    
    Return $lReturn
EndFunc

Func _PixelSearchInArray($pPixels, $pVariation)
    Dim $lColor[2] = [0xe2e0d9, 0xd5d5d3]
    
    $lPixels = _FilterPixelsByColorArray($pPixels, $lColor, 30)
    
    Return $lPixels
EndFunc

Func _FilterPixelsByColorArray($pPixels, $pColors, $pVariation)
    If UBound($pPixels,0) <> 2 Then Return SetError(1,0,0)
    
    Local $pReturn[UBound($pPixels,1)][UBound($pPixels,2)]
    
    For $x = 1 to UBound($pPixels,1)-1
        For $y = 1 to UBound($pPixels,2)-1
            For $i = 0 to UBound($pColors)-1
                If ( _ColorInBounds( $pPixels[$x][$y], $pColors[$i] , 30) ) Then
                    $pReturn[$x][$y] = 1
                Else
                    $pReturn[$x][$y] = 0
                EndIf
            Next
        Next
    Next
    
    Return $pReturn
EndFunc

Func _ColorInBounds($pMColor, $pTColor, $pVariation)
    $lMCBlue = _ColorGetBlue($pMColor)
    $lMCGreen = _ColorGetGreen($pMColor)
    $lMCRed = _ColorGetRed($pMColor)
    
    $lTCBlue = _ColorGetBlue($pTColor)
    $lTCGreen = _ColorGetGreen($pTColor)
    $lTCRed = _ColorGetRed($pTColor)
    
    $a = Abs($lMCBlue - $lTCBlue)
    $b = Abs($lMCGreen - $lTCGreen)
    $c = Abs($lMCRed - $lTCRed)
    
    If ( ( $a < $pVariation ) AND ( $b < $pVariation ) AND ( $c < $pVariation ) ) Then
        Return 1
    Else
        Return 0
    EndIf
EndFunc
Edited by Manadar

Share this post


Link to post
Share on other sites
jebus495

WOW!

That looks like a lot of work lol.

I'll spend some time studying that.

I'm not sure it will be what I'm looking for but I should at least be able to make some use of this. :)

One thing that immediately comes to my head is the necessity for arrays for each character. I was planning on searching for specific words. Could I do this and simply treat it as a character?

Would the word "Flux" translate as such in array?

0000001000000000000

1111101000000000000

1000001000000000000

1000001010001010001

1111101010001001010

1000001010001000100

1000001010001000100

1000001010001001010

1000001001111010001

And then to:

$_word_flux[3][3] = [[0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0],_

[1,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0],_

[1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0],_

[1,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1],_

[1,1,1,1,1,0,1,0,1,0,0,0,1,0,0,1,0,1,0],_

[1,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0],_

[1,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0],_

[1,0,0,0,0,0,1,0,1,0,0,0,1,0,0,1,0,1,0],_

[1,0,0,0,0,0,1,0,0,1,1,1,1,0,1,0,0,0,1]]

I think that's correct.

The part that confuses me is how do I "look" for this in another array? I think your script may be a bit more complicated than it needs to be for my intended use but I will try to get it down!

Edit: Those arrays are not correct lol. They need to be "up and down".

Edited by jebus495

Share this post


Link to post
Share on other sites
jvanegmond

Yeah, I think I may be overcomplicating this when I brought in a fully working method of reading characters from a screen.

Here's something more simple that may get you going right now:

Dim $aSearchArray[2][2] = [[0,1],[1,0]]
;; Here's an example array of what we want to search for.

Dim $aCompleteArray[10][10] = [ _ 
[1,1,1,1,1,1,1,1,1,1], _ 
[1,1,1,1,1,1,1,1,1,1], _ 
[1,1,1,1,1,0,1,1,1,1], _ 
[1,1,1,1,1,0,1,1,1,1], _ 
[1,1,1,0,1,1,1,1,1,1], _ 
[1,1,1,1,0,1,1,1,1,1], _ 
[1,1,1,1,1,1,1,1,1,1], _ 
[1,1,1,1,1,1,1,1,1,1], _ 
[1,1,1,1,1,1,1,1,1,1], _ 
[1,1,1,1,1,1,1,1,1,1]]
;; In this case, there is only one instance of what we want to search for.
;; Its position is 4, 3

For $x = 0 to UBound($aCompleteArray,1)-1
    For $y = 0 to UBound($aCompleteArray,2)-1
        If ( $aCompleteArray[$x][$y] == $aSearchArray[0][0] ) Then ;; Just finds a starting point for the correct match, then later checks if this is correct
            If ( _IsCorrect($x,$y) == 1 ) Then
                MsgBox(0x40,"Au3 Test", "Correct match found at position [" & $x & "," & $y & "].")
                Exit
            EndIf
        EndIf
    Next
Next

Func _IsCorrect($n,$m) ; This is helper function which goes through the global array to see if this is the correct match we are looking for. Returns 1 for succes.
    $k = $n+UBound($aSearchArray,1)-1
    $l = $m+UBound($aSearchArray,2)-1
    If ( $k > UBound($aCompleteArray,1) ) Then Return 0 ; goes outside the boundaries, so we can be sure this isn't correct
    If ( $l > UBound($aCompleteArray,2) ) Then Return 0
    
    For $x = $n to $k
        For $y = $m to $l
            If ( $aCompleteArray[$x][$y] <> $aSearchArray[$x-$n][$y-$m] ) Then
                Return 0
            EndIf
        Next
    Next
    
    Return 1
EndFunc

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  

×