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 lo has hecho, agrega Firebase a tu proyecto de Android .
- 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'
} - 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: 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.<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 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.
Para reconocer texto en una imagen, cree un objetoFirebaseVisionImage
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
.Crea un objeto
FirebaseVisionImage
a partir de tu imagen.Para crear un objeto
FirebaseVisionImage
a partir de un objetomedia.Image
, como al capturar una imagen desde la cámara de un dispositivo, pase el objetomedia.Image
y la rotación de la imagen aFirebaseVisionImage.fromMediaImage()
.Si usa la biblioteca CameraX , las clases
OnImageCapturedListener
eImageAnalysis.Analyzer
calculan el valor de rotación por usted, por lo que solo necesita convertir la rotación a una de las constantesROTATION_
del kit ML antes de llamarFirebaseVisionImage.fromMediaImage()
: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
// ...
}
}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:
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;
}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 aFirebaseVisionImage.fromMediaImage()
:FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation);
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 aFirebaseVisionImage.fromFilePath()
. Esto es útil cuando usas un intentACTION_GET_CONTENT
para pedirle al usuario que seleccione una imagen de su aplicación de galería.FirebaseVisionImage image;
try {
image = FirebaseVisionImage.fromFilePath(context, uri);
} catch (IOException e) {
e.printStackTrace();
}val image: FirebaseVisionImage
try {
image = FirebaseVisionImage.fromFilePath(context, uri)
} catch (e: IOException) {
e.printStackTrace()
} - Para crear un objeto
FirebaseVisionImage
a partir de unByteBuffer
o una matriz de bytes, primero calcule la rotación de la imagen como se describe anteriormente para la entradamedia.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:FirebaseVisionImageMetadata metadata = new FirebaseVisionImageMetadata.Builder()
.setWidth(480) // 480x360 is typically sufficient for
.setHeight(360) // image recognition
.setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21)
.setRotation(rotation)
.build();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
:FirebaseVisionImage image = FirebaseVisionImage.fromByteBuffer(buffer, metadata);
// Or: FirebaseVisionImage image = FirebaseVisionImage.fromByteArray(byteArray, metadata);val image = FirebaseVisionImage.fromByteBuffer(buffer, metadata)
// Or: val image = FirebaseVisionImage.fromByteArray(byteArray, metadata) - Para crear un objeto
FirebaseVisionImage
a partir de un objetoBitmap
: La imagen representada por el objetoFirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);
val image = FirebaseVisionImage.fromBitmap(bitmap)
Bitmap
debe estar en posición vertical, sin necesidad de rotación adicional.
Obtenga una instancia de
FirebaseVisionTextRecognizer
.Para utilizar el modelo en el dispositivo:
FirebaseVisionTextRecognizer detector = FirebaseVision.getInstance()
.getOnDeviceTextRecognizer();val detector = FirebaseVision.getInstance()
.onDeviceTextRecognizerPara utilizar el modelo basado en la nube:
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();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()Finalmente, pasa la imagen al método
processImage
: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
// ...
}
});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 objetoFirebaseVisionText
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:
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();
}
}
}
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
- 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 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 objetoFirebaseVisionImage
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
.Crea un objeto
FirebaseVisionImage
a partir de tu imagen.Para crear un objeto
FirebaseVisionImage
a partir de un objetomedia.Image
, como al capturar una imagen desde la cámara de un dispositivo, pase el objetomedia.Image
y la rotación de la imagen aFirebaseVisionImage.fromMediaImage()
.Si usa la biblioteca CameraX , las clases
OnImageCapturedListener
eImageAnalysis.Analyzer
calculan el valor de rotación por usted, por lo que solo necesita convertir la rotación a una de las constantesROTATION_
del kit ML antes de llamarFirebaseVisionImage.fromMediaImage()
: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
// ...
}
}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:
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;
}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 aFirebaseVisionImage.fromMediaImage()
:FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation);
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 aFirebaseVisionImage.fromFilePath()
. Esto es útil cuando usas un intentACTION_GET_CONTENT
para pedirle al usuario que seleccione una imagen de su aplicación de galería.FirebaseVisionImage image;
try {
image = FirebaseVisionImage.fromFilePath(context, uri);
} catch (IOException e) {
e.printStackTrace();
}val image: FirebaseVisionImage
try {
image = FirebaseVisionImage.fromFilePath(context, uri)
} catch (e: IOException) {
e.printStackTrace()
} - Para crear un objeto
FirebaseVisionImage
a partir de unByteBuffer
o una matriz de bytes, primero calcule la rotación de la imagen como se describe anteriormente para la entradamedia.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:FirebaseVisionImageMetadata metadata = new FirebaseVisionImageMetadata.Builder()
.setWidth(480) // 480x360 is typically sufficient for
.setHeight(360) // image recognition
.setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21)
.setRotation(rotation)
.build();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
:FirebaseVisionImage image = FirebaseVisionImage.fromByteBuffer(buffer, metadata);
// Or: FirebaseVisionImage image = FirebaseVisionImage.fromByteArray(byteArray, metadata);val image = FirebaseVisionImage.fromByteBuffer(buffer, metadata)
// Or: val image = FirebaseVisionImage.fromByteArray(byteArray, metadata) - Para crear un objeto
FirebaseVisionImage
a partir de un objetoBitmap
: La imagen representada por el objetoFirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);
val image = FirebaseVisionImage.fromBitmap(bitmap)
Bitmap
debe estar en posición vertical, sin necesidad de rotación adicional.
Obtenga una instancia de
FirebaseVisionDocumentTextRecognizer
: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);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)Finalmente, pasa la imagen al método
processImage
: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
// ...
}
});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:
-
FirebaseVisionDocumentText.Block
-
FirebaseVisionDocumentText.Paragraph
-
FirebaseVisionDocumentText.Word
-
FirebaseVisionDocumentText.Symbol
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:
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();
}
}
}
}
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
- 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 .