ژست‌ها را با ML Kit در iOS شناسایی کنید

کیت ML دو SDK بهینه شده برای تشخیص ژست ارائه می‌دهد.

نام SDK تشخیص ژست تشخیص ژست دقیق
پیاده‌سازی دارایی‌های مربوط به آشکارساز پایه در زمان ساخت به صورت ایستا به برنامه شما متصل می‌شوند. دارایی‌های مربوط به آشکارساز دقیق، در زمان ساخت به صورت ایستا به برنامه شما متصل می‌شوند.
اندازه برنامه تا ۲۹.۶ مگابایت تا ۳۳.۲ مگابایت
عملکرد آیفون X: حدود ۴۵ فریم بر ثانیه آیفون X: حدود ۲۹ فریم بر ثانیه

امتحانش کن.

قبل از اینکه شروع کنی

  1. پادهای کیت ML زیر را در پادفایل خود قرار دهید:

    # If you want to use the base implementation:
    pod 'GoogleMLKit/PoseDetection', '8.0.0'
    
    # If you want to use the accurate implementation:
    pod 'GoogleMLKit/PoseDetectionAccurate', '8.0.0'
    
  2. پس از نصب یا به‌روزرسانی پادهای پروژه، پروژه Xcode خود را با استفاده از xcworkspace آن باز کنید. ML Kit در Xcode نسخه ۱۳.۲.۱ یا بالاتر پشتیبانی می‌شود.

۱. یک نمونه از PoseDetector ایجاد کنید

برای تشخیص حالت چهره در یک تصویر، ابتدا یک نمونه از PoseDetector ایجاد کنید و به صورت اختیاری تنظیمات آشکارساز را مشخص کنید.

گزینه‌های PoseDetector

حالت تشخیص

PoseDetector در دو حالت تشخیص عمل می‌کند. مطمئن شوید که حالتی را انتخاب می‌کنید که با مورد استفاده شما مطابقت دارد.

stream (پیش‌فرض)
آشکارساز حالت ابتدا برجسته‌ترین فرد در تصویر را تشخیص می‌دهد و سپس تشخیص حالت را اجرا می‌کند. در فریم‌های بعدی، مرحله تشخیص فرد انجام نخواهد شد مگر اینکه فرد مبهم شود یا دیگر با اطمینان بالا تشخیص داده نشود. آشکارساز حالت تلاش می‌کند تا برجسته‌ترین فرد را ردیابی کند و حالت او را در هر استنتاج برگرداند. این کار تأخیر را کاهش می‌دهد و تشخیص را روان‌تر می‌کند. از این حالت زمانی استفاده کنید که می‌خواهید حالت را در یک جریان ویدیویی تشخیص دهید.
singleImage
آشکارساز حالت، یک شخص را شناسایی کرده و سپس تشخیص حالت را اجرا می‌کند. مرحله تشخیص شخص برای هر تصویر اجرا می‌شود، بنابراین تأخیر بیشتر خواهد بود و ردیابی شخص وجود ندارد. هنگام استفاده از تشخیص حالت روی تصاویر ثابت یا جایی که ردیابی مطلوب نیست، از این حالت استفاده کنید.

گزینه‌های آشکارساز حالت را مشخص کنید:

سویفت

// Base pose detector with streaming, when depending on the PoseDetection SDK
let options = PoseDetectorOptions()
options.detectorMode = .stream

// Accurate pose detector on static images, when depending on the
// PoseDetectionAccurate SDK
let options = AccuratePoseDetectorOptions()
options.detectorMode = .singleImage

هدف-سی

// Base pose detector with streaming, when depending on the PoseDetection SDK
MLKPoseDetectorOptions *options = [[MLKPoseDetectorOptions alloc] init];
options.detectorMode = MLKPoseDetectorModeStream;

// Accurate pose detector on static images, when depending on the
// PoseDetectionAccurate SDK
MLKAccuratePoseDetectorOptions *options =
    [[MLKAccuratePoseDetectorOptions alloc] init];
options.detectorMode = MLKPoseDetectorModeSingleImage;

در نهایت، یک نمونه از PoseDetector دریافت کنید. گزینه‌هایی را که مشخص کرده‌اید، به آن بدهید:

سویفت

let poseDetector = PoseDetector.poseDetector(options: options)

هدف-سی

MLKPoseDetector *poseDetector =
    [MLKPoseDetector poseDetectorWithOptions:options];

۲. تصویر ورودی را آماده کنید

برای تشخیص حالت‌ها، برای هر تصویر یا فریم از ویدیو، مراحل زیر را انجام دهید. اگر حالت پخش جریانی را فعال کرده‌اید، باید اشیاء VisionImage از CMSampleBuffer ایجاد کنید.

با استفاده از UIImage یا CMSampleBuffer یک شیء VisionImage ایجاد کنید.

اگر از UIImage استفاده می‌کنید، مراحل زیر را دنبال کنید:

  • یک شیء VisionImage با UIImage ایجاد کنید. مطمئن شوید که .orientation صحیح را مشخص می‌کنید.

    سویفت

    let image = VisionImage(image: UIImage)
    visionImage.orientation = image.imageOrientation

    هدف-سی

    MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image];
    visionImage.orientation = image.imageOrientation;

اگر از CMSampleBuffer استفاده می‌کنید، مراحل زیر را دنبال کنید:

  • جهت داده‌های تصویر موجود در CMSampleBuffer را مشخص کنید.

    برای بدست آوردن جهت تصویر:

    سویفت

    func imageOrientation(
      deviceOrientation: UIDeviceOrientation,
      cameraPosition: AVCaptureDevice.Position
    ) -> UIImage.Orientation {
      switch deviceOrientation {
      case .portrait:
        return cameraPosition == .front ? .leftMirrored : .right
      case .landscapeLeft:
        return cameraPosition == .front ? .downMirrored : .up
      case .portraitUpsideDown:
        return cameraPosition == .front ? .rightMirrored : .left
      case .landscapeRight:
        return cameraPosition == .front ? .upMirrored : .down
      case .faceDown, .faceUp, .unknown:
        return .up
      }
    }
          

    هدف-سی

    - (UIImageOrientation)
      imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation
                             cameraPosition:(AVCaptureDevicePosition)cameraPosition {
      switch (deviceOrientation) {
        case UIDeviceOrientationPortrait:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationLeftMirrored
                                                                : UIImageOrientationRight;
    
        case UIDeviceOrientationLandscapeLeft:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationDownMirrored
                                                                : UIImageOrientationUp;
        case UIDeviceOrientationPortraitUpsideDown:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationRightMirrored
                                                                : UIImageOrientationLeft;
        case UIDeviceOrientationLandscapeRight:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationUpMirrored
                                                                : UIImageOrientationDown;
        case UIDeviceOrientationUnknown:
        case UIDeviceOrientationFaceUp:
        case UIDeviceOrientationFaceDown:
          return UIImageOrientationUp;
      }
    }
          
  • با استفاده از شیء و جهت‌گیری CMSampleBuffer ، یک شیء VisionImage ایجاد کنید:

    سویفت

    let image = VisionImage(buffer: sampleBuffer)
    image.orientation = imageOrientation(
      deviceOrientation: UIDevice.current.orientation,
      cameraPosition: cameraPosition)

    هدف-سی

     MLKVisionImage *image = [[MLKVisionImage alloc] initWithBuffer:sampleBuffer];
     image.orientation =
       [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation
                                    cameraPosition:cameraPosition];

۳. تصویر را پردازش کنید

VisionImage به یکی از متدهای پردازش تصویرِ تشخیص‌دهنده‌ی حالت (position detector) ارسال کنید. می‌توانید از متدِ process(image:) ناهمگام یا متد results() همگام استفاده کنید.

برای تشخیص اشیاء به صورت همزمان:

سویفت

var results: [Pose]
do {
  results = try poseDetector.results(in: image)
} catch let error {
  print("Failed to detect pose with error: \(error.localizedDescription).")
  return
}
guard let detectedPoses = results, !detectedPoses.isEmpty else {
  print("Pose detector returned no results.")
  return
}

// Success. Get pose landmarks here.

هدف-سی

NSError *error;
NSArray *poses = [poseDetector resultsInImage:image error:&error];
if (error != nil) {
  // Error.
  return;
}
if (poses.count == 0) {
  // No pose detected.
  return;
}

// Success. Get pose landmarks here.

برای تشخیص اشیاء به صورت ناهمزمان:

سویفت

poseDetector.process(image) { detectedPoses, error in
  guard error == nil else {
    // Error.
    return
  }
  guard !detectedPoses.isEmpty else {
    // No pose detected.
    return
  }

  // Success. Get pose landmarks here.
}

هدف-سی

[poseDetector processImage:image
                completion:^(NSArray * _Nullable poses,
                             NSError * _Nullable error) {
                    if (error != nil) {
                      // Error.
                      return;
                    }
                    if (poses.count == 0) {
                      // No pose detected.
                      return;
                    }

                    // Success. Get pose landmarks here.
                  }];

۴. اطلاعات مربوط به ژست شناسایی شده را دریافت کنید

اگر شخصی در تصویر تشخیص داده شود، API تشخیص حالت، بسته به اینکه متد ناهمزمان یا همزمان را فراخوانی کرده باشید، یا آرایه‌ای از اشیاء Pose را به کنترل‌کننده تکمیل ارسال می‌کند یا آرایه را برمی‌گرداند.

اگر فرد کاملاً درون تصویر نبود، مدل مختصات نقاط دیدنی گمشده را خارج از قاب اختصاص می‌دهد و به آنها مقادیر InFrameConfidence پایینی می‌دهد.

اگر هیچ شخصی شناسایی نشده باشد، آرایه خالی است.

سویفت

for pose in detectedPoses {
  let leftAnkleLandmark = pose.landmark(ofType: .leftAnkle)
  if leftAnkleLandmark.inFrameLikelihood > 0.5 {
    let position = leftAnkleLandmark.position
  }
}

هدف-سی

for (MLKPose *pose in detectedPoses) {
  MLKPoseLandmark *leftAnkleLandmark =
      [pose landmarkOfType:MLKPoseLandmarkTypeLeftAnkle];
  if (leftAnkleLandmark.inFrameLikelihood > 0.5) {
    MLKVision3DPoint *position = leftAnkleLandmark.position;
  }
}

نکاتی برای بهبود عملکرد

کیفیت نتایج شما به کیفیت تصویر ورودی بستگی دارد:

  • برای اینکه کیت ML بتواند ژست را به طور دقیق تشخیص دهد، فرد موجود در تصویر باید با داده‌های پیکسلی کافی نمایش داده شود؛ برای بهترین عملکرد، سوژه باید حداقل ۲۵۶x۲۵۶ پیکسل باشد.
  • اگر در یک برنامه بلادرنگ ژست را تشخیص می‌دهید، ممکن است بخواهید ابعاد کلی تصاویر ورودی را نیز در نظر بگیرید. تصاویر کوچکتر می‌توانند سریع‌تر پردازش شوند، بنابراین برای کاهش تأخیر، تصاویر را با وضوح پایین‌تر ضبط کنید، اما الزامات وضوح بالا را در نظر داشته باشید و مطمئن شوید که سوژه تا حد امکان فضای بیشتری از تصویر را اشغال کند.
  • فوکوس ضعیف تصویر نیز می‌تواند بر دقت تأثیر بگذارد. اگر نتایج قابل قبولی به دست نیاوردید، از کاربر بخواهید که دوباره تصویر را ثبت کند.

اگر می‌خواهید از تشخیص ژست در یک برنامه‌ی بلادرنگ استفاده کنید، برای دستیابی به بهترین نرخ فریم، این دستورالعمل‌ها را دنبال کنید:

  • از SDK پایه PoseDetection و حالت تشخیص stream استفاده کنید.
  • ضبط تصاویر با وضوح پایین‌تر را در نظر بگیرید. با این حال، الزامات ابعاد تصویر این API را نیز در نظر داشته باشید.
  • برای پردازش فریم‌های ویدیویی، از API همزمان results(in:) آشکارساز استفاده کنید. این متد را از تابع captureOutput(_, didOutput:from:) مربوط به AVCaptureVideoDataOutputDelegate فراخوانی کنید تا نتایج از فریم ویدیویی داده شده به صورت همزمان دریافت شوند. مقدار alwaysDiscardsLateVideoFrames مربوط به AVCaptureVideoDataOutput را برای فراخوانی‌های throttle به آشکارساز، روی true نگه دارید. اگر فریم ویدیویی جدیدی در حین اجرای آشکارساز در دسترس قرار گیرد، حذف خواهد شد.
  • اگر از خروجی آشکارساز برای همپوشانی گرافیک روی تصویر ورودی استفاده می‌کنید، ابتدا نتیجه را از کیت ML دریافت کنید، سپس تصویر و همپوشانی را در یک مرحله رندر کنید. با انجام این کار، برای هر فریم ورودی پردازش شده، فقط یک بار روی سطح نمایشگر رندر می‌کنید. برای مثال، به کلاس‌های previewOverlayView و MLKDetectionOverlayView در برنامه نمونه ویترین مراجعه کنید.

مراحل بعدی