تصنيف الصور باستخدام نموذج مدرَّب على تكنولوجيا تعلُّم الآلة على نظام التشغيل iOS

بعد تدريب نموذجك الخاص باستخدام AutoML Vision Edge، يمكنك استخدامه في تطبيقك لتصنيف الصور.

هناك طريقتان لدمج النماذج المدرَّبة من AutoML Vision Edge. يمكنك تجميع النموذج عن طريق نسخ ملفات النموذج إلى مشروع Xcode لديك، أو يمكنك تنزيله ديناميكيًا من Firebase.

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

التجربة الآن

  • جرّب نموذج التطبيق للاطّلاع على مثال لاستخدام واجهة برمجة التطبيقات هذه.

قبل البدء

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

لدمج نموذج مع تطبيقك:
    pod 'GoogleMLKit/ImageLabelingAutoML'
    
لتنزيل نموذج من Firebase بشكل ديناميكي، أضِف القاعدة التابعة LinkFirebase:
    pod 'GoogleMLKit/ImageLabelingAutoML'
    pod 'GoogleMLKit/LinkFirebase'
    
2. بعد تثبيت مجموعات Pod الخاصة بمشروعك أو تحديثها، افتح مشروع Xcode باستخدام .xcworkspaceالرمز الخاص به. إنّ حزمة MLK متوافقة مع الإصدار 13.2.1 من Xcode أو الإصدارات الأحدث. 3- إذا أردت تنزيل نموذج، تأكّد من إضافة Firebase إلى مشروع iOS الخاص بك إذا لم يسبق لك ذلك، لأنّ هذا الإجراء ليس مطلوبًا عند تجميع النموذج.

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

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

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

1. استخرِج النموذج وبياناته الوصفية من أرشيف ZIP الذي نزّلته من "وحدة تحكّم Firebase" إلى مجلد:
    your_model_directory
      |____dict.txt
      |____manifest.json
      |____model.tflite
    
يجب أن تكون الملفات الثلاثة في المجلد نفسه. ننصحك باستخدام الملفات أثناء تنزيلها، بدون أي تعديل (بما في ذلك أسماء الملفات).

2- انسخ المجلد إلى مشروع Xcode، مع الحرص على اختيار إنشاء مراجع للمجلدات عند إجراء ذلك. سيتم تضمين ملف النموذج والبيانات الوصفية في حزمة التطبيق، كما سيتم إتاحته في حزمة ML Kit.

3- أنشئ كائن AutoMLImageLabelerLocalModel مع تحديد المسار إلى ملف بيان النموذج:

Swift

guard let manifestPath = Bundle.main.path(
    forResource: "manifest",
    ofType: "json",
    inDirectory: "your_model_directory"
) else { return }
let localModel = AutoMLImageLabelerLocalModel(manifestPath: manifestPath)

Objective-C

NSString *manifestPath =
    [NSBundle.mainBundle pathForResource:@"manifest"
                                  ofType:@"json"
                             inDirectory:@"your_model_directory"];
MLKAutoMLImageLabelerLocalModel *localModel =
    [[MLKAutoMLImageLabelerLocalModel alloc] initWithManifestPath:manifestPath];

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

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

Swift

let remoteModel = AutoMLImageLabelerRemoteModel(
    name: "your_remote_model"  // The name you assigned in
                               // the Firebase console.
)

Objective-C

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

بعد ذلك، ابدأ مهمة تنزيل النموذج، مع تحديد الشروط التي تريد السماح بالتنزيل بموجبها. إذا لم يكن النموذج مثبَّتًا على الجهاز، أو إذا توفَّر إصدار أحدث من النموذج، سيتم تنزيل النموذج من 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];

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

إنشاء تصنيف صورة من نموذجك

بعد ضبط مصادر النماذج، أنشئ كائن ImageLabeler من أحدها.

إذا كان لديك نموذج مجمّع محليًا فقط، ما عليك سوى إنشاء تصنيف من عنصر AutoMLImageLabelerLocalModel وضبط حد نتيجة الثقة الذي تريد طلبه (راجِع تقييم وضعك:

Swift

let options = AutoMLImageLabelerOptions(localModel: localModel)
options.confidenceThreshold = NSNumber(value: 0.0)  // Evaluate your model in the Firebase console
                                                    // to determine an appropriate value.
let imageLabeler = ImageLabeler.imageLabeler(options: options)

Objective-C

MLKAutoMLImageLabelerOptions *options =
    [[MLKAutoMLImageLabelerOptions alloc] initWithLocalModel:localModel];
options.confidenceThreshold = @(0.0);  // Evaluate your model in the Firebase console
                                       // to determine an appropriate value.
MLKImageLabeler *imageLabeler =
    [MLKImageLabeler imageLabelerWithOptions:options];

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

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

Swift

var options: AutoMLImageLabelerOptions!
if (ModelManager.modelManager().isModelDownloaded(remoteModel)) {
  options = AutoMLImageLabelerOptions(remoteModel: remoteModel)
} else {
  options = AutoMLImageLabelerOptions(localModel: localModel)
}
options.confidenceThreshold = NSNumber(value: 0.0)  // Evaluate your model in the Firebase console
                                                    // to determine an appropriate value.
let imageLabeler = ImageLabeler.imageLabeler(options: options)

Objective-C

MLKAutoMLImageLabelerOptions *options;
if ([[MLKModelManager modelManager] isModelDownloaded:remoteModel]) {
  options = [[MLKAutoMLImageLabelerOptions alloc] initWithRemoteModel:remoteModel];
} else {
  options = [[MLKAutoMLImageLabelerOptions alloc] initWithLocalModel:localModel];
}
options.confidenceThreshold = @(0.0);  // Evaluate your model in the Firebase console
                                       // to determine an appropriate value.
MLKImageLabeler *imageLabeler =
    [MLKImageLabeler imageLabelerWithOptions:options];

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

يمكنك معرفة حالة تنزيل النموذج عن طريق إرفاق مراقبين بـ "مركز الإشعارات" التلقائي. احرِص على استخدام إشارة ضعيفة إلى 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];
            }];

2- تجهيز صورة الإدخال

أنشئ كائن 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];

3- تشغيل أداة تصنيف الصور

بشكل غير متزامن:

Swift

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

Objective-C

[imageLabeler
    processImage:image
      completion:^(NSArray *_Nullable labels,
                   NSError *_Nullable error) {
        if (labels.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.

Objective-C

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

4. الحصول على معلومات حول العناصر المصنّفة

إذا نجحت عملية تصنيف الصور، ستعرض لك الصفيفة ImageLabel. ويمثل كل ImageLabel شيئًا تم تصنيفه في الصورة. يمكنك الحصول على الوصف النصي لكل تسمية (إذا كان متاحًا في بيانات التعريف لملف نموذج TensorFlow Lite) ودرجة الثقة والفهرس. مثال:

Swift

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

Objective-C

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

نصائح لتحسين الأداء في الوقت الفعلي

إذا أردت تصنيف الصور في تطبيق في الوقت الفعلي، اتّبِع هذه الإرشادات لتحقيق أفضل عدد من اللقطات:

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