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

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

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

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

    מָהִיר

    import Firebase

    Objective-C

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

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

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

    3. אם APIs מבוסס ענן אינו כבר מופעל, לחץ אפשר ממשקים מבוססי ענן.

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

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

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

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

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

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

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


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

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

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

העבר את התמונה כ- 'UIImage' או כ- 'CMSampleBufferRef' לשיטת 'VisionTextRecognizer' (_: complete:) ':
  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 אל VisionDocumentTextRecognizer של" process(_:completion:) השיטה:

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

הצעדים הבאים