После того, как всё заработало в предыдущем посте, осталось сделать финальную настройку, чтобы светодиоды более точно передавали изображение на экране. Для начала посмотрим на картинку, на основе которой мы выставляем цвета, с помощью простого скрипта, который делает чтение буфера из EasyCap и сохраняет его в файл. Как обычно мой любимый vim screenshot.py:
import numpy as np import cv2 import sys cap = cv2.VideoCapture(0) if not cap.isOpened(): print "Failed to initialize" exit(0) ret, frame = cap.read() if not ret: print "Failed to read frame" exit(0) cv2.imwrite(sys.argv[1],frame)
Единственная новшество тут – это запись в файл с помощью функции cv2.imwrite, которая сама определяет формат сохранения в зависимости от расширения файла. То есть, если туда передать .jpg – то будет JPEG, а если .png то PNG.
sys.argv[1] – это чтение параметра из командной строки. Нулевой элемент – это имя скрипта. Таким образом, объединив эти две вещи, скрипт будет сохранять в формат файла в зависимости от параметра который мы передадим. Проверьте переключатель формата на устройстве конвертации из HDMI в аналоговый видеосигнал. У меня он установлен в NTSC поэтому делаю первый снимок с соответствующим именем:
sudo python screenshot.py /run/ntsc.jpg
На снимке экрана видно, что слева и справа здоровенная чёрная рамка, поменьше снизу и маленькая сверху. Именно из-за этой рамки цвет светодиодов так сильно отличается. В дополнение к этому картинка обрезана слева и справа. Посмотрим, что будет если попробовать PAL. Переведите переключатель на конвертере в другое положение и повторите процедуру, чтобы получить второй снимок и решить, какой из режимов предпочтительнее.
sudo python screenshot.py /run/pal.jpeg
Тут также здоровенная рамка, да ещё и картинка сильнее обрезана справа и снизу. Так что мой выбор очевиден – NTSC. Если у вас такая же ситуация, то переведите переключатель обратно.
Теперь нам нужно модифицировать наш скрипт управления лентой, чтобы он не учитывал чёрные пиксели рамки, а работал только с той частью, которая показывает картинку с устройства. Для этого нужно померить количество пикселей с каждой стороны в любом графическом редакторе, например mspaint-е. После этого заведём четыре переменные, которые и будут определять начало значимых для нас пикселей на картинке. Для этого откроем наш скрипт и добавим новые переменные. vim run.py:
import numpy as np import time import cv2 import sys from neopixel import * LED_PIN = 18 LED_HEIGHT = 15 LED_WIDTH = 25 LED_FREQ = 800000 LED_DMA = 5 LED_BRIGHTNESS = 255 LED_INVERT = False xborderl = 23 xborderr = 21 ybordert = 2 yborderb = 9
Последние четыре строчки показывают количество пикселей, которое я намерил для каждой стороны. Теперь, после того, как мы прочитали картинку с девайса – необходимо выкусить только ту часть, которая не содержит в себе чёрную рамку:
strip = Adafruit_NeoPixel(LED_HEIGHT*2+LED_WIDTH*2,LED_PIN,LED_FREQ,\ LED_DMA,LED_INVERT,LED_BRIGHTNESS) strip.begin() cap = cv2.VideoCapture(0) if (not cap.isOpened()): print "unable to initialize!" exit(0) ret,frame1 = cap.read() ret,frame2 = cap.read() while(cap.isOpened()): ret,frame1 = cap.read(frame1) ret,frame2 = cap.read(frame2) img = frame2[ybordert:frame2.shape[0]-yborderb,\ xborderl:frame2.shape[1]-xborderr]
Последняя строчка определяет как раз границы, по-которым мы будем обрезать. Теперь нам нужно уже resize-ить не всю картинку, а только значимую область:
rsz1 = cv2.resize(img, (LED_HEIGHT, LED_WIDTH))
а всё остальное остаётся по старому:
for i in range(LED_WIDTH): BGR = rsz1[LED_WIDTH-i-1,0] color = Color(int(BGR[2]),int(BGR[1]),int(BGR[0])) strip.setPixelColor(i, color) for i in range(LED_HEIGHT): BGR = rsz1[0,i] color = Color(int(BGR[2]),int(BGR[1]),int(BGR[0])) strip.setPixelColor(i+LED_WIDTH, color) for i in range(LED_WIDTH): BGR = rsz1[i,LED_HEIGHT-1] color = Color(int(BGR[2]),int(BGR[1]),int(BGR[0])) strip.setPixelColor(i+LED_HEIGHT+LED_WIDTH, color) for i in range(LED_HEIGHT): BGR = rsz1[LED_WIDTH-1,LED_HEIGHT-i-1] color = Color(int(BGR[2]),int(BGR[1]),int(BGR[0])) strip.setPixelColor(i+LED_HEIGHT+LED_WIDTH*2, color) strip.show()
Пришло время попробовать. В youtube полно видео для тестирования ambilight. Мне понравилось вот это (не забудьте включить полный экран):
Вот как это выглядит у меня:
Так же нашёл прикольное видео с Laser show – решил попробовать свой билд на нём:
В общем видно, что ещё есть над чем работать. Задержка заметна, видно пропуски, да и ленту надо чуть переклеить. Думаю, что на новогодних каникулах разберусь