Ale*_*x L 9 c python optimization screenshot python-imaging-library
我写了一个快速的python脚本来返回屏幕周边的矩形的平均颜色.(这里的最终目标是在我的显示器周围放置RGB LED条,以便在电影期间获得发光效果 - 像这样(youtube),但更有趣,因为我自己制作它).
我目前正在使用autopy将屏幕作为位图("屏幕截图"),获取每个像素值以及RGB < - > HEX转换.
简化版:
step = 1
width = 5
height = 5
b = autopy.bitmap.capture_screen()
for block in border_block(width, height): # for each rectangle around the perimeter of my screen
R,G,B = 0,0,0
count = 0
for x in xrange(block.x_min, block.x_max, step):
for y in xrange(block.y_min, block.y_max, step):
r,g,b = autopy.color.hex_to_rgb(image.get_color(x, y))
R += r; G += g; B += b
count += 1
block.colour = "#{:06x}".format(autopy.color.rgb_to_hex(R/count,G/count,B/count))
Run Code Online (Sandbox Code Playgroud)
然后我使用matplotlib以下方法显示块:(配置为5x5块,步长= 1)

问题是实现的速度 - 因为这是一个块中每个像素的循环(2560*1600分辨率/ 5 = 320*512块=每块163,840像素),并且周边的每个块(16*163,840 = 2,621,440个循环) ).总的来说,这需要花费2.814秒来完成.
如果我增加步长值,它会加速,但还不够:(这是在边界周围使用更逼真的15x10块)
Step Time (s)
1 1.35099983215
2 0.431000232697
5 0.137000083923
10 0.0980000495911
15 0.095999956131
20 0.0839998722076
50 0.0759999752045
Run Code Online (Sandbox Code Playgroud)
这是因为截图本身需要大约0.070秒 - 这意味着我的速度限制在12.8 FPS.
>>> timeit.Timer("autopy.bitmap.capture_screen()", "import autopy").timeit(100)/100
0.06874468830306966
Run Code Online (Sandbox Code Playgroud)
问题:
是否有更快的方法来获取屏幕截图并平均屏幕区域?
我不太担心准确性,但希望能够以大约30 FPS的速度返回这些值,理想情况下更快(20-30 ms)以允许串行传输开销.请记住我的屏幕分辨率是2560*1600!
我听说过Python Imaging Library(PIL),但还没有时间研究这个ImageGrab函数的速度,但看起来很有希望.
我可以直接从GPU读取像素值吗?
另一个想法 - 什么是检测电影上/下边缘的最佳方法?(如果宽高比是宽屏,屏幕截图的顶部/底部有黑条,有些矩形是黑色).
使用PIL的grab():
>>> timeit.Timer("ImageGrab.grab()", "from PIL import ImageGrab").timeit(100)/100
0.1099840205312789
Run Code Online (Sandbox Code Playgroud)
PIL - 调整大小:(ChristopheD)
>>> timeit.Timer("PIL.ImageGrab.grab().resize((15, 10), PIL.Image.NEAREST)", "import PIL").timeit(100)/100
0.1028043677442085
>>> timeit.Timer("PIL.ImageGrab.grab().resize((15, 10), PIL.Image.ANTIALIAS)", "import PIL").timeit(100)/100
0.3267692217886088
Run Code Online (Sandbox Code Playgroud)
注意:这是对上面获得的结果的改进,但我们仍然限于9 FPS,或具有完全抗锯齿的3 FPS.
PIL - 最近调整大小:(Mark Ransom)
>>> for step in [1,2,5,10,15,20,50]:
print step, timeit.Timer("PIL.ImageGrab.grab().resize(("+str(2560/step)+", "+str(1600/step)+"), PIL.Image.NEAREST).resize((15, 10), PIL.Image.ANTIALIAS)", "import PIL.ImageGrab").timeit(100)/100
Run Code Online (Sandbox Code Playgroud)
结果:
Step Time(s)
1 0.333048412226
2 0.16206895716
5 0.117172371393
10 0.102383282629
15 0.101844097599
20 0.101229094581
50 0.100824552193
Run Code Online (Sandbox Code Playgroud)
比autopy在顶部手动循环要快得多,但我们仍然限制在~9 FPS(在'步骤'为10).
注意:这不包括所需的RGB到HEX转换
任何人都可以想出一个更快的方法 - 即采取部分截图?我应该用C写一些东西吗?
快速获胜的方法可能是对resize5x5 图像使用操作(在 PIL 中)(您可以使用简单的插值来提高速度),而不是对区域进行平均,例如:
myimg = ImageGrab.grab()
resized = myimg.resize((5, 5), Image.NEAREST)
Run Code Online (Sandbox Code Playgroud)
这应该产生与您自己进行平均工作大致相同的效果。
虽然不太确定 PIL 的 ImageGrab 的速度(以及它与 的比较autopy),但是很容易尝试并找出答案。