Sign in to follow this  
Followers 0
johnmcloud

Find Image in Image --> Loop

6 posts in this topic

#1 ·  Posted (edited)

Hi guys and happy holidays ;)

I have found a cool Func and i'm playing around

This is the script:

#include <GDIPlus.au3>
#include <ScreenCapture.au3>

Opt("WinTitleMatchMode", 4) ;Matching windows by advanced options

;~ Constants for type of picture matching
Const $c24RGBFullMatch = 1 ;Load as 24 bits and full match
Const $c24RGBPartialMatch = 2 ;Load as 24 bits and partial match
Const $c16RGBFullMatch = 3 ;Load as 16 bits and full match
Const $c16RGBPartialMatch = 4 ;Load as 16 bits and partial match

; Screen samples
Global Const $Bitmap1Filename = @ScriptDir & "\FULLSCREEN.bmp"
Global Const $Bitmap2Filename = @ScriptDir & "\CALCULATOR.bmp"

; Initialize GDI+ library
_GDIPlus_Startup()

;Calculator, make sure its started
$calcHWND = WinGetHandle("[REGEXPCLASS:.*Calc.*]")
If $calcHWND = "" Then
Run("calc.exe")
Sleep(2000)
$calcHWND = WinGetHandle("[REGEXPCLASS:.*Calc.*]")
EndIf

;Capture the calculator screen
WinActivate($calcHWND)
_ScreenCapture_CaptureWnd($Bitmap2Filename, $calcHWND, 0, 0, -1, -1, False)
ConsoleWrite("Saving calculator window" & @LF)

; Capture full screen
_ScreenCapture_Capture($Bitmap1Filename, 0, 0, -1, -1, False)
ConsoleWrite("Saving full screen" & @LF)

Func FileGetName($f)
Local $i
$i = StringInStr($f, "\", False, -1)
If $i > 0 Then
Return StringMid($f, $i + 1)
Else
Return $f
EndIf
EndFunc ;==>Filegetname

;Do the actual find
Func _FindTester($BMP1, $BMP2, $Type)
Local $tResult
$tResult = _FindBMP($BMP1, $BMP2, $Type)
ConsoleWrite($tResult & " " & FileGetName($BMP2) & " in " & FileGetName($BMP1) & " ** matchtype " & $Type & @LF)
EndFunc ;==>_FindTester

_FindTester("SCREEN", $Bitmap2Filename, $c24RGBFullMatch);Find the full calculator screen
_FindTester("SCREEN", $Bitmap2Filename, $c24RGBPartialMatch);Find the full calculator screen with partial match
_FindTester("SCREEN", $Bitmap2Filename, $c16RGBFullMatch);Find the full calculator screen
_FindTester("SCREEN", $Bitmap2Filename, $c16RGBPartialMatch);Find the full calculator screen with partial match
_FindTester($Bitmap1Filename, $Bitmap2Filename, $c16RGBFullMatch);Find the full calculator screen
_FindTester($Bitmap1Filename, $Bitmap2Filename, $c16RGBPartialMatch);Find the full calculator screen with partial match

_GDIPlus_Shutdown()
;===============================================================================
; Function Name: _FindBMP
; Description: Finds a bitmap (.BMP) in another BMP file (other formats BMP, GIF, JPEG, PNG, TIFF, Exif, WMF, and EMF should work but not tested)
; Syntax: _FindBMP($BMP1, $BMP2, $MatchType=TRUE)
;
; Parameter(s): $BMP1 = Filename of bitmap to search in
;    $BMP2 = Filename of bitmap to search for
;    $MatchType = c24RGBFullMatch, c24RGBPartialMatch, c16RGBFullMatch, c16RGBPartialMatch
;
; Return Value(s): On Success: = Returns Array List
;    On Failure: = @error 1 (Control was found but there was an error with the DLLCall)
;
; Author(s): JunkEW
;
; Note(s):
; * Its never an exact match even with TRUE as last few bits are disposed in algorithm and lines below
;    are not checked under assumption that those are 99.99% of the time correct
;    * locking bits overview http://www.bobpowell.net/lockingbits.htm
; ToDo:
; * Transparency (when search letters on a different background) http://www.winprog.org/tutorial/transparency.html
; * Match quicker by doing a bitblt with srcinvert when first line is found (instead of checking line by line)
; * $BMP1 and $BMP2 to be HBITMAP handle as input instead of filenames (will make searching within partial screen easier)
; Example(s):
;
;===============================================================================
Func _FindBMP($BMP1, $BMP2, $MatchType = $c24RGBFullMatch)
Dim $fLine[1];Line number of found line(s), redimmed when second picture size is known
Dim $BMP1Data = "", $BMP1Width = 0, $BMP1Height = 0, $BMP1LineWidth = 0;
Dim $BMP2Data = "", $BMP2Width = 0, $BMP2Height = 0, $BMP2LineWidth = 0
Dim $foundAt = "", $matchPossible = False, $matchedLines = 0, $foundAtLeft = -1, $foundAtTop = -1
Dim $bestMatchLine = -1, $HighestMatchingLines = -1; For knowing when no match is found where best area is
Dim $iPos = 1;
Dim $imgBytes;
Local $iFuzzyDist, $searchFor, $iAbove, $bMatchPossible, $aboveLine
Local $j, $imgBits
If ($MatchType = $c24RGBFullMatch) Or ($MatchType = $c24RGBPartialMatch) Then
$imgBytes = 3
Else
$imgBytes = 2
EndIf
; Load the bitmap to search in
getImage($BMP1, $BMP1Data, $BMP1Width, $BMP1Height, $BMP1LineWidth, $imgBytes)
$BMP1Data = BinaryToString($BMP1Data)
; Load the bitmap to find
getImage($BMP2, $BMP2Data, $BMP2Width, $BMP2Height, $BMP2LineWidth, $imgBytes)
;Make it strings to be able to use string functions for searching
$BMP2Data = BinaryToString($BMP2Data)
;For reference of line where in BMP2FindIn a line of BMP2Find was found
If $BMP2Height = 0 Then
SetError(1, 0, 0)
Return False
EndIf
ReDim $fLine[$BMP2Height]
;If exact match check every 1 line else do it more fuzzy (as most likely other lines are unique)
If ($MatchType = $c24RGBFullMatch) Or ($MatchType = $c16RGBFullMatch) Then
$iFuzzyDist = 1
Else
;Check fuzzy every 10% of lines
$iFuzzyDist = Ceiling(($BMP2Height * 0.1))
EndIf
$begin = TimerInit()
;Look for each line of the bitmap if it exists in the bitmap to find in
For $i = 0 To $BMP2Height - 1
;Minus imgbytes as last bits are padded with unpredictable bytes (24 bits image assumption) or 2 when 16 bits
$searchFor = StringMid($BMP2Data, 1 + ($i * $BMP2LineWidth), ($BMP2LineWidth - $imgBytes))
$iPos = StringInStr($BMP1Data, $searchFor, 2, 1, $iPos)
;Look for all lines above if there is also a match
;Not doing it for the lines below as speed is more important and risk of mismatch on lines below is small
$iAbove = 1
If $iPos > 0 Then
$bMatchPossible = True
$matchedLines = 1;As first found line is matched we start counting
;Location of the match
$foundAtTop = Int($iPos / $BMP1LineWidth) - $i
$foundAtLeft = Int(Mod($iPos, $BMP1LineWidth) / $imgBytes)
Else
$bMatchPossible = False
ExitLoop
EndIf
While (($i + $iAbove) <= ($BMP2Height - 1)) And ($bMatchPossible = True)
$searchFor = StringMid($BMP2Data, 1 + (($i + $iAbove) * $BMP2LineWidth), ($BMP2LineWidth - $imgBytes))
$aboveLine = StringMid($BMP1Data, $iPos + ($iAbove * $BMP1LineWidth), ($BMP2LineWidth - $imgBytes))
If $aboveLine <> $searchFor Then
$bMatchPossible = False
;To remember the area with the best match
If $matchedLines >= $HighestMatchingLines Then
     $HighestMatchingLines = $matchedLines
     ;Best guess of location
     $foundAtTop = Int($iPos / $BMP1LineWidth);+ $i - $BMP2Height
     $bestMatchLine = Int($iPos / $BMP1LineWidth)
EndIf
ExitLoop
EndIf
$matchedLines = $matchedLines + 1
$iAbove = $iAbove + $iFuzzyDist
WEnd
;If bMatchPossible is still true most likely we have found the bitmap
If $bMatchPossible = True Then
;~ ConsoleWrite("Could match top: " & $foundAtTop & " left: " & $foundAtLeft & " in " & TimerDiff($begin) / 1000 & " seconds" & @LF)
; MouseMove($foundatleft, $foundatTop)
ExitLoop
Else
;~ consolewrite("i not matched " & $ipos & " " & $matchedlines & @crlf )
EndIf
Next
;Return an error if not found else return an array with all information
If $bMatchPossible = False Then
SetError(1, 0, 0)
EndIf
; return stringsplit($bMatchPossible & ";" & $matchedLines & ";" & $foundAtLeft & ";" & $foundAtTop & ";" & $bmp2width & ";" & $BMP2Height & ";" & $HighestMatchingLines & ";" & $bestMatchLine,";")
Return $bMatchPossible & ";" & $matchedLines & ";" & $foundAtLeft & ";" & $foundAtTop & ";" & $BMP2Width & ";" & $BMP2Height & ";" & $HighestMatchingLines & ";" & $bestMatchLine
EndFunc ;==>_FindBMP
Func GetImage($BMPFile, ByRef $BMPDataStart, ByRef $Width, ByRef $Height, ByRef $Stride, $imgBytes = 3)
Local $Scan0, $pixelData, $hbScreen, $pBitmap, $pBitmapCap, $handle
; 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
;~ 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

Work fine, but i'd like to add it in a loop ( my goal is search for the temperature of an HW component , if is X then start an alarm, in this case i have posted, as always, an example for everyone )

I have try many ways with While-WEnd and Do-Until, but if the $tResult is False, it's everytime false, never change.

So in the example i'd like to do:

1) Open the script

2) If i open Calc.exe , the script comparing the two images, and give me a MsgBox

Thanks for any help ;)

Edited by johnmcloud

Share this post


Link to post
Share on other sites



Hi,

If it works outside a loop it should work in a loop.

Plus, it does not work for me at all.


 

OS : Win XP SP2 (32 bits) / Win 7 SP1 (64 bits) / Win 8 (64 bits) | Autoit version: latest stable / beta.
Hardware : Intel(R) Core(TM) i5-2400 CPU @ 3.10Ghz / 8 GiB RAM DDR3.

My UDFs : Skype UDF | TrayIconEx UDF | GUI Panel UDF | Excel XML UDF | Is_Pressed_UDF

My Projects : YouTube Multi-downloader | FTP Easy-UP | Lock'n | WinKill | AVICapture | Skype TM | Tap Maker | ShellNew | Scriptner | Const Replacer | FT_Pocket | Chrome theme maker

My Examples : Capture toolIP Camera | Crosshair | Draw Captured Region | Picture Screensaver | Jscreenfix | Drivetemp | Picture viewer

My Snippets : Basic TCP | Systray_GetIconIndex | Intercept End task | Winpcap various | Advanced HotKeySet | Transparent Edit control

 

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

Hi,

If it works outside a loop it should work in a loop.

Plus, it does not work for me at all.

If i put it in a loop i have everytime the same value, so if is true is always true, also if the real value is false, don't know why

I have tested on XP SP3 x86 and on Windows 7 x64, work on both. Just press F5 and wait.

This is the ConsoleWrite output:

Saving calculator window
Saving full screen
True;322;125;0;228;322;-1;-1 CALCULATOR.bmp in SCREEN ** matchtype 1
True;11;125;0;228;322;-1;-1 CALCULATOR.bmp in SCREEN ** matchtype 2
True;322;125;0;228;322;-1;-1 CALCULATOR.bmp in SCREEN ** matchtype 3
True;11;125;0;228;322;-1;-1 CALCULATOR.bmp in SCREEN ** matchtype 4
True;322;125;0;228;322;-1;-1 CALCULATOR.bmp in FULLSCREEN.bmp ** matchtype 3
True;11;125;0;228;322;-1;-1 CALCULATOR.bmp in FULLSCREEN.bmp ** matchtype 4
Edited by johnmcloud

Share this post


Link to post
Share on other sites

#4 ·  Posted (edited)

Not sure what you are saying. If it works without a loop it should work with a loop to.

I looked thru under W7 and 64 bits as library was written a long time ago by me in Windows XP / 32 bits

On my W7 64 bits machine it gives in the end an issue as bitmap and bitmaparea of the screen where the calculator is seems indeed to be different for me for unknown reason

debugging code (creates hex files) to show this (its only of by 1 byte) easiest shown if you have a white background (put blanco MS Paint screen behind calculator)

  • only 1 findtester active as this 24 bits is most complicated

    _FindTester("SCREEN", $Bitmap2Filename, $c24RGBFullMatch);Find the full calculator screen

  • Sections added for start debugging / end debugging that writes the data to the files
  • check files BMP2DATA.TXT, BMP1DATA.TXT and COMPAREDLINES.TXT (with good editor you will see where it mismatches)
So no clue why it has in the fullscreen image a different bmp written (must be something weird of GDI)

At least is shows the algorithm in itself is correct and the issue is in the BMP files created

workaround: doing a subcheck within the string but that would slow down the comparison

[Edit] Created more debugging stuff in the code and enable with a boolean the debugging

[Edit2] Fixed with new function added

func comparePicLine($s1,$s2)
if $s1=$s2 Then
  return True
Else
  $iMatched=0
  $sLen=stringlen($s1)
  for $tJ=1 to $slen
   if stringmid($s1,$tJ,1)=stringmid($s2,$tJ,1) Then
    $iMatched=$imatched+1
   endif
  Next
  if  ($iMatched / $sLen ) > $cMatchLinePercentage then
   return true
  Else
   return false
  endif
EndIf
endfunc

Full demo code (not in debugging mode, turn $bDebug=True to understand and analyse the details in difference in hex textfiles)

#include <GDIPlus.au3>
#include <ScreenCapture.au3>
#include <string.au3>

;~ If debugging output is wanted to understand and analyse the algorithm put this on true/false
Const $bDebug=False

Const $cMatchLinePercentage=0.99 ;Minimum matching, put on 1 if exact matching is needed on all lines

Opt("WinTitleMatchMode", 4) ;Matching windows by advanced options

;~ Constants for type of picture matching
Const $c24RGBFullMatch = 1 ;Load as 24 bits and full match
Const $c24RGBPartialMatch = 2 ;Load as 24 bits and partial match
Const $c16RGBFullMatch = 3 ;Load as 16 bits and full match
Const $c16RGBPartialMatch = 4 ;Load as 16 bits and partial match

; Screen samples
;~ Works with all GDI formats but most stable for the bitmaps BMP, TIFF, PNG
;~ Global Const $Bitmap1Filename = @ScriptDir & "\FULLSCREEN.bmp"
;~ Global Const $Bitmap2Filename = @ScriptDir & "\CALCULATOR.bmp"
;~ Global Const $Bitmap1Filename = @ScriptDir & "\FULLSCREEN.TIFF"
;~ Global Const $Bitmap2Filename = @ScriptDir & "\CALCULATOR.TIFF"

;~ PNG seems to be smarter to use as it minimizes filesize
Global Const $Bitmap1Filename = @ScriptDir & "\FULLSCREEN.PNG"
Global Const $Bitmap2Filename = @ScriptDir & "\CALCULATOR.PNG"

; Initialize GDI+ library
_GDIPlus_Startup()

;Calculator, make sure its started
$calcHWND = WinGetHandle("[REGEXPCLASS:.*Calc.*]")
If $calcHWND = "" Then
Run("calc.exe")
Sleep(2000)
$calcHWND = WinGetHandle("[REGEXPCLASS:.*Calc.*]")
EndIf

;Capture the calculator screen
WinActivate($calcHWND)
_ScreenCapture_CaptureWnd($Bitmap2Filename, $calcHWND, 0, 0, -1, -1, False)
ConsoleWrite("Saving calculator window" & @LF)

; Capture full screen
_ScreenCapture_Capture($Bitmap1Filename, 0, 0, -1, -1, False)
ConsoleWrite("Saving full screen" & @LF)

Func FileGetName($f)
Local $i
$i = StringInStr($f, "\", False, -1)
If $i > 0 Then
Return StringMid($f, $i + 1)
Else
Return $f
EndIf
EndFunc ;==>Filegetname

;Do the actual find
Func _FindTester($BMP1, $BMP2, $Type)
Local $tResult
$tResult = _FindBMP($BMP1, $BMP2, $Type)
ConsoleWrite($tResult & " " & FileGetName($BMP2) & " in " & FileGetName($BMP1) & " ** matchtype " & $Type & @LF)
EndFunc ;==>_FindTester

_FindTester("SCREEN", $Bitmap2Filename, $c24RGBFullMatch);Find the full calculator screen
if not $bDebug=True Then
_FindTester("SCREEN", $Bitmap2Filename, $c24RGBPartialMatch);Find the full calculator screen with partial match
_FindTester("SCREEN", $Bitmap2Filename, $c16RGBFullMatch);Find the full calculator screen
_FindTester("SCREEN", $Bitmap2Filename, $c16RGBPartialMatch);Find the full calculator screen with partial match
_FindTester($Bitmap1Filename, $Bitmap2Filename, $c16RGBFullMatch);Find the full calculator screen
_FindTester($Bitmap1Filename, $Bitmap2Filename, $c16RGBPartialMatch);Find the full calculator screen with partial match
EndIf

_GDIPlus_Shutdown()
;===============================================================================
; Function Name: _FindBMP
; Description: Finds a bitmap (.BMP) in another BMP file (other formats BMP, GIF, JPEG, PNG, TIFF, Exif, WMF, and EMF should work but not tested)
; Syntax: _FindBMP($BMP1, $BMP2, $MatchType=TRUE)
;
; Parameter(s): $BMP1 = Filename of bitmap to search in
;    $BMP2 = Filename of bitmap to search for
;    $MatchType = c24RGBFullMatch, c24RGBPartialMatch, c16RGBFullMatch, c16RGBPartialMatch
;
; Return Value(s): On Success: = Returns Array List
;    On Failure: = @error 1 (Control was found but there was an error with the DLLCall)
;
; Author(s): JunkEW
;
; Note(s):
; * Its never an exact match even with TRUE as last few bits are disposed in algorithm and lines below
;    are not checked under assumption that those are 99.99% of the time correct
;    * locking bits overview http://www.bobpowell.net/lockingbits.htm
; ToDo:
; * Transparency (when search letters on a different background) http://www.winprog.org/tutorial/transparency.html
; * Match quicker by doing a bitblt with srcinvert when first line is found (instead of checking line by line)
; * $BMP1 and $BMP2 to be HBITMAP handle as input instead of filenames (will make searching within partial screen easier)
; Example(s):
;
;===============================================================================
Func _FindBMP($BMP1, $BMP2, $MatchType = $c24RGBFullMatch)
Dim $fLine[1];Line number of found line(s), redimmed when second picture size is known
Dim $BMP1Data = "", $BMP1Width = 0, $BMP1Height = 0, $BMP1LineWidth = 0;
Dim $BMP2Data = "", $BMP2Width = 0, $BMP2Height = 0, $BMP2LineWidth = 0
Dim $foundAt = "", $matchPossible = False, $matchedLines = 0, $foundAtLeft = -1, $foundAtTop = -1
Dim $bestMatchLine = -1, $HighestMatchingLines = -1; For knowing when no match is found where best area is
Dim $iPos = 1;
Dim $imgBytes;
Local $iFuzzyDist, $searchFor, $iAbove, $bMatchPossible, $aboveLine
Local $j, $imgBits
If ($MatchType = $c24RGBFullMatch) Or ($MatchType = $c24RGBPartialMatch) Then
$imgBytes = 3
Else
$imgBytes = 2
EndIf
; Load the bitmap to search in
getImage($BMP1, $BMP1Data, $BMP1Width, $BMP1Height, $BMP1LineWidth, $imgBytes)
$BMP1Data = BinaryToString($BMP1Data)

; Load the bitmap to find
getImage($BMP2, $BMP2Data, $BMP2Width, $BMP2Height, $BMP2LineWidth, $imgBytes)
;Make it strings to be able to use string functions for searching
$BMP2Data = BinaryToString($BMP2Data)

if $bDebug=True Then
;~ START debugging
;Get some debugging information
FileDelete(@ScriptDir & "\BMP1DATA.TXT")
FileDelete(@ScriptDir & "\BMP2DATA.TXT")
FileDelete(@ScriptDir & "\COMPAREDLINES.TXT")

consolewrite($BMP1Width & @crlf)
consolewrite($BMP1Height & @crlf)
consolewrite($BMP1LineWidth & @crlf)
consolewrite(stringlen($BMP1Data) & @crlf)

consolewrite(".{" & $BMP1LineWidth & "}"& @CRLF)

consolewrite(".{" & $BMP2LineWidth & "}"& @CRLF)
$tDebug=StringRegExpReplace(_stringtohex($BMP1Data),"(.{" & $BMP1LineWidth*2 & "})","$1" & @CRLF)
consolewrite(@error & @extended & @CRLF)
FileWrite (@ScriptDir & "\BMP1DATA.TXT" , $tdebug)

$tDebug=StringRegExpReplace(_stringtohex($BMP2Data),"(.{" & $BMP2LineWidth*2 & "})","$1" & @CRLF)
consolewrite(@error & @extended & @CRLF)
FileWrite (@ScriptDir & "\BMP2DATA.TXT" , $tdebug)
;~ END debugging
EndIf

;For reference of line where in BMP2FindIn a line of BMP2Find was found
If $BMP2Height = 0 Then
SetError(1, 0, 0)
Return False
EndIf
ReDim $fLine[$BMP2Height]
;If exact match check every 1 line else do it more fuzzy (as most likely other lines are unique)
If ($MatchType = $c24RGBFullMatch) Or ($MatchType = $c16RGBFullMatch) Then
$iFuzzyDist = 1
Else
;Check fuzzy every 10% of lines
$iFuzzyDist = Ceiling(($BMP2Height * 0.1))
EndIf

$begin = TimerInit()
;Look for each line of the bitmap if it exists in the bitmap to find in
For $i = 0 To $BMP2Height - 1
;Minus imgbytes as last bits are padded with unpredictable bytes (24 bits image assumption) or 2 when 16 bits
$searchFor = StringMid($BMP2Data, 1 + ($i * $BMP2LineWidth), ($BMP2LineWidth - $imgBytes))
$iPos = StringInStr($BMP1Data, $searchFor, 2, 1, $iPos)
;Look for all lines above if there is also a match
;Not doing it for the lines below as speed is more important and risk of mismatch on lines below is small
$iAbove = 1
If $iPos > 0 Then
$bMatchPossible = True
$matchedLines = 1;As first found line is matched we start counting
;Location of the match
$foundAtTop = Int($iPos / $BMP1LineWidth) - $i
$foundAtLeft = Int(Mod($iPos, $BMP1LineWidth) / $imgBytes)
Else
$bMatchPossible = False
ExitLoop
EndIf

While (($i + $iAbove) <= ($BMP2Height - 1)) And ($bMatchPossible = True)
$searchFor = StringMid($BMP2Data, 1 + (($i + $iAbove) * $BMP2LineWidth), ($BMP2LineWidth - $imgBytes))
$aboveLine = StringMid($BMP1Data, $iPos + ($iAbove * $BMP1LineWidth), ($BMP2LineWidth - $imgBytes))

if $bDebug=True Then
;~ START debugging
$tDebug=StringRegExpReplace(_stringtohex($searchfor),"(.{8})","$1_")
FileWrite (@ScriptDir & "\COMPAREDLINES.TXT" , $tDebug & @crlf)
$tDebug=StringRegExpReplace(_stringtohex($aboveline),"(.{8})","$1_")
FileWrite (@ScriptDir & "\COMPAREDLINES.TXT" , $tDebug & @crlf)
If $aboveLine <> $searchFor Then
FileWrite (@ScriptDir & "\COMPAREDLINES.TXT" , "** MISMATCH ** of line " & (1+$iAbove) & " in 2nd bitmap at line " & ($foundAtTop + $i) & @crlf)
endIf
;~ END debugging
EndIf

if comparePicLine($aboveline,$searchfor) = false then
$bMatchPossible = False
;To remember the area with the best match
If $matchedLines >= $HighestMatchingLines Then
$HighestMatchingLines = $matchedLines
;Best guess of location
$foundAtTop = Int($iPos / $BMP1LineWidth);+ $i - $BMP2Height
$bestMatchLine = Int($iPos / $BMP1LineWidth)
EndIf
ExitLoop
EndIf
$matchedLines = $matchedLines + 1
$iAbove = $iAbove + $iFuzzyDist
WEnd
;If bMatchPossible is still true most likely we have found the bitmap
If $bMatchPossible = True Then
;~ ConsoleWrite("Could match top: " & $foundAtTop & " left: " & $foundAtLeft & " in " & TimerDiff($begin) / 1000 & " seconds" & @LF)
; MouseMove($foundatleft, $foundatTop)
ExitLoop
Else
;~ consolewrite("i not matched " & $ipos & " " & $matchedlines & @crlf )
EndIf
Next
;Return an error if not found else return an array with all information
If $bMatchPossible = False Then
SetError(1, 0, 0)
EndIf
; return stringsplit($bMatchPossible & ";" & $matchedLines & ";" & $foundAtLeft & ";" & $foundAtTop & ";" & $bmp2width & ";" & $BMP2Height & ";" & $HighestMatchingLines & ";" & $bestMatchLine,";")
Return $bMatchPossible & ";" & $matchedLines & ";" & $foundAtLeft & ";" & $foundAtTop & ";" & $BMP2Width & ";" & $BMP2Height & ";" & $HighestMatchingLines & ";" & $bestMatchLine
EndFunc ;==>_FindBMP

func comparePicLine($s1,$s2)

if $s1=$s2 Then
return True
Else
$iMatched=0
$sLen=stringlen($s1)
for $tJ=1 to $slen
if stringmid($s1,$tJ,1)=stringmid($s2,$tJ,1) Then
$iMatched=$imatched+1
endif
Next
if  ($iMatched / $sLen ) > $cMatchLinePercentage then
return true
Else
return false
endif
EndIf
endfunc

Func GetImage($BMPFile, ByRef $BMPDataStart, ByRef $Width, ByRef $Height, ByRef $Stride, $imgBytes = 3)
Local $Scan0, $pixelData, $hbScreen, $pBitmap, $pBitmapCap, $handle
; 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
;~ 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_PXF32ARGB)
$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_PXF32ARGB)
$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
Edited by junkew

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

think the solution will be in the lockbits parameters $GDIP_PXF32PARGB but then I have to change and test a little more

[edit] 05 jan 2013: lockbits is not the issue gives same result, its just one part of a pixel different regardless of 2,3 or 4 bytes per pixel.

Pixels as shown hexadecimal seems jus a color shade difference which is weird as calculator is saved at sime time as full screenshot

726557FF_726456FF_716356FF_716355FF_706355FF

726557FF_726456FF_726356FF_716356FF_706355FF

see full module over here

Edited by junkew

Share this post


Link to post
Share on other sites

Thanks, i'll check it out ;)

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