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

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

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

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

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

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

جرّبه الآن

قبل البدء

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

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

    pod 'GoogleMLKit/ObjectDetectionCustom', '15.5.0'
    

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

    pod 'GoogleMLKit/ObjectDetectionCustom', '15.5.0'
    pod 'GoogleMLKit/LinkFirebase', '15.5.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 تحتوي البيانات الوصفية للنموذج البسيط على أوصاف للتصنيفات.
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];
  }
}

ضمان تجربة رائعة للمستخدم

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

  • يعتمد اكتشاف الكائن الناجح على التعقيد البصري للكائن. ضِمن جهاز واحد، قد تحتاج الأجسام ذات عدد قليل من الميزات المرئية لكي تشغل جزءًا أكبر من الصورة يجب عليك تقديم إرشادات للمستخدمين حول التقاط مدخلات تعمل بشكل جيد مع نوع العناصر التي تريد رصدها.
  • عند استخدام التصنيف، إذا كنت تريد رصد الأجسام التي لا تسقط بوضوح في الفئات المعتمدة، وتنفيذ معالجة خاصة للفئات الأخرى.

يمكنك أيضًا الاطّلاع على [تطبيق عرض التصميم المتعدد الأبعاد لمجموعة أدوات تعلّم الآلة][showcase-link]{: .external } و التصميم المتعدد الأبعاد مجموعة أنماط الميزات المستنِدة إلى تعلُّم الآلة:

تحسين الأداء

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

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

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