DIY: Универсальный Ambilight для домашней мультимедиа системы — Атмосвет
Для своей первой статьи я выбрал одну из самых успешных своих поделок: HDMI-passthrough аналог Ambilight от Philips, далее я будут называть эту композицию «Атмосвет».
Введение
В интернетах не очень сложно найти готовые/открытые решения и статьи как сделать Амбилайт для монитора/телевизора, если ты выводишь картинку с ПК. Но в моей мультимедиа системе вывод картинки на телевизор c ПК занимает только 5% времени использования, большее кол-во времени я играю с игровых консолей, а значит нужно было придумать что-то свое.
Исходные данные:
- 60″ Плазменный телевизор
- HTPC на базе Asrock Vision 3D 137B
- Xbox 360
- PS3
- PS4
- WiiU
Требование:
Необходимо обеспечить централизованную поддержку Атмосвета для всех устройств подключенных к телевизору.
Реализация
Я не буду рассказывать, как я прикреплял 4.5м светодиодную ленту к телевизору и что нужно сделать с Arduino, в качестве базы можно использовать эту статью.
Единственный нюанс:
Я заметил, что внизу экрана идут странные мерцания, сначала погрешил на сигнал, перековырял дефликер, изменил ресазинг картинки и еще кучу всего перекопал, стало лучше, но от мерцания не помогло. Стал наблюдать. Оказалось, что мерцание было только в конце ленты и то при ярких сценах. Взяв мультиметр, я замерил напряжение на начале, середине и конце ленты и угадал с причиной мерцаний: в начале ленты было 4.9В( да китайский БП дает напряжение с отклонением, это не существенно), в середине 4.5 в конце 4.22 — Падение напряжение слишком существенно, пришлось решить проблему просто — к середине ленты я подвел питание от бп, провод пустил за телевизором. Помогло мгновенно, какие либо мерцания прекратились вообще.
Захватываем картинку вебкамерой
Первая тестовая версия для обкатки идеи и её визуализации была выбрана через захват картинки через вебкамеру) выглядело это как-то так:
Низкая цветопередача и высокий latency показал, что эта реализация не может быть никак использована.
Захват картинки через HDMI
- Сигнал со всех устройств подается на 5in-1out HDMI свитч, который поддерживает HDCP
- Выходной сигнал подается на 1in-2out HDMI splitter, который мало того, что поддерживает HDCP, так еще отключайте его на выходе(слава китайцам).
- Один из выходных сигналов идет на телевизор
- Другой выходной сигнал идет на HDMI to AV конвертер
- S-Video сигнал идет на коробочку захвата от ICONBIT
- Коробочка захвата подключается к вечно работающему HTCP по USB, который подключен к Arduino контроллеру ленте на телевизоре.
- Это работает.
- Сумарно все это дело, заказывая из китая, мне обошлось тысяч в 3-4 тыс. рублей.
Почему я не использовал плату для HDMI захвата? Все просто: самый дешевый вариант и доступный — это Blackmagic Intensity Shuttle, но она не может работать с сигналом 1080p/60fps, только с 1080p/30fps — что не приемлемо, т.к. я не хотел понижать фреймрейт, чтобы можно было захватывать картинку. + это дело стоило в районе 10 тыc. рублей. — что не дешево при неизвестном результате.
Потери на конвертации HDMI to S-video несущественны для захвата цвета в разрешении 46х26 светодиодной подсветки.
Изначально для захвата S-video я пробовал использовать EasyCap( у него много китайских вариаций), но суть в том, что используемый там чип крайне убог, и с ним нельзя работать при помощи openCV.
Единственный минус — выходной сигнал S-Video содержал черные полосы по краям срезающий реальный контент(около 2-5%), выходную картинку с платы захвата я обрезал, чтобы удалить эти полосы, сама потеря изображения в тех областях на практике не сказалась на результате.
Для меня это была самая интересная часть, т.к. с железками я не очень люблю ковыряться.
Для захвата картинки я использовал openCV и в частности его .NET враппер emgu CV.
Я решил также применить несколько разных техник постобработки изображения и его подготовки, прежде чем отдавать список цветов на контроллер.
Процесс обработки фрейма
1. Получение захваченного фрейма
2. Кроп фрейма, для исключения черных полос
Обрезаем 8 пикселей сверху, 8 справа и 18 снизу.(слева полосы нет)
3. Ресайзим фрейм в разрешение подсветки, незачем нам таскать с собой здоровую картинку
Тоже ничего сложного, делаем это средствами openCV:
frame.Resize(LedWidth — 2*LedSideOverEdge,
LedHeight — LedBottomOverEdge — LedTopOverEdge,
INTER.CV_INTER_LINEAR);
Внимательный читатель заметит, обилие переменных. Дело в том, что у меня рамка телевизора достаточно большая, занимая 1 светодиод по бокам, 1 сверху и 3 снизу, поэтому ресайз делается на светодиоды, которые находятся непосредственно напротив дисплея, а углы мы уже дополняем потом. При ресайзинге мы как раз получаем усредненные цвета, которые должны будут иметь пиксели светодиодов.
4. Выполняем мапинг светодиодов с отреcайзенного фрейма
Ну тут тоже все просто, тупо проходим по каждой стороне и последовательно заполняем массив из 136 значений цветом светодиодов. Так вышло, что на текущий момент все остальные операции проще выполнять с массивом светодиодов, чем с фреймом, который тяжелее в обработке. Также на будущее я добавил параметр «глубины» захвата(кол-во пикселей от границы экрана, для усреднения цвета светодиода), но в конечном сетапе, оказалось лучше без неё.
5. Выполняем коррекцию цвета (баланс белого/цветовой баланс)
Стены за телевизором у меня из бруса, брус желтый, поэтому нужно компенсировать желтизну.
var blue = 255.0f/(255.0f + blueLevelFloat)*pixelBuffer[k];
var green = 255.0f/(255.0f + greenLevelFloat)*pixelBuffer[k + 1];
var red = 255.0f/(255.0f + redLevelFloat)*pixelBuffer[k + 2];
Вообще я изначально из исходников какого-то опенсорс редактора взял цветовой баланс, но он не менял белый(белый оставался белым), я поменял формулы немного, опечатался, и получил прям то, что нужно: если level компонента цвета отрицательный(я поинмаю как — этого цвета не хватает), то мы добавляем его интенсивность и наоборот. Для моих стен это получилось: RGB(-30,5,85).
В кореркции цвета я также выполняю выравнивание уровня черного(черный приходит где-то на уровне 13,13,13 по RGB), просто вычитая 13 из каждой компоненты.
6. Выполняем десатурацию (уменьшение насыщенности изображения)
В конечном сетапе, я не использую десатурацию, но может в определенный момент понадобится, фактически это делает цвета более «пастельными», как у Филипсовского амбилайта. Код приводить не буду, мы просто конвертим из RGB -> HSL, уменьшаем компоненту Saturation(насыщенность) и возвращаемся обратно уже в RGB.
7. Дефликер
Так уж выходит, что входное изображение «дрожит» — это следствие конвертации в аналоговый сигнал, как я полагаю. Я сначала пытался решить по своему, потом подсмотрел в исходники Defliker фильтра, используемом в VirtualDub, переписал его на C#(он был на С++), понял, что он не работает, ибо он такое впечталение, что борется с мерцаниями между кадрами, в итоге я совместил свое решение и этот дефликер получив что-то странное, но работающее лучше чем ожидалось. Изначальный дефликер работал только с интенсивностью всего фрейма, мне нужно по каждому светодиоду отдельно. Изначальный дефликер сравнивал изменение интенсивности как суммы, мне больше нравится сравнение длинны вектора цвета, Изначальный дефликер сравнивал дельту изменения интенсивности по сравнению с предыдущим кадром, это не подходит, и я переделал на среднюю величину интенсивности в пределах окна предыдущих кадров. И еще много других мелочей, в результате чего от начального дефликера мало что осталось.
Основная идея: исходя из средней интенсивности предыдущих кадров, выполнять модификацию текущего кадра, если его интенсивность не выше определенного порога (у меня этот порог в конечном сетапе 25), если порог преодолевается, то производится сброс окна, без модификации.
Немного модифицированный (для читаемости вне контекста) код моего дефликера:
Пусть _leds — массив светодиодов класса Color, _ledsOld — значения кадра до конвертации, LedLumWindow — ширина окна предыдущих кадров, для оценки среднего изменения интенсивности, в конечном сетапе окно у меня было 100, что примерно при 30кад/с равняется 3-секундам. _lumData — массив значения интенсивности предыдущих кадров.
В конечном итоге данный механизм дал еще приятные неожиданные последствия на картинку, сложно описать как это воспринимается визуально, но он делает темнее где надо и ярче где надо, словно динамический контраст. Цель дефликера в итоге получилась широкая, не только устранение мерцаний, но и общее уравновешивание выводимого цвета, как и по компонентам, так и по времени в пределах окна.
8. Сглаживание светодиодов по соседям.
Вообще в конечном сетапе, сглаживание мне не очень понравилось, и я его отключил, но в некоторых случаях может пригодиться. Тут мы просто усредняем цвет каждого светодиода по его соседним.
9. Сохраняем текущий стейт, чтобы тред отправки пакетов схватил и отправил его на контроллер подсветки.
Я умышленно разделил процесс обработки кадров и отправки пакетов на контроллер: пакеты отправляются раз в определенный интервал(у меня это 40мс), чтобы ардуино спела обработать предыдущий, ибо чаще чем 30мс она захлебывается, таким образом выходит, что мы не зависим напрямую от частоты кадров захвата и не мешаем тому процессу(а ведь отправка пакета тоже тратит время).
Немного про ардуино
Нельзя просто так взять и отправить по сериалу здоровенный пакет на ардуино, ибо онв ыйдет за пределы дефолтного буфера HardwareSerial и ты потеряешь его конец.
Решается это довольно просто: выставляем значение размера буфера HardwareSerial достаточного размера, чтобы влезал весь отправляемый пакет с массивом цветов, для меня это 410.
Сам софт был реализован в виде win службы, чтобы настраивать все параметры + включать/отключать я сделал Web UI, который связывался с службой через WebService на службе. Итоговый интерфейс на экране мобильника выглядит так: 
Сейчас планирую прикрутить голосовое управление через Kinect for Windows подключенном к HTCP.
Результат
В итоге результат оправдал все ожидания, и теперь играя в игры на консолях я получаю еще больше погружения в атмосферу игры.
Как общий результат работы я записал видео с работой атмосвета по моей схеме:
Испытуемый образец 1: Pacific Rim, сцена битвы в Шанхае, этот фильм хорошо подходит для тестирования и демонстрации, много ярких сцен и вспышек, ударов молнии и т.д.:
Испытуемый образец 2: Какой-то ролик из MLP, слитый с ютуба, очень хорошо подходит для теста сцен с яркими цветами(мне понравились полосы), а также быстро сменяющихся сцен(под конец виде можно разглядеть последствия задержки, видных только на видео, при реальном просмотре этого не заметно, пробовал измерить задержку по видео — получилось 10-20мс):
И на последок стоит заметить про потребление ресурсов от HTPC:
HTPC у меня ASRock Vision 3D на i3, служба атмосвета отжирает 5-10% CPU и 32MB RAM.
DIY Ambilight System

A kind of a smart backlight system for a TV spotted in a commercial several years ago immediately draw my attention. When I encountered the relatively affordable individually controllable RGB LED strips, I could not resist to try to make my own version of the so-called ambilight system.
DIY Ambilight System
What it is and what it is used for?
Ambilight system is a sophisticated backlight for a TV or a PC monitor (which is the case described here). It accommodates the color and intensity of the light according to the current color content of the screen, more specifically to the content present at the screen borders. As such, it visually extends the picture displayed on the monitor and it significantly improves the movie watching or gameplay experience.
Architecture of the DIY solution
The arrangement of the proposed ambilight system is shown in the following image.

In total, there are 85 RGB LEDs on the back side of the monitor placed around its circumference. Each of these LEDs can be controlled separately via a serial data interface. The brightness of the individual red, blue and green color components is encoded by an 8 bit value and transmitted as a series of voltage pulses — a short one standing for logical 0 and a long one standing for logical 1. Generation of these control signals is the responsibility of a microcontroller.
Since the LED drivers support daisy-chaining, only a single shared data line is sufficient for control of the whole strip. The cost for this is the decrease in the refresh frequency with the rising number of LEDs, which is, however, not a problem at this scale. When connecting the individual segments of the LED chain (top, left side, etc.), mind the orientation of the strip, since one of its ends always acts just like a data input, while the other acts as data output. This direction is indicated by little arrows in between the LEDs.
I used a so-called, BluePill board, which was supposed to be equipped with an STM32F103C8T6 Cortex M3 microcontroller. As it, however, showed up, the one I bought was a fraudulent one, but fortunately, it still behaved according to the ST datasheet. I used Platformio as a development environment and LibOpenCM3 as a library for more convenient usage of the chip peripherals. If I should do the work again, I would, however, not use any of such libraries (neither LibOpenCM3 nor ST’s HAL (Hardware Abstraction Layer) or LL (Low Level) drivers) and instead, I would manipulate the MCU registers myself and create my own abstraction layer. I think this would bring me more joy from detailed understanding of the platform and probably at the same time save me quite a bit of time spend on debugging foreign code and guessing how to use the poorly documented libraries.
All of the interconnected LEDs are powered over a shared power rail. To avoid visible and distracting variations in LED brightness over the length of the strip caused by an uneven power distribution, interconnect the corresponding voltage terminals on the two of its ends. The wattage of the source has to be sufficiently high, for 85 LEDs the minimum should be 25.5W (it has to provide at least 5.1 A at 5 V, which is given by the fact that each of the 85 RGB LEDs consumes 60mA at its maximum brightness). I used a higher-rated 40 W power source adapter to have some margin and be able to use it later in other projects with even more LEDs.
The color information for individual LEDs is obtained by grabbing the screen content using a Python script and computing an average value from a small patch around each of the LED. An array of these values is then send over through a virtual COM port oven a USB cable and received by the BluePill board. The contained MCU then drives the LEDs as was already mentioned above. On my machine I was easily able to achieve a framerate greater then 30 fps — more then sufficient for movie watching purposes. Details can be seen directly from code shared at projects Git repository.
Подсветка телевизора в стиле "Ambilight"

Делаем подсветку стиле "Ambilight" на телевизоре.
Итак, входные данные: телевизор подключён к компьютеру длинным HDMI кабелем и используется для просмотра фильмов. ТВ-каналы не подключены и не нужны. Данная конфигурация идеальна для наиболее простой реализации, а именно Adalight + Ambibox.
Сначала нужна светодиодная лента, я так подумал и решил брать на 12в, чтобы ток был меньше, и нагрузка на провода тоже меньше.
Заказал "WS2811 Светодиодные полосы 5 м IC Vedio шоу индивидуально адресуемых IP30 водонепроницаемый IP67 5050 RGB SMD 30 48 60 LED /m 3 варианта быстро VU" в варианте 30 штук на метр с aliexpress. Для питания этого безобразия "12V5A DC 12 В 5A AC 110-240 В" оттуда же. Стоит примерно 1300р в сумме.
Начинаем пайку
Задумка такая — соединить 4 сегмента ленты. При соединении важно учитывать "направление" — отмечено стрелкой на ленте. Я соединил в круг провода +12v и GND, и каждый угол подсоединил к источнику питания — так будет ток, протекающий через ленту, ниже, и вероятность перегрева и порчи дорожек на ленте меньше. Провод сигнальный подпаивается к "началу" ленты и далее идёт последовательно по всем сегментам, последний сегмент с первым не соединять! Сигнальный провод втыкается в ардуину. Лучше припаять, но я просто залудил и воткнул в панельку, сидит плотно.
Ардуина питается от того же источника, 12в это нормально. По факту там не 12в на самом деле, БП не очень — где-то 11.5в с небольшой нагрузкой.
Первая проверка
Места пайки замазал термоклеем и сверху посадил кусочки термоусадки.
Монтаж на телевизор
Всё это клеится на телевизор, пока что поклеил ленту её собственной клеевой поверхностью, может и не будет отваливаться. Посмотрим.
Далее нужна ардуина, логично было бы взять nano, но у меня валялся клон uno сразу в корпусе, его и поставил — какая разница-то… Приклеил на 2-сторонний скотч.
Ещё нужен качественный 5-метровый usb кабель, у меня такой совершенно случайно валялся уже много лет. Все провода дополнительно приделываются пластиковыми хомутами, кое-где фиксируются армированным скотчем, чтобы не болтались.
В процессе отладки выяснился нюанс, о котором никто не удосужился написать ранее в статьях. Если брать ленту, в которой контроллеры будут встроены прямо в светодиоды, то каждый диод будет адресуем. А если взять ленту как у меня, то адресуются только кусками по 5 см! Три диода с точки зрения софта — это один! Потратил часа полтора наверное, пока понял, в чём подвох. В итоге получилось не 168 "диодов", а 56, после указания верного количества всё заработало.
Ещё эта лента работает не в RGB режиме, а RBG. Удалось подобрать опытным путём — в ambibox есть режим "заливки цветом".
Используемый софт:
Для ардуины вот это www.adafruit.com/product/461
И на компе вот это www.ambibox.ru/en/index.php/Main_Page
Весь софт бесплатный, кроме playclaw в составе ambibox, но его можно и не ставить.
Вот первый запуск, когда оно таки заработало как надо:
Осталось сделать:
1) Подкрутить настройки в ambibox — уменьшить яркость, чуть пригасить зелёный и синий.
2) Проложить кабели нормально.
В целом результатом доволен, получил интересный опыт, при этом ничего сложного делать не надо.
Динамическая фоновая подсветка экрана своими руками
Динамическая фоновая подсветка экрана телевизора или монитора компьютера. Работает под управлением Arduino, на компьютере вертится программа Ambibox. Arduino управляет адресной светодиодной лентой на чипах WS2812. В схему добавлен фоторезистор для адаптивной подстройки яркости ленты в зависимости от интенсивности освещения в помещении.
- Разрешение самодельной фоновой подсветки гораздо выше, чем предлагают даже дорогие модели от Philips
- Самая простая схема подключения среди всех моих проектов
- Удобная программа Ambibox для настройки и персонализации фоновой подсветки



ГОТОВЫЙ НАБОР
У наших партнёров Giant4 появился готовый набор ( ссылка на товар ) для сборки динамической подсветки! В комплекте идёт:
- Лента (длину можно выбрать)
- Провода для подключения
- Блок питания
- Удобный контроллер
- Подробная инструкция по установке




ВИДЕО
КОМПОНЕНТЫ
Каталоги ссылок на Алиэкспресс на этом сайте:
Стараюсь оставлять ссылки только на проверенные крупные магазины, из которых заказываю сам. Также по первые ссылки ведут по возможности на минимальное количество магазинов, чтобы минимально платить за доставку. Если какие-то ссылки не работают, можно поискать аналогичную железку в каталоге Ардуино модулей . Также проект можно попробовать собрать из компонентов моего набора GyverKIT .
- Купить в РФ, 60 свет/метр, 30 свет/метр
- Купить на Али ссылка, ссылка
- Black PCB / White PCB – цвет подложки ленты, чёрная / белая. В видео была чёрная
- 1m/5m – длина ленты в метрах (чтобы заказать 2 метра, берите два заказа 1m, очевидно)
- 30/60/74/96/100/144 – количество светодиодов на 1 метр ленты. В видео использовалась лента 60 диодов на метр
- IP30 лента без влагозащиты (как на видео)
- IP65 лента покрыта силиконом
- IP67 лента полностью в силиконовом коробе
- Постфикс ECO – лента чуть более низкого качества, меньше меди, на длинной ленте будет сильно проседать яркость
СХЕМЫ





ПРОШИВКА
УПРАВЛЕНИЕ
Теперь ставим программу амбибокс. Тут всё стандартно, далее далее продолжить далее далее завершить. В конце при выборе устройства нужно указать адалайт. Запускаем. Сразу можно поставить русский язык. И можно поставить автозапуск программы при старте компьютера. Чтобы она не мешала остальным, можно поставить задержку запуска. Теперь переходим на вторую вкладку и сразу жмём кнопку больше настроек. Не пугаемся. Вспоминаем номер порта, у меня это был порт номер 5, и указываем его. Далее в программе есть несколько методов захвата изображения, из них у меня работают вроде бы первые 6, можете их все потыкать посомтреть посмотреть какой будет меньше тормозить. Но. Все методы кроме GDI FS Aero включают классическую тему оформления виндоус, то есть без прозрачных окошек, они даже подписаны no aero. Я люблю прозрачные окошки так что оставил аэро. Теперь нажимаем показать зоны захвата и видим, что они не настроены. Зон должно быть столько же, сколько у вас светодиодов. 98. Оп, перезагрузилась. Теперь жмём мастера настрйоки зон. Я наклеивал ленту так, что она получилась без угловых светодиодов, ставлю галочку. Далее, по горизонтали у меня 31 светодиод, ориентироваться нужно не на это число, а сразу смотреть вниз на зоны. Соотношение сторон определяется автоматически, но я на всякий случай поставил как у своего монитора, 16 на 9. И ещё можно удлинить зоны, чтобы они брали источник цвета с большей площади, так результат будет более симпатичным. Ну и всё. Сохраняем настрйоки и ставим галку включить подсветку. Тадаааам. Поздравляю, теперь у нас есть динамическая подсветка монитора. С режимом виндоус аэро наблюдается небольшая задержка, в других режимах без аэро задержки почти нет. В папке с картинками для тестов вы найдёте несколько сочных картинок для проверки вашей фоновой подсветки.
Рекомендую попробовать программу Adalight EtVersion, вот отсюда
ОШИБКИ И FAQ
Может случиться так, что при работе от USB компьютер не выключается, пока не будет извлечён штекер, ведущий к Arduino
Ответы на большинство вопросов можно найти здесь: https://alexgyver.ru/ws2812_guide/
В: Я купил ленту, на ней контакты G R B 12V. Как подключить?
О: Молодец, можешь кинуть ей в собаку. Это не та лента.
В: Не работает! Какие есть типичные ошибки?
О: Скорее всего в подключении. В основном забывают объединить GND ленты и GND Ардуины.
ПОДДЕРЖАТЬ
Вы можете поддержать меня за создание доступных проектов с открытым исходным кодом, полный список реквизитов есть вот здесь .
