Puoi configurare ogni caso d'uso di CameraX per controllare aspetti diversi delle operazioni del caso d'uso.
Ad esempio, con il caso d'uso di acquisizione di immagini, puoi impostare proporzioni target e una modalità flash. Il codice che segue mostra un esempio:
Kotlin
val imageCapture = ImageCapture.Builder() .setFlashMode(...) .setTargetAspectRatio(...) .build()
Java
ImageCapture imageCapture = new ImageCapture.Builder() .setFlashMode(...) .setTargetAspectRatio(...) .build();
Oltre alle opzioni di configurazione, alcuni casi d'uso espongono le API a modificare dinamicamente le impostazioni dopo la creazione del caso d'uso. Per informazioni sulla configurazione specifica per i singoli casi d'uso, consulta Implementare un'anteprima, Analizzare le immagini e Acquisizione delle immagini.
Configurazione CameraX
Per semplicità, CameraX dispone di configurazioni predefinite, come esecutori e gestori interni, adatti alla maggior parte degli scenari di utilizzo. Tuttavia, se la tua applicazione ha requisiti speciali o preferisce personalizzare queste configurazioni, CameraXConfig
è l'interfaccia adeguata.
Con CameraXConfig
, un'applicazione può:
- Ottimizza la latenza di avvio con
setAvailableCameraLimiter()
. - Fornisci l'esecutore dell'applicazione a CameraX con
setCameraExecutor()
. - Sostituisci il gestore dello scheduler predefinito con
setSchedulerHandler()
. - Modifica il livello di logging con
setMinimumLoggingLevel()
.
Modello di utilizzo
La seguente procedura descrive come utilizzare CameraXConfig
:
- Crea un oggetto
CameraXConfig
con le tue configurazioni personalizzate. - Implementa l'interfaccia
CameraXConfig.Provider
nel tuoApplication
e restituisci l'oggettoCameraXConfig
ingetCameraXConfig()
. - Aggiungi la tua classe
Application
al fileAndroidManifest.xml
, come descritto qui.
Ad esempio, il seguente esempio di codice limita il logging di CameraX solo ai messaggi di errore:
Kotlin
class CameraApplication : Application(), CameraXConfig.Provider { override fun getCameraXConfig(): CameraXConfig { return CameraXConfig.Builder.fromConfig(Camera2Config.defaultConfig()) .setMinimumLoggingLevel(Log.ERROR).build() } }
Conserva una copia locale dell'oggetto CameraXConfig
se l'applicazione deve conoscere la configurazione di CameraX dopo averla impostata.
Limitatore fotocamera
Durante la prima chiamata a ProcessCameraProvider.getInstance()
, CameraX enumera ed esegue query sulle caratteristiche delle videocamere disponibili sul dispositivo. Poiché CameraX deve comunicare con i componenti hardware, questo processo può richiedere un tempo non banale per ogni videocamera, in particolare sui dispositivi di fascia bassa. Se l'applicazione utilizza solo fotocamere specifiche sul dispositivo,
ad esempio la fotocamera anteriore predefinita, puoi impostare CameraX in modo che ignori altre fotocamere,
il che può ridurre la latenza di avvio per le fotocamere utilizzate dall'applicazione.
Se il campo CameraSelector
passato
a
CameraXConfig.Builder.setAvailableCamerasLimiter()
esclude una videocamera, CameraX si comporta come se quella videocamera non esistesse. Ad esempio, il seguente codice limita l'applicazione in modo che l'applicazione utilizzi solo la fotocamera posteriore predefinita del dispositivo:
Kotlin
class MainApplication : Application(), CameraXConfig.Provider { override fun getCameraXConfig(): CameraXConfig { return CameraXConfig.Builder.fromConfig(Camera2Config.defaultConfig()) .setAvailableCamerasLimiter(CameraSelector.DEFAULT_BACK_CAMERA) .build() } }
Thread
Molte delle API delle piattaforme su cui è sviluppata CameraX richiedono il blocco delle comunicazioni IPC (Interprocess Communication) con hardware la cui risposta può richiedere a volte centinaia di millisecondi. Per questo motivo, CameraX chiama queste API solo dai thread in background, in modo che il thread principale non venga bloccato e l'interfaccia utente rimanga fluida. CameraX gestisce internamente questi thread in background in modo che
questo comportamento appaia trasparente. Tuttavia, alcune applicazioni richiedono
un controllo rigoroso dei thread. CameraXConfig
consente a un'applicazione di impostare i thread in background
utilizzati tramite
CameraXConfig.Builder.setCameraExecutor()
e
CameraXConfig.Builder.setSchedulerHandler()
.
Esecutore videocamera
L'esecutore della fotocamera viene utilizzato per tutte le chiamate API della piattaforma Camera interne, nonché per i callback da queste API. CameraX alloca e gestisce una Executor
interna per eseguire queste attività.
Tuttavia, se la tua applicazione richiede un controllo più rigoroso dei thread, utilizza CameraXConfig.Builder.setCameraExecutor()
.
Gestore scheduler
Il gestore dello scheduler viene utilizzato per pianificare le attività interne a intervalli fissi, ad esempio
ritentare l'apertura della fotocamera quando non è disponibile. Questo gestore
non esegue i job, ma li invia soltanto all'esecutore della videocamera. A volte viene utilizzato anche sulle piattaforme API legacy che richiedono Handler
per i callback. In questi casi, i
callback vengono comunque inviati direttamente solo all'esecutore della videocamera. CameraX assegna e gestisce una HandlerThread
interna per eseguire queste attività, ma puoi eseguirne l'override con CameraXConfig.Builder.setSchedulerHandler()
.
Logging
Il logging di CameraX consente alle applicazioni di filtrare i messaggi logcat, poiché può essere buona norma evitare messaggi dettagliati nel codice di produzione. CameraX supporta quattro livelli di registrazione, dal più dettagliato al più grave:
Log.DEBUG
(valore predefinito)Log.INFO
Log.WARN
Log.ERROR
Per descrizioni dettagliate di questi livelli di log, consulta la documentazione relativa ai log di Android. Utilizza CameraXConfig.Builder.setMinimumLoggingLevel(int)
per impostare il livello di logging appropriato per la tua applicazione.
Selezione automatica
CameraX fornisce automaticamente funzionalità specifiche per il dispositivo su cui è in esecuzione la tua app. Ad esempio, CameraX determina automaticamente la risoluzione migliore da utilizzare se non ne specifichi una o se quella specificata non è supportata. Tutto questo viene gestito dalla libreria, eliminando la necessità di scrivere codice specifico per il dispositivo.
L'obiettivo di CameraX è inizializzare correttamente una sessione della videocamera. Ciò significa che CameraX compromette la risoluzione e le proporzioni in base alle funzionalità del dispositivo. La compromissione può verificarsi perché:
- Il dispositivo non supporta la risoluzione richiesta.
- Il dispositivo presenta problemi di compatibilità, ad esempio dispositivi legacy che richiedono determinate risoluzioni per funzionare correttamente.
- Su alcuni dispositivi, alcuni formati sono disponibili solo con alcune proporzioni.
- Il dispositivo ha una preferenza per la "mod16 più vicina" per la codifica JPEG o video. Per maggiori informazioni, vedi
SCALER_STREAM_CONFIGURATION_MAP
.
Sebbene CameraX crei e gestisca la sessione, controlla sempre le dimensioni delle immagini restituite nell'output del caso d'uso nel codice e apporta le modifiche necessarie.
Rotazione
Per impostazione predefinita, la rotazione della videocamera è impostata in modo da corrispondere alla rotazione del display predefinito durante la creazione del caso d'uso. In questo caso predefinito, CameraX produce output per consentire all'app di corrispondere a ciò che ti aspetti di vedere nell'anteprima. Puoi modificare la rotazione impostandola su un valore personalizzato per supportare i dispositivi multi-display, passando l'orientamento del display corrente durante la configurazione degli oggetti caso d'uso o dinamicamente dopo la loro creazione.
La tua app può impostare la rotazione target utilizzando le impostazioni di configurazione. Può quindi aggiornare le impostazioni di rotazione utilizzando i metodi delle API dei casi d'uso (ad esempio ImageAnalysis.setTargetRotation()
), anche quando il ciclo di vita è in esecuzione. Puoi utilizzare questa opzione quando l'app
è bloccata in modalità Ritratto, quindi non viene eseguita alcuna riconfigurazione
in rotazione, ma il caso d'uso della foto o dell'analisi deve essere consapevole della
rotazione corrente del dispositivo. Ad esempio, potrebbe essere necessario il rilevamento della rotazione, in modo che i volti siano orientati correttamente per il rilevamento facciale oppure le foto siano impostate su orizzontale o verticale.
I dati delle immagini acquisite potrebbero essere archiviati senza informazioni sulla rotazione. I dati EXIF contengono informazioni sulla rotazione per consentire alle applicazioni galleria di mostrare l'immagine nell'orientamento corretto dopo il salvataggio.
Per visualizzare i dati di anteprima con l'orientamento corretto, puoi utilizzare l'output dei metadati di Preview.PreviewOutput()
per creare le trasformazioni.
Il seguente esempio di codice mostra come impostare la rotazione su un evento di orientamento:
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(); }
In base alla rotazione impostata, ogni caso d'uso ruota direttamente i dati immagine o fornisce metadati di rotazione ai consumatori dei dati immagine non ruotati.
- Anteprima: l'output dei metadati viene fornito in modo che la rotazione della risoluzione di destinazione sia nota utilizzando
Preview.getTargetRotation()
. - ImageAnalysis: l'output dei metadati viene fornito in modo che le coordinate del buffer di immagine siano note relative alle coordinate di visualizzazione.
- Image Capture: i metadati EXIF dell'immagine, il buffer o sia il buffer sia i metadati vengono modificati in modo da notare l'impostazione di rotazione. Il valore modificato dipende dall'implementazione dell'HAL.
Ritaglia rettangolo
Per impostazione predefinita, il rettangolo di ritaglio è l'intero rettangolo buffer. Puoi personalizzarla con ViewPort
e UseCaseGroup
. Raggruppando i casi d'uso e impostando l'area visibile, CameraX garantisce che i retti di ritaglio di tutti i casi d'uso del gruppo puntino alla stessa area nel sensore della videocamera.
Il seguente snippet di codice mostra come utilizzare questi due corsi:
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
definisce il rettangolo del buffer visibile agli utenti finali. Quindi, CameraX calcola il rettangolo di ritaglio più grande possibile in base alle proprietà dell'area visibile e ai casi d'uso allegati. In genere, per ottenere un effetto WYSIWYG, puoi configurare
l'area visibile in base al caso d'uso dell'anteprima. Un modo semplice per ottenere l'area visibile
è usare PreviewView
.
I seguenti snippet di codice mostrano come ottenere l'oggetto ViewPort
:
Kotlin
val viewport = findViewById<PreviewView>(R.id.preview_view).viewPort
Java
ViewPort viewPort = ((PreviewView)findViewById(R.id.preview_view)).getViewPort();
Nell'esempio precedente, i dati che l'app ottiene da ImageAnalysis
e ImageCapture
corrisponde a ciò che l'utente finale vede in PreviewView
, supponendo che il tipo di scala di PreviewView
sia impostato sul valore predefinito, FILL_CENTER
. Dopo aver applicato il rettangolo di ritaglio e la rotazione al buffer di output, l'immagine in tutti i casi d'uso è la stessa, anche se possibilmente con risoluzioni diverse. Per ulteriori informazioni su come applicare le informazioni sulla trasformazione, vedi Transform output.
Selezione fotocamera
CameraX seleziona automaticamente la fotocamera più adatta ai requisiti e ai casi d'uso della tua applicazione. Se vuoi utilizzare un dispositivo diverso da quello selezionato per te, hai a disposizione alcune opzioni:
- Richiedi la fotocamera anteriore predefinita con
CameraSelector.DEFAULT_FRONT_CAMERA
. - Richiedi la fotocamera posteriore predefinita con
CameraSelector.DEFAULT_BACK_CAMERA
. - Filtra l'elenco dei dispositivi disponibili in base al relativo
CameraCharacteristics
conCameraSelector.Builder.addCameraFilter()
.
Il seguente esempio di codice illustra come creare un CameraSelector
per
influenzare la selezione del dispositivo:
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)
Seleziona più videocamere contemporaneamente
A partire da CameraX 1.3, puoi anche selezionare più fotocamere contemporaneamente. Ad esempio, puoi eseguire l'associazione a una fotocamera anteriore e posteriore per scattare foto o registrare video da entrambe le prospettive contemporaneamente.
Quando utilizzi la funzionalità Fotocamera simultanea, il dispositivo può attivare contemporaneamente due videocamere con obiettivi diversi o due fotocamere posteriori contemporaneamente. Il seguente blocco di codice mostra come impostare due videocamere quando si chiama bindToLifecycle
e come recuperare entrambi gli oggetti Camera dall'oggetto ConcurrentCamera
restituito.
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);
Risoluzione fotocamera
Puoi scegliere di consentire a CameraX di impostare la risoluzione dell'immagine in base a una combinazione delle funzionalità del dispositivo, del livello di hardware supportato, del caso d'uso e delle proporzioni fornite. In alternativa, puoi impostare una risoluzione target specifica o un formato specifico nei casi d'uso che supportano tale configurazione.
Risoluzione automatica
CameraX è in grado di determinare automaticamente le migliori impostazioni di risoluzione in base ai
casi d'uso specificati in cameraProcessProvider.bindToLifecycle()
. Se possibile, specifica tutti i casi d'uso necessari per l'esecuzione contemporanea in una singola sessione in un'unica chiamata a bindToLifecycle()
. CameraX determina le risoluzioni in base all'insieme di casi d'uso vincolati considerando il livello hardware supportato del dispositivo e tenendo conto della varianza specifica del dispositivo (in cui un dispositivo supera o non soddisfa le configurazioni di streaming disponibili).
Lo scopo è consentire l'esecuzione dell'applicazione su un'ampia gamma di dispositivi riducendo al minimo i percorsi di codice specifici dei dispositivi.
Le proporzioni predefinite per i casi d'uso di acquisizione e analisi delle immagini sono 4:3.
I casi d'uso prevedono proporzioni configurabili per consentire all'applicazione di specificare il formato desiderato in base al design dell'interfaccia utente. L'output di CameraX viene prodotto per corrispondere alle proporzioni richieste, esattamente come quelle supportate dal dispositivo. Se non è supportata una risoluzione con corrispondenza esatta, viene selezionata quella che soddisfa il maggior numero di condizioni. Pertanto, l'applicazione determina come la fotocamera viene visualizzata nell'app e CameraX determina le impostazioni di risoluzione migliori per la risoluzione sui diversi dispositivi.
Ad esempio, un'app può effettuare le seguenti operazioni:
- Specifica una risoluzione target pari a 4:3 o 16:9 per un caso d'uso
- Specifica una risoluzione personalizzata, di cui CameraX tenta di trovare la corrispondenza più simile
- Specifica le proporzioni di ritaglio per
ImageCapture
CameraX sceglie automaticamente le risoluzioni della superficie interna di Camera2. La tabella seguente mostra le risoluzioni:
Caso d'uso | Risoluzione della superficie interna | Risoluzione dei dati di output |
---|---|---|
Anteprima | Proporzioni:la risoluzione che meglio si adatta al target all'impostazione. | Risoluzione della superficie interna. Vengono forniti metadati per consentire un'azione di ritaglio, scalabilità e rotazione in base alle proporzioni target. |
Risoluzione predefinita: la risoluzione di anteprima massima o la risoluzione preferita dal dispositivo, che corrisponde alle proporzioni dell'anteprima. | ||
Risoluzione massima:dimensione dell'anteprima, che si riferisce alla dimensione migliore corrispondente alla risoluzione dello schermo del dispositivo oppure a 1080p (1920 x 1080), a seconda di quale sia la più piccola. | ||
Analisi delle immagini | Proporzioni:la risoluzione che meglio si adatta al target all'impostazione. | Risoluzione della superficie interna. |
Risoluzione predefinita: l'impostazione predefinita della risoluzione target è 640 x 480. La regolazione sia della risoluzione target sia delle proporzioni corrispondenti consente di ottenere una risoluzione più supportata. | ||
Risoluzione massima:la risoluzione massima di output del dispositivo della fotocamera, nel formato
YUV_420_888, recuperata da
StreamConfigurationMap.getOutputSizes() .
La risoluzione target è impostata su 640 x 480 per impostazione predefinita, quindi se vuoi una risoluzione superiore a 640 x 480, devi utilizzare setTargetResolution() e setTargetAspectRatio() per ottenere la risoluzione più simile tra quelle supportate.
|
||
Acquisizione di immagini | Proporzioni:il formato che meglio si adatta all'impostazione. | Risoluzione della superficie interna. |
Risoluzione predefinita: la risoluzione più alta disponibile o la massima risoluzione preferita dal dispositivo che corrisponde alle proporzioni di Image Capture. | ||
Risoluzione massima:la risoluzione di output massima del dispositivo della fotocamera in un formato JPEG. Utilizza
StreamConfigurationMap.getOutputSizes()
per recuperarlo.
|
Specifica una risoluzione
Puoi impostare risoluzioni specifiche durante la creazione di casi d'uso utilizzando il
metodo setTargetResolution(Size resolution)
, come mostrato nel seguente
esempio di codice:
Kotlin
val imageAnalysis = ImageAnalysis.Builder() .setTargetResolution(Size(1280, 720)) .build()
Java
ImageAnalysis imageAnalysis = new ImageAnalysis.Builder() .setTargetResolution(new Size(1280, 720)) .build();
Non puoi impostare sia le proporzioni che la risoluzione target nello stesso caso d'uso. In questo modo viene generato un IllegalArgumentException
durante la creazione dell'oggetto di configurazione.
Esprimi la risoluzione Size
nel frame delle coordinate dopo aver ruotato le dimensioni supportate dalla rotazione di destinazione. Ad esempio, un dispositivo con orientamento naturale verticale nella rotazione del target naturale che richiede un'immagine verticale può specificare una dimensione di 480 x 640, mentre lo stesso dispositivo, ruotato di 90 gradi e con orientamento orizzontale per il targeting, può specificare 640 x 480.
La risoluzione target tenta di stabilire un limite minimo per la risoluzione dell'immagine. La risoluzione effettiva dell'immagine è la risoluzione più vicina disponibile in termini di dimensioni non inferiore alla risoluzione target, come stabilito dall'implementazione della fotocamera.
Tuttavia, se non esiste una risoluzione uguale o superiore a quella target, viene scelta la risoluzione più vicina disponibile inferiore a quella target. Alle risoluzioni con le stesse proporzioni dell'elemento Size
specificato viene assegnata una priorità maggiore rispetto a quelle con proporzioni diverse.
CameraX applica la risoluzione più adatta in base alle richieste. Se l'esigenza principale è soddisfare le proporzioni, specifica solo setTargetAspectRatio
e CameraX determinerà una risoluzione specifica adatta al dispositivo.
Se la necessità principale dell'app è specificare una risoluzione per rendere più efficiente
l'elaborazione delle immagini (ad esempio un'immagine di piccole o medie dimensioni basata sulla funzionalità di elaborazione
del dispositivo), utilizza setTargetResolution(Size resolution)
.
Se la tua app richiede una risoluzione esatta, consulta la tabella all'interno di
createCaptureSession()
per determinare le risoluzioni massime supportate da ogni livello hardware. Per
controllare le risoluzioni specifiche supportate dal dispositivo attuale, consulta
StreamConfigurationMap.getOutputSizes(int)
.
Se la tua app utilizza Android 10 o versioni successive, puoi utilizzare
isSessionConfigurationSupported()
per verificare un SessionConfiguration
specifico.
Controlla l'output della videocamera
Oltre a consentirti di configurare l'output della videocamera in base alle necessità per ogni singolo caso d'uso, CameraX implementa anche le seguenti interfacce per supportare le operazioni della videocamera comuni a tutti i casi d'uso correlati:
CameraControl
ti consente di configurare le funzionalità più comuni della videocamera.CameraInfo
ti consente di eseguire query sullo stato delle funzionalità più comuni della fotocamera.
Di seguito sono riportate le funzionalità della fotocamera supportate con CameraControl:
- Zoom
- Torcia
- Messa a fuoco e misurazione esposimetrica (tocca per mettere a fuoco)
- Compensazione dell'esposizione
Recuperare istanze di CameraControl e CameraInfo
Recupera le istanze di CameraControl
e CameraInfo
utilizzando l'oggetto Camera
restituito da ProcessCameraProvider.bindToLifecycle()
.
Il seguente codice mostra un esempio:
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()
Ad esempio, puoi inviare lo zoom e altre operazioni di CameraControl
dopo
aver chiamato bindToLifecycle()
. Dopo aver interrotto o eliminato l'attività utilizzata per associare
l'istanza della videocamera, CameraControl
non può più eseguire operazioni e
restituisce un ListenableFuture
non riuscito.
Zoom
CameraControl offre due metodi per modificare il livello di zoom:
setZoomRatio()
imposta lo zoom in base al rapporto di zoom.Il rapporto deve essere compreso nell'intervallo di
CameraInfo.getZoomState().getValue().getMinZoomRatio()
eCameraInfo.getZoomState().getValue().getMaxZoomRatio()
. In caso contrario, la funzione restituisce un erroreListenableFuture
.setLinearZoom()
imposta lo zoom corrente con un valore di zoom lineare che va da 0 a 1,0.Il vantaggio dello zoom lineare è che consente di scalare il campo visivo con variazioni dello zoom. Per questo è ideale per l'utilizzo con una vista
Slider
.
CameraInfo.getZoomState()
restituisce un valore LiveData dello stato di zoom corrente. Il valore cambia quando la fotocamera
viene inizializzata o se il livello di zoom viene impostato utilizzando setZoomRatio()
o
setLinearZoom()
. Se chiami uno dei due metodi, vengono impostati i valori di supporto per ZoomState.getZoomRatio()
e ZoomState.getLinearZoom()
.
Ciò è utile se vuoi visualizzare il testo del rapporto di zoom insieme a un dispositivo di scorrimento.
È sufficiente osservare l'LiveData
di ZoomState
per aggiornarli entrambi senza dover effettuare
una conversione.
L'elemento ListenableFuture
restituito da entrambe le API consente alle applicazioni di ricevere una notifica quando viene completata una richiesta ricorrente con il valore di zoom specificato. Inoltre, se imposti un nuovo valore di zoom mentre l'operazione precedente è ancora in esecuzione, l'elemento ListenableFuture
dell'operazione di zoom precedente non riesce immediatamente.
Torcia
CameraControl.enableTorch(boolean)
attiva o disattiva la torcia.
CameraInfo.getTorchState()
può essere utilizzato per eseguire query sullo stato attuale della torcia. Puoi controllare il valore restituito da CameraInfo.hasFlashUnit()
per determinare se è disponibile una torcia. In caso contrario, la chiamata a
CameraControl.enableTorch(boolean)
fa sì che il valore ListenableFuture
restituito
venga completato immediatamente con un risultato non riuscito e lo stato della torcia viene impostato su
TorchState.OFF
.
Quando la torcia è attiva, rimane accesa durante l'acquisizione di foto e video indipendentemente dall'impostazione flashMode. flashMode
in ImageCapture
funziona solo quando la torcia è disattivata.
Messa a fuoco e misurazione esposimetrica
CameraControl.startFocusAndMetering()
attiva la messa a fuoco automatica e la misurazione dell'esposizione impostando le regioni di misurazione AF/AE/AWB
in base alla FocusMeteringAction specificata. Questa funzionalità viene spesso usata
per implementare la funzionalità "tocca per mettere a fuoco".
Punto misurazione
Per iniziare, crea una MeteringPoint
utilizzando MeteringPointFactory.createPoint(float x, float y, float
size)
.
Un MeteringPoint
rappresenta un singolo punto della fotocamera
Surface
. Viene memorizzato in un formato normalizzato in modo da poter essere facilmente convertito in coordinate del sensore per specificare le regioni AF/AE/AWB.
La dimensione dell'intervallo MeteringPoint
va da 0 a 1, con una dimensione predefinita di 0,15f. Quando chiami MeteringPointFactory.createPoint(float x, float y, float
size)
, CameraX crea una regione rettangolare centrata su (x, y)
per il size
specificato.
Il seguente codice mostra come creare un MeteringPoint
:
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)
startMetering Focus e ActionMetering
Per richiamare
startFocusAndMetering()
,
le applicazioni devono creare un
FocusMeteringAction
,
composto da uno o più MeteringPoints
con combinazioni facoltative della modalità di misurazione
da
FLAG_AF
,
FLAG_AE
e
FLAG_AWB
. Il seguente codice dimostra questo utilizzo:
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)
Come mostrato nel codice precedente, startFocusAndMetering()
richiede un valore FocusMeteringAction
costituito da un MeteringPoint
per le regioni di misurazione AF/AE/AWB e un altro MeteringPoint solo per AF e AE.
Internamente, CameraX lo converte in Camera2
MeteringRectangles
e imposta i parametri
CONTROL_AF_REGIONS
/
CONTROL_AE_REGIONS
/
CONTROL_AWB_REGIONS
corrispondenti alla richiesta di acquisizione.
Poiché non tutti i dispositivi supportano AF/AE/AWB e più regioni, CameraX esegue
FocusMeteringAction
con il massimo sforzo. CameraX utilizza il numero massimo di punti di misurazione supportati, nell'ordine in cui sono stati aggiunti i punti. Tutti i
MeteringPoint aggiunti dopo il conteggio massimo vengono ignorati. Ad esempio, se un FocusMeteringAction
viene fornito con 3 punti di misurazione su una piattaforma che ne supporta solo 2, vengono utilizzati solo i primi 2 punti di misurazione. L'ultimo elemento MeteringPoint
viene
ignorato da CameraX.
Compensazione dell'esposizione
La compensazione dell'esposizione è utile quando le applicazioni devono regolare i valori di esposizione (EV) oltre il risultato dell'output di esposizione automatica (AE). I valori di compensazione dell'esposizione vengono combinati nel seguente modo per determinare l'esposizione necessaria per le attuali condizioni dell'immagine:
Exposure = ExposureCompensationIndex * ExposureCompensationStep
CameraX fornisce la funzione Camera.CameraControl.setExposureCompensationIndex()
per impostare la compensazione dell'esposizione come valore di indice.
I valori di indice positivi rendono l'immagine più luminosa, mentre quelli negativi attenuano l'immagine. Le applicazioni possono eseguire query sull'intervallo supportato tramite
CameraInfo.ExposureState.exposureCompensationRange()
descritto nella prossima sezione. Se il valore è supportato, il valore ListenableFuture
restituito viene completato quando il valore viene abilitato correttamente nella richiesta di acquisizione. Se l'indice specificato non rientra nell'intervallo supportato, setExposureCompensationIndex()
fa sì che il valore ListenableFuture
restituito venga completato immediatamente con un risultato non riuscito.
CameraX conserva solo l'ultima richiesta setExposureCompensationIndex()
in sospeso e richiama la funzione più volte prima che la richiesta precedente venga eseguita ne risulti l'annullamento.
Lo snippet seguente imposta un indice di compensazione dell'esposizione e registra un callback per quando è stata eseguita la richiesta di modifica dell'esposizione:
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()
recupera l'elemento corrente diExposureState
tra cui:- Supporta il controllo della compensazione dell'esposizione.
- L'indice di compensazione dell'esposizione corrente.
- L'intervallo dell'indice di compensazione dell'esposizione.
- L'intervallo di compensazione dell'esposizione utilizzato nel calcolo del valore di compensazione dell'esposizione.
Ad esempio, il seguente codice inizializza le impostazioni per un'esposizione SeekBar
con gli attuali valori ExposureState
:
Kotlin
val exposureState = camera.cameraInfo.exposureState binding.seekBar.apply { isEnabled = exposureState.isExposureCompensationSupported max = exposureState.exposureCompensationRange.upper min = exposureState.exposureCompensationRange.lower progress = exposureState.exposureCompensationIndex }
Risorse aggiuntive
Per saperne di più su CameraX, consulta le risorse aggiuntive che seguono.
Codelab
Esempio di codice
Community di sviluppatori
Gruppo di discussione di Android CameraX