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 iOS.
Możesz zobaczyć, jak działa to zadanie, wyświetlając prezentację internetową. Więcej informacji na temat możliwości, modeli i opcji konfiguracji tego zadania znajdziesz w sekcji Omówienie.
Przykładowy kod
Przykładowy kod MediaPipe Tasks to podstawowa implementacja aplikacji do rozpoznawania gestów na iOS. W tym przykładzie użyto aparatu w fizycznym urządzeniu z iOS, 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 iOS 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 rozproszonego 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/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 po konfiguracji na iOS.
Kluczowe elementy
Poniższe pliki zawierają kluczowy kod dla przykładowej aplikacji Rozpoznawanie gestów:
- GestureRecognizerService.swift: inicjuje moduł rozpoznawania gestów, obsługuje wybór modelu i uruchamia wnioskowanie na danych wejściowych.
- CameraViewController.swift: implementuje interfejs użytkownika w trybie wprowadzania obrazu z kamery na żywo i wizualizuje wyniki.
- MediaLibraryViewController.swift: implementuje interfejs użytkownika trybu wejściowego plików obrazu i wideo oraz wizualizuje wyniki.
Konfiguracja
W tej sekcji opisujemy najważniejsze czynności, jakie należy wykonać, by skonfigurować środowisko programistyczne i projekty kodu tak, aby używały modułu 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 dla iOS.
Zależności
Moduł rozpoznawania gestów korzysta z biblioteki MediaPipeTasksVision
, która musi być zainstalowana przy użyciu CocoaPods. Biblioteka jest zgodna z aplikacjami Swift i Objective-C i nie wymaga dodatkowej konfiguracji pod kątem określonego języka.
Instrukcje instalowania CocoaPods w systemie macOS znajdziesz w przewodniku instalacji CocoaPods.
Instrukcje tworzenia Podfile
z podami niezbędnymi do działania aplikacji znajdziesz w artykule Korzystanie z CocoaPods.
Dodaj pod MediaPipeTasksVision w narzędziu Podfile
za pomocą tego kodu:
target 'MyGestureRecognizerApp' do
use_frameworks!
pod 'MediaPipeTasksVision'
end
Jeśli aplikacja zawiera cele testu jednostkowego, dodatkowe informacje o konfigurowaniu Podfile
znajdziesz w przewodniku konfiguracji na iOS.
Model
Zadanie rozpoznawania gestów MediaPipe wymaga wytrenowanego modelu zgodnego z tym zadaniem. Więcej informacji o dostępnych wytrenowanych modelach na potrzeby rozpoznawania gestów znajdziesz w sekcji przeglądu zadań w sekcji „Modele”.
Wybierz i pobierz model, a potem dodaj go do katalogu projektów za pomocą Xcode. Instrukcje dodawania plików do projektu Xcode znajdziesz w artykule Zarządzanie plikami i folderami w projekcie Xcode.
Aby określić ścieżkę do modelu w pakiecie aplikacji, użyj właściwości BaseOptions.modelAssetPath
. Przykładowy kod znajdziesz w następnej sekcji.
Tworzenie zadania
Zadanie rozpoznawania gestów możesz utworzyć, wywołując jeden z jego inicjatorów. Inicjator GestureRecognizer(options:)
akceptuje wartości opcji konfiguracji.
Jeśli nie potrzebujesz narzędzia do rozpoznawania gestów zainicjowanego z dostosowanymi opcjami konfiguracji, możesz użyć inicjatora GestureRecognizer(modelPath:)
, by utworzyć narzędzie do rozpoznawania 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 strumienie wideo na żywo. Domyślnie GestureRecognizer(modelPath:)
inicjuje zadanie dotyczące nieruchomych obrazów. Jeśli chcesz, aby Twoje zadanie zostało zainicjowane w celu przetworzenia plików wideo lub strumieni wideo na żywo, użyj funkcji 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 asynchronicznie dostarczanie wyników rozpoznawania gestów do przedstawicieli.
Wybierz kartę odpowiadającą Twojemu trybowi biegowemu, aby zobaczyć, jak utworzyć zadanie i uruchomić wnioskowanie.
Swift
Obraz
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)
Wideo
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)
Transmisja na żywo
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
Obraz
@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];
Wideo
@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];
Transmisja na żywo
@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
To zadanie ma te opcje konfiguracji w przypadku aplikacji na iOS:
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. W tym trybie gestureRecognizerLiveStreamDelegate musi być ustawiony na instancję klasy, która implementuje GestureRecognizerLiveStreamDelegate , aby asynchronicznie otrzymywać wyniki rozpoznawania gestów.
|
{RunningMode.image, RunningMode.video, RunningMode.liveStream } |
RunningMode.image |
|
num_hands |
GestureRecognizer może wykryć maksymalną liczbę rąk.
|
Any integer > 0 |
1 |
|
min_hand_detection_confidence |
Minimalny stopień pewności, że wykrywanie dłoni zostanie uznane za udane w modelu wykrywania dłoni. | 0.0 - 1.0 |
0.5 |
|
min_hand_presence_confidence |
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 |
|
min_tracking_confidence |
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 |
|
canned_gestures_classifier_options |
Opcje konfigurowania działania klasyfikatora gotowych gestów. Gotowe gesty to ["None", "Closed_Fist", "Open_Palm", "Pointing_Up", "Thumb_Down", "Thumb_Up", "Victory", "ILoveYou"] |
|
|
|
custom_gestures_classifier_options |
Opcje konfigurowania działania klasyfikatora gestów niestandardowych. |
|
|
|
result_listener |
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 |
Gdy tryb biegowy jest ustawiony na transmisję na żywo, narzędzie do rozpoznawania gestów wymaga dodatkowej opcji konfiguracji gestureRecognizerLiveStreamDelegate
, która umożliwia asynchronicznie dostarczanie wyników rozpoznawania gestów.
Osoba, której przekazano dostęp, musi wdrożyć metodę gestureRecognizer(_:didFinishRecognition:timestampInMilliseconds:error:)
, którą narzędzie do 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 |
Włącza funkcję rozpoznawania gestów, która asynchronicznie odbiera wyniki rozpoznawania gestów w trybie transmisji na żywo. Klasa, której instancja jest ustawiona na tę właściwość, musi implementować metodę gestureRecognizer(_:didFinishRecognition:timestampInMilliseconds:error:) . |
Nie dotyczy | Nie ustawiono |
Przygotuj dane
Przed przekazaniem obrazu wejściowego lub ramki do obiektu MPImage
musisz go przekonwertować do modułu rozpoznawania gestów. MPImage
obsługuje różne typy formatów obrazów na iOS i może ich używać w każdym trybie działania, aby wnioskować. Więcej informacji na temat MPImage
znajdziesz w interfejsie MPImage API
Wybierz format obrazu na iOS zależnie od swojego przypadku użycia i trybu uruchamiania, którego wymaga Twoja aplikacja.MPImage
akceptuje formaty obrazów UIImage
, CVPixelBuffer
i CMSampleBuffer
(iOS).
UIImage
Format UIImage
dobrze sprawdza się w tych trybach biegania:
Obrazy: obrazy z pakietu aplikacji, galerii użytkownika lub systemu plików sformatowane jako obrazy
UIImage
można przekonwertować na obiektMPImage
.Filmy: użyj narzędzia AVAssetImageGenerator, aby wyodrębnić klatki wideo do formatu CGImage, a następnie przekonwertuj je na obrazy
UIImage
.
Swift
// 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)
Objective-C
// 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];
W tym przykładzie inicjuje się MPImage
z domyślną orientacją UIImage.Orientation.Up. Możesz zainicjować MPImage
przy użyciu dowolnej z obsługiwanych wartości UIImage.Orientation. Moduł rozpoznawania gestów nie obsługuje odbicia lustrzanego w orientacji takich jak .upMirrored
,
.downMirrored
, .leftMirrored
, .rightMirrored
.
Więcej informacji na temat UIImage
znajdziesz w dokumentacji dla programistów Apple dotyczącej UIImage (w języku angielskim).
CVPixelBuffer
Format CVPixelBuffer
dobrze sprawdza się w aplikacjach, które generują ramki i wykorzystują do przetwarzania platformę CoreImage w systemie iOS.
Format CVPixelBuffer
dobrze sprawdza się w tych trybach biegania:
Obrazy: aplikacje generujące obrazy
CVPixelBuffer
po przetworzeniu przy użyciu platformyCoreImage
systemu iOS mogą być wysyłane do modułu rozpoznawania gestów w trybie uruchamiania obrazów.Filmy: klatki wideo można przekonwertować do formatu
CVPixelBuffer
, aby je przetworzyć, a potem wysłać do modułu rozpoznawania gestów w trybie wideo.transmisja na żywo: aplikacje korzystające z kamery w iOS do generowania klatek można skonwertować do formatu
CVPixelBuffer
w celu przetworzenia, zanim trafią do modułu rozpoznawania gestów w trybie transmisji na żywo.
Swift
// 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)
Objective-C
// 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 na temat CVPixelBuffer
znajdziesz w dokumentacji dla programistów Apple CVPixelBuffer.
CMSampleBuffer
Format CMSampleBuffer
przechowuje próbki multimediów jednolitego typu i dobrze sprawdza się w trybie transmisji na żywo. Klatki na żywo z kamer na iOS są przesyłane asynchronicznie w formacie CMSampleBuffer
przez system iOS AVCaptureVideoDataOutput.
Swift
// 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)
Objective-C
// 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 na temat CMSampleBuffer
znajdziesz w dokumentacji dla programistów Apple CMSampleBuffer.
Uruchamianie zadania
Aby uruchomić rozpoznawanie gestów, użyj metody recognize()
odpowiedniej dla przypisanego trybu biegowego:
- Nieruchomy obraz:
recognize(image:)
- Film:
recognize(videoFrame:timestampInMilliseconds:)
- Transmisja na żywo:
recognizeAsync(image:timestampInMilliseconds:)
Poniższe przykłady kodu pokazują podstawowe przykłady uruchamiania rozpoznawania gestów w różnych trybach biegania:
Swift
Obraz
let result = try gestureRecognizer.recognize(image: image)
Wideo
let result = try gestureRecognizer.recognize( videoFrame: image, timestampInMilliseconds: timestamp)
Transmisja na żywo
try gestureRecognizer.recognizeAsync( image: image, timestampInMilliseconds: timestamp)
Objective-C
Obraz
MPPGestureRecognizerResult *result = [gestureRecognizer recognizeImage:mppImage error:nil];
Wideo
MPPGestureRecognizerResult *result = [gestureRecognizer recognizeVideoFrame:image timestampInMilliseconds:timestamp error:nil];
Transmisja na żywo
BOOL success = [gestureRecognizer recognizeAsyncImage:image timestampInMilliseconds:timestamp error:nil];
Przykładowy kod pozwala użytkownikowi przełączać się między trybami przetwarzania, które mogą nie być wymagane w Twoim przypadku.
Uwaga:
W trybie wideo lub transmisji na żywo musisz też podać sygnaturę czasową ramki wejściowej w zadaniu Rozpoznawanie gestów.
Gdy działa w trybie obrazu lub filmu, zadanie Rozpoznawanie gestów blokuje bieżący wątek do momentu zakończenia przetwarzania obrazu lub klatki wejściowej. Aby uniknąć zablokowania bieżącego wątku, wykonaj przetwarzanie w wątku w tle za pomocą platform Dispatch lub NSOperation w systemie iOS.
W trybie transmisji na żywo zadanie rozpoznawania gestów jest natychmiast zwracane i nie blokuje bieżącego wątku. Po przetworzeniu każdej ramki wejściowej wywołuje metodę
gestureRecognizer(_:didFinishRecognition:timestampInMilliseconds:error:)
z wynikiem rozpoznawania gestów. Moduł rozpoznawania gestów wywołuje tę metodę asynchronicznie w dedykowanej szeregowej kolejce wysyłki. W przypadku wyświetlania wyników w interfejsie po ich przetworzeniu wyślij do głównej kolejki. Jeśli funkcjarecognizeAsync
zostanie wywołana, gdy zadanie Rozpoznawanie gestów jest zajęte przetwarzaniem innej ramki, moduł rozpoznawania gestów ignoruje nową ramkę wejściową.
Obsługa i wyświetlanie wyników
Po uruchomieniu wnioskowania zadanie rozpoznawania gestów zwraca wartość GestureRecognizerResult
, która zawiera punkty orientacyjne dłoni w współrzędnych obrazach, punkty orientacyjne dłoni we współrzędnych świata, ręka(lewa/prawa ręka) oraz kategorie gestów wykrytych 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: