המשימה 'זיהוי ציוני דרך של ידיים' ב-MediaPipe מאפשרת לזהות את ציוני הדרך של הידיים בתמונה. בהוראות הבאות מוסבר איך להשתמש ב-Hand Landmarker עם אפליקציות ל-iOS. דוגמת הקוד שמתוארת בהוראות האלה זמינה ב-GitHub.
בסקירה הכללית תוכלו לקרוא מידע נוסף על היכולות, המודלים ואפשרויות ההגדרה של המשימה הזו.
קוד לדוגמה
קוד הדוגמה של MediaPipe Tasks הוא הטמעה בסיסית של אפליקציית Hand Landmarker ל-iOS. בדוגמה, נעשה שימוש במצלמה במכשיר iOS פיזי כדי לזהות סימני יד בשידור וידאו רציף. האפליקציה יכולה גם לזהות נקודות ציון של היד בתמונות ובסרטונים מהגלריה של המכשיר.
אפשר להשתמש באפליקציה כנקודת התחלה לאפליקציית iOS משלכם, או להיעזר בה כשמשנים אפליקציה קיימת. קוד הדוגמה של Hand Landmarker מתארח ב-GitHub.
להורדת הקוד
בהוראות הבאות מוסבר איך ליצור עותק מקומי של קוד הדוגמה באמצעות הכלי של שורת הפקודה git.
כדי להוריד את הקוד לדוגמה:
משכפלים את מאגר ה-Git באמצעות הפקודה הבאה:
git clone https://github.com/google-ai-edge/mediapipe-samples
אפשר גם להגדיר את מכונה של git כך שתשתמש ב-sparse checkout, כך שיישארו רק הקבצים של אפליקציית הדוגמה Hand Landmarker:
cd mediapipe git sparse-checkout init --cone git sparse-checkout set examples/hand_landmarker/ios/
אחרי שיוצרים גרסה מקומית של קוד הדוגמה, אפשר להתקין את ספריית המשימות של MediaPipe, לפתוח את הפרויקט באמצעות Xcode ולהפעיל את האפליקציה. להוראות, אפשר לעיין במדריך ההגדרה ל-iOS.
רכיבים מרכזיים
הקבצים הבאים מכילים את הקוד החשוב לאפליקציית הדוגמה של Hand Landmarker:
- HandLandmarkerService.swift: הפונקציה הזו מפעילה את Hand Landmarker, מטפלת בבחירת המודל ומריצה הסקת מסקנות על נתוני הקלט.
- CameraViewController.swift: הקוד הזה מטמיע את ממשק המשתמש של מצב הקלט של פיד המצלמה בשידור חי ומציג את התוצאות באופן חזותי.
- MediaLibraryViewController.swift: הקוד הזה מטמיע את ממשק המשתמש של מצב הקלט של קובצי תמונות וסרטונים סטטיים, ומציג את התוצאות באופן חזותי.
הגדרה
בקטע הזה מתוארים השלבים העיקריים להגדרת סביבת הפיתוח וקוד הפרויקטים לשימוש ב-Hand Landmarker. במדריך ההגדרה ל-iOS תוכלו לקרוא מידע כללי על הגדרת סביבת הפיתוח לשימוש במשימות MediaPipe, כולל הדרישות לגרסת הפלטפורמה.
יחסי תלות
התכונה Hand Landmarker משתמשת בספרייה MediaPipeTasksVision
, שצריך להתקין באמצעות CocoaPods. הספרייה תואמת לאפליקציות Swift וגם לאפליקציות Objective-C, ולא נדרשת הגדרה נוספת ספציפית לשפה.
הוראות להתקנת CocoaPods ב-macOS מפורטות במדריך להתקנת CocoaPods.
הוראות ליצירת Podfile
עם ה-pods הנדרשים לאפליקציה מפורטות במאמר שימוש ב-CocoaPods.
מוסיפים את ה-pod MediaPipeTasksVision ב-Podfile
באמצעות הקוד הבא:
target 'MyHandLandmarkerApp' do
use_frameworks!
pod 'MediaPipeTasksVision'
end
אם האפליקציה כוללת יעדי בדיקת יחידה, תוכלו לעיין במדריך ההגדרה ל-iOS כדי לקבל מידע נוסף על הגדרת Podfile
.
דגם
כדי לבצע את המשימה 'זיהוי נקודות ציון ביד' ב-MediaPipe, נדרש מודל מאומן שתואם למשימה הזו. מידע נוסף על המודלים המאומנים הזמינים לזיהוי נקודות ציון ביד זמין בקטע 'מודלים' שבסקירה הכללית של המשימה.
בוחרים מודל ומורידים אותו, ומוסיפים אותו לספריית הפרויקט באמצעות Xcode. הוראות להוספת קבצים לפרויקט ב-Xcode מפורטות במאמר ניהול קבצים ותיקיות בפרויקט ב-Xcode.
השתמשו במאפיין BaseOptions.modelAssetPath
כדי לציין את הנתיב למודל בקובץ האפליקציה. דוגמה לקוד מופיעה בקטע הבא.
יצירת המשימה
אפשר ליצור את המשימה Hand Landmarker על ידי קריאה לאחד מהמפעילים שלה. ה-initializer של HandLandmarker(options:)
מקבל ערכים לאפשרויות ההגדרה.
אם אתם לא צריכים ציוני דרך של יד שאתחול עם אפשרויות הגדרה מותאמות אישית, תוכלו להשתמש באתחול HandLandmarker(modelPath:)
כדי ליצור ידנית ציון דרך עם אפשרויות ברירת המחדל. למידע נוסף על אפשרויות ההגדרה, ראו סקירה כללית של ההגדרות.
המשימה 'סימון נקודות ציון ביד' תומכת ב-3 סוגי נתוני קלט: תמונות סטילס, קובצי וידאו ושידורי וידאו חיים. כברירת מחדל, HandLandmarker(modelPath:)
מאתחלת משימה לתמונות סטילס. אם רוצים שהמשימה תאופס לעיבוד קובצי וידאו או סטרימינג של וידאו בשידור חי, צריך להשתמש ב-HandLandmarker(options:)
כדי לציין את מצב ההפעלה של הסרטון או השידור החי. כדי להשתמש במצב של שידור חי, צריך גם להגדיר את האפשרות הנוספת handLandmarkerLiveStreamDelegate
, שמאפשרת ל-Hand Landmarker לשלוח את התוצאות של סימון הידיים למשתתף אחר באופן אסינכרוני.
בחרו את הכרטיסייה שתואמת למצב הריצה כדי לראות איך יוצרים את המשימה ומריצים את ההסקה.
Swift
תמונה
import MediaPipeTasksVision let modelPath = Bundle.main.path(forResource: "hand_landmarker", ofType: "task") let options = HandLandmarkerOptions() options.baseOptions.modelAssetPath = modelPath options.runningMode = .image options.minHandDetectionConfidence = minHandDetectionConfidence options.minHandPresenceConfidence = minHandPresenceConfidence options.minTrackingConfidence = minHandTrackingConfidence options.numHands = numHands let handLandmarker = try HandLandmarker(options: options)
וידאו
import MediaPipeTasksVision let modelPath = Bundle.main.path(forResource: "hand_landmarker", ofType: "task") let options = HandLandmarkerOptions() options.baseOptions.modelAssetPath = modelPath options.runningMode = .video options.minHandDetectionConfidence = minHandDetectionConfidence options.minHandPresenceConfidence = minHandPresenceConfidence options.minTrackingConfidence = minHandTrackingConfidence options.numHands = numHands let handLandmarker = try HandLandmarker(options: options)
שידור חי
import MediaPipeTasksVision // Class that conforms to the `HandLandmarkerLiveStreamDelegate` protocol and // implements the method that the hand landmarker calls once it finishes // performing landmarks detection in each input frame. class HandLandmarkerResultProcessor: NSObject, HandLandmarkerLiveStreamDelegate { func handLandmarker( _ handLandmarker: HandLandmarker, didFinishDetection result: HandLandmarkerResult?, timestampInMilliseconds: Int, error: Error?) { // Process the hand landmarker result or errors here. } } let modelPath = Bundle.main.path( forResource: "hand_landmarker", ofType: "task") let options = HandLandmarkerOptions() 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 `handLandmarkerLiveStreamDelegate` // property. let processor = HandLandmarkerResultProcessor() options.handLandmarkerLiveStreamDelegate = processor let handLandmarker = try HandLandmarker(options: options)
Objective-C
תמונה
@import MediaPipeTasksVision; NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"hand_landmarker" ofType:@"task"]; MPPHandLandmarkerOptions *options = [[MPPHandLandmarkerOptions alloc] init]; options.baseOptions.modelAssetPath = modelPath; options.runningMode = MPPRunningModeImage; options.minHandDetectionConfidence = minHandDetectionConfidence; options.minHandPresenceConfidence = minHandPresenceConfidence; options.minTrackingConfidence = minHandTrackingConfidence; options.numHands = numHands; MPPHandLandmarker *handLandmarker = [[MPPHandLandmarker alloc] initWithOptions:options error:nil];
וידאו
@import MediaPipeTasksVision; NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"hand_landmarker" ofType:@"task"]; MPPHandLandmarkerOptions *options = [[MPPHandLandmarkerOptions alloc] init]; options.baseOptions.modelAssetPath = modelPath; options.runningMode = MPPRunningModeVideo; options.minHandDetectionConfidence = minHandDetectionConfidence; options.minHandPresenceConfidence = minHandPresenceConfidence; options.minTrackingConfidence = minHandTrackingConfidence; options.numHands = numHands; MPPHandLandmarker *handLandmarker = [[MPPHandLandmarker alloc] initWithOptions:options error:nil];
שידור חי
@import MediaPipeTasksVision; // Class that conforms to the `MPPHandLandmarkerLiveStreamDelegate` protocol // and implements the method that the hand landmarker calls once it finishes // performing landmarks detection in each input frame. @interface APPHandLandmarkerResultProcessor : NSObject@end @implementation APPHandLandmarkerResultProcessor - (void)handLandmarker:(MPPHandLandmarker *)handLandmarker didFinishDetectionWithResult:(MPPHandLandmarkerResult *)handLandmarkerResult timestampInMilliseconds:(NSInteger)timestampInMilliseconds error:(NSError *)error { // Process the hand landmarker result or errors here. } @end NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"hand_landmarker" ofType:@"task"]; MPPHandLandmarkerOptions *options = [[MPPHandLandmarkerOptions 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 `handLandmarkerLiveStreamDelegate` // property. APPHandLandmarkerResultProcessor *processor = [APPHandLandmarkerResultProcessor new]; options.handLandmarkerLiveStreamDelegate = processor; MPPHandLandmarker *handLandmarker = [[MPPHandLandmarker alloc] initWithOptions:options error:nil];
אפשרויות תצורה
למשימה הזו יש את אפשרויות התצורה הבאות לאפליקציות ל-iOS:
שם האפשרות | תיאור | טווח ערכים | ערך ברירת מחדל |
---|---|---|---|
running_mode |
הגדרת מצב ההפעלה של המשימה. יש שלושה מצבים: IMAGE: המצב להזנת תמונה אחת. VIDEO: המצב של פריימים מפוענחים של סרטון. LIVE_STREAM: המצב של סטרימינג בשידור חי של נתוני קלט, למשל ממצלמה. במצב הזה, צריך להפעיל את resultListener כדי להגדיר מאזין שיקבל את התוצאות באופן אסינכרוני. במצב הזה, צריך להגדיר את handLandmarkerLiveStreamDelegate למכונה של מחלקה שמטמיעה את HandLandmarkerLiveStreamDelegate כדי לקבל את תוצאות זיהוי ציוני הדרך ביד באופן אסינכרוני.
|
{RunningMode.image, RunningMode.video, RunningMode.liveStream } |
RunningMode.image |
numHands |
המספר המקסימלי של ידיים שזוהו על ידי הגלאי של נקודות ציון ביד. | Any integer > 0 |
1 |
minHandDetectionConfidence |
ציון הסמך המינימלי כדי שזיהוי היד ייחשב כמוצלח במודל זיהוי כף היד. | 0.0 - 1.0 |
0.5 |
minHandPresenceConfidence |
דירוג האמון המינימלי של דירוג נוכחות היד במודל לזיהוי ציוני ציון ביד. במצב וידאו ובמצב שידור חי, אם דירוג האמינות של נוכחות היד ממודל ציון הנקודות ביד נמוך מהסף הזה, הכלי לזיהוי נקודות ביד מפעיל את מודל זיהוי כף היד. אחרת, אלגוריתם קל למעקב אחר הידיים קובע את המיקום שלהן לצורך זיהוי של נקודות ציון בהמשך. | 0.0 - 1.0 |
0.5 |
minTrackingConfidence |
ציון הסמך המינימלי כדי שהמעקב אחרי היד ייחשב מוצלח. זהו סף IoU של תיבת הגבול בין הידיים בפריים הנוכחי לבין הפריים האחרון. במצב וידאו ובמצב סטרימינג של Hand landmarker, אם המעקב נכשל, Hand IMAPer מפעיל זיהוי יד. אחרת, המערכת תדלג על זיהוי היד. | 0.0 - 1.0 |
0.5 |
result_listener |
מגדיר את מאזין התוצאות כך שיקבל את תוצאות הזיהוי באופן אסינכרוני כשהכלי לסימון נקודות על היד נמצא במצב של שידור חי.
רלוונטי רק כשמצב ההפעלה מוגדר כ-LIVE_STREAM |
לא רלוונטי | לא רלוונטי |
כשמגדירים את מצב ההפעלה כשידור חי, צריך להגדיר את אפשרות ההגדרה הנוספת handLandmarkerLiveStreamDelegate
ב-Hand Landmarker כדי לאפשר לו לספק את תוצאות זיהוי נקודות ציון ביד באופן אסינכרוני. משתמש שקיבל הרשאה צריך להטמיע את השיטה handLandmarker(_:didFinishDetection:timestampInMilliseconds:error:)
, ש- בהתאמה אישית קוראת לה אחרי עיבוד תוצאות הזיהוי של ציוני הדרך ידנית לכל פריים.
שם האפשרות | תיאור | טווח ערכים | ערך ברירת מחדל |
---|---|---|---|
handLandmarkerLiveStreamDelegate |
הפעלה של Hand Landmarker כדי לקבל את תוצאות זיהוי הנקודות של היד באופן אסינכרוני במצב של שידור חי. המחלקה שבה מוגדרת המופע של המאפיין הזה צריכה להטמיע את השיטה handLandmarker(_:didFinishDetection:timestampInMilliseconds:error:) . |
לא רלוונטי | לא מוגדר |
הכנת הנתונים
צריך להמיר את התמונה או את המסגרת של הקלט לאובייקט MPImage
לפני שמעבירים אותו ל-Hand Landmarker. ב-MPImage
יש תמיכה בסוגים שונים של פורמטים של תמונות ב-iOS, ותוכלו להשתמש בהם בכל מצב הרצה לצורך הסקת מסקנות. למידע נוסף על MPImage
, אפשר לעיין במאמר MPImage API.
בוחרים את פורמט התמונה ל-iOS בהתאם לתרחיש לדוגמה ולמצב ההפעלה שנדרש לאפליקציה. MPImage
תומך בפורמטים של תמונות ל-iOS UIImage
, CVPixelBuffer
ו-CMSampleBuffer
.
UIImage
הפורמט UIImage
מתאים במיוחד למצבי הריצה הבאים:
תמונות: אפשר להמיר תמונות מ-App Bundle, מגלריית משתמשים או ממערכת קבצים בפורמט
UIImage
לאובייקטMPImage
.סרטונים: משתמשים ב-AVAssetImageGenerator כדי לחלץ פריימים של סרטונים לפורמט CGImage, ולאחר מכן ממירים אותם לתמונות
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];
הדוגמה מפעילה MPImage
עם כיוון ברירת המחדל UIImage.Orientation.Up. אפשר לאתחל MPImage
עם כל אחד מהערכים הנתמכים של UIImage.Orientation. התכונה 'סימון נקודות ציון ביד' לא תומכת בכיוונים מוחזרים כמו .upMirrored
, .downMirrored
, .leftMirrored
, .rightMirrored
.
מידע נוסף על UIImage
זמין במסמכי התיעוד למפתחים של Apple בנושא UIImage.
CVPixelBuffer
הפורמט CVPixelBuffer
מתאים לאפליקציות שיוצרות פריימים ומשתמשות במסגרת CoreImage של iOS לעיבוד.
הפורמט CVPixelBuffer
מתאים במיוחד למצבי ההפעלה הבאים:
תמונות: אפליקציות שיוצרות תמונות
CVPixelBuffer
אחרי עיבוד מסוים באמצעות מסגרתCoreImage
של iOS יכולות להישלח ל-Hand Landmarker במצב 'הפעלת תמונה'.סרטונים: אפשר להמיר את הפריימים של הסרטון לפורמט
CVPixelBuffer
לצורך עיבוד, ואז לשלוח אותם ל-Hand Landmarker במצב וידאו.בשידור חי: אפליקציות שנעשה בהן שימוש במצלמת iOS ליצירת פריימים יכולות לעבור המרה לפורמט
CVPixelBuffer
לעיבוד, לפני שהן נשלחות ל-HandGuideer במצב שידור חי.
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];
מידע נוסף על CVPixelBuffer
זמין במסמכי התיעוד למפתחים של CVPixelBuffer Apple.
CMSampleBuffer
הפורמט CMSampleBuffer
שומר דוגמאות מדיה מסוג מדיה אחידה, והוא מתאים למצב ההרצה של השידור החי. פריימים חיים ממצלמות iOS נשלחים באופן אסינכרוני בפורמט CMSampleBuffer
על ידי 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];
מידע נוסף על CMSampleBuffer
זמין במסמכי העזרה למפתחים של Apple בנושא CMSampleBuffer.
הרצת המשימה
כדי להריץ את Hand landmarker, משתמשים ב-method detect()
שספציפית למצב הריצה שהוקצה:
- תמונה סטטית:
detect(image:)
- סרטון:
detect(videoFrame:timestampInMilliseconds:)
- צפייה בשידור חי:
detectAsync(image:timestampInMilliseconds:)
Swift
תמונה
let result = try handLandmarker.detect(image: image)
וידאו
let result = try handLandmarker.detect( videoFrame: image, timestampInMilliseconds: timestamp)
שידור חי
try handLandmarker.detectAsync( image: image, timestampInMilliseconds: timestamp)
Objective-C
תמונה
MPPHandLandmarkerResult *result = [handLandmarker detectInImage:image error:nil];
וידאו
MPPHandLandmarkerResult *result = [handLandmarker detectInVideoFrame:image timestampInMilliseconds:timestamp error:nil];
שידור חי
BOOL success = [handLandmarker detectAsyncInImage:image timestampInMilliseconds:timestamp error:nil];
בדוגמה של הקוד של Hand Lawer אפשר לראות בפירוט את ההטמעות של כל אחד מהמצבים האלה. קוד הדוגמה מאפשר למשתמש לעבור בין מצבי עיבוד, אבל יכול להיות שהוא לא נדרש לתרחיש לדוגמה שלכם.
שימו לב לנקודות הבאות:
כשעובדים במצב סרטון או במצב שידור חי, צריך גם לציין את חותמת הזמן של מסגרת הקלט למשימה של Hand Scoreer.
כשהיא פועלת במצב תמונה או סרטון, המשימה 'סימון נקודות על היד' חוסמת את השרשור הנוכחי עד שהיא מסיימת לעבד את התמונה או את הפריים של הקלט. כדי למנוע חסימה של השרשור הנוכחי, צריך להריץ את העיבוד בשרשור רקע באמצעות מסגרות ה-iOS Dispatch או NSOperation.
כשהיא פועלת במצב של שידור חי, המשימה 'סימון ידיים' מחזירה תשובה באופן מיידי ולא חוסמת את השרשור הנוכחי. הוא מפעיל את השיטה
handLandmarker(_:didFinishDetection:timestampInMilliseconds:error:)
עם התוצאה של זיהי הנקודות ביד אחרי עיבוד כל מסגרת קלט. ה-Hand Landmarker מפעיל את השיטה הזו באופן אסינכרוני בתור שליחה טורית ייעודי. כדי להציג תוצאות בממשק המשתמש, צריך לשלוח את התוצאות לתור הראשי אחרי עיבוד התוצאות. אם הפונקציהdetectAsync
נקראת כשמשימה של Hand Landmarker עסוקה בעיבוד של פריים אחר, Hand Landmarker מתעלם מפריים הקלט החדש.
טיפול בתוצאות והצגתן
לאחר הפעלת ההסקה, המשימה 'זיהוי ציוני דרך ביד' מחזירה את הערך HandLandmarkerResult
שמכיל את ציוני הדרך ביד בקואורדינטות התמונה, את ציוני הדרך ביד בקואורדינטות העולם ואת הצד של היד(יד ימין/יד שמאל) של הידיים שזוהו.
בהמשך מוצגת דוגמה לנתוני הפלט של המשימה הזו:
הפלט של HandLandmarkerResult
מכיל שלושה רכיבים. כל רכיב הוא מערך, שבו כל רכיב מכיל את התוצאות הבאות לגבי יד אחת שזוהתה:
יד דומיננטית
היד הדומיננטית מייצגת אם הידיים שזוהו הן יד שמאל או יד ימין.
ציוני דרך
יש 21 נקודות ציון ביד, כל אחת מורכבת מהקואורדינטות
x
, y
ו-z
. הקואורדינטותx
ו-y
מנורמלות ל-[0.0, 1.0] לפי רוחב וגובה התמונה, בהתאמה. הקואורדינטהz
מייצגת את עומק ציון הדרך, כאשר עומק פרק כף היד הוא המקור. ככל שהערך קטן יותר, כך ציון הדרך קרוב יותר למצלמה. עוצמתz
משתמשת בערך באותו סולם כמוx
.אתרים חשובים בעולם
21 נקודות הציון של היד מוצגות גם בקואורדינטות גלובליות. כל ציון דרך מורכב מ-
x
,y
ו-z
, שמייצגות קואורדינטות תלת-ממדיות בעולם האמיתי במטרים, עם המקור במרכז הגאומטרי של היד.
HandLandmarkerResult:
Handedness:
Categories #0:
index : 0
score : 0.98396
categoryName : Left
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)
בתמונה הבאה מוצגת תצוגה חזותית של הפלט של המשימה: