Я написал быстрый скрипт на Python, чтобы вернуть средний цвет прямоугольников, окружающих периметр моего экрана. (Конечная цель здесь иметь RGB-светодиодывокруг моего монитора для эффекта свечения во время просмотра фильмов — как это (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 блоков = 163 840 пикселей на блок), и каждый блок по периметру (16 * 163 840 = 2 621 440 циклов). В целом на это ушло 2,814 с.
Если я увеличу step, это ускоряется, но недостаточно: (здесь используются более реалистичные блоки 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 кадров в секунду, в идеале быстрее (20–30 мс), чтобы обеспечить накладные расходы на последовательную передачу. Имейте в виду, что у меня разрешение экрана 2560*1600!
Я слышал о Python Imaging Library (PIL), но еще не успел изучить скорость работы функции ImageGrab
, но она выглядит многообещающе.
Можно ли считывать значения пикселей непосредственно с графического процессора?
Еще одна мысль: как лучше всего определить верхний/нижний край фильма? (Если соотношение сторон широкоэкранное, вверху/внизу скриншота есть черные полосы, а некоторые прямоугольники черные).
Использование PIL's grab():
>>> timeit.Timer("ImageGrab.grab()", "from PIL import ImageGrab").timeit(100)/100
0.1099840205312789
PIL - resize:(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 кадрами в секунду, или 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 в HEX.
Может ли кто-нибудь предложить более быстрый способ — например, сделать частичный снимок экрана? Должен ли я написать что-нибудь на C?