Zadanie MediaPipe Gesture Recognizer umożliwia rozpoznawanie gestów dłoni w czasie rzeczywistym. Wyniki rozpoznawania gestów dłoni oraz punkty orientacyjne dłoni wykrywanych dłoni. Te instrukcje pokazują, jak używać rozpoznawania gestów w aplikacjach na iOS.
Aby zobaczyć to zadanie w działaniu, 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 podstawowe wdrożenie aplikacji rozpoznawania gestów na iOS. Przykład używa kamery na fizycznym urządzeniu z iOS do ciągłego wykrywania gestów dłoni. Może też używać obrazów i filmów z galerii urządzenia do statycznego wykrywania gestów.
Możesz użyć tej aplikacji jako punktu wyjścia do tworzenia własnej aplikacji na iOS lub jako odniesienia podczas modyfikowania istniejącej aplikacji. Przykładowy kod rozpoznawania gestów jest hostowany na GitHub.
Pobieranie kodu
Z tych instrukcji 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, aby używać rzadkiego sprawdzania, dzięki czemu będziesz mieć tylko pliki przykładowej aplikacji rozpoznawania gestów:
cd mediapipe-samples git sparse-checkout init --cone git sparse-checkout set examples/gesture_recognizer/ios/
Po utworzeniu lokalnej wersji przykładowego kodu możesz zainstalować bibliotekę zadań MediaPipe, otworzyć projekt za pomocą Xcode i uruchomić aplikację. Instrukcje znajdziesz w przewodniku konfiguracji na iOS.
Kluczowe komponenty
Te pliki zawierają kluczowy kod aplikacji przykładowej rozpoznawania gestów:
- GestureRecognizerService.swift inicjuje rozpoznawanie gestów, obsługuje wybór modelu i wykonuje wnioskowanie na danych wejściowych.
- CameraViewController.swift: implementuje interfejs użytkownika w trybie podglądu na żywo z kamery i wizualizuje wyniki.
- MediaLibraryViewController.swift implementuje interfejs użytkownika dla trybu wprowadzania statycznych obrazów i plików wideo oraz wizualizuje wyniki.
Konfiguracja
W tej sekcji opisaliśmy najważniejsze kroki konfigurowania środowiska programistycznego i projektów kodu na potrzeby używania usługi Rozpoznawanie gestów. Ogólne informacje o konfigurowaniu środowiska programistycznego do korzystania z zadań MediaPipe, w tym wymagania dotyczące wersji platformy, znajdziesz w przewodniku konfiguracji dla iOS.
Zależności
Rozpoznawanie gestów korzysta z biblioteki MediaPipeTasksVision
, którą należy zainstalować za pomocą CocoaPods. Biblioteka jest zgodna z aplikacją w języku Swift i Objective-C i nie wymaga dodatkowej konfiguracji językowej.
Instrukcje instalacji CocoaPods na macOS znajdziesz w przewodniku instalacji CocoaPods.
Instrukcje tworzenia Podfile
z podstawowymi komponentami potrzebnymi do działania aplikacji znajdziesz w artykule Korzystanie z CocoaPods.
Dodaj podproces MediaPipeTasksVision w pliku Podfile
, używając tego kodu:
target 'MyGestureRecognizerApp' do
use_frameworks!
pod 'MediaPipeTasksVision'
end
Jeśli Twoja aplikacja zawiera cele testów jednostkowych, dodatkowe informacje o konfigurowaniu Podfile
znajdziesz w przewodniku konfiguracji na iOS.
Model
Zadanie MediaPipe Gesture Recognizer wymaga wytrenowanego modelu, który jest zgodny z tym zadaniem. Więcej informacji o dostępnych wytrenowanych modelach usługi Rozpoznawanie gestów znajdziesz w sekcji Modele w omówieniu zadania.
Wybierz i pobierz model, a następnie dodaj go do katalogu projektu za pomocą Xcode. Instrukcje dodawania plików do projektu Xcode znajdziesz w artykule Zarządzanie plikami i folderami w projekcie Xcode.
Użyj właściwości BaseOptions.modelAssetPath
, aby określić ścieżkę do modelu w pakiecie aplikacji. Przykład kodu znajdziesz w następnej sekcji.
Tworzenie zadania
Zadaniem rozpoznawania gestów możesz utworzyć, wywołując jedną z jego funkcji inicjujących. Inicjalizator GestureRecognizer(options:)
może przyjmować wartości opcji konfiguracji.
Jeśli nie potrzebujesz rozpoznawania gestów zainicjowanego za pomocą niestandardowych opcji konfiguracji, możesz użyć funkcji inicjalizującej GestureRecognizer(modelPath:)
, aby utworzyć rozpoznawanie gestów z opcjami domyślnymi. Więcej informacji o opcjach konfiguracji znajdziesz w artykule Omówienie konfiguracji.
Zadanie rozpoznawania gestów obsługuje 3 typy danych wejściowych: obrazy, pliki wideo i transmisje na żywo. Domyślnie GestureRecognizer(modelPath:)
inicjuje zadanie dotyczące zdjęć statycznych. Jeśli chcesz, aby zadanie zostało zainicjowane w celu przetworzenia plików wideo lub transmisji na żywo, użyj parametru GestureRecognizer(options:)
, aby określić tryb działania filmu lub transmisji na żywo. Tryb transmisji na żywo wymaga też dodatkowej opcji konfiguracji gestureRecognizerLiveStreamDelegate
, która umożliwia modułowi rozpoznawania gestów asynchroniczne przesyłanie wyników rozpoznawania gestów do delegata.
Aby dowiedzieć się, jak utworzyć zadanie i przeprowadzić wnioskowanie, wybierz kartę odpowiadającą trybowi działania.
Swift
import MediaPipeTasksVision let modelPath = Bundle.main.path(forResource: "gesture_recognizer", ofType: "task") let options = GestureRecognizerOptions() options.baseOptions.modelAssetPath = modelPath options.runningMode = .image options.minHandDetectionConfidence = minHandDetectionConfidence options.minHandPresenceConfidence = minHandPresenceConfidence options.minTrackingConfidence = minHandTrackingConfidence options.numHands = numHands let gestureRecognizer = try GestureRecognizer(options: options)
import MediaPipeTasksVision let modelPath = Bundle.main.path(forResource: "gesture_recognizer", ofType: "task") let options = GestureRecognizerOptions() options.baseOptions.modelAssetPath = modelPath options.runningMode = .video options.minHandDetectionConfidence = minHandDetectionConfidence options.minHandPresenceConfidence = minHandPresenceConfidence options.minTrackingConfidence = minHandTrackingConfidence options.numHands = numHands let gestureRecognizer = try GestureRecognizer(options: options)
import MediaPipeTasksVision // Class that conforms to the `GestureRecognizerLiveStreamDelegate` protocol and // implements the method that the gesture recognizer calls once it finishes // performing recognizing hand gestures in each input frame. class GestureRecognizerResultProcessor: NSObject, GestureRecognizerLiveStreamDelegate { func gestureRecognizer( _ gestureRecognizer: GestureRecognizer, didFinishRecognition result: GestureRecognizerResult?, timestampInMilliseconds: Int, error: Error?) { // Process the gesture recognizer result or errors here. } } let modelPath = Bundle.main.path( forResource: "gesture_recognizer", ofType: "task") let options = GestureRecognizerOptions() options.baseOptions.modelAssetPath = modelPath options.runningMode = .liveStream options.minHandDetectionConfidence = minHandDetectionConfidence options.minHandPresenceConfidence = minHandPresenceConfidence options.minTrackingConfidence = minHandTrackingConfidence options.numHands = numHands // Assign an object of the class to the `gestureRecognizerLiveStreamDelegate` // property. let processor = GestureRecognizerResultProcessor() options.gestureRecognizerLiveStreamDelegate = processor let gestureRecognizer = try GestureRecognizer(options: options)
Objective-C
@import MediaPipeTasksVision; NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"gesture_recognizer" ofType:@"task"]; MPPGestureRecognizerOptions *options = [[MPPGestureRecognizerOptions alloc] init]; options.baseOptions.modelAssetPath = modelPath; options.runningMode = MPPRunningModeImage; options.minHandDetectionConfidence = minHandDetectionConfidence options.minHandPresenceConfidence = minHandPresenceConfidence options.minTrackingConfidence = minHandTrackingConfidence options.numHands = numHands MPPGestureRecognizer *gestureRecognizer = [[MPPGestureRecognizer alloc] initWithOptions:options error:nil];
@import MediaPipeTasksVision; NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"gesture_recognizer" ofType:@"task"]; MPPGestureRecognizerOptions *options = [[MPPGestureRecognizerOptions alloc] init]; options.baseOptions.modelAssetPath = modelPath; options.runningMode = MPPRunningModeVideo; options.minHandDetectionConfidence = minHandDetectionConfidence options.minHandPresenceConfidence = minHandPresenceConfidence options.minTrackingConfidence = minHandTrackingConfidence options.numHands = numHands MPPGestureRecognizer *gestureRecognizer = [[MPPGestureRecognizer alloc] initWithOptions:options error:nil];
@import MediaPipeTasksVision; // Class that conforms to the `MPPGestureRecognizerLiveStreamDelegate` protocol // and implements the method that the gesture recognizer calls once it finishes // performing gesture recognition on each input frame. @interface APPGestureRecognizerResultProcessor : NSObject@end @implementation APPGestureRecognizerResultProcessor - (void)gestureRecognizer:(MPPGestureRecognizer *)gestureRecognizer didFinishRecognitionWithResult:(MPPGestureRecognizerResult *)gestureRecognizerResult timestampInMilliseconds:(NSInteger)timestampInMilliseconds error:(NSError *)error { // Process the gesture recognizer result or errors here. } @end NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"gesture_recognizer" ofType:@"task"]; MPPGestureRecognizerOptions *options = [[MPPGestureRecognizerOptions alloc] init]; options.baseOptions.modelAssetPath = modelPath; options.runningMode = MPPRunningModeLiveStream; options.minHandDetectionConfidence = minHandDetectionConfidence options.minHandPresenceConfidence = minHandPresenceConfidence options.minTrackingConfidence = minHandTrackingConfidence options.numHands = numHands // Assign an object of the class to the `gestureRecognizerLiveStreamDelegate` // property. APPGestureRecognizerResultProcessor *processor = [APPGestureRecognizerResultProcessor new]; options.gestureRecognizerLiveStreamDelegate = processor; MPPGestureRecognizer *gestureRecognizer = [[MPPGestureRecognizer alloc] initWithOptions:options error:nil];
Opcje konfiguracji
W tym zadaniu dostępne są te opcje konfiguracji aplikacji na iOS:
Nazwa opcji | Opis | Zakres wartości | Wartość domyślna | |
---|---|---|---|---|
runningMode |
Ustawia tryb działania zadania. Dostępne są 3 tryby: OBRAZ: tryb dla pojedynczych obrazów wejściowych. FILM: tryb dekodowanych klatek filmu. LIVE_STREAM: tryb transmisji na żywo danych wejściowych, takich jak dane z kamery. W tym trybie należy wywołać metodę resultListener, aby skonfigurować odbiornik, który będzie asynchronicznie odbierał wyniki. W tym trybie gestureRecognizerLiveStreamDelegate musi być ustawiony jako instancja klasy, która implementuje GestureRecognizerLiveStreamDelegate , aby otrzymywać wyniki asynchronicznego rozpoznawania gestów.
|
{RunningMode.image, RunningMode.video, RunningMode.liveStream } |
RunningMode.image |
|
num_hands |
Maksymalna liczba dłoni, które może wykryć GestureRecognizer , to
|
Any integer > 0 |
1 |
|
min_hand_detection_confidence |
Minimalny wynik ufności wykrywania dłoni, który jest uznawany za udany w przypadku modelu wykrywania dłoni. | 0.0 - 1.0 |
0.5 |
|
min_hand_presence_confidence |
Minimalny wynik ufności obecności ręki w modelu wykrywania punktów orientacyjnych ręki. W trybie wideo i w trybie transmisji na żywo usługi rozpoznawania gestów, jeśli wskaźnik ufności obecności ręki z modelu punktów orientacyjnych ręki jest poniżej tego progu, uruchamia model wykrywania dłoni. W przeciwnym razie do określenia lokalizacji dłoni(dłoni) w celu wykrywania punktów orientacyjnych używany jest lekki algorytm śledzenia dłoni. | 0.0 - 1.0 |
0.5 |
|
min_tracking_confidence |
Minimalny wynik ufności śledzenia dłoni, który jest uznawany za udany. To próg współczynnika podobieństwa ramki ograniczającej między dłońmi w bieżącej i ostatniej ramie. W trybie wideo i strumień w rozpoznawaniu gestów, jeśli śledzenie zawiedzie, rozpoznawanie gestów uruchamia wykrywanie ręki. W przeciwnym razie wykrywanie dłoni zostanie pominięte. | 0.0 - 1.0 |
0.5 |
|
canned_gestures_classifier_options |
Opcje konfiguracji zachowania klasyfikatora gotowych gestów. Gotowe gesty: ["None", "Closed_Fist", "Open_Palm", "Pointing_Up", "Thumb_Down", "Thumb_Up", "Victory", "ILoveYou"] |
|
|
|
custom_gestures_classifier_options |
Opcje konfiguracji zachowania klasyfikatora niestandardowych gestów. |
|
|
|
result_listener |
Ustawia odbiornik wyników w celu asynchronicznego otrzymywania wyników klasyfikacji, gdy rozpoznawacz gestów jest w trybie transmisji na żywo.
Można go używać tylko wtedy, gdy tryb działania ma wartość LIVE_STREAM . |
ResultListener |
Nie dotyczy | Nie dotyczy |
Gdy tryb działania jest ustawiony na „transmisja na żywo”, usługa rozpoznawania gestów wymaga dodatkowej opcji konfiguracji gestureRecognizerLiveStreamDelegate
, która umożliwia asynchroniczne rozpoznawanie gestów.
Delegat musi zaimplementować metodę gestureRecognizer(_:didFinishRecognition:timestampInMilliseconds:error:)
, którą usługa rozpoznawania gestów wywołuje po przetworzeniu wyników rozpoznawania gestów w każdej klatce.
Nazwa opcji | Opis | Zakres wartości | Wartość domyślna |
---|---|---|---|
gestureRecognizerLiveStreamDelegate |
Umożliwia usługom rozpoznawania gestów asynchroniczne otrzymywanie wyników rozpoznawania gestów w trybie transmisji na żywo. Klasa, której instancja jest ustawiona w tej właściwości, musi implementować metodę gestureRecognizer(_:didFinishRecognition:timestampInMilliseconds:error:) . |
Nie dotyczy | Nie ustawiono |
Przygotuj dane
Przed przekazaniem go do usługi rozpoznawania gestów musisz przekonwertować podany obraz lub ramkę na obiekt MPImage
. MPImage
obsługuje różne typy formatów obrazów iOS i może ich używać w dowolnym trybie działania do wnioskowania. Więcej informacji o MPImage
znajdziesz w dokumentacji interfejsu MPImage API.
Wybierz format obrazu iOS na podstawie przypadku użycia i trybułu działania wymaganego przez aplikację.MPImage
obsługuje formaty obrazów iOS UIImage
, CVPixelBuffer
i CMSampleBuffer
.
UIImage
Format UIImage
jest odpowiedni do tych trybów działania:
Obrazy: obrazy z pakietu aplikacji, galerii użytkownika lub systemu plików sformatowane jako obrazy
UIImage
można przekształcić w obiektMPImage
.Filmy: użyj narzędzia AVAssetImageGenerator, aby wyodrębnić klatki wideo do formatu CGImage, a następnie przekonwertuj je na obrazy
UIImage
.
// Load an image on the user's device as an iOS `UIImage` object. // Convert the `UIImage` object to a MediaPipe's Image object having the default // orientation `UIImage.Orientation.up`. let image = try MPImage(uiImage: image)
// Load an image on the user's device as an iOS `UIImage` object. // Convert the `UIImage` object to a MediaPipe's Image object having the default // orientation `UIImageOrientationUp`. MPImage *image = [[MPPImage alloc] initWithUIImage:image error:nil];
Przykład inicjalizuje MPImage
z domyślnym ułożeniem UIImage.Orientation.Up. Możesz zainicjować MPImage
dowolną z obsługiwanych wartości UIImage.Orientation. Rozpoznawanie gestów nie obsługuje orientacji lustrzanych, takich jak .upMirrored
, .downMirrored
, .leftMirrored
, .rightMirrored
.
Więcej informacji o UIImage
znajdziesz w dokumentacji UIImage dla deweloperów Apple.
CVPixelBuffer
Format CVPixelBuffer
jest odpowiedni do aplikacji, które generują klatki i korzystają z ramy CoreImage na iOS do przetwarzania.
Format CVPixelBuffer
jest odpowiedni do tych trybów działania:
Obrazy: aplikacje, które generują obrazy
CVPixelBuffer
po przetworzeniu ich za pomocą interfejsuCoreImage
w iOS, mogą być wysyłane do rozpoznawacza gestów w trybie uruchamiania obrazu.Filmy: ramki wideo można przekształcić w format
CVPixelBuffer
do przetwarzania, a następnie wysłać do rozpoznawania gestów w trybie wideo.transmisja na żywo: aplikacje korzystające z aparatu iOS do generowania klatek mogą zostać przekonwertowane do formatu
CVPixelBuffer
na potrzeby przetwarzania przed wysłaniem do rozpoznawacza gestów w trybie transmisji na żywo.
// Obtain a CVPixelBuffer. // Convert the `CVPixelBuffer` object to a MediaPipe's Image object having the default // orientation `UIImage.Orientation.up`. let image = try MPImage(pixelBuffer: pixelBuffer)
// Obtain a CVPixelBuffer. // Convert the `CVPixelBuffer` object to a MediaPipe's Image object having the // default orientation `UIImageOrientationUp`. MPImage *image = [[MPPImage alloc] initWithUIImage:image error:nil];
Więcej informacji o CVPixelBuffer
znajdziesz w dokumentacji dla deweloperów Apple dotyczącej CVPixelBuffer.
CMSampleBuffer
Format CMSampleBuffer
przechowuje próbki multimediów o jednolitym typie i jest odpowiedni do uruchamiania transmisji na żywo. Ramki na żywo z kamer iOS są asynchronicznie dostarczane w formacie CMSampleBuffer
przez AVCaptureVideoDataOutput.
// Obtain a CMSampleBuffer. // Convert the `CMSampleBuffer` object to a MediaPipe's Image object having the default // orientation `UIImage.Orientation.up`. let image = try MPImage(sampleBuffer: sampleBuffer)
// Obtain a `CMSampleBuffer`. // Convert the `CMSampleBuffer` object to a MediaPipe's Image object having the // default orientation `UIImageOrientationUp`. MPImage *image = [[MPPImage alloc] initWithSampleBuffer:sampleBuffer error:nil];
Więcej informacji o CMSampleBuffer
znajdziesz w dokumentacji CMSampleBuffer dla deweloperów Apple.
Uruchamianie zadania
Aby uruchomić rozpoznawanie gestów, użyj metody recognize()
odpowiedniej do przypisanego trybu działania:
- Statyczny obraz:
recognize(image:)
- Film:
recognize(videoFrame:timestampInMilliseconds:)
- Transmisja na żywo:
recognizeAsync(image:timestampInMilliseconds:)
Poniższe przykłady kodu pokazują podstawowe przykłady uruchamiania rozpoznawacza gestów w tych trybach:
Swift
let result = try gestureRecognizer.recognize(image: image)
let result = try gestureRecognizer.recognize( videoFrame: image, timestampInMilliseconds: timestamp)
try gestureRecognizer.recognizeAsync( image: image, timestampInMilliseconds: timestamp)
Objective-C
MPPGestureRecognizerResult *result = [gestureRecognizer recognizeImage:mppImage error:nil];
MPPGestureRecognizerResult *result = [gestureRecognizer recognizeVideoFrame:image timestampInMilliseconds:timestamp error:nil];
BOOL success = [gestureRecognizer recognizeAsyncImage:image timestampInMilliseconds:timestamp error:nil];
Przykładowy kod umożliwia użytkownikowi przełączanie się między trybami przetwarzania, które mogą nie być wymagane w Twoim przypadku.
Pamiętaj:
W trybie wideo lub transmisji na żywo musisz też przekazać zadaniu rozpoznawania gestów sygnaturę czasową ramki wejściowej.
W trybie obrazu lub filmu zadanie rozpoznawania gestów blokuje bieżący wątek, dopóki nie zakończy przetwarzania obrazu wejściowego lub ramki. Aby uniknąć blokowania bieżącego wątku, przeprowadź przetwarzanie w wątku tła za pomocą frameworków iOS Dispatch lub NSOperation.
W trybie transmisji na żywo zadanie wykrywania gestów zwraca wynik natychmiast i nie blokuje bieżącego wątku. Po przetworzeniu każdego klatki wejściowej wywołuje metodę
gestureRecognizer(_:didFinishRecognition:timestampInMilliseconds:error:)
z wynikiem rozpoznawania gestów. Rozpoznawanie gestów wywołuje tę metodę asynchronicznie w dedykowanej kolejce wysyłania asynchronicznego. Aby wyświetlić wyniki w interfejsie użytkownika, prześlij je do kolejki głównej po przetworzeniu. Jeśli funkcjarecognizeAsync
zostanie wywołana, gdy zadanie rozpoznawania gestów jest zajęte przetwarzaniem innego kadru, funkcja ta zignoruje nowy element danych.
Obsługa i wyświetlanie wyników
Po przeprowadzeniu wnioskowania zadanie rozpoznawania gestów zwraca dane GestureRecognizerResult
, które zawierają punkty orientacyjne dłoni w współrzędnych obrazu, punkty orientacyjne dłoni w współrzędnych świata, rękę(lewą lub prawą) oraz kategorie gestów wykrytych dłoni.
Poniżej znajdziesz przykład danych wyjściowych z tego zadania:
Wynik GestureRecognizerResult
zawiera 4 komponenty, z których każdy jest tablicą, a każdy element zawiera wykryty wynik dla jednej wykrytej ręki.
Ręka dominująca
Ręka określa, czy wykryta ręka jest lewą czy prawą.
Gesty
Kategorie gestów wykryte w wykrytych rękach.
Punkty orientacyjne
Jest 21 punktów orientacyjnych dłoni, z których każdy składa się ze współrzędnych
x
,y
iz
. współrzędnex
iy
są normalizowane do zakresu [0,0, 1,0] odpowiednio według szerokości i wysokości obrazu; Współrzędnaz
reprezentuje głębokość punktu orientacyjnego, przy czym punktem wyjścia jest głębokość na wysokości nadgarstka. Im mniejsza wartość, tym obiektyw jest bliżej zabytku. Wielkośćz
używa mniej więcej tej samej skali cox
.Punkty orientacyjne na świecie
21 punktów orientacyjnych dłoni jest też przedstawionych w współrzędnych światowych. Każdy punkt orientacyjny składa się z wartości
x
,y
iz
, które reprezentują rzeczywiste współrzędne 3D w metrach z początkiem w geometrycznym środku 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 widać wizualizację danych wyjściowych zadania: