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

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

Сразу стало понятно, что для реализации всей задумки, мне понадобится готовый стенд. Он должен удовлетворять следующим параметрам:
- Быть закрытым, чтобы не было бликов на мониторе.
- Быть носимым, чтобы можно было перемещать по квартире.
- В нём должна обеспечиваться достаточная вентиляция, чтобы монитор не перегревался.
- Необходимо иметь возможность в широких пределах менять месторасположение камеры и жёстко её фиксировать.
▍ Фанерный ящик
Первое, что было изготовлено — это фанерный ящик. Тут никаких хитростей нет, разве что съёмная боковая и верхняя крышка. Для уменьшения бликов изнутри был окрашен чёрной тушью. Это было сделано по неопытности, идеальная краска, с хорошим светопоглащением, доступная в любом магазине — это акриловая газовая сажа.
Ящик не так прост, как кажется на первый взгляд. Как я уже сказал, необходимо обеспечить охлаждение, поэтому ящик располагается на ножках, которые просто вырезаны из той же фанеры, с набойкой из войлока. Это нужно, чтобы снизу было пространство для движения воздуха. В месте установки монитора — сделаны отверстия воздухозабора (там же, где они у самого монитора) и отверстия под его ножки. Для удобства подключения — сзади установлена обычная розетка, куда подключается монитор и блок питания одноплатника.


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

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

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


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

На фотографии не видно, но суппорт прижимается к рельсам с помощью барашка. Это оказалось не очень удобно, и дальше я решил сделать фанерный диск с запрессованной гайкой.
▍ Окончательная сборка
Поскольку проект растянулся на много лет, и описать все события с ним, в рамках одной статьи, невозможно, основной акцент я дам только на последних изменениях. Аппаратные решения минувшего прошлого я просто не помню, всё это было утрачено в веках.
Мозгами всего устройства выступает Raspberry Pi 4, для камеры взял устаревший модуль V2. Поскольку всё работает в закрытом корпусе, для лучшего охлаждения одноплатника приобрёл дополнительный корпус-радиатор с вентиляторами.

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

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

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

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

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


Настройка и разработка софта
Самая сложная часть — это не собрать ящик, хоть эта часть выглядит круто и понятна каждому. Самая сложная и скрытная часть — это настроить всё, и разработать ПО.
▍ Корректная установка камеры
Для меня это самая муторная задача, потому что надо в течение нескольких часов двигать суппорт и крутить винты. И да, я до сих пор недоволен идеальностью выставленной камеры.
В первый раз я выставлял камеру достаточно хитрым способом: скачал на DVD-диск специальные настроечные таблицы и выводил с помощью проигрывателя эти таблицы на монитор, а на телевизор выводил результат того, что снимает камера.

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

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

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

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

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

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

Виден засвет тёмной области, это именно та проблема, которая возникает в абсолютно тёмном ящике. Поэтому и нужен контр-свет.
▍ Разработка софта. Серверная часть
В первоначальном прототипе у меня был вебсайт, где всё работало через CGI. Но это было не самый удобный вариант и по многим параметрам он мне не нравится. Поэтому было принято волевое решение шагать в ногу со временем и сделать telegram-бота. Сам бот — это для меня запредельная магия (шучу), я потыкал в него палочкой и не смог реализовать. Поэтому слёзно просил помочь мне его сделать man_of_letters. О подобном боте у нас есть отличная статья «Проект — электрический помощник для редакции». С небольшими изменениями из него получился бот для получения и отдачи фотографий пользователю. Более подробно рассказать не смогу, потому что сильно код бота не ковырял.
API работы устроено достаточно просто:
- Бот принимает картинку от пользователя, шинкует её на три канала цвета RGB и сохраняет картинки в png с соответствующими именами.
- После успешной шинковки создаёт просто пустой файл, с именем трёх файлов. Создание этого файла и имя файла является ключём для того, чтобы начать обработку.
- После того как моё устройство заберёт эти файлы, перемелет их, а далее складывает обратно — все три обработанных файла в другую папку. Бот их сводит и отдаёт клиенту.
Итого, у меня три папки, которые и являются API для взаимодействия с ботом. Для работы с ними решили использовать протокол ssh, потому что это удобно, надёжно и просто. Как же я ошибался…
▍ Клиентская часть
Основная проблема работы по ssh — это держать постоянное подключение. И оказалось, что при длительном соединении постоянно «лопалась труба» (ошибка broken pipe).

Лопнувшие трубы 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 ls -1tr /*****/workaround | while read file; do
Вывод на экран делаю в консольном режиме, используя стандартную программу вывода во фреймбуффер:
sudo fbi -T 2 --nocomments --noverbose -a /***/hipcrt/${file%.*}$num.png
Самое сложное было разобраться с тем, как это фотографировать. Когда-то, давным-давно, я использовал приложение raspistill, но с тех пор много воды утекло и появилось другое приложение.
Необходимо было подобрать оптимальное разрешение, чтобы было всё чётко видно, и не занимало много места, и настроить выдержку с таким параметром, чтобы картинка успела отрисоваться вся, и при этом не было пересвета и баланс белого.

Пример неудачно подобранной выдержки, когда идут разноцветные полосы из-за того, что кадр не успел отрисоваться весь.
В результате после небольшого НИР получилась следующая команда:
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
На самом деле, я как-то так легко и просто всё расписал, но в реальности — вся эта куча экспериментов и опытов вылилась в недели работы, потому что было неясно, где и что отваливается.
Так, и где же я могу всё это попробовать?

Хочется уже попробовать, правда? Такая краткая инструкция для начинающих:
- Бот обитает по следующему адресу.
- Заходим в него и жмём «запустить».
- После этого у вас появится меню.
- Выбираем «Обработать новое изображение» и скармливаем любой графический файл со сжатием.
После этого ваше изображение добавляется в очередь. Обработка каждого изображения занимает 15 секунд, поэтому из-за хабраэффекта, пожалуйста, соблюдайте терпение, все получат свои картинки рано или поздно. С телефона всё выглядит вот так.


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

В моей жизни — этот проект самый эпичный долгострой, который всё же был реализован и доведён до конца. Проект меня многому научил. Когда я делал сайт, то впервые вообще столкнулся с js, php и вообще web-программированием, CGI вообще был для меня пустым звуком, а ещё разработка своих скриптов… Всё это стало для меня замечательным опытом и дало весьма неплохой навык, который пригодился в моей дальнейшей работе.
Да, сам проект может быть глупым и абсурдным, но лично меня он научил очень многому, и я благодарен, что он состоялся.
Главное я благодарен всем моим друзьям, которые мне помогали с этим проектом. Не буду перечислять всех по именам, вы все молодцы. Громадное спасибо man_of_letters за помощь с сайтом в начале пути, и за помощь с ботом в завершении проекта. Компании RuVDS за помощь в подготовке этого проекта.
А главное, вам мои дорогие читатели, за то, что будете его использовать и понимать что это просто прикольно!
HIPCRT_BOT
И напоследок, вот видео, которое изготовлено на этом аппарате. Понадобился день, чтобы обработать все кадры этого короткого видеоролика.
З.Ы. Если всё будет хорошо, постараюсь чтобы аппаратная часть проработала не меньше месяца!
Telegram-канал с полезностями и уютный чат
