如何使用Python更快地处理图像?

7

我想编写一个脚本,它可以在屏幕上检测RGB值,然后单击x、y值。我知道如何执行点击操作,但我需要比下面的代码更快地处理图像。Python可以实现吗?

目前,我是一次读取一行,在x = 1920时进入第二行,但处理一行需要大约10秒钟。到那时,屏幕上的人可能已经移动到完全不同的位置,而我只完成了一行!

我能否加速这段代码,或者是否有更好的方法来实现我的目标呢?如果在Python中不可行,我也可以考虑C++选项 :)

import Image

x = 0
y = 0

im = Image.open("C:\Users\sean\Desktop\screen.jpg")
pix = im.load()
print im.size #get width and height of the image for iterating over
while x < 1920:
    print pix[x,y] #get RGBA value of the pixel of an image
    print "x is:" +str(x)
    x = x + 1
    print "y is: " +str(y)
    if x == 1920:
        x = 0
        y = y + 1

1
你可以尝试使用OpenCV Python包装器? - Zero
链接:OpenCV - MattDMo
“点击 x,y” 是什么意思? - martineau
6个回答

6

通常情况下,您应该避免在Python中使用逐像素循环。它们总是很慢的。要获得相对较快的图像处理速度,您需要习惯使用矩阵而不是单个像素。您基本上有两个选择,可以使用NumPy或OpenCV,或者两者的组合。NumPy是一个通用的数学矩阵/数组库,但您可以使用它进行许多与图像相关的操作。如果您需要更具体的功能,OpenCV支持许多常见的图像操作。


2

感谢您的回复,以下是我使用的代码,我没有更改原始代码。原来它足够快,但打印是一项非常昂贵的操作 :) 它在不到一秒钟内找到了RGB值的x和y坐标

#check for certain RGB in image

##need to screen grab

import Image, sys

x = 0
y = 0

im = Image.open('C:\\Users\\sean\\Desktop\\test.jpg')
pix = im.load()
print im.size #get width and height of the image for iterating over
while x < 1914:
    value = pix[x,y] #get RGBA value of the pixel of an image
    if value == (33, 179, 80):
        #call left_click(x,y)
        print x,y
    x = x + 1
    if x == 1914:
        x = 0
        y = y + 1
print "Finished"
sys.exit()

在默认的IDLE环境中,打印是一项非常昂贵的操作,但在其他工具(如PyCharm)中速度要快得多,而且在没有IDE的情况下速度最快。 - Walter

1

Image.getpixel 被认为是非常慢的。相反,考虑使用Image.getdata。它会给你一个包含所有像素数据的序列,你可以迭代遍历。

类似这样:

import Image
import math

x = 0
y = 0

im = Image.open("IMG_2977.JPG")
(width, height) = im.size
print width
print height

pix = im.getdata()

i = 0

for pixel in pix:
    print pixel
    x = i % ( width )
    y = math.trunc( i / width)
    print "x is: {}".format(x)
    print "y is: {}".format(y)
    i += 1

在我的MacBook Pro上,不打印(只将像素存储在变量中)且用户时间为2秒(处理器时间为0.02秒)的情况下运行。


1

您可能想在此处执行以下两个操作之一。

1. 从图像中获取单个像素

在这种情况下,您不需要遍历整个文件。只需使用im.getpixel。@Daniel提出了一个有效的观点,即在循环中这样做会很慢,但如果您只想要一个单独的像素,则非常高效。

from PIL import Image
im = Image.open('screenshot.png')

im.getpixel((x, y))    # Returns the colour at (x, y)

2. 处理图像中的多个像素

最好使用NumPy来完成,就像@Lukáš建议的那样。例如,如果您想获取像素周围10 x 10网格的平均颜色。

您可以使用scipy.misc.fromimage将数据作为NumPy数组获取。

from PIL import Image
from scipy.misc import fromimage

im = Image.open('screenshot.png')
data = fromimage(img)

让我们比较一下获取这个数据所需的时间和使用for循环的时间。

In [32]: pix = im.load()

In [33]: %timeit fromimage(im)
10 loops, best of 3: 8.24 ms per loops

In [34]: %timeit [pix[x, y] for x in xrange(im.size[0]) for y in xrange(im.size[1])]
1 loops, best of 3: 637 ms per loop

总结一下:

  • scipy.misc.fromimage 是最快的,对于一个1920x1080像素的图像大约需要8毫秒
  • 循环遍历 pix[x, y] 需要大约640毫秒,慢了80倍

0

有一种叫做 pyautogui 的工具,它通常可以在1-5秒内找到屏幕上的整张图片,速度不算太快但似乎比你目前的选项要好。


0

你可以在两个线程中获取图像的前半部分和后半部分,并处理这些部分,但对我来说只能加速15%。对我来说,高度为375,宽度为483的图像的正常速度是2.7秒。线程将其加速到2.3秒。这就是为什么我正在寻找这个问题的答案。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接