Ambilight подсветка телевизора своими руками

Для своей первой статьи я выбрал одну из самых успешных своих поделок: HDMI-passthrough аналог Ambilight от Philips, далее я будут называть эту композицию «Атмосвет».

Введение

В интернетах не очень сложно найти готовые/открытые решения и статьи как сделать Амбилайт для монитора/телевизора, если ты выводишь картинку с ПК. Но в моей мультимедиа системе вывод картинки на телевизор c ПК занимает только 5% времени использования, большее кол-во времени я играю с игровых консолей, а значит нужно было придумать что-то свое.

Исходные данные:
  • 60″ Плазменный телевизор
  • HTPC на базе Asrock Vision 3D 137B
  • Xbox 360
  • PS3
  • PS4
  • WiiU
Требование:

Необходимо обеспечить централизованную поддержку Атмосвета для всех устройств подключенных к телевизору.

Реализация

Я не буду рассказывать, как я прикреплял 4.5м светодиодную ленту к телевизору и что нужно сделать с Arduino, в качестве базы можно использовать эту статью.

ПОДСТВЕТКА ambilight своими руками с АЛИ ЭКСПРЕСС

Единственный нюанс:
Я заметил, что внизу экрана идут странные мерцания, сначала погрешил на сигнал, перековырял дефликер, изменил ресазинг картинки и еще кучу всего перекопал, стало лучше, но от мерцания не помогло. Стал наблюдать. Оказалось, что мерцание было только в конце ленты и то при ярких сценах. Взяв мультиметр, я замерил напряжение на начале, середине и конце ленты и угадал с причиной мерцаний: в начале ленты было 4.9В( да китайский БП дает напряжение с отклонением, это не существенно), в середине 4.5 в конце 4.22 — Падение напряжение слишком существенно, пришлось решить проблему просто — к середине ленты я подвел питание от бп, провод пустил за телевизором. Помогло мгновенно, какие либо мерцания прекратились вообще.

Захватываем картинку вебкамерой

image

Первая тестовая версия для обкатки идеи и её визуализации была выбрана через захват картинки через вебкамеру) выглядело это как-то так:

Низкая цветопередача и высокий 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. Кроп фрейма, для исключения черных полос


Тут все просто:

frame.ROI = new Rectangle(8, 8, frame.Width — 8, frame.Height — 18 — 8);

Обрезаем 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), если порог преодолевается, то производится сброс окна, без модификации.
Немного модифицированный (для читаемости вне контекста) код моего дефликера:

Array.Copy(_leds, _ledsOld, _leds.Length); for (var i = 0; i < _leds.Length; i++) < double lumSum = 0; // Calculate the luminance of the current led. lumSum += _leds[i].R*_leds[i].R; lumSum += _leds[i].G*_leds[i].G; lumSum += _leds[i].B*_leds[i].B; lumSum = Math.Sqrt(lumSum); // Do led processing var avgLum = 0.0; for (var j = 0; j < LedLumWindow; j++) < avgLum += _lumData[j, i]; >var avg = avgLum/LedLumWindow; var ledChange = false; if (_strengthcutoff < 256 _lumData[0, i] != 256 Math.Abs((int) lumSum — avg) >= _strengthcutoff) < _lumData[0, i] = 256; ledChange = true; >// Calculate the adjustment factor for the current led. var scale = 1.0; int r, g, b; if (ledChange) < for (var j = 0; j < LedLumWindow; j++) < _lumData[j, i] = (int) lumSum; >> else < for (var j = 0; j < LedLumWindow — 1; j++) < _lumData[j, i] = _lumData[j + 1, i]; >_lumData[LedLumWindow — 1, i] = (int) lumSum; if (lumSum > 0) < scale = 1.0f/((avg+lumSum)/2); var filt = 0.0f; for (var j = 0; j < LedLumWindow; j++) < filt += (float) _lumData[j, i]/LedLumWindow; >scale *= filt; > // Adjust the current Led. r = _leds[i].R; g = _leds[i].G; b = _leds[i].B; // save source values var sr = r; var sg = g; var sb = b; var max = r; if (g > max) max = g; if (b > max) max = b; double s; if (scale*max > 255) s = 255.0/max; else s = scale; r = (int) (s*r); g = (int) (s*g); b = (int) (s*b); // keep highlight double k; if (sr > _lv) < k = (sr — _lv)/(double) (255 — _lv); r = (int) ((k*sr) + ((1.0 — k)*r)); >if (sg > _lv) < k = (sg — _lv)/(double) (255 — _lv); g = (int) ((k*sg) + ((1.0 — k)*g)); >if (sb > _lv) < k = (sb — _lv)/(double) (255 — _lv); b = (int) ((k*sb) + ((1.0 — k)*b)); >_leds[i] = Color.FromArgb(r, g, b); > /* Temporal softening phase. */ if (ledChange || _softening == 0) continue; var diffR = Math.Abs(_leds[i].R — _ledsOld[i].R); var diffG = Math.Abs(_leds[i].G — _ledsOld[i].G); var diffB = Math.Abs(_leds[i].B — _ledsOld[i].B); r = _leds[i].R; g = _leds[i].G; b = _leds[i].B; int sum; if (diffR < _softening) < if (diffR >(_softening >> 1)) < sum = _leds[i].R + _leds[i].R + _ledsOld[i].R; r = sum/3; >> if (diffG < _softening) < if (diffG >(_softening >> 1)) < sum = _leds[i].G + _leds[i].G + _ledsOld[i].G; g = sum/3; >> if (diffB < _softening) < if (diffB >(_softening >> 1)) < sum = _leds[i].B + _leds[i].B + _ledsOld[i].B; b = sum/3; >> _leds[i] = Color.FromArgb(r, g, b); >

Пусть _leds — массив светодиодов класса Color, _ledsOld — значения кадра до конвертации, LedLumWindow — ширина окна предыдущих кадров, для оценки среднего изменения интенсивности, в конечном сетапе окно у меня было 100, что примерно при 30кад/с равняется 3-секундам. _lumData — массив значения интенсивности предыдущих кадров.

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

8. Сглаживание светодиодов по соседям.

Вообще в конечном сетапе, сглаживание мне не очень понравилось, и я его отключил, но в некоторых случаях может пригодиться. Тут мы просто усредняем цвет каждого светодиода по его соседним.

Еще по теме:  Ultra hd 4K LED телевизор 58 telefunken tf led58s01t2su обзор

var smothDiameter = 2*_smoothRadius + 1; Array.Copy(_leds, _ledsOld, _leds.Length); for (var i = 0; i < _ledsOld.Length; i++) < var r = 0; var g = 0; var b = 0; for (var rad = -_smoothRadius; rad else if (pos > _ledsOld.Length — 1) < pos = pos — _ledsOld.Length; >r += _ledsOld[pos].R; g += _ledsOld[pos].G; b += _ledsOld[pos].B; > _leds[i] = Color.FromArgb(r/smothDiameter, g/smothDiameter, b/smothDiameter); >

9. Сохраняем текущий стейт, чтобы тред отправки пакетов схватил и отправил его на контроллер подсветки.

Я умышленно разделил процесс обработки кадров и отправки пакетов на контроллер: пакеты отправляются раз в определенный интервал(у меня это 40мс), чтобы ардуино спела обработать предыдущий, ибо чаще чем 30мс она захлебывается, таким образом выходит, что мы не зависим напрямую от частоты кадров захвата и не мешаем тому процессу(а ведь отправка пакета тоже тратит время).

Немного про ардуино

Нельзя просто так взять и отправить по сериалу здоровенный пакет на ардуино, ибо онв ыйдет за пределы дефолтного буфера HardwareSerial и ты потеряешь его конец.
Решается это довольно просто: выставляем значение размера буфера HardwareSerial достаточного размера, чтобы влезал весь отправляемый пакет с массивом цветов, для меня это 410.

UI

image

Сам софт был реализован в виде 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.

Спасибо за внимание, очень надеюсь, что кому-нибудь моя статья поможет.

Источник: habr.com

Ambilight своими руками

Ниже представлен проект изготовления подсветки Ambilight для телевизора или монитора. В предыдущей статье «Динамическая подсветка ТВ» использовался простой подход с использованием четырех RGB светодиодных лент, что позволяло отображать на каждой стороне ТВ только один цвет.
В данном статье мы усовершенствуем нашу подсветку, использовав для этого RGB LED пиксели, которые позволяют управлять каждым RGB-светодиодом. Подробнее читайте здесь: RGB LED Pixels.

Итак, что нам понадобится:
— лента цифровых RGB LED Pixels на основе нового контроллера WS2801. Одной такой ленты (25 светодиодов) вполне хватит на обычный среднестатический монитор. Расстояние между RGB-модулями около 10 см. Для большого телевизора могут понадобиться 2 такие ленты
— стабилизированный источник питания 5В для питания RGB LED. Максимальный ток БП нужно подбирать исходя из энергопотребления RGB LED модулей. Если будет использоваться одна лента (25 RGB LED), то ток БП нужен 1.5А, если 2 ленты, то соответственно 3А.
— контроллер Arduino, разъемы и др. мелочи. Монтаж Для облегчения подключения к Arduino и БП с лентой были произведены небольшие доработки. Для линии data и clock ленты, были припаяны соединительные коннекторы, чтобы их можно было надежно вставить в разъемы Arduino. Для подключения блока питания припаяли разъем. От разъема, к Arduino припаяли общую «землю».

На фото ниже я думаю все вполне понятно: Подпаиваем разъемыВ Arduino 13-ый пин использовался для clock, а 11-ый пин для data. Плюс, не забудьте «землю». Теперь, надо определиться как будет все это крепиться на задней стенке телевизора или монитора.

Здесь вариантов много, и можно тупо прикрепить светодиоды скотчем сзади монитора, а можно вырезать красивый шаблон или оргстекла. Наш шаблон бы сделан из тонкого пластика, со всеми необходимыми вырезами под монитор и крепления: ШаблонЗатем, необходимо равномерно расположить 25 LED RGB светодиодов.

У меня вышло расстояние между светодиодами около 50мм. Закрепляем RGB LEDКогда будете изготавливать шаблон, не закрывайте вентиляционные отверстия на мониторе, если таковые имеются. После того, как все RGB LED пиксели закреплены, осталось прикрепить контроллер Arduino. Для этих целей лучше всего подойдет двухсторонний скотч.

Подсоединяем USB кабель к Arduino и источник питания 5В к RGB LED ленте. Подсоединение ArduinoПрограммное обеспечение Все необходимое ПО вы можете скачать с GitHub. В папке Arduino->LEDstream находится скетч для Arduino. Скомпилируйте его и загрузите в контроллер.

Для компьютера используется ПО под Processing IDE, который необходимо скачать и установить отдельно (не путать с Arduino Processing!). Если в вашей конфигурации не 25 RGB LED, то в скетч необходимо будет внести изменения. Также, необходимо выбрать COM-порт, к которому подключен контроллер Arduino, чтобы передавать данные (см. скриншот ниже).

Подсоединение ArduinoПрограмма работает следующим образом: после запуска, программа работает в фоновом режиме и постоянно делает скриншоты экрана и анализирует цвета отдельных точек по периметру. Потом вычисляет среднее цвета для точек и передает данные в контроллер Arduino. И не важно, что запущенно на компьютере — медиаплеер, браузер с роликом с youtube или еще что-то. Подсоединение Arduino

Код программы рассматривать не будем, т.к. он хорошо комментирован. Кстати в папке Colorswirl находится небольшой пример демо-скетча, который выводит на RGB светодиоды радугу.
Некоторое старое железо, может не справиться с нагрузкой (к примеру первые Atom’ы на нетбуках), т.к. постоянно делаются скриншоты. В этом случае может помочь уменьшение разрешения, к примеру 800х600. Оригинал статьи

Еще по теме:  Как заменить HDMI разъем на телевизоре

Теги:

Колтыков А.В. Опубликована: 2011 г. 0 0

Вознаградить Я собрал 0 0

Источник: cxem.net

Ambientlight подсветка своими руками

На картинке изображен наш 40” телевизор с Ambientlight подсветкой, сделанной собственными руками. Подсветку по трем сторонам обеспечивают 50 светодиодов, которые управляются при помощи платы Arduino. Что касается программного обеспечения, то работает подсветка при помощи ПО Ambibox и библиотеки FastLED для Arduino.

Материалы

  • 50 светодиодов WS2811;
  • Плата Arduino Nano;
  • Источник питания.

Предупреждение!

Данный проект очень дешев, но работает только при помощи ПК. Вы не сможете использовать данный проект на автономном ТВ, так как для его работы необходимо ПО, работающее в фоновом режиме на ПК.

Linux или Mac не поддерживается. Программное обеспечение Ambibox доступно только на Windows.

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

Необходимые светодиоды

Светодиоды являются одной из самых важных частей нашего проекта. Но какие именно светодиоды вы будете использовать – не столь важно. Главное, чтобы они поддерживались библиотекой FastLed.

Наиболее распространенными являются светодиоды WS2811 или WS2812, так как они дешевы и достаточно просты в использовании. Можно использовать как отдельные светодиоды, так и светодиодные ленты.

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

Теперь необходимо рассчитать количество необходимых светодиодов. Мы использовали шаг в 30мм между светодиодами. При такой расстановке 50 светодиодов хватает для четырехстороннего расположения на 27” экране или трехстороннего на 40”.

Рамка для светодиодов

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

Для создания рамки мы выбрали алюминий. Необходимо вырезать три полосы по размеру экрана и собрать их воедино. Напомню, что в нашем случае будет использоваться трехсторонняя подсветка, так как ТВ стоит на столе. Если же в вашем случае ТВ закреплен на стене, лучше использовать подсветку по всем четырем сторонам.

Arduino Nano

Для управления светодиодами нужен контроллер. Именно в этой роли и выступает плата Arduino Nano. Для подключения нам понадобится разъем USB, один цифровой контакт и заземление.

Питание

Для работы светодиодов необходимо подать на них питание. Обычно это 5V. Лучше всего купить отдельный блок питания, который будет подходить по мощности. Можно конечно использовать 5V, от блока питания на ПК, но этот вариант намного сложней и требует определенных знаний и опыта. Поэтому я его не советую.

Подключение

Если вы используете светодиоды WS2811/12, вам необходимо произвести всего 3 соединения.

  1. 5V от источника питания подключить к соответствующей 5V линии на светодиодах;
  2. Соединить GND БП с землей на светодиодах и плате Arduino Nano;
  3. Подключить светодиоды к одному из цифровых выходов на плате.

ПО для Arduino Nano

Первым делом необходимо установить библиотеку http://fastled.io/.

Код можно написать самостоятельно или же использовать готовый.

Возможно вам будет необходимо изменить некоторые данные кода:

  • NUM_LEDS, установить по количеству используемых светодиодов;
  • DATA_PIN, установить в зависимости от тогоЖ какой цифровой порт был использован;
  • SerialRate, определяет скорость светодиодов (500000 максимум).

ПО Ambibox для Windows

Данное ПО является бесплатным и его можно без проблем скачать с сайта производителя.

После установки следует изменить один файл. Путь: C: Program Files (x86) AmbiBox SerialPortConfig.ini. Изменяем скорость передачи данных на «Adalight 50000». Так как нам нужны одинаковые значения и в коде Arduino, и здесь. После изменения сохраняем файл и перезапускаем программу.

Основные настройки

Самые важные для нас настройки находятся в графе «Дополнительных настроек». Здесь мы устанавливаем количество светодиодов и другие основные параметры.

  • F7 – наша горячая клавиша для включения/отключения светодиодов;
  • Использовать разные профили нет необходимости, поэтому выбираем Default;
  • Mode – переключает режим работы светодиодов. Для тестирования лучше выбрать статичный цвет. Если все диоды корректно работают, устанавливаем захват изображения с Win 8. Данная программа корректно работает, начиная с ОС Win 7 и до Win 10;
  • Также следует установить минимальную задержку и максимальный Fps, для достижения лучшей синхронизации.

Область захвата

Как несложно догадаться, здесь мы выбираем область экрана для захвата изображения. Нам необходимо захватить весь экран, поэтому выбираем «Wizard capture zones» и выделяем весь экран. Далее сохраняем и закрываем настройки.

Ну вот и все! Наша подсветка полностью готова!

Статья является авторским переводом с сайта instructables.com.

Данная статья является собственностью Amperkot.ru. При перепечатке данного материала активная ссылка на первоисточник, не закрытая для индексации поисковыми системами, обязательна.

Источник: amperkot.ru

Оцените статью
Добавить комментарий