Der Anwendungsfall Bildanalyse stellt Ihrer App ein CPU-zugängliches Bild zur Verfügung, auf dem Sie Bildverarbeitung, Computer Vision oder Machine Learning-Inferenz ausführen können. Die Anwendung implementiert eine analyze()-Methode, die für jeden Frame ausgeführt wird.
Informationen zum Einbinden des ML-Kits von Google in Ihre CameraX-App finden Sie unter ML Kit Analyzer.
Betriebsmodi
Wenn die Analysepipeline der Anwendung nicht mit den Anforderungen von CameraX an die Framerate Schritt halten kann, kann CameraX so konfiguriert werden, dass Frames auf eine der folgenden Arten verworfen werden:
Nicht blockierend (Standard): In diesem Modus speichert der Executor immer das neueste Bild in einem Bildpuffer (ähnlich einer Warteschlange mit einer Tiefe von eins), während die Anwendung das vorherige Bild analysiert. Wenn CameraX ein neues Bild empfängt, bevor die Verarbeitung abgeschlossen ist, wird das neue Bild im selben Zwischenspeicher gespeichert und das vorherige Bild überschrieben. Beachten Sie, dass
ImageAnalysis.Builder.setImageQueueDepth()in diesem Szenario keine Auswirkungen hat und der Inhalt des Zwischenspeichers immer überschrieben wird. Sie können diesen nicht blockierenden Modus aktivieren, indem SiesetBackpressureStrategy()mitSTRATEGY_KEEP_ONLY_LATESTaufrufen. Weitere Informationen zu den Auswirkungen von Executors finden Sie in der Referenzdokumentation zuSTRATEGY_KEEP_ONLY_LATEST.Blockieren: In diesem Modus kann der interne Executor der internen Bildwarteschlange mehrere Bilder hinzufügen und beginnt erst dann mit dem Verwerfen von Frames, wenn die Warteschlange voll ist. Die Blockierung erfolgt im gesamten Bereich des Kamerageräts: Wenn das Kameragerät mehrere gebundene Anwendungsfälle hat, werden diese alle blockiert, während CameraX diese Bilder verarbeitet. Wenn beispielsweise sowohl die Vorschau als auch die Bildanalyse an ein Kameragerät gebunden sind, wird die Vorschau auch blockiert, während CameraX die Bilder verarbeitet. Sie können den Blockierungsmodus aktivieren, indem Sie
STRATEGY_BLOCK_PRODUCERansetBackpressureStrategy()übergeben. Sie können die Tiefe der Bildwarteschlange auch mit ImageAnalysis.Builder.setImageQueueDepth() konfigurieren.
Bei einem Analysetool mit niedriger Latenz und hoher Leistung, bei dem die Gesamtzeit für die Analyse eines Bildes kürzer ist als die Dauer eines CameraX-Frames (z. B. 16 ms bei 60 fps), bieten beide Betriebsmodi eine reibungslose Gesamterfahrung. Der Blockierungsmodus kann in einigen Szenarien dennoch hilfreich sein, z. B. bei sehr kurzen System-Jittern.
Bei einem Analysetool mit hoher Latenz und hoher Leistung ist der Blockierungsmodus mit einer längeren Warteschlange erforderlich, um die Latenz auszugleichen. Beachten Sie jedoch, dass die Anwendung weiterhin alle Frames verarbeiten kann.
Bei einem Analysetool mit hoher Latenz und hohem Zeitaufwand (das Analysetool kann nicht alle Frames verarbeiten) ist ein nicht blockierender Modus möglicherweise die bessere Wahl, da Frames für den Analysepfad verworfen werden müssen, andere gleichzeitige gebundene Anwendungsfälle aber weiterhin alle Frames sehen können.
Implementierung
So verwenden Sie die Bildanalyse in Ihrer Anwendung:
- Erstellen Sie einen
ImageAnalysis-Anwendungsfall. - Erstellen Sie einen
ImageAnalysis.Analyzer. - Stelle den Analysator auf
ImageAnalysisein. - Binde den LifecycleOwner, die Kameraauswahl und den Anwendungsfall
ImageAnalysisan den Lebenszyklus.
Unmittelbar nach der Bindung sendet CameraX Bilder an den registrierten Analysator.
Rufen Sie nach Abschluss der Analyse ImageAnalysis.clearAnalyzer() auf oder heben Sie die Bindung des Anwendungsfalls ImageAnalysis auf, um die Analyse zu beenden.
Anwendungsfall „ImageAnalysis“ erstellen
ImageAnalysis verbindet Ihren Analyzer (einen Bild-Consumer) mit CameraX, einem Bild-Producer.
Anwendungen können ImageAnalysis.Builder verwenden, um ein ImageAnalysis-Objekt zu erstellen. Mit der ImageAnalysis.Builder kann die Anwendung Folgendes konfigurieren:
- Bildausgabeparameter:
- Format: CameraX unterstützt
YUV_420_888undRGBA_8888übersetOutputImageFormat(int). Das Standardformat istYUV_420_888. - Resolution und AspectRatio: Sie können einen dieser Parameter festlegen, aber nicht beide gleichzeitig.
- Rotation.
- Zielname: Verwenden Sie diesen Parameter für Debugging-Zwecke.
- Format: CameraX unterstützt
- Einstellungen für den Bildfluss:
Anwendungen können entweder die Auflösung oder das Seitenverhältnis festlegen, aber nicht beides. Die genaue Ausgabeauflösung hängt von der von der Anwendung angeforderten Größe (oder dem Seitenverhältnis) und den Hardwarefunktionen ab und kann von der angeforderten Größe oder dem angeforderten Verhältnis abweichen. Informationen zum Algorithmus für den Auflösungsabgleich finden Sie in der Dokumentation zu setTargetResolution().
Eine Anwendung kann die Pixel des Ausgabebilds so konfigurieren, dass sie im YUV- (Standard) oder RGBA-Farbraum liegen. Wenn Sie ein RGBA-Ausgabeformat festlegen, konvertiert CameraX Bilder intern vom YUV- in den RGBA-Farbraum und packt Bildbits in den ByteBuffer der ersten Ebene des ImageProxy (die anderen beiden Ebenen werden nicht verwendet) mit der folgenden Sequenz:
ImageProxy.getPlanes()[0].buffer[0]: alpha
ImageProxy.getPlanes()[0].buffer[1]: red
ImageProxy.getPlanes()[0].buffer[2]: green
ImageProxy.getPlanes()[0].buffer[3]: blue
...
Wenn Sie eine komplizierte Bildanalyse durchführen, bei der das Gerät nicht mit der Framerate mithalten kann, können Sie CameraX so konfigurieren, dass Frames mit den im Abschnitt Betriebsmodi dieses Themas beschriebenen Strategien verworfen werden.
Analyse erstellen
Anwendungen können Analysetools erstellen, indem sie die Schnittstelle ImageAnalysis.Analyzer implementieren und analyze(ImageProxy image) überschreiben.
In jedem Analyseprogramm erhalten Anwendungen ein ImageProxy, das ein Wrapper für Media.Image ist.
Das Bildformat kann mit ImageProxy.getFormat() abgefragt werden.
Das Format ist einer der folgenden Werte, die die Anwendung mit dem ImageAnalysis.Builder bereitstellt:
ImageFormat.RGBA_8888, wenn die AppOUTPUT_IMAGE_FORMAT_RGBA_8888angefordert hat.ImageFormat.YUV_420_888, wenn die AppOUTPUT_IMAGE_FORMAT_YUV_420_888angefordert hat.
Informationen zu Farbraumkonfigurationen und zum Abrufen der Pixel-Byte finden Sie im Anwendungsfall „ImageAnalysis erstellen“.
In einem Analyzer sollte die Anwendung Folgendes tun:
- Analysieren Sie einen bestimmten Frame so schnell wie möglich, vorzugsweise innerhalb des Zeitlimits für die Framerate (z. B. weniger als 32 ms bei 30 fps). Wenn die Anwendung einen Frame nicht schnell genug analysieren kann, sollten Sie einen der unterstützten Mechanismen zum Verwerfen von Frames in Betracht ziehen.
- Gib die
ImageProxyfür CameraX frei, indem duImageProxy.close()aufrufst. Beachten Sie, dass Sie die Funktion „close“ (Media.Image.close()) des verpackten Media.Image nicht aufrufen sollten.
Anwendungen können das verpackte Media.Image direkt in ImageProxy verwenden.
Rufen Sie Media.Image.close() nicht für das umschlossene Bild auf, da dies den Mechanismus zur Bildfreigabe in CameraX beeinträchtigen würde. Verwenden Sie stattdessen ImageProxy.close(), um das zugrunde liegende Media.Image für CameraX freizugeben.
Analyzer für ImageAnalysis konfigurieren
Nachdem Sie einen Analyzer erstellt haben, registrieren Sie ihn mit ImageAnalysis.setAnalyzer(), um die Analyse zu starten. Wenn Sie mit der Analyse fertig sind, verwenden Sie ImageAnalysis.clearAnalyzer(), um den registrierten Analysator zu entfernen.
Für die Bildanalyse kann nur ein aktiver Analysator konfiguriert werden. Durch den Aufruf von ImageAnalysis.setAnalyzer() wird der registrierte Analyzer ersetzt, falls er bereits vorhanden ist. Anwendungen können jederzeit einen neuen Analyzer festlegen, bevor oder nachdem der Anwendungsfall gebunden wurde.
„ImageAnalysis“ an einen Lebenszyklus binden
Es wird dringend empfohlen, die ImageAnalysis mit der Funktion ProcessCameraProvider.bindToLifecycle() an einen vorhandenen AndroidX-Lebenszyklus zu binden. Beachten Sie, dass die Funktion bindToLifecycle() das ausgewählte Camera-Gerät zurückgibt, mit dem erweiterte Einstellungen wie die Belichtung optimiert werden können. Weitere Informationen zum Steuern der Kameraausgabe finden Sie in diesem Leitfaden.
Im folgenden Beispiel werden alle Schritte aus den vorherigen Schritten kombiniert und die CameraX-Anwendungsfälle ImageAnalysis und Preview an einen lifeCycle-Inhaber gebunden:
val imageAnalysis = ImageAnalysis.Builder() // enable the following line if RGBA output is needed. // .setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888) .setTargetResolution(Size(1280, 720)) .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST) .build() imageAnalysis.setAnalyzer(executor, ImageAnalysis.Analyzer { imageProxy -> val rotationDegrees = imageProxy.imageInfo.rotationDegrees // insert your code here. ... // after done, release the ImageProxy object imageProxy.close() }) cameraProvider.bindToLifecycle(this as LifecycleOwner, cameraSelector, imageAnalysis, preview)
Zusätzliche Ressourcen
Weitere Informationen zu CameraX finden Sie in den folgenden Ressourcen.
Codelab
Codebeispiel