找回密码
 加入
搜索
查看: 1711|回复: 2

请大家一起帮忙改写找BMP内存位图代码

[复制链接]
发表于 2009-1-24 16:52:50 | 显示全部楼层 |阅读模式
把SSS文件解压放到TMP临时文件夹然后屏幕分辨率调到1280*1024进行调试,代码来自主站
我都调用别人的插件来找图,本人英文差,不好解决下面这段代码
这段代码应该是找图核心代码吧,

Opt('MustDeclareVars', 1)
;#include <GUIConstants.au3>
#include <GDIPlus.au3>
#Include <ScreenCapture.au3>

;~ 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

; ** Example start **
; Screen samples
Global Const $Bitmap1Filename = @TempDir & "\FULLSCREEN.bmp"
Global Const $Bitmap2Filename = @TempDir & "\CALCULATOR.bmp"
Global Const $Bitmap3Filename = @TempDir & "\BACKSPACE.bmp"

;BMP samples
Global Const $Bitmap4Filename = @TempDir & "\7WDS_BW.bmp"
Global Const $Bitmap5Filename = @TempDir & "\SEVEN_BW.bmp"
Global Const $Bitmap6Filename = @TempDir & "\CAT_BW.bmp"
Global Const $Bitmap7Filename = @TempDir & "\AUTOIT3.bmp" ;Make sure the homepage of autoit with 3 is visible
local $calcHWND, $begin, $pos, $aWinPos, $aWinCSize, $start
local $pBitmap, $BitmapData, $pixelFormat
Opt("WinTitleMatchMode", 4);Matching windows by advanced options

; Initialize GDI+ library
_GDIPlus_Startup ()

;Calculator, make sure its started
$calcHWND = WinGetHandle("[CLASS:SciCalc]")
if $calchwnd = "" Then
    run("calc.exe")
    sleep(2000)
    $calcHWND = WinGetHandle("[CLASS:SciCalc]")
EndIf

;Capture the calculator screen
$begin = TimerInit()
winactivate($calcHWND)
_ScreenCapture_CaptureWnd($Bitmap2Filename, $calcHWND,0,0,-1,-1,False)
ConsoleWrite("Saving calculator window " & TimerDiff($begin) & " milliseconds " & @LF)
winmove("[ACTIVE]","",223,341)

;Capture an area within the calculator area backspace
$begin = TimerInit()
$pos=controlgetpos("","","[CLASS:Button; TEXT:BACKSPACE]");;;;TEXT:BACKSPACE]")这里要修改一下
$aWinPos = WinGetPos($calchWnd)
$aWinCSize = WinGetClientSize($calchWnd)
;Q&D calculation of offsets to capture
_ScreenCapture_Capture($Bitmap3Filename, ($aWinPos[0]+$pos[0]) + ($aWinPos[2] - $aWinCSize[0])-3, ($awinpos[1]+$pos[1])+ ($aWinPos[3]-$aWinCSize[1])-3, $aWinPos[0]+$pos[0]+$pos[2]+3, ($awinpos[1]+$pos[1])+ ($aWinPos[3]-$aWinCSize[1])+$pos[3]-3,false)
ConsoleWrite("Saving backspacebutton " & TimerDiff($begin) & " milliseconds " & @LF)

; Capture full screen
$begin = TimerInit()
_ScreenCapture_Capture($Bitmap1Filename,0,0,-1,-1,False)
ConsoleWrite("Saving full screen took " & TimerDiff($begin) & " milliseconds " & @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

;Do the actual find
Func FindTester($BMP1, $BMP2, $Bool)
    local $tResult
    $start = TimerInit()
    $tResult=findBMP($BMP1,$BMP2, $Bool)
    ConsoleWrite($tResult &  " " & FileGetName($BMP2) & " in " & FileGetName($BMP1) & " ** matchtype " & $Bool & " time elapsed: " & TimerDiff($start) & "  milliseconds" & @LF)
EndFunc

; Not very usefull to find full screen and tricky as screen is most likely changed (clock, output from application etc.)
; findTester("SCREEN",$Bitmap1Filename,TRUE);Find the full screen itself
; findTester($Bitmap1Filename,$Bitmap1Filename,$c24RGBFullMatch);Find the full screen itself 31 seconds
findTester($Bitmap1Filename,$Bitmap1Filename,$c24RGBPartialMatch);Find the full screen itself 2.8529088255245  seconds
; findTester($Bitmap1Filename,$Bitmap1Filename,$c16RGBFullMatch);Find the full screen itself 21 seconds
findTester($Bitmap1Filename,$Bitmap1Filename,$c16RGBPartialMatch);Find the full screen itself 1 seconds

; Be aware that overlapping windows, moving things on screen can make it difficult to find on full screen
findTester("SCREEN",$Bitmap2Filename,$c24RGBFullMatch);Find the full calculatorscreen
findTester("SCREEN",$Bitmap2Filename,$c24RGBPArtialMatch);Find the full calculatorscreen with partial match
findTester("SCREEN",$Bitmap2Filename,$c16RGBFullMatch);Find the full calculatorscreen
findTester("SCREEN",$Bitmap2Filename,$c16RGBPArtialMatch);Find the full calculatorscreen with partial match

findTester($Bitmap1Filename,$Bitmap2Filename,$c16RGBFullMatch);Find the full calculatorscreen
findTester($Bitmap1Filename,$Bitmap2Filename,$c16RGBPartialMatch);Find the full calculatorscreen with partial match

findTester($Bitmap2Filename,$Bitmap3Filename,$c24RGBFullMatch);Find the backspace button
findTester($Bitmap2Filename,$Bitmap3Filename,$c24RGBPartialMatch);Find the backspace button with partial match
findTester($Bitmap2Filename,$Bitmap3Filename,$c16RGBFullMatch);Find the backspace button
findTester($Bitmap2Filename,$Bitmap3Filename,$c16RGBPartialMatch);Find the backspace button with partial match

winactivate($calcHWND);Make sure calculator is active on the screen
findTester("[ACTIVE]",$Bitmap3Filename,$c24RGBFullMatch);Find the backspace button
findTester("[ACTIVE]",$Bitmap3Filename,$c24RGBPartialMatch);Find the backspace button with partial match
findTester("[ACTIVE]",$Bitmap3Filename,$c16RGBFullMatch);Find the backspace button on active screen
findTester("[ACTIVE]",$Bitmap3Filename,$c16RGBPartialMatch);Find the backspace button with partial match

findTester("SCREEN",$Bitmap3Filename,$c24RGBFullMatch);Find the backspace button
findTester("SCREEN",$Bitmap3Filename,$c24RGBPartialMatch);Find the backspace button with partial match
findTester("SCREEN",$Bitmap3Filename,$c16RGBFullMatch);Find the backspace button
findTester("SCREEN",$Bitmap3Filename,$c16RGBPartialMatch);Find the backspace button with partial match

findTester($Bitmap4Filename,$Bitmap5Filename,$c16RGBFullMatch);Find the seven
findTester($Bitmap4Filename,$Bitmap5Filename,$c16RGBPartialMatch);Find the seven with partial match

findTester($Bitmap4Filename,$Bitmap6Filename,$c16RGBFullMatch);Find the cat
findTester($Bitmap4Filename,$Bitmap6Filename,$c16RGBPartialMatch);Find the cat with partial match

findTester($Bitmap1Filename,$Bitmap7Filename,$c24RGBFullMatch);Find the 3 of Autoit Homepage
findTester($Bitmap1Filename,$Bitmap7Filename,$c24RGBPartialMatch);Find the 3 of Autoit Homepage
findTester($Bitmap1Filename,$Bitmap7Filename,$c16RGBFullMatch);Find the 3 of Autoit Homepage
findTester($Bitmap1Filename,$Bitmap7Filename,$c16RGBPartialMatch);Find the 3 of Autoit Homepage

_GDIPlus_Shutdown()

;** Example end **

=============================================================================================
以写是函数
===========================================================================================
;===============================================================================
; 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=0;
    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)

;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 = $fline[$i] + $i - $BMP2Height  
                    $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

;For some debugging of time
;    if $bMatchPossible = True Then
;        ConsoleWrite("Searching took " & TimerDiff($begin) / 1000 & "  seconds " & @LF)
;    Else
;        ConsoleWrite("NOT FOUND Searching took " & TimerDiff($begin) / 1000 & "  seconds" & @LF)
;    endif

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

[ 本帖最后由 autoita 于 2009-1-24 16:58 编辑 ]

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?加入

×
发表于 2009-1-25 12:24:13 | 显示全部楼层
好长的代码、、、。。。
 楼主| 发表于 2009-1-25 16:11:21 | 显示全部楼层
Code below searches a certain bitmap (all supported formats of GDI+) picture in another picture or on screen (after saved as bitmap)
not depending on 3rd party dll's
Pentium 4 of 3 GHz takes
* about 4.5 seconds on a 1280*1024 desktop to find a 260*260 bitmap. Partial match 0.5 seconds
* about 1 seconds on a 1280*1024 desktop to find a 20*17 bitmap. Partial match 0.5 seconds

Some references I used to come up with this solution
* code to get a smaller bitmap: http://www.autoitscript.com/forum/index.ph...=pixelchecksum)
* Pixelchecksum seems not to do the full job but in combination with below it can become very fast: http://www.autoitscript.com/forum/index.ph...l=pixelchecksum
* A pixel by pixel searcher http://www.autoitscript.com/forum/index.ph...&hl=compare
* UDF Get or Read Pixel from Memory
* GetDIBits

Not fully finished but all comments/enhancements are appreciated
* Save to file or directly on special window description SCREEN, [ACTIVE] or name of picture file
* Searching is done on a line by line basis instead of pixel by pixel
* Bitmap to search in example program should be fully visible to work for first 3 examples as it are screenshots taken. Same applies for 3 in AUTOIT homepage
* Speed depends on the size of the bitmap you are searching for but is about linear and < 5 seconds
* Some doubts on left and top returned (sometimes seems to be off by 1 or several pixels)
* 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

Sample to work
* Install pics.zip into %temp% / Save BMP attachments for example to @tempdir (%temp%) for example to work




http://www.autoitscript.com/foru ... ic=66545&hl=bmp请链接这里
您需要登录后才可以回帖 登录 | 加入

本版积分规则

QQ|手机版|小黑屋|AUTOIT CN ( 鲁ICP备19019924号-1 )谷歌 百度

GMT+8, 2024-6-15 14:36 , Processed in 0.110512 second(s), 25 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表