iOS에서 ML Kit를 사용하여 이미지 속 텍스트 인식

ML Kit를 사용하여 도로 표지판 텍스트와 같은 이미지 또는 동영상 속 텍스트를 인식할 수 있습니다. 이 기능의 주요 특징은 다음과 같습니다.

텍스트 인식 v2 API
설명이미지 또는 동영상 속 텍스트를 인식하고 라틴어, 중국어, 데바나가리 문자, 일본어, 한국어 스크립트를 지원하며 다양한 언어를 지원합니다.
SDK 이름GoogleMLKit/TextRecognition
GoogleMLKit/TextRecognitionChinese
GoogleMLKit/TextRecognitionDevanagari
GoogleMLKit/TextRecognitionJapanese
GoogleMLKit/TextRecognitionKorean
구현빌드 시간에 애셋이 앱에 정적으로 연결됨
앱 크기의 영향스크립트 SDK당 약 38MB
성능라틴 스크립트 SDK의 경우 대부분의 기기에서는 실시간이지만 다른 기기에서는 느립니다.

사용해 보기

  • 샘플 앱을 살펴보고 이 API의 사용 예를 확인합니다.
  • Codelab으로 직접 코드를 사용해 보세요.

시작하기 전에

  1. Podfile에 다음 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. 프로젝트의 포드를 설치하거나 업데이트한 후 .xcworkspace를 사용하여 Xcode 프로젝트를 엽니다. ML Kit는 Xcode 12.4 이상 버전에서 지원됩니다.

1. TextRecognizer 인스턴스 만들기

+textRecognizer(options:)를 호출하고 위에서 종속 항목으로 선언한 SDK와 관련된 옵션을 전달하여 TextRecognizer 인스턴스를 만듭니다.

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. 입력 이미지 준비

이미지를 UIImage 또는 CMSampleBufferRefTextRecognizerprocess(_:completion:) 메서드에 전달합니다.

UIImage 또는 CMSampleBuffer를 사용하여 VisionImage 객체를 만듭니다.

UIImage를 사용하는 경우 다음 단계를 따르세요.

  • UIImage를 사용하여 VisionImage 객체를 만듭니다. 올바른 .orientation를 지정해야 합니다.

    Swift

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

    Objective-C

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

CMSampleBuffer를 사용하는 경우 다음 단계를 따르세요.

  • CMSampleBuffer에 포함된 이미지 데이터의 방향을 지정합니다.

    이미지 방향을 가져오려면 다음 단계를 따르세요.

    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;
      }
    }
          
  • CMSampleBuffer 객체와 방향을 사용하여 VisionImage 객체를 만듭니다.

    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. 이미지 처리

그런 다음 이미지를 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. 인식된 텍스트 블록에서 텍스트 추출

텍스트 인식 작업이 성공하면 Text 객체가 반환됩니다. Text 객체는 이미지에서 인식된 전체 텍스트 및 0개 이상의 TextBlock 객체를 포함합니다.

TextBlock는 0개 이상의 TextLine 객체를 포함하는 사각형 모양의 텍스트 블록을 나타냅니다. 각 TextLine 객체에는 단어와 단어와 유사한 항목(예: 날짜, 숫자)을 나타내는 TextElement 객체가 0개 이상 포함됩니다.

TextBlock, TextLine, TextElement 객체에 대해 해당 영역에서 인식된 텍스트와 영역의 경계 좌표를 가져올 수 있습니다.

예를 들면 다음과 같습니다.

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

입력 이미지 가이드라인

  • ML Kit가 텍스트를 정확하게 인식하려면 입력 이미지에 충분한 픽셀 데이터로 표시된 텍스트가 있어야 합니다. 각 문자가 16x16픽셀 이상인 것이 좋습니다. 문자가 24x24픽셀보다 클수록 일반적으로 정확성이라는 이점이 없습니다.

    예를 들어 640x480 이미지는 이미지의 전체 너비를 차지하는 명함을 스캔하는 데 적합할 수 있습니다. 문자 크기의 용지에 인쇄된 문서를 스캔하려면 720x1280픽셀 이미지가 필요할 수 있습니다.

  • 이미지 초점이 잘 맞지 않으면 텍스트 인식 정확도에 영향을 줄 수 있습니다. 허용 가능한 수준의 결과를 얻지 못하면 사용자에게 이미지를 다시 캡처하도록 요청합니다.

  • 실시간 애플리케이션에서 텍스트를 인식하는 경우 입력 이미지의 전체 크기를 고려해야 합니다. 이미지 크기가 작을수록 더 빠르게 처리될 수 있습니다. 지연 시간을 줄이려면 텍스트가 이미지의 최대한 많은 부분을 차지하도록 하고 낮은 해상도에서 이미지를 캡처하세요 (위에 언급된 정확도 요구사항에 유의). 자세한 내용은 성능 개선을 위한 팁을 참고하세요.

실적 개선을 위한 팁

  • 동영상 프레임을 처리하려면 감지기의 results(in:) 동기 API를 사용합니다. AVCaptureVideoDataOutputSampleBufferDelegate captureOutput(_, didOutput:from:) 함수에서 이 메서드를 호출하여 주어진 동영상 프레임에서 결과를 동기식으로 가져옵니다. AVCaptureVideoDataOutput alwaysDiscardsLateVideoFramestrue로 유지하여 감지기 호출을 제한합니다. 인식기가 실행 중일 때 새 동영상 프레임이 제공되면 삭제됩니다.
  • 인식기 출력을 사용하여 입력 이미지에서 그래픽을 오버레이하는 경우 먼저 ML Kit에서 결과를 가져온 후 이미지를 렌더링하고 단일 단계로 오버레이합니다. 이렇게 하면 처리된 입력 프레임마다 한 번만 디스플레이 표면에 렌더링됩니다. 관련 예는 ML Kit 빠른 시작 샘플에서 updatePreviewOverlayViewWithLastFrame을 참조하세요.
  • 낮은 해상도에서 이미지를 캡처하는 것이 좋습니다. 단, 이 API의 이미지 크기 요구사항도 유의해야 합니다.
  • 잠재적 성능 저하를 방지하려면 서로 다른 스크립트 옵션으로 여러 TextRecognizer 인스턴스를 동시에 실행하지 마세요.