זיהוי טקסט בתמונות עם ערכת ML ב-iOS

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

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

  1. אם עדיין לא הוספת את Firebase לאפליקציה שלך, עשה זאת על ידי ביצוע השלבים במדריך לתחילת העבודה .
  2. כלול את ספריות ML Kit ב-Podfile שלך:
    pod 'Firebase/MLVision', '6.25.0'
    # If using an on-device API:
    pod 'Firebase/MLVisionTextModel', '6.25.0'
    
    לאחר שתתקין או תעדכן את ה-Pods של הפרויקט שלך, הקפד לפתוח את פרויקט Xcode שלך ​​באמצעות .xcworkspace שלו.
  3. באפליקציה שלך, ייבא את Firebase:

    מָהִיר

    import Firebase

    Objective-C

    @import Firebase;
  4. אם ברצונך להשתמש במודל מבוסס ענן, ועדיין לא הפעלת את ממשקי API מבוססי הענן עבור הפרויקט שלך, עשה זאת כעת:

    1. פתח את דף ממשקי API של ML Kit של מסוף Firebase.
    2. אם עדיין לא שדרגת את הפרויקט שלך לתוכנית תמחור Blaze, לחץ על שדרג כדי לעשות זאת. (תתבקש לשדרג רק אם הפרויקט שלך אינו בתוכנית Blaze.)

      רק פרויקטים ברמת Blaze יכולים להשתמש בממשקי API מבוססי ענן.

    3. אם ממשקי API מבוססי ענן עדיין לא מופעלים, לחץ על הפעל ממשקי API מבוססי ענן .

    אם ברצונך להשתמש רק בדגם שבמכשיר, תוכל לדלג על שלב זה.

עכשיו אתה מוכן להתחיל לזהות טקסט בתמונות.

הנחיות לקלט תמונה

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

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

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

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


זיהוי טקסט בתמונות

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

1. הפעל את מזהה הטקסט

העבר את התמונה בתור `UIImage` או `CMSampleBufferRef` לשיטת `process(_:completion:)` של `VisionTextRecognizer`:
  1. קבל מופע של VisionTextRecognizer על ידי קריאה ל- onDeviceTextRecognizer או cloudTextRecognizer :

    מָהִיר

    כדי להשתמש בדגם במכשיר:

    let vision = Vision.vision()
    let textRecognizer = vision.onDeviceTextRecognizer()
    

    כדי להשתמש במודל הענן:

    let vision = Vision.vision()
    let textRecognizer = vision.cloudTextRecognizer()
    
    // Or, to provide language hints to assist with language detection:
    // See https://cloud.google.com/vision/docs/languages for supported languages
    let options = VisionCloudTextRecognizerOptions()
    options.languageHints = ["en", "hi"]
    let textRecognizer = vision.cloudTextRecognizer(options: options)
    

    Objective-C

    כדי להשתמש בדגם במכשיר:

    FIRVision *vision = [FIRVision vision];
    FIRVisionTextRecognizer *textRecognizer = [vision onDeviceTextRecognizer];
    

    כדי להשתמש במודל הענן:

    FIRVision *vision = [FIRVision vision];
    FIRVisionTextRecognizer *textRecognizer = [vision cloudTextRecognizer];
    
    // Or, to provide language hints to assist with language detection:
    // See https://cloud.google.com/vision/docs/languages for supported languages
    FIRVisionCloudTextRecognizerOptions *options =
            [[FIRVisionCloudTextRecognizerOptions alloc] init];
    options.languageHints = @[@"en", @"hi"];
    FIRVisionTextRecognizer *textRecognizer = [vision cloudTextRecognizerWithOptions:options];
    
  2. צור אובייקט VisionImage באמצעות UIImage או CMSampleBufferRef .

    כדי להשתמש UIImage :

    1. במידת הצורך, סובב את התמונה כך שהמאפיין imageOrientation שלה יהיה .up .
    2. צור אובייקט VisionImage באמצעות UIImage המסובב כהלכה. אל תציין מטא נתונים כלשהם של סיבוב - יש להשתמש בערך ברירת המחדל, .topLeft .

      מָהִיר

      let image = VisionImage(image: uiImage)

      Objective-C

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

    כדי להשתמש ב- CMSampleBufferRef :

    1. צור אובייקט VisionImageMetadata המציין את הכיוון של נתוני התמונה הכלולים במאגר CMSampleBufferRef .

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

      מָהִיר

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

      לאחר מכן, צור את אובייקט המטא נתונים:

      מָהִיר

      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 והמטא נתונים של הסיבוב:

      מָהִיר

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

      Objective-C

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer];
      image.metadata = metadata;
  3. לאחר מכן, העבירו את התמונה לשיטת process(_:completion:) :

    מָהִיר

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

    Objective-C

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

2. חלץ טקסט מגושים של טקסט מוכר

אם פעולת זיהוי הטקסט תצליח, היא תחזיר אובייקט [`VisionText`][VisionText]. אובייקט `VisionText` מכיל את הטקסט המלא המוכר בתמונה ואפס או יותר אובייקטים [`VisionTextBlock`][VisionTextBlock]. כל `VisionTextBlock` מייצג בלוק מלבני של טקסט, המכיל אפס או יותר אובייקטים [`VisionTextLine`][VisionTextLine]. כל אובייקט `VisionTextLine` מכיל אפס או יותר אובייקטים [`VisionTextElement`][VisionTextElement], המייצגים מילים וישויות דמויות מילים (תאריכים, מספרים וכן הלאה). עבור כל אובייקט `VisionTextBlock`, `VisionTextLine` ו-`VisionTextElement`, ניתן לזהות את הטקסט באזור ואת הקואורדינטות התוחמות של האזור. לדוגמה:

מָהִיר

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

Objective-C

NSString *resultText = result.text;
for (FIRVisionTextBlock *block in result.blocks) {
  NSString *blockText = block.text;
  NSNumber *blockConfidence = block.confidence;
  NSArray<FIRVisionTextRecognizedLanguage *> *blockLanguages = block.recognizedLanguages;
  NSArray<NSValue *> *blockCornerPoints = block.cornerPoints;
  CGRect blockFrame = block.frame;
  for (FIRVisionTextLine *line in block.lines) {
    NSString *lineText = line.text;
    NSNumber *lineConfidence = line.confidence;
    NSArray<FIRVisionTextRecognizedLanguage *> *lineLanguages = line.recognizedLanguages;
    NSArray<NSValue *> *lineCornerPoints = line.cornerPoints;
    CGRect lineFrame = line.frame;
    for (FIRVisionTextElement *element in line.elements) {
      NSString *elementText = element.text;
      NSNumber *elementConfidence = element.confidence;
      NSArray<FIRVisionTextRecognizedLanguage *> *elementLanguages = element.recognizedLanguages;
      NSArray<NSValue *> *elementCornerPoints = element.cornerPoints;
      CGRect elementFrame = element.frame;
    }
  }
}

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

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

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

הצעדים הבאים


זיהוי טקסט בתמונות של מסמכים

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

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

כדי להשתמש ב-API לזיהוי טקסט של מסמכים:

1. הפעל את מזהה הטקסט

העבר את התמונה כ- UIImage או CMSampleBufferRef לשיטת process(_:completion:) של VisionDocumentTextRecognizer :

  1. קבל מופע של VisionDocumentTextRecognizer על ידי קריאה ל- cloudDocumentTextRecognizer :

    מָהִיר

    let vision = Vision.vision()
    let textRecognizer = vision.cloudDocumentTextRecognizer()
    
    // Or, to provide language hints to assist with language detection:
    // See https://cloud.google.com/vision/docs/languages for supported languages
    let options = VisionCloudDocumentTextRecognizerOptions()
    options.languageHints = ["en", "hi"]
    let textRecognizer = vision.cloudDocumentTextRecognizer(options: options)
    

    Objective-C

    FIRVision *vision = [FIRVision vision];
    FIRVisionDocumentTextRecognizer *textRecognizer = [vision cloudDocumentTextRecognizer];
    
    // Or, to provide language hints to assist with language detection:
    // See https://cloud.google.com/vision/docs/languages for supported languages
    FIRVisionCloudDocumentTextRecognizerOptions *options =
            [[FIRVisionCloudDocumentTextRecognizerOptions alloc] init];
    options.languageHints = @[@"en", @"hi"];
    FIRVisionDocumentTextRecognizer *textRecognizer = [vision cloudDocumentTextRecognizerWithOptions:options];
    
  2. צור אובייקט VisionImage באמצעות UIImage או CMSampleBufferRef .

    כדי להשתמש UIImage :

    1. במידת הצורך, סובב את התמונה כך שהמאפיין imageOrientation שלה יהיה .up .
    2. צור אובייקט VisionImage באמצעות UIImage המסובב כהלכה. אל תציין מטא נתונים כלשהם של סיבוב - יש להשתמש בערך ברירת המחדל, .topLeft .

      מָהִיר

      let image = VisionImage(image: uiImage)

      Objective-C

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

    כדי להשתמש ב- CMSampleBufferRef :

    1. צור אובייקט VisionImageMetadata המציין את הכיוון של נתוני התמונה הכלולים במאגר CMSampleBufferRef .

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

      מָהִיר

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

      לאחר מכן, צור את אובייקט המטא נתונים:

      מָהִיר

      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 והמטא נתונים של הסיבוב:

      מָהִיר

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

      Objective-C

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer];
      image.metadata = metadata;
  3. לאחר מכן, העבירו את התמונה לשיטת process(_:completion:) :

    מָהִיר

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

    Objective-C

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

2. חלץ טקסט מגושים של טקסט מוכר

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

עבור כל אובייקט VisionDocumentTextBlock , VisionDocumentTextParagraph , VisionDocumentTextWord ו- VisionDocumentTextSymbol , ניתן לזהות את הטקסט באזור ואת הקואורדינטות התוחמות של האזור.

לדוגמה:

מָהִיר

let resultText = result.text
for block in result.blocks {
    let blockText = block.text
    let blockConfidence = block.confidence
    let blockRecognizedLanguages = block.recognizedLanguages
    let blockBreak = block.recognizedBreak
    let blockCornerPoints = block.cornerPoints
    let blockFrame = block.frame
    for paragraph in block.paragraphs {
        let paragraphText = paragraph.text
        let paragraphConfidence = paragraph.confidence
        let paragraphRecognizedLanguages = paragraph.recognizedLanguages
        let paragraphBreak = paragraph.recognizedBreak
        let paragraphCornerPoints = paragraph.cornerPoints
        let paragraphFrame = paragraph.frame
        for word in paragraph.words {
            let wordText = word.text
            let wordConfidence = word.confidence
            let wordRecognizedLanguages = word.recognizedLanguages
            let wordBreak = word.recognizedBreak
            let wordCornerPoints = word.cornerPoints
            let wordFrame = word.frame
            for symbol in word.symbols {
                let symbolText = symbol.text
                let symbolConfidence = symbol.confidence
                let symbolRecognizedLanguages = symbol.recognizedLanguages
                let symbolBreak = symbol.recognizedBreak
                let symbolCornerPoints = symbol.cornerPoints
                let symbolFrame = symbol.frame
            }
        }
    }
}

Objective-C

NSString *resultText = result.text;
for (FIRVisionDocumentTextBlock *block in result.blocks) {
  NSString *blockText = block.text;
  NSNumber *blockConfidence = block.confidence;
  NSArray<FIRVisionTextRecognizedLanguage *> *blockRecognizedLanguages = block.recognizedLanguages;
  FIRVisionTextRecognizedBreak *blockBreak = block.recognizedBreak;
  CGRect blockFrame = block.frame;
  for (FIRVisionDocumentTextParagraph *paragraph in block.paragraphs) {
    NSString *paragraphText = paragraph.text;
    NSNumber *paragraphConfidence = paragraph.confidence;
    NSArray<FIRVisionTextRecognizedLanguage *> *paragraphRecognizedLanguages = paragraph.recognizedLanguages;
    FIRVisionTextRecognizedBreak *paragraphBreak = paragraph.recognizedBreak;
    CGRect paragraphFrame = paragraph.frame;
    for (FIRVisionDocumentTextWord *word in paragraph.words) {
      NSString *wordText = word.text;
      NSNumber *wordConfidence = word.confidence;
      NSArray<FIRVisionTextRecognizedLanguage *> *wordRecognizedLanguages = word.recognizedLanguages;
      FIRVisionTextRecognizedBreak *wordBreak = word.recognizedBreak;
      CGRect wordFrame = word.frame;
      for (FIRVisionDocumentTextSymbol *symbol in word.symbols) {
        NSString *symbolText = symbol.text;
        NSNumber *symbolConfidence = symbol.confidence;
        NSArray<FIRVisionTextRecognizedLanguage *> *symbolRecognizedLanguages = symbol.recognizedLanguages;
        FIRVisionTextRecognizedBreak *symbolBreak = symbol.recognizedBreak;
        CGRect symbolFrame = symbol.frame;
      }
    }
  }
}

הצעדים הבאים