Mit ML Kit können Sie Objekte in Videoframes erkennen und verfolgen.
Wenn Sie ML Kit-Bilder übergeben, gibt ML Kit für jedes Bild eine Liste bis zu fünf erkannte Objekte und ihre Position im Bild. Bei der Erkennung von Objekten in Videostreams hat jedes Objekt eine ID, mit der Sie das Objekt in Bildern verfolgen können. Optional können Sie auch die grobe Objektklassifizierung aktivieren, bei der Objekte mit allgemeinen Kategoriebeschreibungen gekennzeichnet werden.
Hinweis
- Falls noch nicht geschehen, Fügen Sie Ihrem Android-Projekt Firebase 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-object-detection-model:19.0.6' }
1. Objektdetektor konfigurieren
Um mit der Erkennung und dem Tracking von Objekten zu beginnen, erstellen Sie zunächst eine Instanz von
FirebaseVisionObjectDetector
und optional die von Ihnen festgelegten Detektoreinstellungen
die Standardeinstellung ändern möchten.
Konfigurieren Sie den Objektdetektor für Ihren Anwendungsfall mit einem
FirebaseVisionObjectDetectorOptions
-Objekt. Sie können Folgendes ändern: Einstellungen:Einstellungen für den Objektdetektor Erkennungsmodus STREAM_MODE
(Standard) |SINGLE_IMAGE_MODE
In
STREAM_MODE
(Standardeinstellung) wird der Objektdetektor ausgeführt mit niedriger Latenz, führt aber möglicherweise zu unvollständigen Ergebnissen (z. B. nicht spezifizierten Begrenzungsrahmen oder Kategorielabels) Aufrufe des Detektors. Außerdem gibt es inSTREAM_MODE
weist der Detektor Objekten Tracking-IDs zu, mit denen Sie um Objekte über Frames hinweg zu verfolgen. Verwenden Sie diesen Modus, wenn Sie oder wenn eine niedrige Latenz wichtig ist, z. B. bei der Verarbeitung Videostreams in Echtzeit.In
SINGLE_IMAGE_MODE
wartet der Objektdetektor bis zum Begrenzungsrahmen eines erkannten Objekts und (falls Sie sind verfügbar, bevor eine Ergebnis. Die Erkennungslatenz ist daher potenziell höher. Außerdem sind Tracking-IDs inSINGLE_IMAGE_MODE
nicht zugewiesen sind. Verwenden Sie diesen Modus, wenn die Latenz nicht kritisch ist und Sie keine Teilergebnisse verarbeiten möchten.Mehrere Objekte erkennen und verfolgen false
(Standard) |true
Ob bis zu fünf Objekte oder nur das auffälligste Objekt (Standardeinstellung) erkannt und verfolgt werden sollen.
Objekte klassifizieren false
(Standard) |true
Ob erkannte Objekte in grobe Kategorien klassifiziert werden sollen. Wenn die Funktion aktiviert ist, klassifiziert der Objekterkennungsalgorithmus Objekte in die folgenden Kategorien: Modeartikel, Lebensmittel, Haushaltswaren, Orte, Pflanzen und „Unbekannt“.
Die Object Detection and Tracking API ist für die folgenden beiden Hauptanwendungsfälle optimiert:
- Live-Erkennung und Verfolgung des auffälligsten Objekts in der Kamera Sucher
- Erkennung mehrerer Objekte in einem statischen Bild
So konfigurieren Sie die API für diese Anwendungsfälle:
Java
// Live detection and tracking FirebaseVisionObjectDetectorOptions options = new FirebaseVisionObjectDetectorOptions.Builder() .setDetectorMode(FirebaseVisionObjectDetectorOptions.STREAM_MODE) .enableClassification() // Optional .build(); // Multiple object detection in static images FirebaseVisionObjectDetectorOptions options = new FirebaseVisionObjectDetectorOptions.Builder() .setDetectorMode(FirebaseVisionObjectDetectorOptions.SINGLE_IMAGE_MODE) .enableMultipleObjects() .enableClassification() // Optional .build();
Kotlin+KTX
// Live detection and tracking val options = FirebaseVisionObjectDetectorOptions.Builder() .setDetectorMode(FirebaseVisionObjectDetectorOptions.STREAM_MODE) .enableClassification() // Optional .build() // Multiple object detection in static images val options = FirebaseVisionObjectDetectorOptions.Builder() .setDetectorMode(FirebaseVisionObjectDetectorOptions.SINGLE_IMAGE_MODE) .enableMultipleObjects() .enableClassification() // Optional .build()
Rufen Sie eine Instanz von
FirebaseVisionObjectDetector
ab:Java
FirebaseVisionObjectDetector objectDetector = FirebaseVision.getInstance().getOnDeviceObjectDetector(); // Or, to change the default settings: FirebaseVisionObjectDetector objectDetector = FirebaseVision.getInstance().getOnDeviceObjectDetector(options);
Kotlin+KTX
val objectDetector = FirebaseVision.getInstance().getOnDeviceObjectDetector() // Or, to change the default settings: val objectDetector = FirebaseVision.getInstance().getOnDeviceObjectDetector(options)
2. Objektdetektor ausführen
Übergeben Sie Bilder an den FirebaseVisionObjectDetector
, um Objekte zu erkennen und zu verfolgen
Methode processImage()
der Instanz.
Gehen Sie für jeden Frame eines Videos oder Bildes in einer Sequenz so vor:
Erstellen Sie ein
FirebaseVisionImage
-Objekt aus Ihrem Bild.-
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 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+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 Rotation des Bildes anzeigt, den Wert aus der Gerätedrehung und der Kameraausrichtung berechnen kann. Sensor im Gerät:
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 Drehwert anFirebaseVisionImage.fromMediaImage()
:Java
FirebaseVisionImage image = FirebaseVisionImage.fromMediaImage(mediaImage, rotation);
Kotlin+KTX
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()
. 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, 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+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)
- Um 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.
-
Übergeben Sie das Bild an die
processImage()
-Methode:Java
objectDetector.processImage(image) .addOnSuccessListener( new OnSuccessListener<List<FirebaseVisionObject>>() { @Override public void onSuccess(List<FirebaseVisionObject> detectedObjects) { // Task completed successfully // ... } }) .addOnFailureListener( new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { // Task failed with an exception // ... } });
Kotlin+KTX
objectDetector.processImage(image) .addOnSuccessListener { detectedObjects -> // Task completed successfully // ... } .addOnFailureListener { e -> // Task failed with an exception // ... }
Wenn der Aufruf von
processImage()
erfolgreich ist, wird dem Erfolgsempfänger eine Liste vonFirebaseVisionObject
s übergeben.Jedes
FirebaseVisionObject
enthält die folgenden Attribute:Begrenzungsrahmen Eine Rect
, die die Position des Objekts im Bild angibt.Tracking-ID Eine Ganzzahl, die das Objekt in Bildern identifiziert. Null in SINGLE_IMAGE_MODE. Kategorie Die grobe Kategorie des Objekts. Wenn die Klassifizierung für den Objektdetektor nicht aktiviert ist, ist dies immer FirebaseVisionObject.CATEGORY_UNKNOWN
.Zuverlässigkeit Der Konfidenzwert der Objektklassifizierung. Wenn die Klassifizierung für den Objekt-Detektor nicht aktiviert ist oder das Objekt als unbekannt klassifiziert wird, ist das null
.Java
// The list of detected objects contains one item if multiple object detection wasn't enabled. for (FirebaseVisionObject obj : detectedObjects) { Integer id = obj.getTrackingId(); Rect bounds = obj.getBoundingBox(); // If classification was enabled: int category = obj.getClassificationCategory(); Float confidence = obj.getClassificationConfidence(); }
Kotlin+KTX
// The list of detected objects contains one item if multiple object detection wasn't enabled. for (obj in detectedObjects) { val id = obj.trackingId // A number that identifies the object across images val bounds = obj.boundingBox // The object's position in the image // If classification was enabled: val category = obj.classificationCategory val confidence = obj.classificationConfidence }
Nutzerfreundlichkeit und Leistung verbessern
Beachten Sie in Ihrer App die folgenden Richtlinien, um die Nutzerfreundlichkeit zu optimieren:
- Die erfolgreiche Objekterkennung hängt von der visuellen Komplexität des Objekts ab. Objekte mit wenigen visuellen Features möglicherweise einen größeren Teil des das zu erkennende Bild ist. Sie sollten Nutzenden dabei helfen, die sich gut für die Art von Objekten eignet, die Sie erkennen möchten.
- Wenn Sie bei der Klassifizierung Objekte erkennen möchten, die nicht fallen in die unterstützten Kategorien einzuordnen, spezielle Behandlungen für unbekannte Objekte.
Sehen Sie sich auch die [ML Kit Material Design Showcase-App][showcase-link]{: .external } und die Material Design Sammlung Muster für durch maschinelles Lernen unterstützte Funktionen
Wenn Sie den Streaming-Modus in einer Echtzeitanwendung verwenden, sollten Sie um die besten Frame-Rates zu erzielen:
Verwenden Sie im Streamingmodus nicht die Mehrfachobjekterkennung, da die meisten Geräte dies angemessene Framerates zu erzielen.
Deaktivieren Sie die Klassifizierung, wenn Sie sie nicht benötigen.
- Aufrufe an den Detektor drosseln Wenn ein neuer Videoframe wenn der Detektor ausgeführt wird, lassen Sie den Frame weg.
- Wenn Sie die Ausgabe des Detektors 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. 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 im
ImageFormat.NV21
-Format auf.