矩形截图彩色求平均值(Screenshot colour averaging of rectangl

2019-07-29 11:20发布

我写了一个快速的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的块,步骤= 1)

问题是执行的速度 - 因为这是循环用于在块中的每个像素(2560×1600分辨率/ 5 = 320 * 512块中的每个块= 163840个像素),并在周边的每个块(16 * 163840 = 2621440环)。 总体来说,这款拍拍2.814s完成。

如果我增加了步长值,它的速度,但没有足够的:(这是使用周围的边框更逼真的15×10块)

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.070s - 这意味着我限制在12.8 FPS。

>>> timeit.Timer("autopy.bitmap.capture_screen()", "import autopy").timeit(100)/100
0.06874468830306966

问题:

  • 是否有采取截图和平均屏幕区域更快的方法?

    我不是太担心的准确性,但希望能够以约每秒30帧返回这些值,最好快(20-30毫秒),以允许串行传输开销。 记住我的屏幕分辨率为2560 * 1600!

    我听说过Python图像库(PIL) ,但还没有来得及看进入的速度ImageGrab功能还没有,但它看起来很有希望。

  • 我可以直接从GPU读取的像素值?

  • 另一种思考 - 什么是检测电影的顶部/底部边缘的最佳方式? (如果纵横比宽屏,有在屏幕截图的顶部/底部的黑条,而一些矩形是黑色)。


使用PIL的抓斗():

>>> 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 -最近然后调整:(马克赎金)

>>> 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为十六进制的转换


任何人都可以想出一个更快的方法 - 即以部分屏幕截图? 我应该用C编写的东西吗?

Answer 1:

使用Python图像库。 从文档 (在图像模块):

getcolors

im.getcolors()=>的(计数,颜色)的元组或无列表

im.getcolors(maxcolors)=>的列表(计数,颜色)的元组或无

(新中1.1.5)返回(计数,颜色)的元组,其中,所述计数是在图像中出现的相应颜色的次数未排序列表。

图像模块还包含一个作物()方法,你可以用它来获得每个矩形插到getcolors()。 您可以轻松地从一个加权平均值。

它应该比Python的手动运行循环快得多。 我不知道这是否是足够快的实时使用,但你会得到一个显着的速度提升。 您也可以采取截图每秒几次,因为赔率是,以60个FPS的指示灯发出信号对10个FPS不会特别明显。 它不看为“仅限于12.8 FPS”,把它看成“只能更新的LED每5帧一次”,这不应该是一个明显的区别。

编辑:如果你在这里进一步优化非常感兴趣,我想你会发现采取窗口与Python截图最快的方式非常有用。



Answer 2:

速赢可以使用resize操作(PIL)(你可以用速度简单的插值),以一个5x5的图像,而不是平均的区域,例如:

myimg = ImageGrab.grab()
resized = myimg.resize((5, 5), Image.NEAREST) 

这将产生大致相同的效果做平均工作自己。

真的不知道关于PIL的ImageGrab的速度(以及它如何比较autopy ),虽然,但它很容易,试图找出答案。



Answer 3:

要加快调整大小操作就可以分两步做。 使用NEAREST的第一个削减的像素数目最快可能的方式,然后ANTIALIAS合并到那些具有代表性的样本。 这相当于你与早期试验步长,与PIL功能来完成。

PIL.ImageGrab.grab().resize((150, 100), PIL.Image.NEAREST).resize((15, 10), PIL.Image.ANTIALIAS)


文章来源: Screenshot colour averaging of rectangles