使用Python解析像素数据的最有效/最快的方法? [英] Most efficient/quickest way to parse pixel data with Python?

查看:211
本文介绍了使用Python解析像素数据的最有效/最快的方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have created a simple Python script that gets activated whenever a specific program is running. That program sends information to the screen, which the script needs to grab and analyze.

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

Part of the script's logic can be expressed as follows:

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 Imaging Library(PIL)的解决方案:

I have already found something that does exactly this, but not quite as fast as I'd like. Here is a solution using Python Imaging Library (PIL) with arbitrary values:

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值并将其与函数获得的先前值进行比较。如果它改变了,那么屏幕上发生了一些事情,这意味着程序做了一些事情,因此脚本可以相应地运行。
然而,脚本需要快速反应,特别是因为这只是一个具有自身复杂性和缺陷的大型函数的一部分,所以我正在优化代码位的过程中从此开始。

I can then take that RGB value and compare it with the previous value obtained by the function. If it changed then something happened in the screen, which means the program did something, and so the script can behave accordingly. However, the script needs to react fast, especially because this is just part of a larger function with its own intricacies and flaws, so I'm in the process of optimizing the code bit by bit, starting by this.

此解决方案将脚本限制为在i7 4770k cpu上每秒约30次迭代。看起来很快,但是将其添加到其他功能中,这些功能本身以类似的速率解析像素信息,并且事情开始累积起来。我的目标是在单个函数上每秒至少200次,每次150次迭代,这样结束脚本可以每秒5-10次迭代运行。

This solution limits the script to ~30 iterations per second on a i7 4770k cpu. Seems fast, but adding it with other functions which themselves parse pixel information at a similar rate and things start to add up . My goal is at least 200, maybe 150 iterations per second on a single function so that the end script can run at 5-10 iterations per second.

所以,长篇故事short:还有什么方法可以更快速地从屏幕上解析像素?

So, long story short: what other method is there to parse pixels from the screen more rapidly?

推荐答案

好好偷看,经过一番挖掘后发现它确实可以用Python和简单的pywin32模块完成我想要的东西(感谢Mark Hammond)。没有必要使用更强大的语言或将工作外包给numpy等等。
这里是5行代码(6行代码):

Alright peeps, after some digging turns out it is indeed possible to do what exactly what I wanted with Python and the simple pywin32 module (thanks based Mark Hammond). There's no need for the "beefier" language or to outsource the job to numpy and whatnot. Here it is, 5 lines of code (6 with the import):

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):

And that's it. It will return a number (COLORREF) of the selected pixel on each iteration, which is a way to represent color (just like RGB or hex) and, most importantly, data I can parse! If you aren't convinced here are some benchmarks on my desktop pc (standard Python build CPython and i7 4770k):

我以前的解决方案包含虚拟秒表(随意自行运行并检查):

My previous solution wrapped around a virtual stopwatch (feel free to run them yourself and check it):

    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次迭代。让我们使用它作为我们进行比较的基本速度。

Obtained 29 iterations per second. Let's use this as the base speed to which we'll make our comparisons.

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

Here's the solution pointed by BenjaminGolder using 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%的改进,但它我正在寻找的数量级改进。

Average 54 iterations per second. That's a fancy 86% improvement but it is not the order of magnitude improvement I was looking for.

所以,最后,这是它来了:

So, finally, here is it comes:

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%
它是如此之快以至于计数+ = 1增量会减慢它的速度。
我在100k迭代上做了一些测试,因为1000对于这段代码来说太低了,平均值保持大致相同,每秒14-16k迭代。它也在7-8秒内完成了这项工作,而之前的那些工作是在我开始写这篇文章时开始的......好吧他们还在继续。

Roughly 16000 iterations a second of a pixel thirsty script. Yes, 16000. That's at least 2 orders of magnitude faster than the previous solutions and a whooping 29600 % improvement. It's so fast that the count+=1 increment slows it down. I did some tests on 100k iterations because 1000 was too low for this piece of code, the average stays roughly the same, 14-16k iterations/second. It also did the job in 7-8 seconds, whereas the previous ones where started when I started writing this and... well they are still going.

好吧,还有而已!希望这可以帮助任何具有类似目标并遇到类似问题的人。请记住,Python找到了一种方法。

Alright, and that's it! Hope this can help anyone with a similar objective and faced similar problems. And remember, Python finds a way.

这篇关于使用Python解析像素数据的最有效/最快的方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆