我编写了一个快速的 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))
然后我使用matplotlib
: (这被配置为 5x5 块,step = 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
那是因为屏幕截图本身大约需要 0.070 秒 - 这意味着我被限制为 12.8 FPS。
>>> timeit.Timer("autopy.bitmap.capture_screen()", "import autopy").timeit(100)/100
0.06874468830306966
问题:
有没有更快的截屏和平均屏幕区域的方法?
我不太担心准确性,但希望能够以大约 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
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
注意:这是对上面获得的结果的改进,但我们仍然限制在 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
结果:
Step Time(s)
1 0.333048412226
2 0.16206895716
5 0.117172371393
10 0.102383282629
15 0.101844097599
20 0.101229094581
50 0.100824552193
比autopy
在顶部手动循环要快得多,但我们仍然限制在 ~9 FPS(“步长”为 10)。
注意:这不包括所需的 RGB 到 HEX 转换
谁能想出一个更快的方法 - 即截取部分截图?我应该用C写一些东西吗?