В век «онлайна», печатная фотография стала больше походить на диковинку, как это было раньше с фотографией цифровой. В последнее время, различного рода фотобудки, стали набирать популярность, как интересный способ развлечь гостей и получить памятный сувенир в виде фотографии. Я фотограф, который увлекается программированием, и при этом сочетании, было бы странно не попробовать сделать себе фотобудку.
В отличии от коммерческих моделей фотобудок, которые есть в продаже, мне хотелось сделать действительно компактную и автономную систему. Чтоб я параллельно основной работе, мог за пару минут ее установить хоть в поле и не таскать с собой лишние десятки килограмм веса. И у меня это получилось.
Под катом будет рассказ о железе, raspberry pi и программировании всего этого под linuх и конечно же мой любимый python. Забегая вперед, скажу, что мне хотелось именно качественных фотографий, поэтому съемка ведется не на веб камеру, а на DSLR, поэтому статья должна получиться еще больше и интересней.
Железо. От простого к сложному.
Когда я брался за этот проект, была зима. Зимой у меня куча свободного времени и мало работы, поэтому проект должен быть максимально дешевым. Кроме финансовой составляющей, я люблю принцип KISS — система должна быть максимально простой. От простоты зависит так же и такие составляющие, как надежность, размер и, что немаловажно, энергопотребление.
А начну я рассказ о железе с того, как можно было бы сделать гораздо проще, и далее, по ходу работы над проектом, «проще» заменялось на более сложное. Возможно реализация «проще» кому нибудь пригодится.
И так, у нас есть DSLR камера и задача: по команде человека делать снимок и отправлять его на печать. С этим на самом деле очень и очень просто. Взять кнопку, подключить ее к любому МК (да хоть целиком arduino воткнуть). При нажатии человеком кнопки, вести отсчет количества секунд, и по истечении этого времени, делать снимок. Снимок на DSLR делать тоже просто — достаточно «притвориться» либо проводным пультом (подключается к камере по разъему 2.5 jack и по сути, «замыкает» два контакта), либо «притвориться» беспроводным ИК пультом (реализаций под МК очень много). Для отсчета времени можно использовать любой сигментный индикатора, либо LCD дисплей, но я планировал сделать «аналоговую» индикация — серво-привод и стрелка. С отправкой на печать фотографии с камеры, тоже проблем быть не должно. Есть замечательные SD карты памяти со встроенным WiFi передатчиком. Об этом, кстати, я уже подробно писал на хабре. Далее, на ноутбуке, уже можно было бы написать простой скрипт, который отправляет на печать полученные фотографии.
Далее, в моей «мысленной» работой над проектом, потребовалось усложнить систему. В первом варианте, делается одна фотография, но хочется как в «настоящих» фотобудках, делать серию, и распечатывать ее на одном листе бумаги. Реализовать это можно, с помощью второй кнопки (человек выбирает, делать одно фото, либо сразу несколько). Возникает проблема — как ноутбук узнает, какую кнопку нажали, и соответственно печатать эту фотографию, либо ждать еще 3, для размещения на одном листе. Решается это тоже просто — всеми любимая esp8266, которую можно подключить к той же сети, что и SD карта с WiFi. Она «сообщит» ноутбуку о выборе пользователя.
Проект и остался бы таким, если бы я не задумался об очень важной вещи — люди должны видеть себя во время съемки. Им не известно, на кокое расстояние нужно подойти, сколько человек влезет в кадр и пр. Есть конечно дисплей самого фотоаппарата, который можно включить в режим LiveView, я уже начал задумываться над системой зеркал и линз, чтоб эта картинка была видна людям (задача упрощалась тем, что дисплей на камере поворотный), но я вспомнил про то, что в камере есть HDMI выход и на известном магазине «китайской» электроники, должно быть что то мне нужное. В итоге был заказан 7-ми дюймовый LCD дисплей с контроллером, который может принимать сигнал от различных источников, включая HDMI.
Пока шел дисплей, я решил что таскать с собой еще и ноутбук, очень не хочется. В голову пришло сделать действительно автономную систему. И тут на сцену выходит «мозг» всей системы — Raspberry Pi. С его появлением, я решил полностью возложить на него всю работу: отказаться от кнопок, позволив пользователю наживать кнопки на тачскрине, показывать ему картинку с LiveView и самое главное «утверждать» фотографии на печать, так как не редки случаи, когда человек, например, банально «моргает» во время съемки.
Когда пришли все запчасти, я начал соединять все воедино. Из инструментов у меня был паяльник, клеевой пистолет и сайдинг (!). Первым был готов блок дисплея — эдакий самодельный монитор.
На фотографии сверху контроллер дисплея, снизу USB контроллер тачскрина. Весь набор был куплен на aliexpress (искать так)
Со стороны дисплея, это выглядит так:
Питается все это дело от 5 вольт и потребляет в пике 700-800 миллиампер.
«Корпус» для raspberry pi я делал из того же самого сайдинга (это первое что мне попалось на глаза, да и с ним очень легко работать).
Поясню что за «кулебяка» получилась. Сверху стоит 5-ти вольтовый куллер. Я побоялся перегрева, и он включается при достижении температуры 55 градусов, простым скриптом, который запускается из крона.
#!/usr/bin/env python
import RPIO
import subprocess
RPIO.setwarnings(False)
RPIO.setup(18,RPIO.OUT)
sub=subprocess.Popen(['/opt/vc/bin/vcgencmd', 'measure_temp'],stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=False)
temp=float(sub.stdout.read().split('=')[1].split("'")[0])
if temp>55:
RPIO.output(18,1)
if temp<45:
RPIO.output(18,0)
Слева виднеется модуль реле. Он предназначен для включения диодной подсветки, во время работы. Поясню зачем это нужно: на разного рода банкетах, во время перерыва на танцы может быть очень темно. Подсветка нужна как для работы автофокуса при съемки, так и для того, чтобы во время «позирования» люди видели себя, а не темноту на экране. Во время съемки в помещении, у меня стоит стойка со вспышкой и софтбоксом, который работают через обычный радиосинхронизатор, который подключен к горячему башкаму фотоаппарата. Таким образом, я получаю хороший свет на снимках. Хотя можно было бы оставить просто диодную подсветку, но качество снимков было бы хуже.
Прототип корпусы был собран из того же сайдинга, для того, чтобы оценить требования и размеры к итоговому варианту.
Сам корпус я захотел стилизовать под старинный фотоаппарат. Я не решился делать его сам и заказал изготовление знакомым, которые занимаются декором. Корпус изготовили из ламината, с использованием кожзама для «гармошки».
Он очень уж понравился котам, но пришлось их все же выгнать чтобы разместить всю начинку.
Питается все это дело от двух повербанков. В теории, хватило бы одного на 10000 mA/h на 5-6 часов работы, но при одновременном подключении и дисплея и raspberry, нагрузка по току больше, и аккумуляторы отдают меньшую емкость.
Пару слов о печати фотографий, ради чего это затевалось. Печатать фотографии можно на чем угодно, хоть на обычном бытовом струйном принтере. Но мне опять же нужна была компактность. Кроме компактности, для автономной работы, нужна еще надежность. Не очень хочется беспокоиться об уровне чернил, забившихся дюзах и пр. В итоге был выбран дешевый и компактный термосублимационный принтер. Из плюсов: малый размер принтера, безотказная печать (можно забыть о полосах, пятнах краски и пр), возможность транспортировки и печати хоть вверх ногами, долговечность снимков (сразу после печати снимок окунал в воду, и ему ничего не было). Из минусов: высокая себестоимость печати и необходимость замены бумаги раз в 18 снимков и картриджа с лентов раз в 36 снимков. Расходные материалы только оригинальные (в комплекте, кроме спец бумаги, еще и спец картридж с лентой), себестоимость одного отпечатка — 25 рублей, хотя это закладывается в конечную стоимость услуги. Принтер работает по WiFi, для этого к raspberry pi подключен «WiFi свисток».
Софт
Для «серийных» фотобудок есть в продаже свой софт, который существует естественно только под PC и Windows. Для linux под arm пришлось писать все с нуля (да ладно пришлось, мне это просто нравится!). В качестве языка программирования был выбран python (на самом деле, я ничего другого не знаю).
Для начала, нужно как то научиться взаимодействовать с фотоаппаратом, который подключен по USB. Я не удивился, когда обнаружил, что для в linux'е уже есть готовые инструменты. Это консольная утилита gphoto2.
Первым делом, понадобился экран настроек, который запускается сразу же после старта системы.
GUI написано на Tkinter, который более чем подходит под эти задачи.
Здесь можно настроить фотоаппарат под конкретные условия съемки, запустить основную программу, настроить ее поведение (делать одну большую фотографию, либо позволять выбирать «одно фото» и «4 в 1», печатать или только сохранять, а так же режим печать, но об этом позже), и делать тестовый снимок. Об этом поподробнее.
Для начала, нужно записать настройки в фотоаппарат, делается это просто:
#список со значениями баланса белого
bb_list=['Авто','Дневной','Тень','Облачно','Вольф.','Флюр. лампа','Вспышка','Ручной']
sub=subprocess.Popen(['gphoto2',
'--set-config', 'whitebalance='+str(bb_list.index(settings['bb'])),
'--set-config', 'iso='+t_iso,
'--set-config', 'aperture='+settings['a'],
'--set-config', 'imageformat=7' #настройка размера фотографии (jpeg размером 1920х1080)
],stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=False)
err=sub.stderr.read()
Теперь нужно сделать тестовый снимок и показать его на экране.
sub=subprocess.Popen(['gphoto2','--capture-image-and-download','--filename','/tmp/booth.jpg','--force-overwrite'],stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=False)
err=sub.stderr.read()
Камера сделает снимок и он запишется в файл /tmp/booth.jpg (чтобы ускорить работу и сберечь ресурс карты памяти в raspberry, такие вещи лучше делать в /tmp, которая по дефолту смонтирована в tmpfs, то есть работает в оперативной памяти). После этого снимок выводится на экран для оценки, а настройки записываются в файл, с помощью обычной open('/home/pi/settings.dat','wb').write(repr(settings))
Итак, фотоаппарат настроили, пора запускать интерфейс пользователя.
Сам интерфейс написан с использованием известной библиотеки pygame.
Естественно, чтобы пользователи не могли нажать «куда не нужно», приложение запускается на полный экран:
pygame.init()
pygame.mouse.set_visible(0)
screen = pygame.display.set_mode((800,480), pygame.HWSURFACE | pygame.FULLSCREEN,32)
Архитектура приложения до боли проста: интерфейс рисуется из заранее сохраненных картинок, а сама программа работает по методу конечного автомата, с заранее определенными состояниями. Более подробно, мне хотелось бы рассказать по части взаимодействия с фотоаппаратом.
Первое, что нам необходимо, это получить LiveView картинку с камеры, чтобы пользователи могли видеть себя во время приготовления к съемкам. Я пробовал это сделать с помощью утилиты gphoto2, но по причинам, о которых я уже не помню, у меня это не получилось. Была найдена библиотека к питону piggyphoto, где эта задача решается просто:
cam = piggyphoto.camera()
cam.leave_locked()
while WORK:
s=self.cam.capture_preview()
s.save('/tmp/preview.jpg')
s.clean() # этого в примерах нет, но без этого возникает утечка памяти https://github.com/alexdu/piggyphoto/issues/2
from_camera = pygame.image.load('/tmp/preview.jpg') # загружаем фотографию
from_camera=pygame.transform.scale(from_camera, (800, 530)) # уменьшаем до размера экрана
from_camera=pygame.transform.flip(from_camera,1,0) # делаем флип по горизонтали, чтоб на экране все было как в зеркале)
Под режим LiveView так же необходимо настроить камеру. Например, если сама съемка ведется с ISO 100, то на LiveView этого может быть мало. Перед включение нужно сделать примерно так:
sub=subprocess.Popen(['gphoto2',
'--set-config', 'whitebalance=0', # баланс белого на Авто
'--set-config', 'iso=0', # ISO на авто
'--set-config', 'aperture=2.8', # диафрагму открываем
'--set-config', 'imageformat=7'
],stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=False)
После завершения работы таймера, можно уже делать сам кадр, как описывалось выше. Если выбран режим «4 кадра в 1», то соответственно это все повторяется 4 раза, чтоб получить 4 разные фотографии, которые потом склеиваются в одну. Этим уже занимается библиотека Pillow (я настоятельно рекомендую использовать ее, а не устаревшую PIL, как минимум из за производительности), которая кроме объеденения нескольких фотографий на один лист, накладывает логотип, и делает возможным сделать какой либо брендинг:
Для демонстрации, я сделал небольшое видео:
Фотография готова, ее можно отправлять на печать. В linux это делается всего одной командой: lpr FILENAME. Отправка фотографии на печать по WiFi на принтер canon selphie имеет один нюанс: фотография должна быть отправлена на печать «напрямую», то есть принтер принимает уже готовый jpg файл: lpr -o RAW filename.
Собственно, основной функционал готов. В последствии было добавлено еще несколько «фич». Первое, что захотелось реализовать, это отдача фотографий в электронном виде. Раз WiFi и так работает в режиме точки доступа, к которой подключается принтер, почему бы не сделать ее открытой. На raspberry был поднят веб сервер, с простенькой галереей. Чтобы не возникло проблем с поисков этого веб сервера, настроил Captive Portal — при подключении к точке доступа, страница с галереей открывается сама. Это делается, путем установки DNS сервера, который на все запросы отдавал IP адрес веб сервера.
На самом деле, в рамках одной статьи, рассказать обо всех нюансах невозможно. По мере возможности, постараюсь ответить на ваши вопросы в комментариях. Следующая моя статья, тоже обещает быть интересной, в ней мы будет скрещивать старые необычные технологии в печати фотографий, и новые технологии в области программного обеспечения.
Автор: kAIST