Mit ML Kit unter iOS Text in Bildern erkennen

Mit ML Kit können Sie Text in Bildern erkennen. ML Kit bietet sowohl eine Allzweck-API, die sich zum Erkennen von Text in Bildern eignet, z. B. Text auf einem Straßenschild, als auch eine API, die für das Erkennen von Text in Dokumenten optimiert ist. Die Allzweck-API bietet sowohl Modelle auf dem Gerät als auch cloudbasierte Modelle. Die Texterkennung in Dokumenten ist nur als cloudbasiertes Modell verfügbar. Einen Vergleich der Cloud- und On-Device-Modelle finden Sie in der Übersicht.

Hinweis

  1. Wenn Sie Firebase noch nicht in Ihre App eingebunden haben, folgen Sie der Anleitung im Leitfaden für den Einstieg.
  2. Fügen Sie die ML Kit-Bibliotheken in Ihre Podfile ein:
    pod 'Firebase/MLVision', '6.25.0'
    # If using an on-device API:
    pod 'Firebase/MLVisionTextModel', '6.25.0'
    
    Nachdem Sie die Pods Ihres Projekts installiert oder aktualisiert haben, müssen Sie Ihr Xcode-Projekt über die Datei .xcworkspace öffnen.
  3. Importieren Sie Firebase in Ihre App:

    Swift

    import Firebase

    Objective-C

    @import Firebase;
  4. Wenn Sie das cloudbasierte Modell verwenden möchten und die cloudbasierten APIs für Ihr Projekt noch nicht aktiviert haben, tun Sie dies jetzt:

    1. Öffnen Sie in der Firebase-Konsole die Seite ML Kit APIs.
    2. Wenn Sie Ihr Projekt noch nicht auf den Blaze-Tarif umgestellt haben, klicken Sie auf Upgrade, um dies zu tun. (Sie werden nur dann zum Upgrade aufgefordert, wenn Ihr Projekt nicht im Blaze-Tarif ist.)

      Cloudbasierte APIs können nur in Projekten auf Blaze-Ebene verwendet werden.

    3. Wenn cloudbasierte APIs noch nicht aktiviert sind, klicken Sie auf Cloudbasierte APIs aktivieren.

    Wenn Sie nur das On-Device-Modell verwenden möchten, können Sie diesen Schritt überspringen.

Jetzt können Sie mit der Texterkennung in Bildern beginnen.

Richtlinien für Eingabebilder

  • Damit Text von ML Kit genau erkannt werden kann, müssen Eingabebilder Text enthalten, der durch ausreichend Pixeldaten dargestellt wird. Idealerweise sollte jedes Zeichen bei lateinischem Text mindestens 16 × 16 Pixel groß sein. Bei chinesischem, japanischem und koreanischem Text (nur von den cloudbasierten APIs unterstützt) sollte jedes Zeichen 24 × 24 Pixel groß sein. Bei allen Sprachen ist die Genauigkeit bei Zeichen, die größer als 24 × 24 Pixel sind, in der Regel nicht höher.

    Ein Bild mit 640 × 480 Pixeln eignet sich beispielsweise gut zum Scannen einer Visitenkarte, die die gesamte Breite des Bildes einnimmt. Wenn Sie ein auf Papier im Letter-Format gedrucktes Dokument scannen möchten, ist möglicherweise ein Bild mit 720 × 1.280 Pixeln erforderlich.

  • Eine schlechte Bildschärfe kann die Genauigkeit der Texterkennung beeinträchtigen. Wenn Sie keine akzeptablen Ergebnisse erhalten, bitten Sie den Nutzer, das Bild noch einmal aufzunehmen.

  • Wenn Sie Text in einer Echtzeitanwendung erkennen, sollten Sie auch die Gesamtabmessungen der Eingabebilder berücksichtigen. Kleinere Bilder können schneller verarbeitet werden. Um die Latenz zu verringern, sollten Sie Bilder mit niedrigeren Auflösungen aufnehmen (unter Berücksichtigung der oben genannten Anforderungen an die Genauigkeit) und darauf achten, dass der Text so viel wie möglich vom Bild einnimmt. Weitere Informationen finden Sie unter Tipps zur Verbesserung der Echtzeitleistung.


Erkennt Text in Bildern

Wenn Sie Text in einem Bild mit einem geräteinternen oder Cloud-basierten Modell erkennen möchten, führen Sie die Texterkennung wie unten beschrieben aus.

1. Texterkennung ausführen

Übergeben Sie das Bild als `UIImage` oder `CMSampleBufferRef` an die Methode `process(_:completion:)` von `VisionTextRecognizer`:
  1. Sie erhalten eine Instanz von VisionTextRecognizer, indem Sie entweder onDeviceTextRecognizer oder cloudTextRecognizer aufrufen:

    Swift

    So verwenden Sie das On-Device-Modell:

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

    So verwenden Sie das Cloud-Modell:

    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

    So verwenden Sie das On-Device-Modell:

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

    So verwenden Sie das Cloud-Modell:

    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. Erstellen Sie ein VisionImage-Objekt mit einem UIImage oder einem CMSampleBufferRef.

    So verwenden Sie ein UIImage:

    1. Drehen Sie das Bild bei Bedarf so, dass die Property imageOrientation den Wert .up hat.
    2. Erstellen Sie ein VisionImage-Objekt mit dem korrekt gedrehten UIImage. Geben Sie keine Metadaten zur Drehung an. Es muss der Standardwert .topLeft verwendet werden.

      Swift

      let image = VisionImage(image: uiImage)

      Objective-C

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

    So verwenden Sie ein CMSampleBufferRef:

    1. Erstellen Sie ein VisionImageMetadata-Objekt, das die Ausrichtung der Bilddaten im CMSampleBufferRef-Puffer angibt.

      So rufen Sie die Bildausrichtung ab:

      Swift

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

      Erstellen Sie dann das Metadatenobjekt:

      Swift

      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. Erstellen Sie ein VisionImage-Objekt mit dem CMSampleBufferRef-Objekt und den Rotationsmetadaten:

      Swift

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

      Objective-C

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer];
      image.metadata = metadata;
  3. Übergeben Sie das Bild dann an die process(_:completion:)-Methode:

    Swift

    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. Text aus Blöcken mit erkanntem Text extrahieren

Wenn der Vorgang zur Texterkennung erfolgreich ist, wird ein [`VisionText`][VisionText]-Objekt zurückgegeben. Ein `VisionText`-Objekt enthält den gesamten im Bild erkannten Text und null oder mehr [`VisionTextBlock`][VisionTextBlock]-Objekte. Jeder `VisionTextBlock` stellt einen rechteckigen Textblock dar, der null oder mehr [`VisionTextLine`][VisionTextLine]-Objekte enthält. Jedes `VisionTextLine`-Objekt enthält null oder mehr [`VisionTextElement`][VisionTextElement]-Objekte, die Wörter und wortähnliche Einheiten (Datumsangaben, Zahlen usw.) darstellen. Für jedes Objekt vom Typ `VisionTextBlock`, `VisionTextLine` und `VisionTextElement` können Sie den in der Region erkannten Text und die Begrenzungskoordinaten der Region abrufen. Beispiel:

Swift

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

Tipps zur Verbesserung der Echtzeitleistung

Wenn Sie das On-Device-Modell verwenden möchten, um Text in einer Echtzeitanwendung zu erkennen, sollten Sie die folgenden Richtlinien beachten, um die besten Framerates zu erzielen:

  • Drosseln Sie Aufrufe des Texterkennungssystems. Wenn ein neuer Videoframes verfügbar wird, während die Texterkennung ausgeführt wird, verwerfen Sie den Frame.
  • Wenn Sie die Ausgabe der Texterkennung verwenden, um Grafiken auf das Eingabebild zu legen, rufen Sie zuerst das Ergebnis von ML Kit ab und rendern Sie dann das Bild und das Overlay in einem einzigen Schritt. Dadurch wird für jeden Eingabe-Frame nur einmal auf die Displayoberfläche gerendert. Ein Beispiel finden Sie in den Klassen previewOverlayView und FIRDetectionOverlayView in der Showcase-Beispiel-App.
  • Nehmen Sie Bilder mit einer niedrigeren Auflösung auf. Beachten Sie jedoch auch die Anforderungen an die Bildabmessungen für diese API.

Nächste Schritte


Text in Bildern von Dokumenten erkennen

Wenn Sie den Text eines Dokuments erkennen möchten, konfigurieren Sie den cloudbasierten Dokumenttexterkenner und führen Sie ihn wie unten beschrieben aus.

Die unten beschriebene API zur Texterkennung in Dokumenten bietet eine Schnittstelle, die für die Arbeit mit Bildern von Dokumenten gedacht ist. Wenn Sie jedoch die von der Sparse Text API bereitgestellte Schnittstelle bevorzugen, können Sie sie stattdessen zum Scannen von Dokumenten verwenden, indem Sie den Cloud-Texterkenner so konfigurieren, dass er das Dense Text-Modell verwendet.

So verwenden Sie die API zur Texterkennung in Dokumenten:

1. Texterkennung ausführen

Übergeben Sie das Bild als UIImage oder CMSampleBufferRef an die process(_:completion:)-Methode von VisionDocumentTextRecognizer:

  1. Rufen Sie eine Instanz von VisionDocumentTextRecognizer ab, indem Sie cloudDocumentTextRecognizer aufrufen:

    Swift

    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. Erstellen Sie ein VisionImage-Objekt mit einem UIImage oder einem CMSampleBufferRef.

    So verwenden Sie ein UIImage:

    1. Drehen Sie das Bild bei Bedarf so, dass die Property imageOrientation den Wert .up hat.
    2. Erstellen Sie ein VisionImage-Objekt mit dem korrekt gedrehten UIImage. Geben Sie keine Metadaten zur Drehung an. Es muss der Standardwert .topLeft verwendet werden.

      Swift

      let image = VisionImage(image: uiImage)

      Objective-C

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

    So verwenden Sie ein CMSampleBufferRef:

    1. Erstellen Sie ein VisionImageMetadata-Objekt, das die Ausrichtung der Bilddaten im CMSampleBufferRef-Puffer angibt.

      So rufen Sie die Bildausrichtung ab:

      Swift

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

      Erstellen Sie dann das Metadatenobjekt:

      Swift

      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. Erstellen Sie ein VisionImage-Objekt mit dem CMSampleBufferRef-Objekt und den Rotationsmetadaten:

      Swift

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

      Objective-C

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer];
      image.metadata = metadata;
  3. Übergeben Sie das Bild dann an die process(_:completion:)-Methode:

    Swift

    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. Text aus Blöcken mit erkanntem Text extrahieren

Wenn die Texterkennung erfolgreich ist, wird ein VisionDocumentText-Objekt zurückgegeben. Ein VisionDocumentText-Objekt enthält den gesamten im Bild erkannten Text und eine Hierarchie von Objekten, die die Struktur des erkannten Dokuments widerspiegelt:

Für jedes VisionDocumentTextBlock-, VisionDocumentTextParagraph-, VisionDocumentTextWord- und VisionDocumentTextSymbol-Objekt können Sie den in der Region erkannten Text und die Begrenzungskoordinaten der Region abrufen.

Beispiel:

Swift

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

Nächste Schritte