How can I get the pixel data from an area of the screen (much) faster in AHK?

后端 未结 2 548
长发绾君心
长发绾君心 2021-01-15 03:23

I understand that for some things it would be better to write certain things in C++, but I\'d really like to be able to do this in AHK:

I want to be able to retrieve

相关标签:
2条回答
  • 2021-01-15 03:59

    I found a way to do it 103 times faster than Forivin's solution :D

    SetBatchLines, -1
    CoordMode, Pixel, screen
    
    FileDelete, Log.txt
    
    searchSpace := 400
    jumpSize := 1 ; how many units to skip each interval
    total := Round(((searchSpace * searchSpace) / jumpSize), 0)
    startTimer := getTimestamp()
    getPixelMapSlow(searchSpace, jumpSize)
    endTimer := getTimestamp()
    duration := endTimer - startTimer
    rate := total / duration
    FileAppend, % "[getPixelMapSlow] Retrieved " . total . " pixels from bitmap, duration: " . duration . "ms at at a rate of " . rate . " pixels/ms.`n", Log.txt
    
    searchSpace := 400
    jumpSize := 1 ; how many units to skip each interval
    total := Round(((searchSpace * searchSpace) / jumpSize), 0)
    startTimer := getTimestamp()
    getPixelMapFast(searchSpace, jumpSize)
    endTimer := getTimestamp()
    duration := endTimer - startTimer
    rate := total / duration
    FileAppend, % "[getPixelMapFast] Retrieved " . total . " pixels from bitmap, duration: " . duration . "ms at at a rate of " . rate . " pixels/ms.`n", Log.txt
    
    
    getPixelMapFast(searchSpace, jumpSize){
        width := 1920
        height := 1080
        centerX := width / 2
        centerY := height / 2
        searchSpacehalf := searchSpace / 2
        searchCounterX := 0
        searchCounterY := 0
        pixelMap := {}
        pBitmap := Gdip_BitmapFromScreen((centerX - searchSpacehalf) . "|" . (centerY - searchSpacehalf) . "|" . searchSpace . "|" . searchSpace)
        E1 := Gdip_LockBits(pBitmap, 0, 0, Gdip_GetImageWidth(pBitmap), Gdip_GetImageHeight(pBitmap), Stride, Scan0, BitmapData)
        Loop, %searchSpace%
        {
            tick := A_Index * jumpSize
            if (tick < searchSpace) {
                New_Index_X := tick
                Loop, %searchSpace%
                {
                    tick := A_Index * jumpSize
                    if (tick < searchSpace) {
                        New_Index_Y := tick
                        color1ARGB := Gdip_GetLockBitPixel(Scan0, New_Index_X, New_Index_Y, Stride)
                        SetFormat, Integer, H
                        color1RGB := 0x00ffffff & color1ARGB
                        SetFormat, Integer, D
                        if (!pixelMap[New_Index_X]){
                            pixelMap[New_Index_X] := {}
                        }
                        pixelMap[New_Index_X][New_Index_Y] := color1RGB
                    }
                }
            }
        }
        Gdip_UnlockBits(pBitmap, BitmapData)
        Gdip_DisposeImage(pBitmap)
        return pixelMap
    }
    
    getPixelMapSlow(searchSpace, jumpSize){
        width := 1920
        height := 1080
        centerX := width / 2
        centerY := height / 2
        searchSpacehalf := searchSpace / 2
        searchCounterX := 0
        searchCounterY := 0
        pixelMap := {}
        pBitmap := Gdip_BitmapFromScreen((centerX - searchSpacehalf) . "|" . (centerY - searchSpacehalf) . "|" . searchSpace . "|" . searchSpace)
        Loop, %searchSpace%
        {
            tick := A_Index * jumpSize
            if (tick < searchSpace) {
                New_Index_X := tick
                Loop, %searchSpace%
                {
                    tick := A_Index * jumpSize
                    if (tick < searchSpace) {
                        New_Index_Y := tick
                        color1ARGB := Gdip_GetPixel(pBitmap, New_Index_X, New_Index_Y)
                        if (!pixelMap[New_Index_X]){
                            pixelMap[New_Index_X] := {}
                        }
                        color1RGB := ARGBtoRGB(color1ARGB)
                        pixelMap[New_Index_X][New_Index_Y] := color1RGB
                    }
                }
            }
        }
        Gdip_DisposeImage(pBitmap)
        return pixelMap
    }
    
    ARGBtoRGB( ARGB ) {
        VarSetCapacity( RGB,6,0 )
        DllCall( "msvcrt.dll\sprintf", Str,RGB, Str,"%06X", UInt,ARGB<<8 )
        Return "0x" RGB
    }
    
    getTimestamp()
    {
        DllCall("QueryPerformanceCounter", "Int64*", timestamp)
        DllCall("QueryPerformanceFrequency", "Int64*", frequency)
        return Round(timestamp * 1000 / frequency)
    }
    

    Of course include the relevant functions of the AHK Gdip library (found on Github) in your code for this to work.

    Log:

    [getPixelMapSlow] Retrieved 160000 pixels from bitmap, duration: 33161ms at at a rate of 4.824945 pixels/ms.
    [getPixelMapFast] Retrieved 160000 pixels from bitmap, duration: 321ms at at a rate of 498.442368 pixels/ms.
    
    0 讨论(0)
  • 2021-01-15 04:05

    To reduce delays between commands to a minimum you should also use SetBatchLines, -1. This alone can give you a significant performance boost.
    I think you have already figured out the rest.
    But in case anyone else stumbles across this question. Here is how you can do it with GDI+:

    SetBatchLines, -1
    
    #Include Gdip.ahk
    
    pToken := Gdip_Startup()
    
    ; Screen area ("X|Y|Width|Height")
    pBitmap := Gdip_BitmapFromScreen("500|600|300|100")
    
    ; Read RGB color from pixel x290 y65
    ARGB := Gdip_GetPixel( pBitmap, 290, 65 )
    pixelColor := ARGBtoRGB( ARGB )
    MsgBox, % pixelColor
    
    ; Read RGB color from pixel x167 y90
    ARGB := Gdip_GetPixel( pBitmap, 167, 90 )
    pixelColor := ARGBtoRGB( ARGB )
    MsgBox, % pixelColor
    
    
    Gdip_DisposeImage(pBitmap)
    Gdip_Shutdown(pToken)
    
    ARGBtoRGB( ARGB ) {
        VarSetCapacity( RGB,6,0 )
        DllCall( "msvcrt.dll\sprintf", Str,RGB, Str,"%06X", UInt,ARGB<<8 )
        Return "0x" RGB
    }
    

    The code is mostly what I already posted in another answer right here.

    0 讨论(0)
提交回复
热议问题