В предыдущем посте я описал, что нужно поставить, чтобы управлять светодиодной лентой. Настало время заставить ленту светиться так как нам этого хочется – реагируя на изображение на входе устройства захвата.
Для этого можно модифицировать скрипт, который мы написали для тестирования.
cp test.py run.py vim run.py
теперь помимо тех библиотек, которые мы уже подключили нам понадобится ещё time и neopixel.
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 strip = Adafruit_NeoPixel(LED_HEIGHT*2+LED_WIDTH*2,LED_PIN,LED_FREQ,\ LED_DMA,LED_INVERT,LED_BRIGHTNESS) strip.begin()
теперь инициализируем видеозахват используя OpenCV, этот код уже был написан в прошлый раз:
cap = cv2.VideoCapture(0) if (not cap.isOpened()): print "unable to initialize!" exit(0)
создаем переменные с которыми будем работать и читаем кадр из устройства
ret,frame1 = cap.read()
теперь нам нужен цикл который будет все время вычитывать кадры и управлять лентой:
while(cap.isOpened()): ret,frame1 = cap.read(frame1)
EasyCap выдает картинку 720×480 пикселей на основе, которой нам надо выставлять цвет для светодиодов. Самый простой способ, который я вижу это просто сжать эту самую картинку до размера количества светодиодов, то есть из 720×480 должно получиться 25×15. К счастью в OpenCV это делается одной строчкой:
rsz1 = cv2.resize(frame1, (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)
Тут следует сказать о двух особенностях.
- У меня лента начинается в нижнем левом углу телевизора и идёт по часовой стрелки если смотреть на экран. Соответственно мне нужны пиксели с левой стороны картинки то есть X=0, а Y=высота картинки – индекс, так как начало картинки находится в верхнем левом углу
- В Картинках, представленных как массивы numpy, сначала идут Y координаты, а потом X
Дальше нужно повторить всё тоже самое только для верха, правого бока и низа:
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*2+LED_WIDTH, color)
Единственное, на что нужно обратить внимание – это то, что каждый раз вызывая setPixelColor вы должны сдвигать index светодиода для которого вы выставляете цвет. В первом цикле у нас 15 светодиодов, соответственно во втором цикле мы уже выставляем цвет для 15+i-го светодиода, а в 3ем цикле для 15+25+i-го и т.д..
Теперь, когда цвет для всех светодиодов задан осталось только отправить эти данные на ленту:
strip.show()
Вот и всё – скрипт готов, пришло время запускать.
sudo python run.py
светодиоды зажгутся и если вы запустите кино или просто свернёте все окна то увидите, что некоторые (или все) светодиоды начнут неприятно моргать:
Первое, что можно сделать, чтобы избавиться от этого – это разогнать Raspberry Pi 2 используя стандартную утилиту raspi-config.
sudo raspi-config
выберите overclocking
затем выберите preset pi2 – 1000MHz
Перезагрузитесь и попробуйте ещё раз. Должно стать лучше, но не идеально. Причина тому, видимо в том, что мы читаем только один кадр, в то время, как EasyCap предосталвяет buffer из двух. Чтобы проверить это можно воспользоваться всё тем же v4l2-ctl и опцией –all:
в голову приходит только один фикс – читать два раза. Для этого сделаем небольшое изменение для нашего скрипта vim run.py на строчке 30:
ret,frame1 = cap.read() ret,frame2 = cap.read()
и на строчках 34-37
ret,frame1 = cap.read(frame1) ret,frame2 = cap.read(frame2) rsz1 = cv2.resize(frame2, (LED_WIDTH, LED_HEIGHT))
и попробуем ещё раз
sudo python ryn.py
Теперь почти хорошо, осталось прогнать тест и сделать последние доработки, но это уже в следующий раз.