Autohotkey 如何在AHK中更快地从屏幕区域获取像素数据? 我知道,对于某些事情,最好在C++中写一些东西,但是我真的希望能在AKK中做到这一点:

Autohotkey 如何在AHK中更快地从屏幕区域获取像素数据? 我知道,对于某些事情,最好在C++中写一些东西,但是我真的希望能在AKK中做到这一点:,autohotkey,Autohotkey,我希望能够从屏幕的100x300区域检索像素数据,但是PixelGetColor太慢了。这里有一个测试表明,从整个1920 x 1080屏幕获取像素数据大约需要每像素0.02秒,也就是大约11.5小时 在测试中,仅从屏幕的15 x 15区域获取像素数据大约需要4-5秒 width := 15 ; 1920 height := 15 ; 1080 searchResolution := 1 ; 3 columns := width / searchResolution rows := height

我希望能够从屏幕的100x300区域检索像素数据,但是
PixelGetColor
太慢了。这里有一个测试表明,从整个1920 x 1080屏幕获取像素数据大约需要每像素0.02秒,也就是大约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文件以供检查的版本,请参阅

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


PixelSearch
非常快速地搜索屏幕的很大区域,我不确定为什么相比之下
PixelGetColor
会如此缓慢。必须有一些
.dll
或其他一些函数,我可以使用它们从屏幕的一个小区域获取像素数据,速度要快得多

要将命令之间的延迟降至最低,还应使用
SetBatchLines,-1
。仅此一项就可以显著提高性能。
我想你已经解决了剩下的问题。
但万一有人碰到这个问题。以下是使用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
}
SetBatchLines,-1
#包括Gdip.ahk
pToken:=Gdip_启动()
; 屏幕区域(“X | Y |宽度|高度”)
pBitmap:=Gdip|U位图fromScreen(“500 | 600 | 300 | 100”)
; 从像素x290 y65读取RGB颜色
ARGB:=Gdip_GetPixel(pBitmap,290,65)
pixelColor:=ARGBtoRGB(ARGB)
MsgBox,%pixelColor
; 从像素x167 y90读取RGB颜色
ARGB:=Gdip_GetPixel(pBitmap,167,90)
pixelColor:=ARGBtoRGB(ARGB)
MsgBox,%pixelColor
Gdip_处置图像(pBitmap)
Gdip_关闭(pToken)
ARGB组织(ARGB){
可变容量(RGB,6,0)

DllCall(“msvcrt.dll\sprintf”、Str、RGB、Str、“%06X”、UInt、ARGB我找到了一种比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)
}

也许拍摄一张屏幕截图,然后在图像上迭代以构建2x2像素颜色阵列。不确定AHK是否能够实现类似的效果。我只是一直使用PixelGetColor。有人能验证我是否打算将其用作解决方案,但示例代码没有保存屏幕截图。了解到我需要使用ansi 32位ve对ahk进行rsion以使其正常工作。仍在为此制定总体解决方案。@chickenfeets如果使用正确的DLL,它可以:)请参阅我的答案。我找到了一种方法,可以将速度提高103倍xD(运行我的代码以进行基准测试)另一个要考虑的事情可能不是计算RGB值,而是保持ARGB值,只与这些值一起工作。A组件将总是<代码> 0x00 < /代码>无论如何。@福里文谢谢,是的,当你执行160000次循环迭代的计算时,每次被遗漏的一个字符串转换会产生很大的差异。@ Forivin实际上,你的建议使它比100快了160倍,哇。不用定义变量tick,你可以直接使用New_Index_X。在许多情况下,=比:=快。不过,我不确定它是否真的对你有帮助。
[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.