Распознаем жесты камерой или моя работа для Swift Student Challenge 2021

Привет, меня зовут Тамерлан, я разработчик iOS-приложений и студент Astana IT University. Я использую Swift для разработки мобильных приложений с 16 лет и мне всегда был интересен Swift Student Challenge, который ежегодно проводится перед WWDC, но мне не удавалось принять участие в прошлых конкурсах. Причины были разные, в основном все упиралось в недостаток времени, в этом году я решил взять быка за рога и принять участие.

Предыстория

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

О проекте

При запуске приложения, вас встретит меню с двумя режимами игры: запомнить последовательность и повторить последовательность.

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

Режим повторить последовательность представляет собой игру, в которой вам нужно успеть показать жест, который находится в фокусе. Механика игры вышла подобной механике популярной ритм-игре Just Dance

Ну и конечно, так как это все-таки игра, в каждом режиме по мере прохождения сложность игры будет соответственно увеличиваться.

Как это работает?

Алгоритм

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

Отсюда будет логично спросить, как же определить открыт палец или нет? Ответ кроется в фалангах наших пальцев, сравнивая расстояние от каждой фаланги до запястья мы можем с легкостью понять вытянут ли палец. Допустим, если рассматривать указательный палец, при вытянутом состоянии расстояние от дистальной фаланги до запястья больше чем расстояние от проксимальной фаланги. Немаловажно рассмотреть большой палец отдельно, ведь расстояний от фаланг недостаточно для определения вытянутости, ведь при закрытии большого пальца нам потребуется его сильно согнуть, чтобы алгоритм определил его как закрытый. Чтобы решить эту проблему нам нужно определить значение угла, образованного проксимальной и пястной фалангами и сравнивать его с каким-то значением, в моем случае я выяснил что сравнение с углом 170 градусов в большинстве случаев дает точное значение.

Реализация

Как же все это реализовать? Vision. Начиная с iOS 11 нам доступен этот зверь, который дает возможность пользоваться алгоритмами компьютерного зрения. На WWDC20 показали, что теперь фреймворк умеет в распознавание рук и поз тела, что теперь значительно облегчает нам жизнь. 

Настроив сессию, создав реквест и подписавшись под делегат, мы начинаем получать распознанные данные о руке, которую увидел девайс. Данные являются экземпляром класса VNHumanHandPoseObservation, который в свою очередь имеет метод recognizedPoints(_:). Метод ожидает получить название группы точек нужных суставов пальца, так как нам нужно получить точки всех суставов, мы передаем VNHumanHandPoseObservation.JointsGroupName.all. Наконец мы получаем словарь, где ключем является название сустава, а значением – точка.

На картинке снизу мы можем увидеть как Apple назвали каждый сустав и опираясь на это мы достаем из словаря все распознанные точки. Но вот незадача, тип точки не знакомый нам CGPoint, а какой-то VNRecognizedPoint. Дело в том что этот класс представляет нормализированную распознанную точку на картинке или видео и так как этот класс является наследником VNDetectedPoint, который в свою очередь наследуется от VNPoint, мы можем использовать такие переменные суперклассов как confidence : VNConfidence(определяет точность распознанной точки) и location : CGPoint(определяет положение точки в пространстве). Пугаться, что свойство confidence имеет тип VNConfidence не стоит, ведь это просто алиас над Float.

В итоге, имея все это, мы можем с легкостью собрать все точки с условием confidence > 0.3, в какой-нибудь массив и дальше работать уже с ним. Важно заметить что location дает нам значение в координатной системе алгоритмов фреймворка Vision, там ось Y находится в левом нижнем углу, следовательно чтобы преобразовать в координаты AVFoundation(ось Y в левом верхнем углу), нам нужно перевернуть координату Y перед тем как записать в массив. В итоге при записи в массив мы получим что-то в этом духе:

var filteredPoints = points.filter { $0.value.confidence > 0.3 }.mapValues { value in
    return CGPoint(x: value.location.x, y: 1 - value.location.y)
}

На этом приключения с получением точки еще не заканчиваются, теперь же нам предстоит эту точку опять конвертировать, но уже из AVFoundation координат в UIKit координаты. Благо для это есть функция слоя камеры, layerPointConverted(fromCaptureDevicePoint:), которая возвращает нам желанную точку.

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

После всех этих манипуляций мы наконец-то должны иметь точки, с которыми можно уже работать по алгоритму, который я объяснял ранее. А чтобы найти расстояние между точками и образованный угол точками(для большого пальца) можно использовать любые математические формулы, которые вам нравятся.

Итог

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

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

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

Надеюсь статья была полезна какой-то части коммьюнити, буду рад любому фидбеку!

Comments 1

Login to leave a comment

Идея очень крутая! Тамерлан, Вы молодец!

Reply