برچسب‌گذاری تصاویر با مدل سفارشی در iOS

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

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

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

امتحان کنید

قبل‌از شروع

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

    pod 'GoogleMLKit/ImageLabelingCustom', '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 را ببینید.

پیکربندی برچسب‌زن تصویر

پس‌از پیکربندی منابع مدل، از یکی از آن‌ها شیء ImageLabeler ایجاد کنید.

گزینه‌های زیر دردسترس است:

گزینه‌ها
confidenceThreshold

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

maxResultCount

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

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

Swift

let options = CustomImageLabelerOptions(localModel: localModel)
options.confidenceThreshold = NSNumber(value: 0.0)
let imageLabeler = ImageLabeler.imageLabeler(options: options)

آبجکتیو-سی

MLKCustomImageLabelerOptions *options =
    [[MLKCustomImageLabelerOptions alloc] initWithLocalModel:localModel];
options.confidenceThreshold = @(0.0);
MLKImageLabeler *imageLabeler =
    [MLKImageLabeler imageLabelerWithOptions:options];

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

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

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 = CustomImageLabelerOptions(localModel: model)
let imageLabeler = ImageLabeler.imageLabeler(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];
}

MLKCustomImageLabelerOptions *options = [[MLKCustomImageLabelerOptions alloc] initWithLocalModel:model];
MLKImageLabeler *imageLabeler = [MLKImageLabeler imageLabelerWithOptions: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.initializeLabeler(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 labeler
      self.initializeLabeler(with: modelURL)
    }
  }
}

func initializeLabeler(with modelURL: URL) {
  let localModel = LocalModel(path: modelURL.path)
  let options = CustomImageLabelerOptions(localModel: localModel)
  self.imageLabeler = ImageLabeler.imageLabeler(options: options)
  // Enable ML-related UI features here
  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 initializeLabelerWithURL: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 labeler
                 [self initializeLabelerWithURL:URL];
               }
             }];
}

- (void)initializeLabelerWithURL:(NSURL *)modelURL {
  MLKLocalModel *localModel = [[MLKLocalModel alloc] initWithPath:modelURL.path];
  MLKCustomImageLabelerOptions *options = [[MLKCustomImageLabelerOptions alloc] initWithLocalModel:localModel];
  self.imageLabeler = [MLKImageLabeler imageLabelerWithOptions:options];

  // Enable ML-related UI features here
  [self enableMLFeatures];
}

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

بااستفاده از 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];

۳. اجرای برچسب‌زن تصویر

برای برچسب‌گذاری اشیاء در تصویر، شیء image را به روش process() ImageLabeler ارسال کنید.

ناهمگام:

Swift

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

آبجکتیو-سی

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

هم‌زمان:

Swift

var labels: [ImageLabel]
do {
    labels = try imageLabeler.results(in: image)
} catch let error {
    // Handle the error.
    return
}
// Show results.

آبجکتیو-سی

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

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

اگر عملیات برچسب‌گذاری تصویر موفق باشد، آرایه‌ای از ImageLabel برمی‌گرداند. هر ImageLabel نشان‌دهنده چیزی است که در تصویر برچسب‌گذاری شده است. می‌توانید شرح نوشتاری هر برچسب (درصورت وجود در فراداده فایل مدل LiteRT)، امتیاز اطمینان، و نمایه‌اش را دریافت کنید. برای مثال:

Swift

for label in labels {
  let labelText = label.text
  let confidence = label.confidence
  let index = label.index
}

آبجکتیو-سی

for (MLKImageLabel *label in labels) {
  NSString *labelText = label.text;
  float confidence = label.confidence;
  NSInteger index = label.index;
}

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

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

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