Аппаратный ЭЛТ-фильтр для картинок

q9a8dslttmbpxjznmlvdj5kzlvg.jpeg


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

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

Как вы понимаете, этот проект — самый эпичный долгострой в моей жизни, раз я задумал его ещё в конце 2000-х. Где-то примерно в году 2015 он работал для друзей, и даже в 2016 году он ездил на Chaos Construction. Но это всё было не то, интерфейсы не те. И вот, наконец проект завершён, и может быть показан широкому зрителю.

А прежде, чем вы залезете под кат, можно сразу попробовать отфильтровать картинку — достаточно просто зайти в наш телеграмм бот. 

Поехали, ниже много аппаратной жести.

Концепция


Идея достаточно проста, родилась она в то время, когда автоматическая обработка фотографий только набирала обороты, и всякие аппаратные решения могли бы быть достаточно забавными.

На чёрно-белый ЭЛТ-монитор выводится картинка, затем фотографируется камерой, а дальше уже сводятся цвета.

Вообще, те, кто давно следят за моим творчеством, могут сопоставить несколько статей по данной теме. Например, когда я искал монитор, то в качестве него хотел использовать видоискатель от старой видеокамеры. Так получилась статья «Мини ЭЛТ монитор». Но, к сожалению, экран от видеокамеры оказался слишком мал для таких целей. Поэтому, в дальнейшем, я приобрёл небольшой чёрно-белый охранный монитор, который был больше по размерам и оказался намного более удобным для моей задачи. 

4grupcczeluk2sr1-8tbkitk1x0.jpeg

Охранный монитор «Topica TP-098»

В процессе экспериментов я подбирал различные камеры. Вообще, хотел использовать зеркальный фотоаппарат и даже пробовал его подключать. Это вы читали в статье «Старый фотик + bash = таймлапс». К сожалению, из-за малого ресурса, а также всяких аппаратных косяков — решил отказаться от этого варианта. Остановился на Raspberry Pi и малиновой камере.

От идеи до готового прототипа


k-ppdny0eu3nh8j_jtgubh9j3j0.jpeg

Внешний вид первого работающего прототипа (2016 г.)

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

  1. Быть закрытым, чтобы не было бликов на мониторе.
  2. Быть носимым, чтобы можно было перемещать по квартире.
  3. В нём должна обеспечиваться достаточная вентиляция, чтобы монитор не перегревался.
  4. Необходимо иметь возможность в широких пределах менять месторасположение камеры и жёстко её фиксировать.


▍ Фанерный ящик


Первое, что было изготовлено — это фанерный ящик. Тут никаких хитростей нет, разве что съёмная боковая и верхняя крышка. Для уменьшения бликов изнутри был окрашен чёрной тушью. Это было сделано по неопытности, идеальная краска, с хорошим светопоглащением, доступная в любом магазине — это акриловая газовая сажа.

Ящик не так прост, как кажется на первый взгляд. Как я уже сказал, необходимо обеспечить охлаждение, поэтому ящик располагается на ножках, которые просто вырезаны из той же фанеры, с набойкой из войлока. Это нужно, чтобы снизу было пространство для движения воздуха. В месте установки монитора — сделаны отверстия воздухозабора (там же, где они у самого монитора) и отверстия под его ножки. Для удобства подключения — сзади установлена обычная розетка, куда подключается монитор и блок питания одноплатника.

mmnv2ik7u5-hd-rj15nxfofghae.jpeg

Отверстия воздухозабора и под ножки

inkunnelc0si0w0lg6ym4dewva8.jpeg

Дополнительная розетка питания сзади

Для того чтобы камеру точно можно было позиционировать внутри, и она не сдвигалась в процессе эксплуатации, внутри решено было сделать деревянные рельсы. Изначально попробовал посмотреть, как это будет выглядеть из бросового материала — утеплителя.

wf3jexer16amncgycuhuqesult4.jpeg


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

qygwzj76b2-l9a0eke3fei4stmi.jpeg

Готовые рельсы из соснового щита

Когда стало понятно, что это крепление наиболее оптимально, я выпилил все необходимые детали на лобзиковом станке для установки болтов. Они нужны для регулировки высоты и наклона камеры. Прорезь нужна, чтобы можно было смещать камеру поперёк оси. Не знаю, как корректно именовать этот элемент, назову суппортом.

xhlc7tobe-iam2crtcbtemwimvi.jpeg


unj5drsz05v2pn1wvd9hqf5ijny.jpeg

Готовый суппорт

В результате всех примерок и перестановок получился следующий готовый прототип.

g0aora0xvuquuxrsxnnobwidpiw.jpeg


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

▍ Окончательная сборка


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

Мозгами всего устройства выступает Raspberry Pi 4, для камеры взял устаревший модуль V2. Поскольку всё работает в закрытом корпусе, для лучшего охлаждения одноплатника приобрёл дополнительный корпус-радиатор с вентиляторами.

e2q2tz9dmxmdj4qawc5c0yhsvjk.jpeg

Исходники в коробочках

После чего всё примеряю по месту и думаю об оптимальном расположении элементов.

lkb3vin2lykvwsprsm12das7w_y.jpeg

Примерка

Самое сложное было сделать крепление камеры. Необходимо было обеспечить жёсткость крепления так, чтобы камера не болталась и не дрожала. Перепробовал несколько вариантов, самым оптимальным оказалось крепление на винтах М2, между гаек.

e5rugfebmbjg1gxys4dllzbhnbe.jpeg

Крепление камеры

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

e0msebq4yck6v9zzflid9nmq6dk.jpeg

Окраска

После всех манипуляций эмпирическим путём было установлено, что совсем без света в ящике нельзя. Потому что не будет видно стильную рамку самого монитора. А самое главное, камера будет постоянно настраивать отдельную яркость под каждую картинку и картинка будет получаться неодинаковой освещённости. Поэтому внутрь установил световое кольцо, и на заднюю стенку поставил лист обычной бумаги. Между кольцом и суппортом проложил лист бумаги, покрашенный чёрной краской, чтобы не было засветов снизу, и не сияли металлические болты в кадре.

holl5lqtzhhcrztm3cphnkxuqyc.jpeg

Дополнительный свет

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

Всё укомплектовано, засветов лишних практически нет. Теперь всё готово к настройке и разработке софта.

_sfbebpx6cb-n0msi3kajzind2w.jpeg

Готовый ящик

vkvzqgogrqdhpkft8lbuazqpn64.jpeg

Ящик с закрытой крышкой

Настройка и разработка софта


Самая сложная часть — это не собрать ящик, хоть эта часть выглядит круто и понятна каждому. Самая сложная и скрытная часть — это настроить всё, и разработать ПО.

▍ Корректная установка камеры


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

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

p3efbzhtjicufcd6rcsinxcrodq.jpeg

Настройка положения камеры в далёком 2016 году

Сейчас такими глупостями заниматься я не стал, потому что ни телевизора, ни плеера у меня уже нет. Поступил сильно проще, я открыл документацию на камеру для малины. И просто сделал трансляцию того, что она выводит в VLC. Главное поставить разрешение поменьше, а с помощью fbi (Linux framebuffer imageviewer) выводил на экран обычную настроечную таблицу для чёрно-белых телевизоров и старался, чтобы она хоть как-то совпадала с тем, что я должен увидеть.

v1qhvlyrpgzq5hjdetaazl0bnui.png

Настроечная таблица чёрно-белых телевизоров

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

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

dqnthzlq5h-klg1jabkww1vq0uy.jpeg

Успешный вывод настроечной таблицы

▍ Позвольте, а откуда цвет?


Внимательный читатель заметил, что в своём проекте я использую чёрно-белый монитор. Можно даже потрудиться, найти на него документацию и убедиться, что цвет он выводить не умеет. Но как же можно получить цветное изображение?

Всё просто, берётся цветная картинка, например:

qb3e7hyeijwdpkwdxv_otdgoefk.png


И разделяется на три канала по цветам (делается это программно). 

85y_ylhp93bzuxwr4vhjm3kgk1m.png

Три отдельных картинки с каждым цветом

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

zco41xw6ollsz6zyb4xzndq_jkc.png

Реальные фотографии с монитора

После чего, все три кадра снова сводятся единую фотографию и получается снова цветное изображение.

i8eq9ohjdq5alfwwnjori-ohdsc.png

Изображение, полученное с монитора

Виден засвет тёмной области, это именно та проблема, которая возникает в абсолютно тёмном ящике. Поэтому и нужен контр-свет.

▍ Разработка софта. Серверная часть


В первоначальном прототипе у меня был вебсайт, где всё работало через CGI. Но это было не самый удобный вариант и по многим параметрам он мне не нравиося. Поэтому было принято волевое решение шагать в ногу со временем и сделать telegram-бота. Сам бот — это для меня запредельная магия (шучу), я потыкал в него палочкой и не смог реализовать. Поэтому слёзно просил помочь мне его сделать man_of_letters. О подобном боте у нас есть отличная статья «Проект — электрический помощник для редакции». С небольшими изменениями из него получился бот для получения и отдачи фотографий пользователю. Более подробно рассказать не смогу, потому что сильно код бота не ковырял.

API работы устроено достаточно просто:

  1. Бот принимает картинку от пользователя, шинкует её на три канала цвета RGB и сохраняет картинки в png с соответствующими именами.
  2. После успешной шинковки создаёт просто пустой файл, с именем трёх файлов. Создание этого файла и имя файла является ключём для того, чтобы начать обработку.
  3. После того как моё устройство заберёт эти файлы, перемолет их, а далее складывает обратно — все три обработанных файла в другую папку. Бот их сводит и отдаёт клиенту. 


Итого, у меня три папки, которые и являются API для взаимодействия с ботом. Для работы с ними решили использовать протокол ssh, потому что это удобно, надёжно и просто. Как же я ошибался…

▍ Клиентская часть


Главной проблемой работы по ssh — это держать постоянное подключение. И оказалось, что при длительном соединении постоянно «лопалась труба» (ошибка broken pipe).

aaegvlc_qo8v3gw5tmauwp2n5m0.jpeg


Лопнувшие трубы ssh соединения сильно портили малину, и порой даже бились данные. Решила эти проблемы следующая статья. Но, изначальный сервер у нас был на Debian, любезно предоставленный компанией RuVDS, а там этот фокус вообще чуть не погасил весь ssh. Поэтому в срочном порядке пришлось переехать на сервер с Ubuntu 20.04. Для наших задач хватит самой простецкой конфигурации.

Далее там создаём файл:

sudo vim /etc/ssh/sshd_config.d/alive.conf


И добавляем туда следующие строки:

ClientAliveInterval 30
ClientAliveCountMax 30
TCPKeepAlive no


И не забываем перезапустить sshd-демон:

sudo systemctl restart ssh


Теперь возникает другой вопрос: как на стороне клиента aka Raspberry Pi мониторить создание файла на удалённом сервере?

Изначально для этих целей я использовал приложение inotifywait и отслеживал создание новых файлов, вот такой совершенно страшной конструкцией и далее в теле while уже делал все свои грязные дела:

ssh teleuser@$server inotifywait -e create /****/workaround --format "%f" -q -m| while read file; do
...


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

ssh teleuser@$server inotifywait -e create /****/workaround --format "%f" -q -m| while read file; do


Вывод на экран делаю в консольном режиме, используя стандартную программу вывода во фреймбуффер:

sudo fbi -T 2  --nocomments --noverbose -a /***/hipcrt/${file%.*}$num.png


Самое сложное было разобраться с тем, как это фотографировать. Когда-то, давным-давно, я использовал приложение raspistill, но с тех пор много воды утекло и появилось другое приложение.

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

jdkpzt51zyciv-v3tzuqlwoabhk.jpeg


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

В результате после небольшого НИР получилась следующая команда:

libcamera-still -n --width 800 --height 600 -o /****/hipcrt/result/${file%.*}$num.jpg -e jpg --shutter 125000 -t 500 --awb fluorescent


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

#!/bin/bash
server=***.***.***.***

while true
do
	sleep 0.1
		ssh teleuser@$server ls -1tr  /*****/workaround |  while read file; do
		scp teleuser@$server:/*****/pic_from_user_split/${file%.*}*  /*****/hipcrt/
		ssh teleuser@$server rm -f /*****/workaround/$file
		ssh teleuser@$server rm -f /*****/pic_from_user/${file%.*}*
		ssh teleuser@$server rm -f /*****/pic_from_user_split/${file%.*}*
		for num in "_r" "_b" "_g"
		do
			sudo fbi -T 2  --nocomments --noverbose -a /*****/hipcrt/${file%.*}$num.png
			sleep 0.5
			sudo libcamera-still -n --width 800 --height 600 -o /*****/hipcrt/result/${file%.*}$num.jpg -e jpg --shutter 125000 -t 500 --awb fluorescent
		done
		sudo killall fbi
		scp /*****/hipcrt/result/${file%.*}* teleuser@$server:/*****/pic_from_crt/
		rm -f /*****/hipcrt/*.png /*****/hipcrt/result/*
	done 
done
exit 0


На самом деле, я как-то так легко и просто всё расписал, но в реальности — вся эта куча экспериментов и опытов вылилась в недели работы, потому что было неясно, где и что отваливается.

Так, и где же я могу всё это попробовать?


gl3xas698srj5xx3ji-7whghn_k.jpeg

Рекурсивная фотография аппаратного ЭЛТ-фильтра, обработанная на аппаратном ЭЛТ-фильтре

Хочется уже попробовать, правда? Такая краткая инструкция для начинающих:

  • Бот обитает по следующему адресу.
  • Заходим в него и жмём «запустить».
  • После этого у вас появится меню.
  • Выбираем «Обработать новое изображение» и скармливаем любой графический файл со сжатием.


После этого ваше изображение добавляется в очередь. Обработка каждого изображения занимает 15 секунд, поэтому из-за хабраэффекта, пожалуйста, соблюдайте терпение, все получат свои картинки рано или поздно. С телефона всё выглядит вот так.

yz-fz_u_ea-2igenwffuajdb9ss.jpeg


jrsculjdveqr1dv9cgnmm54myii.jpeg


Чтобы канал не забил один крепкий кликер фоток — там стоит антиспам, ограничивающий количество фотографий от одного человека. Так что выбирайте фотографии лучше.

Заключение


smoiliqgblovhusgvv7lcuuy4fi.jpeg


В моей жизни — этот проект самый эпичный долгострой, который всё же был реализован и доведён до конца. Проект меня многому научил. Когда я делал сайт, то впервые вообще столкнулся с js, php и вообще web-программированием, CGI вообще был для меня пустым звуком, а ещё разработка своих скриптов… Всё это стало для меня замечательным опытом и дало весьма неплохой навык, который пригодился в моей дальнейшей работе.

Да, сам проект может быть глупым и абсурдным, но лично меня он научил очень многому, и я благодарен, что он состоялся.

Главное я благодарен всем моим друзьям, которые мне помогали с этим проектом. Не буду перечислять всех по именам, вы все молодцы. Громадное спасибо man_of_letters за помощь с сайтом в начале пути, и за помощь с ботом в завершении проекта. Компании RuVDS за помощь в подготовке этого проекта.

А главное, вам мои дорогие читатели, за то, что будете его использовать и понимать что это просто прикольно!

HIPCRT_BOT

И напоследок, вот видео, которое изготовлено на этом аппарате. Понадобился день, чтобы обработать все кадры этого короткого видеоролика.


З.Ы. Если всё будет хорошо, постараюсь чтобы аппаратная часть проработала не меньше месяца!

RUVDS | Community в telegram и уютный чат

sz7jpfj8i1pa6ocj-eia09dev4q.png

© Habrahabr.ru