É possível usar o Kit de ML para reconhecimento de texto em imagens. O Kit tem uma API de uso geral que reconhece texto em imagens, como texto de placa de rua, bem como uma API otimizada para reconhecer texto de documentos. A API de uso geral tem modelos baseados no dispositivo e na nuvem. O reconhecimento de texto em documentos está disponível apenas como modelo baseado na nuvem. Consulte a visão geral para uma comparação entre esses dois tipos de modelos.
Antes de começar
- Se você ainda não adicionou o Firebase ao seu app, siga as etapas no guia de iniciação.
- Inclua as bibliotecas do Kit de ML no seu Podfile:
pod 'Firebase/MLVision', '6.25.0' # If using an on-device API: pod 'Firebase/MLVisionTextModel', '6.25.0'
Depois de instalar ou atualizar os pods do projeto, abra o projeto do Xcode usando o.xcworkspace
. - Importe o Firebase para seu app:
Swift
import Firebase
Objective-C
@import Firebase;
-
Se você quiser usar o modelo baseado em nuvem e ainda não tiver ativado as APIs baseadas em nuvem para seu projeto, faça isso agora:
- Abra a página APIs do Kit de ML no console do Firebase.
-
Se você ainda não fez o upgrade de seu projeto para um plano de preços do Blaze, clique em Upgrade para fazer isso. Você só vai receber uma mensagem para fazer upgrade se o projeto não estiver no plano Blaze.
Apenas projetos no nível Blaze podem usar APIs baseadas na nuvem.
- Caso as APIs baseadas na nuvem ainda não estejam ativadas, clique em Ativar APIs baseadas na nuvem.
Se você quiser usar apenas o modelo no dispositivo, pule esta etapa.
Agora você já pode reconhecer texto em imagens.
Diretrizes das imagens de entrada
-
Para que o Kit de ML reconheça o texto com precisão, as imagens de entrada devem conter texto representado por dados de pixel suficientes. O ideal, para textos em alfabeto romano, é que cada caractere tenha pelo menos 16 x 16 pixels. Para textos em chinês, japonês e coreano (com suporte somente para APIs baseadas em nuvem), cada caractere deve ter 24 x 24 pixels. Para todos os idiomas, geralmente não há melhorias de precisão em usar caracteres maiores que 24 x 24 pixels.
Por exemplo, uma imagem de 640 x 480 pixels pode funcionar para digitalizar um cartão de visita que ocupe toda a largura da imagem. Para digitalizar um documento impresso em papel de tamanho carta, talvez seja necessária uma imagem de 720 x 1280 pixels.
-
O foco inadequado da imagem pode prejudicar a precisão do reconhecimento de texto. Se você não está conseguindo resultados aceitáveis, peça para o usuário recapturar a imagem.
-
Se você estiver fazendo reconhecimento de texto em um aplicativo em tempo real, considere as dimensões gerais das imagens de entrada. Como as imagens menores podem ser processadas mais rapidamente, reduza a latência capturando imagens em resoluções menores (lembrando os requisitos de precisão acima) e faça o texto ocupar o máximo possível da imagem. Consulte também Dicas para melhorar o desempenho em tempo real.
Reconhecer texto em imagens
Para reconhecer texto em imagens usando o modelo baseado no dispositivo ou na nuvem, execute o reconhecedor de texto conforme descrito nas etapas a seguir.
1. Executar o reconhecedor de texto
Transmita a imagem como "UIImage" ou "CMSampleBufferRef" para o método process(_:completion:) de "VisionTextRecognizer":- Receba uma instância de
VisionTextRecognizer
chamandoonDeviceTextRecognizer
oucloudTextRecognizer
:Swift
Para usar o modelo no dispositivo:
let vision = Vision.vision() let textRecognizer = vision.onDeviceTextRecognizer()
Para usar o modelo de nuvem:
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
Para usar o modelo no dispositivo:
FIRVision *vision = [FIRVision vision]; FIRVisionTextRecognizer *textRecognizer = [vision onDeviceTextRecognizer];
Para usar o modelo de nuvem:
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];
-
Crie um objeto
VisionImage
usando umUIImage
ou umCMSampleBufferRef
.Para usar um
UIImage
:- Se necessário, gire a imagem para que a propriedade
imageOrientation
seja.up
. - Crie um objeto
VisionImage
usando aUIImage
com a rotação correta. Não especifique metadados de rotação: o valor padrão,.topLeft
, precisa ser usado.Swift
let image = VisionImage(image: uiImage)
Objective-C
FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];
Para usar um
CMSampleBufferRef
:-
Crie um objeto
VisionImageMetadata
que especifique a orientação dos dados da imagem contidos no bufferCMSampleBufferRef
.Para ver a orientação da imagem:
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; } }
Em seguida, crie o objeto de metadados:
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];
- Crie um objeto
VisionImage
usando o objetoCMSampleBufferRef
e os metadados de rotação:Swift
let image = VisionImage(buffer: sampleBuffer) image.metadata = metadata
Objective-C
FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer]; image.metadata = metadata;
- Se necessário, gire a imagem para que a propriedade
-
Em seguida, transmita a imagem para o método
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. Extrair texto de blocos de texto reconhecido
Se a operação de reconhecimento de texto for bem-sucedida, ela retornará um objeto [`VisionText`][VisionText]. Um objeto "VisionText" contém o texto completo reconhecido na imagem e zero ou mais objetos [`VisionTextBlock`][VisionTextBlock]. Cada "VisionTextBlock" representa um bloco de texto retangular, que contém zero ou mais objetos ["VisionTextLine"] [VisionTextLine]. Cada objeto "VisionTextLine" contém zero ou mais objetos [`VisionTextElement`][VisionTextElement], que representam palavras e entidades semelhantes (datas, números e assim por diante). Para cada "VisionTextBlock", "VisionTextLine" e "VisionTextElement", você pode obter o texto reconhecido na região e as coordenadas delimitadoras da região. Exemplo: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; } } }
Dicas para melhorar o desempenho em tempo real
Se preferir usar o modelo no dispositivo para reconhecer texto em um aplicativo em tempo real, siga estas diretrizes para conseguir as melhores taxas de quadros:
- Limite as chamadas ao reconhecedor de texto. Se um novo frame de vídeo ficar disponível durante a execução do reconhecedor de texto, descarte esse frame.
- Se você estiver usando a saída do reconhecedor de texto para sobrepor elementos gráficos na imagem de entrada, primeiro acesse o resultado do Kit de ML e, em seguida, renderize a imagem e a sobreposição em uma única etapa. Ao fazer isso, você renderiza a superfície de exibição apenas uma vez para cada quadro de entrada. Consulte as classes previewOverlayView e FIRDetectionOverlayView no app de amostra da demonstração para ver um exemplo.
- Capture imagens em uma resolução menor. No entanto, lembre-se também dos requisitos de dimensão de imagem da API.
Próximas etapas
- Antes de implantar em produção um aplicativo que usa uma API do Cloud, é preciso seguir mais algumas etapas para evitar ou atenuar o efeito do acesso não autorizado à API.
Reconhecer texto em imagens de documentos
Para reconhecer o texto de um documento, configure e execute o documento baseado na nuvem conforme descrito nas instruções abaixo.
A API de reconhecimento de texto em documentos descrita abaixo tem uma interface desenvolvida para trabalhar com imagens de documentos. No entanto, se você preferir a interface fornecida pela API de texto em imagem, poderá usá-la para digitalizar documentos. Para fazer isso, basta configurar o reconhecedor de texto em nuvem para usar o modelo de texto denso.
Para usar a API de reconhecimento de texto em documentos, siga estas etapas:
1. Executar o reconhecedor de texto
Transmita a imagem como umUIImage
ou um CMSampleBufferRef
para o método process(_:completion:)
do VisionDocumentTextRecognizer
:
- Para receber uma instância de
VisionDocumentTextRecognizer
, chamecloudDocumentTextRecognizer
.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];
-
Crie um objeto
VisionImage
usando umUIImage
ou umCMSampleBufferRef
.Para usar um
UIImage
:- Se necessário, gire a imagem para que a propriedade
imageOrientation
seja.up
. - Crie um objeto
VisionImage
usando aUIImage
com a rotação correta. Não especifique metadados de rotação: o valor padrão,.topLeft
, precisa ser usado.Swift
let image = VisionImage(image: uiImage)
Objective-C
FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];
Para usar um
CMSampleBufferRef
:-
Crie um objeto
VisionImageMetadata
que especifique a orientação dos dados da imagem contidos no bufferCMSampleBufferRef
.Para ver a orientação da imagem:
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; } }
Em seguida, crie o objeto de metadados:
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];
- Crie um objeto
VisionImage
usando o objetoCMSampleBufferRef
e os metadados de rotação:Swift
let image = VisionImage(buffer: sampleBuffer) image.metadata = metadata
Objective-C
FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer]; image.metadata = metadata;
- Se necessário, gire a imagem para que a propriedade
-
Em seguida, transmita a imagem para o método
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. Extrair texto de blocos de texto reconhecido
Se a operação de reconhecimento de texto for bem-sucedida, ela retornará um objetoVisionDocumentText
. Um objeto VisionDocumentText
contém o texto completo reconhecido na imagem e uma hierarquia de objetos que refletem a estrutura do documento reconhecido:
Para cada objeto VisionDocumentTextBlock
, VisionDocumentTextParagraph
, VisionDocumentTextWord
e VisionDocumentTextSymbol
, é possível obter o texto reconhecido na região e as coordenadas delimitadoras da região.
Exemplo:
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; } } } }
Próximas etapas
- Antes de implantar em produção um app que usa uma API do Cloud, é preciso seguir mais algumas etapas para evitar ou atenuar o efeito do acesso não autorizado à API.