تصنيف الصور باستخدام نموذج تم تدريبه باستخدام ميزة "التعلم الآلي التلقائي" على أجهزة iOS

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

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

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

جرّبه الآن

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

قبل البدء

1. أدرِج مكتبات ML Kit في Podfile:

لتجميع نموذج مع تطبيقك:
    pod 'GoogleMLKit/ImageLabelingAutoML'
    
لتنزيل نموذج ديناميكيًا من Firebase، أضِف التبعية LinkFirebase:
    pod 'GoogleMLKit/ImageLabelingAutoML'
    pod 'GoogleMLKit/LinkFirebase'
    
2. بعد تثبيت حِزم Pods في مشروعك أو تعديلها، افتح مشروع Xcode باستخدام .xcworkspacecode>. تتوفّر حزمة ML Kit في الإصدار 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، مع تحديد المسار إلىملف بيان النموذج:
SwiftObjective-C
guard let manifestPath = Bundle.main.path(
    forResource: "manifest",
    ofType: "json",
    inDirectory: "your_model_directory"
) else { return }
let localModel = AutoMLImageLabelerLocalModel(manifestPath: manifestPath)
NSString *manifestPath =
    [NSBundle.mainBundle pathForResource:@"manifest"
                                  ofType:@"json"
                             inDirectory:@"your_model_directory"];
MLKAutoMLImageLabelerLocalModel *localModel =
    [[MLKAutoMLImageLabelerLocalModel alloc] initWithManifestPath:manifestPath];

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

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

SwiftObjective-C
let remoteModel = AutoMLImageLabelerRemoteModel(
    name: "your_remote_model"  // The name you assigned in
                               // the Firebase console.
)
MLKAutoMLImageLabelerRemoteModel *remoteModel =
    [[MLKAutoMLImageLabelerRemoteModel alloc]
        initWithName:@"your_remote_model"];  // The name you assigned in
                                             // the Firebase console.

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

SwiftObjective-C
let downloadConditions = ModelDownloadConditions(
  allowsCellularAccess: true,
  allowsBackgroundDownloading: true
)

let downloadProgress = ModelManager.modelManager().download(
  remoteModel,
  conditions: downloadConditions
)
MLKModelDownloadConditions *downloadConditions =
    [[MLKModelDownloadConditions alloc] initWithAllowsCellularAccess:YES
                                         allowsBackgroundDownloading:YES];

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

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

إنشاء أداة تصنيف الصور من النموذج

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

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

SwiftObjective-C
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)
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: أنشئ أداة وضع العلامات من النموذج عن بُعد إذا تم تنزيله، ومن النموذج المحلي بخلاف ذلك.

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

SwiftObjective-C
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]
    // ...
}
__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 الصحيح.
    SwiftObjective-C
    let image = VisionImage(image: UIImage)
    visionImage.orientation = image.imageOrientation
    MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image];
    visionImage.orientation = image.imageOrientation;

إذا كنت تستخدم CMSampleBuffer، اتّبِع الخطوات التالية:

  • حدِّد اتجاه بيانات الصورة الواردة في العنصر CMSampleBuffer.

    للحصول على اتجاه الصورة:

    SwiftObjective-C
    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;
      }
    }
          
  • أنشئ كائن VisionImage باستخدام كائن CMSampleBuffer واتجاهه:
    SwiftObjective-C
    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];

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

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

SwiftObjective-C
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 (labels.count == 0) {
            // Handle the error.
            return;
        }
        // Show results.
     }];

بشكل متزامن:

SwiftObjective-C
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.

4. الحصول على معلومات عن الأجسام المصنَّفة

إذا نجحت عملية تصنيف الصور، ستُرجع مصفوفة من ImageLabel. يمثّل كل ImageLabel شيئًا تم وضع تصنيف له في الصورة. يمكنك الحصول على وصف نصي لكل تصنيف (إذا كان متوفّرًا في البيانات الوصفية لملف نموذج TensorFlow Lite) ودرجة الثقة والفهرس. على سبيل المثال:
SwiftObjective-C
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 للحصول على النتائج بشكل متزامن من إطار الفيديو المحدَّد. اضبط alwaysDiscardsLateVideoFrames في AVCaptureVideoDataOutput على true لتقليل عدد المكالمات إلى أداة الرصد. إذا توفّر إطار فيديو جديد أثناء تشغيل أداة الكشف، سيتم تجاهله.
  • إذا كنت تستخدِم ناتج أداة الكشف لوضع الرسومات فوق صورة الإدخال، يمكنك أولاً الحصول على النتيجة من ML Kit، ثم عرض الصورة ووضعها فوق الصورة الأصلية في خطوة واحدة. وبذلك، يتم عرض المحتوى على سطح العرض مرّة واحدة فقط لكل إطار إدخال تمت معالجته. يمكنك الاطّلاع على updatePreviewOverlayViewWithLastFrame في نموذج البدء السريع لمجموعة ML Kit للاطّلاع على مثال.