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

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

قبل البدء

  1. إذا لم يسبق لك إضافة Firebase إلى تطبيقك، عليك اتّباع الخطوات الواردة في دليل البدء.
  2. تضمين مكتبات ML Kit في Podfile:
    pod 'Firebase/MLVision', '6.25.0'
    pod 'Firebase/MLVisionAutoML', '6.25.0'
    
    بعد تثبيت مجموعات Podfile الخاصة بمشروعك أو تعديلها، احرص على فتح مشروع Xcode الخاص بك باستخدام .xcworkspace.
  3. في تطبيقك، استورد Firebase:

    Swift

    import Firebase

    Objective-C

    @import Firebase;

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

تشغّل مجموعة أدوات تعلُّم الآلة النماذج التي يتم إنشاؤها تلقائيًا باستخدام تعلُّم الآلة على الجهاز. مع ذلك، يمكنك ضبط أداة تعلّم الآلة لتحميل نموذجك عن بُعد من Firebase أو من مساحة التخزين على الجهاز أو كليهما.

وعند استضافة النموذج على Firebase، يمكنك تعديل النموذج بدون طرح إصدار جديد من التطبيق، ويمكنك استخدام "الإعداد عن بُعد" و"اختبار A/B" لعرض نماذج مختلفة ديناميكيًا لمجموعات مختلفة من المستخدمين.

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

من خلال تجميع نموذجك مع تطبيقك، يمكنك ضمان استمرار عمل ميزات تعلُّم الآلة في تطبيقك في حال عدم توفُّر النموذج المستضاف على Firebase.

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

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

Swift

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

Objective-C

FIRAutoMLRemoteModel *remoteModel = [[FIRAutoMLRemoteModel 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

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

NSProgress *downloadProgress =
    [[FIRModelManager modelManager] downloadRemoteModel:remoteModel
                                             conditions:downloadConditions];

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

إعداد مصدر نموذج محلي

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

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

    Swift

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

    Objective-C

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

إنشاء مصنِّف للصور من نموذجك

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

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

Swift

let options = VisionOnDeviceAutoMLImageLabelerOptions(localModel: localModel)
options.confidenceThreshold = 0  // Evaluate your model in the Firebase console
                                 // to determine an appropriate value.
let labeler = Vision.vision().onDeviceAutoMLImageLabeler(options: options)

Objective-C

FIRVisionOnDeviceAutoMLImageLabelerOptions *options =
    [[FIRVisionOnDeviceAutoMLImageLabelerOptions alloc] initWithLocalModel:localModel];
options.confidenceThreshold = 0;  // Evaluate your model in the Firebase console
                                  // to determine an appropriate value.
FIRVisionImageLabeler *labeler =
    [[FIRVision vision] onDeviceAutoMLImageLabelerWithOptions:options];

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

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

Swift

var options: VisionOnDeviceAutoMLImageLabelerOptions?
if (ModelManager.modelManager().isModelDownloaded(remoteModel)) {
  options = VisionOnDeviceAutoMLImageLabelerOptions(remoteModel: remoteModel)
} else {
  options = VisionOnDeviceAutoMLImageLabelerOptions(localModel: localModel)
}
options.confidenceThreshold = 0  // Evaluate your model in the Firebase console
                                 // to determine an appropriate value.
let labeler = Vision.vision().onDeviceAutoMLImageLabeler(options: options)

Objective-C

VisionOnDeviceAutoMLImageLabelerOptions *options;
if ([[FIRModelManager modelManager] isModelDownloaded:remoteModel]) {
  options = [[FIRVisionOnDeviceAutoMLImageLabelerOptions alloc] initWithRemoteModel:remoteModel];
} else {
  options = [[FIRVisionOnDeviceAutoMLImageLabelerOptions alloc] initWithLocalModel:localModel];
}
options.confidenceThreshold = 0.0f;  // Evaluate your model in the Firebase console
                                     // to determine an appropriate value.
FIRVisionImageLabeler *labeler = [[FIRVision vision] onDeviceAutoMLImageLabelerWithOptions:options];

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

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

Swift

NotificationCenter.default.addObserver(
    forName: .firebaseMLModelDownloadDidSucceed,
    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: .firebaseMLModelDownloadDidFail,
    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:FIRModelDownloadDidSucceedNotification
                object:nil
                 queue:nil
            usingBlock:^(NSNotification *_Nonnull note) {
              if (weakSelf == nil | note.userInfo == nil) {
                return;
              }
              __strong typeof(self) strongSelf = weakSelf;

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

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

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

2- تحضير صورة الإدخال

بعد ذلك، ولكل صورة تريد تصنيفها، أنشِئ عنصر VisionImage باستخدام أحد الخيارات الموضّحة في هذا القسم ومرِّره إلى مثيل VisionImageLabeler (الموضّح في القسم التالي).

يمكنك إنشاء عنصر VisionImage باستخدام UIImage أو CMSampleBufferRef.

لاستخدام UIImage:

  1. إذا لزم الأمر، عليك تدوير الصورة لتكون السمة imageOrientation هي .up.
  2. أنشِئ كائن VisionImage باستخدام عنصر UIImage الذي تم تدويره بشكل صحيح. لا تحدِّد أي بيانات وصفية حول عرض الإعلانات بالتناوب، يجب استخدام القيمة التلقائية .topLeft.

    Swift

    let image = VisionImage(image: uiImage)

    Objective-C

    FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];

لاستخدام CMSampleBufferRef:

  1. أنشِئ عنصر VisionImageMetadata يحدّد اتجاه بيانات الصورة المضمَّنة في المخزن المؤقت CMSampleBufferRef.

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

    Swift

    func imageOrientation(
        deviceOrientation: UIDeviceOrientation,
        cameraPosition: AVCaptureDevice.Position
        ) -> VisionDetectorImageOrientation {
        switch deviceOrientation {
        case .portrait:
            return cameraPosition == .front ? .leftTop : .rightTop
        case .landscapeLeft:
            return cameraPosition == .front ? .bottomLeft : .topLeft
        case .portraitUpsideDown:
            return cameraPosition == .front ? .rightBottom : .leftBottom
        case .landscapeRight:
            return cameraPosition == .front ? .topRight : .bottomRight
        case .faceDown, .faceUp, .unknown:
            return .leftTop
        }
    }

    Objective-C

    - (FIRVisionDetectorImageOrientation)
        imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation
                               cameraPosition:(AVCaptureDevicePosition)cameraPosition {
      switch (deviceOrientation) {
        case UIDeviceOrientationPortrait:
          if (cameraPosition == AVCaptureDevicePositionFront) {
            return FIRVisionDetectorImageOrientationLeftTop;
          } else {
            return FIRVisionDetectorImageOrientationRightTop;
          }
        case UIDeviceOrientationLandscapeLeft:
          if (cameraPosition == AVCaptureDevicePositionFront) {
            return FIRVisionDetectorImageOrientationBottomLeft;
          } else {
            return FIRVisionDetectorImageOrientationTopLeft;
          }
        case UIDeviceOrientationPortraitUpsideDown:
          if (cameraPosition == AVCaptureDevicePositionFront) {
            return FIRVisionDetectorImageOrientationRightBottom;
          } else {
            return FIRVisionDetectorImageOrientationLeftBottom;
          }
        case UIDeviceOrientationLandscapeRight:
          if (cameraPosition == AVCaptureDevicePositionFront) {
            return FIRVisionDetectorImageOrientationTopRight;
          } else {
            return FIRVisionDetectorImageOrientationBottomRight;
          }
        default:
          return FIRVisionDetectorImageOrientationTopLeft;
      }
    }

    بعد ذلك، أنشئ كائن البيانات الوصفية:

    Swift

    let cameraPosition = AVCaptureDevice.Position.back  // Set to the capture device you used.
    let metadata = VisionImageMetadata()
    metadata.orientation = imageOrientation(
        deviceOrientation: UIDevice.current.orientation,
        cameraPosition: cameraPosition
    )

    Objective-C

    FIRVisionImageMetadata *metadata = [[FIRVisionImageMetadata alloc] init];
    AVCaptureDevicePosition cameraPosition =
        AVCaptureDevicePositionBack;  // Set to the capture device you used.
    metadata.orientation =
        [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation
                                     cameraPosition:cameraPosition];
  2. يمكنك إنشاء عنصر VisionImage باستخدام الكائن CMSampleBufferRef والبيانات الوصفية الخاصة بالتدوير:

    Swift

    let image = VisionImage(buffer: sampleBuffer)
    image.metadata = metadata

    Objective-C

    FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer];
    image.metadata = metadata;

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

لتصنيف العناصر في صورة، مرِّر كائن VisionImage إلى طريقة process() في VisionImageLabeler:

Swift

labeler.process(image) { labels, error in
    guard error == nil, let labels = labels else { return }

    // Task succeeded.
    // ...
}

Objective-C

[labeler
    processImage:image
      completion:^(NSArray<FIRVisionImageLabel *> *_Nullable labels, NSError *_Nullable error) {
        if (error != nil || labels == nil) {
          return;
        }

        // Task succeeded.
        // ...
      }];

في حال نجاح تصنيف الصور، سيتم تمرير مصفوفة من عناصر VisionImageLabel إلى معالِج الإكمال. من كل كائن، يمكنك الحصول على معلومات حول الميزة التي تم التعرف عليها في الصورة.

على سبيل المثال:

Swift

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

Objective-C

for (FIRVisionImageLabel *label in labels) {
  NSString *labelText = label.text;
  NSNumber *confidence = label.confidence;
}

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

  • التحكُّم في المكالمات الواردة إلى أداة الرصد. إذا أصبح إطار فيديو جديد متاحًا أثناء تشغيل أداة الرصد، أفلِت الإطار.
  • إذا كنت تستخدم ناتج أداة الرصد لتركيب رسومات على الصورة التي تم إدخالها، يمكنك أولاً الحصول على النتيجة من ML Kit، ثم عرض الصورة والمحتوى الذي يظهر على سطح الصورة في خطوة واحدة. ومن خلال إجراء ذلك، ستظهر على سطح الشاشة مرة واحدة فقط لكل إطار إدخال. للاطّلاع على مثال، يمكنك الاطّلاع على الفئتَين previewOverlayView وFIRDetectionOverlayView في نموذج تطبيق العرض