תיוג תמונות באמצעות ML Kit ב-iOS

קל לארגן דפים בעזרת אוספים אפשר לשמור ולסווג תוכן על סמך ההעדפות שלך.

אפשר להשתמש בערכת למידת מכונה כדי להוסיף תוויות לאובייקטים שזוהו בתמונה. מודל ברירת המחדל שכלול בערכת ה-ML תומך ביותר מ-400 תוויות שונות.

רוצה לנסות?

לפני שמתחילים

  1. יש לכלול את ה-pods הבאים ב-ML Kit ב-Podfile:
    pod 'GoogleMLKit/ImageLabeling', '3.2.0'
    
  2. אחרי ההתקנה או העדכון של ה-Pods של הפרויקט, פותחים את פרויקט Xcode באמצעות .xcworkspace שלו. ערכת ה-ML נתמכת ב-Xcode מגרסה 12.4 ואילך.

עכשיו אפשר להוסיף תוויות לתמונות.

1. מכינים את תמונת הקלט

יוצרים אובייקט 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];

2. הגדרה והפעלה של מתייג התמונות

כדי להוסיף תוויות לאובייקטים בתמונה, יש להעביר את האובייקט VisionImage למתודה processImage() של ImageLabeler.

  1. בתור התחלה, משיגים מופע של ImageLabeler.

Swift

let labeler = ImageLabeler.imageLabeler()

// Or, to set the minimum confidence required:
// let options = ImageLabelerOptions()
// options.confidenceThreshold = 0.7
// let labeler = ImageLabeler.imageLabeler(options: options)

Objective-C

MLKImageLabeler *labeler = [MLKImageLabeler imageLabeler];

// Or, to set the minimum confidence required:
// MLKImageLabelerOptions *options =
//         [[MLKImageLabelerOptions alloc] init];
// options.confidenceThreshold = 0.7;
// MLKImageLabeler *labeler =
//         [MLKImageLabeler imageLabelerWithOptions:options];
  1. לאחר מכן, צריך להעביר את התמונה לשיטה processImage():

Swift

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

    // Task succeeded.
    // ...
}

Objective-C

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

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

3. קבלת מידע על אובייקטים מתויגים

אם התיוג של התמונות מצליח, ה-handler של ההשלמה יקבל מערך של אובייקטים מסוג ImageLabel. כל אובייקט ImageLabel מייצג משהו שסומן בתמונה. מודל הבסיס תומך ביותר מ-400 תוויות שונות. תוכלו לראות את תיאור הטקסט של כל תווית, להוסיף לאינדקס בין כל התוויות שנתמכות במודל, ואת מידת המהימנות של ההתאמה. למשל:

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

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

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

  • לעיבוד מסגרות וידאו, יש להשתמש ב-API הסינכרוני של results(in:) של תווית התמונה. ניתן לקרוא לשיטה הזו באמצעות הפונקציה AVCaptureVideoDataOutputSampleBufferDelegate captureOutput(_, didOutput:from:) כדי לקבל תוצאות סינכרוניות מהפריים של הווידאו. שמירת הקובץ alwaysDiscardsLateVideoFrames של AVCaptureVideoDataOutput בתור true כדי לווסת את השיחות לתיוג התמונות. אם יהפוך לפריים חדש של וידאו בזמן שמתייג התמונות פועל, הוא יוסר.
  • אם משתמשים בפלט של הלייבל שמכיל שכבת-על לגרפיקה בתמונת הקלט, קודם צריך לקבל את התוצאה מ-ML Kit, ואז לעבד את התמונה ואת שכבת-העל בפעולה אחת. אם עושים זאת, מתבצע רינדור של התצוגה למשטח התצוגה רק פעם אחת בכל מסגרת קלט שעברה עיבוד. כדי לקבל דוגמה, אפשר לעיין בupdatePreviewLayerViewWithLastFrame שבדוגמה למתחילים של ML.