Задача «Распознаватель жестов MediaPipe» позволяет распознавать жесты рук в реальном времени и предоставляет результаты распознанных жестов рук и ориентиры обнаруженных рук. В этих инструкциях показано, как использовать Распознаватель жестов с приложениями Android. Пример кода, описанный в этой инструкции, доступен на GitHub .
Вы можете увидеть эту задачу в действии, просмотрев веб-демо . Дополнительные сведения о возможностях, моделях и параметрах конфигурации этой задачи см. в разделе Обзор .
Пример кода
Пример кода задач MediaPipe — это простая реализация приложения распознавания жестов для Android. В примере используется камера на физическом устройстве Android для постоянного обнаружения жестов рук, а также могут использоваться изображения и видео из галереи устройства для статического обнаружения жестов.
Вы можете использовать это приложение в качестве отправной точки для своего собственного приложения для Android или обращаться к нему при изменении существующего приложения. Пример кода Распознавателя жестов размещен на GitHub .
Загрузите код
Следующие инструкции показывают, как создать локальную копию кода примера с помощью инструмента командной строки git .
Чтобы загрузить пример кода:
-  Клонируйте репозиторий git, используя следующую команду: git clone https://github.com/google-ai-edge/mediapipe-samples 
- При желании настройте свой экземпляр git на использование разреженной проверки, чтобы у вас были только файлы для примера приложения Распознаватель жестов: cd mediapipe-samples git sparse-checkout init --cone git sparse-checkout set examples/gesture_recognizer/android 
После создания локальной версии кода примера вы можете импортировать проект в Android Studio и запустить приложение. Инструкции см. в Руководстве по установке для Android .
Ключевые компоненты
Следующие файлы содержат ключевой код для этого примера приложения распознавания жестов рук:
- GestureRecouncerHelper.kt — инициализирует распознаватель жестов и обрабатывает выбор модели и делегата.
-  MainActivity.kt — реализует приложение, включая вызов GestureRecognizerHelperиGestureRecognizerResultsAdapter.
- GestureRecouncerResultsAdapter.kt — обрабатывает и форматирует результаты.
Настраивать
В этом разделе описаны ключевые шаги по настройке среды разработки и проектов кода специально для использования Распознаватель жестов. Общие сведения о настройке среды разработки для использования задач MediaPipe, включая требования к версии платформы, см. в руководстве по настройке для Android .
Зависимости
 Задача Распознавателя жестов использует библиотеку com.google.mediapipe:tasks-vision . Добавьте эту зависимость в файл build.gradle вашего приложения Android:
dependencies {
    implementation 'com.google.mediapipe:tasks-vision:latest.release'
}
Модель
Для задачи Распознавателя жестов MediaPipe требуется пакет обученной модели, совместимый с этой задачей. Дополнительную информацию о доступных обученных моделях для Распознаватель жестов см. в разделе «Модели» обзора задач.
Выберите и загрузите модель и сохраните ее в каталоге вашего проекта:
<dev-project-root>/src/main/assets
 Укажите путь к модели в параметре ModelAssetPath . В примере кода модель определена в файле GestureRecognizerHelper.kt :
baseOptionBuilder.setModelAssetPath(MP_RECOGNIZER_TASK)
Создать задачу
 Задача Распознавателя жестов MediaPipe использует функцию createFromOptions() для настройки задачи. Функция createFromOptions() принимает значения параметров конфигурации. Дополнительные сведения о параметрах конфигурации см. в разделе Параметры конфигурации .
Распознаватель жестов поддерживает три типа входных данных: неподвижные изображения, видеофайлы и прямые видеопотоки. При создании задачи вам необходимо указать режим работы, соответствующий вашему типу входных данных. Выберите вкладку, соответствующую вашему типу входных данных, чтобы узнать, как создать задачу и выполнить вывод.
Изображение
val baseOptionsBuilder = BaseOptions.builder().setModelAssetPath(MP_RECOGNIZER_TASK)
val baseOptions = baseOptionBuilder.build()
val optionsBuilder =
    GestureRecognizer.GestureRecognizerOptions.builder()
        .setBaseOptions(baseOptions)
        .setMinHandDetectionConfidence(minHandDetectionConfidence)
        .setMinTrackingConfidence(minHandTrackingConfidence)
        .setMinHandPresenceConfidence(minHandPresenceConfidence)
        .setRunningMode(RunningMode.IMAGE)
val options = optionsBuilder.build()
gestureRecognizer =
    GestureRecognizer.createFromOptions(context, options)
    Видео
val baseOptionsBuilder = BaseOptions.builder().setModelAssetPath(MP_RECOGNIZER_TASK)
val baseOptions = baseOptionBuilder.build()
val optionsBuilder =
    GestureRecognizer.GestureRecognizerOptions.builder()
        .setBaseOptions(baseOptions)
        .setMinHandDetectionConfidence(minHandDetectionConfidence)
        .setMinTrackingConfidence(minHandTrackingConfidence)
        .setMinHandPresenceConfidence(minHandPresenceConfidence)
        .setRunningMode(RunningMode.VIDEO)
val options = optionsBuilder.build()
gestureRecognizer =
    GestureRecognizer.createFromOptions(context, options)
    Прямая трансляция
val baseOptionsBuilder = BaseOptions.builder().setModelAssetPath(MP_RECOGNIZER_TASK)
val baseOptions = baseOptionBuilder.build()
val optionsBuilder =
    GestureRecognizer.GestureRecognizerOptions.builder()
        .setBaseOptions(baseOptions)
        .setMinHandDetectionConfidence(minHandDetectionConfidence)
        .setMinTrackingConfidence(minHandTrackingConfidence)
        .setMinHandPresenceConfidence(minHandPresenceConfidence)
        .setResultListener(this::returnLivestreamResult)
        .setErrorListener(this::returnLivestreamError)
        .setRunningMode(RunningMode.LIVE_STREAM)
val options = optionsBuilder.build()
gestureRecognizer =
    GestureRecognizer.createFromOptions(context, options)
     Реализация примера кода Распознаватель жестов позволяет пользователю переключаться между режимами обработки. Такой подход усложняет код создания задачи и может не подойти для вашего варианта использования. Вы можете увидеть этот код в функции setupGestureRecognizer() в файле GestureRecognizerHelper.kt .
Варианты конфигурации
Эта задача имеет следующие параметры конфигурации для приложений Android:
| Название опции | Описание | Диапазон значений | Значение по умолчанию | |
|---|---|---|---|---|
| runningMode | Устанавливает режим выполнения задачи. Есть три режима: ИЗОБРАЖЕНИЕ: Режим для ввода одного изображения. ВИДЕО: Режим декодированных кадров видео. LIVE_STREAM: режим прямой трансляции входных данных, например, с камеры. В этом режиме необходимо вызвать resultListener, чтобы настроить прослушиватель на асинхронное получение результатов. | { IMAGE, VIDEO, LIVE_STREAM} | IMAGE | |
| numHands | Максимальное количество рук может быть обнаружено с помощью GestureRecognizer. | Any integer > 0 | 1 | |
| minHandDetectionConfidence | Минимальный показатель достоверности, позволяющий считать обнаружение рук успешным в модели обнаружения ладоней. | 0.0 - 1.0 | 0.5 | |
| minHandPresenceConfidence | Минимальный показатель достоверности оценки присутствия руки в модели обнаружения ориентиров рук. В режиме видео и режиме прямой трансляции Распознаватель жестов, если показатель достоверности присутствия руки по модели ориентира руки ниже этого порога, активируется модель обнаружения ладони. В противном случае для определения местоположения руки (рук) для последующего обнаружения ориентиров используется упрощенный алгоритм отслеживания рук. | 0.0 - 1.0 | 0.5 | |
| minTrackingConfidence | Минимальный показатель достоверности, позволяющий считать отслеживание рук успешным. Это порог IoU ограничивающей рамки между руками в текущем кадре и последнем кадре. В режиме «Видео» и «Потоковый режим» Распознаватель жестов, если отслеживание не удается, Распознаватель жестов запускает обнаружение руки. В противном случае обнаружение руки пропускается. | 0.0 - 1.0 | 0.5 | |
| cannedGesturesClassifierOptions | Параметры настройки поведения классификатора стандартных жестов. Стандартные жесты: ["None", "Closed_Fist", "Open_Palm", "Pointing_Up", "Thumb_Down", "Thumb_Up", "Victory", "ILoveYou"] | 
 | 
 | |
| customGesturesClassifierOptions | Параметры настройки поведения классификатора пользовательских жестов. | 
 | 
 | |
| resultListener | Настраивает прослушиватель результатов на асинхронное получение результатов классификации, когда распознаватель жестов находится в режиме прямого потока. Может использоваться только в том случае, если для режима работы установлено значение LIVE_STREAM | ResultListener | Н/Д | Н/Д | 
| errorListener | Устанавливает дополнительный прослушиватель ошибок. | ErrorListener | Н/Д | Н/Д | 
Подготовьте данные
Распознаватель жестов работает с изображениями, видеофайлами и потоковым видео в реальном времени. Задача выполняет предварительную обработку входных данных, включая изменение размера, поворот и нормализацию значений.
Следующий код демонстрирует, как передать данные для обработки. Эти примеры включают подробную информацию о том, как обрабатывать данные из изображений, видеофайлов и потоков видео в реальном времени.
Изображение
import com.google.mediapipe.framework.image.BitmapImageBuilder import com.google.mediapipe.framework.image.MPImage // Convert the input Bitmap object to an MPImage object to run inference val mpImage = BitmapImageBuilder(image).build()
Видео
import com.google.mediapipe.framework.image.BitmapImageBuilder import com.google.mediapipe.framework.image.MPImage val argb8888Frame = if (frame.config == Bitmap.Config.ARGB_8888) frame else frame.copy(Bitmap.Config.ARGB_8888, false) // Convert the input Bitmap object to an MPImage object to run inference val mpImage = BitmapImageBuilder(argb8888Frame).build()
Прямая трансляция
import com.google.mediapipe.framework.image.BitmapImageBuilder import com.google.mediapipe.framework.image.MPImage // Convert the input Bitmap object to an MPImage object to run inference val mpImage = BitmapImageBuilder(rotatedBitmap).build()
 В примере кода Распознавателя жестов подготовка данных выполняется в файле GestureRecognizerHelper.kt .
Запустить задачу
 Распознаватель жестов использует recognize , recognizeForVideo и recognizeAsync для запуска логических выводов. Для распознавания жестов это включает предварительную обработку входных данных, обнаружение рук на изображении, обнаружение ориентиров рук и распознавание жестов рук по ориентирам.
Следующий код демонстрирует, как выполнить обработку с помощью модели задачи. Эти примеры включают подробную информацию о том, как обрабатывать данные из изображений, видеофайлов и потоков видео в реальном времени.
Изображение
val result = gestureRecognizer?.recognize(mpImage)
    Видео
val timestampMs = i * inferenceIntervalMs gestureRecognizer?.recognizeForVideo(mpImage, timestampMs) ?.let { recognizerResult -> resultList.add(recognizerResult) }
Прямая трансляция
val mpImage = BitmapImageBuilder(rotatedBitmap).build()
val frameTime = SystemClock.uptimeMillis()
gestureRecognizer?.recognizeAsync(mpImage, frameTime)
    Обратите внимание на следующее:
- При работе в режиме видео или режиме прямой трансляции вы также должны предоставить метку времени входного кадра задаче Распознавателя жестов.
- При работе в режиме изображения или видео задача «Распознаватель жестов» блокирует текущий поток до тех пор, пока он не завершит обработку входного изображения или кадра. Чтобы избежать блокировки пользовательского интерфейса, выполняйте обработку в фоновом потоке.
- При работе в режиме прямой трансляции задача «Распознаватель жестов» не блокирует текущий поток, а немедленно возвращается. Он будет вызывать свой прослушиватель результатов с результатом распознавания каждый раз, когда завершает обработку входного кадра. Если функция распознавания вызывается, когда задача «Распознаватель жестов» занята обработкой другого кадра, задача будет игнорировать новый входной кадр.
 В примере кода Распознавателя жестов функции recognize , recognizeForVideo и recognizeAsync определены в файле GestureRecognizerHelper.kt .
Обработка и отображение результатов
Распознаватель жестов генерирует объект результата обнаружения жестов для каждого запуска распознавания. Объект результата содержит ориентиры рук в координатах изображения, ориентиры рук в мировых координатах, направление руки (левая/правая рука) и категории жестов обнаруженных рук.
Ниже показан пример выходных данных этой задачи:
 Полученный результат GestureRecognizerResult содержит четыре компонента, каждый из которых представляет собой массив, где каждый элемент содержит обнаруженный результат одной обнаруженной руки.
- Рукава - Handedness показывает, являются ли обнаруженные руки левыми или правыми. 
- Жесты - Распознанные категории жестов обнаруженных рук. 
- Достопримечательности - Имеется 21 ручной ориентир, каждый из которых состоит из координат - x,- yи- z. Координаты- xи- yнормализуются на [0,0, 1,0] по ширине и высоте изображения соответственно. Координата- zпредставляет глубину ориентира, при этом глубина на запястье является началом координат. Чем меньше значение, тем ближе ориентир к камере. Величина- zиспользует примерно тот же масштаб, что и- x.
- Достопримечательности мира - 21 ручной ориентир также представлен в мировых координатах. Каждый ориентир состоит из - x,- yи- z, представляющих реальные трехмерные координаты в метрах с началом координат в геометрическом центре руки.
GestureRecognizerResult:
  Handedness:
    Categories #0:
      index        : 0
      score        : 0.98396
      categoryName : Left
  Gestures:
    Categories #0:
      score        : 0.76893
      categoryName : Thumb_Up
  Landmarks:
    Landmark #0:
      x            : 0.638852
      y            : 0.671197
      z            : -3.41E-7
    Landmark #1:
      x            : 0.634599
      y            : 0.536441
      z            : -0.06984
    ... (21 landmarks for a hand)
  WorldLandmarks:
    Landmark #0:
      x            : 0.067485
      y            : 0.031084
      z            : 0.055223
    Landmark #1:
      x            : 0.063209
      y            : -0.00382
      z            : 0.020920
    ... (21 world landmarks for a hand)
На следующих изображениях показана визуализация результатов задачи:

 В примере кода Распознавателя жестов класс GestureRecognizerResultsAdapter в файле GestureRecognizerResultsAdapter.kt обрабатывает результаты.