شناسایی، ردیابی، و طبقه‌بندی اشیا با مدل طبقه‌بندی سفارشی در iOS

می‌توانید از ML Kit برای شناسایی و ردیابی اشیا در فریم‌های متوالی ویدیو استفاده کنید.

وقتی تصویری را به ML Kit می‌دهید، این کیت حداکثر پنج شیء را در تصویر به‌همراه موقعیت هر شیء در تصویر تشخیص می‌دهد. هنگام شناسایی اشیاء در جاری‌سازی‌های ویدیویی، هر شیء شناسه یکتایی دارد که می‌توانید از آن برای ردیابی شیء از فریمی به فریم دیگر استفاده کنید.

می‌توانید از مدل طبقه‌بندی تصویر سفارشی برای طبقه‌بندی کردن اشیایی که شناسایی می‌شوند استفاده کنید. برای راهنمایی درباره الزامات سازگاری مدل، مکان یافتن مدل‌های ازپیش آموزش‌دیده، و نحوه آموزش مدل‌های خودتان، به مدل‌های سفارشی با ML Kit مراجعه کنید.

دو روش برای یکپارچه کردن مدل سفارشی وجود دارد. می‌توانید مدل را با قرار دادن آن در پوشه دارایی برنامه‌تان بسته‌بندی کنید، یا می‌توانید آن را به‌طور پویا از Cloud Storage بارگیری کنید. جدول زیر این دو گزینه را مقایسه می‌کند.

مدل بسته‌ای مدل میزبانی‌شده
این مدل بخشی از فایل .ipa برنامه شما است که اندازه آن را افزایش می‌دهد. این مدل بخشی از فایل .ipa برنامه‌تان نیست. این برنامه با بارگذاری در Cloud Storage میزبانی می‌شود. توصیه می‌کنیم از Cloud Storage for Firebase استفاده کنید.
مدل فوراً دردسترس قرار می‌گیرد، حتی وقتی دستگاه Android آفلاین باشد برنامه‌تان باید حاوی کدی برای بارگیری مدل درصورت درخواست باشد
نیازی به پروژه Firebase نیست به پروژه Firebase نیاز دارد (اگر از «فضای ذخیره‌سازی ابری ویژه Firebase» استفاده می‌کنید).
برای به‌روزرسانی مدل باید برنامه‌تان را دوباره منتشر کنید به‌روزرسانی‌های مدل را بدون انتشار مجدد برنامه‌تان ارسال کنید
نداشتن آزمایش آ/ب داخلی آزمون آ/ب با پیکربندی از راه دور Firebase

امتحان کنید

قبل‌از شروع

  1. کتابخانه‌های ML Kit را در Podfile خود اضافه کنید:

    pod 'GoogleMLKit/ObjectDetectionCustom', '8.0.0'
    
  2. پس‌از نصب یا به‌روزرسانی Pods پروژه‌تان، پروژه Xcode را بااستفاده از .xcworkspace آن باز کنید. ‫ML Kit در Xcode نسخه ۱۳.۲.۱ یا بالاتر پشتیبانی می‌شود.

  3. اگر می‌خواهید مدلی را بااستفاده از «فضای ذخیره‌سازی ابری ویژه Firebase» بارگیری کنید، مطمئن شوید که Firebase را به پروژه iOS خود اضافه کرده‌اید، اگر قبلاً این کار را نکرده‌اید. این کار هنگام دسته‌بندی مدل الزامی نیست.

۱. بار کردن مدل

پیکربندی منبع مدل محلی

برای دسته‌بندی مدل با برنامه:

  1. فایل مدل (معمولاً با پسوند .tflite یا .lite) را در پروژه Xcode خود کپی کنید و هنگام انجام این کار، حتماً Copy bundle resources را انتخاب کنید. فایل مدل در بسته برنامه گنجانده خواهد شد و برای ML Kit دردسترس خواهد بود.

  2. با مشخص کردن مسیر فایل مدل، شیء LocalModel را ایجاد کنید:

    Swift

    let localModel = LocalModel(path: localModelFilePath)

    آبجکتیو-سی

    MLKLocalModel *localModel =
        [[MLKLocalModel alloc] initWithPath:localModelFilePath];

پیکربندی منبع مدل میزبانی‌شده از راه دور

برای استفاده از مدل میزبانی‌شده از راه دور، باید فایل مدل را بااستفاده از منطق برنامه خودتان در فضای ذخیره‌سازی محلی دستگاه بارگیری کنید و سپس آن را به‌عنوان مدل محلی بار کنید. توصیه می‌کنیم از Cloud Storage for Firebase برای میزبانی مدل استفاده کنید. برای جزئیات پیاده‌سازی، راهنمای انتقال Firebase ML به Cloud Storage را ببینید.

۲. پیکربندی آشکارساز شیء

پس‌از پیکربندی منابع مدل، آشکارساز شیء را برای مورد استفاده‌تان با شیء CustomObjectDetectorOptions پیکربندی کنید. می‌توانید تنظیمات زیر را تغییر دهید:

تنظیمات آشکارساز اشیا
حالت تشخیص ‫STREAM_MODE (پیش‌فرض) | SINGLE_IMAGE_MODE

در STREAM_MODE (پیش‌فرض)، آشکارساز شیء با تأخیر کم اجرا می‌شود، اما ممکن است در چند فراخوانی اول آشکارساز، نتایج ناقصی (مثل چارگوش‌های محدودکننده یا برچسب‌های دسته‌بندی نامشخص) تولید کند. همچنین در STREAM_MODE، آشکارساز شناسه‌های رهگیری را به اشیا اختصاص می‌دهد که می‌توانید از آن‌ها برای رهگیری اشیا در سراسر قاب‌ها استفاده کنید. از این حالت زمانی استفاده کنید که می‌خواهید اشیا را ردیابی کنید، یا زمانی که تأخیر کم مهم است، مثلاً هنگام پردازش جاری‌سازی‌های ویدیو به‌صورت هم‌زمان.

در SINGLE_IMAGE_MODE، آشکارساز شیء نتیجه را پس‌از تعیین کادر محدودکننده شیء برمی‌گرداند. اگر دسته‌بندی را نیز فعال کنید، نتیجه را پس‌از دردسترس قرار گرفتن کادر محدودکننده و برچسب دسته برمی‌گرداند. درنتیجه، تأخیر تشخیص احتمالاً بیشتر است. همچنین، در SINGLE_IMAGE_MODE، شناسه‌های رهگیری اختصاص داده نمی‌شوند. اگر تأخیر مهم نیست و نمی‌خواهید با نتایج جزئی سروکار داشته باشید، از این حالت استفاده کنید.

شناسایی و ردیابی چند شیء ‫false (پیش‌فرض) | true

اینکه حداکثر پنج شیء یا فقط برجسته‌ترین شیء (پیش‌فرض) شناسایی و ردیابی شود.

طبقه‌بندی اشیاء ‫false (پیش‌فرض) | true

اینکه آیا اشیای شناسایی‌شده بااستفاده از مدل طبقه‌بند سفارشی ارائه‌شده طبقه‌بندی شوند یا نه. برای استفاده از مدل طبقه‌بندی سفارشی‌تان، باید این را روی true تنظیم کنید.

آستانه اطمینان طبقه‌بندی

حداقل امتیاز اطمینان برچسب‌های شناسایی‌شده. اگر تنظیم نشده باشد، از هر آستانه طبقه‌بندی‌کننده‌ای که توسط فراداده مدل مشخص شده است استفاده خواهد شد. اگر مدل هیچ فراداده‌ای نداشته باشد یا فراداده آستانه طبقه‌بندی را مشخص نکند، از آستانه پیش‌فرض ۰٫۰ استفاده خواهد شد.

حداکثر برچسب‌ها برای هر شیء

حداکثر تعداد برچسب‌ها برای هر شیء که آشکارساز برمی‌گرداند. اگر تنظیم نشود، از مقدار پیش‌فرض ۱۰ استفاده خواهد شد.

اگر فقط مدل دسته‌بندی محلی دارید، کافی است آشکارساز شیء را از شیء LocalModel خودتان ایجاد کنید:

Swift

let options = CustomObjectDetectorOptions(localModel: localModel)
options.detectorMode = .singleImage
options.shouldEnableClassification = true
options.shouldEnableMultipleObjects = true
options.classificationConfidenceThreshold = NSNumber(value: 0.5)
options.maxPerObjectLabelCount = 3

آبجکتیو-سی

MLKCustomObjectDetectorOptions *options =
    [[MLKCustomObjectDetectorOptions alloc] initWithLocalModel:localModel];
options.detectorMode = MLKObjectDetectorModeSingleImage;
options.shouldEnableClassification = YES;
options.shouldEnableMultipleObjects = YES;
options.classificationConfidenceThreshold = @(0.5);
options.maxPerObjectLabelCount = 3;

اگر مدل از دور میزبانی می‌شود، باید بررسی کنید که قبل‌از اجرا شدن بارگیری شده باشد.

اگرچه فقط باید این موضوع را قبل‌از اجرای آشکارساز شیء تأیید کنید، اما اگر هم مدل میزبانی‌شده از راه دور و هم مدل بسته‌بندی‌شده محلی دارید، ممکن است منطقی باشد که این بررسی را هنگام نمونه‌سازی ObjectDetector انجام دهید: اگر مدل از راه دور بارگیری شده است، یک آشکارساز از آن ایجاد کنید و درغیراین‌صورت از مدل محلی استفاده کنید.

Swift

// Path where your download logic saves the model
let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let localModelURL = documentDirectory.appendingPathComponent("my_remote_model.tflite")

let model: LocalModel
if FileManager.default.fileExists(atPath: localModelURL.path) {
  // Use the downloaded model
  model = LocalModel(path: localModelURL.path)
} else {
  // Fall back to bundled model
  guard let bundledModelPath = Bundle.main.path(forResource: "model", ofType: "tflite") else { return }
  model = LocalModel(path: bundledModelPath)
}

let options = CustomObjectDetectorOptions(localModel: model)
options.detectorMode = .singleImage
options.shouldEnableClassification = true
options.shouldEnableMultipleObjects = true
options.classificationConfidenceThreshold = NSNumber(value: 0.5)
options.maxPerObjectLabelCount = 3
let objectDetector = ObjectDetector.objectDetector(options: options)

آبجکتیو-سی

NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
NSString *localModelPath = [documentsDirectory stringByAppendingPathComponent:@"my_remote_model.tflite"];

MLKLocalModel *model;
if ([NSFileManager.defaultManager fileExistsAtPath:localModelPath]) {
  // Use the downloaded model
  model = [[MLKLocalModel alloc] initWithPath:localModelPath];
} else {
  // Fall back to bundled model
  NSString *bundledModelPath = [NSBundle.mainBundle pathForResource:@"model" ofType:@"tflite"];
  model = [[MLKLocalModel alloc] initWithPath:bundledModelPath];
}

MLKCustomObjectDetectorOptions *options = [[MLKCustomObjectDetectorOptions alloc] initWithLocalModel:model];
options.detectorMode = MLKObjectDetectorModeSingleImage;
options.shouldEnableClassification = YES;
options.shouldEnableMultipleObjects = YES;
options.classificationConfidenceThreshold = @(0.5);
options.maxPerObjectLabelCount = 3;
MLKObjectDetector *objectDetector = [MLKObjectDetector objectDetectorWithOptions:options];

اگر فقط مدل میزبانی‌شده از دور دارید، باید عملکرد مربوط به مدل را غیرفعال کنید—برای مثال، بخشی از میانای کاربری‌تان را خاکستری کنید یا پنهان کنید—تا زمانی که تأیید کنید مدل بارگیری شده است.

Swift

let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let localModelURL = documentDirectory.appendingPathComponent("my_remote_model.tflite")
if FileManager.default.fileExists(atPath: localModelURL.path) {
  // Model is already cached, initialize immediately
  self.initializeDetector(with: localModelURL)
} else {
  // Model is not yet available, show loading UI and start download
  self.showLoadingUI()
  let storage = Storage.storage()
  let modelRef = storage.reference(forURL: "gs://YOUR_BUCKET/path/to/model.tflite")
  modelRef.write(toFile: localModelURL) { url, error in
    self.hideLoadingUI()
    if let error = error {
      // Handle download error
      self.showErrorUI()
    } else if let modelURL = url {
      // Download success, initialize detector
      self.initializeDetector(with: modelURL)
    }
  }
}

func initializeDetector(with modelURL: URL) {
  let localModel = LocalModel(path: modelURL.path)
  let options = CustomObjectDetectorOptions(localModel: localModel)
  options.detectorMode = .singleImage
  options.shouldEnableClassification = true
  options.shouldEnableMultipleObjects = true
  self.objectDetector = ObjectDetector.objectDetector(options: options)
  // Enable ML features in UI
  self.enableMLFeatures()
}

آبجکتیو-سی

NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
NSString *localModelPath = [documentsDirectory stringByAppendingPathComponent:@"my_remote_model.tflite"];
NSURL *localModelURL = [NSURL fileURLWithPath:localModelPath];

if ([NSFileManager.defaultManager fileExistsAtPath:localModelPath]) {
  // Model is already cached, initialize immediately
  [self initializeDetectorWithURL:localModelURL];
} else {
  // Model is not yet available, show loading UI and start download
  [self showLoadingUI];

  FIRStorage *storage = [FIRStorage storage];
  FIRStorageReference *modelRef = [storage referenceForURL:@"gs://YOUR_BUCKET/path/to/model.tflite"];

  [modelRef writeToFile:localModelURL
             completion:^(NSURL * _Nullable URL, NSError * _Nullable error) {
               [self hideLoadingUI];
               if (error != nil) {
                 // Handle download error
                 [self showErrorUI];
               } else {
                 // Download success, initialize detector
                 [self initializeDetectorWithURL:URL];
               }
             }];
}

- (void)initializeDetectorWithURL:(NSURL *)modelURL {
  MLKLocalModel *localModel = [[MLKLocalModel alloc] initWithPath:modelURL.path];
  MLKCustomObjectDetectorOptions *options = [[MLKCustomObjectDetectorOptions alloc] initWithLocalModel:localModel];
  options.detectorMode = MLKObjectDetectorModeSingleImage;
  options.shouldEnableClassification = YES;
  options.shouldEnableMultipleObjects = YES;
  self.objectDetector = [MLKObjectDetector objectDetectorWithOptions:options];

  // Enable ML features in UI
  [self enableMLFeatures];
}

‫API تشخیص و ردیابی شیء برای این دو مورد استفاده اصلی بهینه‌سازی شده است:

  • تشخیص و ردیابی زنده برجسته‌ترین شیء در نمایاب دوربین.
  • تشخیص چند شیء از یک تصویر ثابت.

برای پیکربندی میانای برنامه‌سازی کاربردی برای این موارد استفاده:

Swift

// Live detection and tracking
let options = CustomObjectDetectorOptions(localModel: localModel)
options.shouldEnableClassification = true
options.maxPerObjectLabelCount = 3

// Multiple object detection in static images
let options = CustomObjectDetectorOptions(localModel: localModel)
options.detectorMode = .singleImage
options.shouldEnableMultipleObjects = true
options.shouldEnableClassification = true
options.maxPerObjectLabelCount = 3

آبجکتیو-سی

// Live detection and tracking
MLKCustomObjectDetectorOptions *options =
    [[MLKCustomObjectDetectorOptions alloc] initWithLocalModel:localModel];
options.shouldEnableClassification = YES;
options.maxPerObjectLabelCount = 3;

// Multiple object detection in static images
MLKCustomObjectDetectorOptions *options =
    [[MLKCustomObjectDetectorOptions alloc] initWithLocalModel:localModel];
options.detectorMode = MLKObjectDetectorModeSingleImage;
options.shouldEnableMultipleObjects = YES;
options.shouldEnableClassification = YES;
options.maxPerObjectLabelCount = 3;

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

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

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

  • یک شیء VisionImage با UIImage ایجاد کن. حتماً .orientation صحیح را مشخص کنید.

    Swift

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

    آبجکتیو-سی

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

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

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

    برای دریافت جهت تصویر:

    Swift

    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 ایجاد کنید:

    Swift

    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];

۴. ایجاد و اجرای آشکارساز شیء

  1. ایجاد آشکارساز شیء جدید:

    Swift

    let objectDetector = ObjectDetector.objectDetector(options: options)

    آبجکتیو-سی

    MLKObjectDetector *objectDetector = [MLKObjectDetector objectDetectorWithOptions:options];
  2. سپس، از آشکارساز استفاده کنید:

    ناهمگام:

    Swift

    objectDetector.process(image) { objects, error in
        guard error == nil, let objects = objects, !objects.isEmpty else {
            // Handle the error.
            return
        }
        // Show results.
    }

    آبجکتیو-سی

    [objectDetector
        processImage:image
          completion:^(NSArray *_Nullable objects,
                       NSError *_Nullable error) {
            if (objects.count == 0) {
                // Handle the error.
                return;
            }
            // Show results.
         }];

    هم‌زمان:

    Swift

    var objects: [Object]
    do {
        objects = try objectDetector.results(in: image)
    } catch let error {
        // Handle the error.
        return
    }
    // Show results.

    آبجکتیو-سی

    NSError *error;
    NSArray *objects =
        [objectDetector resultsInImage:image error:&error];
    // Show results or handle the error.

۵. دریافت اطلاعات درباره اشیای برچسب‌گذاری‌شده

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

هر Object شامل ویژگی‌های زیر است:

frame CGRect که موقعیت شیء را در تصویر نشان می‌دهد.
trackingID عدد صحیحی که شیء را در تصاویر شناسایی می‌کند، یا `nil` در SINGLE_IMAGE_MODE.
labels
label.text شرح نوشتاری برچسب. فقط درصورتی برگردانده می‌شود که فراداده مدل LiteRT حاوی شرح برچسب باشد.
label.index شاخص برچسب در میان همه برچسب‌های پشتیبانی‌شده توسط طبقه‌بند.
label.confidence مقدار اطمینان طبقه‌بندی شیء.

Swift

// objects contains one item if multiple object detection wasn't enabled.
for object in objects {
  let frame = object.frame
  let trackingID = object.trackingID
  let description = object.labels.enumerated().map { (index, label) in
    "Label \(index): \(label.text), \(label.confidence), \(label.index)"
  }.joined(separator: "\n")
}

آبجکتیو-سی

// The list of detected objects contains one item if multiple object detection
// wasn't enabled.
for (MLKObject *object in objects) {
  CGRect frame = object.frame;
  NSNumber *trackingID = object.trackingID;
  for (MLKObjectLabel *label in object.labels) {
    NSString *labelString =
        [NSString stringWithFormat:@"%@, %f, %lu",
                                   label.text,
                                   label.confidence,
                                   (unsigned long)label.index];
  }
}

تضمین تجربه کاربری عالی

برای ارائه بهترین تجربه کاربری، این دستورالعمل‌ها را در برنامه‌تان دنبال کنید:

  • تشخیص موفقیت‌آمیز شیء به پیچیدگی بصری شیء بستگی دارد. برای شناسایی شدن، اشیایی که تعداد کمی ویژگی‌های بصری دارند ممکن است لازم باشد بخش بزرگ‌تری از تصویر را اشغال کنند. باید به کاربران درباره گرفتن ورودی که با نوع اشیایی که می‌خواهید شناسایی کنید به‌خوبی کار می‌کند راهنمایی ارائه دهید.
  • هنگام استفاده از طبقه‌بندی، اگر می‌خواهید اشیایی را که به‌طور واضح در دسته‌های پشتیبانی‌شده قرار نمی‌گیرند شناسایی کنید، مدیریت ویژه‌ای برای اشیای ناشناخته پیاده‌سازی کنید.

همچنین، برنامه ویترین ML Kit Material Design و مجموعه الگوهای ویژگی‌های مجهز به یادگیری ماشین Material Design را بررسی کنید.

بهبود عملکرد

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

  • وقتی از حالت جاری‌سازی در یک برنامه هم‌زمان استفاده می‌کنید، از تشخیص چندگانه شیء استفاده نکنید، زیرا اکثر دستگاه‌ها نمی‌توانند نرخ فریم کافی تولید کنند.

  • برای پردازش قاب‌های ویدیو، از results(in:) میانای برنامه‌سازی کاربردی هم‌زمان آشکارساز استفاده کنید. این روش را از تابع captureOutput(_, didOutput:from:) مربوط به AVCaptureVideoDataOutputSampleBufferDelegate فراخوانی کنید تا نتایج را به‌صورت همگام از فریم ویدیو داده‌شده دریافت کنید. AVCaptureVideoDataOutput alwaysDiscardsLateVideoFrames را به‌عنوان true نگه دارید تا تماس‌ها با آشکارساز را محدود کنید. اگر درحین اجرای آشکارساز، فریم ویدیویی جدیدی دردسترس قرار گیرد، آن فریم حذف خواهد شد.
  • اگر از خروجی آشکارساز برای هم‌پوشانی گرافیک روی تصویر ورودی استفاده می‌کنید، ابتدا نتیجه را از ML Kit دریافت کنید، سپس تصویر و هم‌پوشانی را در یک مرحله رندر کنید. با انجام این کار، برای هر قاب ورودی پردازش‌شده، فقط یک‌بار به سطح نمایشگر رندر می‌کنید. برای نمونه، updatePreviewOverlayViewWithLastFrame را در نمونه راه‌اندازی سریع ML Kit ببینید.