Reconocer texto en imágenes con ML Kit en Android

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

  1. Si aún no lo has hecho, agrega Firebase a tu proyecto de Android .
  2. Agregue las dependencias de las bibliotecas de Android ML Kit al archivo Gradle de su módulo (nivel de aplicación) (generalmente app/build.gradle ):
    apply plugin: 'com.android.application'
    apply plugin: 'com.google.gms.google-services'
    
    dependencies {
      // ...
    
      implementation 'com.google.firebase:firebase-ml-vision:24.0.3'
    }
    
  3. Opcional pero recomendado : si usa la API en el dispositivo, configure su aplicación para descargar automáticamente el modelo ML en el dispositivo después de instalarla desde Play Store.

    Para hacerlo, agregue la siguiente declaración al archivo AndroidManifest.xml de su aplicación:

    <application ...>
      ...
      <meta-data
          android:name="com.google.firebase.ml.vision.DEPENDENCIES"
          android:value="ocr" />
      <!-- To use multiple models: android:value="ocr,model2,model3" -->
    </application>
    
    Si no habilita las descargas de modelos durante la instalación, el modelo se descargará la primera vez que ejecute el detector en el dispositivo. Las solicitudes que realice antes de que se complete la descarga no producirán resultados.
  4. 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:

    1. Abra la página API del kit de aprendizaje automático de Firebase console.
    2. 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.

    3. 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.

Para reconocer texto en una imagen, cree un objeto FirebaseVisionImage a partir de un Bitmap , media.Image , ByteBuffer , una matriz de bytes o un archivo en el dispositivo. Luego, pase el objeto FirebaseVisionImage al método processImage de FirebaseVisionTextRecognizer .

  1. Crea un objeto FirebaseVisionImage a partir de tu imagen.

    • Para crear un objeto FirebaseVisionImage a partir de un objeto media.Image , como al capturar una imagen desde la cámara de un dispositivo, pase el objeto media.Image y la rotación de la imagen a FirebaseVisionImage.fromMediaImage() .

      Si usa la biblioteca CameraX , las clases OnImageCapturedListener e ImageAnalysis.Analyzer calculan el valor de rotación por usted, por lo que solo necesita convertir la rotación a una de las constantes ROTATION_ del kit ML antes de llamar FirebaseVisionImage.fromMediaImage() :

      Java

      private class YourAnalyzer implements ImageAnalysis.Analyzer {
      
          private int degreesToFirebaseRotation(int degrees) {
              switch (degrees) {
                  case 0:
                      return FirebaseVisionImageMetadata.ROTATION_0;
                  case 90:
                      return FirebaseVisionImageMetadata.ROTATION_90;
                  case 180:
                      return FirebaseVisionImageMetadata.ROTATION_180;
                  case 270:
                      return FirebaseVisionImageMetadata.ROTATION_270;
                  default:
                      throw new IllegalArgumentException(
                              "Rotation must be 0, 90, 180, or 270.");
              }
          }
      
          @Override
          public void analyze(ImageProxy imageProxy, int degrees) {
              if (imageProxy == null || imageProxy.getImage() == null) {
                  return;
              }
              Image mediaImage = imageProxy.getImage();
              int rotation = degreesToFirebaseRotation(degrees);
              FirebaseVisionImage image =
                      FirebaseVisionImage.fromMediaImage(mediaImage, rotation);
              // Pass image to an ML Kit Vision API
              // ...
          }
      }
      

      Kotlin+KTX

      private class YourImageAnalyzer : ImageAnalysis.Analyzer {
          private fun degreesToFirebaseRotation(degrees: Int): Int = when(degrees) {
              0 -> FirebaseVisionImageMetadata.ROTATION_0
              90 -> FirebaseVisionImageMetadata.ROTATION_90
              180 -> FirebaseVisionImageMetadata.ROTATION_180
              270 -> FirebaseVisionImageMetadata.ROTATION_270
              else -> throw Exception("Rotation must be 0, 90, 180, or 270.")
          }
      
          override fun analyze(imageProxy: ImageProxy?, degrees: Int) {
              val mediaImage = imageProxy?.image
              val imageRotation = degreesToFirebaseRotation(degrees)
              if (mediaImage != null) {
                  val image = FirebaseVisionImage.fromMediaImage(mediaImage, imageRotation)
                  // Pass image to an ML Kit Vision API
                  // ...
              }
          }
      }
      

      Si no utiliza una biblioteca de cámaras que le proporcione la rotación de la imagen, puede calcularla a partir de la rotación del dispositivo y la orientación del sensor de la cámara en el dispositivo:

      Java

      private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
      static {
          ORIENTATIONS.append(Surface.ROTATION_0, 90);
          ORIENTATIONS.append(Surface.ROTATION_90, 0);
          ORIENTATIONS.append(Surface.ROTATION_180, 270);
          ORIENTATIONS.append(Surface.ROTATION_270, 180);
      }
      
      /**
       * Get the angle by which an image must be rotated given the device's current
       * orientation.
       */
      @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
      private int getRotationCompensation(String cameraId, Activity activity, Context context)
              throws CameraAccessException {
          // Get the device's current rotation relative to its "native" orientation.
          // Then, from the ORIENTATIONS table, look up the angle the image must be
          // rotated to compensate for the device's rotation.
          int deviceRotation = activity.getWindowManager().getDefaultDisplay().getRotation();
          int rotationCompensation = ORIENTATIONS.get(deviceRotation);
      
          // On most devices, the sensor orientation is 90 degrees, but for some
          // devices it is 270 degrees. For devices with a sensor orientation of
          // 270, rotate the image an additional 180 ((270 + 270) % 360) degrees.
          CameraManager cameraManager = (CameraManager) context.getSystemService(CAMERA_SERVICE);
          int sensorOrientation = cameraManager
                  .getCameraCharacteristics(cameraId)
                  .get(CameraCharacteristics.SENSOR_ORIENTATION);
          rotationCompensation = (rotationCompensation + sensorOrientation + 270) % 360;
      
          // Return the corresponding FirebaseVisionImageMetadata rotation value.
          int result;
          switch (rotationCompensation) {
              case 0:
                  result = FirebaseVisionImageMetadata.ROTATION_0;
                  break;
              case 90:
                  result = FirebaseVisionImageMetadata.ROTATION_90;
                  break;
              case 180:
                  result = FirebaseVisionImageMetadata.ROTATION_180;
                  break;
              case 270:
                  result = FirebaseVisionImageMetadata.ROTATION_270;
                  break;
              default:
                  result = FirebaseVisionImageMetadata.ROTATION_0;
                  Log.e(TAG, "Bad rotation value: " + rotationCompensation);
          }
          return result;
      }

      Kotlin+KTX

      private val ORIENTATIONS = SparseIntArray()
      
      init {
          ORIENTATIONS.append(Surface.ROTATION_0, 90)
          ORIENTATIONS.append(Surface.ROTATION_90, 0)
          ORIENTATIONS.append(Surface.ROTATION_180, 270)
          ORIENTATIONS.append(Surface.ROTATION_270, 180)
      }
      /**
       * Get the angle by which an image must be rotated given the device's current
       * orientation.
       */
      @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
      @Throws(CameraAccessException::class)
      private fun getRotationCompensation(cameraId: String, activity: Activity, context: Context): Int {
          // Get the device's current rotation relative to its "native" orientation.
          // Then, from the ORIENTATIONS table, look up the angle the image must be
          // rotated to compensate for the device's rotation.
          val deviceRotation = activity.windowManager.defaultDisplay.rotation
          var rotationCompensation = ORIENTATIONS.get(deviceRotation)
      
          // On most devices, the sensor orientation is 90 degrees, but for some
          // devices it is 270 degrees. For devices with a sensor orientation of
          // 270, rotate the image an additional 180 ((270 + 270) % 360) degrees.
          val cameraManager = context.getSystemService(CAMERA_SERVICE) as CameraManager
          val sensorOrientation = cameraManager
                  .getCameraCharacteristics(cameraId)
                  .get(CameraCharacteristics.SENSOR_ORIENTATION)!!
          rotationCompensation = (rotationCompensation + sensorOrientation + 270) % 360
      
          // Return the corresponding FirebaseVisionImageMetadata rotation value.
          val result: Int
          when (rotationCompensation) {
              0 -> result = FirebaseVisionImageMetadata.ROTATION_0
              90 -> result = FirebaseVisionImageMetadata.ROTATION_90
              180 -> result = FirebaseVisionImageMetadata.ROTATION_180
              270 -> result = FirebaseVisionImageMetadata.ROTATION_270
              else -> {
                  result = FirebaseVisionImageMetadata.ROTATION_0
                  Log.e(TAG, "Bad rotation value: $rotationCompensation")
              }
          }
          return result
      }

      Luego, pasa el objeto media.Image y el valor de rotación a FirebaseVisionImage.fromMediaImage() :

      Java

      FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation);

      Kotlin+KTX

      val image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation)
    • Para crear un objeto FirebaseVisionImage a partir de un URI de archivo, pase el contexto de la aplicación y el URI del archivo a FirebaseVisionImage.fromFilePath() . Esto es útil cuando usas un intent ACTION_GET_CONTENT para pedirle al usuario que seleccione una imagen de su aplicación de galería.

      Java

      FirebaseVisionImage image;
      try {
          image = FirebaseVisionImage.fromFilePath(context, uri);
      } catch (IOException e) {
          e.printStackTrace();
      }

      Kotlin+KTX

      val image: FirebaseVisionImage
      try {
          image = FirebaseVisionImage.fromFilePath(context, uri)
      } catch (e: IOException) {
          e.printStackTrace()
      }
    • Para crear un objeto FirebaseVisionImage a partir de un ByteBuffer o una matriz de bytes, primero calcule la rotación de la imagen como se describe anteriormente para la entrada media.Image .

      Luego, crea un objeto FirebaseVisionImageMetadata que contenga la altura, el ancho, el formato de codificación de color y la rotación de la imagen:

      Java

      FirebaseVisionImageMetadata metadata = new FirebaseVisionImageMetadata.Builder()
              .setWidth(480)   // 480x360 is typically sufficient for
              .setHeight(360)  // image recognition
              .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21)
              .setRotation(rotation)
              .build();

      Kotlin+KTX

      val metadata = FirebaseVisionImageMetadata.Builder()
              .setWidth(480) // 480x360 is typically sufficient for
              .setHeight(360) // image recognition
              .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21)
              .setRotation(rotation)
              .build()

      Utilice el búfer o matriz y el objeto de metadatos para crear un objeto FirebaseVisionImage :

      Java

      FirebaseVisionImage image = FirebaseVisionImage.fromByteBuffer(buffer, metadata);
      // Or: FirebaseVisionImage image = FirebaseVisionImage.fromByteArray(byteArray, metadata);

      Kotlin+KTX

      val image = FirebaseVisionImage.fromByteBuffer(buffer, metadata)
      // Or: val image = FirebaseVisionImage.fromByteArray(byteArray, metadata)
    • Para crear un objeto FirebaseVisionImage a partir de un objeto Bitmap :

      Java

      FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);

      Kotlin+KTX

      val image = FirebaseVisionImage.fromBitmap(bitmap)
      La imagen representada por el objeto Bitmap debe estar en posición vertical, sin necesidad de rotación adicional.

  2. Obtenga una instancia de FirebaseVisionTextRecognizer .

    Para utilizar el modelo en el dispositivo:

    Java

    FirebaseVisionTextRecognizer detector = FirebaseVision.getInstance()
            .getOnDeviceTextRecognizer();

    Kotlin+KTX

    val detector = FirebaseVision.getInstance()
            .onDeviceTextRecognizer

    Para utilizar el modelo basado en la nube:

    Java

    FirebaseVisionTextRecognizer detector = FirebaseVision.getInstance()
            .getCloudTextRecognizer();
    // Or, to change the default settings:
    //   FirebaseVisionTextRecognizer detector = FirebaseVision.getInstance()
    //          .getCloudTextRecognizer(options);
    // Or, to provide language hints to assist with language detection:
    // See https://cloud.google.com/vision/docs/languages for supported languages
    FirebaseVisionCloudTextRecognizerOptions options = new FirebaseVisionCloudTextRecognizerOptions.Builder()
            .setLanguageHints(Arrays.asList("en", "hi"))
            .build();
    

    Kotlin+KTX

    val detector = FirebaseVision.getInstance().cloudTextRecognizer
    // Or, to change the default settings:
    // val detector = FirebaseVision.getInstance().getCloudTextRecognizer(options)
    // Or, to provide language hints to assist with language detection:
    // See https://cloud.google.com/vision/docs/languages for supported languages
    val options = FirebaseVisionCloudTextRecognizerOptions.Builder()
            .setLanguageHints(listOf("en", "hi"))
            .build()
    
  3. Finalmente, pasa la imagen al método processImage :

    Java

    Task<FirebaseVisionText> result =
            detector.processImage(image)
                    .addOnSuccessListener(new OnSuccessListener<FirebaseVisionText>() {
                        @Override
                        public void onSuccess(FirebaseVisionText firebaseVisionText) {
                            // Task completed successfully
                            // ...
                        }
                    })
                    .addOnFailureListener(
                            new OnFailureListener() {
                                @Override
                                public void onFailure(@NonNull Exception e) {
                                    // Task failed with an exception
                                    // ...
                                }
                            });

    Kotlin+KTX

    val result = detector.processImage(image)
            .addOnSuccessListener { firebaseVisionText ->
                // Task completed successfully
                // ...
            }
            .addOnFailureListener { e ->
                // Task failed with an exception
                // ...
            }

2. Extraer texto de bloques de texto reconocido

Si la operación de reconocimiento de texto tiene éxito, se pasará un objeto FirebaseVisionText al oyente exitoso. Un objeto FirebaseVisionText contiene el texto completo reconocido en la imagen y cero o más objetos TextBlock .

Cada TextBlock representa un bloque rectangular de texto, que contiene cero o más objetos Line . Cada objeto Line contiene cero o más objetos Element , que representan palabras y entidades similares a palabras (fechas, números, etc.).

Para cada objeto TextBlock , Line y Element , puede obtener el texto reconocido en la región y las coordenadas delimitadoras de la región.

Por ejemplo:

Java

String resultText = result.getText();
for (FirebaseVisionText.TextBlock block: result.getTextBlocks()) {
    String blockText = block.getText();
    Float blockConfidence = block.getConfidence();
    List<RecognizedLanguage> blockLanguages = block.getRecognizedLanguages();
    Point[] blockCornerPoints = block.getCornerPoints();
    Rect blockFrame = block.getBoundingBox();
    for (FirebaseVisionText.Line line: block.getLines()) {
        String lineText = line.getText();
        Float lineConfidence = line.getConfidence();
        List<RecognizedLanguage> lineLanguages = line.getRecognizedLanguages();
        Point[] lineCornerPoints = line.getCornerPoints();
        Rect lineFrame = line.getBoundingBox();
        for (FirebaseVisionText.Element element: line.getElements()) {
            String elementText = element.getText();
            Float elementConfidence = element.getConfidence();
            List<RecognizedLanguage> elementLanguages = element.getRecognizedLanguages();
            Point[] elementCornerPoints = element.getCornerPoints();
            Rect elementFrame = element.getBoundingBox();
        }
    }
}

Kotlin+KTX

val resultText = result.text
for (block in result.textBlocks) {
    val blockText = block.text
    val blockConfidence = block.confidence
    val blockLanguages = block.recognizedLanguages
    val blockCornerPoints = block.cornerPoints
    val blockFrame = block.boundingBox
    for (line in block.lines) {
        val lineText = line.text
        val lineConfidence = line.confidence
        val lineLanguages = line.recognizedLanguages
        val lineCornerPoints = line.cornerPoints
        val lineFrame = line.boundingBox
        for (element in line.elements) {
            val elementText = element.text
            val elementConfidence = element.confidence
            val elementLanguages = element.recognizedLanguages
            val elementCornerPoints = element.cornerPoints
            val elementFrame = element.boundingBox
        }
    }
}

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.
  • Si utiliza la API Camera2, capture imágenes en formato ImageFormat.YUV_420_888 .

    Si utiliza la API de cámara anterior, capture imágenes en formato ImageFormat.NV21 .

  • 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


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 FirebaseVisionTextRecognizer , 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.

Para reconocer texto en una imagen, cree un objeto FirebaseVisionImage a partir de un Bitmap , media.Image , ByteBuffer , una matriz de bytes o un archivo en el dispositivo. Luego, pase el objeto FirebaseVisionImage al método processImage de FirebaseVisionDocumentTextRecognizer .

  1. Crea un objeto FirebaseVisionImage a partir de tu imagen.

    • Para crear un objeto FirebaseVisionImage a partir de un objeto media.Image , como al capturar una imagen desde la cámara de un dispositivo, pase el objeto media.Image y la rotación de la imagen a FirebaseVisionImage.fromMediaImage() .

      Si usa la biblioteca CameraX , las clases OnImageCapturedListener e ImageAnalysis.Analyzer calculan el valor de rotación por usted, por lo que solo necesita convertir la rotación a una de las constantes ROTATION_ del kit ML antes de llamar FirebaseVisionImage.fromMediaImage() :

      Java

      private class YourAnalyzer implements ImageAnalysis.Analyzer {
      
          private int degreesToFirebaseRotation(int degrees) {
              switch (degrees) {
                  case 0:
                      return FirebaseVisionImageMetadata.ROTATION_0;
                  case 90:
                      return FirebaseVisionImageMetadata.ROTATION_90;
                  case 180:
                      return FirebaseVisionImageMetadata.ROTATION_180;
                  case 270:
                      return FirebaseVisionImageMetadata.ROTATION_270;
                  default:
                      throw new IllegalArgumentException(
                              "Rotation must be 0, 90, 180, or 270.");
              }
          }
      
          @Override
          public void analyze(ImageProxy imageProxy, int degrees) {
              if (imageProxy == null || imageProxy.getImage() == null) {
                  return;
              }
              Image mediaImage = imageProxy.getImage();
              int rotation = degreesToFirebaseRotation(degrees);
              FirebaseVisionImage image =
                      FirebaseVisionImage.fromMediaImage(mediaImage, rotation);
              // Pass image to an ML Kit Vision API
              // ...
          }
      }
      

      Kotlin+KTX

      private class YourImageAnalyzer : ImageAnalysis.Analyzer {
          private fun degreesToFirebaseRotation(degrees: Int): Int = when(degrees) {
              0 -> FirebaseVisionImageMetadata.ROTATION_0
              90 -> FirebaseVisionImageMetadata.ROTATION_90
              180 -> FirebaseVisionImageMetadata.ROTATION_180
              270 -> FirebaseVisionImageMetadata.ROTATION_270
              else -> throw Exception("Rotation must be 0, 90, 180, or 270.")
          }
      
          override fun analyze(imageProxy: ImageProxy?, degrees: Int) {
              val mediaImage = imageProxy?.image
              val imageRotation = degreesToFirebaseRotation(degrees)
              if (mediaImage != null) {
                  val image = FirebaseVisionImage.fromMediaImage(mediaImage, imageRotation)
                  // Pass image to an ML Kit Vision API
                  // ...
              }
          }
      }
      

      Si no utiliza una biblioteca de cámaras que le proporcione la rotación de la imagen, puede calcularla a partir de la rotación del dispositivo y la orientación del sensor de la cámara en el dispositivo:

      Java

      private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
      static {
          ORIENTATIONS.append(Surface.ROTATION_0, 90);
          ORIENTATIONS.append(Surface.ROTATION_90, 0);
          ORIENTATIONS.append(Surface.ROTATION_180, 270);
          ORIENTATIONS.append(Surface.ROTATION_270, 180);
      }
      
      /**
       * Get the angle by which an image must be rotated given the device's current
       * orientation.
       */
      @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
      private int getRotationCompensation(String cameraId, Activity activity, Context context)
              throws CameraAccessException {
          // Get the device's current rotation relative to its "native" orientation.
          // Then, from the ORIENTATIONS table, look up the angle the image must be
          // rotated to compensate for the device's rotation.
          int deviceRotation = activity.getWindowManager().getDefaultDisplay().getRotation();
          int rotationCompensation = ORIENTATIONS.get(deviceRotation);
      
          // On most devices, the sensor orientation is 90 degrees, but for some
          // devices it is 270 degrees. For devices with a sensor orientation of
          // 270, rotate the image an additional 180 ((270 + 270) % 360) degrees.
          CameraManager cameraManager = (CameraManager) context.getSystemService(CAMERA_SERVICE);
          int sensorOrientation = cameraManager
                  .getCameraCharacteristics(cameraId)
                  .get(CameraCharacteristics.SENSOR_ORIENTATION);
          rotationCompensation = (rotationCompensation + sensorOrientation + 270) % 360;
      
          // Return the corresponding FirebaseVisionImageMetadata rotation value.
          int result;
          switch (rotationCompensation) {
              case 0:
                  result = FirebaseVisionImageMetadata.ROTATION_0;
                  break;
              case 90:
                  result = FirebaseVisionImageMetadata.ROTATION_90;
                  break;
              case 180:
                  result = FirebaseVisionImageMetadata.ROTATION_180;
                  break;
              case 270:
                  result = FirebaseVisionImageMetadata.ROTATION_270;
                  break;
              default:
                  result = FirebaseVisionImageMetadata.ROTATION_0;
                  Log.e(TAG, "Bad rotation value: " + rotationCompensation);
          }
          return result;
      }

      Kotlin+KTX

      private val ORIENTATIONS = SparseIntArray()
      
      init {
          ORIENTATIONS.append(Surface.ROTATION_0, 90)
          ORIENTATIONS.append(Surface.ROTATION_90, 0)
          ORIENTATIONS.append(Surface.ROTATION_180, 270)
          ORIENTATIONS.append(Surface.ROTATION_270, 180)
      }
      /**
       * Get the angle by which an image must be rotated given the device's current
       * orientation.
       */
      @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
      @Throws(CameraAccessException::class)
      private fun getRotationCompensation(cameraId: String, activity: Activity, context: Context): Int {
          // Get the device's current rotation relative to its "native" orientation.
          // Then, from the ORIENTATIONS table, look up the angle the image must be
          // rotated to compensate for the device's rotation.
          val deviceRotation = activity.windowManager.defaultDisplay.rotation
          var rotationCompensation = ORIENTATIONS.get(deviceRotation)
      
          // On most devices, the sensor orientation is 90 degrees, but for some
          // devices it is 270 degrees. For devices with a sensor orientation of
          // 270, rotate the image an additional 180 ((270 + 270) % 360) degrees.
          val cameraManager = context.getSystemService(CAMERA_SERVICE) as CameraManager
          val sensorOrientation = cameraManager
                  .getCameraCharacteristics(cameraId)
                  .get(CameraCharacteristics.SENSOR_ORIENTATION)!!
          rotationCompensation = (rotationCompensation + sensorOrientation + 270) % 360
      
          // Return the corresponding FirebaseVisionImageMetadata rotation value.
          val result: Int
          when (rotationCompensation) {
              0 -> result = FirebaseVisionImageMetadata.ROTATION_0
              90 -> result = FirebaseVisionImageMetadata.ROTATION_90
              180 -> result = FirebaseVisionImageMetadata.ROTATION_180
              270 -> result = FirebaseVisionImageMetadata.ROTATION_270
              else -> {
                  result = FirebaseVisionImageMetadata.ROTATION_0
                  Log.e(TAG, "Bad rotation value: $rotationCompensation")
              }
          }
          return result
      }

      Luego, pasa el objeto media.Image y el valor de rotación a FirebaseVisionImage.fromMediaImage() :

      Java

      FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation);

      Kotlin+KTX

      val image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation)
    • Para crear un objeto FirebaseVisionImage a partir de un URI de archivo, pase el contexto de la aplicación y el URI del archivo a FirebaseVisionImage.fromFilePath() . Esto es útil cuando usas un intent ACTION_GET_CONTENT para pedirle al usuario que seleccione una imagen de su aplicación de galería.

      Java

      FirebaseVisionImage image;
      try {
          image = FirebaseVisionImage.fromFilePath(context, uri);
      } catch (IOException e) {
          e.printStackTrace();
      }

      Kotlin+KTX

      val image: FirebaseVisionImage
      try {
          image = FirebaseVisionImage.fromFilePath(context, uri)
      } catch (e: IOException) {
          e.printStackTrace()
      }
    • Para crear un objeto FirebaseVisionImage a partir de un ByteBuffer o una matriz de bytes, primero calcule la rotación de la imagen como se describe anteriormente para la entrada media.Image .

      Luego, crea un objeto FirebaseVisionImageMetadata que contenga la altura, el ancho, el formato de codificación de color y la rotación de la imagen:

      Java

      FirebaseVisionImageMetadata metadata = new FirebaseVisionImageMetadata.Builder()
              .setWidth(480)   // 480x360 is typically sufficient for
              .setHeight(360)  // image recognition
              .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21)
              .setRotation(rotation)
              .build();

      Kotlin+KTX

      val metadata = FirebaseVisionImageMetadata.Builder()
              .setWidth(480) // 480x360 is typically sufficient for
              .setHeight(360) // image recognition
              .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21)
              .setRotation(rotation)
              .build()

      Utilice el búfer o matriz y el objeto de metadatos para crear un objeto FirebaseVisionImage :

      Java

      FirebaseVisionImage image = FirebaseVisionImage.fromByteBuffer(buffer, metadata);
      // Or: FirebaseVisionImage image = FirebaseVisionImage.fromByteArray(byteArray, metadata);

      Kotlin+KTX

      val image = FirebaseVisionImage.fromByteBuffer(buffer, metadata)
      // Or: val image = FirebaseVisionImage.fromByteArray(byteArray, metadata)
    • Para crear un objeto FirebaseVisionImage a partir de un objeto Bitmap :

      Java

      FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);

      Kotlin+KTX

      val image = FirebaseVisionImage.fromBitmap(bitmap)
      La imagen representada por el objeto Bitmap debe estar en posición vertical, sin necesidad de rotación adicional.

  2. Obtenga una instancia de FirebaseVisionDocumentTextRecognizer :

    Java

    FirebaseVisionDocumentTextRecognizer detector = FirebaseVision.getInstance()
            .getCloudDocumentTextRecognizer();
    // Or, to provide language hints to assist with language detection:
    // See https://cloud.google.com/vision/docs/languages for supported languages
    FirebaseVisionCloudDocumentRecognizerOptions options =
            new FirebaseVisionCloudDocumentRecognizerOptions.Builder()
                    .setLanguageHints(Arrays.asList("en", "hi"))
                    .build();
    FirebaseVisionDocumentTextRecognizer detector = FirebaseVision.getInstance()
            .getCloudDocumentTextRecognizer(options);

    Kotlin+KTX

    val detector = FirebaseVision.getInstance()
            .cloudDocumentTextRecognizer
    // Or, to provide language hints to assist with language detection:
    // See https://cloud.google.com/vision/docs/languages for supported languages
    val options = FirebaseVisionCloudDocumentRecognizerOptions.Builder()
            .setLanguageHints(listOf("en", "hi"))
            .build()
    val detector = FirebaseVision.getInstance()
            .getCloudDocumentTextRecognizer(options)

  3. Finalmente, pasa la imagen al método processImage :

    Java

    detector.processImage(myImage)
            .addOnSuccessListener(new OnSuccessListener<FirebaseVisionDocumentText>() {
                @Override
                public void onSuccess(FirebaseVisionDocumentText result) {
                    // Task completed successfully
                    // ...
                }
            })
            .addOnFailureListener(new OnFailureListener() {
                @Override
                public void onFailure(@NonNull Exception e) {
                    // Task failed with an exception
                    // ...
                }
            });

    Kotlin+KTX

    detector.processImage(myImage)
            .addOnSuccessListener { firebaseVisionDocumentText ->
                // Task completed successfully
                // ...
            }
            .addOnFailureListener { e ->
                // Task failed with an exception
                // ...
            }

2. Extraer texto de bloques de texto reconocido

Si la operación de reconocimiento de texto tiene éxito, devolverá un objeto FirebaseVisionDocumentText . Un objeto FirebaseVisionDocumentText contiene el texto completo reconocido en la imagen y una jerarquía de objetos que reflejan la estructura del documento reconocido:

Para cada objeto Block , Paragraph , Word y Symbol , puede obtener el texto reconocido en la región y las coordenadas delimitadoras de la región.

Por ejemplo:

Java

String resultText = result.getText();
for (FirebaseVisionDocumentText.Block block: result.getBlocks()) {
    String blockText = block.getText();
    Float blockConfidence = block.getConfidence();
    List<RecognizedLanguage> blockRecognizedLanguages = block.getRecognizedLanguages();
    Rect blockFrame = block.getBoundingBox();
    for (FirebaseVisionDocumentText.Paragraph paragraph: block.getParagraphs()) {
        String paragraphText = paragraph.getText();
        Float paragraphConfidence = paragraph.getConfidence();
        List<RecognizedLanguage> paragraphRecognizedLanguages = paragraph.getRecognizedLanguages();
        Rect paragraphFrame = paragraph.getBoundingBox();
        for (FirebaseVisionDocumentText.Word word: paragraph.getWords()) {
            String wordText = word.getText();
            Float wordConfidence = word.getConfidence();
            List<RecognizedLanguage> wordRecognizedLanguages = word.getRecognizedLanguages();
            Rect wordFrame = word.getBoundingBox();
            for (FirebaseVisionDocumentText.Symbol symbol: word.getSymbols()) {
                String symbolText = symbol.getText();
                Float symbolConfidence = symbol.getConfidence();
                List<RecognizedLanguage> symbolRecognizedLanguages = symbol.getRecognizedLanguages();
                Rect symbolFrame = symbol.getBoundingBox();
            }
        }
    }
}

Kotlin+KTX

val resultText = result.text
for (block in result.blocks) {
    val blockText = block.text
    val blockConfidence = block.confidence
    val blockRecognizedLanguages = block.recognizedLanguages
    val blockFrame = block.boundingBox
    for (paragraph in block.paragraphs) {
        val paragraphText = paragraph.text
        val paragraphConfidence = paragraph.confidence
        val paragraphRecognizedLanguages = paragraph.recognizedLanguages
        val paragraphFrame = paragraph.boundingBox
        for (word in paragraph.words) {
            val wordText = word.text
            val wordConfidence = word.confidence
            val wordRecognizedLanguages = word.recognizedLanguages
            val wordFrame = word.boundingBox
            for (symbol in word.symbols) {
                val symbolText = symbol.text
                val symbolConfidence = symbol.confidence
                val symbolRecognizedLanguages = symbol.recognizedLanguages
                val symbolFrame = symbol.boundingBox
            }
        }
    }
}

Próximos pasos