Mit ML Kit können Sie Objekte, die in einem Bild erkannt werden, entweder mit einem On-Device-Modell oder einem Cloud-Modell taggen. In der Übersicht finden Sie Informationen zu den Vorteilen der einzelnen Ansätze.
Hinweis
- Fügen Sie Ihrem Android-Projekt Firebase hinzu, falls noch nicht geschehen.
- Fügen Sie der Gradle-Datei des Moduls (auf Anwendungsebene, in der Regel
app/build.gradle
) die Abhängigkeiten für die ML Kit-Android-Bibliotheken hinzu: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 On-Device API 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 der Datei
AndroidManifest.xml
Ihrer App die folgende Erklärung hinzu: Wenn Sie den Download von Modellen bei der Installation nicht aktivieren, wird das Modell beim ersten Ausführen des On-Device-Erkners heruntergeladen. Anfragen, die Sie vor Abschluss des Downloads stellen, führen zu keinen Ergebnissen.<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 cloudbasierte Modell verwenden möchten und die cloudbasierten APIs für Ihr Projekt noch nicht aktiviert haben, gehen Sie so vor:
- Öffnen Sie in der Firebase-Konsole die Seite ML Kit APIs.
-
Wenn Sie Ihr Projekt noch nicht auf einen Blaze-Tarif umgestellt haben, klicken Sie auf Upgrade. Sie werden nur dann zum Umstellen aufgefordert, wenn Ihr Projekt nicht den Blaze-Tarif hat.
Cloud-basierte APIs können nur in Projekten auf Blaze-Ebene verwendet werden.
- Wenn cloudbasierte APIs noch nicht aktiviert sind, klicken Sie auf Cloudbasierte APIs aktivieren.
Wenn Sie nur das Modell auf dem Gerät verwenden möchten, können Sie diesen Schritt überspringen.
Jetzt können Sie Bilder entweder mit einem On-Device-Modell oder einem cloudbasierten Modell labeln.
1. Eingabebild vorbereiten
Erstellen Sie aus Ihrem Bild einFirebaseVisionImage
-Objekt.
Der Bildlabeler funktioniert am schnellsten, wenn Sie ein Bitmap
oder, wenn Sie die camera2 API verwenden, ein im JPEG-Format vorliegendes media.Image
verwenden. Wir empfehlen, nach Möglichkeit diese Formate zu verwenden.
-
Wenn Sie ein
FirebaseVisionImage
-Objekt aus einemmedia.Image
-Objekt erstellen möchten, z. B. wenn Sie ein Bild mit der Kamera eines Geräts aufnehmen, übergeben Sie dasmedia.Image
-Objekt und die Drehung des Bilds anFirebaseVisionImage.fromMediaImage()
.Wenn Sie die CameraX-Bibliothek verwenden, wird der Drehwert von den Klassen
OnImageCapturedListener
undImageAnalysis.Analyzer
für Sie berechnet. Sie müssen ihn also nur in eine derROTATION_
-Konstanten von ML Kit umwandeln, 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
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 die Drehung des Bildes angibt, können Sie sie anhand 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
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 Drehwert anFirebaseVisionImage.fromMediaImage()
:Java
FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation);
Kotlin
val image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation)
- Wenn Sie ein
FirebaseVisionImage
-Objekt aus einem Datei-URI erstellen möchten, übergeben Sie den App-Kontext und den Datei-URI anFirebaseVisionImage.fromFilePath()
. Das ist nützlich, wenn Sie mit einerACTION_GET_CONTENT
-Intent den Nutzer auffordern, ein Bild aus seiner Galerie-App auszuwählen.Java
FirebaseVisionImage image; try { image = FirebaseVisionImage.fromFilePath(context, uri); } catch (IOException e) { e.printStackTrace(); }
Kotlin
val image: FirebaseVisionImage try { image = FirebaseVisionImage.fromFilePath(context, uri) } catch (e: IOException) { e.printStackTrace() }
- Wenn Sie ein
FirebaseVisionImage
-Objekt aus einemByteBuffer
oder einem Byte-Array erstellen möchten, berechnen Sie zuerst die Bilddrehung wie oben für diemedia.Image
-Eingabe beschrieben.Erstellen Sie dann ein
FirebaseVisionImageMetadata
-Objekt, das die Höhe, Breite, Farbcodierung und Drehung des Bildes 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
val metadata = FirebaseVisionImageMetadata.Builder() .setWidth(480) // 480x360 is typically sufficient for .setHeight(360) // image recognition .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21) .setRotation(rotation) .build()
Verwende 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
val image = FirebaseVisionImage.fromByteBuffer(buffer, metadata) // Or: val image = FirebaseVisionImage.fromByteArray(byteArray, metadata)
- So erstellen Sie ein
FirebaseVisionImage
-Objekt aus einemBitmap
-Objekt:Java
FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);
Kotlin
val image = FirebaseVisionImage.fromBitmap(bitmap)
Bitmap
-Objekt dargestellte Bild muss aufrecht sein und darf nicht zusätzlich gedreht werden.
2. Bildlabeler konfigurieren und ausführen
Wenn Sie Objekte in einem Bild mit Labels versehen möchten, übergeben Sie dasFirebaseVisionImage
-Objekt an die processImage
-Methode des FirebaseVisionImageLabeler
-Objekts.
Rufen Sie zuerst eine Instanz von
FirebaseVisionImageLabeler
ab.So verwenden Sie die On-Device-Bilderkennung:
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
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)
So verwenden Sie den Cloud-Bildlabeler:
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
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
processImage()
-Methode: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
labeler.processImage(image) .addOnSuccessListener { labels -> // Task completed successfully // ... } .addOnFailureListener { e -> // Task failed with an exception // ... }
3. Informationen zu gekennzeichneten Objekten abrufen
Wenn der Vorgang zum Beschriften von Bildern erfolgreich war, wird dem Erfolgs-Listener eine Liste vonFirebaseVisionImageLabel
-Objekten übergeben. Jedes FirebaseVisionImageLabel
-Objekt steht für etwas, das im Bild gekennzeichnet wurde. Für jedes Label können Sie die Textbeschreibung des Labels, die Knowledge Graph-Entitäts-ID (falls verfügbar) und den Konfidenzwert der Übereinstimmung abrufen. Beispiel:
Java
for (FirebaseVisionImageLabel label: labels) {
String text = label.getText();
String entityId = label.getEntityId();
float confidence = label.getConfidence();
}
Kotlin
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 taggen möchten, beachten Sie die folgenden Richtlinien, um die beste Framerate zu erzielen:
- Aufrufe an den Bildbeschrifter drosseln Wenn während der Ausführung des Bildestikkers ein neuer Videoframe verfügbar wird, legen Sie ihn ab.
- Wenn Sie die Ausgabe des Bildes-Labelers verwenden, um Grafiken auf das Eingabebild zu legen, rufen Sie zuerst das Ergebnis aus ML Kit ab und rendern Sie dann das Bild und das Overlay in einem einzigen Schritt. So wird für jeden Eingabeframe nur einmal auf die Displayoberfläche gerendert.
-
Wenn Sie die Camera2 API verwenden, sollten Sie Bilder im
ImageFormat.YUV_420_888
-Format aufnehmen.Wenn Sie die ältere Camera API verwenden, nehmen Sie Bilder im
ImageFormat.NV21
-Format auf.
Nächste Schritte
- Bevor Sie eine App, die eine Cloud API verwendet, in der Produktionsumgebung bereitstellen, sollten Sie einige zusätzliche Schritte ausführen, um unbefugten API-Zugriff zu verhindern und die Auswirkungen zu minimieren.