Sie konfigurieren jeden CameraX-Anwendungsfall, um verschiedene Aspekte der Vorgänge des Anwendungsfalls zu steuern.
Beim Anwendungsfall „Bilderfassung“ können Sie beispielsweise ein Ziel-Seitenverhältnis und einen Blitzmodus festlegen. Der folgende Code zeigt ein Beispiel:
Kotlin
val imageCapture = ImageCapture.Builder() .setFlashMode(...) .setTargetAspectRatio(...) .build()
Java
ImageCapture imageCapture = new ImageCapture.Builder() .setFlashMode(...) .setTargetAspectRatio(...) .build();
Zusätzlich zu den Konfigurationsoptionen stellen einige Anwendungsfälle APIs bereit, mit denen Einstellungen nach dem Erstellen des Anwendungsfalls dynamisch geändert werden können. Informationen zur Konfiguration für die einzelnen Anwendungsfälle finden Sie unter Vorschau implementieren, Bilder analysieren und Bilderfassung.
CameraXConfig
Der Einfachheit halber bietet CameraX Standardkonfigurationen wie interne Executors und Handler, die für die meisten Anwendungsfälle geeignet sind. Wenn Ihre Anwendung jedoch besondere Anforderungen hat oder Sie diese Konfigurationen anpassen möchten, ist CameraXConfig die Schnittstelle für diesen Zweck.
Mit CameraXConfig kann eine Anwendung Folgendes tun:
- Optimieren Sie die Startlatenz mit
setAvailableCameraLimiter(). - Stellen Sie CameraX den Executor der Anwendung mit
setCameraExecutor()zur Verfügung. - Ersetzen Sie den Standard-Scheduler-Handler durch
setSchedulerHandler(). - Ändern Sie die Logging-Ebene mit
setMinimumLoggingLevel().
Nutzungsmodell
Im Folgenden wird beschrieben, wie Sie CameraXConfig verwenden:
- Erstellen Sie ein
CameraXConfig-Objekt mit Ihren benutzerdefinierten Konfigurationen. - Implementieren Sie die
CameraXConfig.Provider-Schnittstelle in IhrerApplicationund geben Sie IhrCameraXConfig-Objekt ingetCameraXConfig()zurück. - Fügen Sie die Klasse
Applicationder DateiAndroidManifest.xmlhinzu, wie hier beschrieben.
Im folgenden Codebeispiel wird das CameraX-Logging beispielsweise auf Fehlermeldungen beschränkt:
Kotlin
class CameraApplication : Application(), CameraXConfig.Provider { override fun getCameraXConfig(): CameraXConfig { return CameraXConfig.Builder.fromConfig(Camera2Config.defaultConfig()) .setMinimumLoggingLevel(Log.ERROR).build() } }
Behalte eine lokale Kopie des CameraXConfig-Objekts, wenn deine Anwendung die CameraX-Konfiguration nach dem Festlegen kennen muss.
Kamerabegrenzung
Beim ersten Aufruf von ProcessCameraProvider.getInstance() listet CameraX die auf dem Gerät verfügbaren Kameras auf und fragt ihre Eigenschaften ab. Da CameraX mit Hardwarekomponenten kommunizieren muss, kann dieser Vorgang für jede Kamera eine gewisse Zeit in Anspruch nehmen, insbesondere auf Geräten mit geringer Leistung. Wenn deine App nur bestimmte Kameras auf dem Gerät verwendet, z. B. die Standard-Frontkamera, kannst du CameraX so einstellen, dass andere Kameras ignoriert werden. Dadurch kann die Startlatenz für die von deiner App verwendeten Kameras reduziert werden.
Wenn der an CameraXConfig.Builder.setAvailableCamerasLimiter() übergebene CameraSelector eine Kamera herausfiltert, verhält sich CameraX so, als ob diese Kamera nicht vorhanden wäre. Mit dem folgenden Code wird die Anwendung beispielsweise so eingeschränkt, dass nur die standardmäßige Rückkamera des Geräts verwendet wird:
Kotlin
class MainApplication : Application(), CameraXConfig.Provider { override fun getCameraXConfig(): CameraXConfig { return CameraXConfig.Builder.fromConfig(Camera2Config.defaultConfig()) .setAvailableCamerasLimiter(CameraSelector.DEFAULT_BACK_CAMERA) .build() } }
Threads
Viele der Plattform-APIs, auf denen CameraX basiert, erfordern eine blockierende Interprocess Communication (IPC) mit Hardware, deren Antwort manchmal Hunderte von Millisekunden dauern kann. Aus diesem Grund ruft CameraX diese APIs nur über Hintergrundthreads auf, damit der Hauptthread nicht blockiert wird und die Benutzeroberfläche flüssig bleibt. CameraX verwaltet diese Hintergrundthreads intern, sodass dieses Verhalten transparent erscheint. Einige Anwendungen erfordern jedoch eine strenge Kontrolle der Threads. Mit CameraXConfig kann eine Anwendung die Hintergrundthreads festlegen, die über CameraXConfig.Builder.setCameraExecutor() und CameraXConfig.Builder.setSchedulerHandler() verwendet werden.
Kamera-Executor
Der Kamera-Executor wird für alle internen API-Aufrufe der Kamera-Plattform sowie für Callbacks von diesen APIs verwendet. CameraX weist einen internen Executor zu und verwaltet ihn, um diese Aufgaben auszuführen.
Wenn Ihre Anwendung jedoch eine strengere Kontrolle der Threads erfordert, verwenden Sie CameraXConfig.Builder.setCameraExecutor().
Planer-Handler
Der Scheduler-Handler wird verwendet, um interne Aufgaben in festen Intervallen zu planen, z. B. um die Kamera noch einmal zu öffnen, wenn sie nicht verfügbar ist. Dieser Handler führt keine Jobs aus, sondern leitet sie nur an den Kamera-Executor weiter. Sie wird manchmal auch auf Legacy-API-Plattformen verwendet, die einen Handler für Callbacks erfordern. In diesen Fällen werden die Callbacks weiterhin nur direkt an den Kamera-Executor gesendet. CameraX weist einen internen HandlerThread zu und verwaltet ihn, um diese Aufgaben auszuführen. Sie können ihn jedoch mit CameraXConfig.Builder.setSchedulerHandler() überschreiben.
Logging
Mit dem CameraX-Logging können Anwendungen Logcat-Nachrichten filtern, da es sinnvoll sein kann, ausführliche Nachrichten im Produktionscode zu vermeiden. CameraX unterstützt vier Logging-Stufen, von der ausführlichsten bis zur schwerwiegendsten:
Log.DEBUG(Standard)Log.INFOLog.WARNLog.ERROR
Ausführliche Beschreibungen dieser Logebenen finden Sie in der Dokumentation zu Android-Logs. Verwenden Sie CameraXConfig.Builder.setMinimumLoggingLevel(int), um die entsprechende Logging-Ebene für Ihre Anwendung festzulegen.
Automatische Auswahl
CameraX bietet automatisch Funktionen, die für das Gerät, auf dem Ihre App ausgeführt wird, spezifisch sind. Beispielsweise ermittelt CameraX automatisch die beste Auflösung, wenn Sie keine Auflösung angeben oder die von Ihnen angegebene Auflösung nicht unterstützt wird. All dies wird von der Bibliothek erledigt, sodass Sie keinen gerätespezifischen Code schreiben müssen.
Das Ziel von CameraX ist es, eine Kamerasitzung erfolgreich zu initialisieren. Das bedeutet, dass CameraX je nach Gerätefunktionen Kompromisse bei Auflösung und Seitenverhältnis eingeht. Das kann folgende Gründe haben:
- Das Gerät unterstützt die angeforderte Auflösung nicht.
- Das Gerät hat Kompatibilitätsprobleme, z. B. ältere Geräte, die bestimmte Auflösungen benötigen, um ordnungsgemäß zu funktionieren.
- Auf einigen Geräten sind bestimmte Formate nur bei bestimmten Seitenverhältnissen verfügbar.
- Das Gerät bevorzugt „nächstes mod16“ für die JPEG- oder Videocodierung. Weitere Informationen finden Sie unter
SCALER_STREAM_CONFIGURATION_MAP.
Obwohl CameraX die Sitzung erstellt und verwaltet, sollten Sie immer die zurückgegebenen Bildgrößen in der Ausgabe des Anwendungsfalls in Ihrem Code prüfen und entsprechend anpassen.
Rotation
Standardmäßig ist die Kamerarotation so eingestellt, dass sie der Standardrotation des Displays bei der Erstellung des Anwendungsfalls entspricht. In diesem Standardfall erzeugt CameraX Ausgaben, damit die App dem entspricht, was Sie in der Vorschau erwarten. Du kannst die Drehung auf einen benutzerdefinierten Wert ändern, um Geräte mit mehreren Displays zu unterstützen. Dazu übergibst du die aktuelle Displayausrichtung, wenn du Anwendungsfallobjekte konfigurierst, oder dynamisch, nachdem sie erstellt wurden.
Ihre App kann die Zielrotation mithilfe von Konfigurationseinstellungen festlegen. Anschließend können die Rotationseinstellungen mithilfe der Methoden aus den Anwendungsfall-APIs (z. B. ImageAnalysis.setTargetRotation()) aktualisiert werden, auch wenn der Lebenszyklus ausgeführt wird. Dies kann nützlich sein, wenn die App im Porträtmodus gesperrt ist und daher bei einer Drehung keine Neukonfiguration erfolgt, aber der Foto- oder Analyseanwendungsfall die aktuelle Drehung des Geräts kennen muss. Beispielsweise kann die Rotationserkennung erforderlich sein, damit Gesichter für die Gesichtserkennung richtig ausgerichtet sind oder Fotos im Quer- oder Hochformat angezeigt werden.
Daten für aufgenommene Bilder werden möglicherweise ohne Rotationsinformationen gespeichert. Exif-Daten enthalten Informationen zur Drehung, damit Galerieanwendungen das Bild nach dem Speichern in der richtigen Ausrichtung anzeigen können.
Wenn Sie Vorschaudaten mit der richtigen Ausrichtung anzeigen möchten, können Sie die Metadatenausgabe von Preview.PreviewOutput() verwenden, um Transformationen zu erstellen.
Im folgenden Codebeispiel wird gezeigt, wie die Drehung für ein Ausrichtungsereignis festgelegt wird:
Kotlin
override fun onCreate() { val imageCapture = ImageCapture.Builder().build() val orientationEventListener = object : OrientationEventListener(this as Context) { override fun onOrientationChanged(orientation : Int) { // Monitors orientation values to determine the target rotation value val rotation : Int = when (orientation) { in 45..134 -> Surface.ROTATION_270 in 135..224 -> Surface.ROTATION_180 in 225..314 -> Surface.ROTATION_90 else -> Surface.ROTATION_0 } imageCapture.targetRotation = rotation } } orientationEventListener.enable() }
Java
@Override public void onCreate() { ImageCapture imageCapture = new ImageCapture.Builder().build(); OrientationEventListener orientationEventListener = new OrientationEventListener((Context)this) { @Override public void onOrientationChanged(int orientation) { int rotation; // Monitors orientation values to determine the target rotation value if (orientation >= 45 && orientation < 135) { rotation = Surface.ROTATION_270; } else if (orientation >= 135 && orientation < 225) { rotation = Surface.ROTATION_180; } else if (orientation >= 225 && orientation < 315) { rotation = Surface.ROTATION_90; } else { rotation = Surface.ROTATION_0; } imageCapture.setTargetRotation(rotation); } }; orientationEventListener.enable(); }
Je nach festgelegter Drehung wird bei jedem Anwendungsfall entweder die Bilddaten direkt gedreht oder es werden Rotationsmetadaten für die Nutzer der nicht gedrehten Bilddaten bereitgestellt.
- Vorschau: Die Metadatenausgabe wird bereitgestellt, damit die Drehung der Zielauflösung mit
Preview.getTargetRotation()bekannt ist. - ImageAnalysis: Es wird eine Metadatenausgabe bereitgestellt, damit die Koordinaten des Bildzwischenspeichers relativ zu den Anzeigekoordinaten bekannt sind.
- ImageCapture: Die Exif-Metadaten des Bildes, der Zwischenspeicher oder sowohl der Zwischenspeicher als auch die Metadaten werden geändert, um die Rotationseinstellung zu berücksichtigen. Der geänderte Wert hängt von der HAL-Implementierung ab.
Zuschneiderechteck
Standardmäßig ist das Zuschneiderechteck das vollständige Pufferrechteck. Sie können sie mit ViewPort und UseCaseGroup anpassen. Durch das Gruppieren von Anwendungsfällen und das Festlegen des Darstellungsbereichs wird mit CameraX sichergestellt, dass die Zuschneiderechtecke aller Anwendungsfälle in der Gruppe auf denselben Bereich im Kamerasensor verweisen.
Das folgende Code-Snippet zeigt, wie diese beiden Klassen verwendet werden:
Kotlin
val viewPort = ViewPort.Builder(Rational(width, height), display.rotation).build() val useCaseGroup = UseCaseGroup.Builder() .addUseCase(preview) .addUseCase(imageAnalysis) .addUseCase(imageCapture) .setViewPort(viewPort) .build() cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, useCaseGroup)
Java
ViewPort viewPort = new ViewPort.Builder( new Rational(width, height), getDisplay().getRotation()).build(); UseCaseGroup useCaseGroup = new UseCaseGroup.Builder() .addUseCase(preview) .addUseCase(imageAnalysis) .addUseCase(imageCapture) .setViewPort(viewPort) .build(); cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, useCaseGroup);
ViewPort definiert das für Endnutzer sichtbare Pufferrechteck. Anschließend berechnet CameraX das größtmögliche Zuschneiderechteck basierend auf den Eigenschaften des Darstellungsbereichs und den angehängten Anwendungsfällen. Normalerweise können Sie den Darstellungsbereich basierend auf dem Vorschau-Anwendungsfall konfigurieren, um einen WYSIWYG-Effekt zu erzielen. Eine einfache Möglichkeit, den Darstellungsbereich abzurufen, ist die Verwendung von PreviewView.
Die folgenden Code-Snippets zeigen, wie Sie das ViewPort-Objekt abrufen:
Kotlin
val viewport = findViewById<PreviewView>(R.id.preview_view).viewPort
Java
ViewPort viewPort = ((PreviewView)findViewById(R.id.preview_view)).getViewPort();
Im vorherigen Beispiel entspricht das, was die App von ImageAnalysis und ImageCapture erhält, dem, was der Endnutzer in PreviewView sieht, vorausgesetzt, der Skalierungstyp von PreviewView ist auf den Standardwert FILL_CENTER festgelegt. Nachdem das Zuschneiderechteck und die Drehung auf den Ausgabepuffer angewendet wurden, ist das Bild aus allen Anwendungsfällen identisch, möglicherweise jedoch mit unterschiedlichen Auflösungen. Weitere Informationen zum Anwenden der Transformationsinformationen finden Sie unter Transformationsausgabe.
Kameraauswahl
CameraX wählt automatisch die beste Kamera für die Anforderungen und Anwendungsfälle Ihrer App aus. Wenn du ein anderes Gerät als das für dich ausgewählte verwenden möchtest, hast du folgende Möglichkeiten:
- Fordern Sie die standardmäßige Frontkamera mit
CameraSelector.DEFAULT_FRONT_CAMERAan. - Fordern Sie die standardmäßige Rückkamera mit
CameraSelector.DEFAULT_BACK_CAMERAan. - Filtern Sie die Liste der verfügbaren Geräte nach
CameraCharacteristicsmitCameraSelector.Builder.addCameraFilter().
Das folgende Codebeispiel zeigt, wie Sie ein CameraSelector erstellen, um die Geräteauswahl zu beeinflussen:
Kotlin
fun selectExternalOrBestCamera(provider: ProcessCameraProvider):CameraSelector? { val cam2Infos = provider.availableCameraInfos.map { Camera2CameraInfo.from(it) }.sortedByDescending { // HARDWARE_LEVEL is Int type, with the order of: // LEGACY < LIMITED < FULL < LEVEL_3 < EXTERNAL it.getCameraCharacteristic(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL) } return when { cam2Infos.isNotEmpty() -> { CameraSelector.Builder() .addCameraFilter { it.filter { camInfo -> // cam2Infos[0] is either EXTERNAL or best built-in camera val thisCamId = Camera2CameraInfo.from(camInfo).cameraId thisCamId == cam2Infos[0].cameraId } }.build() } else -> null } } // create a CameraSelector for the USB camera (or highest level internal camera) val selector = selectExternalOrBestCamera(processCameraProvider) processCameraProvider.bindToLifecycle(this, selector, preview, analysis)
Mehrere Kameras gleichzeitig auswählen
Ab CameraX 1.3 können Sie auch mehrere Kameras gleichzeitig auswählen. Du kannst beispielsweise eine Front- und eine Rückkamera binden, um gleichzeitig Fotos oder Videos aus beiden Perspektiven aufzunehmen.
Bei Verwendung der Funktion „Gleichzeitige Kamera“ kann das Gerät zwei Kameras mit unterschiedlich ausgerichteten Objektiven oder zwei Rückkameras gleichzeitig betreiben. Der folgende Codeblock zeigt, wie Sie beim Aufrufen von bindToLifecycle zwei Kameras festlegen und wie Sie beide Kameraobjekte aus dem zurückgegebenen ConcurrentCamera-Objekt abrufen.
Kotlin
// Build ConcurrentCameraConfig val primary = ConcurrentCamera.SingleCameraConfig( primaryCameraSelector, useCaseGroup, lifecycleOwner ) val secondary = ConcurrentCamera.SingleCameraConfig( secondaryCameraSelector, useCaseGroup, lifecycleOwner ) val concurrentCamera = cameraProvider.bindToLifecycle( listOf(primary, secondary) ) val primaryCamera = concurrentCamera.cameras[0] val secondaryCamera = concurrentCamera.cameras[1]
Java
// Build ConcurrentCameraConfig SingleCameraConfig primary = new SingleCameraConfig( primaryCameraSelector, useCaseGroup, lifecycleOwner ); SingleCameraConfig secondary = new SingleCameraConfig( primaryCameraSelector, useCaseGroup, lifecycleOwner ); ConcurrentCamera concurrentCamera = mCameraProvider.bindToLifecycle(Arrays.asList(primary, secondary)); Camera primaryCamera = concurrentCamera.getCameras().get(0); Camera secondaryCamera = concurrentCamera.getCameras().get(1);
Kameraauflösung
Sie können CameraX die Bildauflösung basierend auf einer Kombination aus den Gerätefunktionen, der unterstützten Hardwareebene des Geräts, dem Anwendungsfall und dem angegebenen Seitenverhältnis festlegen lassen. Alternativ können Sie in Anwendungsfällen, die diese Konfiguration unterstützen, eine bestimmte Zielauflösung oder ein bestimmtes Seitenverhältnis festlegen.
Automatische Auflösung
CameraX kann die besten Auflösungseinstellungen automatisch anhand der in cameraProcessProvider.bindToLifecycle() angegebenen Anwendungsfälle ermitteln. Geben Sie nach Möglichkeit alle Anwendungsfälle, die gleichzeitig in einer einzelnen Sitzung ausgeführt werden müssen, in einem einzigen bindToLifecycle()-Aufruf an. CameraX bestimmt die Auflösungen anhand der gebundenen Anwendungsfälle, indem die unterstützte Hardwarestufe des Geräts berücksichtigt und gerätespezifische Abweichungen berücksichtigt werden (wenn ein Gerät die verfügbaren Streamkonfigurationen überschreitet oder nicht erfüllt).
Die Anwendung soll auf einer Vielzahl von Geräten ausgeführt werden können, wobei gerätespezifische Codepfade minimiert werden sollen.
Das Standardseitenverhältnis für Anwendungsfälle der Bilderfassung und Bildanalyse ist 4:3.
Anwendungsfälle haben ein konfigurierbares Seitenverhältnis, damit die Anwendung das gewünschte Seitenverhältnis basierend auf dem UI-Design angeben kann. Die CameraX-Ausgabe wird so erzeugt, dass sie den angeforderten Seitenverhältnissen so weit wie möglich entspricht, wie es das Gerät unterstützt. Wenn keine Auflösung mit genauer Übereinstimmung unterstützt wird, wird die Auflösung ausgewählt, die die meisten Bedingungen erfüllt. Die Anwendung bestimmt also, wie die Kamera in der App angezeigt wird, und CameraX ermittelt die besten Einstellungen für die Kameraauflösung, um dies auf verschiedenen Geräten zu ermöglichen.
Eine App kann beispielsweise Folgendes tun:
- Zielauflösung von 4:3 oder 16:9 für einen Anwendungsfall angeben
- Benutzerdefinierte Auflösung angeben, für die CameraX versucht, die beste Übereinstimmung zu finden
- Seitenverhältnis für den Zuschneidebereich für
ImageCaptureangeben
CameraX wählt die internen Camera2-Oberflächenauflösungen automatisch aus. In der folgenden Tabelle sind die Auflösungen aufgeführt:
| Anwendungsfall | Auflösung der internen Oberfläche | Auflösung der Ausgabedaten |
|---|---|---|
| Vorschau | Seitenverhältnis: Die Auflösung, die am besten zum Ziel der Einstellung passt. | Interne Oberflächenauflösung. Es werden Metadaten bereitgestellt, damit eine Ansicht für das Zielseitenverhältnis zugeschnitten, skaliert und gedreht werden kann. |
| Standardauflösung:Höchste Vorschauauflösung oder höchste vom Gerät bevorzugte Auflösung, die dem Seitenverhältnis der Vorschau entspricht. | ||
| Maximale Auflösung:Vorschaugröße, die der besten Größe für die Bildschirmauflösung des Geräts entspricht, oder 1080p (1920 × 1080), je nachdem, welcher Wert kleiner ist. | ||
| Bildanalyse | Seitenverhältnis: Die Auflösung, die am besten zum Ziel und zur Einstellung passt. | Interne Oberflächenauflösung. |
| Standardauflösung: Die Standardeinstellung für die Zielauflösung ist 640 × 480. Wenn du sowohl die Zielauflösung als auch das entsprechende Seitenverhältnis anpasst, erhältst du die am besten unterstützte Auflösung. | ||
Maximale Auflösung:Die maximale Ausgabeauflösung des Kamerageräts im Format YUV_420_888, die von StreamConfigurationMap.getOutputSizes() abgerufen wird.
Die Zielauflösung ist standardmäßig auf 640 × 480 festgelegt. Wenn Sie eine Auflösung größer als 640 × 480 wünschen, müssen Sie setTargetResolution() und setTargetAspectRatio() verwenden, um die nächstgelegene Auflösung aus den unterstützten Auflösungen zu erhalten.
|
||
| Bilderfassung | Seitenverhältnis:Seitenverhältnis, das am besten zur Einstellung passt. | Interne Oberflächenauflösung. |
| Standardauflösung:Höchste verfügbare Auflösung oder höchste vom Gerät bevorzugte Auflösung, die dem Seitenverhältnis von ImageCapture entspricht. | ||
Maximale Auflösung:Die maximale Ausgabeauflösung des Kamerageräts im JPEG-Format. Verwende die StreamConfigurationMap.getOutputSizes(), um diese abzurufen.
|
Auflösung angeben
Sie können bestimmte Auflösungen festlegen, wenn Sie Anwendungsfälle mit der Methode setTargetResolution(Size resolution) erstellen, wie im folgenden Codebeispiel gezeigt:
Kotlin
val imageAnalysis = ImageAnalysis.Builder() .setTargetResolution(Size(1280, 720)) .build()
Java
ImageAnalysis imageAnalysis = new ImageAnalysis.Builder() .setTargetResolution(new Size(1280, 720)) .build();
Sie können nicht sowohl das Zielseitenverhältnis als auch die Zielauflösung für denselben Anwendungsfall festlegen. Andernfalls wird beim Erstellen des Konfigurationsobjekts ein IllegalArgumentException-Fehler ausgegeben.
Geben Sie die Auflösung Size im Koordinatensystem an, nachdem Sie die unterstützten Größen um die Zieldrehung gedreht haben. Beispiel: Ein Gerät mit natürlicher Ausrichtung im Hochformat, das ein Bild im Hochformat anfordert, kann 480 × 640 angeben. Dasselbe Gerät, das um 90 Grad gedreht ist und auf das Querformat ausgerichtet ist, kann 640 × 480 angeben.
Mit der Zielauflösung wird versucht, eine Mindestgrenze für die Bildauflösung festzulegen. Die tatsächliche Bildauflösung ist die nächstgelegene verfügbare Auflösung, die nicht kleiner als die Zielauflösung ist, wie von der Kameraimplementierung festgelegt.
Wenn jedoch keine Auflösung vorhanden ist, die der Zielauflösung entspricht oder größer ist, wird die nächstgelegene verfügbare Auflösung ausgewählt, die kleiner als die Zielauflösung ist. Auflösungen mit demselben Seitenverhältnis wie der angegebene Size haben eine höhere Priorität als Auflösungen mit anderen Seitenverhältnissen.
CameraX wendet die am besten geeignete Auflösung basierend auf den Anfragen an. Wenn das primäre Ziel darin besteht, das Seitenverhältnis zu erfüllen, geben Sie nur setTargetAspectRatio an. CameraX bestimmt dann eine geeignete Auflösung basierend auf dem Gerät.
Wenn die App hauptsächlich eine Auflösung angeben muss, um die Bildverarbeitung effizienter zu gestalten (z. B. ein kleines oder mittelgroßes Bild basierend auf der Verarbeitungsleistung des Geräts), verwende setTargetResolution(Size resolution).
Wenn Ihre Anwendung eine genaue Auflösung erfordert, sehen Sie sich die Tabelle unter createCaptureSession() an, um zu ermitteln, welche maximalen Auflösungen von den einzelnen Hardwarestufen unterstützt werden. Informationen zu den vom aktuellen Gerät unterstützten Auflösungen findest du unter StreamConfigurationMap.getOutputSizes(int).
Wenn Ihre App unter Android 10 oder höher ausgeführt wird, können Sie isSessionConfigurationSupported() verwenden, um eine bestimmte SessionConfiguration zu prüfen.
Kameraausgabe steuern
Mit CameraX kannst du nicht nur die Kameraausgabe für jeden einzelnen Anwendungsfall nach Bedarf konfigurieren, sondern auch die folgenden Schnittstellen implementieren, um Kameravorgänge zu unterstützen, die für alle gebundenen Anwendungsfälle gelten:
- Mit
CameraControlkönnen Sie gängige Kamerafunktionen konfigurieren. - Mit
CameraInfokönnen Sie den Status dieser gängigen Kamerafunktionen abfragen.
Folgende Kamerafunktionen werden mit CameraControl unterstützt:
- Zoom
- Fackel
- Fokus und Belichtung (Tippen zum Fokussieren)
- Belichtungskorrektur
Instanzen von CameraControl und CameraInfo abrufen
Rufen Sie Instanzen von CameraControl und CameraInfo mit dem Objekt Camera ab, das von ProcessCameraProvider.bindToLifecycle() zurückgegeben wird.
Der folgende Code zeigt ein Beispiel:
Kotlin
val camera = processCameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview) // For performing operations that affect all outputs. val cameraControl = camera.cameraControl // For querying information and states. val cameraInfo = camera.cameraInfo
Java
Camera camera = processCameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview) // For performing operations that affect all outputs. CameraControl cameraControl = camera.getCameraControl() // For querying information and states. CameraInfo cameraInfo = camera.getCameraInfo()
Sie können beispielsweise Zoom- und andere CameraControl-Vorgänge nach dem Aufruf von bindToLifecycle() senden. Nachdem Sie die Aktivität beendet oder gelöscht haben, die zum Binden der Kamerainstanz verwendet wurde, kann CameraControl keine Vorgänge mehr ausführen und gibt einen fehlgeschlagenen ListenableFuture zurück.
Zoom
„CameraControl“ bietet zwei Methoden zum Ändern der Zoomstufe:
setZoomRatio()legt den Zoom anhand des Zoomverhältnisses fest.Das Verhältnis muss im Bereich von
CameraInfo.getZoomState().getValue().getMinZoomRatio()undCameraInfo.getZoomState().getValue().getMaxZoomRatio()liegen. Andernfalls gibt die Funktion einen fehlgeschlagenenListenableFuturezurück.setLinearZoom()legt den aktuellen Zoom mit einem linearen Zoomwert zwischen 0 und 1,0 fest.Der Vorteil des linearen Zooms besteht darin, dass das Sichtfeld (Field of View, FOV) mit Änderungen des Zooms skaliert wird. Daher eignet es sich ideal für die Verwendung mit einer
Slider-Ansicht.
CameraInfo.getZoomState() gibt ein LiveData-Objekt des aktuellen Zoomstatus zurück. Der Wert ändert sich, wenn die Kamera initialisiert wird oder die Zoomstufe mit setZoomRatio() oder setLinearZoom() festgelegt wird. Durch den Aufruf einer der beiden Methoden werden die Werte für ZoomState.getZoomRatio() und ZoomState.getLinearZoom() festgelegt.
Das ist hilfreich, wenn Sie neben einem Schieberegler Text zum Zoomverhältnis anzeigen möchten.
Beobachten Sie einfach die ZoomState LiveData, um beide zu aktualisieren, ohne eine Konvertierung durchführen zu müssen.
Der von beiden APIs zurückgegebene ListenableFuture bietet Anwendungen die Möglichkeit, benachrichtigt zu werden, wenn eine wiederholte Anfrage mit dem angegebenen Zoomwert abgeschlossen ist. Wenn Sie einen neuen Zoomwert festlegen, während der vorherige Vorgang noch ausgeführt wird, schlägt das ListenableFuture des vorherigen Zoomvorgangs sofort fehl.
Fackel
Mit CameraControl.enableTorch(boolean) wird die Taschenlampe aktiviert oder deaktiviert.
Mit CameraInfo.getTorchState() kann der aktuelle Status der Taschenlampe abgefragt werden. Sie können den von CameraInfo.hasFlashUnit() zurückgegebenen Wert prüfen, um festzustellen, ob eine Taschenlampe verfügbar ist. Andernfalls führt der Aufruf von CameraControl.enableTorch(boolean) dazu, dass die zurückgegebene ListenableFuture sofort mit einem fehlgeschlagenen Ergebnis abgeschlossen wird und der Status des Blitzes auf TorchState.OFF gesetzt wird.
Wenn die Taschenlampe aktiviert ist, bleibt sie während der Foto- und Videoaufnahme eingeschaltet, unabhängig von der Einstellung für „flashMode“. Die flashMode in ImageCapture funktioniert nur, wenn die Taschenlampe deaktiviert ist.
Fokus und Messung
CameraControl.startFocusAndMetering() löst den Autofokus und die Belichtungsmessung aus, indem AF/AE/AWB-Messbereiche basierend auf der angegebenen FocusMeteringAction festgelegt werden. Dies wird häufig verwendet, um die Funktion „Zum Fokussieren tippen“ in vielen Kamera-Apps zu implementieren.
MeteringPoint
Erstellen Sie zuerst mit MeteringPointFactory.createPoint(float x, float y, float
size) ein MeteringPoint.
Ein MeteringPoint stellt einen einzelnen Punkt auf der Surface der Kamera dar. Sie werden in einer normalisierten Form gespeichert, damit sie leicht in Sensorkoordinaten für die Angabe von AF/AE/AWB-Regionen umgewandelt werden können.
Die Größe des MeteringPoint liegt zwischen 0 und 1, wobei die Standardgröße 0,15f beträgt. Beim Aufrufen von MeteringPointFactory.createPoint(float x, float y, float
size) erstellt CameraX einen rechteckigen Bereich, der auf (x, y) für die angegebene size zentriert ist.
Der folgende Code zeigt, wie Sie einen MeteringPoint erstellen:
Kotlin
// Use PreviewView.getMeteringPointFactory if PreviewView is used for preview. previewView.setOnTouchListener((view, motionEvent) -> { val meteringPoint = previewView.meteringPointFactory .createPoint(motionEvent.x, motionEvent.y) … } // Use DisplayOrientedMeteringPointFactory if SurfaceView / TextureView is used for // preview. Please note that if the preview is scaled or cropped in the View, // it’s the application's responsibility to transform the coordinates properly // so that the width and height of this factory represents the full Preview FOV. // And the (x,y) passed to create MeteringPoint might need to be adjusted with // the offsets. val meteringPointFactory = DisplayOrientedMeteringPointFactory( surfaceView.display, camera.cameraInfo, surfaceView.width, surfaceView.height ) // Use SurfaceOrientedMeteringPointFactory if the point is specified in // ImageAnalysis ImageProxy. val meteringPointFactory = SurfaceOrientedMeteringPointFactory( imageWidth, imageHeight, imageAnalysis)
startFocusAndMetering und FocusMeteringAction
Um startFocusAndMetering() aufzurufen, müssen Anwendungen eine FocusMeteringAction erstellen, die aus einer oder mehreren MeteringPoints mit optionalen Kombinationen von Messmodi aus FLAG_AF, FLAG_AE, FLAG_AWB besteht. Der folgende Code veranschaulicht diese Verwendung:
Kotlin
val meteringPoint1 = meteringPointFactory.createPoint(x1, x1) val meteringPoint2 = meteringPointFactory.createPoint(x2, y2) val action = FocusMeteringAction.Builder(meteringPoint1) // default AF|AE|AWB // Optionally add meteringPoint2 for AF/AE. .addPoint(meteringPoint2, FLAG_AF | FLAG_AE) // The action is canceled in 3 seconds (if not set, default is 5s). .setAutoCancelDuration(3, TimeUnit.SECONDS) .build() val result = cameraControl.startFocusAndMetering(action) // Adds listener to the ListenableFuture if you need to know the focusMetering result. result.addListener({ // result.get().isFocusSuccessful returns if the auto focus is successful or not. }, ContextCompat.getMainExecutor(this)
Wie im vorherigen Code gezeigt, verwendet startFocusAndMetering() einen FocusMeteringAction, der aus einem MeteringPoint für AF/AE/AWB-Messbereiche und einem weiteren MeteringPoint nur für AF und AE besteht.
Intern konvertiert CameraX sie in Camera2-MeteringRectangles und legt die entsprechenden Parameter CONTROL_AF_REGIONS/CONTROL_AE_REGIONS/CONTROL_AWB_REGIONS für die Aufnahmeanfrage fest.
Da nicht jedes Gerät AF/AE/AWB und mehrere Regionen unterstützt, führt CameraX die FocusMeteringAction nach bestem Wissen und Gewissen aus. CameraX verwendet die maximal unterstützte Anzahl von MeteringPoints in der Reihenfolge, in der die Punkte hinzugefügt wurden. Alle MeteringPoints, die nach der maximalen Anzahl hinzugefügt werden, werden ignoriert. Wenn beispielsweise ein FocusMeteringAction mit drei MeteringPoints auf einer Plattform bereitgestellt wird, die nur zwei unterstützt, werden nur die ersten beiden MeteringPoints verwendet. Das letzte MeteringPoint wird von CameraX ignoriert.
Belichtungskorrektur
Die Belichtungskorrektur ist nützlich, wenn Anwendungen die Belichtungswerte (EV) über das Ergebnis der automatischen Belichtung (AE) hinaus optimieren müssen. Die Werte für die Belichtungskorrektur werden folgendermaßen kombiniert, um die erforderliche Belichtung für die aktuellen Bildbedingungen zu bestimmen:
Exposure = ExposureCompensationIndex * ExposureCompensationStep
CameraX bietet die Funktion Camera.CameraControl.setExposureCompensationIndex(), mit der die Belichtungskorrektur als Indexwert festgelegt werden kann.
Positive Indexwerte machen das Bild heller, negative Werte dunkler. Anwendungen können den unterstützten Bereich mit CameraInfo.ExposureState.exposureCompensationRange() abfragen, wie im nächsten Abschnitt beschrieben. Wenn der Wert unterstützt wird, wird der zurückgegebene ListenableFuture abgeschlossen, wenn der Wert in der Erfassungsanfrage erfolgreich aktiviert wurde. Wenn der angegebene Index außerhalb des unterstützten Bereichs liegt, wird der zurückgegebene ListenableFuture durch setExposureCompensationIndex() sofort mit einem fehlgeschlagenen Ergebnis abgeschlossen.
CameraX behält nur die letzte ausstehende setExposureCompensationIndex()-Anfrage bei. Wenn die Funktion mehrmals aufgerufen wird, bevor die vorherige Anfrage ausgeführt wird, wird sie abgebrochen.
Im folgenden Snippet wird ein Index für die Belichtungskorrektur festgelegt und ein Callback registriert, der ausgeführt wird, wenn die Anfrage zur Belichtungsänderung ausgeführt wurde:
Kotlin
camera.cameraControl.setExposureCompensationIndex(exposureCompensationIndex) .addListener({ // Get the current exposure compensation index, it might be // different from the asked value in case this request was // canceled by a newer setting request. val currentExposureIndex = camera.cameraInfo.exposureState.exposureCompensationIndex … }, mainExecutor)
Camera.CameraInfo.getExposureState()ruft die aktuelleExposureStateab, einschließlich:- Die Unterstützung der Belichtungskorrektur.
- Der aktuelle Index für die Belichtungskorrektur.
- Der Indexbereich für die Belichtungskorrektur.
- Der Schritt der Belichtungskorrektur, der bei der Berechnung des Belichtungskorrekturwerts verwendet wird.
Im folgenden Code werden beispielsweise die Einstellungen für eine Belichtung SeekBar mit aktuellen ExposureState-Werten initialisiert:
Kotlin
val exposureState = camera.cameraInfo.exposureState binding.seekBar.apply { isEnabled = exposureState.isExposureCompensationSupported max = exposureState.exposureCompensationRange.upper min = exposureState.exposureCompensationRange.lower progress = exposureState.exposureCompensationIndex }
Zusätzliche Ressourcen
Weitere Informationen zu CameraX findest du in den folgenden zusätzlichen Ressourcen.
Codelab
Codebeispiel