תווי תמונות עם דגם מאומן AutoML בפלטפורמות של Apple

לאחר שתאמן את הדגם שלך באמצעות AutoML Vision Edge , תוכל להשתמש בו באפליקציה שלך כדי לתייג תמונות.

ישנן שתי דרכים לשלב דגמים שהוכשרו מ-AutoML Vision Edge. אתה יכול לאגד את המודל על ידי העתקת קבצי המודל לפרויקט Xcode שלך, או שאתה יכול להוריד אותו באופן דינמי מ-Firebase.

אפשרויות חבילת דגמים
מאגד באפליקציה שלך
  • הדגם הוא חלק מהצרור
  • הדגם זמין באופן מיידי, גם כאשר מכשיר אפל במצב לא מקוון
  • אין צורך בפרויקט Firebase
מתארח עם Firebase
  • מארח את הדגם על ידי העלאתו ל- Firebase Machine Learning
  • מקטין את גודל חבילת האפליקציות
  • הורדת הדגם מתבצעת לפי דרישה
  • דחף עדכוני מודל מבלי לפרסם מחדש את האפליקציה שלך
  • בדיקת A/B קלה עם Firebase Remote Config
  • דורש פרויקט Firebase

לפני שאתה מתחיל

  1. כלול את ספריות ML Kit ב-Podfile שלך:

    לאגד דגם עם האפליקציה שלך:

    pod 'GoogleMLKit/ImageLabelingCustom'
    

    להורדה דינמית של מודל מ-Firebase, הוסף את התלות LinkFirebase :

    pod 'GoogleMLKit/ImageLabelingCustom'
    pod 'GoogleMLKit/LinkFirebase'
    
  2. לאחר התקנת או עדכון Pods של הפרויקט שלך, פתח את פרויקט Xcode שלך ​​באמצעות .xcworkspace שלו. ערכת ML נתמכת בגרסת Xcode 12.2 ומעלה.

  3. אם ברצונך להוריד דגם , הקפד להוסיף את Firebase לפרויקט האנדרואיד שלך , אם עדיין לא עשית זאת. זה לא נדרש כאשר אתה מצרף את הדגם.

1. טען את הדגם

הגדר מקור דגם מקומי

כדי לאגד את הדגם עם האפליקציה שלך:

  1. חלץ את המודל ואת המטא נתונים שלו מארכיון ה-zip שהורדת ממסוף Firebase לתיקיה:

    your_model_directory
      |____dict.txt
      |____manifest.json
      |____model.tflite
    

    כל שלושת הקבצים חייבים להיות באותה תיקיה. אנו ממליצים להשתמש בקבצים כפי שהורדתם אותם, ללא שינוי (כולל שמות הקבצים).

  2. העתק את התיקיה לפרויקט Xcode שלך, הקפד לבחור באפשרות צור הפניות לתיקיות כאשר אתה עושה זאת. קובץ הדגם והמטא נתונים ייכללו ב-App Bundle וזמינים ל-ML Kit.

  3. צור אובייקט LocalModel , תוך ציון הנתיב לקובץ המניפסט של המודל:

    מָהִיר

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

    Objective-C

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

הגדר מקור מודל שמתארח ב-Firebase

כדי להשתמש במודל המתארח מרחוק, צור אובייקט CustomRemoteModel , תוך ציון השם שהקצית למודל כשפרסמת אותו:

מָהִיר

// Initialize the model source with the name you assigned in
// the Firebase console.
let remoteModelSource = FirebaseModelSource(name: "your_remote_model")
let remoteModel = CustomRemoteModel(remoteModelSource: remoteModelSource)

Objective-C

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

לאחר מכן, התחל את משימת הורדת הדגם, תוך ציון התנאים שבהם ברצונך לאפשר הורדה. אם הדגם אינו במכשיר, או אם זמינה גרסה חדשה יותר של הדגם, המשימה תוריד את הדגם באופן אסינכרוני מ-Firebase:

מָהִיר

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] downloadRemoteModel:remoteModel
                                             conditions:downloadConditions];

אפליקציות רבות מתחילות את משימת ההורדה בקוד האתחול שלהן, אך תוכל לעשות זאת בכל שלב לפני שתצטרך להשתמש במודל.

צור תוויות תמונה מהדגם שלך

לאחר שתגדיר את מקורות המודל שלך, צור אובייקט ImageLabeler מאחד מהם.

אם יש לך רק מודל מקובץ מקומית, פשוט צור תוויות מאובייקט LocalModel שלך והגדר את סף ציון הביטחון שאתה רוצה לדרוש (ראה הערכת המודל שלך ):

מָהִיר

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

Objective-C

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

אם יש לך דגם שמתארח מרחוק, תצטרך לבדוק שהוא הורד לפני שתפעיל אותו. אתה יכול לבדוק את המצב של משימת הורדת המודל באמצעות שיטת isModelDownloaded(remoteModel:) של מנהל המודלים.

למרות שאתה רק צריך לאשר זאת לפני הפעלת התווית, אם יש לך גם דגם שמתארח מרחוק וגם דגם עם חבילה מקומית, ייתכן שיהיה הגיוני לבצע את הבדיקה הזו בעת הפעלת ה- ImageLabeler : צור תוויות מהדגם המרוחק אם זה הורד, ומהדגם המקומי אחרת.

מָהִיר

var options: CustomImageLabelerOptions
if (ModelManager.modelManager().isModelDownloaded(remoteModel)) {
  options = CustomImageLabelerOptions(remoteModel: remoteModel)
} else {
  options = CustomImageLabelerOptions(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

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

אם יש לך רק דגם שמתארח מרחוק, עליך להשבית את הפונקציונליות הקשורה לדגם - למשל, לאפור או להסתיר חלק מהממשק שלך - עד שתאשר שהדגם הורד.

אתה יכול לקבל את סטטוס הורדת הדגם על ידי צירוף צופים למרכז ההתראות המוגדר כברירת מחדל. הקפד להשתמש בהתייחסות חלשה self בבלוק הצופה, מכיוון שההורדות יכולות להימשך זמן מה, והאובייקט המקור יכול להשתחרר עד לסיום ההורדה. לדוגמה:

מָהִיר

NotificationCenter.default.addObserver(
    forName: .mlkitMLModelDownloadDidSucceed,
    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: .mlkitMLModelDownloadDidFail,
    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 או CMSampleBufferRef .

אם אתה משתמש ב- UIImage , בצע את השלבים הבאים:

  • צור אובייקט VisionImage עם UIImage . הקפד לציין את .orientation הנכון.

    מָהִיר

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

    Objective-C

    MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image];
    visionImage.orientation = image.imageOrientation;

אם אתה משתמש ב- CMSampleBufferRef , בצע את השלבים הבאים:

  • ציין את הכיוון של נתוני התמונה הכלולים במאגר CMSampleBufferRef .

    כדי לקבל את כיוון התמונה:

    מָהִיר

    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 position == AVCaptureDevicePositionFront ? UIImageOrientationLeftMirrored
                                                          : UIImageOrientationRight;
    
        case UIDeviceOrientationLandscapeLeft:
          return position == AVCaptureDevicePositionFront ? UIImageOrientationDownMirrored
                                                          : UIImageOrientationUp;
        case UIDeviceOrientationPortraitUpsideDown:
          return position == AVCaptureDevicePositionFront ? UIImageOrientationRightMirrored
                                                          : UIImageOrientationLeft;
        case UIDeviceOrientationLandscapeRight:
          return position == AVCaptureDevicePositionFront ? UIImageOrientationUpMirrored
                                                          : UIImageOrientationDown;
        case UIDeviceOrientationUnknown:
        case UIDeviceOrientationFaceUp:
        case UIDeviceOrientationFaceDown:
          return UIImageOrientationUp;
      }
    }
          
  • צור אובייקט VisionImage באמצעות האובייקט והכיוון CMSampleBufferRef :

    מָהִיר

    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. הפעל את תווית התמונות

באופן אסינכרוני:

מָהִיר

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<MLKImageLabel *> *_Nullable labels,
                   NSError *_Nullable error) {
        if (label.count == 0) {
            // Handle the error.
            return;
        }
        // Show results.
     }];

באופן סינכרוני:

מָהִיר

var labels: [ImageLabel]
do {
    labels = try imageLabeler.results(in: image)
} catch let error {
    // Handle the error.
    return
}
// Show results.

Objective-C

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

4. קבל מידע על אובייקטים מסומנים

אם פעולת תיוג התמונה מצליחה, היא מחזירה מערך של ImageLabel . כל ImageLabel מייצג משהו שסומן בתמונה. אתה יכול לקבל את תיאור הטקסט של כל תווית (אם זמין במטא נתונים של קובץ המודל של TensorFlow Lite), ציון ביטחון ואינדקס. לדוגמה:

מָהִיר

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

טיפים לשיפור הביצועים בזמן אמת

אם ברצונך לסמן תמונות ביישום בזמן אמת, פעל לפי ההנחיות הבאות כדי להשיג את קצבי המסגרות הטובים ביותר:

  • מצערת קוראת לגלאי. אם מסגרת וידאו חדשה הופכת לזמינה בזמן שהגלאי פועל, שחרר את המסגרת.
  • אם אתה משתמש בפלט של הגלאי כדי לשכב גרפיקה על תמונת הקלט, תחילה קבל את התוצאה, ולאחר מכן עבד את התמונה ואת שכבת העל בצעד אחד. על ידי כך, אתה מעבד למשטח התצוגה רק פעם אחת עבור כל מסגרת קלט. ראה את המחלקות previewOverlayView ו- FIRDetectionOverlayView באפליקציה לדוגמה לראווה לדוגמא.