Rozpoznawanie tekstu na obrazach za pomocą ML Kit na iOS

Możesz używać ML Kit do rozpoznawania tekstu na obrazach lub w filmach, np. na znaku drogowym. Główne cechy tej funkcji:

Text Recognition v2 API
Opisrozpoznawanie tekstu na obrazach lub w filmach, obsługa pisma łacińskiego, chińskiego, dewanagari, japońskiego i koreańskiego oraz wiele języków.
Nazwy pakietów SDKGoogleMLKit/TextRecognition
GoogleMLKit/TextRecognitionChinese
GoogleMLKit/TextRecognitionDevanagari
GoogleMLKit/TextRecognitionJapanese
GoogleMLKit/TextRecognitionKorean
ImplementacjaKomponenty są statycznie powiązane z aplikacją w momencie kompilacji.
Wpływ rozmiaru aplikacjiOkoło 38 MB na skrypt SDK
WynikiW czasie rzeczywistym na większości urządzeń w przypadku pakietu SDK dla alfabetu łacińskiego, wolniej w przypadku innych.

Wypróbuj

Zanim zaczniesz

  1. Dodaj do pliku Podfile te pody ML Kit:
    # To recognize Latin script
    pod 'GoogleMLKit/TextRecognition', '7.0.0'
    # To recognize Chinese script
    pod 'GoogleMLKit/TextRecognitionChinese', '7.0.0'
    # To recognize Devanagari script
    pod 'GoogleMLKit/TextRecognitionDevanagari', '7.0.0'
    # To recognize Japanese script
    pod 'GoogleMLKit/TextRecognitionJapanese', '7.0.0'
    # To recognize Korean script
    pod 'GoogleMLKit/TextRecognitionKorean', '7.0.0'
    
  2. Po zainstalowaniu lub zaktualizowaniu pakietów projektu otwórz projekt Xcode za pomocą .xcworkspace. ML Kit jest obsługiwany w Xcode w wersji 12.4 lub nowszej.

1. Utwórz instancję TextRecognizer

Utwórz instancję TextRecognizer, wywołując funkcję +textRecognizer(options:), przekazując opcje związane z pakietem SDK zadeklarowanym jako zależność:

Swift

// When using Latin script recognition SDK
let latinOptions = TextRecognizerOptions()
let latinTextRecognizer = TextRecognizer.textRecognizer(options:options)

// When using Chinese script recognition SDK
let chineseOptions = ChineseTextRecognizerOptions()
let chineseTextRecognizer = TextRecognizer.textRecognizer(options:options)

// When using Devanagari script recognition SDK
let devanagariOptions = DevanagariTextRecognizerOptions()
let devanagariTextRecognizer = TextRecognizer.textRecognizer(options:options)

// When using Japanese script recognition SDK
let japaneseOptions = JapaneseTextRecognizerOptions()
let japaneseTextRecognizer = TextRecognizer.textRecognizer(options:options)

// When using Korean script recognition SDK
let koreanOptions = KoreanTextRecognizerOptions()
let koreanTextRecognizer = TextRecognizer.textRecognizer(options:options)

Objective-C

// When using Latin script recognition SDK
MLKTextRecognizerOptions *latinOptions = [[MLKTextRecognizerOptions alloc] init];
MLKTextRecognizer *latinTextRecognizer = [MLKTextRecognizer textRecognizerWithOptions:options];

// When using Chinese script recognition SDK
MLKChineseTextRecognizerOptions *chineseOptions = [[MLKChineseTextRecognizerOptions alloc] init];
MLKTextRecognizer *chineseTextRecognizer = [MLKTextRecognizer textRecognizerWithOptions:options];

// When using Devanagari script recognition SDK
MLKDevanagariTextRecognizerOptions *devanagariOptions = [[MLKDevanagariTextRecognizerOptions alloc] init];
MLKTextRecognizer *devanagariTextRecognizer = [MLKTextRecognizer textRecognizerWithOptions:options];

// When using Japanese script recognition SDK
MLKJapaneseTextRecognizerOptions *japaneseOptions = [[MLKJapaneseTextRecognizerOptions alloc] init];
MLKTextRecognizer *japaneseTextRecognizer = [MLKTextRecognizer textRecognizerWithOptions:options];

// When using Korean script recognition SDK
MLKKoreanTextRecognizerOptions *koreanOptions = [[MLKKoreanTextRecognizerOptions alloc] init];
MLKTextRecognizer *koreanTextRecognizer = [MLKTextRecognizer textRecognizerWithOptions:options];

2. Przygotuj obraz wejściowy

Przekaż obraz jako UIImage lub CMSampleBufferRef do metody process(_:completion:) w obiekcie TextRecognizer:

Utwórz obiekt VisionImage za pomocą obiektu UIImage lub CMSampleBuffer.

Jeśli używasz UIImage, wykonaj te czynności:

  • Utwórz obiekt VisionImage za pomocą funkcji UIImage. Pamiętaj, aby podać prawidłowy adres .orientation.

    Swift

    let image = VisionImage(image: UIImage)
    visionImage.orientation = image.imageOrientation

    Objective-C

    MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image];
    visionImage.orientation = image.imageOrientation;

Jeśli używasz CMSampleBuffer, wykonaj te czynności:

  • Określ orientację danych obrazu zawartych w elemencie CMSampleBuffer.

    Aby uzyskać orientację obrazu:

    Swift

    func imageOrientation(
      deviceOrientation: UIDeviceOrientation,
      cameraPosition: AVCaptureDevice.Position
    ) -> UIImage.Orientation {
      switch deviceOrientation {
      case .portrait:
        return cameraPosition == .front ? .leftMirrored : .right
      case .landscapeLeft:
        return cameraPosition == .front ? .downMirrored : .up
      case .portraitUpsideDown:
        return cameraPosition == .front ? .rightMirrored : .left
      case .landscapeRight:
        return cameraPosition == .front ? .upMirrored : .down
      case .faceDown, .faceUp, .unknown:
        return .up
      }
    }
          

    Objective-C

    - (UIImageOrientation)
      imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation
                             cameraPosition:(AVCaptureDevicePosition)cameraPosition {
      switch (deviceOrientation) {
        case UIDeviceOrientationPortrait:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationLeftMirrored
                                                                : UIImageOrientationRight;
    
        case UIDeviceOrientationLandscapeLeft:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationDownMirrored
                                                                : UIImageOrientationUp;
        case UIDeviceOrientationPortraitUpsideDown:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationRightMirrored
                                                                : UIImageOrientationLeft;
        case UIDeviceOrientationLandscapeRight:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationUpMirrored
                                                                : UIImageOrientationDown;
        case UIDeviceOrientationUnknown:
        case UIDeviceOrientationFaceUp:
        case UIDeviceOrientationFaceDown:
          return UIImageOrientationUp;
      }
    }
          
  • Utwórz obiekt VisionImage, używając obiektu CMSampleBuffer i jego orientacji:

    Swift

    let image = VisionImage(buffer: sampleBuffer)
    image.orientation = imageOrientation(
      deviceOrientation: UIDevice.current.orientation,
      cameraPosition: cameraPosition)

    Objective-C

     MLKVisionImage *image = [[MLKVisionImage alloc] initWithBuffer:sampleBuffer];
     image.orientation =
       [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation
                                    cameraPosition:cameraPosition];

3. Przetwarzanie obrazu

Następnie przekaż obraz metodzie process(_:completion:):

Swift

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

Objective-C

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

4. Wyodrębnianie tekstu z bloków rozpoznanego tekstu

Jeśli operacja rozpoznawania tekstu się powiedzie, zwróci obiekt Text. Obiekt Text zawiera pełny tekst rozpoznany na obrazie oraz co najmniej jeden obiekt TextBlock.

Każdy element TextBlock reprezentuje prostokątny blok tekstu, który zawiera co najmniej 0 lub więcej obiektów TextLine. Każdy obiekt TextLine zawiera co najmniej 1 obiekt TextElement, który reprezentuje słowa i elementy podobne do słów, takie jak daty i liczby.

W przypadku każdego obiektu TextBlock, TextLine i TextElement możesz uzyskać tekst rozpoznany w regionie oraz współrzędne ograniczające region.

Na przykład:

Swift

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

Objective-C

NSString *resultText = result.text;
for (MLKTextBlock *block in result.blocks) {
  NSString *blockText = block.text;
  NSArray<MLKTextRecognizedLanguage *> *blockLanguages = block.recognizedLanguages;
  NSArray<NSValue *> *blockCornerPoints = block.cornerPoints;
  CGRect blockFrame = block.frame;
  for (MLKTextLine *line in block.lines) {
    NSString *lineText = line.text;
    NSArray<MLKTextRecognizedLanguage *> *lineLanguages = line.recognizedLanguages;
    NSArray<NSValue *> *lineCornerPoints = line.cornerPoints;
    CGRect lineFrame = line.frame;
    for (MLKTextElement *element in line.elements) {
      NSString *elementText = element.text;
      NSArray<NSValue *> *elementCornerPoints = element.cornerPoints;
      CGRect elementFrame = element.frame;
    }
  }
}

Wskazówki dotyczące obrazów

  • Aby ML Kit mógł dokładnie rozpoznawać tekst, obrazy wejściowe muszą zawierać tekst reprezentowany przez wystarczającą ilość danych pikseli. W idealnym przypadku każdy znak powinien mieć co najmniej 16 x 16 pikseli. Zwykle nie ma korzyści z ustawienia znaków na większy rozmiar niż 24 x 24 piksele.

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

  • Złe wyostrzanie obrazu może wpływać na dokładność rozpoznawania tekstu. Jeśli nie uzyskujesz zadowalających wyników, poproś użytkownika o ponowne zrobienie zdjęcia.

  • Jeśli tekst jest rozpoznawany w aplikacji działającej w czasie rzeczywistym, należy wziąć pod uwagę ogólne wymiary obrazów wejściowych. Mniejsze obrazy można przetwarzać szybciej. Aby zmniejszyć opóźnienie, zadbaj o to, aby tekst zajmował jak największą część obrazu, oraz rób zdjęcia w niższych rozdzielczościach (z uwzględnieniem wspomnianych powyżej wymagań dotyczących dokładności). Więcej informacji znajdziesz w artykule Wskazówki dotyczące zwiększania skuteczności.

Wskazówki dotyczące zwiększania skuteczności

  • Do przetwarzania klatek wideo użyj synchronicznego interfejsu API results(in:) do wykrywania. Aby synchronicznie uzyskać wyniki z danego kadru wideo, wywołaj tę metodę z  AVCaptureVideoDataOutputSampleBufferDelegate captureOutput(_, didOutput:from:). Aby ograniczyć liczbę połączeń z detektorem, zachowaj AVCaptureVideoDataOutput  alwaysDiscardsLateVideoFrames jako true. Jeśli podczas działania detektora pojawi się nowa klatka wideo, zostanie ona odrzucona.
  • Jeśli używasz danych wyjściowych z detektora do nakładania grafiki na obraz wejściowy, najpierw uzyskaj wynik z ML Kit, a potem wyrenderuj obraz i nałóż go w jednym kroku. Dzięki temu renderujesz na powierzchni wyświetlacza tylko raz dla każdego przetworzonego kadru wejściowego. Przykładowy kod updatePreviewOverlayViewWithLastFrame znajdziesz w pliku sample_mlkit_quick_start.cpp.
  • Rozważ robienie zdjęć w niższej rozdzielczości. Pamiętaj jednak o wymaganiach dotyczących wymiarów obrazu w tym interfejsie API.
  • Aby uniknąć potencjalnego pogorszenia wydajności, nie uruchamiaj jednocześnie wielu instancji TextRecognizer z różnymi opcjami skryptu.