В отличии от коммерческих моделей фотобудок, которые есть в продаже, мне хотелось сделать действительно компактную и автономную систему. Чтоб я параллельно основной работе, мог за пару минут ее установить хоть в поле и не таскать с собой лишние десятки килограмм веса. И у меня это получилось.
Под катом будет рассказ о железе, 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 адрес веб сервера.
На самом деле, в рамках одной статьи, рассказать обо всех нюансах невозможно. По мере возможности, постараюсь ответить на ваши вопросы в комментариях. Следующая моя статья, тоже обещает быть интересной, в ней мы будет скрещивать старые необычные технологии в печати фотографий, и новые технологии в области программного обеспечения.
Комментарии (19)
safari2012
21.03.2016 15:42del
kAIST
21.03.2016 16:02Не знаю, почему вы удалили комментарий, он на самом деле актуальный. С raspberry pi 2 скорость превью возрасла бы не на много, но вот некоторые вещи все же хочется ускорить. Например, финальная обработка фотографии с отправкой на печать, занимает секунд 20-30(если их 4 штуки), в этом время следующие просто ждут. Можно эту работу отдать второму ядру, а на первом продолжать работу.
Сейчас как раз хочу переводить проект на raspberry pi 2. Были попытки что то сделать на других одноплатниках, типа orange pi, но они потерпели неудачу. Например, нельзя выставить разрешение HDMI 800х480 (родное для дисплея).safari2012
21.03.2016 17:18Посмотрев ролик, я подумал, что LiveView программый, больно уж тормозит. Но, перечитав статью понял, что он крутится напрямую с камеры.
На Orange Pi 800х480 можно сделать через LVDS (в вашем случае, видимо, придется подключаться напрямую к контроллеру дисплея).kAIST
21.03.2016 17:22Нет нет, он именно программный. Карды берутся с камеры и выводятся на экран. Подключение к дисплею организовано по HDMI, а контроллер дисплея уже общается с дисплеем. Тут узкое место не дисплей, так как можно спокойно смотреть на нем даже видео. Из камеры кадры приходят в виде jpg картинок, которые еще нужно декодировать и отобразить на экране.
safari2012
21.03.2016 17:21Вот так: http://sunxi.org/Cubieboard/LVDS
kAIST
21.03.2016 17:24Спасибо, не знал. Но на orange pi я не стал бы рисковать и покупать LVDS дисплей, так как дефолтные образы там работают и так еле еле, а заведется ли дисплей, не известно.
safari2012
21.03.2016 17:42а там образ не надо ковырять, есть загрузочный http://sunxi.org/Script.bin, который в буте живёт и делается он конвертацией конфигурационного FEX-файла http://sunxi.org/Fex_Guide
глубоко внутри почти у любого TFT-дисплея всё равно LVDS интерфейс, который у вас хорошо на фотке виден.
nygger
21.03.2016 17:30Можно подробнее — пробовали что-то кроме orange pi? По предзаказу жду https://www.pine64.com/product#features
kAIST
21.03.2016 17:44Огромный плюс raspberry это поддержка сообщества и полностью рабочий образ OS.
У меня при попытки портирования вылезло две большие проблемы: разрешение дисплея (выше отписывались что можно сделать), и драйвера контроллера тачскрина. На raspberry пришлось пересобрать ядро, включив поддержку тача. Делал я это впервые в жизни, и благодаря сотням статей, сделал это с первого раза. На orange pi я это сделать так и не смог. Я уж не говорю про другие мелкие проблемы, например: WTF, куда делось под нагрузкой одно ядро, я ведь на него рассчитываю.
Возможно с другой платой можно сделать все тоже самое, но большими усилиями, поэтому я все же жду raspberry pi 2, а orange pi у меня сейчас ушел на другой проект.safari2012
21.03.2016 17:47если не купили ещё, попробуйте сразу Pi3 купить на аукционе. если постараться, можно по цене двойки купить, тут уж как повезет.
safari2012
21.03.2016 18:27Если не секрет, зачем купили?
nygger
21.03.2016 20:04Основная задача — сёрф в инете, ибо домашней станции на core i7 и 16 гиг оперативы для этой задачи как-то с переизбытком. Ну и возможно углубить теоретические знания. О Pi3 на момент предзаказа не знал.
nygger
21.03.2016 15:50+1Наличие DSLR существенно увеличивает стоимость готового «фото-аттракциона». С качественной вебкой вышло бы конечно хуже, но и в разы дешевле. Было бы интересно вместо публичной галереи организовать отправку на e-mail.
kAIST
21.03.2016 15:53Конкретно у меня, вторая камера и так валяется в рюкзаке в качестве запасной, этому рациональнее использовать то что было. Если использовать вебку, то нужно что то думать с постоянным светом, например, использовать кольцо из мощных светодиодов.
Но замечание ваше справедливо, с вебкой и программная часть получилась бы гораздо легче.
RomanArzumanyan
21.03.2016 18:56Камеры с мехами выглядят ну совсем иначе. Честно говоря, такой внешний вид "удешевляет" хорошее решение, реализованное вами. Можно было купить что-то нерабочее вроде Фотокора — получилось бы визуально гораздо круче.
kAIST
21.03.2016 19:07В "фотокор" не влезло бы никак, я проверял ) Решение с корпусом больше продиктовано начинкой.
angru
А не рассматривали вариант с вебкой или каким-нибудь модулем камеры для малины для превью, вместо того чтобы постоянно, дергать LiveView фотоаппарата?
kAIST
Смысла нет, так как смысл превью в том, чтоб оно было такое же, как и получившееся изображение. Например, я могу поставить объектив 24 мм или поставить объектив 35 мм. Да и дергать LiveView фотоаппарата не страшно — это штатная его функция. Расход аккумулятора фотоаппарата больше, но его с запасом хватает на весь вечер работы.