Check out what’s new from Firebase at Google I/O 2022. Learn more

Rozpoznaj tekst na obrazach za pomocą ML Kit na iOS

Możesz użyć ML Kit do rozpoznawania tekstu na obrazach. ML Kit ma zarówno interfejs API ogólnego przeznaczenia, odpowiedni do rozpoznawania tekstu na obrazach, taki jak tekst znaku ulicznego, oraz interfejs API zoptymalizowany do rozpoznawania tekstu dokumentów. Interfejs API ogólnego przeznaczenia ma zarówno modele na urządzeniu, jak i w chmurze. Rozpoznawanie tekstu dokumentu jest dostępne tylko jako model oparty na chmurze. Zobacz przegląd , aby porównać modele w chmurze i na urządzeniu.

Zanim zaczniesz

  1. Jeśli nie dodałeś jeszcze Firebase do swojej aplikacji, wykonaj czynności opisane w przewodniku wprowadzającym .
  2. Dołącz biblioteki ML Kit do swojego 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 pamiętaj, aby otworzyć projekt Xcode przy użyciu jego .xcworkspace .
  3. W swojej aplikacji zaimportuj Firebase:

    Szybki

    import Firebase

    Cel C

    @import Firebase;
  4. Jeśli chcesz korzystać z modelu opartego na chmurze, a nie masz jeszcze włączonych interfejsów API opartych na chmurze dla swojego projektu, zrób to teraz:

    1. Otwórz stronę ML Kit APIs w konsoli Firebase.
    2. Jeśli Twój projekt nie został jeszcze uaktualniony do planu cenowego Blaze, kliknij Uaktualnij , aby to zrobić. (Zostaniesz poproszony o uaktualnienie tylko wtedy, gdy Twój projekt nie jest objęty planem Blaze).

      Tylko projekty na poziomie Blaze mogą korzystać z interfejsów API opartych na chmurze.

    3. Jeśli interfejsy API oparte na chmurze nie są jeszcze włączone, kliknij Włącz interfejsy API oparte na chmurze .

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

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

Wskazówki dotyczące obrazu wejściowego

  • Aby zestaw ML Kit mógł dokładnie rozpoznać tekst, obrazy wejściowe muszą zawierać tekst reprezentowany przez wystarczającą ilość danych pikseli. Idealnie, w przypadku tekstu łacińskiego, każdy znak powinien mieć co najmniej 16x16 pikseli. W przypadku tekstu w języku chińskim, japońskim i koreańskim (obsługiwane tylko przez interfejsy API oparte na chmurze) każdy znak powinien mieć wymiary 24 x 24 piksele. W przypadku wszystkich języków nie ma na ogół żadnej korzyści z dokładności w przypadku znaków większych niż 24x24 piksele.

    Na przykład obraz 640x480 może dobrze się sprawdzić w przypadku wizytówki zajmującej całą szerokość obrazu. Aby zeskanować dokument wydrukowany na papierze formatu Letter, może być wymagany obraz o wymiarach 720x1280 pikseli.

  • Słaba ostrość obrazu może zaszkodzić dokładności rozpoznawania tekstu. Jeśli nie uzyskujesz zadowalających wyników, poproś użytkownika o ponowne przechwycenie obrazu.

  • Jeśli rozpoznajesz tekst w aplikacji działającej w czasie rzeczywistym, możesz również wziąć pod uwagę ogólne wymiary obrazów wejściowych. Mniejsze obrazy można przetwarzać szybciej, więc aby zmniejszyć opóźnienia, przechwytuj obrazy w niższych rozdzielczościach (pamiętając o powyższych wymaganiach dotyczących dokładności) i upewnij się, że tekst zajmuje jak najwięcej obrazu. Zobacz także Wskazówki dotyczące poprawy wydajności w czasie rzeczywistym .


Rozpoznawaj tekst na obrazach

Aby rozpoznać tekst na obrazie przy użyciu modelu na urządzeniu lub w chmurze, uruchom aparat rozpoznawania tekstu zgodnie z poniższym opisem.

1. Uruchom aparat rozpoznawania tekstu

Przekaż obraz jako `UIImage` lub `CMSampleBufferRef` do metody `process(_:completion:)` `VisionTextRecognizer`:
  1. Uzyskaj instancję VisionTextRecognizer , wywołując onDeviceTextRecognizer lub cloudTextRecognizer :

    Szybki

    Aby użyć modelu na urządzeniu:

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

    Aby skorzystać z modelu chmury:

    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)
    

    Cel C

    Aby użyć modelu na urządzeniu:

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

    Aby skorzystać z modelu chmury:

    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 przy użyciu UIImage lub CMSampleBufferRef .

    Aby użyć UIImage :

    1. W razie potrzeby obróć obraz tak, aby jego właściwość imageOrientation miała wartość .up .
    2. Utwórz obiekt VisionImage przy użyciu poprawnie obróconego UIImage . Nie określaj żadnych metadanych rotacji — należy użyć wartości domyślnej .topLeft .

      Szybki

      let image = VisionImage(image: uiImage)

      Cel C

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

    Aby użyć CMSampleBufferRef :

    1. Utwórz obiekt VisionImageMetadata , który określa orientację danych obrazu zawartych w buforze CMSampleBufferRef .

      Aby uzyskać orientację obrazu:

      Szybki

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

      Cel 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:

      Szybki

      let cameraPosition = AVCaptureDevice.Position.back  // Set to the capture device you used.
      let metadata = VisionImageMetadata()
      metadata.orientation = imageOrientation(
          deviceOrientation: UIDevice.current.orientation,
          cameraPosition: cameraPosition
      )

      Cel 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 przy użyciu obiektu CMSampleBufferRef i metadanych obrotu:

      Szybki

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

      Cel C

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

    Szybki

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

    Cel C

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

2. Wyodrębnij tekst z bloków rozpoznanego tekstu

Jeśli operacja rozpoznawania tekstu się powiedzie, zwróci obiekt [`VisionText`][VisionText]. Obiekt `VisionText` zawiera pełny tekst rozpoznany na obrazie i zero lub więcej obiektów [`VisionTextBlock`][VisionTextBlock]. Każdy `VisionTextBlock` reprezentuje prostokątny blok tekstu, który zawiera zero lub więcej obiektów [`VisionTextLine`][VisionTextLine]. Każdy obiekt `VisionTextLine` zawiera zero lub więcej obiektów [`VisionTextElement`][VisionTextElement], które reprezentują słowa i elementy wyrazopodobne (daty, liczby itd.). Dla każdego obiektu `VisionTextBlock`, `VisionTextLine` i `VisionTextElement` można uzyskać tekst rozpoznawany w regionie oraz współrzędne ograniczające regionu. Na przykład:

Szybki

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

Cel 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 wydajności w czasie rzeczywistym

Jeśli chcesz używać modelu na urządzeniu do rozpoznawania tekstu w aplikacji działającej w czasie rzeczywistym, postępuj zgodnie z poniższymi wskazówkami, aby uzyskać najlepszą liczbę klatek na sekundę:

  • Ograniczaj wywołania aparatu rozpoznawania tekstu. Jeśli nowa ramka wideo stanie się dostępna, gdy aparat rozpoznawania tekstu jest uruchomiony, upuść ramkę.
  • Jeśli używasz danych wyjściowych aparatu rozpoznawania tekstu do nakładania grafiki na obraz wejściowy, najpierw pobierz wynik z ML Kit, a następnie wyrenderuj obraz i nakładkę w jednym kroku. W ten sposób renderujesz na powierzchnię wyświetlania tylko raz dla każdej klatki wejściowej. Zobacz na przykład klasy previewOverlayView i FIRDetectionOverlayView w przykładowej aplikacji prezentacji.
  • Rozważ robienie zdjęć w niższej rozdzielczości. Należy jednak pamiętać o wymaganiach dotyczących wymiarów obrazu tego interfejsu API.

Następne kroki


Rozpoznawaj tekst na obrazach dokumentów

Aby rozpoznać tekst dokumentu, skonfiguruj i uruchom oparty na chmurze aparat rozpoznawania tekstu dokumentu zgodnie z poniższym opisem.

Opisany poniżej interfejs API rozpoznawania tekstu dokumentu zapewnia interfejs, który ma być wygodniejszy do pracy z obrazami dokumentów. Jeśli jednak wolisz interfejs udostępniany przez interfejs API rzadkiego tekstu, możesz go użyć do skanowania dokumentów, konfigurując aparat rozpoznawania tekstu w chmurze tak, aby używał modelu gęstego tekstu .

Aby użyć interfejsu API rozpoznawania tekstu dokumentu:

1. Uruchom aparat rozpoznawania tekstu

Przekaż obraz jako UIImage lub CMSampleBufferRef do metody process(_:completion:) VisionDocumentTextRecognizer :

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

    Szybki

    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)
    

    Cel 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 przy użyciu UIImage lub CMSampleBufferRef .

    Aby użyć UIImage :

    1. W razie potrzeby obróć obraz tak, aby jego właściwość imageOrientation miała wartość .up .
    2. Utwórz obiekt VisionImage przy użyciu poprawnie obróconego UIImage . Nie określaj żadnych metadanych rotacji — należy użyć wartości domyślnej .topLeft .

      Szybki

      let image = VisionImage(image: uiImage)

      Cel C

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

    Aby użyć CMSampleBufferRef :

    1. Utwórz obiekt VisionImageMetadata , który określa orientację danych obrazu zawartych w buforze CMSampleBufferRef .

      Aby uzyskać orientację obrazu:

      Szybki

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

      Cel 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:

      Szybki

      let cameraPosition = AVCaptureDevice.Position.back  // Set to the capture device you used.
      let metadata = VisionImageMetadata()
      metadata.orientation = imageOrientation(
          deviceOrientation: UIDevice.current.orientation,
          cameraPosition: cameraPosition
      )

      Cel 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 przy użyciu obiektu CMSampleBufferRef i metadanych obrotu:

      Szybki

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

      Cel C

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

    Szybki

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

    Cel C

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

2. Wyodrębnij tekst z bloków rozpoznanego tekstu

Jeśli operacja rozpoznawania tekstu się powiedzie, zwróci obiekt VisionDocumentText . Obiekt VisionDocumentText zawiera pełny tekst rozpoznany na obrazie oraz hierarchię obiektów, która odzwierciedla strukturę rozpoznanego dokumentu:

Dla każdego VisionDocumentTextBlock , VisionDocumentTextParagraph , VisionDocumentTextWord i VisionDocumentTextSymbol można uzyskać tekst rozpoznany w regionie i współrzędne ograniczające regionu.

Na przykład:

Szybki

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

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

Następne kroki