ML Kit를 사용하여 이미지 속 텍스트를 인식할 수 있습니다. ML Kit에는 도로 표지판 텍스트와 같은 이미지 속 텍스트 인식에 적합한 범용 API와 문서의 텍스트 인식에 최적화된 API가 모두 있습니다. 범용 API에는 기기별 및 클라우드 기반 모델이 모두 있습니다. 문서 텍스트 인식은 클라우드 기반 모델에서만 사용할 수 있습니다. 클라우드 및 기기별 모델 비교에 대한 개요를 참조하세요.
시작하기 전에
- 앱에 Firebase를 아직 추가하지 않았다면 시작 가이드의 단계에 따라 추가합니다.
- Podfile에 ML Kit 라이브러리를 포함합니다.
pod 'Firebase/MLVision', '6.25.0' # If using an on-device API: pod 'Firebase/MLVisionTextModel', '6.25.0'
프로젝트의 포드를 설치하거나 업데이트한 후.xcworkspace
를 사용하여 Xcode 프로젝트를 열어야 합니다. - 앱에서 Firebase를 가져옵니다.
Swift
import Firebase
Objective-C
@import Firebase;
-
클라우드 기반 모델을 사용하려는 경우 프로젝트에 클라우드 기반 API를 아직 사용 설정하지 않았으면 지금 설정하세요.
- Firebase Console의 ML Kit API 페이지를 엽니다.
-
프로젝트를 Blaze 요금제로 아직 업그레이드하지 않은 경우 업그레이드를 클릭하여 업그레이드하세요. 프로젝트가 Blaze 요금제가 아닌 경우에만 업그레이드하라는 메시지가 표시됩니다.
Blaze 수준 프로젝트만 클라우드 기반 API를 사용할 수 있습니다.
- 클라우드 기반 API가 아직 사용 설정되지 않은 경우 클라우드 기반 API 사용 설정을 클릭합니다.
기기별 모델만 사용하려는 경우 이 단계를 건너뛸 수 있습니다.
이제 이미지 속 텍스트 인식을 시작할 수 있습니다.
입력 이미지 가이드라인
-
ML Kit가 텍스트를 정확하게 인식하려면 입력 이미지에 충분한 픽셀 데이터로 표시된 텍스트가 있어야 합니다. 라틴어 텍스트의 경우 각 문자가 16x16픽셀 이상이어야 좋습니다. Cloud 기반 API에서만 지원되는 한국어, 일본어, 중국어 텍스트의 경우 각 문자가 24x24픽셀이어야 합니다. 일반적으로 모든 언어의 문자가 24x24픽셀보다 크면 정확도가 더 이상 향상되지 않습니다.
예를 들어 이미지의 전체 너비를 차지하는 명함을 스캔하려면 640x480픽셀 이미지가 적합합니다. 레터 사이즈 용지에 인쇄된 문서 스캔은 720x1280픽셀 이미지가 적합합니다.
-
이미지 초점이 잘 맞지 않으면 텍스트 인식 정확도가 저하될 수 있습니다. 허용 가능한 수준의 결과를 얻지 못하는 경우 사용자에게 이미지를 다시 캡처하도록 요청합니다.
-
실시간 애플리케이션에서 텍스트를 인식하는 경우 입력 이미지의 전체 크기를 고려해야 할 수도 있습니다. 이미지 크기가 작을수록 더 빠르게 처리될 수 있으므로 지연 시간을 줄이려면 위의 정확도 요구사항에 유의하여 낮은 해상도에서 이미지를 캡처하고 텍스트가 가능한 많은 이미지를 차지하도록 합니다. 또한 실시간 성능 향상을 위한 팁도 참조하세요.
이미지 속 텍스트 인식
기기별 모델 또는 클라우드 기반 모델을 사용하여 이미지 속 텍스트를 인식하려면 아래에 설명된 대로 텍스트 인식기를 실행합니다.
1. 텍스트 인식기 실행
이미지를 `UIImage` 또는 `CMSampleBufferRef`로 `VisionTextRecognizer`의 `process(_:completion:)` 메서드에 전달합니다.onDeviceTextRecognizer
또는cloudTextRecognizer
를 호출하여VisionTextRecognizer
의 인스턴스를 가져옵니다.Swift
기기별 모델을 사용하려면 다음을 수행합니다.
let vision = Vision.vision() let textRecognizer = vision.onDeviceTextRecognizer()
클라우드 모델을 사용하려면 다음 안내를 따르세요.
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)
Objective-C
기기별 모델을 사용하려면 다음을 수행합니다.
FIRVision *vision = [FIRVision vision]; FIRVisionTextRecognizer *textRecognizer = [vision onDeviceTextRecognizer];
클라우드 모델을 사용하려면 다음 안내를 따르세요.
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];
-
UIImage
또는CMSampleBufferRef
를 사용하여VisionImage
객체를 만듭니다.UIImage
를 사용하는 방법은 다음과 같습니다.- 필요한 경우
imageOrientation
속성이.up
이 되도록 이미지를 회전합니다. - 올바르게 회전된
UIImage
를 사용하여VisionImage
객체를 만듭니다. 회전 메타데이터를 지정하지 마세요. 기본값인.topLeft
를 사용해야 합니다.Swift
let image = VisionImage(image: uiImage)
Objective-C
FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];
CMSampleBufferRef
를 사용하는 방법은 다음과 같습니다.-
CMSampleBufferRef
버퍼에 포함된 이미지 데이터의 방향을 지정하는VisionImageMetadata
객체를 만듭니다.이미지 방향을 가져오는 방법은 다음과 같습니다.
Swift
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 } }
Objective-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; } }
그런 다음 메타데이터 객체를 만듭니다.
Swift
let cameraPosition = AVCaptureDevice.Position.back // Set to the capture device you used. let metadata = VisionImageMetadata() metadata.orientation = imageOrientation( deviceOrientation: UIDevice.current.orientation, cameraPosition: cameraPosition )
Objective-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];
CMSampleBufferRef
객체 및 회전 메타데이터를 사용하여VisionImage
객체를 만듭니다.Swift
let image = VisionImage(buffer: sampleBuffer) image.metadata = metadata
Objective-C
FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer]; image.metadata = metadata;
- 필요한 경우
- 이제 이미지를
process(_:completion:)
메서드에 전달합니다.Swift
textRecognizer.process(visionImage) { result, error in guard error == nil, let result = result else { // ... return } // Recognized text }
Objective-C
[textRecognizer processImage:image completion:^(FIRVisionText *_Nullable result, NSError *_Nullable error) { if (error != nil || result == nil) { // ... return; } // Recognized text }];
2. 인식된 텍스트 블록에서 텍스트 추출
텍스트 인식 작업이 성공하면 [`VisionText`][VisionText] 객체를 반환합니다. `VisionText` 객체는 이미지에서 인식되는 전체 텍스트 및 0개 이상의 [`VisionTextBlock`][VisionTextBlock] 객체를 포함합니다. 각 `VisionTextBlock`은 0개 이상의 [`VisionTextLine`][VisionTextLine] 객체를 포함하는 직사각형 모양의 텍스트 블록을 나타냅니다. 각 `VisionTextLine` 객체는 단어 및 단어와 유사한 항목(날짜, 숫자 등)을 나타내는 0개 이상의 [`VisionTextElement`][VisionTextElement] 객체를 포함합니다. 각 `VisionTextBlock`, `VisionTextLine`, `VisionTextElement` 객체에 대해 해당 영역에서 인식된 텍스트와 영역의 경계 좌표를 가져올 수 있습니다. 예를 들면 다음과 같습니다.Swift
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 } } }
Objective-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; } } }
실시간 성능 향상을 위한 팁
기기별 모델을 사용하여 실시간 애플리케이션에서 텍스트를 인식하고자 하는 경우 다음 안내에 따르면 최상의 프레임 속도를 얻을 수 있습니다.
- 텍스트 인식기 호출을 제한합니다. 텍스트 인식기가 실행 중일 때 새 동영상 프레임을 사용할 수 있게 되면 프레임을 낮춥니다.
- 텍스트 인식기 출력을 사용해서 입력 이미지에서 그래픽을 오버레이하는 경우 먼저 ML Kit에서 텍스트 인식 결과를 가져온 후 이미지를 렌더링하고 단일 단계로 오버레이합니다. 이렇게 하면 입력 프레임별로 한 번만 디스플레이 표면에 렌더링됩니다. 관련 예시는 쇼케이스 샘플 앱에서 previewOverlayView 및 FIRDetectionOverlayView 클래스를 참조하세요.
- 낮은 해상도에서 이미지 캡처를 고려합니다. 단, API의 이미지 크기 요구사항도 유의해야 합니다.
다음 단계
- Cloud API를 사용하는 앱을 프로덕션 환경에 배포하기 전에 몇 가지 추가 단계를 수행하여 승인되지 않은 API 액세스를 방지하고 그로 인한 영향을 완화합니다.
문서의 이미지 속 텍스트 인식
문서의 텍스트를 인식하려면 아래에 설명된 대로 클라우드 기반 문서 텍스트 인식기를 구성하고 실행합니다.
아래에 설명된 문서 텍스트 인식 API는 문서 이미지 작업에 더욱 편리한 전용 인터페이스를 제공합니다. 하지만 희소 텍스트 API에서 제공하는 인터페이스를 선호하는 경우 클라우드 텍스트 인식기에서 밀집 텍스트 모델을 사용하도록 구성하여 이 인터페이스로 문서를 스캔할 수 있습니다.
문서 텍스트 인식 API를 사용하려면 다음을 수행합니다.
1. 텍스트 인식기 실행
이미지를UIImage
또는 CMSampleBufferRef
로 VisionDocumentTextRecognizer
의 process(_:completion:)
메서드에 전달합니다.
cloudDocumentTextRecognizer
을 호출하여VisionDocumentTextRecognizer
인스턴스를 가져옵니다.Swift
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)
Objective-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];
-
UIImage
또는CMSampleBufferRef
를 사용하여VisionImage
객체를 만듭니다.UIImage
를 사용하는 방법은 다음과 같습니다.- 필요한 경우
imageOrientation
속성이.up
이 되도록 이미지를 회전합니다. - 올바르게 회전된
UIImage
를 사용하여VisionImage
객체를 만듭니다. 회전 메타데이터를 지정하지 마세요. 기본값인.topLeft
를 사용해야 합니다.Swift
let image = VisionImage(image: uiImage)
Objective-C
FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];
CMSampleBufferRef
를 사용하는 방법은 다음과 같습니다.-
CMSampleBufferRef
버퍼에 포함된 이미지 데이터의 방향을 지정하는VisionImageMetadata
객체를 만듭니다.이미지 방향을 가져오는 방법은 다음과 같습니다.
Swift
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 } }
Objective-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; } }
그런 다음 메타데이터 객체를 만듭니다.
Swift
let cameraPosition = AVCaptureDevice.Position.back // Set to the capture device you used. let metadata = VisionImageMetadata() metadata.orientation = imageOrientation( deviceOrientation: UIDevice.current.orientation, cameraPosition: cameraPosition )
Objective-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];
CMSampleBufferRef
객체 및 회전 메타데이터를 사용하여VisionImage
객체를 만듭니다.Swift
let image = VisionImage(buffer: sampleBuffer) image.metadata = metadata
Objective-C
FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer]; image.metadata = metadata;
- 필요한 경우
- 이제 이미지를
process(_:completion:)
메서드에 전달합니다.Swift
textRecognizer.process(visionImage) { result, error in guard error == nil, let result = result else { // ... return } // Recognized text }
Objective-C
[textRecognizer processImage:image completion:^(FIRVisionDocumentText *_Nullable result, NSError *_Nullable error) { if (error != nil || result == nil) { // ... return; } // Recognized text }];
2. 인식된 텍스트 블록에서 텍스트 추출
텍스트 인식 작업이 성공하면VisionDocumentText
객체가 반환됩니다. VisionDocumentText
객체는 이미지에서 인식된 전체 텍스트 및 인식된 문서 구조를 반영하는 객체의 계층 구조를 포함합니다.
각 VisionDocumentTextBlock
, VisionDocumentTextParagraph
, VisionDocumentTextWord
, VisionDocumentTextSymbol
객체에 대해 해당 영역에서 인식된 텍스트와 영역의 경계 좌표를 가져올 수 있습니다.
예를 들면 다음과 같습니다.
Swift
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 } } } }
Objective-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; } } } }
다음 단계
- Cloud API를 사용하는 앱을 프로덕션 환경에 배포하기 전에 몇 가지 추가 단계를 수행하여 승인되지 않은 API 액세스를 방지하고 그로 인한 영향을 완화합니다.