Руководство по распознаванию жестов для Android

Задача «Распознаватель жестов MediaPipe» позволяет распознавать жесты рук в реальном времени и предоставляет результаты распознанных жестов рук и ориентиры обнаруженных рук. В этих инструкциях показано, как использовать Распознаватель жестов с приложениями Android. Пример кода, описанный в этой инструкции, доступен на GitHub .

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

Пример кода

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

Вы можете использовать это приложение в качестве отправной точки для создания собственного приложения для Android или обращаться к нему при изменении существующего приложения. Пример кода Распознавателя жестов размещен на GitHub .

Загрузите код

Следующие инструкции показывают, как создать локальную копию кода примера с помощью инструмента командной строки git .

Чтобы загрузить пример кода:

  1. Клонируйте репозиторий git, используя следующую команду:
    git clone https://github.com/google-ai-edge/mediapipe-samples
    
  2. При желании настройте свой экземпляр git на использование разреженной проверки, чтобы у вас были только файлы для примера приложения Распознаватель жестов:
    cd mediapipe
    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"]
  • Язык отображаемых имен: языковой стандарт, используемый для отображаемых имен, указанных в метаданных модели TFLite, если таковые имеются.
  • Максимальное количество результатов: максимальное количество возвращаемых результатов классификации с наибольшим количеством баллов. Если < 0, будут возвращены все доступные результаты.
  • Порог оценки: балл, ниже которого результаты отклоняются. Если установлено значение 0, будут возвращены все доступные результаты.
  • Список разрешенных категорий: список разрешенных названий категорий. Если поле не пусто, результаты классификации, категории которых нет в этом наборе, будут отфильтрованы. Взаимоисключающие со списком запретов.
  • Список запрещенных категорий: список запрещенных имен категорий. Если не пусто, результаты классификации, категория которых находится в этом наборе, будут отфильтрованы. Взаимоисключающее со списком разрешений.
    • Локаль отображаемых имен: any string
    • Максимальное количество результатов: any integer
    • Порог оценки: 0.0-1.0
    • Список разрешенных категорий: vector of strings
    • Список запрещенных категорий: vector of strings
    • Язык отображаемых имен: "en"
    • Максимальное количество результатов: -1
    • Порог оценки: 0
    • Белый список категорий: пусто
    • Список запрещенных категорий: пустой
    customGesturesClassifierOptions Параметры настройки поведения классификатора пользовательских жестов.
  • Язык отображаемых имен: языковой стандарт, используемый для отображаемых имен, указанных в метаданных модели TFLite, если таковые имеются.
  • Максимальное количество результатов: максимальное количество возвращаемых результатов классификации с наибольшим количеством баллов. Если < 0, будут возвращены все доступные результаты.
  • Порог оценки: балл, ниже которого результаты отклоняются. Если установлено значение 0, будут возвращены все доступные результаты.
  • Список разрешенных категорий: список разрешенных названий категорий. Если поле не пусто, результаты классификации, категории которых нет в этом наборе, будут отфильтрованы. Взаимоисключающее со списком запретов.
  • Список запрещенных категорий: список запрещенных имен категорий. Если не пусто, результаты классификации, категория которых находится в этом наборе, будут отфильтрованы. Взаимоисключающее со списком разрешений.
    • Локаль отображаемых имен: any string
    • Максимальное количество результатов: any integer
    • Порог оценки: 0.0-1.0
    • Список разрешенных категорий: vector of strings
    • Список запрещенных категорий: vector of strings
    • Язык отображения отображаемых имен: "en"
    • Максимальное количество результатов: -1
    • Порог оценки: 0
    • Белый список категорий: пусто
    • Список запрещенных категорий: пустой
    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 .