autohotkey - 在 AHK 中如何更快地从屏幕区域获取像素数据?

标签 autohotkey

我知道对于某些事情,用 C++ 编写某些事情会更好,但我真的很希望能够在 AHK 中做到这一点:

我希望能够从屏幕的 100x300 区域检索像素数据,但是 PixelGetColor 太慢了。下面的测试表明,每个像素大约需要 0.02 秒,即从整个 1920 x 1080 屏幕获取像素数据大约需要 11.5 小时。

在测试中,从屏幕的 15 x 15 区域获取像素数据大约需要4-5 秒

width := 15 ; 1920
height := 15 ; 1080
searchResolution := 1 ; 3
columns := width / searchResolution
rows := height / searchResolution
resultRows := {}
columnCounter := 0
rowCounter := 0
resultCounter := 0

start := getTimestamp()
loop, %columns%
{
    resultRows[columnCounter] := {}
    loop, %rows%
    {
        PixelGetColor, pixelColor, columnCounter, rowCounter
        resultRows[columnCounter][rowCounter] := pixelColor
        rowCounter += searchResolution
        resultCounter += 1
    }
    columnCounter += searchResolution
    rowCounter := 0
}
end := getTimestamp()

MsgBox % "Finished! It took " . (end - start) / 1000 . 
" seconds to record pixel data from a " . 
width . " x " . height . " area of the screen (" . resultCounter . " pixels)."

getTimestamp()
{
    DllCall("QueryPerformanceCounter", "Int64*", timestamp)
    DllCall("QueryPerformanceFrequency", "Int64*", frequency)
    return Round(timestamp * 1000 / frequency)
}

如果您想要包含调试日志记录和将数据导出到 XML 文件以供检查的版本,则为 here

有没有更快的方法从屏幕的一部分获取像素数据?

PixelSearch 非常快地搜索屏幕上很大的区域,我不确定为什么 PixelGetColor 相比之下会如此缓慢。一定有一些 .dll 或其他一些函数可以用来比这更快地从屏幕的一小块区域获取像素数据。

最佳答案

我找到了一种比 Forivin 的解决方案快 103 倍的方法: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)
}

当然,在您的代码中包含 AHK Gdip 库(在 Github 上找到)的相关函数才能使其工作。

日志:

[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.

关于autohotkey - 在 AHK 中如何更快地从屏幕区域获取像素数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44621796/

相关文章:

autohotkey - WinHttpRequest 超时

autohotkey - 通过 Autohotkey 控制事件处理?

python - 如何在 Python (2.7) 中运行自动热键脚本

autohotkey - 如果程序尚未启动,如何启动程序,如果已经启动,如何将焦点放在?

AutoHotKey:按一个键移动到下一个程序

keyboard - 使用 autohotkey 在 Microsoft 设计器键盘中将表情符号键更改为 ctrl

autohotkey - 每次目标窗口在 AutoHotkey 中激活时如何激活功能

window - 确定窗口在哪个屏幕上(通过检查最大表面积所在的位置)

windows - 如何使用自动热键将窗口停靠在左侧?

autohotkey - 使用 AHK 将绝对路径与相对路径结合起来