python - 使用 Python 解析像素数据的最有效/最快速的方法?

标签 python image-processing python-imaging-library pixels

我创建了一个简单的 Python 脚本,只要特定程序运行,它就会被激活。该程序将信息发送到屏幕,脚本需要抓取和分析这些信息。

脚本的部分逻辑可以表示如下:

while a certain condition is met:
    function to continuously check pixel information on a fixed area of the screen()
    if pixel data (e.g. RGB) changes:
        do something
    else:
        continues to check

我已经找到了可以做到这一点的东西,但速度没有我想要的那么快。 这是使用具有任意值的 Python 图像库 (PIL) 的解决方案:

import ImageGrab

box = (0,0,100,100) # 100x100 screen area to capture (0x0 is top left corner)
pixel = (60,20) #target pixel coordenates (must be within the box's boundaries)
im = ImageGrab.grab(box) #grabs the image area (aka printscreen) -> source of bottleneck
hm = im.getpixel(pixel) # gets pixel information from the captured image in the form of an RGB value

然后我可以获取该 RGB 值并将其与该函数获得的先前值进行比较。如果它改变了,那么屏幕上就会发生一些事情,这意味着程序做了一些事情,因此脚本可以相应地运行。 然而,脚本需要快速 react ,特别是因为这只是一个更大的函数的一部分,有其自身的复杂性和缺陷,所以我正在一点一点地优化代码,从这个。

此解决方案将脚本限制为在 i7 4770k CPU 上每秒约 30 次迭代。看起来很快,但是将它与其他本身以类似速率解析像素信息的函数相结合,事情就开始加起来了。我的目标是在单个函数上每秒至少 200 次,也许 150 次迭代,以便最终脚本可以以每秒 5-10 次迭代的速度运行。

那么,长话短说:还有什么其他方法可以更快地从屏幕上解析像素?

最佳答案

好吧,经过一些挖掘后发现确实可以使用 Python 和简单的 pywin32 模块(感谢 Mark Hammond)做我想做的事情。不需要“更强大”的语言或将工作外包给 numpy 等等。 这是 5 行代码(6 行带有导入):

import win32ui
window_name = "Target Window Name" # use EnumerateWindow for a complete list
wd = win32ui.FindWindow(None, window_name)
dc = wd.GetWindowDC() # Get window handle
j = dc.GetPixel (60,20)  # as practical and intuitive as using PIL!
print j
dc.DeleteDC() # necessary to handle garbage collection, otherwise code starts to slow down over many iterations

就是这样。它将在每次迭代中返回所选像素的数字 (COLORREF),这是一种表示颜色的方式(就像 RGB 或十六进制),最重要的是,我可以解析数据! 如果您不相信这里是我台式机上的一些基准测试(标准 Python 构建 CPython 和 i7 4770k):

我之前的解决方案围绕着一个虚拟秒表(您可以自己运行并检查):

    import ImageGrab, time
    box = (0,0,100,100) #100 x 100 square box to capture
    pixel = (60,20) #pixel coordinates (must be within the box's boundaries)
    t1 = time.time()
    count = 0
    while count < 1000:
        s = ImageGrab.grab(box) #grabs the image area
        h = s.getpixel(pixel) #gets pixel RGB value
        count += 1
    t2 = time.time()
    tf = t2-t1
    it_per_sec = int(count/tf)
    print (str(it_per_sec) + " iterations per second")

每秒获得 29 次迭代。让我们将其用作进行比较的基本速度。

这是 BenjaminGolder 使用 ctypes 指出的解决方案:

from ctypes import windll
import time
dc= windll.user32.GetDC(0)
count = 0
t1 = time.time()
while count < 1000:
    a= windll.gdi32.GetPixel(dc,x,y)
    count += 1
t2 = time.time()
tf = t2-t1
print int(count/tf)

平均每秒 54 次迭代。这是 86% 的惊人改进,但它不是我一直在寻找的数量级改进。

所以,最后,它来了:

name = "Python 2.7.6 Shell" #just an example of a window I had open at the time
w = win32ui.FindWindow( None, name )
t1 = time.time()
count = 0
while count < 1000:
    dc = w.GetWindowDC()
    dc.GetPixel (60,20)
    dc.DeleteDC()
    count +=1
t2 = time.time()
tf = t2-t1
it_per_sec = int(count/tf)
print (str(it_per_sec) + " iterations per second")

像素渴脚本每秒大约迭代 16000 次。是的,16000。这比以前的解决方案至少快了 2 个数量级,而且是惊人的 29600 % 改进。 它是如此之快以致于 count+=1 增量减慢了它的速度。 我对 100k 次迭代进行了一些测试,因为 1000 次对于这段代码来说太低了,平均值大致保持不变,14-16k 次迭代/秒。它还在 7-8 秒内完成了这项工作,而之前的那些是在我开始写这篇文章时就开始的,而且……好吧,它们还在继续。

好的,就是这样!希望这可以帮助任何有类似目标并面临类似问题的人。请记住,Python 找到了一种方法。

关于python - 使用 Python 解析像素数据的最有效/最快速的方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23147244/

相关文章:

python - 字典到具有最小值的元组列表

ruby - 从图像中提取或分析视觉信息

Python:如何从内存中的zip文件读取图像?

python - 如何将 PIL `Image` 转换为 Django `File` ?

python - 无论如何,多线程pdf挖掘?

python - 使用 Python 在字符串列表中查找项目的索引

python - vmcloak 安装后失败,语法无效

c++ - 错误 : identifier <uint8_t> undefined and is it possible to use at openCV

ios - 使用 iphone/ipad 扫描或阅读答卷上包含光学标记的图像

python - 文件未找到错误: [Errno 2] No such file or directory: 'frame0.png' but actually has