截面颜色平均矩形

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)

5x5截图

问题是实现的速度 - 因为这是一个块中每个像素的循环(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写一些东西吗?

Chr*_*heD 1

快速获胜的方法可能是对resize5x5 图像使用操作(在 PIL 中)(您可以使用简单的插值来提高速度),而不是对区域进行平均,例如:

myimg = ImageGrab.grab()
resized = myimg.resize((5, 5), Image.NEAREST) 
Run Code Online (Sandbox Code Playgroud)

这应该产生与您自己进行平均工作大致相同的效果。

虽然不太确定 PIL 的 ImageGrab 的速度(以及它与 的比较autopy),但是很容易尝试并找出答案。