Page 1 sur 1

Fonctionnement PixelSearch

Posté : ven. 19 févr. 2021 18:52
par TommyDDR
Bonjour,

Si JCHD passe dans le coin, j'ai une question concernant PixelSearch, j'aimerai savoir comment il fonctionne en interne, en effet, après analyse :
scan.png
J'ai voulu faire de même, je récupère bien les octets correspondants aux couleurs, mais je bloque sur la fonction de recherche.
D'un coté je cherche avec DllStructGetData qui est relativement rapide si le pixel à trouver est proche du début de la recherche et d'un autre je cherche avec StringInStr qui est (contre toute attente) beaucoup plus performant que la 1ere solution quand le pixel se trouve vers la fin.
Alors que PixelSearch reste constant à ~40ms quel que soit la position du pixel à trouver.
#include <Color.au3>
#include <GDIPlus.au3>
#include <GUIConstantsEx.au3>
#include <StructureConstants.au3>
#include <WinAPI.au3>
#include <WinAPIGdi.au3>
#include <WindowsConstants.au3>

Opt("MustDeclareVars", 1)

Global $color = 0xEF7812
Global $posGui = [[0, 0], [@DesktopWidth - 1, @DesktopHeight - 1]]

Global $gui = GUICreate("", 1, 1, 0, 0, $WS_POPUP)
GUISetBkColor($color, $gui)
GUISetState(@SW_SHOW, $gui)
WinSetOnTop($gui, "", 1)

For $i = 0 To UBound($posGui, 1) - 1
   WinMove($gui, "", $posGui[$i][0], $posGui[$i][1])
   pixelSearch_PixelSearch(0, 0, @DesktopWidth - 1, @DesktopHeight - 1, $color)
   pixelSearch_StringMid(0, 0, @DesktopWidth - 1, @DesktopHeight - 1, $color)
   pixelSearch_DLLStructGetData(0, 0, @DesktopWidth - 1, @DesktopHeight - 1, $color)
   ConsoleWrite(@CRLF)
Next

Func pixelSearch_PixelSearch($l, $t, $r, $b, $color)
   Local $timer = TimerInit()
   Local $pos = PixelSearch($l, $t, $r, $b, $color)
   If(Not(IsArray($pos))) Then
      Dim $pos[2] = [-1, -1]
   EndIf
   ConsoleWrite("PixelSearch : " & TimerDiff($timer) & " ms" & @CRLF)
   ConsoleWrite("Pos : " & $pos[0] & ", " & $pos[1] & @CRLF)
EndFunc

Func pixelSearch_StringMid($l, $t, $r, $b, $color)
   Local $timer = TimerInit()
   Local $pos = pixelSearch2($l, $t, $r, $b, $color, True)
   ConsoleWrite("pixelSearch_StringMid : " & TimerDiff($timer) & " ms" & @CRLF)
   ConsoleWrite("Pos : " & $pos[0] & ", " & $pos[1] & @CRLF)
EndFunc

Func pixelSearch_DLLStructGetData($l, $t, $r, $b, $color)
   Local $timer = TimerInit()
   Local $pos = pixelSearch2($l, $t, $r, $b, $color, False)
   ConsoleWrite("pixelSearch_DLLStructGetData : " & TimerDiff($timer) & " ms" & @CRLF)
   ConsoleWrite("Pos : " & $pos[0] & ", " & $pos[1] & @CRLF)
EndFunc

Func pixelSearch2($l, $t, $r, $b, $color, $isStringMid)
   Local $w = $r - $l + 1
   Local $h = $b - $t + 1
   Local $hdc = _WinAPI_GetDC(0)
   Local $hBmp = _WinAPI_CreateCompatibleBitmap($hdc, $w, $h)
   Local $hdc2 = _WinAPI_CreateCompatibleDC($hdc)
   Local $oldObj = _WinAPI_SelectObject($hdc2, $hBmp)
   Local $ret = _WinAPI_StretchBlt($hdc2, $l, $t, $w, $h, $hdc, $l, $t, $w, $h, $SRCCOPY)
   Local $lpBitmapInfo = DllStructCreate($tagBITMAPINFO)
   DllStructSetData($lpBitmapInfo, "biSize", 40)
   DllStructSetData($lpBitmapInfo, "biWidth", $w)
   DllStructSetData($lpBitmapInfo, "biHeight", -1 * $h)
   DllStructSetData($lpBitmapInfo, "biPlanes", 1)
   DllStructSetData($lpBitmapInfo, "biBitCount", 32)
   DllStructSetData($lpBitmapInfo, "biCompression", 0)
   DllStructSetData($lpBitmapInfo, "biSizeImage", 0)
   DllStructSetData($lpBitmapInfo, "biXPelsPerMeter", 0)
   DllStructSetData($lpBitmapInfo, "biYPelsPerMeter", 0)
   DllStructSetData($lpBitmapInfo, "biClrUsed", 0)
   DllStructSetData($lpBitmapInfo, "biClrImportant", 0)
   DllStructSetData($lpBitmapInfo, "biRGBQuad", 0)

   $ret = _WinAPI_GetDIBits($hdc2, $hBmp, 0, 0, Null, $lpBitmapInfo, 0)

   Local $size = DllStructGetData($lpBitmapInfo, "biSizeImage")

   Local $pos = [-1, -1]
   If($isStringMid) Then
      Local $buffer = DllStructCreate("byte[" & $size & "]")
      $ret = _WinAPI_GetDIBits($hdc2, $hBmp, 0, $h, DllStructGetPtr($buffer), $lpBitmapInfo, 0)
      Local $scan0 = Hex(DllStructGetData($buffer, 1))

      Local $rgb = _ColorGetRGB($color)
      Local $search = Hex($rgb[2], 2) & Hex($rgb[1], 2) & Hex($rgb[0], 2) & "FF"
      Local $colorPos = 0
      Local $max = StringLen($scan0)
      Do
         $colorPos = StringInStr($scan0, $search, 0, $colorPos + 1)
         If($colorPos > $max) Then
            $colorPos = 0
         EndIf
      Until(Mod($colorPos-1, 8) == 0 Or $colorPos = 0)
      $colorPos = ($colorPos - 1) / 8
      If($colorPos >= 0) Then
         $pos[1] = Floor($colorPos / ($w))
         $pos[0] = $colorPos - $pos[1] * ($w)
      EndIf
   Else
      Local $buffer = DllStructCreate("int[" & $size/4 & "]")
      $ret = _WinAPI_GetDIBits($hdc2, $hBmp, 0, $h, DllStructGetPtr($buffer), $lpBitmapInfo, 0)

      $color = BitOR(0xFF000000, $color)
      Local $offset
      Local $pixel
      For $y = 0 To $h - 1
         $offset = $y * $w + 1
         For $x = 0 To $w - 1
            $pixel = DllStructGetData($buffer, 1, $offset + $x)
            If($color = $pixel) Then
               $pos[0] = $x
               $pos[1] = $y
               ExitLoop 2
            EndIf
         Next
      Next
   EndIf

   _WinAPI_SelectObject($hdc2, $oldObj)
   _WinAPI_DeleteObject($hBmp)
   _WinAPI_DeleteDC($hdc2)
   _WinAPI_ReleaseDC(Null, $hdc)
   Return $pos
EndFunc

Func quit()
   Exit
EndFunc
Voilà les résultats pour un pixel au début puis à la fin

Code : Tout sélectionner

PixelSearch : 46.5666 ms
Pos : 0, 0
pixelSearch_StringMid : 97.0011 ms
Pos : 0, 0
pixelSearch_DLLStructGetData : 30.6334 ms
Pos : 0, 0

PixelSearch : 36.9423 ms
Pos : 1919, 1079
pixelSearch_StringMid : 1246.8801 ms
Pos : 1919, 1079
pixelSearch_DLLStructGetData : 4511.4611 ms
Pos : 1919, 1079
Pour la petite histoire, j'ai besoin de faire une recherche de pixel sur une fenêtre qui est potentiellement hors écran ou caché par une autre (mais non minimisé) et PixelSearch ne permet de faire une recherche que sur l'écran et non pas dans une fenêtre (malgré son paramètre "hwnd" qui n'a pas l'air de changer quoi que ce soit, que la fenêtre soit visible ou non).

Re: Fonctionnement PixelSearch

Posté : ven. 19 févr. 2021 19:50
par jchd
Désolé mais je n'en ai aucune idée. Je n'ai pas d'accès au code source et je n'utilise pas AutoIt (sauf pour répondre sur les foras) et encore moins PixelSearch.

Re: Fonctionnement PixelSearch

Posté : sam. 20 févr. 2021 00:22
par TommyDDR
D'accord, dommage, merci quand même ^^