رصد العناصر وتتبعها وتصنيفها باستخدام نموذج تصنيف مخصّص على iOS

يمكنك استخدام أدوات تعلّم الآلة لرصد العناصر وتتبّعها في إطارات الفيديو المتتالية.

عند تمرير صورة إلى أدوات تعلّم الآلة، يرصد ما يصل إلى خمسة عناصر في الصورة، بالإضافة إلى موضع كل عنصر في الصورة. عند رصد الكائنات في الفيديوهات المضمّنة، يكون لكل عنصر معرّف فريد يمكنك استخدامه لتتبُّع العنصر من إطار إلى آخر.

يمكنك استخدام نموذج تصنيف مخصّص للصور لتصنيف العناصر التي يتم رصدها. يُرجى الرجوع إلى النماذج المخصّصة باستخدام حزمة تعلّم الآلة للحصول على إرشادات حول متطلبات توافق النماذج، وأماكن العثور على نماذج مدرّبة مسبقًا، وكيفية تدريب نماذجك الخاصة.

هناك طريقتان لدمج النموذج المخصّص. يمكنك تجميع النموذج من خلال وضعه في مجلد مواد العرض في التطبيق أو تنزيله ديناميكيًا من Firebase. يقارن الجدول التالي بين الخيارين.

النموذج المجمّع النموذج المستضاف
يُعد النموذج جزءًا من ملف .ipa لتطبيقك، ما يؤدي إلى زيادة حجمه. النموذج ليس جزءًا من ملف .ipa لتطبيقك. وتتم استضافته عن طريق تحميله إلى ميزة تعلُّم الآلة من Firebase.
يتوفر الطراز على الفور، حتى عندما يكون جهاز Android غير متصل بالإنترنت. يتم تنزيل النموذج عند الطلب
عدم الحاجة إلى مشروع Firebase يجب توفّر مشروع في Firebase.
يجب إعادة نشر تطبيقك لتحديث النموذج. إرسال تحديثات النموذج بدون إعادة نشر تطبيقك
بدون اختبار A/B مدمج إجراء اختبار A/B بسهولة باستخدام ميزة الإعداد عن بُعد في Firebase

تجربة السمات والبيانات

قبل البدء

  1. تضمين مكتبات ML Kit في ملف Podfile:

    لتجميع نموذج مع تطبيقك:

    pod 'GoogleMLKit/ObjectDetectionCustom', '3.2.0'
    

    لتنزيل نموذج بشكل ديناميكي من Firebase، أضِف التبعية LinkFirebase:

    pod 'GoogleMLKit/ObjectDetectionCustom', '3.2.0'
    pod 'GoogleMLKit/LinkFirebase', '3.2.0'
    
  2. بعد تثبيت أو تحديث مجموعات اللوحات لمشروعك، افتح مشروع Xcode باستخدام .xcworkspace الخاص به. تتوفّر هذه الأداة في الإصدار 13.2.1 من Xcode أو الإصدارات الأحدث.

  3. إذا أردت تنزيل نموذج، تأكّد من إضافة Firebase إلى مشروع iOS، إذا لم يسبق لك إجراء ذلك، فهذا ليس مطلوبًا عند تجميع النموذج.

1- تحميل النموذج

ضبط مصدر نموذج محلي

لتجميع النموذج مع تطبيقك:

  1. انسخ ملف النموذج (الذي ينتهي عادةً بالأرقام .tflite أو .lite) إلى مشروع Xcode الخاص بك، مع الحرص على اختيار Copy bundle resources عند إجراء ذلك. سيتم تضمين ملف النموذج في حزمة التطبيق وسيكون متاحًا لبرنامج ML Kit.

  2. إنشاء كائن LocalModel، مع تحديد المسار إلى ملف النموذج:

    Swift

    let localModel = LocalModel(path: localModelFilePath)

    Objective-C

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

ضبط مصدر نموذج مستضاف على Firebase

لاستخدام النموذج الذي تتم استضافته عن بُعد، أنشِئ كائن CustomRemoteModel مع تحديد الاسم الذي تم تخصيص النموذج له عند نشره:

Swift

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

Objective-C

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

بعد ذلك، ابدأ مهمة تنزيل النموذج، مع تحديد الشروط التي تريد السماح بالتنزيل بموجبها. إذا لم يكن النموذج مثبَّتًا على الجهاز أو في حال توفُّر إصدار أحدث من النموذج، سيتم تنزيل النموذج من Firebase بشكل غير متزامن:

Swift

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

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

Objective-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:

Swift

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

Objective-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: يمكنك إنشاء جهاز رصد من النموذج البعيد إذا تم تنزيله، ومن النموذج المحلي بطريقة أخرى.

Swift

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

Objective-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 في قسم المراقب، وذلك لأنّ عمليات التنزيل قد تستغرق بعض الوقت، ويمكن أن تتم إزالة العنصر الأصلي عند انتهاء عملية التنزيل. مثال:

Swift

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]
    // ...
}

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

ويتم تحسين واجهة برمجة التطبيقات الخاصة برصد الكائنات وتتبّعها لحالة الاستخدام الأساسية التالية:

  • الرصد المباشر لأبرز العناصر في عدسة الكاميرا وتتبّعها
  • يشير ذلك المصطلح إلى رصد عناصر متعددة من صورة ثابتة.

لضبط واجهة برمجة التطبيقات لحالات الاستخدام هذه:

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

Objective-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. تحضير صورة الإدخال

أنشِئ عنصر VisionImage باستخدام UIImage أو CMSampleBuffer.

في حال استخدام "UIImage"، يُرجى اتّباع الخطوات التالية:

  • يمكنك إنشاء عنصر VisionImage باستخدام UIImage. تأكَّد من تحديد سمة .orientation الصحيحة.

    Swift

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

    Objective-C

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

    Objective-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 واتجاهه:

    Swift

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

    Objective-C

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

4. إنشاء أداة رصد الكائنات وتشغيلها

  1. إنشاء أداة رصد جديدة للكائنات:

    Swift

    let objectDetector = ObjectDetector.objectDetector(options: options)

    Objective-C

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

    Objective-C

    [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.

    Objective-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 قيمة الثقة لتصنيف العناصر.

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

Objective-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 view app][showcase-link]{: .external } ومجموعة أنماط الميزات المستندة إلى تعلُم الآلة في "التصميم المتعدد الأبعاد".

Improving performance

إذا أردت استخدام ميزة اكتشاف الأجسام في تطبيق في الوقت الفعلي، يُرجى اتّباع الإرشادات التالية لتحقيق أفضل عدد من اللقطات:

  • عند استخدام وضع البث في تطبيق في الوقت الفعلي، يجب عدم استخدام ميزة رصد عناصر متعددة، لأنّ معظم الأجهزة لن تتمكّن من تسجيل عدد لقطات مناسب في الثانية.

  • لمعالجة إطارات الفيديو، استخدِم واجهة برمجة التطبيقات المتزامنة results(in:) لأداة الرصد. ويمكنك استدعاء هذه الطريقة من وظيفة captureOutput(_, didOutput:from:) في AVCaptureVideoDataOutputSampleBufferDelegate للحصول على نتائج متزامنة من إطار الفيديو المحدّد. الاحتفاظ بـ AVCaptureVideoDataOutput alwaysDiscardsLateVideoFrames true لتقليل المكالمات الواردة إلى جهاز الرصد. في حال توفّر إطار فيديو جديد أثناء تشغيل أداة الرصد، سيتم تجاهله.
  • إذا كنت تستخدم نتيجة أداة الرصد لإضافة رسومات على الصورة التي تم إدخالها، احصل أولاً على النتيجة من أدوات تعلّم الآلة، ثم اعرض الصورة والتراكب في خطوة واحدة. بإجراء ذلك، يتم عرضك على سطح الشاشة مرة واحدة فقط لكل إطار إدخال تمت معالجته. للاطّلاع على مثال، يمكن الاطّلاع على updatePreviewOverlayViewWithLastFrame في نموذج البدء السريع في ML Kit.