Puoi utilizzare ML Kit per riconoscere il testo nelle immagini. ML Kit dispone sia di un'API per uso generico adatta per riconoscere il testo nelle immagini, ad esempio il testo di un segnale stradale, sia di un'API ottimizzata per riconoscere il testo dei documenti. L'API per uso generico dispone di modelli sia on-device che basati su cloud. Il riconoscimento del testo dei documenti è disponibile solo come modello basato su cloud. Consulta le panoramica per un confronto modelli cloud e on-device.
Prima di iniziare
- Se non l'hai già fatto, aggiungi Firebase al tuo progetto Android.
- Aggiungi le dipendenze per le librerie Android di ML Kit al file Gradle
(a livello di app) del modulo (di solito
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' }
-
Facoltativo, ma consigliato: se utilizzi l'API on-device, configura la tua app in modo che scarichi automaticamente il modello di ML sul dispositivo dopo l'installazione dall'app Play Store.
Per farlo, aggiungi la seguente dichiarazione al file
AndroidManifest.xml
della tua 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 non attivi i download dei modelli in fase di installazione, il modello verrà scaricato la prima volta che esegui il rilevatore sul dispositivo. Le tue richieste prima del completamento del download non produrranno risultati. -
Se vuoi utilizzare il modello basato su cloud e non hai già abilitato le API basate su cloud per il tuo progetto, fallo ora:
- Apri il ML Kit. API della console Firebase.
-
Se non hai già eseguito l'upgrade del progetto a un piano tariffario Blaze, fai clic su Per farlo, esegui l'upgrade. Ti verrà chiesto di eseguire l'upgrade solo se non è incluso nel piano Blaze.)
Solo i progetti a livello di Blaze possono utilizzare le API basate su cloud.
- Se le API basate su cloud non sono già abilitate, fai clic su Abilita API basate su cloud.
Se vuoi utilizzare solo il modello on-device, puoi saltare questo passaggio.
Ora puoi iniziare a riconoscere il testo nelle immagini.
Linee guida per l'immagine di input
-
Affinché ML Kit riconosca accuratamente il testo, le immagini di input devono contenere di testo rappresentato da un numero sufficiente di dati di pixel. Idealmente, per il testo latino ogni carattere deve essere di almeno 16 x 16 pixel. Per il testo in cinese, giapponese e coreano (supportato solo dalle API basate su cloud), ogni carattere deve avere dimensioni di 24 x 24 pixel. Per tutte le lingue, in genere non c'è maggiore di 24 x 24 pixel.
Ad esempio, un'immagine di 640 x 480 potrebbe essere adatta per la scansione di un biglietto da visita che occupa l'intera larghezza dell'immagine. Per eseguire la scansione di un documento stampato su carta in formato lettera, potrebbe essere necessaria un'immagine di 720 x 1280 pixel.
-
Una messa a fuoco scadente dell'immagine può influire sulla precisione del riconoscimento del testo. Se non ottieni risultati accettabili, prova a chiedere all'utente di acquisire di nuovo l'immagine.
-
Se riconosci il testo in un'applicazione in tempo reale, potresti anche prendere in considerazione le dimensioni complessive delle immagini di input. Le immagini più piccole possono essere elaborate più velocemente, quindi per ridurre la latenza, acquisisci le immagini a risoluzioni inferiori (tenendo presente i requisiti di accuratezza sopra indicati) e assicurati che il testo occupi il maggior spazio possibile dell'immagine. Vedi anche Suggerimenti per migliorare il rendimento in tempo reale.
Riconosce il testo nelle immagini
Per riconoscere il testo in un'immagine utilizzando un modello on-device o basato su cloud, esegui il riconoscimento del testo come descritto di seguito.
1. Esegui il riconoscimento del testo
Per riconoscere il testo in un'immagine, crea un oggettoFirebaseVisionImage
da un array di byte Bitmap
, media.Image
, ByteBuffer
o da un file sul dispositivo. Quindi, passa l'oggetto FirebaseVisionImage
Metodo processImage
di FirebaseVisionTextRecognizer
.
Crea un oggetto
FirebaseVisionImage
dalla tua immagine.-
Per creare un oggetto
FirebaseVisionImage
da unmedia.Image
, ad esempio quando acquisisci un'immagine da un fotocamera del dispositivo, passa l'oggettomedia.Image
e l'oggetto rotazione inFirebaseVisionImage.fromMediaImage()
.Se utilizzi la libreria CameraX, le classi
OnImageCapturedListener
eImageAnalysis.Analyzer
calcolano il valore di rotazione per te, quindi devi solo convertire la rotazione in una delle costantiROTATION_
di ML Kit prima di chiamareFirebaseVisionImage.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 non utilizzi una raccolta di videocamere che ti fornisce la rotazione dell'immagine, può calcolarla in base alla rotazione del dispositivo e all'orientamento della fotocamera nel 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 }
Quindi, passa l'oggetto
media.Image
e valore di rotazione aFirebaseVisionImage.fromMediaImage()
:Java
FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation);
Kotlin+KTX
val image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation)
- Per creare un oggetto
FirebaseVisionImage
da un URI del file, passa il contesto dell'app e l'URI del fileFirebaseVisionImage.fromFilePath()
. È utile quando utilizza un intentACTION_GET_CONTENT
per chiedere all'utente di selezionare un'immagine dall'app Galleria.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() }
- Per creare un oggetto
FirebaseVisionImage
da unByteBuffer
o un array di byte, calcola prima l'immagine rotazione come descritto sopra per l'inputmedia.Image
.Quindi, crea un oggetto
FirebaseVisionImageMetadata
che contiene l'altezza, la larghezza, il formato di codifica del colore, e rotazione: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()
Utilizza il buffer o l'array e l'oggetto metadati per creare un Oggetto
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)
- Per creare un oggetto
FirebaseVisionImage
da un oggettoBitmap
:Java
FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);
Kotlin+KTX
val image = FirebaseVisionImage.fromBitmap(bitmap)
Bitmap
deve essere in verticale, senza alcuna rotazione aggiuntiva.
-
Recupera un'istanza di
FirebaseVisionTextRecognizer
.Per utilizzare il modello on-device:
Java
FirebaseVisionTextRecognizer detector = FirebaseVision.getInstance() .getOnDeviceTextRecognizer();
Kotlin+KTX
val detector = FirebaseVision.getInstance() .onDeviceTextRecognizer
Per utilizzare il modello basato su cloud:
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()
Infine, passa l'immagine al metodo
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. Estrarre il testo da blocchi di testo riconosciuto
Se l'operazione di riconoscimento del testo ha esito positivo, un oggettoFirebaseVisionText
verrà passato all'ascoltatore
positivo. Un oggetto FirebaseVisionText
contiene il testo completo riconosciuto nell'immagine e zero o più oggetti TextBlock
.
Ciascun TextBlock
rappresenta un blocco di testo rettangolare, che contiene zero o
più oggetti Line
. Ogni oggetto Line
contiene zero o più
Element
oggetti, che rappresentano parole e parole
entità (date, numeri e così via).
Per ogni oggetto TextBlock
, Line
e Element
, puoi ottenere il testo riconosciuto nella regione e le coordinate di confine della regione.
Ad esempio:
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 } } }
Suggerimenti per migliorare il rendimento in tempo reale
Se vuoi utilizzare il modello sul dispositivo per riconoscere il testo in tempo reale segui queste linee guida per ottenere le migliori frequenze fotogrammi:
- Regola le chiamate al riconoscitore di testo. Se un nuovo fotogramma disponibili mentre è in esecuzione il riconoscimento del testo, rilascia il frame.
- Se utilizzi l'output del riconoscimento del testo per sovrapporre gli elementi grafici l'immagine di input, occorre prima ottenere il risultato da ML Kit, quindi eseguire il rendering dell'immagine e la sovrapposizione in un solo passaggio. In questo modo, esegui il rendering sulla superficie di visualizzazione solo una volta per ogni frame di input.
-
Se utilizzi l'API Camera2, acquisisci le immagini in Formato
ImageFormat.YUV_420_888
.Se usi l'API Camera precedente, acquisisci le immagini in Formato
ImageFormat.NV21
. - Valuta la possibilità di acquisire le immagini a una risoluzione inferiore. Tuttavia, tieni presente requisiti per le dimensioni immagine di questa API.
Passaggi successivi
- Prima di eseguire il deployment in produzione di un'app che utilizza un'API Cloud, devi eseguire alcuni passaggi aggiuntivi per prevenire e attenuare l'effetto dell'accesso non autorizzato all'API.
Riconoscere il testo nelle immagini dei documenti
Per riconoscere il testo di un documento, configura ed esegui l'interfaccia come descritto di seguito.
L'API di riconoscimento del testo dei documenti, descritta di seguito, fornisce un'interfaccia che
è pensato per essere più comodo per lavorare con le immagini di documenti. Tuttavia, se preferisci l'interfaccia fornita dall'API FirebaseVisionTextRecognizer
, puoi utilizzarla per eseguire la scansione dei documenti configurando il riconoscimento del testo cloud in modo da utilizzare il modello di testo denso.
Per utilizzare l'API di riconoscimento del testo dei documenti:
1. Esegui il riconoscimento del testo
Per riconoscere il testo in un'immagine, crea un oggettoFirebaseVisionImage
da una
Bitmap
, media.Image
, ByteBuffer
, array di byte o un file sul dispositivo.
Quindi, passa l'oggetto FirebaseVisionImage
al metodo processImage
di FirebaseVisionDocumentTextRecognizer
.
Crea un oggetto
FirebaseVisionImage
dalla tua immagine.-
Per creare un oggetto
FirebaseVisionImage
da un oggettomedia.Image
, ad esempio quando acquisisci un'immagine dalla fotocamera di un dispositivo, passa l'oggettomedia.Image
e la rotazione dell'immagine aFirebaseVisionImage.fromMediaImage()
.Se utilizzi nella libreria di CameraX,
OnImageCapturedListener
eImageAnalysis.Analyzer
classi calcolano il valore di rotazione quindi devi solo convertire la rotazione in una CostantiROTATION_
prima di chiamareFirebaseVisionImage.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 non utilizzi una libreria della fotocamera che ti fornisca la rotazione dell'immagine, puoi calcolarla dalla rotazione del dispositivo e dall'orientamento del sensore della fotocamera al suo interno:
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 }
Quindi, passa l'oggetto
media.Image
e valore di rotazione aFirebaseVisionImage.fromMediaImage()
:Java
FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation);
Kotlin+KTX
val image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation)
- Per creare un oggetto
FirebaseVisionImage
da un URI del file, passa il contesto dell'app e l'URI del fileFirebaseVisionImage.fromFilePath()
. È utile quando utilizza un intentACTION_GET_CONTENT
per chiedere all'utente di selezionare un'immagine dall'app Galleria.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() }
- Per creare un oggetto
FirebaseVisionImage
da unByteBuffer
o un array di byte, calcola prima l'immagine rotazione come descritto sopra per l'inputmedia.Image
.Quindi, crea un oggetto
FirebaseVisionImageMetadata
che contiene l'altezza, la larghezza, il formato di codifica del colore, e rotazione: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()
Utilizza il buffer o l'array e l'oggetto metadati per creare un Oggetto
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)
- Per creare un oggetto
FirebaseVisionImage
da un oggettoBitmap
:Java
FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);
Kotlin+KTX
val image = FirebaseVisionImage.fromBitmap(bitmap)
Bitmap
deve in posizione verticale, senza la necessità di ulteriori rotazioni.
-
Ottieni un'istanza di
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)
Infine, passa l'immagine al metodo
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. Estrarre il testo da blocchi di testo riconosciuto
Se il riconoscimento del testo viene eseguito correttamente, viene restituito
FirebaseVisionDocumentText
. Un oggetto FirebaseVisionDocumentText
contiene il testo completo riconosciuto nell'immagine e una gerarchia di oggetti che riflettono la struttura del documento riconosciuto:
FirebaseVisionDocumentText.Block
FirebaseVisionDocumentText.Paragraph
FirebaseVisionDocumentText.Word
FirebaseVisionDocumentText.Symbol
Per ogni oggetto Block
, Paragraph
, Word
e Symbol
, puoi ottenere il testo riconosciuto nella regione e le coordinate di confine della regione.
Ad esempio:
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 } } } }
Passaggi successivi
- Prima di eseguire il deployment in produzione di un'app che utilizza un'API Cloud, devi eseguire alcuni passaggi aggiuntivi per prevenire e attenuare l'effetto dell'accesso non autorizzato all'API.