«Лови коллег»: приложение для корпоративов в стиле Pokémon Go

—

от автора

Привет! Меня зовут Алексей, я разработчик в Битрикс24. 

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

В команде со мной были Евгений Кувалкин и Евгений Васильков.

Откуда взялась идея

На хакатонах обычно делают что-то такое, что давно хочется попробовать, но в другое почему-то не доходят руки. У меня таких идей накопилось довольно много, и «Лови коллег» была одной из них. Проголосовали внутри команды, выбрали его, начали делать.

Нам показалось, что идея хорошая: 

  • Выглядит интересно визуально.

  • Есть понятный сценарий использования — корпоративы.

  • У меня есть ML-опыт, и я понимал, что нужно, чтобы всё заработало.

Как это работает и выглядит

Мы подумали, что должно быть интересно: пользователь приезжает на общий большой корпоратив, видит коллегу и думает: «А вот это тот Вася, с которым я пару раз общался по задаче или нет?». Открывает приложение и начинает снимать незнакомых коллег. Знакомых тоже можно. А приложение показывает, кто все эти люди:

Здесь фото снято с экрана, но в реальной жизни механизм тот же — наводим камеру на лицо и снимаем

Здесь фото снято с экрана, но в реальной жизни механизм тот же — наводим камеру на лицо и снимаем

В MVP-версии получилось 3 основных сценария.

Во-первых, это авторизация. Для использования человек должен быть зарегистрирован на нашем портале Битрикс24. Само приложение на бэкенде связано с нашим порталом через вебхук.

Второй этап — фотоохота на коллег, которых пользователь встречает в реальной жизни.

Третье — сбор коллекции, как в Pokémon Go. Это библиотека уже сфотографированных и успешно распознанных коллег.

Авторизация по фотографии

Приложение заранее нужно связать с нужным порталом Битрикс24 и получали оттуда данные сотрудников и их фотографии.

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

Если в профиле вместо фотографии стоит картинка или аватара вообще нет, авторизация может не сработать. Тогда нужно загрузить нормальную фотографию в профиль, и «Лови коллег» тебя авторизует.

Как работало распознавание

Основой проекта стало несколько open source моделей.

MediaPipe на клиенте анализировал видеопоток с камеры, находил лицо и помогал подготовить кадр для отправки. 

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

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

InsightFace buffalo_l и AdaFace на пару определяли сотрудника. 

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

Если результаты расходились или сходство было недостаточным, приложение просило попробовать снова.

Каждая попытка распознавания получала уникальный ID. Если из-за сети один и тот же запрос прилетал повторно, бэкенд не запускал распознавание второй раз и не начислял очки повторно.

Смысл поиска близок к обычному RAG. То есть кусочки текста мы превращаем в точки в многомерном пространстве. В двумерном можно представить: «Девочка» вот здесь, «Собака» здесь, а «Тигр» вот здесь. Если у нас появится новая точка, мы можем определить, к какой она ближе:

Источник: medium.com

Источник: medium.com

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

Источник: medium.com

Источник: medium.com

Как составили базу фото

Для приложения использовали две категории фотографий:

  1. Актуальное фото сотрудника из профиля Битрикс24 служило исходной точкой: по нему система понимала, какому сотруднику принадлежат остальные снимки, и могла связать лицо с его ID и данными на портале.

  2. Фотографии с прошлых корпоративов. Они расширяли базу для распознавания, чтобы у каждого сотрудника было несколько снимков в разных ракурсах и условиях. Я прогнал этот датасет через модели и сопоставил фотографии с сотрудниками по их портальным фото. Уверенные совпадения система привязывала автоматически, а сомнительные я проверял вручную, если сам знал человека — подтверждал нужного человека или исправлял ошибку.

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

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

Редкие коллеги и механика Pokémon Go

У нас была механика по поиску редких коллег. Редкость там привязана к количеству пригодных фотографий человека в базе.

Например, условный Женя, у которого все фотки, когда он сидит в каком-то хитром ракурсе, и его попробуй распознай. Категории были такие:

  • 1–2 фото — Легендарный

  • 3–4 — Эпический

  • 5–7 — Редкий

  • 8–12 — Необычный

  • больше 12 — Обычный

Ещё карточкам назначались стихии: Огонь, Вода, Трава и другие. Они зависели от подразделения сотрудника: разработчики относились к Стали, продажи к Огню, поддержка к Воде. За первого пойманного сотрудника начислялось 100 очков, и в рейтинге тоже дополнительно учитывалось разнообразие собранных стихий.

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

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

Баг с Unicode

Одного из сотрудников приложение никак не хотело распознавать. Этим человеком был некий Сергей Рыжиков… генеральный директор и сооснователь компании.

Почему так получилось: в современной кодировке это имя может записываться двумя разными Unicode-последовательностями: в одном случае использовался готовый символ «й», в другом — «и» с комбинируемым надстрочным знаком. Об этом есть такая статья: «Й» вам не «и» краткое! О важности нормализации Unicode

И вот у Сергея Владимировича в портале одно написание, а в датасете почему-то появилось другое. Для программы получилось, что есть как бы два Сергея Рыжикова: у одного «й», а у другого — «и» с надстрочным знаком. Поэтому фотографии одного человека разъехались по двум идентификаторам. Новое фото было одинаково похоже на обе группы, и система считала результат неоднозначным.

Итоговые мысли после работы

Их две.

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

А игровая механика превратила технический эксперимент в вещь, которой действительно хотелось пользоваться на корпоративе.

ссылка на оригинал статьи https://habr.com/ru/articles/1099328/