راهنمای تشخیص نشانه های دستی برای iOS

وظیفه MediaPipe Hand Landmarker به شما این امکان را می دهد که نشانه های دست ها را در یک تصویر تشخیص دهید. این دستورالعمل ها به شما نشان می دهد که چگونه از Hand Landmarker با برنامه های iOS استفاده کنید. نمونه کد شرح داده شده در این دستورالعمل ها در GitHub موجود است.

برای اطلاعات بیشتر در مورد قابلیت‌ها، مدل‌ها و گزینه‌های پیکربندی این کار، به نمای کلی مراجعه کنید.

نمونه کد

کد مثال MediaPipe Tasks یک پیاده سازی اساسی از یک برنامه Hand Landmarker برای iOS است. این مثال از دوربین یک دستگاه فیزیکی iOS برای شناسایی نشانه های دستی در یک جریان ویدیویی مداوم استفاده می کند. این برنامه همچنین می تواند نشانه های دست را در تصاویر و ویدیوهای گالری دستگاه تشخیص دهد.

می‌توانید از برنامه به‌عنوان نقطه شروع برای برنامه iOS خودتان استفاده کنید، یا هنگام تغییر یک برنامه موجود به آن مراجعه کنید. کد نمونه Hand Landmarker در GitHub میزبانی می شود.

کد را دانلود کنید

دستورالعمل های زیر به شما نشان می دهد که چگونه با استفاده از ابزار خط فرمان git یک کپی محلی از کد مثال ایجاد کنید.

برای دانلود کد نمونه:

  1. با استفاده از دستور زیر مخزن git را کلون کنید:

    git clone https://github.com/google-ai-edge/mediapipe-samples
    
  2. به صورت اختیاری، نمونه git خود را برای استفاده از پرداخت پراکنده پیکربندی کنید، بنابراین فقط فایل‌های برنامه نمونه 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 را راه‌اندازی می‌کند، انتخاب مدل را مدیریت می‌کند و استنتاج را روی داده‌های ورودی اجرا می‌کند.
  • CameraViewController.swift : رابط کاربری را برای حالت ورودی تغذیه زنده دوربین پیاده سازی می کند و نتایج را به تصویر می کشد.
  • MediaLibraryViewController.swift : رابط کاربری را برای حالت ورودی تصویر ثابت و فایل ویدیویی پیاده‌سازی می‌کند و نتایج را به‌صورت تصویری نمایش می‌دهد.

راه اندازی

این بخش مراحل کلیدی را برای راه اندازی محیط توسعه و پروژه های کد برای استفاده از Hand Landmarker شرح می دهد. برای اطلاعات کلی در مورد تنظیم محیط توسعه خود برای استفاده از وظایف MediaPipe، از جمله الزامات نسخه پلت فرم، به راهنمای راه اندازی برای iOS مراجعه کنید.

وابستگی ها

Hand Landmarker از کتابخانه MediaPipeTasksVision استفاده می کند که باید با استفاده از CocoaPods نصب شود. این کتابخانه با هر دو برنامه Swift و Objective-C سازگار است و نیازی به تنظیمات زبان خاصی ندارد.

برای دستورالعمل‌های نصب CocoaPods در macOS، به راهنمای نصب CocoaPods مراجعه کنید. برای دستورالعمل‌های نحوه ایجاد یک Podfile با پادهای لازم برای برنامه خود، به استفاده از CocoaPods مراجعه کنید.

با استفاده از کد زیر، MediaPipeTasksVision pod را در Podfile اضافه کنید:

target 'MyHandLandmarkerApp' do
  use_frameworks!
  pod 'MediaPipeTasksVision'
end

اگر برنامه شما شامل اهداف تست واحد است، برای اطلاعات بیشتر در مورد راه‌اندازی Podfile ، به راهنمای تنظیم برای iOS مراجعه کنید.

مدل

وظیفه MediaPipe Hand Landmarker به یک مدل آموزش دیده نیاز دارد که با این کار سازگار باشد. برای اطلاعات بیشتر در مورد مدل‌های آموزش‌دیده موجود برای Hand Landmarker، بخش مدل‌های نمای کلی کار را ببینید.

یک مدل را انتخاب و دانلود کنید و با استفاده از Xcode آن را به فهرست پروژه خود اضافه کنید. برای دستورالعمل‌هایی درباره نحوه افزودن فایل‌ها به پروژه Xcode، به مدیریت فایل‌ها و پوشه‌ها در پروژه Xcode خود مراجعه کنید.

از ویژگی BaseOptions.modelAssetPath برای تعیین مسیر مدل در بسته نرم افزاری خود استفاده کنید. برای مثال کد، بخش بعدی را ببینید.

کار را ایجاد کنید

می توانید با فراخوانی یکی از اولیه سازهای آن، وظیفه Hand Landmarker را ایجاد کنید. آغازگر HandLandmarker(options:) مقادیری را برای گزینه های پیکربندی می پذیرد.

اگر به یک Hand Landmarker که با گزینه های پیکربندی سفارشی شده مقداردهی شده است نیاز ندارید، می توانید از مقداردهی اولیه HandLandmarker(modelPath:) برای ایجاد یک Hand Landmarker با گزینه های پیش فرض استفاده کنید. برای اطلاعات بیشتر درباره گزینه‌های پیکربندی، به نمای کلی پیکربندی مراجعه کنید.

وظیفه Hand Landmarker از 3 نوع داده ورودی پشتیبانی می‌کند: تصاویر ثابت، فایل‌های ویدیویی و جریان‌های ویدیویی زنده. به طور پیش فرض، HandLandmarker(modelPath:) یک کار را برای تصاویر ثابت مقداردهی اولیه می کند. اگر می‌خواهید کار شما برای پردازش فایل‌های ویدیویی یا پخش جریانی زنده ویدیویی اولیه شود، از HandLandmarker(options:) برای تعیین حالت اجرای ویدیو یا پخش زنده استفاده کنید. حالت پخش زنده همچنین به گزینه پیکربندی handLandmarkerLiveStreamDelegate اضافی نیاز دارد، که به Hand Landmarker امکان می‌دهد نتایج نشانگر دستی را به صورت ناهمزمان به نماینده ارائه دهد.

برای مشاهده نحوه ایجاد کار و اجرای استنتاج، برگه مربوط به حالت در حال اجرا خود را انتخاب کنید.

سویفت

تصویر

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)
    

هدف-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 حداقل امتیاز اطمینان برای امتیاز حضور دست در مدل تشخیص نقطه عطف دست. در حالت ویدیو و حالت پخش زنده، اگر امتیاز اطمینان حضور دست از مدل نقطه عطف دست کمتر از این آستانه باشد، Hand Landmarker مدل تشخیص کف دست را فعال می‌کند. در غیر این صورت، یک الگوریتم ردیابی دست سبک، مکان دست(ها) را برای تشخیص نشانه های بعدی تعیین می کند. 0.0 - 1.0 0.5
minTrackingConfidence حداقل امتیاز اطمینان برای ردیابی دست که موفقیت آمیز در نظر گرفته شود. این آستانه جعبه محدود کننده IoU بین دست ها در فریم فعلی و آخرین فریم است. در حالت ویدیو و حالت جریان از Hand Landmarker، اگر ردیابی ناموفق باشد، Hand Landmarker تشخیص دست را فعال می‌کند. در غیر این صورت، تشخیص دست را نادیده می گیرد. 0.0 - 1.0 0.5
result_listener شنونده نتیجه را طوری تنظیم می کند که وقتی نشانگر دستی در حالت پخش زنده است، نتایج تشخیص را به صورت ناهمزمان دریافت کند. فقط زمانی قابل اجراست که حالت اجرا روی LIVE_STREAM تنظیم شده باشد N/A N/A

هنگامی که حالت اجرا روی پخش زنده تنظیم می شود، Hand Landmarker به گزینه پیکربندی handLandmarkerLiveStreamDelegate اضافی نیاز دارد، که به Hand Landmarker امکان می دهد نتایج تشخیص نشانه های دستی را به صورت ناهمزمان ارائه دهد. نماینده باید روش handLandmarker(_:didFinishDetection:timestampInMilliseconds:error:) را اجرا کند، که Hand Landmarker پس از پردازش نتایج تشخیص نشانه های دستی برای هر فریم آن را فراخوانی می کند.

نام گزینه توضیحات محدوده ارزش مقدار پیش فرض
handLandmarkerLiveStreamDelegate نشانگر دست را فعال می کند تا نتایج تشخیص نقطه عطف دست را به صورت ناهمزمان در حالت پخش زنده دریافت کند. کلاسی که نمونه آن روی این ویژگی تنظیم شده است باید متد handLandmarker(_:didFinishDetection:timestampInMilliseconds:error:) پیاده سازی کند. قابل اجرا نیست تنظیم نشده است

داده ها را آماده کنید

قبل از ارسال آن به Hand Landmarker، باید تصویر یا فریم ورودی را به یک شی MPImage تبدیل کنید. MPImage از انواع فرمت های تصویر iOS پشتیبانی می کند و می تواند از آنها در هر حالت در حال اجرا برای استنتاج استفاده کند. برای اطلاعات بیشتر در مورد MPImage ، به MPImage API مراجعه کنید.

یک قالب تصویر iOS را بر اساس مورد استفاده خود و حالت اجرای مورد نیاز برنامه خود انتخاب کنید. MPImage فرمت‌های تصویر UIImage ، CVPixelBuffer ، و CMSampleBuffer را می‌پذیرد.

تصویر UII

فرمت UIImage برای حالت‌های اجرای زیر مناسب است:

  • تصاویر: تصاویر از یک بسته نرم افزاری، گالری کاربر یا سیستم فایل فرمت شده به عنوان تصاویر UIImage را می توان به یک شی MPImage تبدیل کرد.

  • ویدیوها: از AVAssetImageGenerator برای استخراج فریم های ویدیو به فرمت CGImage استفاده کنید، سپس آنها را به تصاویر 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)
    

هدف-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 پشتیبانی شده مقداردهی کنید. Hand Landmarker از جهت‌های آینه‌ای مانند .upMirrored ، .downMirrored ، .leftMirrored ، .rightMirrored پشتیبانی نمی‌کند.

برای اطلاعات بیشتر در مورد UIImage ، به UIImage Apple Developer Documentation مراجعه کنید.

CVPixelBuffer

فرمت CVPixelBuffer برای برنامه هایی که فریم تولید می کنند و از چارچوب CoreImage iOS برای پردازش استفاده می کنند، مناسب است.

فرمت CVPixelBuffer برای حالت‌های اجرای زیر مناسب است:

  • تصاویر: برنامه هایی که تصاویر CVPixelBuffer پس از مدتی پردازش با استفاده از چارچوب CoreImage iOS تولید می کنند، می توانند در حالت اجرای تصویر به Hand Landmarker ارسال شوند.

  • فیلم‌ها: فریم‌های ویدیو را می‌توان برای پردازش به فرمت CVPixelBuffer تبدیل کرد و سپس در حالت ویدیو به Hand Landmarker فرستاد.

  • پخش زنده: برنامه هایی که از دوربین iOS برای تولید فریم استفاده می کنند ممکن است قبل از ارسال به Hand Landmarker در حالت پخش زنده به فرمت CVPixelBuffer برای پردازش تبدیل شوند.

سویفت

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

هدف-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 مراجعه کنید.

CMSampleBuffer

فرمت CMSampleBuffer نمونه‌های رسانه‌ای از یک نوع رسانه یکنواخت را ذخیره می‌کند و برای حالت پخش زنده مناسب است. قاب‌های زنده دوربین‌های iOS به‌صورت ناهمزمان در قالب CMSampleBuffer توسط iOS 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)
    

هدف-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، از متد detect() مخصوص حالت اجرای اختصاص داده شده استفاده کنید:

  • تصویر ثابت: detect(image:)
  • ویدیو: detect(videoFrame:timestampInMilliseconds:)
  • پخش زنده: detectAsync(image:timestampInMilliseconds:)

سویفت

تصویر

let result = try handLandmarker.detect(image: image)
    

ویدئو

let result = try handLandmarker.detect(
    videoFrame: image,
    timestampInMilliseconds: timestamp)
    

پخش زنده

try handLandmarker.detectAsync(
  image: image,
  timestampInMilliseconds: timestamp)
    

هدف-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 Landmarker پیاده سازی هر یک از این حالت ها را با جزئیات بیشتری نشان می دهد. کد مثال به کاربر اجازه می دهد تا بین حالت های پردازش جابجا شود، که ممکن است برای مورد استفاده شما مورد نیاز نباشد.

به موارد زیر توجه کنید:

  • هنگام اجرا در حالت ویدیو یا حالت پخش زنده، باید مهر زمانی فریم ورودی را نیز به کار Hand Landmarker ارائه دهید.

  • هنگامی که در حالت تصویر یا ویدیو اجرا می شود، وظیفه Hand Landmarker رشته فعلی را مسدود می کند تا زمانی که پردازش تصویر یا فریم ورودی به پایان برسد. برای جلوگیری از مسدود کردن رشته فعلی، پردازش را در یک رشته پس‌زمینه با استفاده از چارچوب‌های iOS Dispatch یا NSOperation انجام دهید.

  • وقتی در حالت پخش زنده اجرا می‌شود، وظیفه Hand Landmarker بلافاصله برمی‌گردد و رشته فعلی را مسدود نمی‌کند. پس از پردازش هر فریم ورودی، متد handLandmarker(_:didFinishDetection:timestampInMilliseconds:error:) با نتیجه نشانگر دست فراخوانی می کند. Hand Landmarker این روش را به صورت ناهمزمان در یک صف پخش سریال اختصاصی فراخوانی می کند. برای نمایش نتایج در رابط کاربری، پس از پردازش نتایج، نتایج را به صف اصلی ارسال کنید. اگر زمانی که وظیفه 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)

تصویر زیر تصویری از خروجی کار را نشان می دهد: