זיהוי טקסט בתמונות באמצעות ML Kit ב-iOS

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

תוכלו להשתמש ב-ML Kit כדי לזהות טקסט בתמונות או בסרטונים, כמו טקסט של שלט. המאפיינים העיקריים של התכונה הזו הם:

ממשק API לזיהוי טקסט v2
תיאורזיהוי טקסט בתמונות או בסרטונים, תמיכה בסקריפטים לטיניים, סינית, דוונגארי, יפנית וקוריאנית ומגוון רחב של שפות.
שמות של SDKGoogleMLKit/TextRecognition
GoogleMLKit/TextRecognitionChinese
GoogleMLKit/TextRecognitionDevanagari
GoogleMLKit/TextRecognitionJapanese
GoogleMLKit/TextRecognitionKorean
יישוםהנכסים מקושרים באופן סטטי לאפליקציה בזמן היצירה
ההשפעה של גודל האפליקציהכ-38MB לכל סקריפט SDK
ביצועיםזמן אמת ברוב המכשירים עבור SDK Latin Script, אחרים איטיים יותר.

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

  1. יש לכלול ב-Podfile את מוטות ה-ML Kit הבאים:
    # To recognize Latin script
    pod 'GoogleMLKit/TextRecognition', '3.2.0'
    # To recognize Chinese script
    pod 'GoogleMLKit/TextRecognitionChinese', '3.2.0'
    # To recognize Devanagari script
    pod 'GoogleMLKit/TextRecognitionDevanagari', '3.2.0'
    # To recognize Japanese script
    pod 'GoogleMLKit/TextRecognitionJapanese', '3.2.0'
    # To recognize Korean script
    pod 'GoogleMLKit/TextRecognitionKorean', '3.2.0'
    
  2. לאחר ההתקנה או עדכון של ה-Pod של הפרויקט, פותחים את פרויקט Xcode באמצעות .xcworkspace. ערכת ה-ML Kit נתמכת בגרסה Xcode 12.4 ומעלה.

1. יצירת מכונה של TextRecognizer

כדי ליצור מופע של TextRecognizer, מתקשרים אל +textRecognizer(options:) ומעבירים את האפשרויות שקשורות ל-SDK שהצהרתם עליו כתלויות למעלה:

Swift

// When using Latin script recognition SDK
let latinOptions = TextRecognizerOptions()
let latinTextRecognizer = TextRecognizer.textRecognizer(options:options)

// When using Chinese script recognition SDK
let chineseOptions = ChineseTextRecognizerOptions()
let chineseTextRecognizer = TextRecognizer.textRecognizer(options:options)

// When using Devanagari script recognition SDK
let devanagariOptions = DevanagariTextRecognizerOptions()
let devanagariTextRecognizer = TextRecognizer.textRecognizer(options:options)

// When using Japanese script recognition SDK
let japaneseOptions = JapaneseTextRecognizerOptions()
let japaneseTextRecognizer = TextRecognizer.textRecognizer(options:options)

// When using Korean script recognition SDK
let koreanOptions = KoreanTextRecognizerOptions()
let koreanTextRecognizer = TextRecognizer.textRecognizer(options:options)

Objective-C

// When using Latin script recognition SDK
MLKTextRecognizerOptions *latinOptions = [[MLKTextRecognizerOptions alloc] init];
MLKTextRecognizer *latinTextRecognizer = [MLKTextRecognizer textRecognizerWithOptions:options];

// When using Chinese script recognition SDK
MLKChineseTextRecognizerOptions *chineseOptions = [[MLKChineseTextRecognizerOptions alloc] init];
MLKTextRecognizer *chineseTextRecognizer = [MLKTextRecognizer textRecognizerWithOptions:options];

// When using Devanagari script recognition SDK
MLKDevanagariTextRecognizerOptions *devanagariOptions = [[MLKDevanagariTextRecognizerOptions alloc] init];
MLKTextRecognizer *devanagariTextRecognizer = [MLKTextRecognizer textRecognizerWithOptions:options];

// When using Japanese script recognition SDK
MLKJapaneseTextRecognizerOptions *japaneseOptions = [[MLKJapaneseTextRecognizerOptions alloc] init];
MLKTextRecognizer *japaneseTextRecognizer = [MLKTextRecognizer textRecognizerWithOptions:options];

// When using Korean script recognition SDK
MLKKoreanTextRecognizerOptions *koreanOptions = [[MLKKoreanTextRecognizerOptions alloc] init];
MLKTextRecognizer *koreanTextRecognizer = [MLKTextRecognizer textRecognizerWithOptions:options];

2. הכנת תמונת הקלט

התמונה צריכה לעבור UIImage או CMSampleBufferRef לשיטה TextRecognizer's process(_:completion:):

יצירת אובייקט 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. עיבוד התמונה

לאחר מכן, מעבירים את התמונה לשיטה process(_:completion:):

Swift

textRecognizer.process(visionImage) { result, error in
  guard error == nil, let result = result else {
    // Error handling
    return
  }
  // Recognized text
}

Objective-C

[textRecognizer processImage:image
                  completion:^(MLKText *_Nullable result,
                               NSError *_Nullable error) {
  if (error != nil || result == nil) {
    // Error handling
    return;
  }
  // Recognized text
}];

4. חילוץ טקסט מבלוקים של טקסט מזוהה

אם פעולת זיהוי הטקסט מצליחה, הוא מחזיר אובייקט Text. אובייקט Text מכיל את הטקסט המלא שזוהה בתמונה, ואפס או יותר מהאובייקטים TextBlock.

כל TextBlock מייצג בלוק מלבני של טקסט, שמכיל אפס אובייקטים TextLine או יותר. כל אובייקט TextLine מכיל אפס אובייקטים TextElement או יותר, שמייצגים מילים וישויות דומות למילים, כמו תאריכים ומספרים.

בכל אובייקט TextBlock, TextLine ו-TextElement, אפשר לזהות את הטקסט המזוהה באזור ובקואורדינטות של האזור.

למשל:

Swift

let resultText = result.text
for block in result.blocks {
    let blockText = block.text
    let blockLanguages = block.recognizedLanguages
    let blockCornerPoints = block.cornerPoints
    let blockFrame = block.frame
    for line in block.lines {
        let lineText = line.text
        let lineLanguages = line.recognizedLanguages
        let lineCornerPoints = line.cornerPoints
        let lineFrame = line.frame
        for element in line.elements {
            let elementText = element.text
            let elementCornerPoints = element.cornerPoints
            let elementFrame = element.frame
        }
    }
}

Objective-C

NSString *resultText = result.text;
for (MLKTextBlock *block in result.blocks) {
  NSString *blockText = block.text;
  NSArray<MLKTextRecognizedLanguage *> *blockLanguages = block.recognizedLanguages;
  NSArray<NSValue *> *blockCornerPoints = block.cornerPoints;
  CGRect blockFrame = block.frame;
  for (MLKTextLine *line in block.lines) {
    NSString *lineText = line.text;
    NSArray<MLKTextRecognizedLanguage *> *lineLanguages = line.recognizedLanguages;
    NSArray<NSValue *> *lineCornerPoints = line.cornerPoints;
    CGRect lineFrame = line.frame;
    for (MLKTextElement *element in line.elements) {
      NSString *elementText = element.text;
      NSArray<NSValue *> *elementCornerPoints = element.cornerPoints;
      CGRect elementFrame = element.frame;
    }
  }
}

הנחיות להזנת תמונה

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

    לדוגמה, תמונה בגודל 640x480 עשויה להתאים לסריקת כרטיס ביקור שנמצא ברוחב מלא של התמונה. כדי לסרוק מסמך מודפס על דף בגודל אות, ייתכן שיהיה צורך בתמונה בגודל 720x1280 פיקסלים.

  • התמקדות בתמונה נמוכה עלולה להשפיע על הדיוק של זיהוי הטקסט. אם לא מתקבלות תוצאות קבילות, כדאי לבקש מהמשתמש לצלם שוב את התמונה.

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

טיפים לשיפור הביצועים

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