Python 矩形的屏幕截图颜色平均
我编写了一个快速python脚本来返回屏幕周边矩形的平均颜色。(这里的最终目标是让我的显示器周围有一个发光的效果,就像电影一样,但更有趣,因为我自己做的) 我目前使用的是获取屏幕位图(“屏幕截图”),获取每个像素值,以及RGB十六进制转换 简化版:Python 矩形的屏幕截图颜色平均,python,c,optimization,screenshot,python-imaging-library,Python,C,Optimization,Screenshot,Python Imaging Library,我编写了一个快速python脚本来返回屏幕周边矩形的平均颜色。(这里的最终目标是让我的显示器周围有一个发光的效果,就像电影一样,但更有趣,因为我自己做的) 我目前使用的是获取屏幕位图(“屏幕截图”),获取每个像素值,以及RGB十六进制转换 简化版: step = 1 width = 5 height = 5 b = autopy.bitmap.capture_screen() for block in border_block(width, height): # for each recta
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.814秒才能完成
如果我增加步长值,它会加快速度,但这还不够:(这是在边界周围使用更真实的15x10块)
这是因为屏幕截图本身大约需要0.070秒——这意味着我被限制在每秒12.8帧
>>> timeit.Timer("autopy.bitmap.capture_screen()", "import autopy").timeit(100)/100
0.06874468830306966
问题:
- 有没有更快的截图和平均屏幕区域的方法
我不太担心准确性,但希望能够以大约30 FPS的速度返回这些值,最好更快(20-30 ms),以考虑串行传输开销。请记住,我的屏幕分辨率是2560*1600
我听说过,但还没有时间研究
函数的速度,但它看起来很有前途ImageGrab
- 我可以直接从GPU读取像素值吗
- 另一个想法-检测电影上/下边缘的最佳方法是什么?(如果纵横比是宽屏的,屏幕截图的顶部/底部有黑色条,一些矩形是黑色的)
使用PIL的抓斗():
>>> timeit.Timer("ImageGrab.grab()", "from PIL import ImageGrab").timeit(100)/100
0.1099840205312789
PIL-调整大小:(克里斯托弗) 注意:这是对上述结果的改进,但我们仍然限制为9 FPS,或3 FPS,具有完全抗锯齿
PIL-最近然后调整大小:(标记赎金) 结果:
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写点什么吗?快速的成功方法是对5x5图像使用
调整大小
操作(在PIL中)(可以使用简单的插值来提高速度),而不是平均区域,例如:
myimg = ImageGrab.grab()
resized = myimg.resize((5, 5), Image.NEAREST)
这将产生与自己进行平均工作大致相同的效果
虽然不能确定PIL的ImageGrab的速度(以及它与autopy相比的速度),但很容易尝试找到它。使用Python图像库。从(图像模块中的): getcolors im.getcolors()=>一个(计数、颜色)元组列表或无元组列表 im.getcolors(maxcolors)=>一个(count,color)元组列表或无元组列表 (1.1.5中新增)返回(计数,颜色)元组的未排序列表,其中计数是相应颜色在图像中出现的次数 图像模块还包含一个crop()方法,可用于将每个矩形插入getcolors()。你可以很容易地从中得出加权平均值 它应该比在python中手动运行循环快得多。我不确定它是否足够快,可以实时使用,但你会得到惊人的速度提升。您还可以每秒拍摄几次屏幕截图,因为可能以60 fps和10 fps的速度向LED发送信号不会特别明显。不要将其视为“限制为12.8 FPS”,而应将其视为“每5帧只能更新一次LED”,这应该不是一个明显的区别
编辑:如果你真的对这里的进一步优化感兴趣,我想你会发现这很有帮助。要加快调整大小的操作,你可以分两步来完成。对第一个使用“最近”以尽可能快的方式减少像素数,然后使用“反别名”将这些像素合并到具有代表性的样本中。这相当于您之前使用PIL函数试验的步长
PIL.ImageGrab.grab().resize((150, 100), PIL.Image.NEAREST).resize((15, 10), PIL.Image.ANTIALIAS)
我更新了我的问题-看起来像
ImageGrab.grab()
平均需要0.116秒,大约是autopy.bitmap.capture\u screen()的1.6倍。调整大小稍微快一点,不知道为什么。使用Image.NEAREST
根本不进行任何平均-它只是从多个像素中选择一个像素。无法保证它所选择的像素将代表该区域。@Markransem很好-我已经用另一种调整大小的方法更新了我的问题timit
sI已经更新了我的问题-看起来像ImageGrab.grab()
平均需要0.109s-仅9 FPS!我意识到9fps和30fps之间的视觉差异将是最小的,但是优化代码是一个有趣的挑战,对吗?有趣,根本不是我所期望的。我已经链接到一些似乎表现更好的东西,尽管我自己还没有测试过。感谢链接Robert,我将尝试一下gtk!我将在这里发回我的结果。它看起来是关闭的,我将稍后再试一次。调整大小
中使用的大多数模式都会产生很差的结果,因为它们没有采样足够的像素,这就是为什么它们的速度如此接近。最近值取1,双线性取2x2,双三次取3x3。这比ANTIALIAS将使用的170x160远得多。@MarkRansom啊,谢谢你的解释。有趣的是,可以看到使用autopy(1.35s)手动循环与PIL的ANTIALIAS(0.326s)之间的区别——改进了很多!就个人而言,如果PIL还没有这样做的话,这似乎是一个明显的并行化候选。如果
Step Time(s)
1 0.333048412226
2 0.16206895716
5 0.117172371393
10 0.102383282629
15 0.101844097599
20 0.101229094581
50 0.100824552193
myimg = ImageGrab.grab()
resized = myimg.resize((5, 5), Image.NEAREST)
PIL.ImageGrab.grab().resize((150, 100), PIL.Image.NEAREST).resize((15, 10), PIL.Image.ANTIALIAS)