Руками не трогать! Управляем веб-страницей с помощью веб-камеры

lzmz6jivpnk_zuybem3xjjodb-m.png

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

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

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

Попытки сделать удобное бесконтактное управление экранами с помощью жестов предпринимались множество раз. Но всегда стояли какие-то ограничения по их внедрению: требовались периферийные устройства (Intel RealSense, Leap Motion) или утомительная настройка под отдельного пользователя (Npointer).

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

Отображение интерфейса и видео

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

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


pjlkxc6hrmjsiu7gu0ool4e9oiq.png

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


pms5ekwd0opoq1pnd_d0tqc6cjq.png

Готово, видео есть!

Скроллинг страницы

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

Чтобы получить 3D-маппинг лица в пространстве воспользуемся библиотекой Facemesh, о которой писали в мартовском дайджесте.

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

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

Для этого по точкам в 3D пространстве определяем степень наклона головы: берем две точки координат на оси Z так, чтобы при наклоне головы вперед или назад их положение заметно разнилось.

ku4ek8f7zxi8sqkeugfknqgaebu.png

Выбрав эти две точки, мы сможем определить, куда произошел наклон головы (тангаж), а также сказать, насколько сильно наклонена голова по значению разности Z координат.

После этого остается только написать интерфейс взаимодействия с web-браузером. Для скролла web-страницы используем TypeScript.

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

w2nelr3cefl_o8hk4kdo5hhplnu.png

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

2nqzqgohxtlml4djpbwp-z85xyy.png

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

2lf6_j0igktmih-ow8dxk0ogyvq.jpeg

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

pe3iwwsyd-sqkqi9cbh9vveacee.png

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

5xd2dh8ezg_lkr3lupmuo_akek8.gif

Управление курсором

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

xfevlozy2qjjlxcqlbdl7mkblye.gif

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

nlcotrpmbwtmjriorbl36nhjwlo.png

HandEstimator работает аналогично FaceEstimator.

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

tsorvuo6ke0cxgatv7r49bgtzbu.png

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

e1zrasgjd5gll8ywsjrfjzmtvkg.png

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

hqfjacgqaktfotz0btcm7wk1wkm.png

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

moxm1a4r_-5hiynyxnrpytqdjsm.gif

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

iat_wkouitlgwfhphg9b9rxlko4.png

yerxruskqoc_bwg-dxeqhec1gcy.png

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

9cs12ggosuewid_bhg7cw2hrjno.gif

Определение жестов

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

Библиотека не поддерживает определение жестов. Это придется делать самостоятельно. Добавим определение жеста pointer.

Как определить жест с картинки ниже?
— Указательный палец выше всех;
— Остальные пальцы согнуты.

hyenbr_54lu6o_3emas2qz96vog.jpeg

Чтобы определять жест, рассчитываем длины 2 векторов:
— От основания ладони до верхней фаланги указательного пальца;
— От основания ладони до верхней фаланги среднего пальца.

Используем формулу вычисления расстояния между двумя точками A (xa, ya, za) и B (xb, yb, zb) в пространстве:

AB = √(xb — xa)2 + (yb — ya)2 + (zb — za)2

Определяем жест pointer, если (firstLenght / secondLenght) > 1.5.


1iar8891cdzfvguorjdva3idevi.gif

Ссылка на репозиторий с кодом: github.com/worksolutions/screen-gesture-control

Заключение

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

В подготовке материала помогал заросший на самоизоляции dpereverza. Именно его лицо вы видели на всех демонстрациях. Уверен, Дима с радостью ответит на любые комментарии и вопросы. На этом все, спасибо за внимание!

© Habrahabr.ru