Рано или поздно карантин закончится, и жители городов смогут снова покидать дома. Но уже сейчас становится ясно, что месяцы самоизоляции не пройдут бесследно. Наши привычки из жизни до карантина изменятся, и окружающему миру придется под это подстраиваться.
Экономический кризис станет двигателем быстрой адаптации изменений: компании, которые первыми поймут, как дать пользователям дополнительную ценность или удобство, окажутся в топах. Перед 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. Именно его лицо вы видели на всех демонстрациях. Уверен, Дима с радостью ответит на любые комментарии и вопросы. На этом все, спасибо за внимание!
Автор: Максим Мул