Nachdem Sie Ihr eigenes Modell mit AutoML Vision Edge trainiert haben, können Sie es in Ihrer App verwenden, um Bilder zu labeln.
Hinweis
- Falls noch nicht geschehen, Fügen Sie Firebase zu Ihrem Android-Projekt hinzu.
- Abhängigkeiten für die ML Kit-Android-Bibliotheken zu Ihrem Modul hinzufügen
Gradle-Datei auf App-Ebene (in der Regel
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-automl:18.0.5' }
1. Modell laden
ML Kit führt Ihre von AutoML generierten Modelle auf dem Gerät aus. Sie können jedoch können Sie das ML Kit so konfigurieren, dass Ihr Modell remote über Firebase geladen wird, von der lokalen Speicher oder beides.
Wenn Sie das Modell auf Firebase hosten, können Sie es aktualisieren, eine neue App-Version und du kannst Remote Config und A/B Testing für Folgendes verwenden: verschiedenen Gruppen von Nutzern dynamisch verschiedene Modelle bereitstellen.
Wenn Sie das Modell nur durch das Hosting mit Firebase und nicht mit Ihrer App bündeln, können Sie die anfängliche Downloadgröße Ihrer App reduzieren. Wenn das Modell nicht in Ihrer App enthalten ist, modellbezogene Funktionen sind erst verfügbar, wenn Ihre App die um ein neues Modell zu erstellen.
Wenn Sie Ihr Modell mit Ihrer App bündeln, können Sie dafür sorgen, dass die ML-Features Ihrer App funktionieren auch, wenn das von Firebase gehostete Modell nicht verfügbar ist.
Von Firebase gehostete Modellquelle konfigurieren
Erstellen Sie ein FirebaseAutoMLRemoteModel
-Objekt, um das remote gehostete Modell zu verwenden.
Geben Sie den Namen an, den Sie dem Modell bei der Veröffentlichung zugewiesen haben:
Java
// Specify the name you assigned in the Firebase console.
FirebaseAutoMLRemoteModel remoteModel =
new FirebaseAutoMLRemoteModel.Builder("your_remote_model").build();
Kotlin+KTX
// Specify the name you assigned in the Firebase console.
val remoteModel = FirebaseAutoMLRemoteModel.Builder("your_remote_model").build()
Starten Sie dann den Modelldownload und geben Sie die Bedingungen an, unter denen Sie Downloads zulassen möchten. Wenn das Modell nicht auf dem Gerät installiert ist oder ein neueres Modell Version des Modells verfügbar ist, lädt die Aufgabe asynchron das aus Firebase verwenden:
Java
FirebaseModelDownloadConditions conditions = new FirebaseModelDownloadConditions.Builder()
.requireWifi()
.build();
FirebaseModelManager.getInstance().download(remoteModel, conditions)
.addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
// Success.
}
});
Kotlin+KTX
val conditions = FirebaseModelDownloadConditions.Builder()
.requireWifi()
.build()
FirebaseModelManager.getInstance().download(remoteModel, conditions)
.addOnCompleteListener {
// Success.
}
Viele Apps starten die Download-Aufgabe im Initialisierungscode, aber Sie können jederzeit tun, bevor Sie das Modell verwenden müssen.
Lokale Modellquelle konfigurieren
So bündeln Sie das Modell mit Ihrer App:
- Extrahieren Sie das Modell und seine Metadaten aus dem ZIP-Archiv, das Sie aus der Firebase-Konsole heruntergeladen haben. Wir empfehlen, die Dateien so zu verwenden, wie Sie sie heruntergeladen haben. ohne Änderungen (einschließlich der Dateinamen).
-
Fügen Sie das Modell und die zugehörigen Metadatendateien in das Anwendungspaket ein:
- Wenn Sie in Ihrem Projekt noch keinen Assets-Ordner haben, erstellen Sie einen. Klicken Sie dazu mit der rechten Maustaste auf den Ordner
app/
und dann auf Neu > Ordner > Assets-Ordner. - Erstellen Sie einen Unterordner unter dem Assets-Ordner, in dem das Modell gespeichert wird -Dateien.
- Kopieren Sie die Dateien
model.tflite
,dict.txt
undmanifest.json
in den Unterordner (alle drei Dateien müssen sich im im selben Ordner).
- Wenn Sie in Ihrem Projekt noch keinen Assets-Ordner haben, erstellen Sie einen. Klicken Sie dazu mit der rechten Maustaste auf den Ordner
- Fügen Sie der Datei
build.gradle
Ihrer App Folgendes hinzu, um sicherzustellen, Gradle komprimiert die Modelldatei beim Erstellen der App nicht: Die Modelldatei ist im App-Paket enthalten und für ML Kit verfügbar als unbearbeitetes Asset.android { // ... aaptOptions { noCompress "tflite" } }
- Erstellen Sie ein
FirebaseAutoMLLocalModel
-Objekt und geben Sie den Pfad zum Modellmanifest an Datei:Java
FirebaseAutoMLLocalModel localModel = new FirebaseAutoMLLocalModel.Builder() .setAssetFilePath("manifest.json") .build();
Kotlin+KTX
val localModel = FirebaseAutoMLLocalModel.Builder() .setAssetFilePath("manifest.json") .build()
Labelersteller für Bilder aus Ihrem Modell erstellen
Nachdem Sie die Modellquellen konfiguriert haben, erstellen Sie eine FirebaseVisionImageLabeler
Objekt aus einem von ihnen.
Wenn Sie nur ein lokal gebündeltes Modell haben, erstellen Sie einfach einen Labelersteller
FirebaseAutoMLLocalModel
-Objekt und konfigurieren Sie den Schwellenwert für den Konfidenzwert
die Sie anfordern möchten (siehe Modell bewerten):
Java
FirebaseVisionImageLabeler labeler;
try {
FirebaseVisionOnDeviceAutoMLImageLabelerOptions options =
new FirebaseVisionOnDeviceAutoMLImageLabelerOptions.Builder(localModel)
.setConfidenceThreshold(0.0f) // Evaluate your model in the Firebase console
// to determine an appropriate value.
.build();
labeler = FirebaseVision.getInstance().getOnDeviceAutoMLImageLabeler(options);
} catch (FirebaseMLException e) {
// ...
}
Kotlin+KTX
val options = FirebaseVisionOnDeviceAutoMLImageLabelerOptions.Builder(localModel)
.setConfidenceThreshold(0) // Evaluate your model in the Firebase console
// to determine an appropriate value.
.build()
val labeler = FirebaseVision.getInstance().getOnDeviceAutoMLImageLabeler(options)
Wenn Sie ein extern gehostetes Modell haben, müssen Sie prüfen,
die Sie vor der Ausführung heruntergeladen haben. Sie können den Status des Modelldownloads
mit der Methode isModelDownloaded()
des Modellmanagers.
Sie müssen dies nur vor dem Ausführen des Labelerstellers bestätigen. Wenn Sie ein remote gehostetes und ein lokal gebündeltes Modell haben, Sinn, diese Prüfung bei der Instanziierung des Labelerstellers für Bilder durchzuführen: Labelersteller aus dem Remote-Modell, falls es heruntergeladen wurde, und vom lokalen modellieren.
Java
FirebaseModelManager.getInstance().isModelDownloaded(remoteModel)
.addOnSuccessListener(new OnSuccessListener<Boolean>() {
@Override
public void onSuccess(Boolean isDownloaded) {
FirebaseVisionOnDeviceAutoMLImageLabelerOptions.Builder optionsBuilder;
if (isDownloaded) {
optionsBuilder = new FirebaseVisionOnDeviceAutoMLImageLabelerOptions.Builder(remoteModel);
} else {
optionsBuilder = new FirebaseVisionOnDeviceAutoMLImageLabelerOptions.Builder(localModel);
}
FirebaseVisionOnDeviceAutoMLImageLabelerOptions options = optionsBuilder
.setConfidenceThreshold(0.0f) // Evaluate your model in the Firebase console
// to determine an appropriate threshold.
.build();
FirebaseVisionImageLabeler labeler;
try {
labeler = FirebaseVision.getInstance().getOnDeviceAutoMLImageLabeler(options);
} catch (FirebaseMLException e) {
// Error.
}
}
});
Kotlin+KTX
FirebaseModelManager.getInstance().isModelDownloaded(remoteModel)
.addOnSuccessListener { isDownloaded ->
val optionsBuilder =
if (isDownloaded) {
FirebaseVisionOnDeviceAutoMLImageLabelerOptions.Builder(remoteModel)
} else {
FirebaseVisionOnDeviceAutoMLImageLabelerOptions.Builder(localModel)
}
// Evaluate your model in the Firebase console to determine an appropriate threshold.
val options = optionsBuilder.setConfidenceThreshold(0.0f).build()
val labeler = FirebaseVision.getInstance().getOnDeviceAutoMLImageLabeler(options)
}
Wenn Sie nur ein extern gehostetes Modell haben, sollten Sie modellverwandte Funktionen deaktivieren, z. B. einen Teil der Benutzeroberfläche grau ausblenden oder ausblenden, bis Sie bestätigen, dass das Modell heruntergeladen wurde. Dazu fügen Sie der download()
-Methode des Modellmanagers einen Listener hinzu:
Java
FirebaseModelManager.getInstance().download(remoteModel, conditions)
.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void v) {
// Download complete. Depending on your app, you could enable
// the ML feature, or switch from the local model to the remote
// model, etc.
}
});
Kotlin+KTX
FirebaseModelManager.getInstance().download(remoteModel, conditions)
.addOnCompleteListener {
// Download complete. Depending on your app, you could enable the ML
// feature, or switch from the local model to the remote model, etc.
}
2. Eingabebild vorbereiten
Erstellen Sie dann für jedes Bild, das Sie mit einem Label versehen möchten, ein FirebaseVisionImage
-Objekt.
mithilfe einer der in diesem Abschnitt beschriebenen Optionen und übergeben Sie sie an eine Instanz von
FirebaseVisionImageLabeler
(wird im nächsten Abschnitt beschrieben).
Sie können ein FirebaseVisionImage
-Objekt aus einem media.Image
-Objekt erstellen,
auf dem Gerät, ein Byte-Array oder ein Bitmap
-Objekt:
-
Um ein
FirebaseVisionImage
-Objekt aus einemmedia.Image
-Objekt, z. B. beim Aufnehmen eines Bildes von einem des Geräts an und übergib dasmedia.Image
-Objekt und die Rotation aufFirebaseVisionImage.fromMediaImage()
.Wenn Sie die Methode CameraX-Bibliothek, den
OnImageCapturedListener
undImageAnalysis.Analyzer
-Klassen berechnen den Rotationswert Sie müssen also nur die Rotation in eine der ML Kit-ModelleROTATION_
-Konstanten vor dem AufrufFirebaseVisionImage.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 // ... } } }
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+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 aufFirebaseVisionImage.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 App-Kontext und Datei-URI zuFirebaseVisionImage.fromFilePath()
. Dies ist nützlich, wenn Sie Verwenden Sie den IntentACTION_GET_CONTENT
, um den Nutzer zur Auswahl aufzufordern ein Bild aus ihrer Galerie-App.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, berechnen Sie zuerst das Bild Rotation wie oben für diemedia.Image
-Eingabe beschrieben.Erstellen Sie dann ein
FirebaseVisionImageMetadata
-Objekt. die die Höhe, Breite, Farbcodierung, und Rotation: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 Zwischenspeicher oder das Array und das Metadatenobjekt, um einen Objekt
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)
- So erstellen Sie ein
FirebaseVisionImage
-Objekt aus einemBitmap
-Objekt:Java
FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);
Kotlin+KTX
val image = FirebaseVisionImage.fromBitmap(bitmap)
Bitmap
dargestellte Bild muss aufrecht und ohne zusätzliche Drehung aufrecht.
3. Labelersteller für Bilder ausführen
Um Objekte in einem Bild mit einem Label zu versehen, übergeben Sie das FirebaseVisionImage
-Objekt an die
Die Methode processImage()
von FirebaseVisionImageLabeler
.
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
// ...
}
Wenn das Bild-Labeling erfolgreich ist, ein Array von FirebaseVisionImageLabel
-Objekten
an den Erfolgs-Listener übergeben. Von jedem Objekt erhalten Sie
Informationen zu einem im Bild erkannten Merkmal.
Beispiel:
Java
for (FirebaseVisionImageLabel label: labels) {
String text = label.getText();
float confidence = label.getConfidence();
}
Kotlin+KTX
for (label in labels) {
val text = label.text
val confidence = label.confidence
}
Tipps zum Verbessern der Leistung in Echtzeit
- Drosselung von Aufrufen an den Detektor. Wenn ein neuer Videoframe wenn der Detektor ausgeführt wird, lassen Sie den Frame weg.
- Wenn Sie die Ausgabe des Detektors verwenden, um Grafiken Eingabebild, rufen Sie zuerst das Ergebnis aus ML Kit ab und rendern Sie das Bild in einem Schritt übereinanderlegen. Dadurch rendern Sie auf der Anzeigeoberfläche für jeden Eingabe-Frame nur einmal.
-
Wenn Sie die Camera2 API verwenden, nehmen Sie Bilder in
ImageFormat.YUV_420_888
-Format.Wenn Sie die ältere Camera API verwenden, nehmen Sie Bilder in
ImageFormat.NV21
-Format.