
Рано или поздно карантин закончится, и жители городов смогут снова покидать дома. Но уже сейчас становится ясно, что месяцы самоизоляции не пройдут бесследно. Наши привычки из жизни до карантина изменятся, и окружающему миру придется под это подстраиваться.
Экономический кризис станет двигателем быстрой адаптации изменений: компании, которые первыми поймут, как дать пользователям дополнительную ценность или удобство, окажутся в топах. Перед IT-индустрией будет масса челленджей. И в этом материале мы поделимся своим решением одной из проблем нового мира. Но обо всем по порядку.
Люди уже переосмыслили то, как они контактируют с общедоступными поверхностями: одни надевают перчатки, другие протирают все санитайзером. Мы стали более осознанно нажимать кнопки в лифте и браться за дверные ручки. Но не во всех случаях помогают перчатки, и не всегда можно обойтись локтем вместо руки: нам по-прежнему нужно вводить пин-код в банкомате и брать талончик в терминале.
Попытки сделать удобное бесконтактное управление экранами с помощью жестов предпринимались множество раз. Но всегда стояли какие-то ограничения по их внедрению: требовались периферийные устройства (Intel RealSense, Leap Motion) или утомительная настройка под отдельного пользователя (Npointer).
Но сегодня алгоритмы машинного обучения помогут решить эти проблемы. В этом материале мы пошагово продемонстрируем, как настроить управление экраном с помощью жестов и обычной вебкамеры.
Отображение интерфейса и видео
Программа будет работать в браузере, поэтому в будущем оформим ее как расширение для Chrome. Сперва разворачиваем локально верстку. Чтобы протестировать гипотезу, хватит самого простого списка с кнопками.
В правом верхнем углу размещаем блок для отображения видео с камеры.

Для передачи потока данных с web камеры в элемент видео используем TypeScript.

Готово, видео есть!
Скроллинг страницы
Раз мы решили, что трогать клавиатуру и мышь — это плодить всякие бактерии, то воспользуемся лицом. Для начала определяем его положение в пространстве.
Чтобы получить 3D-маппинг лица в пространстве воспользуемся библиотекой Facemesh, о которой писали в мартовском дайджесте.
C Facemash мы можем получить координату любой точки на нашем лице, а значит, простой наклон головы можно использовать для скроллинга.
В идеале хотелось бы дать пользователю возможность пролистывать страницу направлением взгляда, но данная библиотека не предоставляет таких данных. Значит, будем работать с тем, что уже есть.
Для этого по точкам в 3D пространстве определяем степень наклона головы: берем две точки координат на оси Z так, чтобы при наклоне головы вперед или назад их положение заметно разнилось.

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

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

Нас интересует массив mesh. Как видим, это просто куча неразмеченных координат точек в пространстве. Как же понять, какая точка за что отвечает? Ответ находим в документации.

Теперь мы знаем координаты точек и можем вычислить разность Z координат, и найти headPitch. Вообще pitch это угол, а в нашем случае это, скорее, коэффициент.

Соединяем куски кода вместе. Теперь мы можем пролистывать страницу без рук:

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

Здесь код похож на то, что мы делали ра��ьше, но посложнее.

HandEstimator работает аналогично FaceEstimator.
Здесь все не так просто, браузеры обычно не позволяют так просто двигать курсор программно. Поэтому напишем свой указатель — HandCursor.

Пример создания и движения курсора:

Дальше нужно подружить палец с экраном. Для это преобразуем относительные координаты пальца в абсолютные координаты экрана.

И проверим, как это работает:

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


Так удается сгладить путь курсора:

Определение жестов
Теперь осталось научиться определять жесты для выполнения более сложных действий, таких как, например, клик и вызов контекстного меню.
Библиотека не поддерживает определение жестов. Это придется делать самостоятельно. Добавим определение жеста pointer.
Как определить жест с картинки ниже?
— Указательный палец выше всех;
— Остальные пальцы согнуты.

Чтобы определять жест, рассчитываем длины 2 векторов:
— От основания ладони до верхней фаланги указательного пальца;
— От основания ладони до верхней фаланги среднего пальца.
Используем формулу вычисления расстояния между двумя точками A(xa, ya, za) и B(xb, yb, zb) в пространстве:
AB = √(xb — xa)2 + (yb — ya)2 + (zb — za)2
Определяем жест pointer, если (firstLenght / secondLenght) > 1.5.

Ссылка на репозиторий с кодом: github.com/worksolutions/screen-gesture-control
Заключение
Вот так буквально за один день можно реализовать жизнеспособную альтернативу
антивандальным клавиатурам. Конечно, это только начало. Еще нужно оптимизировать код, поработать над определением жестов и реализовать маппинг жестов с API браузеров, но уже виден потенциал этой технологии.
В подготовке материала помогал заросший на самоизоляции dpereverza. Именно его лицо вы видели на всех демонстрациях. Уверен, Дима с радостью ответит на любые комментарии и вопросы. На этом все, спасибо за внимание!
