вторник, 16 апреля 2013 г.

HackDay#25. Проект Virtualens. Отчет.

Черт возьми, мы победили!

Ну а теперь подробнее как это начиналось, как продолжалось и чем закончилось.

С чего все начиналось.

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

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

В субботу я уехал в Саров на выходные, однако даже там я продолжал думать о хакатоне, о идеях. Так что в субботу я ночью вместо того, чтобы читать книжку, ну или на худой конец спать, думал, писал, опять думал, и в результате к 4-м часам ночи написал таки подробное описание шести идей (описание, плюсы-минусы, риски, кто нужен), а седьмую забраковал как не реализуемую. Написал, и разослал список тем знакомым кто мог бы заинтересоваться и поучаствовать.

В понедельник вечером, я скачал и установил PerC SDK, и начал играться запуская примеры пока без спец. камеры. И обнаружил, что из за особенностей реализации (либо технологии распознавания лиц вообще) одна из идей отпадает, ибо становится не реализуемой на дОлжном уровне. Это была идея динамического формирования изображения в зависимости от положения наблюдателя. Правильная реализация подобной идеи была еще в 2007 году, и основывалсь не на распознавании лиц. Посмотреть как это выглядело можно посмотреть на ютубе:
Проблема в том, что из за угла обзора камеры, и нюансов реализации распознавания лиц, алгоритм в PerC SDK периодически теряет лицо, что приводит к не желательным эффектам (подергивания, лаги (то есть задержки)) - иллюзия "окна за которым другой мир" полностью разваливается. И это было хорошо видно потом, на менторской сессии на хакатоне во время демонстрации технологии самими сотрудниками Intel.
(а еще реализацию этой идеи было бы сложно демонстрировать людям - оно работает только для одного наблюдателя, а остальные видят фигню)

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

Поэтому во вторник я написал организаторам письмо, где изложил вышесказанное - чтобы определиться с идеей, нужна камера, а камеру дают после оглашения идеи (уже на хакатоне) - замкнутый круг! Организаторы (а конкретно Михаил) среагировали мгновенно, в переписку была включена Светлана из Intel, и в среду ко мне уже приехала камера. Стало возможно посмотреть на что она способна, и на что способен PerC SDK.

А еще в среду я познакомился с Надей - я искал по знакомым (в том числе и на работе) кто еще хочет пойти, выяснил что Надя собирается идти, и написал ей письмо.

Вообще, к тому моменту у меня в фаворе была идея вовсе не Virtualens'a, а идея таки 3D сканера и сервиса обмена отсканированными моделями. Было даже название придумано - Let's clone. Меня крайне забавляла сама возможность сделать "пиратскую" копию скажем фигурки из шахматного набора. То есть берем предмет, показываем его камере, и в компьютере у нас получается моделька предмета, а потом рраз, и распечатали её на 3Д-принтере. Я прекрасно понимал свои возможности (да и возможности команды, если таковая набралась бы), и знал что мы не сможем за 48 часов научиться сканировать все что угодно. Предполагалось, что будем сканировать спереди и сзади зеркально-симметричный предмет, а затем с помощью жестов из этих половинок лепить готовую модель. Соответственно камеру я проверял в первую очередь на её возможности в приложении для этой идеи.

В ходе экспериментов, я узнал о камере довольно много - понял что там нет защиты от внешней засветки (солнце, лампы дневного света), что она ловит блики от собственного же ИК-фонарика, что подсветка у нее не равномерная, и для 3Д сканера, вообще говоря, неплохо бы построить будет мат. модель этой самой подсветки, чтобы компенсировать вносимые ей искажения. Ну и шум, да. На расстоянии сантиметров в 25 фильтрованный силами SDK сигнал выдавал шум порядка 2-3 миллиметров (то есть между двумя кадрами у одного и того же пикселя разница в глубине может быть 3 миллиметра легко), на не фильтрованном сигнале же... Если воткнуть свой дли-и-инный фильтр (скажем на 1000 кадров), то оно все равно плавает, но уже можно получить точнее 1 миллиметра. А еще оно по разному работает на разных материалах, поэтому вещь которую будем сканировать желательно чтобы была однотонной, не бликующей, зеркально симметричной.

Но несмотря на все это, в четверг я все еще рассматривал 3D-сканер как основную идею, к которой и готовился (искал опенсорс-библиотеки которые могли бы пригодиться, смотрел на "фреймворки" для 3D графики, чтобы было на чем быстро написать визуализацию отсканированной модели. остановился, кстати, на http://www.openframeworks.cc/. Посмотрел код, код примеров - мне понравилось). 

Также в четверг я дошел ногами до Нади, и изложил все свои соображения про идеи проектов, с упором на 3Д сканер.

Да, и в четверг же мне стало уже понятно, что никто из знающих OpenGL (кого я зазывал) на хакотон не идет (поэтому я и смотрел на тот же openframeworks, с нуля на OpenGL вменяемо я не успел бы самостоятельно написать визуализацию).

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

Переломный момент - рождение Virtualens.

В ночь я четверга на пятницу я внезапно обнаружил, что 3D сканирование камерой - это баян. С 2011 года баян! Ну, то есть на рынке уже есть штук 5 классных продуктов, которые делают то, о чем я мог подумать только в самых смелых мечтах. Используют они для этого кинект. И стоят относительно дешево - 150 баксов где-то, и это при наличии бесплатной версии ознакомительной! По сравнению с этим то, что мы изобразим за 48 часов будет смотреться просто жалко, настолько жалко, что даже не вторично, а еще хуже. То есть самое разумное что мы могли бы сделать - скачать одну из бесплатных версий одного продукта, который умеет данные доставать не только с камеры живьем, но и из файла. И каким-то образом расковырять формат этого файла, научиться генерировать такие файлы. Таким образом добавив в этот продукт сбоку кривую поддержку Интеловско-Креативовской камеры. Это выглядело бы уже не так плохо, это выглядело бы просто вторично. И это меня все равно не устраивало.

Так что в пятницу я обсудил ситуацию с Надей, и мы решили выбрать идею виртуального объектива для веб-камеры. Ну, то есть взять идею, которую я не прорабатывал практически с момента записи её в список. Проект не казался мне вах каким полезным. Ну, то есть с точки зрения реализации, математики и программирования - да, интересно и классно. Но с точки зрения применимости на практике - казалось сомнительным. Собственно вот что буквально было записано в пункте "риски/недостатки проекта":
Риски/недостатки проекта: Проект технодемоподобный. То есть его конечно возможно вывести на уровень полезного приложения (особенно если прикрутить туда функцию заливки получившегося на ютуб), но это все равно некая натяжка. Также из за пониженного разрешения IR-сенсора, могут возникнуть проблемы на переходах от фона к переднему плану (края будут "жеваными").
В плюсах же проекта значилось лишь то, что он в каком-то виде скорее всего реализуем за 48 часов.

Вообще, сама идея этого проекта мне пришла где-то с месяц назад, когда я развлекался с алгоритмами обратной свертки (deconvolution) - это алгоритмы которые позволяют "провернуть фарш назад", то есть получить из расфокусированной фотки нормально сфокусированную. Естественно я сразу подумал - "хм, а как на счет обратной задачи? есть фотка везде четкая, а мы хотим динамический фокус, с соответствующим размытием по глубине". Я тогда помнится еще поигрался с двумя камерами чтобы получить карту глубин на основе параллакса, наткнулся на какие-то неоднозначности восстановления такой карты, и забил.

Соответственно в пятницу же (за несколько часов до начала, да!) я спешно придумываю название для проекта (Virtualens) и регистрирую его. Надя регистрируется на сайте хакотона. В результате и проект и Надя оказались похоже последними из того что там было зарегистрировано до начала :-)

Хакатон.

День первый.

Закончив с регистрацией всего и вся, схватив рюкзак (я на работу с рюкзаком и пришел, чтобы не тратить потом время на то, чтобы его из дома забрать) я поехал добираться до места проведения хакотона. Улица Ларина, на которой и стоит этот самый бизнес-инкубатор, где все проводилось, довольно не благоустроена. Тротуары вдоль дороги? Не, не слышали! Зато я добрался за полчаса до начала регистрации участников, соответственно у меня было время отчистить ботинки в туалете :-)

Но улица Ларина не самое страшное что меня ждало в начале мероприятия, самое страшное - ПИТЧИ! Это такая штука.. За 90 секунд надо рассказать кто мы, что за проект, зачем проект, кто нужен в команду. Рассказывать это должен тот, кто заявлял проект, так что похоже, что это был я. 90 секунд! Перед аудиторией! БЕЗ БУМАЖКИ! Тут одно из двух - или я не уложусь в тайминг, либо забуду все самое важное. Пришлось готовиться (кстати, я до сих пор не уверен что подготовка как-то мне помогла - учить что-то наизусть я никогда не умел. Выучить стрихотворение из двух четверостиший - всегда было для меня проблемой. А вот втечение 10-15ти минут, а то и часа, что-то рассказывать из того, что мне интересно - это я легко и без подготовки могу.). Написал текст. Начал репетировать. С секундомером. Вначале каждую часть по отдельности, потом все вместе. Так что когда пришла Надя и поздоровалась, я ответил ей бессмысленным взглядом и шевелящимися губами - я в очередной раз прогонял текст. С секундомером.

Пошли питчи. К счастью проекты шли в порядке регистрации. То есть мы были последними. Что позволяло немного тайминг завалить и за этого никто не убил бы скорее всего. Ну, может только немного покалечили бы. Я не знаю воспользовался я этим или нет - я не смотрел на отсчет времени что показывали на iPad'e. Ну, или смотрел, но не воспринимал совершенно, ибо не помню этого. Но по крайней мере мне было от этого спокойней.

Вроде бы я что-то рассказал, вроде неплохо, только на импровизации "Только математика, только хардкор" я сбился, заикнулся и получилось как-то не так.

Началось формирование команд, мы так никого к себе и не зазвали, но два парня дали нам, как оказалось, довольно ценный совет - забить на OpenGL/шейдеры, и писать все эффекты на CPU. Думаю это таки сэкономило нам время (из за того, что ни шейдеры ни OpenGL мы не умели), хотя и пришлось попотеть над оптимизацией.

А еще у Нади не было ноутбука на котором можно было бы разрабатывать под PerC SDK (там нужно не ниже Win7 систему иметь ну и проц аля i3..i7), так что пришлось просить ребят из Интела, чтобы что-нибудь ноутбукоподобное годное для PerC SDK. И они таки дали замечательный ультрабук фирмы Intel. Ну, то есть не самсунг, не делл какой-то там, а интел. Никогда раньше таких не видел. Вообще, сотрудники Intel'a на мероприятии в плане поддержки участников конкурса проявляли чудеса оперативности - и камеру вторую дали быстро, и, потом, на второй день, оперативно ответили на вопросы по API SDK. Молодцы. Все бы так.

Ну и пообщались с Николаем Долговым - тоже нашим сотрудником, у него была идея тревожной кнопки на смартфоне (http://hackday.ru/events/hackday-25/projects#project-399). У меня был некий скепсис по поводу эффективности подобной штуки, о чем я ему и сказал. Он отлично отбил подачу, и в общем то меня переубедил. Молодец.

В общем команды набрались, и все разошлись в поисках хороших мест. Надя нашла нам уголок, в первой же комнате, где мы и обитали все эти два дня. Разложили ноутбуки, набросали план работ и решили пока разъехаться по домам. Выспаться. Спокойно почитать доки. Это довольно логично было - 48 часов без сна это одно, а 60 часов - это уже другое (мы же встали в пятницу утром все таки), и эти несколько часов могут оказаться критичными на финише. Я доложился за час до чекпоинта Мише, и мы разъехались (а Николай остался кодить свою тревожную кнопку на андроиде).

Дома я еще поковырял код, и попробовал заснуть. Не знаю, по ощущениям я спал в ту ночь часа три - слишком был возбужден чтобы нормально спать. Зато я написал свой "hello world" на PerC SDK, на котором смог оценить сколько проходов по картинке мы можем сделать не снизив fps ниже 30. Это было важно. Картинка не только должна быть красивой, но и быстрой. Если у тебя красивая картинка на видео, но при этом 5 кадров в секунду... Это будут натуральные тормоза, это не естественно и народ это заметит. Иллюзия движения распадется как карточный домик.

День второй.

В субботу я приехал раньше Нади. Так что мы с Николаем успели позавтракать и обсудить что за ночь произошло. Он боролся с андроидом. И победил. Но на это ушла вся ночь.

А потом пришла Надя, позавтракала и мы начали реализовывать первый пункт нашего плана - нужно было написать блюр. Сильный не тормозящий блюр, размытие картинки на разрешении 640x480. Нужно было выжать 30 кадров в секунду и при этом иметь еще запас по мощности, ведь будет же еще обработка глубины. Надя читала папиры, а я ковырял код и иногда думал. А потом я вспомнил что я не только программист, но и бездельник, и ушел на утренний чекпоинт.

Чекпоинт это странно. Сидишь ты, кодишь, весь такой асоциальный, погруженный в код, в голове нет никаких слов (по крайней мере человеческих), только образы как оно там внутри кода все шевелится, ну то есть ты нормальный такой обычный программист. И тут бац. Надо идти на чекпоинт. А там люди. А там надо рассказывать про проект и про людей. И про то зачем этот проект обычным простым людям (не программистам!) будет нужен и интересен. Это шок. Это контрастный душ для мозга. Приходится резко переключать думалку на совершенно другой режим. И мне было стыдно что я тут а чекпоинте фигней какой-то страдаю, а там Надя в одиночку решает важные для проекта задачи. Но с другой стороны, за эти 3-4 чекпоинта что у нас были я как-то научился говорить на эти темы не приходя в сознание. Это потом здорово пригодилось на демонстрации в конце хакатона.

Вернулся с чекпоинта и мы быстро реализовали первый вариант, в лоб, по определению свертки. И получили... 3 fps! Это был кошмар. Пошли лихорадочно гуглить, на тему эффективных алгоритмов, и тут начал отваливаться интернет. Регулярно. Постоянно. Это было ужасно.

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

После сессии, было забавно - мы решили выпить кто кофе, кто чаю, сидим разговариваем, перевариваем остатки обеда и только что прослушанной лекции. И тут подходят господа из интела и спрашивают - а что это мы не работаем? ;-) А что мы не работаем? Мы ждем идей, вдохновения, ну или хотя бы вменяемого интернета. Ибо 3 fps это приговор.

Но сидя за чаем конечно что-либо высидеть сложно. так что мы допили чай и пошли дальше биться головой об тормоза. С интернетом плохо, так что пришлось думать. Думали, придумали как ускорить - реализовать через разностую схему. Теперь сложность алгоритма была не O(W*H*N^2), где W - ширина окна (640) H - высота (480) а N - диаметр размытия, а всего лишь O(W*H*N). Чтобы проверить насколько нам это поможет, реализовал "плоское" размытие - размытие только по горизонтали. Гадость конечно, но реализуется быстро, и оценка сложности та же, что у разностной схемы. Получили 9-10 fps. Это было хорошо. но не достаточно хорошо - надо было где-то взять еще ускорение раза в 4. Надя искала хитрые алгоритмы, которые дали бы O(W*H), а я думал что там в коде можно допилить/еще ускорить. 

И нашел. Я совершенно на всякий случай просто решил проверить, а что у нас будет в релизе. Особой надежды, что там будет что-то принципиально другое у меня не было, ибо обычно там разница в производительости процентов 20 бывает, ну 50. А тут... А тут ускорение в три раза! Черт, мы сразу получили искомые 30 fsp! Мораль команды поднялась, и я начал реализовывать разностную схему в коде. Поскольку хотелось еще скорости, чтобы потом свободно себя чувствовать при обработке данных по глубине, то Надя продолжила поиск идей по дальнейшему ускорению.

К моменту вечернего чекпоинта я уже реализовал схему (она была местами глюкавая, но в основном работала), а Надя подкинула еще идейку, которая ускорила все это хозяйстсво еще раза в полтора-два. Так что можно было уже спокойно заняться разделением переднего и заднего плана картинки. Собственно я эти планы на чекпоинте и озвучил - к утру у нас должна быть реализация прототипа умеющая уже размывыть задник и не размывать то что близко. Оно будет страшненько выглядеть, но работать будет.

По возвращению с чекпоинта я засел за реализацию выделения областей которые нужно и которые не нужно размывать. Области выделить удалось довольно быстро, и мы еще до полуночи уже получили картинку с размытым задним планом, но тут всплыла проблема - между depth-координатами и координатами на цветной картинке нет взаимно однозначного отображения. Соответственно в изображении были дырки. Часть тех пикселов которые не должны размываться, размывались таки. На лице был виден шум. Более того, средствами API получить отображение из цветной картинки в depth вовсе невозможно. Пришлось лепить велосипед для такого отображения. Кроме того, на границах размытия вылезли баги в алгоритме размытия - были дикие черные контуры и тени там где не надо.

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

День третий.

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

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

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

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

Сходили на обед. Я стремительно начал превращаться в зомби - все же организму иногда нужно спать. Впрочем, я до того момента ни разу на хакатоне еще кофе не пил (да и чай почти не пил, пил в основном просто воду), так что на один, последний рывок у меня еще были резервы. Перед репетицией у меня дикий тупняк - не мог совершенно придумать текст речи. На репетиции кое-как что-то изобразил. Меня покритиковали. Спасибо! Я как-то постепенно пришел в себя, и к демофесту таки сочинил и текст вменяемый, и план демонстрации (который мы, впрочем, таки нарушили).

Ну и вот наконец сам демофест. Порядок выступлений не известен! Так, сказать, сюрприз будет. Во время демофеста выйти нельзя, а мне для выступления просто необходимо выпить кофе, иначе я улиточка, а то и просто слизень. Нужно, так сказать, включить турбобуст, а то ничего не выйдет. Но есть нюанс - кофе действует не бесконечно, и после окончания действия (минут 30-40 я полагаю) я окончательно превращусь в овощь. Я рискую и выпиваю чашку перед началом демофеста. И нам везет! Мы выступаем вторые!

Более-менее бодро рассказываю какую штуку мы сделали и зачем это все нужно, Надя синхронно все это демонстрирует, естественно по законам жанра вылезают сразу все глюки моего рендера, о чем меня потом из зала и спросили, можно ли это дело устранить в принципе. Отвечаю на вопросы... Меня спрашивают про команду, её опыт и так далее.. Надя! Мне до сих пор стыдно, что я забыл про тебя сказать когда рассказывал про свой опыт работы. Жутко стыдно! Но я там просто отключился. Я опять не помню секундомера, такое было ощущение, что кратковременная память сказала мне "бай-бай", обойдешься пока без меня, по крайней мере пока не выспишься.

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

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

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

И были наши соперники по конкурсу - Personal DJ. Они класные, креативные. Ребята, вы отлично выступили! Вы были точно лучше чем например вот этот товарищ занявший одно из первых мест в Intel® Perceptual Computing Challenge Phase 1:
В общем, респект вам.

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

И была радость от победы. Черт возьми, это здорово! Это здорово когда много работаешь и это приносит плоды. Как сказала Ася:  "иметь опыт победы - это самое главное в жизни, и ради этого стоит лезть под ток." (отсюда)

Что будет.

И это еще не конец. Будет еще много чего. Мы, я думаю, примем участие в Intel® Perceptual Computing Challenge Phase 2. Это будет много работы, но оно того стоит. У меня есть четкое представление что нужно и как сделать в программе, как должен выглядеть результат и как и где это будет использоваться. Нас еще ждет общение с ребятами из Skype. Возможно будет что-то еще. Все еще только начинается :-)

Большое спасибо организаторам мероприятия, всем менторам, было жутко интересно и очень полезно. Спасибо!