Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/image-processing/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用Python解析像素数据的最有效/最快速的方法?_Python_Image Processing_Python Imaging Library_Pixels - Fatal编程技术网

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

使用Python解析像素数据的最有效/最快速的方法?,python,image-processing,python-imaging-library,pixels,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 somethi

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

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


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

实际上,您不应该像评论中所说的那样,在Python循环中逐像素检查。 您可以尝试Pypy—使用适当的数据结构和Pypy,使用纯Python代码和逐像素数据可以提高10倍


但是,通常的做法是让Python在本机代码中调用库来执行像素操作。PIL和Numpy就是这样的库——例如,在Python中,您应该做的不是检查每个像素的值,而是让图像矩形区域彼此相减,这样您就可以得到一个包含不同像素的矩阵,然后使用Numpy根据需要处理这些差异。这会很快,而且您仍然可以使用Python来完成所有需要的高级功能。

好吧,经过一些挖掘,事实证明,使用Python和简单的pywin32模块(感谢Mark Hammond)确实可以实现我想要的功能。没有必要使用“更强硬”的语言,也没有必要将工作外包给numpy等等。 这是5行代码(6行带导入):

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

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

导入图像抓取,时间
盒子=(0,0100100)#100 x 100方形盒子
像素=(60,20)#像素坐标(必须在框的边界内)
t1=时间。时间()
计数=0
当计数小于1000时:
s=图像抓取。抓取(框)#抓取图像区域
h=s.getpixel(pixel)#获取像素RGB值
计数+=1
t2=时间。时间()
tf=t2-t1
it_per_sec=int(计数/tf)
打印(str(每秒打印次数)+“每秒迭代次数”)
每秒获得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)
从ctypes导入Windell
导入时间
dc=windell.user32.GetDC(0)
计数=0
t1=时间。时间()
当计数小于1000时:
a=windell.gdi32.GetPixel(dc,x,y)
计数+=1
t2=时间。时间()
tf=t2-t1
打印整数(计数/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")
name=“Python 2.7.6 Shell”#只是我当时打开的一个窗口的示例
w=win32ui.FindWindow(无,名称)
t1=时间。时间()
计数=0
当计数小于1000时:
dc=w.GetWindowDC()
dc.GetPixel(60,20)
dc.DeleteDC()
计数+=1
t2=时间。时间()
tf=t2-t1
it_per_sec=int(计数/tf)
打印(str(每秒打印次数)+“每秒迭代次数”)
一个需要像素的脚本大约每秒16000次迭代。是的,16000。这比以前的解决方案至少快了两个数量级,而且大大提高了29600%。 它的速度如此之快,以至于计数+=1的增量会减慢速度。 我对100k次迭代做了一些测试,因为1000次对于这段代码来说太低了,平均值保持大致相同,14-16k次/秒。它也在7-8秒内完成了任务,而之前的那些是在我开始写这篇文章时开始的,并且。。。他们还在继续


好了,就这样!希望这能帮助任何有类似目标和面临类似问题的人。请记住,Python会找到方法。

Python不是这项工作的工具。实时图形处理需要一个BeEver语言,如C++。即使你不受处理代码性能的限制,在大多数窗口系统中,抓取屏幕的一部分也是一个缓慢的操作。@Daniel Shaw:看看这个问题:@nightcracker好吧,那只是。。。令人沮丧的。“肯定有办法至少快一点。”DanielShaw不是来自Python。您最终将调用特定于C API操作系统的代码来加速抓取屏幕的一部分,虽然这可以通过Python使用
ctypes
,但基本上是伪装成C。在Python中,这方面的优秀库有点不足,但我认为一个主要原因是,无论如何,您都无法用Python快速处理生成的屏幕抓图。@BenjaminGolder我用该解决方案获得48-52次迭代/秒。所以速度提高了60%,这是一个开始,但我一直在寻找
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)
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")