Puede utilizar ML Kit para reconocer texto en imágenes. ML Kit tiene una API de uso general adecuada para reconocer texto en imágenes, como el texto de un letrero de calle, y una API optimizada para reconocer el texto de documentos. La API de propósito general tiene modelos tanto en el dispositivo como basados en la nube. El reconocimiento de texto de documentos solo está disponible como modelo basado en la nube. Consulte la descripción general para obtener una comparación de los modelos en la nube y en el dispositivo.
Antes de que empieces
- Si aún no has agregado Firebase a tu aplicación, hazlo siguiendo los pasos de la guía de introducción .
- Incluya las bibliotecas del kit ML en su Podfile:
pod 'Firebase/MLVision', '6.25.0' # If using an on-device API: pod 'Firebase/MLVisionTextModel', '6.25.0'
Después de instalar o actualizar los Pods de su proyecto, asegúrese de abrir su proyecto Xcode usando su.xcworkspace
. - En tu aplicación, importa Firebase:
Rápido
import Firebase
C objetivo
@import Firebase;
Si desea utilizar el modelo basado en la nube y aún no ha habilitado las API basadas en la nube para su proyecto, hágalo ahora:
- Abra la página API del kit de aprendizaje automático de Firebase console.
Si aún no ha actualizado su proyecto a un plan de precios de Blaze, haga clic en Actualizar para hacerlo. (Se le pedirá que actualice solo si su proyecto no está en el plan Blaze).
Solo los proyectos de nivel Blaze pueden utilizar API basadas en la nube.
- Si las API basadas en la nube aún no están habilitadas, haga clic en Habilitar API basadas en la nube .
Si desea utilizar solo el modelo del dispositivo, puede omitir este paso.
Ahora estás listo para comenzar a reconocer texto en imágenes.
Pautas de imagen de entrada
Para que ML Kit reconozca texto con precisión, las imágenes de entrada deben contener texto representado por suficientes datos de píxeles. Idealmente, para texto latino, cada carácter debe tener al menos 16x16 píxeles. Para texto en chino, japonés y coreano (solo compatible con las API basadas en la nube), cada carácter debe tener 24 x 24 píxeles. Para todos los idiomas, generalmente no existe ninguna ventaja en la precisión si los caracteres tienen un tamaño superior a 24 x 24 píxeles.
Así, por ejemplo, una imagen de 640x480 podría funcionar bien para escanear una tarjeta de presentación que ocupe todo el ancho de la imagen. Para escanear un documento impreso en papel tamaño carta, es posible que necesite una imagen de 720 x 1280 píxeles.
Un enfoque deficiente de la imagen puede afectar la precisión del reconocimiento de texto. Si no obtiene resultados aceptables, intente pedirle al usuario que vuelva a capturar la imagen.
Si reconoce texto en una aplicación en tiempo real, es posible que también desee considerar las dimensiones generales de las imágenes de entrada. Las imágenes más pequeñas se pueden procesar más rápido, por lo tanto, para reducir la latencia, capture imágenes con resoluciones más bajas (teniendo en cuenta los requisitos de precisión anteriores) y asegúrese de que el texto ocupe la mayor parte posible de la imagen. Consulte también Sugerencias para mejorar el rendimiento en tiempo real .
Reconocer texto en imágenes
Para reconocer texto en una imagen utilizando un modelo en el dispositivo o basado en la nube, ejecute el reconocedor de texto como se describe a continuación.
1. Ejecute el reconocedor de texto.
Pase la imagen como `UIImage` o `CMSampleBufferRef` al método `process(_:completion:)` de `VisionTextRecognizer`:- Obtenga una instancia de
VisionTextRecognizer
llamando aonDeviceTextRecognizer
ocloudTextRecognizer
:Rápido
Para utilizar el modelo en el dispositivo:
let vision = Vision.vision() let textRecognizer = vision.onDeviceTextRecognizer()
Para utilizar el modelo en la nube:
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)
C objetivo
Para utilizar el modelo en el dispositivo:
FIRVision *vision = [FIRVision vision]; FIRVisionTextRecognizer *textRecognizer = [vision onDeviceTextRecognizer];
Para utilizar el modelo en la nube:
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];
Cree un objeto
VisionImage
utilizandoUIImage
oCMSampleBufferRef
.Para usar una
UIImage
:- Si es necesario, gire la imagen para que su propiedad
imageOrientation
sea.up
. - Cree un objeto
VisionImage
utilizandoUIImage
girado correctamente. No especifique ningún metadato de rotación; se debe utilizar el valor predeterminado,.topLeft
.Rápido
let image = VisionImage(image: uiImage)
C objetivo
FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];
Para utilizar
CMSampleBufferRef
:Cree un objeto
VisionImageMetadata
que especifique la orientación de los datos de la imagen contenidos en el búferCMSampleBufferRef
.Para obtener la orientación de la imagen:
Rápido
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 } }
C objetivo
- (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; } }
Luego, crea el objeto de metadatos:
Rápido
let cameraPosition = AVCaptureDevice.Position.back // Set to the capture device you used. let metadata = VisionImageMetadata() metadata.orientation = imageOrientation( deviceOrientation: UIDevice.current.orientation, cameraPosition: cameraPosition )
C objetivo
FIRVisionImageMetadata *metadata = [[FIRVisionImageMetadata alloc] init]; AVCaptureDevicePosition cameraPosition = AVCaptureDevicePositionBack; // Set to the capture device you used. metadata.orientation = [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation cameraPosition:cameraPosition];
- Cree un objeto
VisionImage
utilizando el objetoCMSampleBufferRef
y los metadatos de rotación:Rápido
let image = VisionImage(buffer: sampleBuffer) image.metadata = metadata
C objetivo
FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer]; image.metadata = metadata;
- Si es necesario, gire la imagen para que su propiedad
- Luego, pasa la imagen al método
process(_:completion:)
:Rápido
textRecognizer.process(visionImage) { result, error in guard error == nil, let result = result else { // ... return } // Recognized text }
C objetivo
[textRecognizer processImage:image completion:^(FIRVisionText *_Nullable result, NSError *_Nullable error) { if (error != nil || result == nil) { // ... return; } // Recognized text }];
2. Extraer texto de bloques de texto reconocido
Si la operación de reconocimiento de texto tiene éxito, devolverá un objeto [`VisionText`][VisionText]. Un objeto `VisionText` contiene el texto completo reconocido en la imagen y cero o más objetos [`VisionTextBlock`][VisionTextBlock]. Cada `VisionTextBlock` representa un bloque rectangular de texto, que contiene cero o más objetos [`VisionTextLine`][VisionTextLine]. Cada objeto `VisionTextLine` contiene cero o más objetos [`VisionTextElement`][VisionTextElement], que representan palabras y entidades similares a palabras (fechas, números, etc.). Para cada objeto `VisionTextBlock`, `VisionTextLine` y `VisionTextElement`, puede obtener el texto reconocido en la región y las coordenadas delimitadoras de la región. Por ejemplo:Rápido
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 } } }
C objetivo
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; } } }
Consejos para mejorar el rendimiento en tiempo real
Si desea utilizar el modelo en el dispositivo para reconocer texto en una aplicación en tiempo real, siga estas pautas para lograr las mejores velocidades de fotogramas:
- Acelera las llamadas al reconocedor de texto. Si hay un nuevo fotograma de vídeo disponible mientras se ejecuta el reconocedor de texto, suelte el fotograma.
- Si está utilizando la salida del reconocedor de texto para superponer gráficos en la imagen de entrada, primero obtenga el resultado del ML Kit, luego renderice la imagen y superpóngala en un solo paso. Al hacerlo, renderiza en la superficie de visualización solo una vez por cada cuadro de entrada. Consulte las clases previaOverlayView y FIRDetectionOverlayView en la aplicación de muestra de presentación para ver un ejemplo.
- Considere capturar imágenes a una resolución más baja. Sin embargo, también tenga en cuenta los requisitos de dimensión de imagen de esta API.
Próximos pasos
- Antes de implementar en producción una aplicación que utiliza una API de la nube, debe tomar algunas medidas adicionales para prevenir y mitigar el efecto del acceso no autorizado a la API .
Reconocer texto en imágenes de documentos.
Para reconocer el texto de un documento, configure y ejecute el reconocedor de texto de documentos basado en la nube como se describe a continuación.
La API de reconocimiento de texto de documentos, que se describe a continuación, proporciona una interfaz que pretende ser más conveniente para trabajar con imágenes de documentos. Sin embargo, si prefiere la interfaz proporcionada por la API de texto disperso, puede usarla para escanear documentos configurando el reconocedor de texto en la nube para usar el modelo de texto denso .
Para utilizar la API de reconocimiento de texto de documentos:
1. Ejecute el reconocedor de texto.
Pase la imagen comoUIImage
o CMSampleBufferRef
al método process(_:completion:)
de VisionDocumentTextRecognizer
:- Obtenga una instancia de
VisionDocumentTextRecognizer
llamandocloudDocumentTextRecognizer
:Rápido
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)
C objetivo
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];
Cree un objeto
VisionImage
utilizandoUIImage
oCMSampleBufferRef
.Para usar una
UIImage
:- Si es necesario, gire la imagen para que su propiedad
imageOrientation
sea.up
. - Cree un objeto
VisionImage
utilizandoUIImage
girado correctamente. No especifique ningún metadato de rotación; se debe utilizar el valor predeterminado,.topLeft
.Rápido
let image = VisionImage(image: uiImage)
C objetivo
FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];
Para utilizar
CMSampleBufferRef
:Cree un objeto
VisionImageMetadata
que especifique la orientación de los datos de la imagen contenidos en el búferCMSampleBufferRef
.Para obtener la orientación de la imagen:
Rápido
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 } }
C objetivo
- (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; } }
Luego, crea el objeto de metadatos:
Rápido
let cameraPosition = AVCaptureDevice.Position.back // Set to the capture device you used. let metadata = VisionImageMetadata() metadata.orientation = imageOrientation( deviceOrientation: UIDevice.current.orientation, cameraPosition: cameraPosition )
C objetivo
FIRVisionImageMetadata *metadata = [[FIRVisionImageMetadata alloc] init]; AVCaptureDevicePosition cameraPosition = AVCaptureDevicePositionBack; // Set to the capture device you used. metadata.orientation = [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation cameraPosition:cameraPosition];
- Cree un objeto
VisionImage
utilizando el objetoCMSampleBufferRef
y los metadatos de rotación:Rápido
let image = VisionImage(buffer: sampleBuffer) image.metadata = metadata
C objetivo
FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer]; image.metadata = metadata;
- Si es necesario, gire la imagen para que su propiedad
- Luego, pasa la imagen al método
process(_:completion:)
:Rápido
textRecognizer.process(visionImage) { result, error in guard error == nil, let result = result else { // ... return } // Recognized text }
C objetivo
[textRecognizer processImage:image completion:^(FIRVisionDocumentText *_Nullable result, NSError *_Nullable error) { if (error != nil || result == nil) { // ... return; } // Recognized text }];
2. Extraer texto de bloques de texto reconocido
Si la operación de reconocimiento de texto tiene éxito, devolverá un objetoVisionDocumentText
. Un objeto VisionDocumentText
contiene el texto completo reconocido en la imagen y una jerarquía de objetos que reflejan la estructura del documento reconocido: Para cada objeto VisionDocumentTextBlock
, VisionDocumentTextParagraph
, VisionDocumentTextWord
y VisionDocumentTextSymbol
, puede obtener el texto reconocido en la región y las coordenadas delimitadoras de la región.
Por ejemplo:
Rápido
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 } } } }
C objetivo
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óximos pasos
- Antes de implementar en producción una aplicación que utiliza una API de la nube, debe tomar algunas medidas adicionales para prevenir y mitigar el efecto del acceso no autorizado a la API .