Распознавайте текст на изображениях с помощью ML Kit на iOS

Вы можете использовать ML Kit для распознавания текста на изображениях или видео, например текста дорожных знаков. Основными характеристиками этой функции являются:

API распознавания текста v2
Описание Распознавание текста на изображениях или видео, поддержка латинского, китайского, деванагари, японского и корейского алфавитов, а также широкого спектра языков .
Имена SDK GoogleMLKit/TextRecognition
GoogleMLKit/TextRecognitionChinese
GoogleMLKit/TextRecognitionDevanagari
GoogleMLKit/TextRecognitionJapanese
GoogleMLKit/TextRecognitionKorean
Выполнение Ресурсы статически связаны с вашим приложением во время сборки.
Влияние размера приложения Около 38 МБ на скрипт SDK
Производительность В реальном времени на большинстве устройств для SDK с латинским алфавитом, медленнее для других.

Попробуйте это

  • Поэкспериментируйте с примером приложения , чтобы увидеть пример использования этого API.
  • Попробуйте код самостоятельно с помощью codelab .

Прежде чем начать

  1. Включите в свой подфайл следующие модули 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. После установки или обновления модулей вашего проекта откройте проект Xcode, используя его .xcworkspace . ML Kit поддерживается в Xcode версии 12.4 или новее.

1. Создайте экземпляр TextRecognizer

Создайте экземпляр TextRecognizer , вызвав +textRecognizer(options:) , передав параметры, относящиеся к SDK, который вы объявили как зависимость выше:

Быстрый

// 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)

Цель-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. Подготовьте входное изображение

Передайте изображение как UIImage или CMSampleBufferRef в метод TextRecognizer process(_:completion:) :

Создайте объект VisionImage используя UIImage или CMSampleBuffer .

Если вы используете UIImage , выполните следующие действия:

  • Создайте объект VisionImage с помощью UIImage . Обязательно укажите правильную .orientation .

    Быстрый

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

    Цель-C

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

Если вы используете CMSampleBuffer , выполните следующие действия:

  • Укажите ориентацию данных изображения, содержащихся в CMSampleBuffer .

    Чтобы получить ориентацию изображения:

    Быстрый

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

    Цель-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;
      }
    }
          
  • Создайте объект VisionImage используя объект CMSampleBuffer и ориентацию:

    Быстрый

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

    Цель-C

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

3. Обработка изображения

Затем передайте изображение в process(_:completion:) :

Быстрый

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

Цель-C

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

4. Извлечение текста из блоков распознанного текста.

Если операция распознавания текста завершается успешно, она возвращает объект Text . Объект Text содержит полный текст, распознанный в изображении, а также ноль или более объектов TextBlock .

Каждый TextBlock представляет собой прямоугольный блок текста, который содержит ноль или более объектов TextLine . Каждый объект TextLine содержит ноль или более объектов TextElement , которые представляют слова и словесные объекты, такие как даты и числа.

Для каждого объекта TextBlock , TextLine и TextElement вы можете получить текст, распознанный в регионе, и ограничивающие координаты региона.

Например:

Быстрый

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

Цель-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;
    }
  }
}

Рекомендации по входному изображению

  • Чтобы ML Kit мог точно распознавать текст, входные изображения должны содержать текст, представленный достаточным количеством пиксельных данных. В идеале размер каждого символа должен быть не менее 16х16 пикселей. Как правило, символы размером более 24x24 пикселей не повышают точность.

    Так, например, изображение размером 640x480 может хорошо подойти для сканирования визитной карточки, занимающей всю ширину изображения. Для сканирования документа, напечатанного на бумаге формата Letter, может потребоваться изображение размером 720x1280 пикселей.

  • Плохая фокусировка изображения может повлиять на точность распознавания текста. Если вы не получили приемлемых результатов, попробуйте попросить пользователя повторно сделать снимок.

  • Если вы распознаете текст в приложении реального времени, вам следует учитывать общие размеры входных изображений. Изображения меньшего размера можно обрабатывать быстрее. Чтобы уменьшить задержку, убедитесь, что текст занимает как можно большую часть изображения, и захватывайте изображения с более низким разрешением (принимая во внимание упомянутые выше требования к точности). Дополнительные сведения см. в разделе Советы по повышению производительности .

Советы по повышению производительности

  • Для обработки видеокадров используйте синхронный API results(in:) детектора. Вызовите этот метод из функции captureOutput(_, didOutput:from:) AVCaptureVideoDataOutputSampleBufferDelegate , чтобы синхронно получить результаты из данного видеокадра. Оставьте для AVCaptureVideoDataOutput значение alwaysDiscardsLateVideoFrames как true , чтобы ограничить вызовы детектора. Если во время работы детектора появится новый видеокадр, он будет удален.
  • Если вы используете выходные данные детектора для наложения графики на входное изображение, сначала получите результат из ML Kit, затем визуализируйте изображение и наложите его за один шаг. При этом вы выполняете рендеринг на поверхность дисплея только один раз для каждого обработанного входного кадра. Пример см. в updatePreviewOverlayViewWithLastFrame в образце быстрого запуска ML Kit.
  • Рассмотрите возможность захвата изображений с более низким разрешением. Однако также имейте в виду требования к размеру изображения этого API.
  • Чтобы избежать потенциального снижения производительности, не запускайте одновременно несколько экземпляров TextRecognizer с разными параметрами сценария.