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

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

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

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

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

مدل همراه مدل میزبانی شده
این مدل بخشی از فایل .ipa برنامه شما است که اندازه آن را افزایش می دهد. مدل بخشی از فایل .ipa . برنامه شما نیست. با آپلود در Firebase Machine Learning میزبانی می شود.
این مدل بلافاصله در دسترس است، حتی زمانی که دستگاه اندروید آفلاین است مدل در صورت تقاضا دانلود می شود
بدون نیاز به پروژه Firebase به پروژه Firebase نیاز دارد
برای به‌روزرسانی مدل، باید برنامه خود را دوباره منتشر کنید به روز رسانی مدل را بدون انتشار مجدد برنامه خود فشار دهید
بدون تست A/B داخلی تست آسان A/B با Firebase Remote Config

آن را امتحان کنید

قبل از شروع

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

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

    pod 'GoogleMLKit/ObjectDetectionCustom', '15.5.0'
    

    برای دانلود پویا یک مدل از Firebase، وابستگی LinkFirebase را اضافه کنید:

    pod 'GoogleMLKit/ObjectDetectionCustom', '15.5.0'
    pod 'GoogleMLKit/LinkFirebase', '15.5.0'
    
  2. پس از نصب یا به روز رسانی Pods پروژه خود، پروژه Xcode خود را با استفاده از .xcworkspace . آن باز کنید. ML Kit در Xcode نسخه 13.2.1 یا بالاتر پشتیبانی می شود.

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

1. مدل را بارگذاری کنید

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

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

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

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

    سویفت

    let localModel = LocalModel(path: localModelFilePath)

    هدف-C

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

یک منبع مدل میزبانی شده توسط Firebase را پیکربندی کنید

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

سویفت

let firebaseModelSource = FirebaseModelSource(
    name: "your_remote_model") // The name you assigned in
                               // the Firebase console.
let remoteModel = CustomRemoteModel(remoteModelSource: firebaseModelSource)

هدف-C

MLKFirebaseModelSource *firebaseModelSource =
    [[MLKFirebaseModelSource alloc]
        initWithName:@"your_remote_model"]; // The name you assigned in
                                            // the Firebase console.
MLKCustomRemoteModel *remoteModel =
    [[MLKCustomRemoteModel alloc]
        initWithRemoteModelSource:firebaseModelSource];

سپس، با مشخص کردن شرایطی که می‌خواهید اجازه دانلود را بدهید، کار دانلود مدل را شروع کنید. اگر مدل در دستگاه نباشد، یا اگر نسخه جدیدتری از مدل موجود باشد، این کار به صورت ناهمزمان مدل را از Firebase دانلود می‌کند:

سویفت

let downloadConditions = ModelDownloadConditions(
  allowsCellularAccess: true,
  allowsBackgroundDownloading: true
)

let downloadProgress = ModelManager.modelManager().download(
  remoteModel,
  conditions: downloadConditions
)

هدف-C

MLKModelDownloadConditions *downloadConditions =
    [[MLKModelDownloadConditions alloc] initWithAllowsCellularAccess:YES
                                         allowsBackgroundDownloading:YES];

NSProgress *downloadProgress =
    [[MLKModelManager modelManager] downloadModel:remoteModel
                                       conditions:downloadConditions];

بسیاری از برنامه‌ها وظیفه دانلود را در کد اولیه خود شروع می‌کنند، اما شما می‌توانید این کار را در هر زمانی قبل از نیاز به استفاده از مدل انجام دهید.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

سویفت

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

هدف-C

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

اگر یک مدل با میزبانی از راه دور دارید، قبل از اجرای آن باید بررسی کنید که دانلود شده است. با استفاده از روش isModelDownloaded(remoteModel:) مدیر مدل می توانید وضعیت وظیفه دانلود مدل را بررسی کنید.

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

سویفت

var options: CustomObjectDetectorOptions!
if (ModelManager.modelManager().isModelDownloaded(remoteModel)) {
  options = CustomObjectDetectorOptions(remoteModel: remoteModel)
} else {
  options = CustomObjectDetectorOptions(localModel: localModel)
}
options.detectorMode = .singleImage
options.shouldEnableClassification = true
options.shouldEnableMultipleObjects = true
options.classificationConfidenceThreshold = NSNumber(value: 0.5)
options.maxPerObjectLabelCount = 3

هدف-C

MLKCustomObjectDetectorOptions *options;
if ([[MLKModelManager modelManager] isModelDownloaded:remoteModel]) {
  options = [[MLKCustomObjectDetectorOptions alloc] initWithRemoteModel:remoteModel];
} else {
  options = [[MLKCustomObjectDetectorOptions alloc] initWithLocalModel:localModel];
}
options.detectorMode = MLKObjectDetectorModeSingleImage;
options.shouldEnableClassification = YES;
options.shouldEnableMultipleObjects = YES;
options.classificationConfidenceThreshold = @(0.5);
options.maxPerObjectLabelCount = 3;

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

می‌توانید با پیوست کردن ناظران به مرکز اطلاع رسانی پیش‌فرض، وضعیت دانلود مدل را دریافت کنید. مطمئن شوید که از یک مرجع ضعیف به self در بلوک ناظر استفاده کنید، زیرا دانلودها ممکن است مدتی طول بکشد، و شی مبدا می‌تواند تا پایان دانلود آزاد شود. به عنوان مثال:

سویفت

NotificationCenter.default.addObserver(
    forName: .mlkitModelDownloadDidSucceed,
    object: nil,
    queue: nil
) { [weak self] notification in
    guard let strongSelf = self,
        let userInfo = notification.userInfo,
        let model = userInfo[ModelDownloadUserInfoKey.remoteModel.rawValue]
            as? RemoteModel,
        model.name == "your_remote_model"
        else { return }
    // The model was downloaded and is available on the device
}

NotificationCenter.default.addObserver(
    forName: .mlkitModelDownloadDidFail,
    object: nil,
    queue: nil
) { [weak self] notification in
    guard let strongSelf = self,
        let userInfo = notification.userInfo,
        let model = userInfo[ModelDownloadUserInfoKey.remoteModel.rawValue]
            as? RemoteModel
        else { return }
    let error = userInfo[ModelDownloadUserInfoKey.error.rawValue]
    // ...
}

هدف-C

__weak typeof(self) weakSelf = self;

[NSNotificationCenter.defaultCenter
    addObserverForName:MLKModelDownloadDidSucceedNotification
                object:nil
                 queue:nil
            usingBlock:^(NSNotification *_Nonnull note) {
              if (weakSelf == nil | note.userInfo == nil) {
                return;
              }
              __strong typeof(self) strongSelf = weakSelf;

              MLKRemoteModel *model = note.userInfo[MLKModelDownloadUserInfoKeyRemoteModel];
              if ([model.name isEqualToString:@"your_remote_model"]) {
                // The model was downloaded and is available on the device
              }
            }];

[NSNotificationCenter.defaultCenter
    addObserverForName:MLKModelDownloadDidFailNotification
                object:nil
                 queue:nil
            usingBlock:^(NSNotification *_Nonnull note) {
              if (weakSelf == nil | note.userInfo == nil) {
                return;
              }
              __strong typeof(self) strongSelf = weakSelf;

              NSError *error = note.userInfo[MLKModelDownloadUserInfoKeyError];
            }];

API تشخیص و ردیابی شی برای این دو مورد اصلی بهینه شده است:

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

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

سویفت

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

هدف-C

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

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

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

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

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

    سویفت

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

    هدف-C

    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
      }
    }
          

    هدف-C

    - (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;
      }
    }
          
  • یک شی VisionImage با استفاده از شی CMSampleBuffer و جهت گیری ایجاد کنید:

    سویفت

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

    هدف-C

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

4. آشکارساز شی را ایجاد و اجرا کنید

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

    سویفت

    let objectDetector = ObjectDetector.objectDetector(options: options)

    هدف-C

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

    به صورت ناهمزمان:

    سویفت

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

    هدف-C

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

    به صورت همزمان:

    سویفت

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

    هدف-C

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

5. اطلاعاتی در مورد اشیاء برچسب دار دریافت کنید

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

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

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

سویفت

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

هدف-C

// 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 showcase app][showcase-link]{: .external } و الگوهای طراحی مواد برای مجموعه ویژگی های مبتنی بر یادگیری ماشین را بررسی کنید.

بهبود عملکرد

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

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

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