Jump to content
Sign in to follow this  
InunoTaishou

PixelSearch in bitmap (handle to a bitmap, bitmap, or hdc)

Recommended Posts

Here's the goal:

  • Create a handle to a bitmap object using _WinApi_PrintWindow (this is done and working properly, I can take a screenshot of the window even when it's hidden or offscreen, does not work minimized)
  • Be able to search for a pixel color in memory on the handle. I can get it to work if I create a Bitmap from an HBITMAP (_GDIPlus_BitmapCreateFromHBITMAP) and then go through each pixel and check it using _GDIPlus_BitmapGetPixel but it's too slow. I've tried doing the _WinApi_GetPIxel using an $hDC but it's much slower than GDI+ (GD+ takes about 20seconds to search for almost 500,000 pixels, GetPixel takes almost 60seconds)

I found the FastFind library but, honestly, it's sloppy and I'm wanting to search a defined area, not set the starting position and then search the rest of the window. I also found a few examples on the forums but I could not get them to work.

Here's the CaptureWindow function. I'm only wanting to capture the client area (Not the border around the client, hence the -16 for the width and the -38 for the height, gets rid of the title bar and the resize bars on the sides. Also I'm wanting to keep the coordinates relative to the window, so if you only want to capture the screen from 480, 200 to 680, 400, then the rest of the area is black on purpose)

#include-once
Func CaptureWindow(Const $iLeft = 0, Const $iTop = 0, Const $iWidth = -1, Const $iHeight = -1, Const $hWindow = WinGetHandle("[Active]"))
    Local $rect_window = WinGetPos($hWindow)
    Local $hDC = _WinAPI_GetWindowDC($hWindow)
    Local $hDestDC = _WinAPI_CreateCompatibleDC($hDC)
    Local $hBitmap = _WinAPI_CreateCompatibleBitmap($hDC, $rect_window[2] - 16, $rect_window[3] - 38)
    Local $hDestSv = _WinAPI_SelectObject($hDestDC, $hBitmap)
    Local $hSrcDC = _WinAPI_CreateCompatibleDC($hDC)
    Local $hBmp = _WinAPI_CreateCompatibleBitmap($hDC, $rect_window[2] - 16, $rect_window[3] - 38)
    Local $hSrcSv = _WinAPI_SelectObject($hSrcDC, $hBmp)
    
    _WinAPI_PrintWindow($hWindow, $hSrcDC, True)
    
    If ($iWidth > 0 and $iHeight > 0) Then
        _WinAPI_BitBlt($hDestDC, $iLeft, $iTop, $iWidth, $iHeight, $hSrcDC, $iLeft, $iTop, $MERGECOPY)
    Else
        _WinAPI_BitBlt($hDestDC, $iLeft, $iTop, $rect_window[2] - 16 - $iLeft, $rect_window[3] - 38 - $iTop, $hSrcDC, $iLeft, $iTop, $MERGECOPY)
    EndIf
    
    _WinAPI_SelectObject($hDestDC, $hDestSv)
    _WinAPI_SelectObject($hSrcDC, $hSrcSv)
    _WinAPI_ReleaseDC($hWindow, $hDC)
    _WinAPI_DeleteDC($hDestDC)
    _WinAPI_DeleteDC($hSrcDC)
    _WinAPI_DeleteObject($hBmp)
    
    Return $hBitmap
EndFunc   ;==>CaptureWindow

And the first attempt for PixelSearch, using GDI+ (Fastest)

Func PixelSearchInhBitmap(Const ByRef $hHBmp, Const ByRef $color, Const $tolerance = 10, Const $iLeft = 0, Const $iTop = 0, $iWidth = -1, $iHeight = -1, Const $iStep = 1)
    Local $hBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hHBmp)
    Local $rbg_color = _ColorGetRGB("0x" & Hex($color, 6))
    Local $found_color = False
    Local $abscoord_color[2] = [0, 0]
    Local $red_low = 0
    Local $green_low = 0
    Local $blue_low = 0
    Local $red_high = 0
    Local $green_high = 0
    Local $blue_high = 0
    
    $red_low = ($tolerance > $rbg_color[0] ? 0 : $rbg_color[0] - $tolerance)
    $green_low = ($tolerance > $rbg_color[1] ? 0 : $rbg_color[1] - $tolerance)
    $blue_low = ($tolerance > $rbg_color[2] ? 0 : $rbg_color[2] - $tolerance)
    $red_high = ($tolerance > 255 - $rbg_color[0] ? 255 : $rbg_color[0] + $tolerance)
    $green_high = ($tolerance > 255 - $rbg_color[1] ? 255 : $rbg_color[1] + $tolerance)
    $blue_high = ($tolerance > 255 - $rbg_color[2] ? 255 : $rbg_color[2] + $tolerance)
    
    If ($iWidth = -1) Then $iWidth = _GDIPlus_ImageGetWidth($hBitmap)
    If ($iHeight = -1) Then $iHeight = _GDIPlus_ImageGetHeight($hBitmap)
    
    Local $start_time = TimerInit()
    For $iY = $iTop To $iHeight Step $iStep
        For $iX = $iLeft To $iWidth Step $iStep
            Local $get_pixel = _GDIPlus_BitmapGetPixel($hBitmap, $iX, $iY)
            If (@Error) Then ContinueLoop
            Local $pixel_color = _ColorGetRGB("0x" & Hex($get_pixel, 6))
            If (@Error) Then ContinueLoop
            
            If (($pixel_color[0] >= $red_low and $pixel_color[0] <= $red_high) and ($pixel_color[1] >= $green_low and $pixel_color[1] <= $green_high) and ($pixel_color[2] >= $blue_low and $pixel_color[2] <= $blue_high)) Then
                $found_color = True
                $abscoord_color[0] = $iX
                $abscoord_color[1] = $iY
                ExitLoop 2
            EndIf
        Next
    Next
    MsgBox("", "", TimerDiff($start_time) / 1000)
    _GDIPlus_BitmapDispose($hBitmap)
    
    If ($found_color) Then
        Return $abscoord_color
    Else
        Return SetError(-1, 0, 0)
    EndIf
EndFunc

Second attempt using _WInApi_GetPixel (Note. I replaced the Autoit function with my own where I replaced the string "gdi32.dll" with a handle to the opened DLL. In the hopes it would improve time. The time difference was not noticable)

Global $HWND_DLL_GDI32 = DLLopen("gdi32.dll")

Func PixelSearchInhDC(Const ByRef $color, Const $tolerance = 10, Const $iLeft = 0, Const $iTop = 0, $iWidth = -1, $iHeight = -1, Const $iStep = 1, Const $hWnd_window = WinGetHandle("[Active]"))
    Local $hDC = _WinAPI_GetWindowDC($hWnd_window)
    Local $rbg_color = _ColorGetRGB("0x" & Hex($color, 6))
    Local $found_color = False
    Local $abscoord_color[2] = [0, 0]
    Local $start_time, $end_time
    Local $red_low = 0
    Local $green_low = 0
    Local $blue_low = 0
    Local $red_high = 0
    Local $green_high = 0
    Local $blue_high = 0
    
    If (Not $hDC) Then
        Return SetError(1, 0, 0)
    EndIf
    
    If ($iWidth = -1 or $iHeight = -1) Then
        Local $rect_window = WinGetPos($hWnd_window)
        If ($iWidth = -1) Then $iWidth = $rect_window[2] - $iLeft
        If ($iHeight = -1) Then $iHeight = $rect_window[3] - $iTop
    EndIf
    
    $red_low = ($tolerance > $rbg_color[0] ? 0 : $rbg_color[0] - $tolerance)
    $green_low = ($tolerance > $rbg_color[1] ? 0 : $rbg_color[1] - $tolerance)
    $blue_low = ($tolerance > $rbg_color[2] ? 0 : $rbg_color[2] - $tolerance)
    $red_high = ($tolerance > 255 - $rbg_color[0] ? 255 : $rbg_color[0] + $tolerance)
    $green_high = ($tolerance > 255 - $rbg_color[1] ? 255 : $rbg_color[1] + $tolerance)
    $blue_high = ($tolerance > 255 - $rbg_color[2] ? 255 : $rbg_color[2] + $tolerance)
    
    $start_time = TimerInit()
    For $iY = $iTop To $iHeight Step $iStep
        For $iX = $iLeft To $iWidth Step $iStep
            Local $get_pixel = __WinAPI_GetPixel($hDC, $iX, $iY)
            If (@Error) Then ContinueLoop
            Local $pixel_color = _ColorGetRGB("0x" & Hex($get_pixel, 6))
            If (@Error) Then ContinueLoop
            
            If (($pixel_color[0] >= $red_low and $pixel_color[0] <= $red_high) and ($pixel_color[1] >= $green_low and $pixel_color[1] <= $green_high) and ($pixel_color[2] >= $blue_low and $pixel_color[2] <= $blue_high)) Then
                $found_color = True
                $abscoord_color[0] = $iX
                $abscoord_color[1] = $iY
                ExitLoop 2
            EndIf
        Next
    Next
    MsgBox("", "", TimerDiff($start_time) / 1000 & "s")
    
    If ($found_color) Then
        Return $abscoord_color
    Else
        Return SetError(1, 0, 0)
    EndIf
EndFunc

Func __WinAPI_GetPixel($hDC, $iX, $iY)
    Local $aRet = DllCall($HWND_DLL_GDI32, 'dword', 'GetPixel', 'handle', $hDC, 'int', $iX, 'int', $iY)
    If @error Or ($aRet[0] = 4294967295) Then Return SetError(@error, @extended, -1)
    ; If $aRet[0] = 4294967295 Then Return SetError(1000, 0, -1)

    Return __RGB($aRet[0])
EndFunc   ;==>__WinAPI_GetPixel

 

Edited by InunoTaishou

Share this post


Link to post
Share on other sites

Looked into _GDIPlus_BitmapLockBits, this seems to be a bit faster (about 8 seconds faster) but it still takes seconds to do the search.

#include <GDIPlus.au3>
#include <GUIConstantsEx.au3>
#include <MsgBoxConstants.au3>
#include <Color.au3>

_GDIPlus_Startup()

TestPixelSearch()

Func TestPixelSearch()
    Local $hImage = _GDIPlus_ImageLoadFromFile(@DesktopDir & "\CaptureWindow.jpg")
    Local $iW = _GDIPlus_ImageGetWidth($hImage), $iH = _GDIPlus_ImageGetHeight($hImage) ;get width and height of the image
    Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($iW, $iH)
    Local $hContext = _GDIPlus_ImageGetGraphicsContext($hBitmap)
    _GDIPlus_GraphicsDrawImageRect($hContext, $hImage, 0, 0, $iW, $iH)

    Local $tBitmapData = _GDIPlus_BitmapLockBits($hBitmap, 0, 0, $iW, $iH, BitOR($GDIP_ILMWRITE, $GDIP_ILMREAD), $GDIP_PXF32RGB)
    Local $iScan0 = DllStructGetData($tBitmapData, "Scan0")
    Local $rbg_color = _ColorGetRGB(0xFFFC00)
    Local $tolerance = 10
    Local $red_low = ($tolerance > $rbg_color[0] ? 0 : $rbg_color[0] - $tolerance)
    Local $green_low = ($tolerance > $rbg_color[1] ? 0 : $rbg_color[1] - $tolerance)
    Local $blue_low = ($tolerance > $rbg_color[2] ? 0 : $rbg_color[2] - $tolerance)
    Local $red_high = ($tolerance > 255 - $rbg_color[0] ? 255 : $rbg_color[0] + $tolerance)
    Local $green_high = ($tolerance > 255 - $rbg_color[1] ? 255 : $rbg_color[1] + $tolerance)
    Local $blue_high = ($tolerance > 255 - $rbg_color[2] ? 255 : $rbg_color[2] + $tolerance)
    Local $tPixel = DllStructCreate("int[" & $iW * $iH & "];", $iScan0)
    Local $iPixel, $iRowOffset
    Local $found_pixel = False
    Local $abscoord_pixel[2] = [0, 0]

    Local $start_timer = TimerInit()
    For $iY = 0 To $iH - 1
        $iRowOffset = $iY * $iW + 1
        For $iX = 0 To $iW - 1 ;get each pixel in each line and row
            $iPixel = DllStructGetData($tPixel, 1, $iRowOffset + $iX) ;get pixel color
            Local $pixel_color = _ColorGetRGB("0x" & Hex($iPixel, 6))
            If (($pixel_color[0] >= $red_low and $pixel_color[0] <= $red_high) and ($pixel_color[1] >= $green_low and $pixel_color[1] <= $green_high) and ($pixel_color[2] >= $blue_low and $pixel_color[2] <= $blue_high)) Then
                $abscoord_pixel[0] = $iX
                $abscoord_pixel[1] = $iY
                $found_pixel = True
                ExitLoop
            EndIf
        Next
    Next
    Local $end_time = TimerDiff($start_timer) / 1000

    MsgBox("", "", $end_time & @CRLF & "Found pixel = " & $found_pixel)

    _GDIPlus_BitmapUnlockBits($hBitmap, $tBitmapData)

    ;cleanup resources
    _GDIPlus_ImageDispose($hImage)
    _GDIPlus_GraphicsDispose($hContext)
    _GDIPlus_BitmapDispose($hBitmap)
    _GDIPlus_Shutdown()
EndFunc

Will probably try to and rewrite this in C++ and give it a test in visual studio, perhaps it will be faster in a dll than in autoit. Also saw something about the WinApi GetDIBits but the apparently copies the whole bitmap into a buffer, not a pointer to a buffer so someone said it would be slow.

Does anyone know of any other way of checking pixels in memory or any way to make this faster? The Autoit Pixelsearch function takes miliseconds to complete. I did find the source code for another *ahem* scripting languages PixelSearch function and it looks like it uses GetDIBits.

Share this post


Link to post
Share on other sites

Why do you need to do pixel search?

Why not look for the control?

Why also do you need to do a snapshot then look at the picture?

Why not look at the screen directly? 

This seems a real difficult way to solve a problem when there are many simpler and more stable methods to do things. 

Share this post


Link to post
Share on other sites

Because it seems fun and an interesting way to learn more about bitmaps. The only problem with that is I don't know a whole lot about bitmaps and my knowledge of the WinApi is very limited. I was also working on a small image editor using GDI+ and being able to find colors in the bitmap will open up the possibility to search and replace colors in a bitmap. I just don't want it to take 20 seconds to go through and replace colors when programs like Photoshop and Gimp can do it in ms and Pixelsearch takes ms to find a pixel on the screen.

That snapshot allows to search in memory, so even if the window is hidden you can still search in it.

Edited by InunoTaishou

Share this post


Link to post
Share on other sites

So your saying you want to make a photo editor? I'm asking for none of your code shows anything to replace colors. It only shows how you want to search a client area. I'm assuming you have a GUI to run the controls for this editor?

Edited by Bert

Share this post


Link to post
Share on other sites

At this point all I'm trying to do is see if I can quickly, and efficiently, find a color in a bitmap (GDI+ bitmap or a WinAPI handle to a bitmap, since they can be converted easily to each other. I've been using the WinAPI one to capture the client area of a program). My GUI has... bugs in it still so I'm not even using it. Atm I've got 2 scripts on my desktop I've been running trying to test this.

Share this post


Link to post
Share on other sites

Hi,

writing a (32-Bit) bitmap into Memory takes a millisecond, writing a struct "over" the RGBA-information (some people say "Pixels" to that ;) ) takes a millisecond too, copying the Information from struct to a string takes another millisecond, searching/replacing "colors" via stringinstr/stringreplace/stringregex[replace] depends on string length, but never more than some milliseconds. 

If you use a slow idea, use slow functions and write slow scripts/programs, its not surprising that you have to wait a long time....

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By SteveJM
      When I use DllStructCreate() to reserve a chunk of memory I would like to know if I can rely on that memory being initialized to zero. Experience suggests that it is, but I have been searching to try and find a definitive statement anywhere that this is the case. I apologise if I have missed somewhere. Part of the reason for this question is so that my next search (after my personal memory has dimmed) should yield a link to this post, hopefully with an answer.
      A number of DLLs I use have structs where a few parts have to be explicitly set and other parts are reserved with the instruction that they must be set to zero. Because DllStructCreate() appears to zero-initialise the memory, I tend to forget to do it explicitly and everything seems to work. I am wondering whether I have been lucky and am storing up trouble for myself. It seems likely that the OS has been asked for zeroed memory, but without a promise in the documentation for DllStructCreate(),  perhaps that could change? Perhaps the developers wish to reserve the right to change their minds?
    • By Chimp
      After watching this movie (https://www.youtube.com/watch?v=cPiDHXtM0VA) I wanted to try the test to see how much i could compete with that chimpanzee so i created this script.
      well, actually passing that test is a lot harder than it sounds. With the difficulty set to seven numbers and a display time of one second, I can only remember 2 or 3 numbers ... (what a disappointment)
      I can only do better if I reduce the slider to 5 numbers and increase the storage time to 2 seconds (the easyest level), a very poor performance. That chimpanzee is great.
      The script offers you a sequence of 10 random quizzes. At the end it gives you the percentage of your "level". The chimpanzee resolves on average 8 out of 10 (80%), so you can compare your performance to that of the chimpanzee.
      How to play:
      Run the script. At the beginning there are 2 sliders at the bottom of the screen where you can set the difficulty level by varying the memorization time and the amount of numbers to memorize as you like. After setting the difficulty, click the circle on the bottom left to get started. after the first move the sliders are no longer displayed until the next game, (the game lasts 10 attempts, there is a progress bar at the bottom of the screen to see where you are) between one test and the other of the ten, click on the circle to move on to the next test have fun.
      #include <GUIConstants.au3> #include <MsgBoxConstants.au3> #include <Array.au3> #include <WinAPIMisc.au3> ; HotKeySet("{ESC}", "_EndOfGame") Global $iNumbersToGuess = 7, $iExpositionTime = 1000, $iMatches = 10, $iMatchesWon Global $aNumbers[10] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] Global $aButtons[10], $aControls[5] Global $iWinWidth = @DesktopWidth / 2, $iWinHeight = @DesktopHeight / 2, $iButtonXSide = Int($iWinWidth / UBound($aNumbers)), $iButtonYSide = Int($iWinHeight / UBound($aNumbers)), $sWinTitle = "Beat the Chimp" Global $aX[Int($iWinWidth / $iButtonXSide)], $aY[Int($iWinHeight / $iButtonYSide)], $iNdx = 0, $aPoints[3], $score, $GUIGetMsg, $iDockHeight = 50, $iProgrssHeight = 5 For $i = 0 To (Int($iWinWidth / $iButtonXSide) - 1) * $iButtonXSide Step $iButtonXSide $aX[$iNdx] = $i $iNdx += 1 Next $iNdx = 0 For $i = 0 To (Int($iWinHeight / $iButtonYSide) - 1) * $iButtonYSide Step $iButtonYSide $aY[$iNdx] = $i $iNdx += 1 Next Global Const $iDockLeftBorder = 200, $iForeColor = 0xFFFFFF, $iBackColor = 0x000000 Global $hGUI = GUICreate($sWinTitle, $iWinWidth, $iWinHeight + $iDockHeight + $iProgrssHeight, @DesktopWidth / 4, @DesktopHeight / 5) GUISetBkColor($iBackColor, $hGUI) ; the circle to continue playing $aControls[0] = GUICtrlCreateLabel(ChrW(0x25EF), 0, $iWinHeight + 1, 100, $iDockHeight, 0x01) ; GUICtrlSetTip(-1, "Click the circle," & @CRLF & "then click the squares" & @CRLF & "in numeric order.") GUICtrlSetFont(-1, 24, 900) GUICtrlSetColor(-1, $iForeColor) GUICtrlSetBkColor(-1, $iBackColor) ; slider for the amount of numbers to guess $aControls[2] = GUICtrlCreateSlider($iDockLeftBorder, $iWinHeight, $iWinWidth - $iDockLeftBorder, Int($iDockHeight / 2)) GUICtrlSetLimit(-1, 10, 5) ; 5 steps 5 (easy) to 10 (hard) GUICtrlSetData(-1, $iNumbersToGuess) ; label for the amount of quizzes $aControls[1] = GUICtrlCreateLabel("Numbers : " & GUICtrlRead($aControls[2]), 100, $iWinHeight + 1, 100) GUICtrlSetColor(-1, $iForeColor) ; slider for the exposition time $aControls[4] = GUICtrlCreateSlider($iDockLeftBorder, $iWinHeight + (Int($iDockHeight / 2)), $iWinWidth - $iDockLeftBorder, $iDockHeight / 2) GUICtrlSetLimit(-1, 8, 1) ; 8 steps (0f 250ms each) GUICtrlSetData(-1, $iExpositionTime / 250) ; label for the exposition time $aControls[3] = GUICtrlCreateLabel("ms to show : " & GUICtrlRead($aControls[4]) * 250, 100, $iWinHeight + 1 + (Int($iDockHeight / 2)), 100) GUICtrlSetColor(-1, $iForeColor) ; progress bar of the match Global $idProgressbar = GUICtrlCreateProgress(0, $iWinHeight + $iDockHeight, $iWinWidth, $iProgrssHeight) ; Create buttons For $i = 0 To 9 $aButtons[$i] = GUICtrlCreateLabel($i + 1, $iWinWidth + 5, $iWinHeight + $iDockHeight + $iProgrssHeight + 5, $iButtonXSide, $iButtonYSide, 0x01) GUICtrlSetFont($aButtons[$i], 24) GUICtrlSetColor($aButtons[$i], $iForeColor) GUICtrlSetBkColor($aButtons[$i], $iBackColor) Next GUISetState(@SW_SHOW) ; --- Main loop --- Do ; New game $iMatchesWon = 0 GUICtrlSetData($idProgressbar, 0) For $iRound = 1 To $iMatches ; the game lasts $iMatches rounds $iNdx = 0 ; reset pointer (index to the next correct answer) _HideControls(__get_IDs_by_indexes($aButtons, $aNumbers)) ; remove the numbers from the screen ; show the dock and wait (only in the first round are also shown the sliders) _ShowControls($iRound = 1 ? $aControls : $aControls[0]) ; display the dock's control(s) While 1 Switch GUIGetMsg() Case $aControls[0] ; The circle (play a new quiz) ExitLoop Case $aControls[2] ; slider to choose how many numbers to guess $iNumbersToGuess = GUICtrlRead($aControls[2]) GUICtrlSetData($aControls[1], "Numbers : " & $iNumbersToGuess) Case $aControls[4] ; slider to choose how long (milliseconds) to show the numbers $iExpositionTime = GUICtrlRead($aControls[4]) * 250 ; 8 steps of 250 milliseconds each GUICtrlSetData($aControls[3], "ms to show : " & $iExpositionTime) Case $GUI_EVENT_CLOSE _EndOfGame() EndSwitch WEnd _HideControls($aControls) ; hide the dock Sleep(750) ; wait a bit $aQuiz = _GenerateQuiz($iNumbersToGuess) ; generate random elements to guess _SpreadControls(__get_IDs_by_indexes($aButtons, $aQuiz)) ; scatter the numbers on the GUI _ShowControls(__get_IDs_by_indexes($aButtons, $aQuiz)) ; display the numbers Sleep($iExpositionTime) ; leave numbers visible for a short time _MaskControls(__get_IDs_by_indexes($aButtons, $aQuiz)) ; mask the numbers GUICtrlSetData($idProgressbar, Round($iRound / $iMatches * 100)) ; _ShowControls(__get_IDs_by_indexes($aButtons, $aQuiz)) ; <------------- keep numbers visible FOR DEBUG PURPOSE ONLY! While 1 ; wait for a move $GUIGetMsg = GUIGetMsg() If $GUIGetMsg = $GUI_EVENT_CLOSE Then _EndOfGame() ; scan all quiz buttons to check if one was pressed For $i = 0 To UBound($aQuiz) - 1 ; $aButtons) - 1 If $GUIGetMsg = $aButtons[$aQuiz[$i] - 1] Then If $i = $iNdx Then ; -------------------------- ; actions for a right move ; -------------------------- ; hide the guessed number _HideControls($aButtons[$aQuiz[$i] - 1]) ; --------------------------------- ; check if this round is complete ; --------------------------------- If $iNdx = (UBound($aQuiz) - 1) Then _WinAPI_PlaySound("SystemExclamation", Null, BitOR($SND_ALIAS, $SND_ASYNC)) $iMatchesWon += 1 ExitLoop 2 EndIf ; play a short ok sound ; _WinAPI_PlaySound("FaxBeep", Null, BitOR($SND_ALIAS, $SND_ASYNC)) ; "SystemAsterisk" $iNdx += 1 ; set index to next correct answer Else ; -------------------------- ; actions for a wrong move ; -------------------------- ; show all the right sequence _ShowControls(__get_IDs_by_indexes($aButtons, $aQuiz)) _WinAPI_PlaySound("DeviceFail", Null, BitOR($SND_ALIAS, $SND_ASYNC)) ; give a little time to the user to control it Sleep(1500) ; go to next step ExitLoop 2 EndIf EndIf Next WEnd ; loop till end of match $score = Round($iMatchesWon / $iMatches * 100, 2) ; percentage Select Case $score < 80 $sResult = "The chimp beat you!" Case $score > 80 $sResult = "You beat the chimp!" Case $score = 80 $sResult = "You tied the chimp." EndSelect Next ; next round ; game over? Until MsgBox($MB_YESNO + $MB_ICONINFORMATION + $MB_TASKMODAL + $MB_SETFOREGROUND, _ "Game over", _ "You got " & $score & "% correct." & @CRLF & _ "Ayumu averages 80% correct." & @CRLF & $sResult & @CRLF & @CRLF & _ "do you want to try again?") <> 6 Func _SpreadControls($aTemp) ; place the required numbers scattered on the GUI SRandom(@YEAR + @MON + @MDAY + @HOUR + @MIN + @SEC) _ArrayShuffle($aX) _ArrayShuffle($aY) ; first, place all buttons out of GUI For $i = 0 To UBound($aButtons) - 1 GUICtrlSetPos($aButtons[$i], $iWinWidth + 5, $iWinHeight + $iDockHeight + $iProgrssHeight + 5) GUICtrlSetState($aButtons[$i], $GUI_DISABLE) Next ; Then place only the numbers of this quiz in visible area For $i = 0 To UBound($aTemp) - 1 GUICtrlSetPos($aTemp[$i], $aX[$i], $aY[$i]) GUICtrlSetState($aTemp[$i], $GUI_ENABLE) Next EndFunc ;==>_SpreadControls Func _GenerateQuiz($iNumElements) ; generate an array of required random numbers SRandom(@YEAR + @MON + @MDAY + @HOUR + @MIN + @SEC) Local $aTemp[$iNumElements] _ArrayShuffle($aNumbers) For $i = 0 To $iNumElements - 1 $aTemp[$i] = $aNumbers[$i] Next _ArraySort($aTemp) Return $aTemp EndFunc ;==>_GenerateQuiz Func _ShowControls($aTemp) ; render controls visible (and enabled) $aTemp = _EnforceArray($aTemp) For $i = 0 To UBound($aTemp) - 1 GUICtrlSetState($aTemp[$i], $GUI_SHOW) GUICtrlSetColor($aTemp[$i], $iForeColor) GUICtrlSetBkColor($aTemp[$i], $iBackColor) Next EndFunc ;==>_ShowControls Func _MaskControls($aTemp) ; mask the controls $aTemp = _EnforceArray($aTemp) For $i = 0 To UBound($aTemp) - 1 GUICtrlSetColor($aTemp[$i], $iForeColor) GUICtrlSetBkColor($aTemp[$i], $iForeColor) Next EndFunc ;==>_MaskControls Func _HideControls($aTemp) ; hide the controls (implies disable) $aTemp = _EnforceArray($aTemp) For $i = 0 To UBound($aTemp) - 1 GUICtrlSetState($aTemp[$i], $GUI_HIDE) ; $GUI_DISABLE) ; GUICtrlSetColor($aButtons[$aTemp[$i] - 1], $iBackColor) ; GUICtrlSetBkColor($aButtons[$aTemp[$i] - 1], $iBackColor) Next EndFunc ;==>_HideControls Func _EnforceArray($vParam) ; if only one value is passed, turn it into an array of only 1 element If Not IsArray($vParam) Then Local $aTemp[1] = [$vParam] Return $aTemp EndIf Return $vParam EndFunc ;==>_EnforceArray Func __get_IDs_by_indexes(ByRef $aCtrls, ByRef $aNdxs) ; returns the handles of the controls pointed to by the indexes Local $aTemp[UBound($aNdxs)] For $i = 0 To UBound($aNdxs) - 1 $aTemp[$i] = $aCtrls[$aNdxs[$i] - 1] Next Return $aTemp EndFunc ;==>__get_IDs_by_indexes Func _EndOfGame() ; _WinAPI_PlaySound ("SystemExit" , Null, $SND_ALIAS) GUIDelete() Exit EndFunc ;==>_EndOfGame P.S. At this link (https://web.archive.org/web/20131006161544/http://games.lumosity.com/chimp.html) there is a Flash version of this game.
    • By AnRios
      Greetings friends!
      I have been searching the help file and Google, with no success, to find a way to validate images from a folder and mark them somehow in a spreadsheet.
      My context is: I made a code with the help of the community that captures images from SAP and saves them in a folder.  Now I'd like to identify which ones are black, if it's even possible. I read about PixelSearch, but did not get it to work. If someone could point me in the right direction, I'd appreciate it.
      The code I'm using:
      #include <File.au3> #include <ScreenCapture.au3> $x = InputBox("Title", "Amount of Images To Capture", "", "", 320, 150) If @error Then Exit $x = Number($x) $y = InputBox("Title", "Batch Name", "", "", 320, 150) If @error Then Exit $y = String($y) HotKeySet("{HOME}", "printscreen") Func printscreen() $FilePath =("C:\Fiscalizacao\Fotos"&"/") $FileName = $y & " - " $FileList = _FileListToArray($FilePath, $FileName & '*.jpg', 1) If Not IsArray($FileList) Then $FileName&= '1.jpg' Else $FileName &= $FileList[0] + 1 & '.jpg' EndIf _ScreenCapture_Capture($FilePath & "\" & $FileName, 354, 196, 673, 436) EndFunc HotKeySet("{BS}", "Terminate") Func Terminate() Exit 0 EndFunc For $i = 1 to $x Opt("WinTitleMatchMode",2) If NOT WinExists("Relatorio") Then MsgBox(0, "Atenção!", "Relatório do MOM deve estar aberto!") Call("Terminate") EndIf Opt("WinTitleMatchMode",2) WinActivate("Relatorio") Sleep (250) Opt("WinTitleMatchMode",2) SendKeepActive("Relatorio") Send("{ENTER}") Sleep (1000) Send("{HOME}") Sleep (200) Opt("WinTitleMatchMode",2) WinActivate("Relatorio") Send("{DOWN}") Next  
    • By plankton
      While IsArray(PixelSearch(100, 100, 300, 300, 0xffffff))     Send("{ESC}")     Sleep(1000) WEnd  MsgBox(0,"Loop exited","") Hi, above is my function that will execute ESC button when white color is present in specific area which is color 0xffffff.
      But how do I do the opposite like when white color is not present in that specific area? Like this below code which gives me error
       
      While IsArray(PixelSearch(100, 100, 300, 300, <>0xffffff))     Send("{ESC}")     Sleep(1000) WEnd  MsgBox(0,"Loop exited","")  
       
    • By plankton
      Hi I want it to search for a specific color in certain area then excute the loop which presses ESC button and stop the loop when the color no longer present in that specific area.  Here is the example of my code. But it doesnt stop when color is disappeared.
       
      Pixelsearch(511, 455, 678, 501, 0xFFFFFF)
      If Not  @Error Then
      While 1
      Sleep(1000)
      Send("{ESC}")
      Pixelsearch(511, 455, 678, 501, 0xFFFFFF)
      If @Error Then Exitloop
       
×
×
  • Create New...