Sie konfigurieren jeden CameraX-Anwendungsfall so, dass verschiedene Aspekte der Vorgänge des Anwendungsfalls gesteuert werden.
Für den Anwendungsfall der Bilderfassung können Sie beispielsweise ein Zielseitenverhä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();
Neben den Konfigurationsoptionen bieten einige Anwendungsfälle APIs auch, um Einstellungen dynamisch zu ändern, nachdem der Anwendungsfall erstellt wurde. Informationen zur Konfiguration, die für die einzelnen Anwendungsfälle spezifisch ist, finden Sie unter Vorschau implementieren, Bilder analysieren und Image-Aufnahme.
CameraXConfig
Der Einfachheit halber verfügt CameraX über Standardkonfigurationen wie interne Executors und Handler, die für die meisten Nutzungsszenarien geeignet sind. Wenn Ihre Anwendung jedoch besondere Anforderungen hat oder diese Konfigurationen anpassen möchte, ist CameraXConfig
die Schnittstelle für diesen Zweck.
Mit CameraXConfig
kann eine Anwendung Folgendes tun:
- Optimieren Sie die Startlatenz mit
setAvailableCameraLimiter()
. - Stellen Sie den Executor der Anwendung für CameraX mit
setCameraExecutor()
bereit. - Ersetzen Sie den Standard-Planer-Handler durch
setSchedulerHandler()
. - Ändern Sie die Logging-Ebene mit
setMinimumLoggingLevel()
.
Nutzungsmodell
Im Folgenden wird die Verwendung von CameraXConfig
beschrieben:
- Erstellen Sie ein
CameraXConfig
-Objekt mit Ihren benutzerdefinierten Konfigurationen. - Implementiere die Schnittstelle
CameraXConfig.Provider
inApplication
und gib das ObjektCameraXConfig
ingetCameraXConfig()
zurück. - Fügen Sie die Klasse
Application
der DateiAndroidManifest.xml
hinzu, wie hier beschrieben.
Das folgende Codebeispiel beschränkt die CameraX-Protokollierung auf Fehlermeldungen:
Kotlin
class CameraApplication : Application(), CameraXConfig.Provider { override fun getCameraXConfig(): CameraXConfig { return CameraXConfig.Builder.fromConfig(Camera2Config.defaultConfig()) .setMinimumLoggingLevel(Log.ERROR).build() } }
Speichern Sie eine lokale Kopie des CameraXConfig
-Objekts, wenn Ihre Anwendung die CameraX-Konfiguration nach dem Festlegen kennen muss.
Kamerabegrenzer
Beim ersten Aufruf von ProcessCameraProvider.getInstance()
listet CameraX die Eigenschaften der auf dem Gerät verfügbaren Kameras auf und fragt diese ab. Da CameraX mit Hardwarekomponenten kommunizieren muss, kann dieser Prozess für jede Kamera, insbesondere auf Low-End-Geräten, sehr viel Zeit in Anspruch nehmen. Wenn Ihre Anwendung nur bestimmte Kameras auf dem Gerät verwendet, z. B. die Standard-Frontkamera, können Sie CameraX so einstellen, dass andere Kameras ignoriert werden. Dadurch kann die Startlatenz für die von Ihrer Anwendung verwendeten Kameras reduziert werden.
Wenn das an CameraXConfig.Builder.setAvailableCamerasLimiter()
übergebene CameraSelector
-Element eine Kamera herausfiltert, verhält sich CameraX so, als wäre diese Kamera nicht vorhanden. Der folgende Code schränkt die Anwendung beispielsweise so ein, dass nur die Standard-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() } }
Unterhaltungen
Viele der Plattform-APIs, auf denen CameraX basiert, erfordern eine Blockierung der Interprozesskommunikation (IPC) mit Hardware, die manchmal Hunderte von Millisekunden in Anspruch nehmen kann. Aus diesem Grund ruft CameraX diese APIs nur aus 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 von Threads. Mit CameraXConfig
kann eine Anwendung die Hintergrundthreads festlegen, die über CameraXConfig.Builder.setCameraExecutor()
und CameraXConfig.Builder.setSchedulerHandler()
verwendet werden.
Kamera-Executor
Der Camera Executor wird für alle API-Aufrufe der internen Kameraplattform sowie für Callbacks von diesen APIs verwendet. CameraX weist ein internes Executor
zu und verwaltet es für diese Aufgaben.
Wenn Ihre Anwendung jedoch eine strengere Steuerung von Threads erfordert, verwenden Sie CameraXConfig.Builder.setCameraExecutor()
.
Planer-Handler
Mit dem Planer-Handler werden interne Aufgaben in festen Intervallen geplant, z. B. wird versucht, die Kamera zu öffnen, wenn sie nicht verfügbar ist. Dieser Handler führt keine Jobs aus, sondern leitet sie nur an den Kamera-Executor weiter. Es wird manchmal auch auf den Legacy-API-Plattformen verwendet, die Handler
für Callbacks erfordern. In diesen Fällen werden die Callbacks nur direkt an den Camera-Executor weitergeleitet. CameraX weist ein internes HandlerThread
für diese Aufgaben zu und verwaltet es. Sie können es jedoch mit CameraXConfig.Builder.setSchedulerHandler()
überschreiben.
Protokollierung
Mit der CameraX-Protokollierung können Anwendungen Logcat-Nachrichten filtern, da es sich bewährt hat, ausführliche Meldungen in Ihrem Produktionscode zu vermeiden. CameraX unterstützt vier Protokollierungsstufen, von der ausführlichsten bis zur schwerwiegendsten:
Log.DEBUG
(Standard)Log.INFO
Log.WARN
Log.ERROR
Ausführliche Beschreibungen dieser Logebenen finden Sie in der Android-Log-Dokumentation. Verwenden Sie CameraXConfig.Builder.setMinimumLoggingLevel(int)
, um die geeignete Logging-Ebene für Ihre Anwendung festzulegen.
Automatische Auswahl
CameraX bietet automatisch gerätespezifische Funktionen. Beispielsweise ermittelt CameraX automatisch die beste Auflösung, wenn du keine Auflösung angibst oder die von dir angegebene Auflösung nicht unterstützt wird. All dies wird von der Bibliothek verarbeitet, sodass Sie keinen gerätespezifischen Code schreiben müssen.
Das Ziel von CameraX ist es, eine Kamerasitzung erfolgreich zu initialisieren. Das bedeutet, dass bei CameraX die Auflösung und das Seitenverhältnis je nach Gerätefunktion beeinträchtigt werden. 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 erfordern, um richtig zu funktionieren.
- Auf einigen Geräten sind bestimmte Formate nur in bestimmten Seitenverhältnissen verfügbar.
- Das Gerät bevorzugt für JPEG- oder Videocodierungen die nächste mod16-Version. Weitere Informationen finden Sie unter
SCALER_STREAM_CONFIGURATION_MAP
.
Obwohl KameraX die Sitzung erstellt und verwaltet, sollten Sie immer die zurückgegebenen Bildgrößen in der Anwendungsfallausgabe in Ihrem Code prüfen und entsprechend anpassen.
Drehung
Standardmäßig ist die Kameradrehung so eingestellt, dass sie der Drehung des Standardbildschirms beim Erstellen des Anwendungsfalls entspricht. In diesem Standardfall liefert CameraX Ausgaben, damit die App dem entspricht, was Sie in der Vorschau sehen möchten. Sie können die Rotation in einen benutzerdefinierten Wert ändern, um Geräte mit mehreren Displays zu unterstützen. Dazu übergeben Sie beim Konfigurieren von Anwendungsfallobjekten die aktuelle Displayausrichtung 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. Sie können diese Option verwenden, wenn die App auf das Hochformat eingestellt ist und bei der Rotation keine Neukonfiguration stattfindet. Beim Foto- oder Analyseanwendungsfall muss jedoch die aktuelle Gerätedrehung berücksichtigt werden. Beispielsweise kann eine Rotationserkennung erforderlich sein, damit Gesichter richtig für die Gesichtserkennung ausgerichtet sind, oder Fotos werden auf Quer- oder Hochformat eingestellt.
Daten für erfasste Bilder können ohne Rotationsinformationen gespeichert werden. EXIF-Daten enthalten Rotationsinformationen, sodass Galerieanwendungen das Bild nach dem Speichern in der richtigen Ausrichtung anzeigen können.
Damit Vorschaudaten mit der richtigen Ausrichtung angezeigt werden, können Sie die Metadatenausgabe von Preview.PreviewOutput()
verwenden, um Transformationen zu erstellen.
Das folgende Codebeispiel zeigt, wie die Rotation 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(); }
Basierend auf der festgelegten Rotation werden in jedem Anwendungsfall entweder die Bilddaten direkt gedreht oder den Nutzern der nicht gedrehten Bilddaten Rotationsmetadaten bereitgestellt.
- Vorabversion: Eine Metadatenausgabe wird bereitgestellt, damit die Rotation der Zielauflösung mithilfe von
Preview.getTargetRotation()
bekannt ist. - ImageAnalysis: Die Metadatenausgabe wird bereitgestellt, sodass die Bildzwischenspeicherkoordinaten relativ zu den Anzeigekoordinaten bekannt sind.
- ImageCapture: Die Metadaten des EXIF-Bilds, der Zwischenspeicher oder beide Zwischenspeicher und die Metadaten werden entsprechend der Rotationseinstellung geändert. Der geänderte Wert hängt von der HAL-Implementierung ab.
Rechteck zuschneiden
Standardmäßig entspricht das Rechteck zuschneiden dem vollständigen Zwischenspeicher. Sie können ihn mit ViewPort
und UseCaseGroup
anpassen. Durch das Gruppieren von Anwendungsfällen und das Festlegen des Darstellungsbereichs sorgt CameraX dafür, dass der Zuschnitt aller Anwendungsfälle in der Gruppe auf denselben Bereich im Kamerasensor verweist.
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 Zwischenspeicherrechteck, das für Endnutzer sichtbar ist. Anschließend berechnet CameraX anhand der Eigenschaften des Darstellungsbereichs und der angehängten Anwendungsfälle den größtmöglichen Zuschneidebereich. Normalerweise können Sie den Darstellungsbereich basierend auf dem Anwendungsfall der Vorschau konfigurieren, um einen WYSIWYG-Effekt zu erzielen. Eine einfache Möglichkeit zum Abrufen des Darstellungsbereichs ist PreviewView
.
Die folgenden Code-Snippets zeigen, wie das Objekt ViewPort
abgerufen wird:
Kotlin
val viewport = findViewById<PreviewView>(R.id.preview_view).viewPort
Java
ViewPort viewPort = ((PreviewView)findViewById(R.id.preview_view)).getViewPort();
Im vorherigen Beispiel stimmen die Informationen, die die Anwendung von ImageAnalysis
und ImageCapture
erhält, mit dem überein, was der Endnutzer in PreviewView
sieht, vorausgesetzt, der Skalierungstyp von PreviewView
ist auf die Standardeinstellung FILL_CENTER
festgelegt. Nach Anwendung des Zuschneidebereichs und der Drehung auf den Ausgabezwischenspeicher ist das Bild aus allen Anwendungsfällen dasselbe, allerdings mit unterschiedlichen Auflösungen. Weitere Informationen zum Anwenden der Transformationsinformationen finden Sie unter Transformationsausgabe.
Kameraauswahl
CameraX wählt automatisch das beste Kameragerät für die Anforderungen und Anwendungsfälle Ihrer Anwendung aus. Wenn Sie ein anderes Gerät als das für Sie ausgewählte verwenden möchten, haben Sie mehrere Möglichkeiten:
- Fordern Sie die Standard-Frontkamera mit
CameraSelector.DEFAULT_FRONT_CAMERA
an. - Mit
CameraSelector.DEFAULT_BACK_CAMERA
kannst du die Standardrückkamera anfordern. - Filtere die Liste der verfügbaren Geräte nach
CameraCharacteristics
mitCameraSelector.Builder.addCameraFilter()
.
Das folgende Codebeispiel zeigt, wie Sie eine 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. Sie können beispielsweise eine Bindung an eine Front- und Rückkamera herstellen, um Fotos oder Videos aus beiden Perspektiven gleichzeitig aufzunehmen.
Wenn die Funktion „Gleichzeitige Kamera“ verwendet wird, kann das Gerät zwei Kameras mit unterschiedlichen Objektiven gleichzeitig oder zwei Rückkameras gleichzeitig bedienen. Der folgende Codeblock zeigt, wie zwei Kameras beim Aufrufen von bindToLifecycle
eingerichtet werden und wie beide Kameraobjekte aus dem zurückgegebenen ConcurrentCamera
-Objekt abgerufen werden.
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
Du kannst KameraX die Bildauflösung anhand einer Kombination aus Gerätefunktionen, unterstützter Hardware, Anwendungsfall und bereitgestelltem 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 anhand der in cameraProcessProvider.bindToLifecycle()
angegebenen Anwendungsfälle automatisch die besten Auflösungseinstellungen ermitteln. Geben Sie nach Möglichkeit alle Anwendungsfälle an, die gleichzeitig in einer einzelnen Sitzung in einem einzigen bindToLifecycle()
-Aufruf ausgeführt werden sollen. CameraX bestimmt die Auflösungen anhand der Gruppe von Anwendungsfällen, die auf der unterstützten Hardwareebene des Geräts festgelegt sind. Außerdem werden gerätespezifische Abweichungen berücksichtigt, z. B. wenn ein Gerät die verfügbaren Streamkonfigurationen überschreitet oder nicht erfüllt.
Damit soll die Anwendung auf einer Vielzahl von Geräten ausgeführt werden und gleichzeitig gerätespezifische Codepfade minimiert werden.
Das Standardseitenverhältnis für die Bilderfassung und ‐analyse beträgt 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 Ausgabe von CameraX wird so erzeugt, dass sie den vom Gerät unterstützten Seitenverhältnissen möglichst genau entspricht. Wenn keine Auflösung für genaue Übereinstimmung unterstützt wird, wird diejenige ausgewählt, die die meisten Bedingungen erfüllt. Die Anwendung gibt also vor, wie die Kamera in der App angezeigt wird, und CameraX ermittelt die beste Kameraauflösung, um dies auf verschiedenen Geräten zu erreichen.
Eine App kann beispielsweise Folgendes tun:
- Geben Sie für einen Anwendungsfall eine Zielauflösung von 4:3 oder 16:9 an
- Geben Sie eine benutzerdefinierte Auflösung an, mit der CameraX die beste Übereinstimmung mit
- Seitenverhältnis für den Zuschnitt für
ImageCapture
angeben
CameraX wählt die Oberflächenauflösungen von Camera2 automatisch aus. Die folgende Tabelle zeigt die Lösungen:
Anwendungsfall | Interne Oberflächenauflösung | Auflösung der Ausgabedaten |
---|---|---|
Vorschau | Seitenverhältnis:Die Auflösung, die am besten zum Ziel passt. | Interne Oberflächenauflösung. Metadaten werden bereitgestellt, damit eine Ansicht das Seitenverhältnis entsprechend dem Zielseitenverhältnis zuschneiden, skalieren und drehen 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 sich auf die beste Größe für die Bildschirmauflösung des Geräts bezieht, oder 1080p (1920 × 1080), je nachdem, welcher Wert kleiner ist. | ||
Bildanalyse | Seitenverhältnis:Die Auflösung, die am besten zum Ziel passt. | Interne Oberflächenauflösung. |
Standardauflösung:Die Standardeinstellung für die Zielauflösung ist 640 x 480. Wenn du sowohl die Zielauflösung als auch das entsprechende Seitenverhältnis anpasst, wird die Auflösung am besten unterstützt. | ||
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 640 × 480. Wenn du also eine höhere Auflösung als 640 × 480 möchtest, musst du setTargetResolution() und setTargetAspectRatio() verwenden, um die nächstgelegene Auflösung zu erhalten.
|
||
Bildaufnahme | Seitenverhältnis:Das am besten zur Einstellung passende Seitenverhältnis. | Interne Oberflächenauflösung. |
Standardauflösung: Höchste verfügbare oder höchste vom Gerät bevorzugte Auflösung, die dem Seitenverhältnis von ImageCapture entspricht. | ||
Maximale Auflösung:Die maximale Ausgabeauflösung der Kamera im JPEG-Format. Verwenden Sie StreamConfigurationMap.getOutputSizes() , um diese abzurufen.
|
Auflösung angeben
Beim Erstellen von Anwendungsfällen können Sie mit der Methode setTargetResolution(Size resolution)
bestimmte Auflösungen festlegen, 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();
Es ist nicht möglich, für denselben Anwendungsfall sowohl das Zielseitenverhältnis als auch die Zielauflösung festzulegen. Dadurch wird beim Erstellen des Konfigurationsobjekts ein IllegalArgumentException
ausgelöst.
Geben Sie die Auflösung Size
im Koordinaten-Frame an, nachdem Sie die unterstützten Größen durch die Zieldrehung gedreht haben. Ein Gerät mit natürlicher Hochformatausrichtung in natürlicher Zielrotation, das ein Hochformatbild anfordert, kann beispielsweise 480 × 640 angeben. Auf demselben Gerät kann für eine 90-Grad-Drehung und für das Querformat 640 × 480 festgelegt werden.
Mit der Zielauflösung wird versucht, eine Mindestgrenze für die Bildauflösung festzulegen. Die tatsächliche Bildauflösung entspricht der nächstgelegenen verfügbaren Auflösung, die nicht kleiner als die Zielauflösung ist, die von der Kameraimplementierung festgelegt wird.
Ist jedoch keine Auflösung vorhanden, die gleich oder größer als die Zielauflösung ist, wird die nächstgelegene verfügbare Auflösung ausgewählt, die kleiner als die Zielauflösung ist. Auflösungen, die mit dem angegebenen Seitenverhältnis für Size
übereinstimmen, haben eine höhere Priorität als Auflösungen mit anderen Seitenverhältnissen.
CameraX wendet je nach den Anforderungen die am besten geeignete Auflösung an. Wenn das Seitenverhältnis in erster Linie wichtig ist, geben Sie nur setTargetAspectRatio
an und CameraX bestimmt eine bestimmte Auflösung, die auf dem Gerät geeignet ist.
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 Geräteverarbeitungsfunktion), verwenden Sie setTargetResolution(Size resolution)
.
Wenn für Ihre Anwendung eine genaue Auflösung erforderlich ist, sehen Sie in der Tabelle unter createCaptureSession()
nach, welche maximalen Auflösungen auf den einzelnen Hardwareebenen unterstützt werden. Die spezifischen Auflösungen, die vom aktuellen Gerät unterstützt werden, findest du unter StreamConfigurationMap.getOutputSizes(int)
.
Wenn deine App unter Android 10 oder höher läuft, kannst du mit isSessionConfigurationSupported()
eine bestimmte SessionConfiguration
bestätigen.
Kameraausgabe steuern
Mit CameraX können Sie nicht nur die Kameraausgabe für jeden einzelnen Anwendungsfall entsprechend konfigurieren, sondern auch die folgenden Schnittstellen, um Kameravorgänge für alle gebundenen Anwendungsfälle zu unterstützen:
- Mit
CameraControl
kannst du gängige Kamerafunktionen konfigurieren. - Mit
CameraInfo
können Sie den Status dieser gängigen Kamerafunktionen abfragen.
Folgende Kamerafunktionen werden von CameraControl unterstützt:
- Zoom
- Fackel
- Fokus und Belichtungsmessung (Zum Fokussieren tippen)
- Belichtungskorrektur
Instanzen von CameraControl und CameraInfo abrufen
Rufen Sie die 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 senden, nachdem Sie bindToLifecycle()
aufgerufen haben. Nachdem Sie die zum Binden der Kamerainstanz verwendete Aktivität beendet oder gelöscht haben, kann CameraControl
keine Vorgänge mehr ausführen und gibt eine fehlgeschlagene ListenableFuture
zurück.
Zoom
CameraControl bietet zwei Methoden zum Ändern der Zoomstufe:
Mit
setZoomRatio()
wird der Zoom anhand des Zoomverhältnisses festgelegt.Das Verhältnis muss zwischen
CameraInfo.getZoomState().getValue().getMinZoomRatio()
undCameraInfo.getZoomState().getValue().getMaxZoomRatio()
liegen. Andernfalls gibt die Funktion einen fehlgeschlagenenListenableFuture
zurück.Mit
setLinearZoom()
wird der aktuelle Zoom auf einen linearen Zoomwert zwischen 0 und 1,0 festgelegt.Der Vorteil des linearen Zooms besteht darin, dass das Sichtfeld bei Änderungen des Zoomfaktors skaliert wird. Daher eignet er sich ideal für die Verwendung mit einer
Slider
-Ansicht.
CameraInfo.getZoomState()
gibt LiveData des aktuellen Zoomstatus zurück. Der Wert ändert sich, wenn die Kamera initialisiert 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.
Dies ist hilfreich, wenn Sie Text für das Zoomverhältnis neben einem Schieberegler anzeigen lassen möchten.
Achten Sie einfach auf ZoomState
LiveData
, um beide zu aktualisieren, ohne eine Conversion ausführen zu müssen.
Mit der von beiden APIs zurückgegebenen ListenableFuture
können Anwendungen benachrichtigt werden, wenn eine wiederkehrende Anfrage mit dem angegebenen Zoomwert abgeschlossen ist. Wenn Sie einen neuen Zoomwert festlegen, während der vorherige Vorgang noch ausgeführt wird, schlägt der ListenableFuture
des vorherigen Zoomvorgangs sofort fehl.
Fackel
CameraControl.enableTorch(boolean)
aktiviert oder deaktiviert die Taschenlampe.
Mit CameraInfo.getTorchState()
kann der aktuelle Taschenlampenstatus abgefragt werden. Sie können den von CameraInfo.hasFlashUnit()
zurückgegebenen Wert prüfen, um festzustellen, ob eine Taschenlampe verfügbar ist. Wenn nicht, führt das Aufrufen von CameraControl.enableTorch(boolean)
dazu, dass die zurückgegebene ListenableFuture
sofort mit einem fehlgeschlagenen Ergebnis abgeschlossen wird und der Fackelstatus auf TorchState.OFF
gesetzt wird.
Wenn die Taschenlampe aktiviert ist, bleibt sie unabhängig von der flashMode-Einstellung während der Foto- und Videoaufnahme eingeschaltet. Die flashMode
in ImageCapture
funktioniert nur, wenn die Taschenlampe deaktiviert ist.
Fokus und Belichtung
CameraControl.startFocusAndMetering()
löst die Autofokus- und Belichtungsmessung aus, indem AF/AE/AWB-Messbereiche basierend auf der jeweiligen FocusMeteringAction festgelegt werden. Damit wird in vielen Kameraanwendungen die Funktion
„Zum Fokussieren tippen“ implementiert.
Messpunkt
Erstellen Sie zuerst mit MeteringPointFactory.createPoint(float x, float y, float
size)
eine MeteringPoint
.
Ein MeteringPoint
steht für einen einzelnen Punkt auf der Kamera-Surface
. Sie werden in normalisierter Form gespeichert, sodass sie leicht in Sensorkoordinaten zur Festlegung von AF-/AE-/AWB-Regionen konvertiert werden können.
Die Größe von 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 bei (x, y)
für die angegebene size
zentriert ist.
Der folgende Code zeigt, wie ein MeteringPoint
erstellt wird:
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
Zum Aufrufen von startFocusAndMetering()
müssen Anwendungen eine FocusMeteringAction
erstellen, die aus einem oder mehreren MeteringPoints
mit optionalen Kombinationen des Messmodus 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
, bestehend aus einer MeteringPoint
für die AF/AE/AWB-Messregionen und einem weiteren MeteringPoint nur für AF und AE.
KameraX wandelt ihn intern in Kamera 2 MeteringRectangles
um und legt die entsprechenden CONTROL_AF_REGIONS
-/CONTROL_AE_REGIONS
-/CONTROL_AWB_REGIONS
-Parameter für die Aufnahmeanfrage fest.
Da nicht jedes Gerät AF/AE/AWB und mehrere Regionen unterstützt, führt CameraX den FocusMeteringAction
bestmöglich aus. CameraX verwendet die maximal unterstützte Anzahl von MeteringPoints in der Reihenfolge, in der die Punkte hinzugefügt wurden. Alle Messpunkte, die nach der maximalen Anzahl hinzugefügt werden, werden ignoriert. Wenn beispielsweise ein FocusMeteringAction
mit 3 MeteringPoints auf einer Plattform bereitgestellt wird, die nur 2 unterstützt, werden nur die ersten beiden MeteringPoints verwendet. Der letzte MeteringPoint
wird von CameraX ignoriert.
Belichtungskorrektur
Die Belichtungskorrektur ist nützlich, wenn Anwendungen Belichtungswerte (LW) über das Ausgabeergebnis der automatischen Belichtung (AE) hinaus anpassen müssen. Belichtungskorrekturwerte werden so kombiniert, um die erforderliche Belichtung für aktuelle Bildbedingungen zu bestimmen:
Exposure = ExposureCompensationIndex * ExposureCompensationStep
CameraX bietet die Funktion Camera.CameraControl.setExposureCompensationIndex()
zum Festlegen der Belichtungskorrektur als Indexwert.
Positive Indexwerte machen das Bild heller, während negative Werte das Bild dimmen. Anwendungen können den unterstützten Bereich von 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, führt setExposureCompensationIndex()
dazu, dass die zurückgegebene ListenableFuture
sofort mit einem fehlgeschlagenen Ergebnis abgeschlossen wird.
CameraX behält nur die letzte ausstehende setExposureCompensationIndex()
-Anfrage bei und ruft die Funktion mehrmals auf, bevor die vorherige Anfrage ausgeführt wird, wird sie abgebrochen.
Das folgende Snippet legt einen Belichtungskompensationsindex fest und registriert einen Callback für den Fall, dass 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 den aktuellenExposureState
ab, einschließlich:- Die Unterstützung für die Belichtungskorrektur.
- Der aktuelle Belichtungskompensationsindex.
- Der Belichtungskompensationsindexbereich.
- Der zur Berechnung des Belichtungskompensationswerts verwendete Belichtungskorrekturschritt.
Mit dem folgenden Code werden beispielsweise die Einstellungen für den Kontakt SeekBar
mit den 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 finden Sie in den folgenden Ressourcen.
Codelab
Codebeispiel
Entwickler-Community
Diskussionsgruppe zu Android CameraX