Reconoce texto en imágenes con el Kit de AA en iOS

Puedes usar el Kit de AA para reconocer texto en imágenes. El Kit de AA tiene una API de uso general que permite reconocer texto en imágenes, como en señales de tránsito, y una API optimizada para reconocer el texto de documentos. La API de uso general tiene modelos para dispositivos y en la nube. El reconocimiento de texto en documentos solo está disponible en el modelo para la nube. Consulta la descripción general a fin de comparar el modelo para dispositivos y el modelo para la nube.

Consulta la muestra de inicio rápido del Kit de AA alojada en GitHub para ver un ejemplo práctico de esta API, o bien prueba el codelab.

Antes de comenzar

  1. Si aún no agregaste Firebase a tu app, sigue los pasos en la guía de introducción para hacerlo.
  2. Incluye las bibliotecas del Kit de AA en el Podfile:
    pod 'Firebase/MLVision'
    # If using an on-device API:
    pod 'Firebase/MLVisionTextModel'
    
    Después de instalar o actualizar los pods de tu proyecto, asegúrate de abrir el proyecto de Xcode a través de su .xcworkspace.
  3. En tu app, importa Firebase:

    Swift

    import Firebase

    Objective-C

    @import Firebase;
  4. Si deseas usar el modelo basado en la nube, pero todavía no habilitaste las API basadas en la nube para el proyecto, hazlo ahora:

    1. Abre la página de API del Kit de AA de Firebase console.
    2. Si todavía no actualizaste tu proyecto a un plan Blaze, haz clic en Actualizar para hacerlo (Se te pedirá que realices la actualización únicamente si tu proyecto no está en el plan Blaze).

      Solo los proyectos con un plan Blaze pueden usar las API de Cloud.

    3. Si las API de Cloud no están habilitadas, haz clic en Habilitar las API de Cloud.

    Si solo quieres usar el modelo en el dispositivo, puedes omitir este paso.

Ya estás listo para comenzar a reconocer texto en imágenes.

Lineamientos para imágenes de entrada

  • Para que el Kit de AA reconozca texto con exactitud, las imágenes de entrada deben contener texto representado con datos de píxeles suficientes. Lo ideal para el texto latino es que cada carácter sea de al menos 16x16 píxeles. Para el texto en chino, japonés y coreano (solo compatible con las API basadas en la nube), cada carácter debe ser de 24x24 píxeles. Generalmente, para todos los idiomas, no se obtiene un beneficio de exactitud cuando el tamaño de los caracteres es superior a 24x24 píxeles.

    Por ejemplo, una imagen de 640x480 puede funcionar bien para escanear una tarjeta de presentación que ocupa todo el ancho de la imagen. Para escanear un documento impreso en tamaño de papel carta, es posible que se requiera una imagen de 720x1280 píxeles.

  • Un enfoque de imagen deficiente puede afectar la exactitud del reconocimiento de texto. Si no obtienes resultados aceptables, intenta pedirle al usuario que vuelva a capturar la imagen.

  • Si reconoces texto en una aplicación en tiempo real, te recomendamos tener en cuenta las dimensiones generales de las imágenes de entrada. Las imágenes más pequeñas se pueden procesar más rápido. Así que, para reducir la latencia, captura las imágenes con resoluciones más bajas (teniendo en cuenta los requisitos de exactitud anteriores) y asegúrate de que el texto ocupe la mayor porción de la imagen que sea posible. Consulta también Sugerencias para mejorar el rendimiento en tiempo real.


Reconoce texto en imágenes

A fin de reconocer texto en una imagen con el modelo para el dispositivo o el correspondiente a la nube, ejecuta el reconocedor de texto como se describe a continuación:

1. Ejecuta el reconocedor de texto

Pasa la imagen como una UIImage o una CMSampleBufferRef al método process(_:completion:) de VisionTextRecognizer:

  1. Obtén una instancia de VisionTextRecognizer a través de una llamada a onDeviceTextRecognizer o a cloudTextRecognizer:

    Swift

    Para usar el modelo en el dispositivo:

    let vision = Vision.vision()
    let textRecognizer = vision.onDeviceTextRecognizer()
    

    Para usar el modelo en la nube, haz lo siguiente:

    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 el modelo en el dispositivo:

    FIRVision *vision = [FIRVision vision];
    FIRVisionTextRecognizer *textRecognizer = [vision onDeviceTextRecognizer];
    

    Para usar el modelo en la nube, haz lo siguiente:

    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];
    
  2. Crea un objeto VisionImage a través de una UIImage o una CMSampleBufferRef.

    Para usar una UIImage:

    1. Si es necesario, rota la imagen para que la propiedad imageOrientation sea .up.
    2. Usa una UIImage que se haya rotado correctamente para crear un objeto VisionImage. No especifiques los metadatos de rotación. Se debe usar el valor predeterminado .topLeft.

      Swift

      let image = VisionImage(image: uiImage)

      Objective-C

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];

    Para usar una CMSampleBufferRef:

    1. Crea un objeto VisionImageMetadata en el que se especifique la orientación de los datos de la imagen contenidos en el búfer CMSampleBufferRef.

      Para obtener la orientación de la imagen, haz lo siguiente:

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

      Luego, crea el objeto de metadatos de esta manera:

      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];
    2. Crea un objeto VisionImage a través del objeto CMSampleBufferRef y los metadatos de rotación:

      Swift

      let image = VisionImage(buffer: sampleBuffer)
      image.metadata = metadata

      Objective-C

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer];
      image.metadata = metadata;
  3. Por último, pasa la imagen al 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 Extrae texto de bloques de texto reconocido

Si la operación de reconocimiento de texto se ejecuta correctamente, se mostrará un objeto VisionText. Un objeto VisionText contiene el texto completo reconocido en la imagen, y cero o más objetos VisionTextBlock.

Cada VisionTextBlock representa un bloque rectangular de texto que contiene cero o más objetos VisionTextLine. Cada objeto VisionTextLine contiene cero o más objetos VisionTextElement, que representan palabras y entidades similares (fechas, números, etcétera).

Para cada objeto VisionTextBlock, VisionTextLine y VisionTextElement, puedes obtener el texto reconocido en la región y las coordenadas que limitan la región.

Por ejemplo:

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

Sugerencias para mejorar el rendimiento en tiempo real

Si quieres usar el modelo en el dispositivo para reconocer texto en una aplicación en tiempo real, sigue estos lineamientos para lograr las mejores velocidades de fotogramas:

  • Regula las llamadas al reconocedor de texto. Si hay un fotograma de video nuevo disponible mientras se ejecuta el reconocedor de texto, ignora ese fotograma.
  • Si estás usando la salida del reconocedor de texto para superponer gráficas en la imagen de entrada, primero obtén el resultado del Kit de AA y luego procesa la imagen y la superposición en un solo paso. De esta manera, procesas en la superficie de visualización solo una vez por cada fotograma de entrada. Consulta las clases previewOverlayView y FIRDetectionOverlayView en la app de muestra para ver un ejemplo.
  • Captura imágenes con una resolución más baja. Sin embargo, también ten en cuenta los requisitos de dimensiones de imágenes de esta API.

Pasos siguientes


Reconoce texto en imágenes de documentos

Para reconocer el texto de un documento, configura y ejecuta el reconocedor de texto en documentos en la nube como se describe a continuación.

La API de reconocimiento de texto en documentos, que se describe a continuación, proporciona una interfaz diseñada para facilitar el trabajo con imágenes en documentos. Sin embargo, si prefieres la interfaz que proporciona la API de texto escaso, puedes usarla para escanear documentos configurando el reconocedor de texto en la nube a fin de utilizar el modelo para mucho texto.

Para usar la API de reconocimiento de texto en documentos, haz lo siguiente:

1. Ejecuta el reconocedor de texto

Pasa la imagen como una UIImage o una CMSampleBufferRef al método process(_:completion:) de VisionDocumentTextRecognizer:

  1. Obtén una instancia de VisionDocumentTextRecognizer a través de una llamada a cloudDocumentTextRecognizer:

    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];
    
  2. Crea un objeto VisionImage a través de una UIImage o una CMSampleBufferRef.

    Para usar una UIImage:

    1. Si es necesario, rota la imagen para que la propiedad imageOrientation sea .up.
    2. Usa una UIImage que se haya rotado correctamente para crear un objeto VisionImage. No especifiques los metadatos de rotación. Se debe usar el valor predeterminado .topLeft.

      Swift

      let image = VisionImage(image: uiImage)

      Objective-C

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];

    Para usar una CMSampleBufferRef:

    1. Crea un objeto VisionImageMetadata en el que se especifique la orientación de los datos de la imagen contenidos en el búfer CMSampleBufferRef.

      Para obtener la orientación de la imagen, haz lo siguiente:

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

      Luego, crea el objeto de metadatos de esta manera:

      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];
    2. Crea un objeto VisionImage a través del objeto CMSampleBufferRef y los metadatos de rotación:

      Swift

      let image = VisionImage(buffer: sampleBuffer)
      image.metadata = metadata

      Objective-C

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer];
      image.metadata = metadata;
  3. Por último, pasa la imagen al 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 Extrae texto de bloques de texto reconocido

Si la operación de reconocimiento de texto se ejecuta correctamente, se mostrará un objeto VisionDocumentText. El objeto VisionDocumentText contiene todo el texto reconocido en la imagen y una jerarquía de objetos que refleja la estructura del documento reconocido:

Para cada objeto VisionDocumentTextBlock, VisionDocumentTextParagraph, VisionDocumentTextWord y VisionDocumentTextSymbol, puedes obtener el texto reconocido en la región y las coordenadas que limitan la región.

Por ejemplo:

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

Pasos siguientes