Как стать автором
Обновить

Как я занял третье место в конкурсе Telegram и выиграл $ 2 000

Время на прочтение4 мин
Количество просмотров8.1K

Краткая предыстория.

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

Задача: Создать кроссплатформенный модуль на C++ для корректировки внешности. Создать приложение для iOS или Android, которое демонстрирует работу этого модуля, в режиме реального времени преобразовывая видео из фронтальной камеры.

Подобная функциональность реализована в таких приложениях, как Instagram и Snapchat, и может подразумевать выравнивание кожи лица, скрытие дефектов кожи, при необходимости, увеличение глаз, уменьшение носа, подбородка или ушей, то есть приведение пропорций лица к универсальным стандартам привлекательности. Модуль должен работать корректно независимо от пола, возраста и цвета кожи. Результат преобразования должен восприниматься зрителем как естественный, не бросающийся в глаза по сравнению с оригиналом. Цель — создать едва заметный фильтр, который, позволил бы пользователям представлять «лучшую версию себя» собеседнику.

Размышления, стоило ли участвовать?

Порог вхождения (сужу по своему опыту), довольно высокий, но ведь дорогу осилит идущий, не так ли? Сразу скажу, что опыта до этого конкурса в этой теме у меня было немного. Отдаленно слышал об ARKit и Metal. Ну и ранее участвовал в конкурсе, в котором использовал CoreML для нахождения и вырезания области на статичных картинках.

С чего бы начать?

Для участия в этой задаче я изучил несколько статей об ARKit и также примеров на GitHub с более-менее работоспособными вещами. Но максимум, что удалось за это время — создать или поверхностную маску для работы в режиме реального времени или использовать заранее сгенерированные модели для наложения, например, глаз, или носа. Для этого я изучил статьи здесь:

Сайт Apple

Распознавание лиц с помощью фронтальной камеры, наложение виртуального контента и анимация мимики в режиме реального времени.

Пример у Рея Вендерлиха

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

Пример работы алгоритма
Пример работы алгоритма

Github

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

Пример с перечислением доступных «‎секторов»
Пример с перечислением доступных «‎секторов»

Заранее были понятны и сложности при таком подходе: количество строго ограничено сейчас, 1220, но может быть изменено позже. Поэтому даже временное решение может оказаться нерабочим в будущих версиях iOS, также его сложно назвать кроссплатформенным, как того требовало условие задачи.

ARFaceGeometry имеет 1220 вершин, и индекс 9 находится на носу, например.

Пример с перечислением доступных «‎секторов».‎

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

Билатеральный фильтр

По условиям, или по тому, как я их понял, я не могу разглашать исходный код. Но с радостью поделюсь ресурсами, которые натолкнули меня на ход размышлений.

Пример на сайте Apple

В этом примере показано, как применить фильтр с розовым цветом линзы с помощью Core Image и Metal. Он также показывает, как визуализировать глубину и сглаженный эффект глубины поверх потока захвата с помощью фильтра оттенков серого.

Пример работы алгоритма на сайте Apple
Пример работы алгоритма на сайте Apple

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

Metal рендерит продвинутую 3D-графику и выполняет параллельные вычисления с использованием графических процессоров (GPU).

Высокопроизводительная обработка изображений может быть выполнена в iOS/macOS благодаря Metal. Также известно, что изображения представляются в виде матрицы. Каждый элемент матрицы представляет собой цвет каждого пикселя.

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

Здесь:

Весовое значение W постоянно в гауссовском фильтре, но зависит от положения целевого пикселя, gid в металическом, в билатеральном.

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

Фильтр Гаусса не учитывает информацию о яркости, поэтому края могут теряться.

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

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

Результат работы алгоритма
Результат работы алгоритма

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

Если вам информация показалось интересной, вы можете поддержать меня, подписавшись на мой канал в Телеграме. Спасибо за прочтение и хорошего дня!

Теги:
Хабы:
Всего голосов 12: ↑10 и ↓2+9
Комментарии3

Публикации