Bilderkennung

  • Hallo

    Ich möchte mit AutoIt einen Mausklick in einem Programmfenster implementieren. Mit ControlClick geht es leider nicht, ich muss MouseClick verwenden. Das Problem ist, dass der Ort des Klicks immer ein anderer ist. Ich dachte nun eine Möglichkeit wäre es den Ort per Bild zu erkennen. Also ich könnte z.B. der Funktion einen Bereich übergeben und zudem noch ein Bild und als Rückgabe bekomme ich x und y Koordinaten, also die Koordinaten wo das Bild im Programm liegt.

    Gibt es so etwas?

    2 Mal editiert, zuletzt von Helveticus (8. Januar 2012 um 11:01)

  • Es gibt eine UDF (ImageSearch.au3 oder ähnlich)
    Mit der kannst du nach einer "Pixelgruppe" (Bild) suchen und bekommst die Position raus. Das ganze läuft auch sehr schnell.

    Evtl kannst du auch überprüfen wo sich das Fenster befindet (Wenn sich der Button nicht verschiebt sondern nur das Fenster) und dann immer, abhängig von Position des Fensters, klicken.

    mfg BB

    "IF YOU'RE GOING TO KILL IT
    OPEN SOURCE IT!"

    by Phillip Torrone

    Zitat von Shoutbox

    [Heute, 11:16] Andy: ....böseböseböseböse....da erinnere ich mich daran, dass man den Puschelschwanz eines KaRnickels auch "Blume" nennt....ob da eins zum anderen passt? :rofl: :rofl: :rofl: :rofl:

    https://autoit.de/index.php?page…leIt#post251138

    Neon Snake

  • ImageSearch
    [autoit]

    ;===============================================================================
    ;
    ; Description: Find the position of an image on the desktop
    ; Syntax: _ImageSearchArea, _ImageSearch
    ; Parameter(s):
    ; $sImage - the image to locate on the desktop
    ; $iTolerance - 0 for no tolerance (0-255). Needed when colors of
    ; image differ from desktop. e.g GIF
    ; $iPosition - Set where the returned x,y location of the image is.
    ; 1 for centre of image, 0 for top left of image
    ; $iX $iY - Return the X and Y location of the image
    ;
    ; Return Value(s): On Success - Returns 1
    ; On Failure - Returns 0
    ;
    ; Note: Use _ImageSearch to search the entire desktop, _ImageSearchArea to specify
    ; a desktop region to search
    ;
    ;===============================================================================
    Func _ImageSearch ($sImage, $iPosition, ByRef $iX, ByRef $iY, $iTolerance)
    Return _ImageSearchArea ($sImage, $iPosition, 0, 0, @DesktopWidth, @DesktopHeight, $iX, $iY, $iTolerance)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _ImageSearchArea ($sImage, $iPosition, $iLeft, $iTop, $iRight, $iBottom, ByRef $iX, ByRef $iY, $iTolerance)
    If $iTolerance > 0 Then $sImage = "*" & $iTolerance & " " & $sImage
    $aRet = DllCall ("ImageSearchDLL.dll", "str", "ImageSearch", "int", $iLeft, "int", $iTop, "int", $iRight, "int", $iBottom, "str", $sImage)
    If IsArray ($aRet) = 0 Then Exit
    If $aRet[0] = "0" Then Return 0

    $aArray = StringSplit ($aRet[0], "|")
    $IX = Int (Number ($aArray[2]))
    $iY = Int (Number ($aArray[3]))
    If $iPosition = 1 Then
    $iX = $iX + Int (Number ($aArray[4]) / 2)
    $iY = $iY + Int (Number ($aArray[5]) / 2)
    EndIf
    Return 1
    EndFunc

    [/autoit]
    WinGetPos
    [autoit]

    $aPos = WinGetPos (WinActive (""))
    If IsArray ($aPos) Then
    MouseClick ("left", $aPos[0], $aPos[1]) ; $aPos[0] und $aPos[1] sind die Koordinaten der linken oberen Ecke des Fensters.
    ; Du musst also noch Pixel dazu addieren, um den Button zu treffen... BadBunny-Version. :P
    ; Mehr dazu gibt es in der Hilfedatei.
    EndIf

    [/autoit]
  • Ich hätte da noch ein paar Fragen. Meine Fragen beziehen sich auf das ImageSearch Skript von $var.

    Ist die ImageSearch.au3 bereits vorhanden oder muss ich da noch selber ein Skript mit dem Code von $var erstellen

    Zitat


    Find the position of an image on the desktop



    Das steht beim Skript von $var. Ich möchte aber nicht ein image auf dem Desktop, sondern in einem Programm suchen, das sozusagen über dem Desktop drüber liegt. Wird das auch erkannt?

    Welches Format sollte das Image am besten haben? GIF, JPG,...? Und was für eine $iTolerance würde ihr für das Format verwenden? Was muss ich für $iX und $iY beim Funktionsaufruf wählen? Und noch eine letzte Frage. Mit $iLeft, $iTop, $iRight und $iBottom kann man ja ein Gebiet definieren. Sind das x- oder y-Koordinaten?

  • [autoit]

    _ImageSearch ($sImage, $iPosition, ByRef $iX, ByRef $iY, $iTolerance)

    [/autoit][autoit][/autoit][autoit]

    #comments-start
    $sImage muss ein Pfad zu einer Bilddatei sein. Eine 24bit BMP ist dabei ideal.
    $iPosition - wenn 1, dann wird die Mitte ausgegeben, bei 0 die linke obere Ecke.
    $iX und $iY müssen einfach nur vordefinierte Variablen sein. In diese werden später die Koordinaten gespeichert.
    $iTolerance muss zwischen 0 und 255 sein. Bei 0 wird das Bild nur gefunden, wenn es EXAKT übereinstimmt.
    Je höher, desto mehr "Spielraum" bleibt.

    [/autoit][autoit][/autoit][autoit]

    Mehr brauchst du nicht. (Außer die Funktion natürlich in dein Script einzufügen.)
    #comments-end

    [/autoit]

    €: Du brauchst noch die ImageSearchDLL.dll, ist mir gerade eingefallen.
    Google it.

  • Vielen Dank

    [autoit]

    Func _ImageSearchArea ($sImage, $iPosition, $iLeft, $iTop, $iRight, $iBottom, ByRef $iX, ByRef $iY, $iTolerance)

    [/autoit]

    Muss ich bei $iLeft die x-Koordinate und bei $iTop die y-Koordinate des linken oberen Ausschnittrandes und bei $iRight die x-Koordinate und bei $iBottom die y-Koordinate des rechten unteren Ausschnittsrandes mitgeben?

    In folgendem Thread hat es noch eine Funktion

    [autoit]

    Func _WaitForImageSearch($findImage,$waitSecs,$resultPosition,ByRef $x, ByRef $y,$tolerance)

    [/autoit]

    Also wo man eine Zeit, die maximal gesucht werden soll, mitgeben kann. Das möchte ich auch, allerdings für die _ImageSearchArea. Also die Suchfläche und die Suchzeit möchte ich begrenzen. Leider habe ich da keine Funktion gefunden. Kennt da jemand etwas?

  • Vielen Dank

    [autoit]

    Func _ImageSearchArea ($sImage, $iPosition, $iLeft, $iTop, $iRight, $iBottom, ByRef $iX, ByRef $iY, $iTolerance)

    [/autoit]

    Muss ich bei $iLeft die x-Koordinate und bei $iTop die y-Koordinate des linken oberen Ausschnittrandes und bei $iRight die x-Koordinate und bei $iBottom die y-Koordinate des rechten unteren Ausschnittsrandes mitgeben?

    Genau richtig.

    Also wo man eine Zeit, die maximal gesucht werden soll, mitgeben kann. Das möchte ich auch, allerdings für die _ImageSearchArea. Also die Suchfläche und die Suchzeit möchte ich begrenzen. Leider habe ich da keine Funktion gefunden. Kennt da jemand etwas?

    Das kannst du dir ganz einfach selbst basteln. :P

    [autoit]

    Local $iTimer = TimerInit ()
    Do
    $iSearch = _ImageSearchArea ($sImage, $iPosition, $iLeft, $iTop, $iRight, $iBottom, ByRef $iX, ByRef $iY, $iTolerance)
    Until $iSearch = 1 Or TimerDiff ($iTimer) >= 5000 ; Sucht fünf Sekunden, oder bis das Bild gefunden wurde.
    ; Wenn du diese Version verwendest, solltest du am besten noch nach der Schleife abfragen, ob die Schleife durch das "Timeout" verlassen wurde,
    ; oder ob das Bild gefunden wurde. Das ist in den meisten Fällen wichtig...

    [/autoit]
  • Ist es eigentlich möglich, dass man die ImageSearch Funktion nebenher in einem Skript laufen lässt? Also so, dass das Skript weiter ausgeführt wird, aber im Hintergrund immer nach einem Bild gesucht wird und wenn eines gefunden wurde, die Ausführung des Skripts unterbrochen wird.

  • Hi,
    sowohl um ein Bild zu erstellen, als auch dieses "Bild" auf dem Screen zu finden und ggf. anzuklicken, gibt es "PushTheButton". Ideal also, um z.B. in Browsern Buttons anzuklicken, die man sonst nicht erreicht.
    Die Suche erfolgt entweder in AutoIt-code, dann wird das Bild in ca. 30-40ms auf einem HD-Screen gefunden, wenn die prospeed.dll im Verzeichnis liegt, wird für die Suche eine Assemblerroutine benutzt, dann findet PushTheButton das Bild in einigen Millisekunden.
    Buttons die beim Mouseover "highlighten", kann man ebenso finden wie animierte Buttons oder sich bewegende Grafiken, wie z.B. der folgende Smilie :rofl:
    Alle Funktionen sind einstellbar im Taskmenü, die Anleitung (auch dort) sollte man durchlesen.

  • Vielen Dank, ich möchte aber eben die ImageSearch Funktion aus der ImageSearch.au3 nebenher benutzen, also so dass das Skript weiterläuft im Hintergrund aber immer nach einem bestimmen Bild gesucht wird.

  • Zitat

    also so dass das Skript weiterläuft im Hintergrund aber immer nach einem bestimmen Bild gesucht wird.

    Auch das ist per PtB natürlich möglich.Genau dafür wurde das Programm ja erstellt^^
    Da die Suchzeit so minimal ist, kann z.B. per Adlib alle 10-20ms der komplette Bildschirm durchsucht werden. In dieser Zeit läuft das Hauptprogramm natürlich weiter.....

  • Was macht denn Adlib?

    Ich habe mir mal deine PushTheButton.au3 angeschaut. Das hast du dir ja sehr viel Arbeit gemacht. Allerdings verstehe ich es nicht ganz wie ich es benutzen muss, habe mir alles durchgelesen. In der PushTheButton.au3 hat es ja sehr viele Funktionen, weiss jetzt nicht welche ich verwenden muss. Und die Demo AU3 ist auch sehr umfangreich. Ich habe ein Screenshot eines Buttons erstellt und möchte nun ganz einfach nach diesem Button suchen.

  • Hi,
    Adlibregister ruft eine Funktion alle x Millisekunden auf

    Beispiel:
    Du erstellst per PtB eine Datei "buttontest.bmp" mit dem Inhalt deines Buttons.
    Achtung, wenn schon mehrere dieser Dateinahmen bestehen, erstellt PtB automatisch eine Folge, also z.B. "buttontest_0001.bmp", dann ggf anpassen/umbenennen anderen Namen wählen.

    Beispielscript starten.

    Spoiler anzeigen
    [autoit]

    #include <WinAPI.au3>
    #include <Array.au3>
    #include <GDIPlus.au3>
    #include <GDIPlusConstants.au3>
    #include <ScreenCapture.au3>
    #include <StructureConstants.au3>
    #include <WinAPI.au3>
    ;#include <prospeed30.au3>
    #include <WindowsConstants.au3>
    #include-once

    [/autoit] [autoit][/autoit] [autoit]

    ;**********example***************
    _GDIPlus_Startup()
    If FileExists("prospeed.dll") Then $prospeed_dll = DllOpen("prospeed.dll")
    AdlibRegister("_findbutton", 100) ;alle 100ms Funktion aufrufen

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    While 1 ;hauptprogramm
    Sleep(100)
    WEnd

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _findbutton()
    Local $coord = _PtB_ClickBMP("buttontest.bmp", "FULLSCREEN");bild im kompletten screen suchen
    If IsArray($coord) Then
    MsgBox(0, "_findbutton()", "Button gefunden an x=" & $coord[0] & " y=" & $coord[1], 3)
    Return $coord
    EndIf
    EndFunc ;==>_findbutton
    ;***********example end**************

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ; #FUNCTION# ====================================================================================================================
    ; Name...........: _PtB_clickBMP (needs prospeed.dll from http://frabbing.bplaced.net/ for fast search in memory)
    ; Description ...: searches a Bitmap in the full Screen or in a Window and clicks at the found position of the Bitmap
    ; It is recommended to use the PushTheButton-Program (http://www.AutoIt.de) for the creation of the Bitmap
    ; Syntax.........: _PtB_clickBMP($bitmapfile[, $hWin = "FULLSCREEN"[,$sMouseButton="left"[, $iClicks=1 ]]]]])
    ; Parameters ....: $bitmapfile - Name of the Bitmap-File to search for
    ; $hWin - Title/Handle of the window to search in, or "FULLSCREEN", or "" for active window
    ; $MouseButton - The button to click: "left", "right", "middle", "main", "menu", "primary", "secondary".
    ; $iClick - The number of times to click the mouse. Default is 1. 0 is possible^^
    ; Return values .: Success - Array with coordinates of the Mouseclick x=array[0] y=array[1]
    ; - if "FULLSCREEN" then coordinates are absolute screen coordinates
    ; - otherwise relative coords to the active window
    ; Failure - @error is set to 1
    ; Author ........: Andy @ http://www.autoit.de
    ; Modified.......:
    ; Remarks .......:
    ; Related .......:
    ; Link ..........;
    ; Example .......; Yes
    ; ===============================================================================================================================
    ;
    ;TODO: wenn vertikale scrollbalken im fenster/fullscreen sind, scrollen erlauben und nur scrollbalken auf bewegung checken

    [/autoit] [autoit][/autoit] [autoit]

    ;untersucht, ob Bitmap2 in Bitmap1 enthalten ist
    ;Originalfunc by JunkEW , modified by Andy@ http://www.autoit.de, finds the exact match
    Func _PtB_ClickBMP($bitmapfile, $hWin = "FULLSCREEN", $sMousebutton = "left", $iClicks = 0) ;rückgabe x- und y-position des gefundenen hotspots in einem array [0]und[1]

    [/autoit] [autoit][/autoit] [autoit]

    Dim $aresult[2] ;return array x- and y-coords
    Local $gefunden = 0, $maxanzahlpixel = 50, $exitflag = 0, $check, $pixel, $px, $py, $dx, $dy
    Local $window_height, $window_width, $xy, $pix, $prozent

    [/autoit] [autoit][/autoit] [autoit]

    If $hWin = "" Then $hWin = "[ACTIVE]" ;
    If $hWin = Default Then $hWin = "FULLSCREEN" ;suche im gesamten Bildschirminhalt
    If $sMousebutton = Default Then $sMousebutton = "left"
    If $iClicks = Default Then $iClicks = 1
    Local $opt_1 = Opt("mouseclickdelay") ;sichern der Optionen, werden am ende der Funktion wieder hergestellt
    Local $opt_2 = Opt("mouseclickdowndelay")
    Local $opt_3 = Opt("MouseCoordMode")
    Local $opt_4 = Opt("PixelCoordMode")
    Local $PtBfile = StringTrimRight($bitmapfile, StringLen($bitmapfile) - StringInStr($bitmapfile, ".") + 1) & ".ptb"
    Opt("mouseclickdelay", 1)
    Opt("mouseclickdowndelay", 1)
    ;im ptbfile sind Parameter für das Suchen der Bitmaps abgelegt
    Local $file = FileOpen($PtBfile, 0) ;daten lesen
    If $file = -1 Then ;fehler beim datenlesen, oder ptb-Datei nicht vorhanden
    If FileExists($bitmapfile) Then ;wenn es aber eine Bitmap gibt, dann kann man auch nur mit der
    $Anzahl_bestpixel = 500 ;bitmapsuche suchen
    Else ;wenn es weder Bitmap noch *.ptb-file gibt, fällt die Suche aus^^
    MsgBox(262144 + 1, "Fehler in Funktion _PtB_ClickBMP()", "Keine Bitmap und keine *.ptb-Datei mit Informationen zur Suche gefunden!" & @CRLF & "Bitte benutzen Sie das Programm PushTheButton, um eine Bitmap zu erzeugen!")
    SetError(1, 0, 1)
    Return -1
    EndIf
    Else ;ansonsten daten aus der *.ptb-Datei einlesen
    $check = FileReadLine($file, 1) ;pixelchecksum
    $pixel = FileReadLine($file, 2) ;pixelfarbe in hex RGB
    $Anzahl_bestpixel = Number(FileReadLine($file, 3)) ;niedrigste Anzahl der gesuchten Pixel
    $px = FileReadLine($file, 4) ;x-Versatz des Hotspots innerhalb des pics
    $py = FileReadLine($file, 5) ;y-Versatz des Hotspots innerhalb des pics
    $dx = FileReadLine($file, 6) ;breite in pixel
    $dy = FileReadLine($file, 7) ;hoehe in pixel
    FileClose($PtBfile)
    EndIf
    If $hWin = "FULLSCREEN" Then
    Opt("PixelCoordmode", 1) ; für Fullscreen setzen
    Opt("MouseCoordMode", 1) ;gesamter screen
    ;thx an Funkey
    Local $VirtualDesktopWidth = DllCall("user32.dll", "int", "GetSystemMetrics", "int", 78) ;sm_virtualwidth
    $window_width = $VirtualDesktopWidth[0]
    Local $VirtualDesktopHeight = DllCall("user32.dll", "int", "GetSystemMetrics", "int", 79) ;sm_virtualheight
    $window_height = $VirtualDesktopHeight[0]
    Else
    Opt("PixelCoordmode", 0) ;für lokales Fenster setzen
    Opt("MouseCoordMode", 0) ;aktives Fenster
    $xy = WinGetPos($hWin) ;breite und höhe des Fensters
    $window_width = $xy[2]
    $window_height = $xy[3]
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    If $Anzahl_bestpixel > $maxanzahlpixel Then ;wenn wenige passende farbige pixel auf dem Bildschirm sind...
    ConsoleWrite("Verfahren mit Bitmapsuche gewählt" & @CRLF) ;dann strings suchen (Bitmap2 in Bitmap1 suchen)
    If FileExists(@ScriptDir & "\ProSpeed.dll") Then
    $aresult = _FindBMP($hWin, $bitmapfile) ;suchen per stringfunktion in der Bitmap
    Else
    $aresult = _FindBMP_slow($hWin, $bitmapfile) ;suchen per stringfunktion in der Bitmap
    EndIf
    If IsArray($aresult) Then $gefunden = 1

    [/autoit] [autoit][/autoit] [autoit]

    Else ;wenn es nur wenige Pixel in der angegebenen Farbe gibt, ist diese Variante mit pixelsearxch schneller
    ConsoleWrite("Verfahren mit Pixelsuche gewählt" & @CRLF)
    Local $x = 0, $y = 0
    While 1
    $pix = PixelSearch($x, $y, $window_width, $window_height, Dec($pixel)) ;pixelfarbe suchen
    If @error Or $exitflag Then ExitLoop ;nicht gefunden oder esc gedrückt, dann pagedown
    ;msgbox(0,"pix gefunden an",$pix[0]&" "&$pix[1])
    While 1
    $x = $pix[0] ;x- und y-koordinaten des gefundenen pixels (hotspot)
    $y = $pix[1]
    ;$prozent = ($y * $window_width + $x) * 100 / $window_width / $window_height
    ;ToolTip(StringFormat("Suche läuft : %.0f%%", $prozent), $window_width / 2, $window_height / 2)
    Local $p1x = $x - $px, $p1y = $y - $py ;umrechnen der hotspotkoordinaten für checksum
    Local $p2x = $p1x + $dx - 1, $p2y = $p1y + $dy - 1
    ; msgbox(0,"pixel mit farbe "&$pixel,$p1x&" "&$p1y&@crlf&$p2x&" "&$p2y&@crlf&PixelChecksum($p1x,$p1y,$p2x,$p2y))
    If PixelChecksum($p1x, $p1y, $p2x, $p2y) = $check Then ;wenn pixelchecksum gleich der gespeicherten pixelchecksum ist, dann gefunden
    $gefunden = 1
    $aresult[0] = $x
    $aresult[1] = $y
    ExitLoop
    EndIf
    $x += 1 ;ein pixel weiter in der zeile
    $pix = PixelSearch($x, $y, $window_width, $y, Dec($pixel)) ;pixel suchen
    If @error Or $exitflag Then ExitLoop ;wenn in der zeile kein pixel mehr, dann raus
    WEnd
    If $gefunden = 1 Then ExitLoop
    $x = 0 ;neue spalte
    $y += 1 ;neue zeile
    WEnd
    EndIf
    $exitflag = 0
    ;ToolTip("")
    If $gefunden = 0 Then ;gesuchte Pixel nicht gefunden
    SetError(1, 0, 1)
    Return -1
    Else ;gefunden
    MouseMove($aresult[0], $aresult[1], 0) ;maus schnellstmöglich zur Position
    For $i = 1 To $iClicks ;anzahl der klicks
    MouseDown($sMousebutton) ;es wird die maustaste betätigt
    MouseUp($sMousebutton)
    Next
    SetError(0, 0, 0)
    Opt("mouseclickdelay", $opt_1)
    Opt("mouseclickdowndelay", $opt_2)
    Opt("MouseCoordMode", $opt_3)
    Opt("PixelCoordMode", $opt_4)
    Return $aresult ;array mit den hotspot-koordinaten zurückgeben
    EndIf
    EndFunc ;==>_PtB_ClickBMP

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ;untersucht, ob Bitmap2 in Bitmap1 enthalten ist
    ;Originalfunc by JunkEW , modified by Andy@ http://www.autoit.de, finds the exact match
    ;modified by Andy November,6,2011
    Func _FindBMP($BMP1, $BMP2)
    Dim $BMP1Data = "", $BMP1Width = 0, $BMP1Height = 0, $BMP1LineWidth = 0, $pbitmap1 = 0, $bitmapinfo1
    Dim $BMP2Data = "", $BMP2Width = 0, $BMP2Height = 0, $BMP2LineWidth = 0, $pbitmap2 = 0, $bitmapinfo2
    Dim $koord[2]
    Local $searchFor, $line, $iPos = 1, $imgBytes = 3, $exit
    Local $ptr1, $ptr2, $struct_bmp1, $struct_bmp2, $struct_1, $struct_2
    Local $string_1, $string_2, $prozent, $flag, $a, $b, $xy
    Local $VirtualDesktopWidth = DllCall("user32.dll", "int", "GetSystemMetrics", "int", 78) ;sm_virtualwidth
    Local $DesktopWidth = $VirtualDesktopWidth[0]
    Local $VirtualDesktopHeight = DllCall("user32.dll", "int", "GetSystemMetrics", "int", 79) ;sm_virtualheight
    Local $DesktopHeight = $VirtualDesktopHeight[0]

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $ptr1 = _GetImage($BMP1, $BMP1Data, $BMP1Width, $BMP1Height, $BMP1LineWidth, $pbitmap1, $bitmapinfo1) ;holt alle Infos aus der Bitmap (Fullscreen, Fenster oder File)
    $ptr2 = _GetImage($BMP2, $BMP2Data, $BMP2Width, $BMP2Height, $BMP2LineWidth, $pbitmap2, $bitmapinfo2)

    [/autoit] [autoit][/autoit] [autoit]

    If $BMP2Height = 0 Then
    SetError(1, 0, 0)
    Return False
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    $exit = DllStructGetSize($ptr1) + 1 ;letzte mögliche bildschirm(fenster) position)
    $struct_2 = DllStructCreate("ubyte[" & ($BMP2Width * 3) & "]");erste zeile der 2. bitmap, nach dieser Position wird gin der ersten Bitmap gesucht
    DllStructSetData($struct_2, 1, $BMP2Data)

    [/autoit] [autoit][/autoit] [autoit]

    ;erste Zeile der Bitmap2 in Bitmap1 suchen
    $iPos = FindBytes(DllStructGetPtr($ptr1), 0, DllStructGetSize($ptr1) - DllStructGetSize($struct_2) - (($BMP2Height - 1) * $BMP1LineWidth), DllStructGetPtr($struct_2), DllStructGetSize($struct_2)) + 1
    ;zeilenweises vergleichen der beiden bitmaps, ist bitmap2 in bitmap1 enthalten?
    While 1
    If $iPos <> 0 And $iPos <> $exit Then ;nur, wenn es eine übereinstimmung gibt weitermachen
    ; ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $iPos = ' & $iPos & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    Local $e = Mod(($iPos - 1), $BMP1LineWidth) ;position innerhalb des Strings
    ;~ If $e / $imgBytes = Int($e / $imgBytes) Then ;prüfen ob ipos am anfang eines farbbits steht, wenn nicht, nächste zeile suchen
    ;~ $prozent = $iPos / 3 * 100 / $BMP1Width / $BMP1Height
    ;~ ToolTip(StringFormat("Suche läuft : %.0f%%", $prozent) & @CRLF & "Zeile " & Int($iPos / $imgBytes / $BMP1Width), $BMP1Width / 2, $BMP1Height / 2)
    $flag = 0
    For $i = 0 To $BMP2Height - 1 ;zeilenweise die Bitmaps vergleichen
    $a = DllStructGetPtr($ptr1) + $iPos - 1 + $i * $BMP1LineWidth ;pointer auf die position in der struct, an der die erste übereinstimmung ist
    $b = DllStructGetPtr($ptr2) + $i * $BMP2LineWidth ;pointer auf die zeile
    If CompareBytes($a, $b, 3 * $BMP2Width, 0) <> 0 Then ;wenn keine Übereinstimmung, dann nächste suchen
    $flag = 1
    ExitLoop
    EndIf
    Next
    If $flag = 0 Then ;alle zeilen haben übereingestimmt, BMP2 ist in BMP1 enthalten! $koord[0] = Mod(($iPos - 1), $BMP1LineWidth) / $imgBytes ;koordinaten auf dem screen
    $koord[0] = Mod(($iPos - 1), $BMP1LineWidth) / $imgBytes ;koordinaten auf dem screen
    $koord[1] = Int(($iPos - 1) / $BMP1LineWidth)
    $BMP1Data = 0 ;strukturen löschen, Speicher freigeben
    $BMP2Data = 0
    $struct_2 = 0
    $ptr1 = 0
    $ptr2 = 0
    _GDIPlus_BitmapUnlockBits($pbitmap1, $bitmapinfo1)
    _GDIPlus_BitmapUnlockBits($pbitmap2, $bitmapinfo2)
    _GDIPlus_ImageDispose($pbitmap1) ;Bitmaps löschen
    _GDIPlus_ImageDispose($pbitmap2)
    Return $koord
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    $iPos = FindBytes(DllStructGetPtr($ptr1), $iPos + $imgBytes, DllStructGetSize($ptr1) - DllStructGetSize($struct_bmp2) - (($BMP2Height - 1) * $BMP1LineWidth) - $iPos, DllStructGetPtr($struct_2), DllStructGetSize($struct_2)) + 1
    If $iPos = 0 Or $iPos = $exit Then ExitLoop ;nicht gefunden
    ;~ Else ;ipos ist innerhalb eines farbbits und nicht am anfang
    ;~ $iPos = FindBytes(DllStructGetPtr($ptr1), $iPos + 1, DllStructGetSize($ptr1) - DllStructGetSize($struct_bmp2) - (($BMP2Height - 1) * $BMP1LineWidth) - $iPos, DllStructGetPtr($struct_2), DllStructGetSize($struct_2)) + 1
    ;~ If $iPos = 0 Or $iPos = $exit Then ExitLoop
    ;~ EndIf
    Else
    ExitLoop
    EndIf
    WEnd
    $BMP1Data = 0 ;strukturen löschen, Speicher freigeben
    $BMP2Data = 0
    $struct_2 = 0
    $ptr1 = 0
    $ptr2 = 0
    _GDIPlus_BitmapUnlockBits($pbitmap1, $bitmapinfo1)
    _GDIPlus_BitmapUnlockBits($pbitmap2, $bitmapinfo2)
    _GDIPlus_ImageDispose($pbitmap1) ;Bitmaps löschen
    _GDIPlus_ImageDispose($pbitmap2)
    SetError(1, 0, 1)
    Return 0 ;
    EndFunc ;==>_FindBMP

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ;aus einer Datei oder einem Screenshot die Pixeldaten im BGR-Format in einen String schreiben
    ;Originalfunc by JunkEW , modified by Andy@ http://www.autoit.de, gets the Bitmapdata as BGR-String
    Func _GetImage($bmpfile, ByRef $BMPDataStart, ByRef $Width, ByRef $Height, ByRef $Stride, ByRef $pBitmap, ByRef $BitmapData)

    [/autoit] [autoit][/autoit] [autoit]

    Local $Scan0, $hbScreen, $handle, $imgBytes = 3, $pixeldata, $pixeldata2, $xy
    Local $VirtualDesktopWidth = DllCall("user32.dll", "int", "GetSystemMetrics", "int", 78) ;sm_virtualwidth
    Local $VirtualDesktopHeight = DllCall("user32.dll", "int", "GetSystemMetrics", "int", 79) ;sm_virtualheight

    [/autoit] [autoit][/autoit] [autoit]

    ; Load the bitmap to search in
    If StringUpper($bmpfile) = "FULLSCREEN" Then
    $hbScreen = _ScreenCapture_Capture("", 0, 0, $VirtualDesktopWidth[0], $VirtualDesktopHeight[0], False)
    If @error Then MsgBox(0, "", "Fehler Screencapture FULLSCREEN")
    $pBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hbScreen); returns memory bitmap
    If @error Then MsgBox(0, "", "Fehler Bitmapcreate_FromHBITMAP Screen")
    Else
    ;try to get a handle
    $handle = WinGetHandle($bmpfile)
    If @error Then
    ;Assume its an unknown handle so correct filename should be given
    $hbScreen = _GDIPlus_BitmapCreateFromFile($bmpfile)
    $pBitmap = $hbScreen
    If @error Then MsgBox(0, "", "Fehler BitmapCreateFromFile")
    Else ;aktuelles fenster
    $xy = WinGetPos($bmpfile)
    $hbScreen = _ScreenCapture_CaptureWnd("", $handle, 0, 0, $xy[2], $xy[3], False)
    If @error Then MsgBox(0, "", "Fehler Screencapturewnd")
    $pBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hbScreen); returns memory bitmap
    If @error Then MsgBox(0, "", "Fehler BitmapCreateFromHBITMAP File")
    EndIf
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    ;_GDIPlus_BitmapLockBits gibt $tagGDIPBITMAPDATA-Struktur zurück
    $BitmapData = _GDIPlus_BitmapLockBits($pBitmap, 0, 0, _GDIPlus_ImageGetWidth($pBitmap), _GDIPlus_ImageGetHeight($pBitmap), $GDIP_ILMREAD, $GDIP_PXF24RGB)
    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("byte[" & (Abs($Stride) * ($Height)) & "]", $Scan0)
    $BMPDataStart = DllStructGetData($pixeldata, 1) ;string im Struct-format, d.h. Byte+nulByte, in dem die pixeldaten im BGR-Format stehen
    ; _GDIPlus_BitmapUnlockBits($pbitmap, $BitmapData)
    ;_GDIPlus_ImageDispose($pBitmap) zerstört die pixeldatastruct, daher erst später!!!
    _WinAPI_DeleteObject($hbScreen)
    Return $pixeldata
    EndFunc ;==>_GetImage

    [/autoit] [autoit][/autoit] [autoit]

    Func _findbytes($string_1, $string_2, $startpos) ;string2 im string1 finden, erst ab sehr grossen strings schneller als stringinstr()
    Local $struct_1 = DllStructCreate("ubyte[" & (StringLen($string_1) + StringLen($string_2)) & "]")
    Local $struct_2 = DllStructCreate("ubyte[" & StringLen($string_2) & "]")
    DllStructSetData($struct_1, 1, $string_1 & $string_2)
    DllStructSetData($struct_2, 1, $string_2)
    Local $t = TimerInit()
    Local $pos = FindBytes(DllStructGetPtr($struct_1), $startpos, DllStructGetSize($struct_1), DllStructGetPtr($struct_2), DllStructGetSize($struct_2)) + 1
    Local $findbytes = TimerDiff($t)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $findbytes = ' & $findbytes & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    ; MsgBox(262144, 'Debug line ~' & @ScriptLineNumber, 'Selection:' & @LF & '$pos' & @LF & @LF & 'Return:' & @LF & $pos) ;### Debug MSGBOX
    $struct_1 = 0
    $struct_2 = 0

    [/autoit] [autoit][/autoit] [autoit]

    If $pos = -1 Or $pos = StringLen($string_1) + 1 Then Return 0
    Return $pos
    EndFunc ;==>_findbytes

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func CompareBytes($S_MemoryPointer1, $S_MemoryPointer2, $S_ByteSize, $S_Tolerance)
    Local $C_Compare = DllCall($prospeed_dll, "long", "CompareBytes", _
    "long", $S_MemoryPointer1, _
    "long", $S_MemoryPointer2, _
    "long", $S_ByteSize, _
    "long", $S_Tolerance)
    Return $C_Compare[0]
    EndFunc ;==>CompareBytes

    [/autoit] [autoit][/autoit] [autoit]

    Func FindBytes($b, $O, $a, $S, $L)
    Local $S_FindBytes = DllCall($prospeed_dll, "long", "FindBytes", _
    "long", $b, _
    "long", $O, _
    "long", $a, _
    "long", $S, _
    "long", $L)
    Return $S_FindBytes[0]
    EndFunc ;==>FindBytes

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _FindBMP_slow($BMP1, $BMP2)
    Dim $BMP1Data = "", $BMP1Width = 0, $BMP1Height = 0, $BMP1LineWidth = 0, $pbitmap1 = 0, $bitmapinfo1
    Dim $BMP2Data = "", $BMP2Width = 0, $BMP2Height = 0, $BMP2LineWidth = 0, $pbitmap2 = 0, $bitmapinfo2
    Dim $koord[2]
    Local $searchFor, $line, $iPos = 1, $imgBytes = 3, $prozent, $ptr1, $ptr2
    Local $VirtualDesktopWidth = DllCall("user32.dll", "int", "GetSystemMetrics", "int", 78) ;sm_virtualwidth
    Local $DesktopWidth = $VirtualDesktopWidth[0]
    Local $VirtualDesktopHeight = DllCall("user32.dll", "int", "GetSystemMetrics", "int", 79) ;sm_virtualheight
    Local $DesktopHeight = $VirtualDesktopHeight[0]

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ; Load the bitmap to search in
    $ptr1 = _GetImage($BMP1, $BMP1Data, $BMP1Width, $BMP1Height, $BMP1LineWidth, $pbitmap1, $bitmapinfo1)
    $BMP1Data = BinaryToString($BMP1Data)
    $ptr2 = _GetImage($BMP2, $BMP2Data, $BMP2Width, $BMP2Height, $BMP2LineWidth, $pbitmap2, $bitmapinfo2)
    $BMP2Data = BinaryToString($BMP2Data)
    If $BMP2Height = 0 Then
    SetError(1, 0, 0)
    Return False
    EndIf
    Local $searchFor1 = StringMid($BMP2Data, 1, ($BMP2Width * $imgBytes)) ;1. pixel-zeile in der bitmap2 (string)
    $iPos = StringInStr($BMP1Data, $searchFor1, 2, 1) ;1. fundstelle des strings in Bitmap2
    ;zeilenweises vergleichen der beiden bitmaps, ist bitmap2 in bitmap1 enthalten?
    While 1
    Local $flag = 0
    If $iPos <> 0 Then
    If ($iPos - 1) / $imgBytes = Int(($iPos - 1) / $imgBytes) Then ;;prüfen ob ipos am anfang eines farbbits steht
    $prozent = $iPos / 3 * 100 / $DesktopWidth / $DesktopHeight
    ToolTip(StringFormat("Suche läuft : %.0f%%", $prozent) & @CRLF & "Zeile " & Int($iPos / $imgBytes / $DesktopWidth), $DesktopWidth / 2, $DesktopHeight / 2)
    For $S = 2 To $BMP2Height ;zeilenweise das suchbild mit dem screen vergleichen
    $searchFor = StringMid($BMP2Data, 1 + (($S - 1) * $BMP2LineWidth), $BMP2Width * $imgBytes) ; s-te zeile aus dem ausschnitt
    $line = StringMid($BMP1Data, $iPos + (($S - 1) * $BMP1LineWidth), $BMP2Width * $imgBytes) ;zeile "unter" der gefundenen zeile im screen
    If $searchFor <> $line Then ;zeilen nicht gleich,
    $flag = 1
    ExitLoop ;exit for/next
    EndIf
    Next
    If $flag = 0 Then ;alle zeilen haben übereingestimmt, BMP2 ist in BMP1 enthalten! $koord[0] = Mod(($iPos - 1), $BMP1LineWidth) / $imgBytes ;koordinaten auf dem screen
    $koord[0] = Mod(($iPos - 1), $BMP1LineWidth) / $imgBytes ;koordinaten auf dem screen
    $koord[1] = Int(($iPos - 1) / $BMP1LineWidth)
    $BMP1Data = 0 ;strukturen löschen, Speicher freigeben
    $BMP2Data = 0
    $ptr1 = 0
    $ptr2 = 0
    _GDIPlus_BitmapUnlockBits($pbitmap1, $bitmapinfo1)
    _GDIPlus_BitmapUnlockBits($pbitmap2, $bitmapinfo2)
    _GDIPlus_ImageDispose($pbitmap1) ;Bitmaps löschen
    _GDIPlus_ImageDispose($pbitmap2)
    ToolTip("")
    Return $koord
    EndIf
    $iPos = StringInStr($BMP1Data, $searchFor1, 2, 1, $iPos + $imgBytes)
    If $iPos = 0 Then ExitLoop ;nicht gefunden
    Else ;ipos ist innerhalb eines farbbits und nicht am anfang
    $iPos = StringInStr($BMP1Data, $searchFor1, 2, 1, $iPos + 1)
    If $iPos = 0 Then ExitLoop
    EndIf
    Else
    ExitLoop
    EndIf
    WEnd
    $BMP1Data = 0 ;strukturen löschen, Speicher freigeben
    $BMP2Data = 0
    $ptr1 = 0
    $ptr2 = 0
    _GDIPlus_BitmapUnlockBits($pbitmap1, $bitmapinfo1)
    _GDIPlus_BitmapUnlockBits($pbitmap2, $bitmapinfo2)
    _GDIPlus_ImageDispose($pbitmap1) ;Bitmaps löschen
    _GDIPlus_ImageDispose($pbitmap2)
    ToolTip("")
    SetError(1, 0, 0)
    Return 0 ;
    EndFunc ;==>_FindBMP_slow

    [/autoit] [autoit][/autoit] [autoit][/autoit]


    // edit, na toll, script zu lang....ich zippe es//


    Wenn der Button auf dem Bildschirm sichtbar ist, wird er gefunden, der Mauszeiger wird zum Button bewegt und eine Messagebox mit den Koordinaten des Buttons erscheint. Diese Msgbox bleibt 3 Sekunden sichtbar, dann wird die Suche erneut durchgeführt, so lange, bis das Script beendet wird. In der Hauptschleife while/wend können die Koordinaten dann ausgewertet werden.
    Die Bewegung des Mauszeigers zum gefundenen Button kann man einfach unterbinden, indem das mousemove() auskommentiert wird.

    ciao
    Andy


    "Schlechtes Benehmen halten die Leute doch nur deswegen für eine Art Vorrecht, weil keiner ihnen aufs Maul haut." Klaus Kinski
    "Hint: Write comments after each line. So you can (better) see what your program does and what it not does. And we can see what you're thinking what your program does and we can point to the missunderstandings." A-Jay

    Wie man Fragen richtig stellt... Tutorial: Wie man Script-Fehler findet und beseitigt...X-Y-Problem

    Einmal editiert, zuletzt von Andy (8. Januar 2012 um 18:43)

  • Hi,
    Adlibregister ruft eine Funktion alle x Millisekunden auf

    Beispiel:
    Du erstellst per PtB eine Datei "buttontest.bmp" mit dem Inhalt deines Buttons.
    Achtung, wenn schon mehrere dieser Dateinahmen bestehen, erstellt PtB automatisch eine Folge, also z.B. "buttontest_0001.bmp", dann ggf anpassen/umbenennen anderen Namen wählen.

    Beispielscript starten.

    Spoiler anzeigen
    [autoit]

    #include <WinAPI.au3>
    #include <Array.au3>
    #include <GDIPlus.au3>
    #include <GDIPlusConstants.au3>
    #include <ScreenCapture.au3>
    #include <StructureConstants.au3>
    #include <WinAPI.au3>
    ;#include <prospeed30.au3>
    #include <WindowsConstants.au3>
    #include-once

    [/autoit] [autoit][/autoit] [autoit]

    ;**********example***************
    _GDIPlus_Startup()
    If FileExists("prospeed.dll") Then $prospeed_dll = DllOpen("prospeed.dll")
    AdlibRegister("_findbutton", 100) ;alle 100ms Funktion aufrufen

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    While 1 ;hauptprogramm
    Sleep(100)
    WEnd

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _findbutton()
    Local $coord = _PtB_ClickBMP("buttontest.bmp", "FULLSCREEN");bild im kompletten screen suchen
    If IsArray($coord) Then
    MsgBox(0, "_findbutton()", "Button gefunden an x=" & $coord[0] & " y=" & $coord[1], 3)
    Return $coord
    EndIf
    EndFunc ;==>_findbutton
    ;***********example end**************

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ;funktionen im zipfile

    [/autoit] [autoit][/autoit] [autoit][/autoit]


    autoit.de/wcf/attachment/14907/

    Wenn der Button auf dem Bildschirm sichtbar ist, wird er gefunden, der Mauszeiger wird zum Button bewegt und eine Messagebox mit den Koordinaten des Buttons erscheint. Diese Msgbox bleibt 3 Sekunden sichtbar, dann wird die Suche erneut durchgeführt, so lange, bis das Script beendet wird. In der Hauptschleife while/wend können die Koordinaten dann ausgewertet werden.
    Die Bewegung des Mauszeigers zum gefundenen Button kann man einfach unterbinden, indem das mousemove() auskommentiert wird.

  • Cool, vielen Dank, werde das gleich mal ausprobieren.

    Zitat

    Adlibregister ruft eine Funktion alle x Millisekunden auf

    Ich habe jetzt zwei Funktionen gefunden, AdlibRegister und AdlibEnable. Welche muss ich da benutzen? Konnte sie von der Funktionalität nicht unterscheiden. Und muss die Funktion die man AddlibRegister übergibt im gleichen Skript definiert sein, oder kann man auch eine externe Funktion aus einem anderen Skript, welches aber mit include eingebunden ist, verwenden?