Przewodnik po rozpoznaniu gestów w Androidzie

Zadanie rozpoznawania gestów MediaPipe umożliwia rozpoznawanie gestów dłoni w czasie rzeczywistym i wyświetla wyniki rozpoznawanych gestów oraz punktów orientacyjnych wykrytych dłoni. W tych instrukcjach pokazujemy, jak używać rozpoznawania gestów w aplikacjach na Androida. Przykładowy kod opisany w tych instrukcjach jest dostępny na GitHub.

Aby zobaczyć, jak działa to zadanie, obejrzyj prezentację internetową. Więcej informacji o możliwościach, modelach i opcjach konfiguracji tego zadania znajdziesz w sekcji Omówienie.

Przykładowy kod

Przykładowy kod MediaPipe Tasks to prosta implementacja aplikacji do rozpoznawania gestów na Androidzie. W tym przykładzie użyto aparatu na fizycznym urządzeniu z Androidem, aby stale wykrywać gesty dłoni, a także do statycznego wykrywania gestów za pomocą obrazów i filmów z galerii urządzenia.

Możesz użyć aplikacji jako punktu wyjścia dla własnej aplikacji na Androida lub skorzystać z niej podczas modyfikowania istniejącej aplikacji. Przykładowy kod modułu rozpoznawania gestów jest hostowany na GitHub.

Pobieranie kodu

Z instrukcji poniżej dowiesz się, jak utworzyć lokalną kopię przykładowego kodu za pomocą narzędzia wiersza poleceń git.

Aby pobrać przykładowy kod:

  1. Sklonuj repozytorium git za pomocą tego polecenia:
    git clone https://github.com/google-ai-edge/mediapipe-samples
    
  2. Opcjonalnie skonfiguruj instancję git tak, aby używała rzadkiego procesu płatności, aby mieć tylko pliki dla przykładowej aplikacji do rozpoznawania gestów:
    cd mediapipe
    git sparse-checkout init --cone
    git sparse-checkout set examples/gesture_recognizer/android
    

Po utworzeniu lokalnej wersji przykładowego kodu możesz zaimportować projekt do Android Studio i uruchomić aplikację. Instrukcje znajdziesz w przewodniku konfiguracji na Androida.

Kluczowe elementy

Poniższe pliki zawierają kluczowy kod tej przykładowej aplikacji do rozpoznawania gestów:

Konfiguracja

W tej sekcji opisujemy najważniejsze czynności, jakie należy wykonać, by skonfigurować środowisko programistyczne i projekty kodu pod kątem używania funkcji rozpoznawania gestów. Ogólne informacje o konfigurowaniu środowiska programistycznego na potrzeby zadań MediaPipe, w tym o wymaganiach dotyczących wersji platformy, znajdziesz w przewodniku konfiguracji na Androida.

Zależności

Zadanie rozpoznawania gestów używa biblioteki com.google.mediapipe:tasks-vision. Dodaj tę zależność do pliku build.gradle aplikacji na Androida:

dependencies {
    implementation 'com.google.mediapipe:tasks-vision:latest.release'
}

Model

Zadanie rozpoznawania gestów MediaPipe wymaga wytrenowanego pakietu modeli, który jest zgodny z tym zadaniem. Więcej informacji o dostępnych wytrenowanych modelach na potrzeby rozpoznawania gestów znajdziesz w sekcji poświęconej modelom na stronie z przeglądem zadań.

Wybierz i pobierz model, a następnie zapisz go w katalogu projektu:

<dev-project-root>/src/main/assets

Podaj ścieżkę modelu w parametrze ModelAssetPath. W przykładowym kodzie model jest zdefiniowany w pliku GestureRecognizerHelper.kt:

baseOptionBuilder.setModelAssetPath(MP_RECOGNIZER_TASK)

Tworzenie zadania

Zadanie rozpoznawania gestów MediaPipe korzysta z funkcji createFromOptions() do skonfigurowania zadania. Funkcja createFromOptions() akceptuje wartości opcji konfiguracji. Więcej informacji o opcjach konfiguracji znajdziesz w artykule Opcje konfiguracji.

Rozpoznawanie gestów obsługuje 3 typy danych wejściowych: obrazy, pliki wideo i strumienie wideo na żywo. Podczas tworzenia zadania musisz określić tryb działania odpowiadający typowi danych wejściowych. Wybierz kartę odpowiadającą typowi danych wejściowych, aby zobaczyć, jak utworzyć zadanie i uruchomić wnioskowanie.

Obraz

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)
    

Wideo

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)
    

Transmisja na żywo

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)
    

Przykładowa implementacja kodu przez narzędzie do rozpoznawania gestów umożliwia użytkownikowi przełączanie trybów przetwarzania. Takie podejście zwiększa złożoność kodu tworzenia zadania i może nie być odpowiednie w Twoim przypadku. Ten kod znajdziesz w funkcji setupGestureRecognizer() w pliku GestureRecognizerHelper.kt.

Opcje konfiguracji

To zadanie ma te opcje konfiguracji aplikacji na Androida:

Nazwa opcji Opis Zakres wartości Wartość domyślna
runningMode Ustawia tryb działania zadania. Są 3 tryby:

IMAGE: tryb wprowadzania pojedynczych obrazów.

WIDEO: tryb dekodowanych klatek filmu.

TRANSMISJA NA ŻYWO: tryb transmisji danych wejściowych na żywo, np. z kamery. W tym trybie należy wywołać metodę resultListener, aby skonfigurować odbiornik, który będzie odbierał wyniki asynchronicznie.
{IMAGE, VIDEO, LIVE_STREAM} IMAGE
numHands GestureRecognizer może wykryć maksymalną liczbę rąk. Any integer > 0 1
minHandDetectionConfidence Minimalny stopień pewności, że wykrywanie dłoni zostanie uznane za udane w modelu wykrywania dłoni. 0.0 - 1.0 0.5
minHandPresenceConfidence Minimalny wynik ufności wskaźnika obecności ręki w modelu wykrywania punktów orientacyjnych ręki. W trybie wideo i w trybie transmisji na żywo Modułu rozpoznawania gestów, jeśli wynik wiarygodności modelu ręki z modelu punktu orientacyjnego dłoni jest poniżej tego progu, uruchamia model wykrywania dłoni. W przeciwnym razie do określenia lokalizacji rąk używany jest uproszczony algorytm śledzenia punktów orientacyjnych. 0.0 - 1.0 0.5
minTrackingConfidence Minimalny wynik pewności, że śledzenie dłoni zostanie uznane za udane. Jest to próg interfejsu użytkownika w ramce ograniczającej między rękami w bieżącej a ostatniej klatce. W trybie wideo i trybie strumienia Modułu rozpoznawania gestów, jeśli śledzenie nie powiedzie się, rozpoznawanie gestów aktywuje wykrywanie dłoni. W przeciwnym razie wykrywanie rąk zostanie pominięte. 0.0 - 1.0 0.5
cannedGesturesClassifierOptions Opcje konfigurowania działania klasyfikatora gotowych gestów. Gotowe gesty to ["None", "Closed_Fist", "Open_Palm", "Pointing_Up", "Thumb_Down", "Thumb_Up", "Victory", "ILoveYou"]
  • Język wyświetlanych nazw: język, który ma być używany dla wyświetlanych nazw określonych za pomocą metadanych modelu TFLite (jeśli występują).
  • Maksymalna liczba wyników: maksymalna liczba najwyżej wyników do zwrócenia. Jeśli wartość jest mniejsza niż 0, zostaną zwrócone wszystkie dostępne wyniki.
  • Próg wyniku: wynik, poniżej którego wyniki są odrzucane. Jeśli ma wartość 0, zwracane są wszystkie dostępne wyniki.
  • Lista dozwolonych kategorii: lista dozwolonych nazw kategorii. Jeśli pole nie jest puste, wyniki klasyfikacji, których kategoria nie należy do tego zbioru, zostaną odfiltrowane. Wzajemnie wykluczają się z listą odrzuconych.
  • Lista odrzuconych kategorii: lista odrzuconych nazw kategorii. Jeśli pole nie jest puste, wyniki klasyfikacji, których kategoria należy do tego zbioru, zostaną odfiltrowane. Wzajemnie wykluczające się dzięki liście dozwolonych.
    • Język wyświetlanych nazw: any string
    • Maksymalna liczba wyników: any integer
    • Próg wyniku: 0.0-1.0
    • Lista dozwolonych kategorii: vector of strings
    • Lista odrzuconych kategorii: vector of strings
    • Język wyświetlanych nazw: "en"
    • Maksymalna liczba wyników: -1
    • Próg wyniku: 0
    • Lista dozwolonych kategorii: pusta
    • Lista odrzuconych kategorii: pusta
    customGesturesClassifierOptions Opcje konfigurowania działania klasyfikatora gestów niestandardowych.
  • Język wyświetlanych nazw: język, który ma być używany dla wyświetlanych nazw określonych za pomocą metadanych modelu TFLite (jeśli występują).
  • Maksymalna liczba wyników: maksymalna liczba najwyżej wyników do zwrócenia. Jeśli wartość jest mniejsza niż 0, zostaną zwrócone wszystkie dostępne wyniki.
  • Próg wyniku: wynik, poniżej którego wyniki są odrzucane. Jeśli ma wartość 0, zwracane są wszystkie dostępne wyniki.
  • Lista dozwolonych kategorii: lista dozwolonych nazw kategorii. Jeśli pole nie jest puste, wyniki klasyfikacji, których kategoria nie należy do tego zbioru, zostaną odfiltrowane. Wzajemnie wykluczają się z listą odrzuconych.
  • Lista odrzuconych kategorii: lista odrzuconych nazw kategorii. Jeśli pole nie jest puste, wyniki klasyfikacji, których kategoria należy do tego zbioru, zostaną odfiltrowane. Wzajemnie wykluczające się dzięki liście dozwolonych.
    • Język wyświetlanych nazw: any string
    • Maksymalna liczba wyników: any integer
    • Próg wyniku: 0.0-1.0
    • Lista dozwolonych kategorii: vector of strings
    • Lista odrzuconych kategorii: vector of strings
    • Język wyświetlanych nazw: "en"
    • Maksymalna liczba wyników: -1
    • Próg wyniku: 0
    • Lista dozwolonych kategorii: pusta
    • Lista odrzuconych kategorii: pusta
    resultListener Ustawia detektor wyników, aby asynchronicznie otrzymywać wyniki klasyfikacji, gdy moduł rozpoznawania gestów jest w trybie transmisji na żywo. Tego ustawienia można używać tylko wtedy, gdy tryb biegowy jest ustawiony na LIVE_STREAM ResultListener Nie dotyczy Nie dotyczy
    errorListener Ustawia opcjonalny detektor błędów. ErrorListener Nie dotyczy Nie dotyczy

    Przygotuj dane

    Rozpoznawanie gestów obsługuje obrazy, pliki wideo i transmisję wideo na żywo. To zadanie obsługuje wstępne przetwarzanie danych wejściowych, w tym zmianę rozmiaru, rotację i normalizację wartości.

    Poniższy kod pokazuje, jak przekazywać dane do przetwarzania. Obejmują one szczegółowe informacje o sposobie postępowania z danymi z obrazów, plików wideo i strumieni wideo na żywo.

    Obraz

    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()
        

    Wideo

    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()
        

    Transmisja na żywo

    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()
        

    W przykładowym kodzie modułu rozpoznawania gestów przygotowywanie danych odbywa się w pliku GestureRecognizerHelper.kt.

    Uruchamianie zadania

    Moduł rozpoznawania gestów używa do tego wnioskowania funkcji recognize, recognizeForVideo i recognizeAsync. Rozpoznawanie gestów obejmuje wstępne przetwarzanie danych wejściowych, wykrywanie rąk na zdjęciu, wykrywanie ich punktów orientacyjnych i rozpoznawanie gestów z punktów orientacyjnych.

    Poniższy kod pokazuje, jak wykonać przetwarzanie za pomocą modelu zadań. Zawierają one szczegółowe informacje na temat postępowania z danymi z obrazów, plików wideo i strumieni wideo na żywo.

    Obraz

    val result = gestureRecognizer?.recognize(mpImage)
        

    Wideo

    val timestampMs = i * inferenceIntervalMs
    
    gestureRecognizer?.recognizeForVideo(mpImage, timestampMs)
        ?.let { recognizerResult ->
            resultList.add(recognizerResult)
        }
        

    Transmisja na żywo

    val mpImage = BitmapImageBuilder(rotatedBitmap).build()
    val frameTime = SystemClock.uptimeMillis()
    
    gestureRecognizer?.recognizeAsync(mpImage, frameTime)
        

    Uwaga:

    • Gdy urządzenie działa w trybie wideo lub w trybie transmisji na żywo, musisz też w zadaniu Rozpoznawanie gestów podać sygnaturę czasową ramki wejściowej.
    • Gdy użytkownik działa w trybie obrazu lub filmu, zadanie rozpoznawania gestów zablokuje bieżący wątek do momentu zakończenia przetwarzania obrazu wejściowego lub klatki. Aby uniknąć zablokowania interfejsu, przetwarzanie odbywa się w wątku w tle.
    • W trybie transmisji na żywo zadanie Rozpoznawanie gestów nie blokuje bieżącego wątku, ale wraca natychmiast. Wywoła on detektor wyników z wynikiem rozpoznawania za każdym razem, gdy zakończy przetwarzanie ramki wejściowej. Jeśli funkcja rozpoznawania zostanie wywołana, gdy zadanie Rozpoznawanie gestów jest zajęte przetwarzaniem innej klatki, to zadanie zignoruje nową ramkę wejściową.

    W przykładowym kodzie modułu rozpoznawania gestów funkcje recognize, recognizeForVideo i recognizeAsync są zdefiniowane w pliku GestureRecognizerHelper.kt.

    Obsługa i wyświetlanie wyników

    Narzędzie do rozpoznawania gestów generuje obiekt wyniku wykrywania gestów przy każdym uruchomieniu rozpoznawania gestów. Otrzymany obiekt zawiera punkty orientacyjne dłoni we współrzędnych zdjęcia, punkty orientacyjne we współrzędnych świata, ręczność(lewa/prawa ręka) oraz kategorie wykrytej dłoni.

    Poniżej znajdziesz przykład danych wyjściowych z tego zadania:

    Wynikowy GestureRecognizerResult zawiera 4 komponenty, a każdy z nich jest tablicą, w której każdy element zawiera wykryty wynik pojedynczej wykrytej dłoni.

    • Ręka dominująca

      Ręka wskazuje, czy wykryte ręce są lewą czy prawą ręką.

    • Gesty

      Rozpoznawane kategorie gestów wykrytych dłoni.

    • Punkty orientacyjne

      Jest 21 punktów orientacyjnych wskazujących dłonie, a każdy z nich składa się ze współrzędnych x, y i z. Współrzędne x i y są normalizowane do wartości [0,0, 1,0] odpowiednio do szerokości i wysokości obrazu. Współrzędna z reprezentuje głębokość punktu orientacyjnego, przy czym głębokość na nadgarstku jest punktem początkowym. Im mniejsza wartość, tym zbliża się punkt orientacyjny do aparatu. Siła działania z jest mniej więcej zbliżona do skali x.

    • Punkty orientacyjne na świecie

      We współrzędnych świata są również przedstawione 21 punktów orientacyjnych. Każdy punkt orientacyjny składa się z elementów x, y i z, które reprezentują rzeczywiste współrzędne 3D w metrach z punktem początkowym w środku geometrycznym dłoni.

    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)
    

    Na tych obrazach pokazano wizualizację wyników zadania:

    W przykładowym kodzie modułu rozpoznawania gestów klasa GestureRecognizerResultsAdapter w pliku GestureRecognizerResultsAdapter.kt obsługuje wyniki.