Rozpoznawanie tekstu na obrazach za pomocą ML Kit na iOS

Za pomocą ML Kit możesz rozpoznawać tekst na zdjęciach i filmach, np. tekst znaku drogowego. Główne cechy tej funkcji:

Interfejs Text Recognition API (wersja 2)
OpisRozpoznawanie tekstu na obrazach i filmach, obsługa alfabetu łacińskiego, chińskiego, dewanagari, japońskiego i koreańskiego oraz wielu różnych języków.
Nazwy pakietów SDKGoogleMLKit/TextRecognition
GoogleMLKit/TextRecognitionChinese
GoogleMLKit/TextRecognitionDevanagari
GoogleMLKit/TextRecognitionJapanese
GoogleMLKit/TextRecognitionKorean
ImplementacjaZasoby są statycznie połączone z aplikacją w czasie kompilacji
Wpływ na rozmiar aplikacjiOkoło 38 MB na pakiet SDK ze skryptem
WystępyDziałanie w czasie rzeczywistym na większości urządzeń w przypadku pakietu SDK obsługującego alfabet łaciński, wolniej w przypadku innych.

Wypróbuj

Zanim zaczniesz

  1. Umieść w pliku Podfile te pody ML Kit:
    # To recognize Latin script
    pod 'GoogleMLKit/TextRecognition', '3.2.0'
    # To recognize Chinese script
    pod 'GoogleMLKit/TextRecognitionChinese', '3.2.0'
    # To recognize Devanagari script
    pod 'GoogleMLKit/TextRecognitionDevanagari', '3.2.0'
    # To recognize Japanese script
    pod 'GoogleMLKit/TextRecognitionJapanese', '3.2.0'
    # To recognize Korean script
    pod 'GoogleMLKit/TextRecognitionKorean', '3.2.0'
    
  2. Po zainstalowaniu lub zaktualizowaniu podów projektu otwórz projekt Xcode, korzystając z jego .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 +textRecognizer(options:) i przekazując opcje związane z pakietem SDK zadeklarowanym powyżej:

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. Przygotowywanie obrazu wejściowego

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

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

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

  • Utwórz obiekt VisionImage z UIImage. Pamiętaj, aby podać prawidłowy atrybut .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 konta CMSampleBuffer, wykonaj te czynności:

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

    Aby określić orientację zdjęcia:

    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 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 do metody 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 zero lub więcej obiektów TextBlock.

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

W przypadku każdego obiektu TextBlock, TextLine i TextElement tekst może być rozpoznawany w regionie i jego współrzędne graniczne.

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 obrazu wejściowego

  • Aby narzędzie ML Kit dokładnie rozpoznawało tekst, obrazy wejściowe muszą zawierać tekst reprezentowany przez wystarczającą ilość danych pikseli. Idealnie każdy znak powinien mieć rozmiar co najmniej 16 × 16 pikseli. Znaki większe niż 24 x 24 piksele zwykle nie poprawiają dokładności.

    Na przykład obraz o wymiarach 640 × 480 może sprawdzić się do skanowania wizytówki, która zajmuje całą szerokość obrazu. Do zeskanowania dokumentu wydrukowanego na papierze o rozmiarze literowym 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 wyniki nie są zadowalające, poproś użytkownika o ponowne zdjęcie obrazu.

  • Jeśli rozpoznajesz tekst w aplikacji przesyłających dane w czasie rzeczywistym, weź pod uwagę ogólne wymiary obrazów wejściowych. Mniejsze obrazy mogą być przetwarzane szybciej. Aby zmniejszyć czas oczekiwania, zadbaj o to, by tekst zajmował jak najwięcej miejsca na obrazie, i rób obrazy w niższej rozdzielczości (pamiętaj o wymaganiach w zakresie dokładności wymienionych powyżej). Więcej informacji znajdziesz w artykule Wskazówki dotyczące zwiększania skuteczności.

Wskazówki dotyczące poprawy skuteczności

  • Do przetwarzania klatek wideo użyj synchronicznego interfejsu API results(in:) wzorca. Wywołaj tę metodę z funkcji captureOutput(_, didOutput:from:) obiektu AVCaptureVideoDataOutputSampleBufferDelegate, aby synchronicznie pobierać wyniki z danej klatki wideo. Pozostaw alwaysDiscardsLateVideoFrames instancji AVCaptureVideoDataOutput jako true, aby ograniczyć wywołania do wzorca. Jeśli podczas działania wykrywacza pojawi się nowa klatka wideo, zostanie usunięta.
  • Jeśli używasz danych wyjściowych detektora 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. Dzięki temu renderujesz na wyświetlaczu tylko raz dla każdej przetworzonej ramki wejściowej. Przykład znajdziesz w sekcji updatePreviewOverlayViewWithLastFrame w krótkim wprowadzeniu do ML Kit.
  • Rozważ robienie zdjęć w niższej rozdzielczości. Pamiętaj jednak o wymaganiach dotyczących wymiarów obrazów w tym interfejsie API.
  • Aby uniknąć potencjalnego spadku wydajności, nie uruchamiaj jednocześnie wielu instancji TextRecognizer z różnymi opcjami skryptu.