Fonctionnement PixelSearch

Aide et conseils concernant AutoIt et ses outils.
Règles du forum
.
Répondre
Avatar du membre
TommyDDR
Modérateur
Modérateur
Messages : 1945
Enregistré le : mar. 22 juil. 2008 21:55
Localisation : Nantes
Status : Hors ligne

Fonctionnement PixelSearch

#1

Message 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).
3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679
Avatar du membre
jchd
AutoIt MVPs (MVP)
AutoIt MVPs (MVP)
Messages : 2200
Enregistré le : lun. 30 mars 2009 22:57
Localisation : Sud-Ouest de la France (43.622788,-1.260864)
Status : Hors ligne

Re: Fonctionnement PixelSearch

#2

Message 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.
La cryptographie d'aujourd'hui c'est le taquin plus l'électricité.
Avatar du membre
TommyDDR
Modérateur
Modérateur
Messages : 1945
Enregistré le : mar. 22 juil. 2008 21:55
Localisation : Nantes
Status : Hors ligne

Re: Fonctionnement PixelSearch

#3

Message par TommyDDR »

D'accord, dommage, merci quand même ^^
3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679
Répondre