Что нового

_BmpSearch помогите с поиском в области

ivantu

Новичок
Сообщения
8
Репутация
1
Друзья помогите реализовать поиск в определенной области, имеется:

Код:
#include <WinAPIGdi.au3>

; #FUNCTION# ====================================================================================================================
; Name ..........: _BmpSearch
; Description ...: Searches for Bitmap in a Bitmap
; Syntax ........: _BmpSearch($hSource, $hFind, $iMax=5000)
; Parameters ....: $hSource             - Handle to bitmap to search
;                  $hFind               - Handle to bitmap to find
;                  $iMax                   - Max matches to find
; Return values .: Success: Returns a 2d array with the following format:
;                            $aCords[0][0] = Total Matches found
;                            $aCords[$i][0] = Width of bitmap
;                            $aCords[$i][1] = Hight of bitmap
;                            $aCords[$i][2] = X cordinate
;                            $aCords[$i][3] = Y cordinate
;
;                    Failure: Returns 0 and sets @error to 1
;
; Author ........: Brian J Christy (Beege)
; ===============================================================================================================================
Func _BmpSearch($hSource, $hFind, $iMax = 5000)

    Static Local $aMemBuff, $tMem, $fStartup = True

    If $fStartup Then
        ;####### (BinaryStrLen = 490) #### (Base64StrLen = 328 )####################################################################################################
        Local $Opcode = 'yBAAAFCNRfyJRfSNRfiJRfBYx0X8AAAAAItVDP8yj0X4i10Ii0UYKdiZuQQAAAD38YnBi0X4OQN0CoPDBOL36akAAACDfSgAdB1TA10oO10YD4OVAAAAi1UkORN1A1vrBluDwwTrvVOLVSyLRTADGjtdGHd3iwg5C3UhA1oEi0gEO10Yd2Y5C3USA1oIi0gIO10Yc1c5' & _
                'C3UDW+sGW4PDBOuCi1UUid6LfQyLTRCJ2AHIO0UYczfzp4P5AHcLSoP6AHQNA3Uc6+KDwwTpVP///4tFIIkYg0UgBIPDBP9F/ItVNDlV/HQG6Tj///9bi0X8ycIwAA=='

        Local $aDecode = DllCall("Crypt32.dll", "bool", "CryptStringToBinary", "str", $Opcode, "dword", 0, "dword", 1, "struct*", DllStructCreate("byte[254]"), "dword*", 254, "ptr", 0, "ptr", 0)
        If @error Or (Not $aDecode[0]) Then Return SetError(1, 0, 0)
        $Opcode = BinaryMid(DllStructGetData($aDecode[4], 1), 1, $aDecode[5])

        $aMemBuff = DllCall("kernel32.dll", "ptr", "VirtualAlloc", "ptr", 0, "ulong_ptr", BinaryLen($Opcode), "dword", 4096, "dword", 64)
        $tMem = DllStructCreate('byte[' & BinaryLen($Opcode) & ']', $aMemBuff[0])
        DllStructSetData($tMem, 1, $Opcode)
        ;####################################################################################################################################################################################
        $fStartup = False
    EndIf

    Local $iTime = TimerInit()

    Local $tSizeSource = _WinAPI_GetBitmapDimension($hSource)
    Local $tSizeFind = _WinAPI_GetBitmapDimension($hFind)

    Local $iRowInc = ($tSizeSource.X - $tSizeFind.X) * 4

    Local $tSource = _GetBmpPixelStruct($hSource)
    Local $tFind = _GetBmpPixelStruct($hFind)

    Local $aFD = _FindFirstDiff($tFind)
    Local $iFirstDiffIdx = $aFD[0]
    Local $iFirstDiffPix = $aFD[1]

    Local $iFirst_Diff_Inc = _FirstDiffInc($iFirstDiffIdx, $tSizeFind.X, $tSizeSource.X)
    If $iFirst_Diff_Inc < 0 Then $iFirst_Diff_Inc = 0

    Local $tCornerPixs = _CornerPixs($tFind, $tSizeFind.X, $tSizeFind.Y)
    Local $tCornerInc = _CornerInc($tSizeFind.X, $tSizeFind.Y, $tSizeSource.X)

    Local $pStart = DllStructGetPtr($tSource)
    Local $iEndAddress = Int($pStart + DllStructGetSize($tSource))

    Local $tFound = DllStructCreate('dword[' & $iMax & ']')

    Local $ret = DllCallAddress('dword', DllStructGetPtr($tMem), 'struct*', $tSource, 'struct*', $tFind, _
            'dword', $tSizeFind.X, 'dword', $tSizeFind.Y, _
            'dword', $iEndAddress, 'dword', $iRowInc, 'struct*', $tFound, _
            'dword', $iFirstDiffPix, 'dword', $iFirst_Diff_Inc, _
            'struct*', $tCornerInc, 'struct*', $tCornerPixs, _
            'dword', $iMax)

    If Not $ret[0] Then Return SetError(1, 0, 0)

    Local $aCords = _GetCordsArray($ret[0], $tFound, $tSizeSource.X, $pStart, $tSizeFind.X, $tSizeFind.Y)
    Return SetExtended(Int(TimerDiff($iTime) * 1000), $aCords)

EndFunc   ;==>_BmpSearch_MC


#Region Internal Functions
;Returns a Dllstructure will all pixels
Func _GetBmpPixelStruct($hBMP)

    Local $tSize = _WinAPI_GetBitmapDimension($hBMP)
    Local $tBits = DllStructCreate('dword[' & ($tSize.X * $tSize.Y) & ']')

    _WinAPI_GetBitmapBits($hBMP, DllStructGetSize($tBits), DllStructGetPtr($tBits))

    Return $tBits

#Tidy_Off
#cs

    This is how the dllstructure index numbers correspond to the pixel cordinates:

    An 5x5 dimension bmp:
        X0    X1    X2    X3    X4
    Y0     1   2    3    4    5
    Y1    6    7    8    9    10
    Y2    11    12    13    14    15
    Y3    16    17    18    19    20
    Y4    21    22    23    24    25

    An 8x8 dimension bmp:
        X0    X1    X2    X3    X4    X5    X6    X7
    Y0    1    2    3    4    5    6    7    8
    Y1    9    10    11    12    13    14    15    16
    Y2    17    18    19    20    21    22    23    24
    Y3    25    26    27    28    29    30    31    32
    Y4    33    34    35    36    37    38    39    40
    Y5    41    42    43    44    45    46    47    48
    Y6    49    50    51    52    53    54    55    56
    Y7    57    58    59    60    61    62    63    64

#ce
     #Tidy_On

EndFunc   ;==>_GetBmpPixelStruct

;Find first pixel that is diffrent than ....the first pixel
Func _FindFirstDiff($tPix)

    ;####### (BinaryStrLen = 106) ########################################################################################################################
    Static Local $Opcode = '0xC80000008B5D0C8B1383C3048B4D103913750C83C304E2F7B800000000EB118B5508FF338F028B451029C883C002EB00C9C20C00'
    Static Local $aMemBuff = DllCall("kernel32.dll", "ptr", "VirtualAlloc", "ptr", 0, "ulong_ptr", BinaryLen($Opcode), "dword", 4096, "dword", 64)
    Static Local $tMem = DllStructCreate('byte[' & BinaryLen($Opcode) & ']', $aMemBuff[0])
    Static Local $fSet = DllStructSetData($tMem, 1, $Opcode)
    ;#####################################################################################################################################################

    Local $iMaxLoops = (DllStructGetSize($tPix) / 4) - 1
    Local $aRet = DllCallAddress('dword', DllStructGetPtr($tMem), 'dword*', 0, 'struct*', $tPix, 'dword', $iMaxLoops)

    Return $aRet

EndFunc   ;==>_FindFirstDiff

; Calculates the value to increase pointer by to check first different pixel
Func _FirstDiffInc($iDx, $iFind_Xmax, $iSource_Xmax)

    Local $aFirstDiffCords = _IdxToCords($iDx, $iFind_Xmax)
    Local $iXDiff = ($iDx - ($aFirstDiffCords[1] * $iFind_Xmax)) - 1

    Return (($aFirstDiffCords[1] * $iSource_Xmax) + $iXDiff) * 4

EndFunc   ;==>_FirstDiffInc

;Converts the pointer addresses to cordinates
Func _GetCordsArray($iTotalFound, $tFound, $iSource_Xmax, $pSource, $iFind_Xmax, $iFind_Ymax)

    Local $aRet[$iTotalFound + 1][4]
    $aRet[0][0] = $iTotalFound

    For $i = 1 To $iTotalFound
        $iFoundIndex = ((DllStructGetData($tFound, 1, $i) - $pSource) / 4) + 1
        $aRet[$i][0] = $iFind_Xmax
        $aRet[$i][1] = $iFind_Ymax
        $aRet[$i][3] = Int(($iFoundIndex - 1) / $iSource_Xmax) ; Y
        $aRet[$i][2] = ($iFoundIndex - 1) - ($aRet[$i][3] * $iSource_Xmax) ; X
    Next

    Return $aRet

EndFunc   ;==>_GetCordsArray

;converts cordinates to dllstructure index number
Func _CordsToIdx($iX, $iY, $iMaxX)
    Return ($iY * $iMaxX) + $iX + 1
EndFunc   ;==>_CordsToIdx

;convert dllstructure index number to cordinates
Func _IdxToCords($iDx, $iMaxX)

    Local $aCords[2]
    $aCords[1] = Int(($iDx - 1) / $iMaxX) ; Y
    $aCords[0] = ($iDx - 1) - ($aCords[1] * $iMaxX) ; X

    Return $aCords

EndFunc   ;==>_IdxToCords

;Retrieves the Pixel Values of Right Top, Left Bottom, Right Bottom. Returns dllstructure
Func _CornerPixs(ByRef $tFind, $iFind_Xmax, $iFind_Ymax)

    Local $tCornerPixs = DllStructCreate('dword[3]')

    DllStructSetData($tCornerPixs, 1, DllStructGetData($tFind, 1, $iFind_Xmax), 1) ; top right corner
    DllStructSetData($tCornerPixs, 1, DllStructGetData($tFind, 1, ($iFind_Xmax + ($iFind_Xmax * ($iFind_Ymax - 2)) + 1)), 2) ;  bottom left corner
    DllStructSetData($tCornerPixs, 1, DllStructGetData($tFind, 1, ($iFind_Xmax * $iFind_Ymax)), 3);    bottom right corner

    Return $tCornerPixs

EndFunc   ;==>_CornerPixs

;Retrieves the pointer adjust values for Right Top, Left Bottom, Right Bottom. Returns dllstructure
Func _CornerInc($iFind_Xmax, $iFind_Ymax, $iSource_Xmax)

    Local $tCornerInc = DllStructCreate('dword[3]')

    DllStructSetData($tCornerInc, 1, ($iFind_Xmax - 1) * 4, 1)
    DllStructSetData($tCornerInc, 1, (($iSource_Xmax - $iFind_Xmax) + $iSource_Xmax * ($iFind_Ymax - 2) + 1) * 4, 2)
    DllStructSetData($tCornerInc, 1, ($iFind_Xmax - 1) * 4, 3)

    Return $tCornerInc

EndFunc   ;==>_CornerInc
#EndRegion Internal Functions

Код:
$anhlocal=@ScriptDir&"\images\1.bmp"
$hwnd=0x00031896;handle 
$p=imageSearchEX($hwnd,$anhlocal)
if $p=0 Then
   MsgBox(0,"","Ошибка")
   EndIf
_ArrayDisplay($p)
MouseClick("left",$p[0],$p[1],3,1)
Func imageSearchEX($hwnd,$bmpLocal)
   $iWidth = _WinAPI_GetWindowWidth($hwnd)
   $iHeight = _WinAPI_GetWindowHeight($hwnd)
   Return imageSearchEXarea($hwnd,$bmpLocal,$iWidth,$iHeight)
   EndFunc
Func imageSearchEXarea($hwnd,$bmpLocal,$iWidth,$iHeight)
   Local $p[2]
_GDIPlus_Startup()
;Get the hBitmap of the image i want to search for
$Bitmap = _GDIPlus_BitmapCreateFromFile($bmpLocal)
$hBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($Bitmap)

;Doing the actual window capture and saving it inside $hBMP
$iWidth = _WinAPI_GetWindowWidth($hwnd) ; $browser = the handle of the window which I am capturing
$iHeight = _WinAPI_GetWindowHeight($hwnd)
$hDDC = _WinAPI_GetDC($hwnd)
$hCDC = _WinAPI_CreateCompatibleDC($hDDC)
$hBMP = _WinAPI_CreateCompatibleBitmap($hDDC, $iWidth, $iHeight)
_WinAPI_SelectObject($hCDC, $hBMP)
DllCall("User32.dll", "int", "PrintWindow", "hwnd", $hwnd, "hwnd", $hCDC, "int", 0)
;Searching for the image
$pos = _BmpSearch($hBMP, $hBitmap,10)
_ArrayDisplay($pos)
if $pos=0 Then
   Return 0
   EndIf
$p[0]=$pos[1][2]
$p[1]=$pos[1][3]


 _WinAPI_ReleaseDC($hwnd, $hDDC)
_WinAPI_DeleteDC($hCDC)
_WinAPI_DeleteObject($hBMP)
_GDIPlus_Shutdown()
Return $p
EndFunc

Код выше работает, в фоном режиме, что очень хорошо, но мне очень сильно не хватает нескольких функций при использовании:
1) Хотелось бы иметь возможность указать зону поиска
2) Задать Толерантність поиска, т.е учитывать погрешность в % соотношении

Ps/ друзья, буду рад помощи, несколько дней бороздю просторы интернета, пока не получается самостоятельно, скорее всего связанно с не высоким уровнем знаний.
 

Oki

Продвинутый
Сообщения
452
Репутация
63
Нотки преждевременного пессимизма удалены.
 
Последнее редактирование:
Автор
I

ivantu

Новичок
Сообщения
8
Репутация
1
Нашел наконец то! Несколько дней были потрачены не зря, есть все что душе угодно в этой UDF,
тесты провел все работает, так как написано в описании.
Делюсь, если кому то тоже будет в этом необходимость
Some highlights:

  • Very fast with imagesearchdll embedded, no external files required.
  • Tolerances and Max Images are supported.
  • Optimized.
  • Use with handle or full screen easily.
  • Included global functions, so you can run multiple functions in one capture.
  • Examples used for testing included.
Notes:

  • Only use to compile to 32 bit AutoIt version (It can completely run on Windows 64 bit)
  • Image use for searching should be a "24-bit Bitmap" format.
  • I included $IsUser32 variable in some places like _GlobalImgInit, _HandleCapture. This variable allowed you to use DllCall with "PrintWindow" parameter instead of _WinAPI_BitBlt with $SRCCOPY. $IsUser32 = True is useful for window explorer handle, $IsUser32 = False is useful for the emulator handle (NoxPlayer handle example included).
  • If hwnd parameter equal "", it will use whole screen instead.
Functions:

  • Global Functions: Run multiple functions with one capture.
    • _GlobalImgInit: Initialization variables.
    • _GlobalImgCapture: Capture the handle.
    • _GlobalGetBitmap: Get captured bitmap handle.
    • _GlobalImgSearch: This is the main function of this UDF.
    • _GlobalGetPixel: Get pixel color in captured image.
    • _GlobalPixelCompare: Compare pixel color with captured image pixel color.
  • Handle Functions: Capture every time.
    • _HandleImgSearch: This is the main function of this UDF. Search for images in the handle of the window with the tolerance and maximum image options.
    • _BmpImgSearch: Search picture in picture instead of handle.
    • _HandleGetPixel: Get pixel in handle image.
    • _HandlePixelCompare: Compare color with pixel color of handle image.
    • _HandleCapture: Capture handle screen.
Thanks to:
  • ImageSearchDLL (Author: kangkeng 2008)
  • MemoryCall (Author: Joachim Bauch)
  • BinaryCall (Author: Ward)

Source code: https://github.com/lamnhan066/HandleImgSearch
 
Автор
I

ivantu

Новичок
Сообщения
8
Репутация
1
Для работы в реально времени можно использовать без проблем, по потреблению ресурсов тоже не заметил особого прожорства )
 

Oki

Продвинутый
Сообщения
452
Репутация
63
по потреблению ресурсов тоже не заметил особого прожорства )
В данном случае ресурс времени решающий. Если получается нетривиального размера картинки с толерантностью обрабатывать в реальном времени, это замечательно.
 
Верх