Tag Archives: ambilight

Новости

Сайт пребывал в некотором подвешенном состоянии по разным причинам.

Во-первых, я сменил пропеллер на звезду и про это будет отдельный пост.

Во-вторых я был отпуске в Дубае, про это тоже будет отдельный пост.

В-третьих, я был в командировке в США и про это тоже будет отдельный пост

В-четвертых, я подсел на компьютерные игры (но уже слез) – это Factorio и Astroneer. Поста, пожалуй, не будет 🙂

В-пятых, я починил свой Raspberry PI, который используется для Ambilight, и запилил пару видео с ним и компьютерными играми. И да, будет отдельный пост 🙂

В-шестых, я решил сделать серию постов про собеседования.

В-седьмых, очередная порция пропагандистких видео и постов о том, как хорошо тут и как плохо там наталкнула меня на  мысль о том, что нужно изучить “пути отступления”. Естественно тоже поделюсь.

И наконец, в-восьмых, пора плотно занятся нейро сетями.

Stay tunned, как говорится.

P.S. Чуть не забыл – серия постов про торговлю акциями тоже найдёт свое завершение.

Ambilight своими руками: Часть 5 – Tuning

После того, как всё заработало в предыдущем посте, осталось сделать финальную настройку, чтобы светодиоды более точно передавали изображение на экране. Для начала посмотрим на картинку, на основе которой мы выставляем цвета, с помощью простого скрипта, который делает чтение буфера из 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

ntsc_defНа снимке экрана видно, что слева и справа здоровенная чёрная рамка, поменьше снизу и маленькая сверху. Именно из-за этой рамки цвет светодиодов так сильно отличается. В дополнение к этому картинка обрезана слева и справа. Посмотрим, что будет если попробовать PAL. Переведите переключатель на конвертере в другое положение и повторите процедуру, чтобы получить второй снимок и решить, какой из режимов предпочтительнее.

sudo python screenshot.py /run/pal.jpeg

pal_defТут также здоровенная рамка, да ещё и картинка сильнее обрезана справа и снизу. Так что мой выбор очевиден – 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 – решил попробовать свой билд на нём:

В общем видно, что ещё есть над чем работать. Задержка заметна, видно пропуски, да и ленту надо чуть переклеить. Думаю, что на новогодних каникулах разберусь

Ambilight своими руками: Часть 4 – всё вместе

В предыдущем посте я описал, что нужно поставить, чтобы управлять светодиодной лентой. Настало время заставить ленту светиться так как нам этого хочется – реагируя на изображение на входе устройства захвата.

Для этого можно модифицировать скрипт, который мы написали для тестирования.

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)

Тут следует сказать о двух особенностях.

  1. У меня лента начинается в нижнем левом углу телевизора и идёт по часовой стрелки если смотреть на экран. Соответственно мне нужны пиксели с левой стороны картинки то есть X=0, а Y=высота картинки – индекс, так как начало картинки находится в верхнем левом углу
  2. В Картинках, представленных как массивы 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

raspiconfigзатем выберите preset pi2 – 1000MHz

raspiconfig-pi2presetПерезагрузитесь и попробуйте ещё раз. Должно стать лучше, но не идеально. Причина тому, видимо в том, что мы читаем только один кадр, в то время, как EasyCap предосталвяет buffer из двух. Чтобы проверить это можно воспользоваться всё тем же v4l2-ctl и опцией –all:

v4l2allв голову приходит только один фикс – читать два раза. Для этого сделаем небольшое изменение для нашего скрипта 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

Теперь почти хорошо, осталось прогнать тест и сделать последние доработки, но это уже в следующий раз.

Ambilight своими руками: Часть 3 – софтверная

Если вы прочитали мой предыдущий пост, все подключили и у вас тоже железо, что и у меня – не спешите радоваться, всё только начинается. Теперь нужно всё настроить.

Обновите ваш Raspbian

sudo apt-get update
sudo apt-get upgrade

Для начала убедитесь, что ваш EasyCap девайс работает. В этом вам помогут команды lsusb и dmesg | tail:

lsusb
dmesg | tail

вывод должен выглядеть примерно так:

lsusbdmesgТут видно, что появился новый USB девайс 1b71:3002, что это USBTV007 от fushicai. Дальше нам понадобятся утилиты Video4linux. С помощью v4l2-ctl –list-devices найдите свой EasyCap. В моем случае это просто /dev/video0.

v4l2ctllistОтлично, запомните (или запишите) результат v4l2-ctl – тот что выглядит как /dev/video0. Теперь используя, например, mplayer можно посмотреть картинку предварительно запустив Иксы:

startx
sudo apt-get -y install mplayer
mplayer tv:// -tv device=/dev/video0 -hardframedrop

вместо /dev/video0 может быть что-то другое – смотри вывод v4l2-ctl –list-devices.

Тут вас ждёт первая засада: чёрный или зелёный экран.

20151119_205807Проверьте кабели и побалуйтесь с переключателем PAL-NTSC:

20151103_220807Или же вы можете указать PAL или NTSC в командной строчке для mplayer

mplayer tv:// -tv device=/dev/video0:norm=NTSC -hardframedrop

20151119_210935Python+OpenCV

Cледующий шаг – это поставить и настроить Python+OpenCV. Python – это скриптовый язык программирования, подробнее о нём можете прочитать например в Wikipedia. Скорее всего Python уже установлен на Raspberry Pi, тем не менее имеет смысл проверить версию, так как я тестировал только с версией 2.7.3.

Далее вам нужно поставить две python библиотеки. Это numpy и OpenCV. Они так же доступны через apt-get.

sudo apt-get install python-numpy
sudo apt-get install python-opencv

Numpy – это библиотека для научных вычислений, а OpenCV – это библиотека машинного зрения. Для того, чтобы проверить, что всё установлено и работает как надо, можно написать простенький скрипт на Python-е. Я люблю vim, но вы можете использовать любой другой текстовый редактор, например nano test.py.

Импортируем библиотеки numpy, OpenCV и sys для последующего расширения и работы с системными функциями.

import numpy as np
import cv2
import sys

Эта часть инициализирует видеозахват для устройства /dev/video0. Если ваш EasyCap имеет другой номер – используйте его вместо 0. И проверяем, что инициализация прошла успешно.

cap = cv2.VideoCapture(0)

if (not cap.isOpened()):
  exit(0)

Читаем кадр из устройства и проверяем, что чтение прошло успешно.

ret,frame = cap.read()

if (not ret):
  exit(0)

И сохраняем в файл.

cv2.imwrite('/run/test.jpeg',frame)

Запускаем наш Python скрипт, чтобы посмотреть как оно работает:

sudo python test.py

Для того, чтобы посмотреть картинки в консоли, я использую fbi.

sudo apt-get install fbi
sudo fbi /run/test.jpeg

20151119_211614

_rpi_ws281x

Следующий шаг – это начать работу со светодиодной лентой. На просторах интернета есть разные реализации. Наиболее часто попадающаяся это rpi_ws281x, в частности инструкия на сайте Adafruit ссылается на неё, однако мне так и не удалось её поставить и заставить работать отдельно на Raspberry Pi 2, в то время как на Raspberry Pi B+ всё работает. Спасибо ребятам из pimoroni, за их волшебный unicorn_hat, который решил все проблемы  и простому shell скрипту, который устанавливает все необходимое. Просто качаете и запускаете.

Сначала ставим саму библиотеку, как описано здесь:

sudo apt-get install build-essential python-dev git scons swig
git clone https://github.com/jgarff/rpi_ws281x.git
cd rpi_ws281x/
scons

После того как библиотека скомпилирована и установлена, нужно её немножко подправить и для этого то и понадобится скрипт от ребят из pimoroni.

wget get.pimoroni.com/unicornhat
chmod +x unicornhat
./unicornhat
sudo pip install unicornhat

Чтобы проверить работоспособность можно запустить один из exmaple-ов.

20151119_222410А в следующей серии вы узнаете как скрестить OpenCV и Adafruit_NeoPixel чтобы управлять светодиодами в зависимости от изображения на экране

 

Ambilight своими руками. Часть 2 – Железо

Итак, вы прочитали первую часть и понимаете какую боль вам придётся испытать и всё равно хотите попробовать? Очень хорошо, я попробую это облегчить.

Хочу сразу подчеркнуть, что если вы хотите и фильмы смотреть и управлять лентой с Raspberry Pi, то вы пришли не по адресу. Мой вариант годиться только для одного – фоновая подсветка для внешнего HDMI сигнала.

Итак вам понадобятся:

  • Raspberry Pi 2
  • Светодиодная лента на базе ws2812b
  • HDMI Splitter
  • HDMI2AV converter
  • EasyCap USB AV Grabber
  • блок питания для Raspberry Pi
  • блок питания для HDMI Splitter-а (Должен быть в комплекте)
  • 3x HDMI кабель
  • RCA-RCA кабель
  • Источник HDMI сигнала, например Nvidia Shield
  • паяльник, припой,

Блок питания для Raspberry Pi

Я не могу передать словами, насколько важен хороший источник питания для Raspberry Pi. Если вы видите вот такой значок в верхнем правом углу, значит вашему Raspberry Pi не хватает питалова.

20151103_221700

я взял SmartBuy с двумя USB на 2 и 1 ампера, проблемы с питанием пропали.

20151103_220456

Ещё хорошо себя показала внешняя батарея от Xiaomi 

20151103_220509

Video Grabber

Easy Cap USB Video Grabber – эта та самая вещь, которая доставит вам много боли, так как их существует великое множество (говорят всего 4), и невозможно определить какой именно девайс вы купите до покупки, так как они выглядят одинаково.

20151103_220604

Мне не повезло – я купил 4 штуки и все они оказались на базе чипа UTV007. К счастью, Raspbian от 2015-05-05 (последний доступный Debian Wheezy на официальном сайте Raspberrypi.org на момент написания) уже включает в себя поддержку драйвера для этого устройства.

20151103_221052

Светодиодная лента

Если вы с паяльником на ты, то вам повезло, и эта часть не вызовет у вас трудностей, но я паять не умею, поэтому мне понадобилась помощь интернета. Вот видео, которое я использовал как видео инструкцию:

На то, чтобы все припаять правильно и ничего не развалилось, пока я нёс это до телевизора ушло вечеров 5. В результате я добился чего хотел – надёжного соединения и без соплей. Правда из-за того, что я сначала отодрал защитный слой со светодиодной ленты, а потом паял, то на него налипла всякая хрень, которая мешает надёжному креплению ленты к телевизору. Появилось даже идея воспользоваться могучим клеем момент, но пока это выглядит вот так:

20151103_220826

Остальные компоненты

HDMI Splitter или разветлитель по нашему. Нужен чтобы сделать из одного выходного сигнала два. Первый всё так же идёт на телевизор, а второй, копия первого, идет на устройство видеозахвата и используется в качестве входных данных для задания цвета светодиодов

20151103_220749

Поскольку EasyCap работает с аналоговым видеосигналом, а на выходе у современных устройств как правило HDMI, то нужен конвертор HDMI2AV.

20151103_220756Его и EasyCap соединяем RCA-RCA кабелем соблюдая маркировку – желтый CVBS/Video в Желтый и т.п.

Подключение светодиодной ленты

Это малость запутанный момент. Можете нарыть разные варианты в интернете. Тот же Adafruit дает неплохое описание. Важно помнить две вещи:

  • У светодиодной ленты и Raspberry Pi должна быть общая земля
  • Для питания светодиодной ленты нужен мощный источник питания, около 60*количество светодиодов мА

У меня 80 светодиодов, то есть мне нужно 4.8 Ампера для светодиодной ленты. Я купил блок питания от какого-то ноутбука на 6 Ампер.

20151116_203458И о чудо – штекер от блока питания идеально подошёл к одному из разъёмов с клеммой, что у меня завалялся.

20151116_203544Соответственно берем минус и подключаем к земле ленты (чёрный провод) и к земле на Raspberry Pi 2 (например к pin 6), а плюс с разъёма подключаем на 5 вольт ленты (красный провод). Последнее, что остаётся сделать – это подключить data (зелёный провод) светодиодной ленты к pin 12.

20151116_212526Распиновку Raspberry Pi 2 можно посмотреть здесь.

pinout6-1220151116_211654

Результат

В результате получилось довольно миленько:

20151103_221509Что скажите? То как выглядит подсветка – норм?

Ambilight своими руками. Часть 1 – Боль

Полгода назад я открыл для себя мир боли и унижения волшебный мир микроконтроллеров и одноплатных компьютеров. Теперь у меня аж целых 6(7) Raspberry Pi, 3 Arduino и 2 девайса от ODROID. И, хотя большинство из них пойдёт в мой автомобильный проект или на подарки друзьям, один из них решено было пустить в какой-нить домашний проект.

20151103_220658 20151107_110215

Одним из первых таких проектов, который попался мне на глаза в интернете был проект по добавлению фоновой подсветки к телевизору наподобие той, что делает Philips.

Естественно, как и всё, что связано со “сделай сам” , оно не могло просто взять и заработать.

Сначала я купил “неправильную” RGB ленту. Которая работает шикарно, но на ней нельзя задать цвет для отдельного светодиода, а только для всей ленты целиком. Правда эта лента пригодилась в другом проекте, о котором обязательно напишу позже.
RGB лента 20151107_115237  20151107_115336

Осознав ошибку я начал искать “правильную” ленту с управлением каждым светодиодом отдельно (Так называемый бегущий огонь). Таких оказалось много разных и я взял первую попавшуюся – на базе ws2812, не подозревая, что могут быть какие-то проблемы.

ws2812

ws2812

Как оказалось, это тоже “неправильная” лента и проекты, которые существуют в интернете либо не поддерживают её, либо требуется дополнительно Arduino… или я просто не умею пользоваться google-ом.

  • Всемирно любимый Hyperion, например, при настройке не имеет поддержки ws2812 лент, но может управлять ей через Arduino (нафига?). С наскока разобраться не получилось, да и сама идея использовать связку RaspberryPi с Arduino мне как-то не нравится
  • ambi-tv вообще поддерживает только один тип лент: LPD8806, хотя имеет возможность расширения
  • “мертвый” boblight тоже может работать с такой лентой только через Arduino.

В дополнение ко всему этому, рабочие примеры в интернете были для Raspberry Pi A или B, а для Raspberry Pi 2 часто можно было встретить оговорку, что “не поддерживается” или “не работает”, что вселяло дополнительный оптимизм.

Ну да ладно, подумал я, говно вопрос – запилю всё сам. Тогда я ещё не знал, что помимо Software проблем меня ждут ещё и Hardware.

Не подходит для Raspberry Pi - недостаточно питалова

Зарядка от телефона Samsung 5v/2a

Как оказалось большинство (или все?) производителей телефонов кладут в комплекте с их устройством говённую зарядку, напряжение которой не хватает для Raspberry Pi, к тому же сам Raspberry Pi имеет ограничение на выходной ток на USB портах. О том что это может вызывать какие-то проблемы с подключенными устройствами я тоже узнал гораздо позже.

Кроме того это кажется очевидным, когда читаешь, но не очевидным, когда делаешь. Светодиодную ленту нужно СНАЧАЛА примерить к телевизору, ЗАТЕМ нарезать. ПОСЛЕ припаять, и ТОЛЬКО ПОТОМ приклеивать к телевизору.

В дополнение ко всему этому мой вариант расположения ленты за телевизором, отличается от классического – светить в стену. Вместо этого мои светодиоды светят в бок. Когда я это делал – мне казалось, что, поскольку край рамку у моего телевизора прозрачный, то возможность видеть подсвеченный светодиод придаст некую изюминку. На деле это отвлекает от картинки и не дает нужного эффекта. Короче НЕ НАДО ТАК ДЕЛАТЬ.
20151103_221509

О том можно ли сделать из Raspberry Pi фоновую подсветку для телевизора и как всё это работает – читайте в следующих частях.