É possível usar o kit de ML para reconhecimento de texto em imagens. Esse kit tem uma API de uso geral que reconhece texto em imagens, como o texto de uma placa de rua, e uma API otimizada para reconhecer texto de documentos. A API de uso geral tem modelos baseados no dispositivo e na nuvem. O reconhecimento de texto em documentos está disponível apenas como modelo baseado na nuvem. Consulte a visão geral para uma comparação entre esses dois tipos de modelos.
Antes de começar
- Adicione o Firebase ao seu projeto para Android, caso ainda não tenha feito isso.
- Adicione as dependências das bibliotecas do Android do Kit de ML ao arquivo
Gradle do módulo (nível do aplicativo), que geralmente é
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, mas recomendado: se você usa a API no dispositivo, configure seu app para fazer o download automaticamente do modelo de ML para o dispositivo depois que seu app for instalado da Play Store:
Para fazer isso, adicione a seguinte declaração ao arquivo
AndroidManifest.xml
do app:<application ...> ... <meta-data android:name="com.google.firebase.ml.vision.DEPENDENCIES" android:value="ocr" /> <!-- To use multiple models: android:value="ocr,model2,model3" --> </application>
Se você não ativar os downloads do modelo de tempo de instalação, ele será transferido na primeira vez em que você executar o detector. As solicitações feitas antes da conclusão do download não produzirão resultados. -
Se você quiser usar o modelo baseado em nuvem e ainda não tiver ativado as APIs baseadas em nuvem para seu projeto, faça isso agora:
- Abra a página APIs do Kit de ML no Console do Firebase.
-
Se você ainda não fez o upgrade de seu projeto para um plano de preços do Blaze, clique em Fazer upgrade para fazer isso. Você só receberá uma mensagem para fazer upgrade se o projeto não estiver no plano Blaze.
Apenas projetos no nível Blaze podem usar APIs baseadas na nuvem.
- Caso as APIs baseadas na nuvem ainda não estejam ativadas, clique em Ativar APIs baseadas na nuvem.
Se você quiser usar apenas o modelo no dispositivo, pule esta etapa.
Agora você já pode reconhecer texto em imagens.
Diretrizes de imagem de entrada
-
Para que o Kit de ML reconheça o texto com precisão, as imagens de entrada devem conter texto representado por dados de pixel suficientes. Idealmente, para texto em latim, cada caractere deve ter pelo menos 16x16 pixels. Para texto em chinês, japonês e coreano (compatíveis apenas com APIs baseadas em nuvem), cada caractere deve ter 24x24 pixels. Para todos os idiomas, geralmente não há melhorias de precisão em usar caracteres maiores que 24x24 pixels.
Por exemplo, uma imagem de 640x480 pixels pode funcionar para digitalizar um cartão de visita que ocupe toda a largura da imagem. Para digitalizar um documento impresso em papel de tamanho carta, talvez seja necessária uma imagem de 720x1280 pixels.
-
O foco inadequado da imagem pode prejudicar a precisão do reconhecimento de texto. Se você não está conseguindo resultados aceitáveis, peça para o usuário recapturar a imagem.
-
Se você estiver fazendo reconhecimento de texto em um aplicativo em tempo real, considere as dimensões gerais das imagens de entrada. Já que imagens menores podem ser processadas mais rapidamente, para reduzir a latência, capture imagens em resoluções mais baixas (tendo em mente os requisitos de precisão acima) e certifique-se de que o texto ocupe o máximo possível da imagem. Consulte também Dicas para melhorar o desempenho em tempo real.
Reconhecer texto em imagens
Para reconhecer texto em imagens usando o modelo baseado no dispositivo ou na nuvem, execute o reconhecedor de texto conforme descrito nas etapas a seguir.
1. Executar o reconhecedor de texto
Para reconhecer texto em uma imagem, crie um objetoFirebaseVisionImage
a partir de um Bitmap
, media.Image
, ByteBuffer
, matriz de bytes ou um arquivo no dispositivo. Em seguida, transmita o objeto FirebaseVisionImage
para o método processImage
do FirebaseVisionTextRecognizer
.
Crie um objeto
FirebaseVisionImage
usando sua imagem.-
Para criar um objeto
FirebaseVisionImage
a partir de um objetomedia.Image
, como ao capturar uma imagem da câmera de um dispositivo, transmita o objetomedia.Image
e a rotação da imagem paraFirebaseVisionImage.fromMediaImage()
.Se você usar a biblioteca CameraX, as classes
OnImageCapturedListener
eImageAnalysis.Analyzer
calcularão o valor de rotação para você. Basta converter a rotação em uma das constantesROTATION_
do Kit de ML antes de chamarFirebaseVisionImage.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 // ... } } }
Se você não usar uma biblioteca de câmera que ofereça a rotação da imagem, será possível calculá-la usando a rotação do dispositivo e a orientação do sensor da câmera:
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 }
Em seguida, transmita o objeto
media.Image
e o valor de rotação paraFirebaseVisionImage.fromMediaImage()
:Java
FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation);
Kotlin+KTX
val image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation)
- Para criar um objeto
FirebaseVisionImage
com base no URI de um arquivo, transmita o contexto do aplicativo e o URI do arquivo paraFirebaseVisionImage.fromFilePath()
. Isso é útil ao usar uma intentACTION_GET_CONTENT
para solicitar que o usuário selecione uma imagem do aplicativo de galeria dele.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 criar um objeto
FirebaseVisionImage
com base em umByteBuffer
ou uma matriz de bytes, primeiro calcule a rotação da imagem conforme descrito acima para a entradamedia.Image
.Em seguida, crie um objeto
FirebaseVisionImageMetadata
que contenha a altura, a largura, o formato de codificação de cores e a rotação da imagem: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()
Use o buffer ou a matriz e o objeto de metadados para criar um 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 criar um objeto
FirebaseVisionImage
com base em um objetoBitmap
:Java
FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);
Kotlin+KTX
val image = FirebaseVisionImage.fromBitmap(bitmap)
Bitmap
precisa estar na posição vertical, sem necessidade de girá-la novamente.
-
Receba uma instância de
FirebaseVisionTextRecognizer
.Para usar o modelo no dispositivo:
Java
FirebaseVisionTextRecognizer detector = FirebaseVision.getInstance() .getOnDeviceTextRecognizer();
Kotlin+KTX
val detector = FirebaseVision.getInstance() .onDeviceTextRecognizer
Para usar o modelo baseado em nuvem:
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()
Por fim, transmita a imagem para o 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. Extrair texto de blocos de texto reconhecido
Se a operação de reconhecimento de texto for bem-sucedida, um objetoFirebaseVisionText
será transmitido para o listener de êxito. Um objeto FirebaseVisionText
contém o texto completo reconhecido na imagem e zero ou mais objetos TextBlock
.
Cada TextBlock
representa um bloco de texto retangular, que contém zero ou mais objetos Line
. Cada objeto Line
contém zero ou mais objetos Element
, que representam palavras e entidades semelhantes (datas, números etc.).
Para cada objeto TextBlock
, Line
e Element
, é possível receber o texto reconhecido na região e as coordenadas delimitadoras da região.
Por exemplo:
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 } } }
Dicas para melhorar o desempenho em tempo real
Se você quiser usar o modelo no dispositivo para reconhecer texto em um aplicativo em tempo real, siga estas diretrizes para conseguir os melhores frame rates:
- Limite as chamadas ao reconhecedor de texto. Se um novo frame de vídeo se tornar disponível durante a execução do reconhecedor de texto, descarte esse frame.
- Se você estiver usando a saída do reconhecedor de texto para sobrepor elementos gráficos na imagem de entrada, primeiro acesse o resultado do Kit de ML e, em seguida, renderize a imagem e a sobreposição em uma única etapa. Ao fazer isso, você renderiza a superfície de exibição apenas uma vez para cada frame de entrada.
-
Se você usar a API Camera2, capture imagens no formato
ImageFormat.YUV_420_888
.Se você usar a API Camera mais antiga, capture imagens no formato
ImageFormat.NV21
. - Capture imagens em uma resolução menor. No entanto, lembre-se também dos requisitos de dimensão de imagem da API.
Próximas etapas
- Antes de implantar em produção um aplicativo que usa uma API do Cloud, é preciso seguir mais algumas etapas para evitar ou atenuar o efeito do acesso não autorizado à API.
Reconhecer texto em imagens de documentos
Para reconhecer o texto de um documento, configure e execute o documento baseado na nuvem conforme descrito nas instruções abaixo.
A API de reconhecimento de texto em documentos descrita abaixo tem uma interface desenvolvida para trabalhar com imagens de documentos. No entanto, se você preferir a interface fornecida pela API FirebaseVisionTextRecognizer
, poderá usá-la para verificar documentos configurando o reconhecedor de texto em nuvem para usar o modelo de texto denso.
Para usar a API de reconhecimento de texto em documentos, siga estas etapas:
1. Executar o reconhecedor de texto
Para reconhecer texto em uma imagem, crie um objetoFirebaseVisionImage
a partir de um Bitmap
, media.Image
, ByteBuffer
, matriz de bytes ou um arquivo no dispositivo.
Em seguida, transmita o objeto FirebaseVisionImage
para o método processImage
do FirebaseVisionDocumentTextRecognizer
.
Crie um objeto
FirebaseVisionImage
usando sua imagem.-
Para criar um objeto
FirebaseVisionImage
a partir de um objetomedia.Image
, como ao capturar uma imagem da câmera de um dispositivo, transmita o objetomedia.Image
e a rotação da imagem paraFirebaseVisionImage.fromMediaImage()
.Se você usar a biblioteca CameraX, as classes
OnImageCapturedListener
eImageAnalysis.Analyzer
calcularão o valor de rotação para você. Basta converter a rotação em uma das constantesROTATION_
do Kit de ML antes de chamarFirebaseVisionImage.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 // ... } } }
Se você não usar uma biblioteca de câmera que ofereça a rotação da imagem, será possível calculá-la usando a rotação do dispositivo e a orientação do sensor da câmera:
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 }
Em seguida, transmita o objeto
media.Image
e o valor de rotação paraFirebaseVisionImage.fromMediaImage()
:Java
FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation);
Kotlin+KTX
val image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation)
- Para criar um objeto
FirebaseVisionImage
com base no URI de um arquivo, transmita o contexto do aplicativo e o URI do arquivo paraFirebaseVisionImage.fromFilePath()
. Isso é útil ao usar uma intentACTION_GET_CONTENT
para solicitar que o usuário selecione uma imagem do aplicativo de galeria dele.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 criar um objeto
FirebaseVisionImage
com base em umByteBuffer
ou uma matriz de bytes, primeiro calcule a rotação da imagem conforme descrito acima para a entradamedia.Image
.Em seguida, crie um objeto
FirebaseVisionImageMetadata
que contenha a altura, a largura, o formato de codificação de cores e a rotação da imagem: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()
Use o buffer ou a matriz e o objeto de metadados para criar um 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 criar um objeto
FirebaseVisionImage
com base em um objetoBitmap
:Java
FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);
Kotlin+KTX
val image = FirebaseVisionImage.fromBitmap(bitmap)
Bitmap
precisa estar na posição vertical, sem necessidade de girá-la novamente.
-
Consiga uma instância 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)
Por fim, transmita a imagem para o 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. Extrair texto de blocos de texto reconhecido
Se a operação de reconhecimento de texto for bem-sucedida, ela retornará um objeto FirebaseVisionDocumentText
. Um objeto FirebaseVisionDocumentText
contém o texto completo reconhecido na imagem e uma hierarquia de objetos que refletem a estrutura do documento reconhecido:
FirebaseVisionDocumentText.Block
FirebaseVisionDocumentText.Paragraph
FirebaseVisionDocumentText.Word
FirebaseVisionDocumentText.Symbol
Para cada objeto Block
, Paragraph
, Word
e Symbol
, é possível receber o texto reconhecido na região e as coordenadas delimitadoras da região.
Por exemplo:
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óximas etapas
- Antes de implantar em produção um aplicativo que usa uma API do Cloud, é preciso seguir mais algumas etapas para evitar ou atenuar o efeito do acesso não autorizado à API.