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:
- Sklonuj repozytorium git za pomocą tego polecenia:
git clone https://github.com/google-ai-edge/mediapipe-samples
- 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:
- GestureRecognizerHelper.kt – inicjuje moduł rozpoznawania gestów i obsługuje model oraz wybiera przedstawicieli.
- MainActivity.kt – implementuje aplikację, w tym wywołuje funkcje
GestureRecognizerHelper
iGestureRecognizerResultsAdapter
. - GestureRecognizerResultsAdapter.kt – obsługuje i formatuje wyniki.
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"] |
|
|
|
customGesturesClassifierOptions |
Opcje konfigurowania działania klasyfikatora gestów niestandardowych. |
|
|
|
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
iz
. Współrzędnex
iy
są normalizowane do wartości [0,0, 1,0] odpowiednio do szerokości i wysokości obrazu. Współrzędnaz
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łaniaz
jest mniej więcej zbliżona do skalix
.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
iz
, 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.