Rozpoznawanie tekstu w obrazach za pomocą ML Kit na iOS

Do rozpoznawania tekstu na obrazach możesz używać pakietu ML Kit. ML Kit zawiera ogólnego przeznaczenia API, odpowiedni do rozpoznawania tekstu na obrazach, takiego jak i tekstu znaku drogowego oraz interfejs API zoptymalizowany pod kątem rozpoznawania tekstu dokumenty. Interfejs API do zwykłych obciążeń obejmuje modele działające na urządzeniu i w chmurze. Rozpoznawanie tekstu dokumentów jest dostępne tylko jako model działający w chmurze. Zobacz przegląd, aby porównać w chmurze i na urządzeniu.

Zanim zaczniesz

  1. Jeśli nie masz jeszcze w aplikacji dodanej Firebase, wykonaj czynności podane w przewodniku dla początkujących.
  2. Umieść biblioteki ML Kit w pliku Podfile:
    pod 'Firebase/MLVision', '6.25.0'
    # If using an on-device API:
    pod 'Firebase/MLVisionTextModel', '6.25.0'
    
    Po zainstalowaniu lub zaktualizowaniu podów projektu otwórz Xcode projektu korzystającego z: .xcworkspace.
  3. W aplikacji zaimportuj Firebase:

    Swift

    import Firebase

    Objective-C

    @import Firebase;
  4. Jeśli chcesz używać modelu działającego w chmurze, który nie został jeszcze włączony interfejsów API działających w chmurze w Twoim projekcie, zrób to teraz:

    1. Otwórz ML Kit Strona interfejsów API w konsoli Firebase.
    2. Jeśli w swoim projekcie nie korzystasz jeszcze z abonamentu Blaze, kliknij Aby to zrobić, przejdź na wyższą wersję. (Prośba o uaktualnienie wyświetli się tylko wtedy, gdy projekt nie jest objęty abonamentem Blaze).

      Tylko projekty na poziomie Blaze mogą korzystać z interfejsów API działających w chmurze.

    3. Jeśli interfejsy API działające w chmurze nie są włączone, kliknij Włącz działające w chmurze interfejsów API.
    .

    Jeśli chcesz używać tylko modelu na urządzeniu, możesz pominąć ten krok.

Teraz możesz zacząć rozpoznawać tekst na obrazach.

Wytyczne dotyczące obrazu wejściowego

  • Aby ML Kit mógł dokładnie rozpoznawać tekst, obrazy wejściowe muszą zawierać który jest reprezentowany przez wystarczającą ilość danych pikseli. najlepiej dla alfabetu łacińskiego tekstu, każdy znak powinien mieć co najmniej 16 x 16 pikseli. W przypadku języka chińskiego, tekst w języku japońskim i koreańskim (obsługiwany tylko przez interfejsy API działające w chmurze), każdy powinien mieć rozmiar 24 x 24 piksele. Dla wszystkich języków zwykle nie ma funkcji w przypadku znaków większych niż 24 x 24 piksele.

    Na przykład obraz o wymiarach 640 x 480 może się sprawdzić do zeskanowania wizytówki zajmuje całą szerokość obrazu. Aby zeskanować dokument wydrukowany na na papierze w formacie letter, może być wymagany obraz o wymiarach 720 x 1280 pikseli.

  • Słaba ostrość obrazu może obniżyć dokładność rozpoznawania tekstu. Jeśli nim nie jesteś uzyskać akceptowalne wyniki, poproś użytkownika o ponowne przechwycenie obrazu.

  • Jeśli rozpoznajesz tekst w aplikacji działającej w czasie rzeczywistym, możesz też należy wziąć pod uwagę ogólne wymiary obrazów wejściowych. Mniejszy szybsze przetwarzanie obrazów. Aby zmniejszyć opóźnienia, należy robić zdjęcia mniejsza rozdzielczość (pamiętając o powyższych wymaganiach dotyczących dokładności) aby tekst zajmował jak największą część obrazu. Zobacz też Wskazówki, jak zwiększyć skuteczność w czasie rzeczywistym.


Rozpoznawanie tekstu w obrazach

Aby rozpoznać tekst na obrazie za pomocą modelu działającego na urządzeniu lub w chmurze: uruchom moduł rozpoznawania tekstu w sposób opisany poniżej.

1. Uruchom moduł rozpoznawania tekstu

Przekaż obraz jako „UIImage” lub „CMSampleBufferRef” do `Proces `VisionText wskaźniki(_:completion:)` :
  1. Uzyskaj instancję VisionTextRecognizer, wywołując jedną z tych opcji: onDeviceTextRecognizer lub cloudTextRecognizer:

    Swift

    Aby używać modelu na urządzeniu:

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

    Aby używać modelu w chmurze:

    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

    Aby używać modelu na urządzeniu:

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

    Aby używać modelu w chmurze:

    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. Utwórz obiekt VisionImage za pomocą UIImage lub CMSampleBufferRef.

    Aby użyć karty UIImage:

    1. W razie potrzeby obróć zdjęcie, tak by jego imageOrientation właściwość to .up.
    2. Utwórz obiekt VisionImage przy użyciu prawidłowo wykonanej rotacji UIImage Nie określaj żadnych metadanych rotacji – są to metadane domyślne. .topLeft.

      Swift

      let image = VisionImage(image: uiImage)

      Objective-C

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

    Aby użyć karty CMSampleBufferRef:

    1. Utwórz obiekt VisionImageMetadata, który określa orientacji danych zdjęć zawartych w Bufor CMSampleBufferRef.

      Aby sprawdzić orientację obrazu:

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

      Następnie utwórz obiekt metadanych:

      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. Utwórz obiekt VisionImage za pomocą Obiekt CMSampleBufferRef i metadane rotacji:

      Swift

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

      Objective-C

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer];
      image.metadata = metadata;
  3. Następnie przekaż obraz do metody process(_:completion:):

    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. Wyodrębnianie tekstu z bloków rozpoznanego tekstu

Jeśli rozpoznawanie tekstu się powiedzie, zwróci błąd Obiekt [`VisionText`][VisionText]. Obiekt „VisionText” zawiera pełny tekst rozpoznane na zdjęciu i zero lub więcej wartości [`VisionTextBlock`][VisionTextBlock] obiektów. Każdy element „VisionTextBlock” reprezentuje prostokątny blok tekstu zawierający zero lub więcej obiektów [`VisionTextLine`][VisionTextLine]. Każda linia „VisionTextLine” obiekt zawiera zero lub więcej obiektów [`VisionTextElement`][VisionTextElement], które reprezentują słowa i elementy słowne (daty, liczby itd.). Dla każdego obiektu `VisionTextBlock`, `VisionTextLine` i `VisionTextElement` dzięki czemu tekst zostanie rozpoznany w regionie, a współrzędne ograniczające i regionie. Przykład:

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

Wskazówki dotyczące poprawy skuteczności w czasie rzeczywistym

Jeśli chcesz używać modelu na urządzeniu do rozpoznawania tekstu w czasie rzeczywistym zastosuj się do tych wskazówek, by uzyskać najlepszą liczbę klatek na sekundę:

  • Ogranicz wywołania do modułu rozpoznawania tekstu. Jeśli nowa klatka wideo dostępne podczas działania modułu rozpoznawania tekstu, upuść ramkę.
  • Jeśli używasz danych wyjściowych modułu rozpoznawania tekstu do nakładania grafiki na obrazu wejściowego, najpierw pobierz wynik z ML Kit, a następnie wyrenderuj obraz i nakładanie nakładek w jednym kroku. W ten sposób renderowanie na powierzchni tylko raz na każdą ramkę wejściową. Zobacz previewOverlayView. i FIRDetectionOverlayView w aplikacji z funkcją prezentacji.
  • Rozważ robienie zdjęć w niższej rozdzielczości. Pamiętaj jednak, wymagania dotyczące wymiarów obrazów w tym interfejsie API.

Dalsze kroki


Rozpoznawanie tekstu na obrazach dokumentów

Aby rozpoznać tekst dokumentu, skonfiguruj i uruchom rozpoznawania tekstu dokumentu, zgodnie z opisem poniżej.

Opisany poniżej interfejs API rozpoznawania tekstu dokumentów zapewnia interfejs, ma ułatwić pracę z obrazami dokumentów. Pamiętaj jednak: Jeśli wolisz interfejs udostępniany przez interfejs API rozproszonego tekstu, możesz go zamiast skanować dokumenty przez skonfigurowanie modułu rozpoznawania tekstu w chmurze używają modelu gęstego.

Aby użyć interfejsu API rozpoznawania tekstu dokumentów:

1. Uruchom moduł rozpoznawania tekstu

Przekaż obraz jako UIImage lub CMSampleBufferRef do process(_:completion:), użytkownik VisionDocumentTextRecognizer :

  1. Pobierz instancję VisionDocumentTextRecognizer, wywołując cloudDocumentTextRecognizer:

    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. Utwórz obiekt VisionImage za pomocą UIImage lub CMSampleBufferRef.

    Aby użyć karty UIImage:

    1. W razie potrzeby obróć zdjęcie, tak by jego imageOrientation właściwość to .up.
    2. Utwórz obiekt VisionImage przy użyciu prawidłowo wykonanej rotacji UIImage Nie określaj żadnych metadanych rotacji – są to metadane domyślne. .topLeft.

      Swift

      let image = VisionImage(image: uiImage)

      Objective-C

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

    Aby użyć karty CMSampleBufferRef:

    1. Utwórz obiekt VisionImageMetadata, który określa orientacji danych zdjęć zawartych w Bufor CMSampleBufferRef.

      Aby sprawdzić orientację obrazu:

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

      Następnie utwórz obiekt metadanych:

      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. Utwórz obiekt VisionImage za pomocą Obiekt CMSampleBufferRef i metadane rotacji:

      Swift

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

      Objective-C

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer];
      image.metadata = metadata;
  3. Następnie przekaż obraz do metody process(_:completion:):

    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. Wyodrębnianie tekstu z bloków rozpoznanego tekstu

Jeśli rozpoznawanie tekstu się powiedzie, zwróci błąd VisionDocumentText. Obiekt VisionDocumentText zawiera pełny tekst rozpoznany na obrazie oraz hierarchię obiektów, odzwierciedlają strukturę rozpoznanego dokumentu:

W przypadku każdej wartości VisionDocumentTextBlock, VisionDocumentTextParagraph, VisionDocumentTextWord i VisionDocumentTextSymbol, możesz uzyskać tekstu rozpoznawanego w regionie oraz jego współrzędnych geograficznych.

Przykład:

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

Dalsze kroki