![](https://habrastorage.org/webt/lz/mz/6j/lzmz6jivpnk_zuybem3xjjodb-m.png)
Рано или поздно карантин закончится, и жители городов смогут снова покидать дома. Но уже сейчас становится ясно, что месяцы самоизоляции не пройдут бесследно. Наши привычки из жизни до карантина изменятся, и окружающему миру придется под это подстраиваться.
Экономический кризис станет двигателем быстрой адаптации изменений: компании, которые первыми поймут, как дать пользователям дополнительную ценность или удобство, окажутся в топах. Перед IT-индустрией будет масса челленджей. И в этом материале мы поделимся своим решением одной из проблем нового мира. Но обо всем по порядку.
Люди уже переосмыслили то, как они контактируют с общедоступными поверхностями: одни надевают перчатки, другие протирают все санитайзером. Мы стали более осознанно нажимать кнопки в лифте и браться за дверные ручки. Но не во всех случаях помогают перчатки, и не всегда можно обойтись локтем вместо руки: нам по-прежнему нужно вводить пин-код в банкомате и брать талончик в терминале.
Попытки сделать удобное бесконтактное управление экранами с помощью жестов предпринимались множество раз. Но всегда стояли какие-то ограничения по их внедрению: требовались периферийные устройства (Intel RealSense, Leap Motion) или утомительная настройка под отдельного пользователя (Npointer).
Но сегодня алгоритмы машинного обучения помогут решить эти проблемы. В этом материале мы пошагово продемонстрируем, как настроить управление экраном с помощью жестов и обычной вебкамеры.
Отображение интерфейса и видео
Программа будет работать в браузере, поэтому в будущем оформим ее как расширение для Chrome. Сперва разворачиваем локально верстку. Чтобы протестировать гипотезу, хватит самого простого списка с кнопками.
В правом верхнем углу размещаем блок для отображения видео с камеры.
![](https://habrastorage.org/webt/pj/lk/xc/pjlkxc6hrmjsiu7gu0ool4e9oiq.png)
Для передачи потока данных с web камеры в элемент видео используем TypeScript.
![](https://habrastorage.org/webt/pm/s5/ek/pms5ekwd0opoq1pnd_d0tqc6cjq.png)
Готово, видео есть!
Скроллинг страницы
Раз мы решили, что трогать клавиатуру и мышь — это плодить всякие бактерии, то воспользуемся лицом. Для начала определяем его положение в пространстве.
Чтобы получить 3D-маппинг лица в пространстве воспользуемся библиотекой Facemesh, о которой писали в мартовском дайджесте.
C Facemash мы можем получить координату любой точки на нашем лице, а значит, простой наклон головы можно использовать для скроллинга.
В идеале хотелось бы дать пользователю возможность пролистывать страницу направлением взгляда, но данная библиотека не предоставляет таких данных. Значит, будем работать с тем, что уже есть.
Для этого по точкам в 3D пространстве определяем степень наклона головы: берем две точки координат на оси Z так, чтобы при наклоне головы вперед или назад их положение заметно разнилось.
![](https://habrastorage.org/webt/ku/4e/k8/ku4ek8f7zxi8sqkeugfknqgaebu.png)
Выбрав эти две точки, мы сможем определить, куда произошел наклон головы (тангаж), а также сказать, насколько сильно наклонена голова по значению разности Z координат.
После этого остается только написать интерфейс взаимодействия с web-браузером. Для скролла web-страницы используем TypeScript.
Мы будем пользоваться собственной оберткой над этой библиотекой. Она даст нам возможность работать с ней через событийную модель.
![](https://habrastorage.org/webt/w2/ne/lr/w2nelr3cefl_o8hk4kdo5hhplnu.png)
Для того, чтобы найти headPitch, нужно побольше узнать о данных из этой библиотеки. Если загрузить в нее снимок лица, то мы получим следующее.
![](https://habrastorage.org/webt/2n/qz/qg/2nqzqgohxtlml4djpbwp-z85xyy.png)
Нас интересует массив mesh. Как видим, это просто куча неразмеченных координат точек в пространстве. Как же понять, какая точка за что отвечает? Ответ находим в документации.
![](https://habrastorage.org/webt/2l/f6/_j/2lf6_j0igktmih-ow8dxk0ogyvq.jpeg)
Теперь мы знаем координаты точек и можем вычислить разность Z координат, и найти headPitch. Вообще pitch это угол, а в нашем случае это, скорее, коэффициент.
![](https://habrastorage.org/webt/pe/3i/ww/pe3iwwsyd-sqkqi9cbh9vveacee.png)
Соединяем куски кода вместе. Теперь мы можем пролистывать страницу без рук:
![](https://habrastorage.org/webt/5x/d2/dh/5xd2dh8ezg_lkr3lupmuo_akek8.gif)
Управление курсором
Природа уже наделила нас отличным курсором — это наш указательный палец. Он нам и заменит мышь. К счастью, у нас есть библиотека Handpose для трекинга пальцев рук. Берем координату края верхней фаланги.
![](https://habrastorage.org/webt/xf/ev/lo/xfevlozy2qjjlxcqlbdl7mkblye.gif)
Здесь код похож на то, что мы делали раньше, но посложнее.
![](https://habrastorage.org/webt/nl/co/tr/nlcotrpmbwtmjriorbl36nhjwlo.png)
HandEstimator работает аналогично FaceEstimator.
Здесь все не так просто, браузеры обычно не позволяют так просто двигать курсор программно. Поэтому напишем свой указатель — HandCursor.
![](https://habrastorage.org/webt/ts/or/vu/tsorvuo6ke0cxgatv7r49bgtzbu.png)
Пример создания и движения курсора:
![](https://habrastorage.org/webt/e1/zr/as/e1zrasgjd5gll8ywsjrfjzmtvkg.png)
Дальше нужно подружить палец с экраном. Для это преобразуем относительные координаты пальца в абсолютные координаты экрана.
![](https://habrastorage.org/webt/hq/fj/ac/hqfjacgqaktfotz0btcm7wk1wkm.png)
И проверим, как это работает:
![](https://habrastorage.org/webt/mo/xm/1a/moxm1a4r_-5hiynyxnrpytqdjsm.gif)
Видно, что курсор дергается. Сделаем его движения более плавными. Здесь нам поможет интерполяция входных данных методом скользящего среднего.
![](https://habrastorage.org/webt/ia/t_/wk/iat_wkouitlgwfhphg9b9rxlko4.png)
![](https://habrastorage.org/webt/ye/rx/ru/yerxruskqoc_bwg-dxeqhec1gcy.png)
Так удается сгладить путь курсора:
![](https://habrastorage.org/webt/9c/s1/2g/9cs12ggosuewid_bhg7cw2hrjno.gif)
Определение жестов
Теперь осталось научиться определять жесты для выполнения более сложных действий, таких как, например, клик и вызов контекстного меню.
Библиотека не поддерживает определение жестов. Это придется делать самостоятельно. Добавим определение жеста pointer.
Как определить жест с картинки ниже?
— Указательный палец выше всех;
— Остальные пальцы согнуты.
![](https://habrastorage.org/webt/hy/en/br/hyenbr_54lu6o_3emas2qz96vog.jpeg)
Чтобы определять жест, рассчитываем длины 2 векторов:
— От основания ладони до верхней фаланги указательного пальца;
— От основания ладони до верхней фаланги среднего пальца.
Используем формулу вычисления расстояния между двумя точками A(xa, ya, za) и B(xb, yb, zb) в пространстве:
AB = v(xb — xa)2 + (yb — ya)2 + (zb — za)2
Определяем жест pointer, если (firstLenght / secondLenght) > 1.5.
![](https://habrastorage.org/webt/1i/ar/88/1iar8891cdzfvguorjdva3idevi.gif)
Ссылка на репозиторий с кодом: github.com/worksolutions/screen-gesture-control
Заключение
Вот так буквально за один день можно реализовать жизнеспособную альтернативу
антивандальным клавиатурам. Конечно, это только начало. Еще нужно оптимизировать код, поработать над определением жестов и реализовать маппинг жестов с API браузеров, но уже виден потенциал этой технологии.
В подготовке материала помогал заросший на самоизоляции dpereverza. Именно его лицо вы видели на всех демонстрациях. Уверен, Дима с радостью ответит на любые комментарии и вопросы. На этом все, спасибо за внимание!
Nattoshina
Надо со своей мышкой ходить беспроводной.