Puoi utilizzare ML Kit per etichettare gli oggetti riconosciuti in un'immagine utilizzando un modello on-device o un modello cloud. Consulta le panoramica per saperne di più sui vantaggi delle ciascun approccio.
Prima di iniziare
- Se non l'hai già fatto, aggiungi Firebase al tuo progetto Android.
- Aggiungi al modulo le dipendenze per le librerie Android di ML Kit
file Gradle (a livello di app) (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' implementation 'com.google.firebase:firebase-ml-vision-image-label-model:20.0.1' }
-
Facoltativo ma consigliato: se utilizzi l'API on-device, configura le
per scaricare automaticamente il modello ML sul dispositivo dopo che
dal Play Store.
Per farlo, aggiungi la seguente dichiarazione alla sezione File
AndroidManifest.xml
: Se non abiliti il download del modello al momento dell'installazione, il modello verrà scaricato la prima volta che esegui il rilevatore sul dispositivo. Le richieste inviate prima del completamento del download non produrranno risultati.<application ...> ... <meta-data android:name="com.google.firebase.ml.vision.DEPENDENCIES" android:value="label" /> <!-- To use multiple models: android:value="label,model2,model3" --> </application>
-
Se vuoi utilizzare il modello basato su cloud e non hai ancora attivato le API basate su cloud per il tuo progetto, fallo ora:
- Apri il ML Kit. API della console Firebase.
-
Se non hai ancora eseguito l'upgrade del progetto a un piano tariffario Blaze, fai clic su Esegui l'upgrade per farlo. Ti verrà chiesto di eseguire l'upgrade solo se il progetto non è nel piano Blaze.
Solo i progetti a livello 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 è tutto pronto per etichettare le immagini utilizzando un modello on-device o un modello basato su cloud.
1. Prepara l'immagine di input
Crea un oggettoFirebaseVisionImage
dalla tua immagine.
Lo strumento di etichettatura delle immagini funziona più velocemente quando usi un Bitmap
o, se usi lo
camera2 dell'API, media.Image
in formato JPEG, consigliate quando
possibile.
-
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 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 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.
2. Configura ed esegui l'etichettatore delle immagini
Per etichettare gli oggetti in un'immagine, passa l'oggettoFirebaseVisionImage
al metodo processImage
di FirebaseVisionImageLabeler
.
Per prima cosa, ottieni un'istanza
FirebaseVisionImageLabeler
Se vuoi utilizzare lo strumento di etichettatura delle immagini sul dispositivo:
Java
FirebaseVisionImageLabeler labeler = FirebaseVision.getInstance() .getOnDeviceImageLabeler(); // Or, to set the minimum confidence required: // FirebaseVisionOnDeviceImageLabelerOptions options = // new FirebaseVisionOnDeviceImageLabelerOptions.Builder() // .setConfidenceThreshold(0.7f) // .build(); // FirebaseVisionImageLabeler labeler = FirebaseVision.getInstance() // .getOnDeviceImageLabeler(options);
Kotlin+KTX
val labeler = FirebaseVision.getInstance().getOnDeviceImageLabeler() // Or, to set the minimum confidence required: // val options = FirebaseVisionOnDeviceImageLabelerOptions.Builder() // .setConfidenceThreshold(0.7f) // .build() // val labeler = FirebaseVision.getInstance().getOnDeviceImageLabeler(options)
Se vuoi utilizzare lo strumento di etichettatura delle immagini sul cloud:
Java
FirebaseVisionImageLabeler labeler = FirebaseVision.getInstance() .getCloudImageLabeler(); // Or, to set the minimum confidence required: // FirebaseVisionCloudImageLabelerOptions options = // new FirebaseVisionCloudImageLabelerOptions.Builder() // .setConfidenceThreshold(0.7f) // .build(); // FirebaseVisionImageLabeler labeler = FirebaseVision.getInstance() // .getCloudImageLabeler(options);
Kotlin+KTX
val labeler = FirebaseVision.getInstance().getCloudImageLabeler() // Or, to set the minimum confidence required: // val options = FirebaseVisionCloudImageLabelerOptions.Builder() // .setConfidenceThreshold(0.7f) // .build() // val labeler = FirebaseVision.getInstance().getCloudImageLabeler(options)
Quindi, passa l'immagine al metodo
processImage()
:Java
labeler.processImage(image) .addOnSuccessListener(new OnSuccessListener<List<FirebaseVisionImageLabel>>() { @Override public void onSuccess(List<FirebaseVisionImageLabel> labels) { // Task completed successfully // ... } }) .addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { // Task failed with an exception // ... } });
Kotlin+KTX
labeler.processImage(image) .addOnSuccessListener { labels -> // Task completed successfully // ... } .addOnFailureListener { e -> // Task failed with an exception // ... }
3. Ricevere informazioni sugli oggetti etichettati
Se l'operazione di etichettatura delle immagini ha esito positivo, viene visualizzato un elencoFirebaseVisionImageLabel
oggetti verranno passati all'account
ascoltatori di successo. Ogni oggetto FirebaseVisionImageLabel
rappresenta qualcosa
etichettata nell'immagine. Per ogni etichetta, puoi visualizzare il relativo testo
descrizione, è
ID entità Knowledge Graph
(se disponibile) e il punteggio di confidenza della corrispondenza. Ad esempio:
Java
for (FirebaseVisionImageLabel label: labels) {
String text = label.getText();
String entityId = label.getEntityId();
float confidence = label.getConfidence();
}
Kotlin+KTX
for (label in labels) {
val text = label.text
val entityId = label.entityId
val confidence = label.confidence
}
Suggerimenti per migliorare il rendimento in tempo reale
Se vuoi etichettare le immagini in un'applicazione in tempo reale, segui questi passaggi: linee guida per ottenere le migliori frequenze fotogrammi:
- Limita le chiamate all'etichettatore delle immagini. Se un nuovo fotogramma disponibili mentre l'etichettatore delle immagini è in esecuzione, rilascia il frame.
- Se stai utilizzando l'output dello strumento di etichettatura delle immagini 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, puoi visualizzare i contenuti 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
.
Passaggi successivi
- Prima di eseguire il deployment in produzione di un'app che utilizza un'API Cloud, devi: alcune misure aggiuntive per prevenire e mitigare dell'accesso non autorizzato all'API.