Sie können ML Kit verwenden, um in einem Bild erkannte Objekte zu beschriften, indem Sie entweder ein On-Device-Modell oder ein Cloud-Modell verwenden. Sehen Sie sich die Übersicht an, um mehr über die Vorteile der einzelnen Ansätze zu erfahren.
Bevor Sie beginnen
- Fügen Sie Ihrem Android-Projekt Firebase hinzu, falls Sie dies noch nicht getan haben .
- Fügen Sie die Abhängigkeiten für die ML Kit-Android-Bibliotheken zu Ihrer Modul-Gradle-Datei (auf App-Ebene) hinzu (normalerweise
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' }
- Optional, aber empfohlen : Wenn Sie die API auf dem Gerät verwenden, konfigurieren Sie Ihre App so, dass das ML-Modell automatisch auf das Gerät heruntergeladen wird, nachdem Ihre App aus dem Play Store installiert wurde.
Fügen Sie dazu die folgende Deklaration zur
AndroidManifest.xml
-Datei Ihrer App hinzu:<application ...> ... <meta-data android:name="com.google.firebase.ml.vision.DEPENDENCIES" android:value="label" /> <!-- To use multiple models: android:value="label,model2,model3" --> </application>
Wenn Sie das Herunterladen von Modellen während der Installation nicht aktivieren, wird das Modell heruntergeladen, wenn Sie den Gerätedetektor zum ersten Mal ausführen. Anfragen, die Sie stellen, bevor der Download abgeschlossen ist, führen zu keinen Ergebnissen. Wenn Sie das Cloud-basierte Modell verwenden möchten und die Cloud-basierten APIs für Ihr Projekt noch nicht aktiviert haben, tun Sie dies jetzt:
- Öffnen Sie die Seite ML Kit APIs der Firebase-Konsole.
Wenn Sie Ihr Projekt noch nicht auf einen Blaze-Preisplan aktualisiert haben, klicken Sie dazu auf Upgrade . (Sie werden nur dann zum Upgrade aufgefordert, wenn Ihr Projekt nicht im Blaze-Plan enthalten ist.)
Nur Projekte auf Blaze-Ebene können Cloud-basierte APIs verwenden.
- Wenn Cloud-basierte APIs nicht bereits aktiviert sind, klicken Sie auf Cloud-basierte APIs aktivieren .
Wenn Sie nur das On-Device-Modell verwenden möchten, können Sie diesen Schritt überspringen.
Jetzt können Sie Bilder entweder mit einem Modell auf dem Gerät oder mit einem Cloud-basierten Modell beschriften.
1. Bereiten Sie das Eingabebild vor
Erstellen Sie einFirebaseVisionImage
-Objekt aus Ihrem Bild. Die Bildbeschriftung wird am schnellsten ausgeführt, wenn Sie eine Bitmap
oder, wenn Sie die camera2-API verwenden, ein JPEG-formatiertes media.Image
, die nach Möglichkeit empfohlen werden.Um ein
FirebaseVisionImage
-Objekt aus einemmedia.Image
Objekt zu erstellen, beispielsweise beim Erfassen eines Bildes von der Kamera eines Geräts, übergeben Sie dasmedia.Image
Objekt und die Drehung des Bilds anFirebaseVisionImage.fromMediaImage()
.Wenn Sie die CameraX- Bibliothek verwenden, berechnen die Klassen
OnImageCapturedListener
undImageAnalysis.Analyzer
den Rotationswert für Sie, sodass Sie die Rotation nur in eine derROTATION_
-Konstanten von ML Kit konvertieren müssen, bevor SieFirebaseVisionImage.fromMediaImage()
aufrufen: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 // ... } } }
Wenn Sie keine Kamerabibliothek verwenden, die Ihnen die Drehung des Bildes liefert, können Sie sie aus der Drehung des Geräts und der Ausrichtung des Kamerasensors im Gerät berechnen:
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 }
Übergeben Sie dann das
media.Image
Objekt und den Rotationswert anFirebaseVisionImage.fromMediaImage()
:Java
FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation);
Kotlin+KTX
val image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation)
- Um ein
FirebaseVisionImage
-Objekt aus einem Datei-URI zu erstellen, übergeben Sie den App-Kontext und den Datei-URI anFirebaseVisionImage.fromFilePath()
. Dies ist nützlich, wenn Sie einenACTION_GET_CONTENT
-Intent verwenden, um den Benutzer aufzufordern, ein Bild aus seiner Galerie-App auszuwählen.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() }
- Um ein
FirebaseVisionImage
-Objekt aus einemByteBuffer
oder einem Byte-Array zu erstellen, berechnen Sie zunächst die Bilddrehung wie oben für diemedia.Image
Eingabe beschrieben.Erstellen Sie dann ein
FirebaseVisionImageMetadata
-Objekt, das die Höhe, Breite, das Farbcodierungsformat und die Drehung des Bilds enthält: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()
Verwenden Sie den Puffer oder das Array und das Metadatenobjekt, um ein
FirebaseVisionImage
-Objekt zu erstellen: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)
- So erstellen Sie ein
FirebaseVisionImage
Objekt aus einemBitmap
Objekt:Das vomJava
FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);
Kotlin+KTX
val image = FirebaseVisionImage.fromBitmap(bitmap)
Bitmap
-Objekt dargestellte Bild muss aufrecht stehen, ohne dass eine zusätzliche Drehung erforderlich ist.
2. Konfigurieren Sie den Image Labeler und führen Sie ihn aus
Um Objekte in einem Bild zu beschriften, übergeben Sie dasFirebaseVisionImage
-Objekt an die processImage
-Methode von FirebaseVisionImageLabeler
.Rufen Sie zunächst eine Instanz von
FirebaseVisionImageLabeler
.Wenn Sie den Bildbezeichner auf dem Gerät verwenden möchten:
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)
Wenn Sie den Cloud Image Labeler verwenden möchten:
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)
Übergeben Sie dann das Bild an die Methode
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. Informieren Sie sich über beschriftete Objekte
Wenn der Bildkennzeichnungsvorgang erfolgreich ist, wird eine Liste vonFirebaseVisionImageLabel
-Objekten an den Erfolgs-Listener übergeben. Jedes FirebaseVisionImageLabel
-Objekt stellt etwas dar, das im Bild beschriftet wurde. Für jedes Label können Sie die Textbeschreibung des Labels, seine Knowledge Graph-Entitäts-ID (falls verfügbar) und den Konfidenzwert der Übereinstimmung abrufen. Zum Beispiel: 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
}
Tipps zur Verbesserung der Echtzeitleistung
Wenn Sie Bilder in einer Echtzeitanwendung beschriften möchten, befolgen Sie diese Richtlinien, um die besten Frameraten zu erzielen:
- Drosseln Sie Aufrufe an den Image-Labeler. Wenn ein neuer Videoframe verfügbar wird, während der Bildlabeler ausgeführt wird, löschen Sie den Frame.
- Wenn Sie die Ausgabe des Bildetikettierers verwenden, um Grafiken über das Eingabebild zu legen, rufen Sie zuerst das Ergebnis von ML Kit ab und rendern dann das Bild und die Überlagerung in einem einzigen Schritt. Dadurch rendern Sie für jeden Eingabeframe nur einmal auf der Anzeigeoberfläche.
Wenn Sie die Camera2-API verwenden, nehmen Sie Bilder im Format
ImageFormat.YUV_420_888
auf.Wenn Sie die ältere Kamera-API verwenden, erfassen Sie Bilder im Format
ImageFormat.NV21
.
Nächste Schritte
- Bevor Sie eine App, die eine Cloud-API verwendet, für die Produktion bereitstellen, sollten Sie einige zusätzliche Schritte unternehmen, um die Auswirkungen eines nicht autorisierten API-Zugriffs zu verhindern und abzumildern .