Puoi configurare ogni caso d'uso di CameraX per controllare diversi aspetti delle operazioni del caso d'uso.
Ad esempio, con il caso d'uso di acquisizione di immagini, puoi impostare un formato target e una modalità flash. Il seguente codice 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 API per modificare dinamicamente le impostazioni dopo la creazione del caso d'uso. Per informazioni sulla configurazione specifica per i singoli casi d'uso, consulta Implementa un'anteprima, Analizza le immagini e Acquisizione di immagini.
CameraXConfig
Per semplicità, CameraX ha configurazioni predefinite, come esecutori e gestori interni, adatte alla maggior parte degli scenari di utilizzo. Tuttavia, se la tua applicazione ha requisiti speciali o preferisci personalizzare queste configurazioni, CameraXConfig è l'interfaccia adatta a questo scopo.
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
CameraXConfigcon le tue configurazioni personalizzate. - Implementa l'interfaccia
CameraXConfig.Providernel tuoApplicatione restituisci l'oggettoCameraXConfigingetCameraXConfig(). - Aggiungi la classe
Applicational 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 la tua applicazione deve conoscere la configurazione di CameraX dopo averla impostata.
Limitatore della videocamera
Durante la prima chiamata di
ProcessCameraProvider.getInstance(),
CameraX enumera ed esegue query sulle caratteristiche delle fotocamere disponibili sul
dispositivo. Poiché CameraX deve comunicare con i componenti hardware, questo processo può richiedere un tempo non trascurabile per ogni fotocamera, in particolare sui dispositivi di fascia bassa. Se la tua applicazione utilizza solo fotocamere specifiche sul dispositivo,
ad esempio la fotocamera anteriore predefinita, puoi impostare CameraX in modo che ignori le altre fotocamere,
il che può ridurre la latenza di avvio delle fotocamere utilizzate dalla tua applicazione.
Se l'oggetto CameraSelector passato
a
CameraXConfig.Builder.setAvailableCamerasLimiter()
filtra una fotocamera, CameraX si comporta come se quella fotocamera non esistesse. Ad esempio, il seguente codice limita l'applicazione all'utilizzo della 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 della piattaforma su cui si basa CameraX richiedono il blocco della comunicazione tra processi (IPC) con l'hardware, che a volte può richiedere centinaia di millisecondi per rispondere. 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().
Camera Executor
L'esecutore della fotocamera viene utilizzato per tutte le chiamate API interne della piattaforma Camera, nonché per i callback di queste API. CameraX alloca e gestisce un Executor interno per eseguire queste attività.
Tuttavia, se la tua applicazione richiede un controllo più rigoroso dei thread, utilizza
CameraXConfig.Builder.setCameraExecutor().
Gestore dello scheduler
Il gestore dello scheduler viene utilizzato per pianificare le attività interne a intervalli fissi,
ad esempio per riprovare ad aprire la fotocamera quando non è disponibile. Questo gestore non esegue i job, ma li invia solo all'esecutore della videocamera. A volte viene utilizzato anche sulle piattaforme API legacy che richiedono un Handler per i callback. In questi casi, i callback vengono comunque inviati direttamente all'esecutore della fotocamera. CameraX
alloca e gestisce un HandlerThread interno 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, in quanto può essere una buona pratica evitare messaggi dettagliati nel codice di produzione. CameraX supporta quattro livelli di logging, dal più dettagliato al più grave:
Log.DEBUG(valore predefinito)Log.INFOLog.WARNLog.ERROR
Per descrizioni dettagliate di questi livelli di log, consulta la documentazione di Android Log. 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 che specifichi 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 fotocamera. Ciò significa che CameraX scende a compromessi su risoluzione e 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, determinati formati sono disponibili solo con determinate proporzioni.
- Il dispositivo preferisce un "mod16 più vicino" per la codifica JPEG o video. Per saperne di più, 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 fotocamera è 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 impostando un valore personalizzato per supportare i dispositivi con più display passando l'orientamento corrente del display durante la configurazione degli oggetti dei casi d'uso o in modo dinamico 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 (come ImageAnalysis.setTargetRotation()), anche quando il ciclo di vita è in esecuzione. Puoi utilizzarlo quando l'app è bloccata in modalità Ritratto, quindi non viene eseguita alcuna riconfigurazione durante la rotazione, ma il caso d'uso di foto o analisi deve essere consapevole della rotazione corrente del dispositivo. Ad esempio, il rilevamento della rotazione potrebbe essere necessario per orientare correttamente i volti per il riconoscimento facciale o per impostare le foto in orizzontale o verticale.
I dati delle immagini acquisite potrebbero essere archiviati senza informazioni sulla rotazione. I dati Exif contengono informazioni sulla rotazione in modo che le applicazioni della galleria possano mostrare l'immagine con l'orientamento corretto dopo il salvataggio.
Per visualizzare i dati di anteprima con l'orientamento corretto, puoi utilizzare i metadati
restituiti da
Preview.PreviewOutput()
per creare 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 dell'immagine o fornisce i metadati di rotazione ai consumer dei dati dell'immagine non ruotati.
- Anteprima: l'output dei metadati viene fornito in modo che la rotazione della risoluzione target sia nota utilizzando
Preview.getTargetRotation(). - ImageAnalysis: l'output dei metadati viene fornito in modo che le coordinate del buffer di immagini siano note rispetto alle coordinate di visualizzazione.
- ImageCapture: i metadati Exif dell'immagine, il buffer o sia il buffer che i metadati vengono modificati per annotare l'impostazione di rotazione. Il valore modificato dipende dall'implementazione dell'HAL.
Rettangolo di ritaglio
Per impostazione predefinita, il rettangolo di ritaglio è il rettangolo del buffer completo. Puoi personalizzarlo con ViewPort e UseCaseGroup. Raggruppando i casi d'uso e impostando l'area visibile, CameraX garantisce che i rettangoli di ritaglio di tutti i casi d'uso del gruppo puntino alla stessa area del sensore della fotocamera.
Il seguente snippet di codice mostra come utilizzare queste due classi:
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. CameraX calcola quindi il rettangolo di ritaglio più grande possibile in base alle proprietà dell'area visibile e ai casi d'uso collegati. 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 è utilizzare 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, ciò che l'app riceve da ImageAnalysis e ImageCapture corrisponde a ciò che l'utente finale vede in PreviewView, supponendo che il tipo di scala di PreviewView sia impostato su FILL_CENTER, ovvero il valore predefinito. Dopo aver applicato il rettangolo di ritaglio e la rotazione al buffer di output, l'immagine di tutti i casi d'uso è la stessa, anche se con risoluzioni diverse. Per saperne di più su come applicare le informazioni sulla trasformazione, consulta Output della trasformazione.
Selezione della videocamera
CameraX seleziona automaticamente il dispositivo con fotocamera migliore per i requisiti e i 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 loro
CameraCharacteristicsconCameraSelector.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ò utilizzare due fotocamere con obiettivi rivolti in direzioni diverse contemporaneamente o due fotocamere posteriori contemporaneamente. Il seguente blocco di codice mostra come impostare due fotocamere quando chiami bindToLifecycle e come ottenere 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 della fotocamera
Puoi scegliere di consentire a CameraX di impostare la risoluzione dell'immagine in base a una combinazione delle funzionalità del dispositivo, del livello hardware supportato dal dispositivo, 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 questa configurazione.
Risoluzione automatica
CameraX può 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 simultanea in una singola sessione in un'unica chiamata bindToLifecycle(). CameraX determina le risoluzioni
in base all'insieme di casi d'uso associati, considerando il livello hardware supportato dal dispositivo
e tenendo conto della variazione specifica del dispositivo (se un dispositivo
supera o non soddisfa le configurazioni di stream
disponibili).
L'obiettivo è consentire l'esecuzione dell'applicazione su un'ampia gamma di dispositivi, riducendo al minimo i percorsi del codice specifici per i dispositivi.
Le proporzioni predefinite per i casi d'uso di acquisizione di immagini e analisi delle immagini sono 4:3.
I casi d'uso hanno proporzioni configurabili per consentire all'applicazione di specificare le proporzioni desiderate in base al design della UI. L'output di CameraX viene prodotto in modo da corrispondere alle proporzioni richieste nel modo più preciso possibile in base al dispositivo. Se non è supportata una risoluzione con corrispondenza esatta, viene selezionata quella che soddisfa il maggior numero di condizioni. Pertanto, l'applicazione determina l'aspetto della fotocamera nell'app e CameraX determina le migliori impostazioni di risoluzione della fotocamera per soddisfare questa esigenza su dispositivi diversi.
Ad esempio, un'app può eseguire una delle seguenti operazioni:
- Specifica una risoluzione target di 4:3 o 16:9 per un caso d'uso
- Specifica una risoluzione personalizzata, per la quale CameraX tenta di trovare la corrispondenza più vicina
- Specifica le proporzioni di ritaglio per
ImageCapture
CameraX sceglie automaticamente le risoluzioni della superficie Camera2 interna. La tabella seguente mostra le risoluzioni:
| Caso d'uso | Risoluzione della superficie interna | Risoluzione dei dati di output |
|---|---|---|
| Anteprima | Proporzioni:la risoluzione che meglio adatta il target all'impostazione. | Risoluzione della superficie interna. I metadati vengono forniti per consentire a una visualizzazione di ritagliare, ridimensionare e ruotare l'immagine in base alle proporzioni target. |
| Risoluzione predefinita: la risoluzione di anteprima più alta o la risoluzione preferita dal dispositivo più alta che corrisponde alle proporzioni dell'anteprima. | ||
| Risoluzione massima:dimensioni dell'anteprima, che si riferiscono alle dimensioni che meglio corrispondono alla risoluzione dello schermo del dispositivo o a 1080p (1920 x 1080), a seconda di quale sia inferiore. | ||
| Analisi delle immagini | Proporzioni:la risoluzione che meglio si adatta al target per l'impostazione. | Risoluzione della superficie interna. |
| Risoluzione predefinita:l'impostazione predefinita della risoluzione target è 640 x 480. La regolazione della risoluzione target e delle proporzioni corrispondenti genera una risoluzione supportata ottimale. | ||
Risoluzione massima:la risoluzione di output massima del dispositivo della fotocamera in 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 quella più vicina tra le risoluzioni supportate.
|
||
| Acquisizione di immagini | Proporzioni:proporzioni più adatte all'impostazione. | Risoluzione della superficie interna. |
| Risoluzione predefinita: la risoluzione più alta disponibile o la risoluzione più alta preferita dal dispositivo che corrisponde alle proporzioni di ImageCapture. | ||
Risoluzione massima:la risoluzione di output massima del dispositivo della fotocamera in 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 target sia la risoluzione target nello stesso caso d'uso. In questo modo viene generato un errore IllegalArgumentException durante la creazione dell'oggetto di configurazione.
Esprimi la risoluzione Size nel frame di coordinate dopo aver ruotato le dimensioni supportate in base alla rotazione target. Ad esempio, un dispositivo con orientamento naturale verticale in rotazione target naturale che richiede un'immagine verticale può specificare 480 x 640, mentre lo stesso dispositivo, ruotato di 90 gradi e con orientamento target orizzontale, 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 disponibile più vicina in termini di dimensioni che non sia inferiore alla risoluzione target, come determinato dall'implementazione della fotocamera.
Tuttavia, se non esiste una risoluzione uguale o superiore a quella target, viene scelta la risoluzione disponibile più vicina inferiore a quella target. Le risoluzioni con le stesse proporzioni del valore Size fornito hanno una priorità più alta rispetto alle risoluzioni 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 determina una risoluzione specifica adatta in base al dispositivo.
Se l'esigenza principale dell'app è specificare una risoluzione per rendere più efficiente l'elaborazione delle immagini (ad esempio un'immagine di piccole o medie dimensioni in base alla capacità 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 corrente, consulta
StreamConfigurationMap.getOutputSizes(int).
Se la tua app è in esecuzione su 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 fotocamera in base alle esigenze di ogni singolo caso d'uso, CameraX implementa anche le seguenti interfacce per supportare le operazioni della fotocamera comuni a tutti i casi d'uso associati:
CameraControlti consente di configurare le funzionalità comuni della fotocamera.CameraInfoti consente di eseguire query sugli stati di queste funzionalità comuni della videocamera.
Di seguito sono riportate le funzionalità della fotocamera supportate con CameraControl:
- Zoom
- Torch
- Messa a fuoco e misurazione (tocca per mettere a fuoco)
- Compensazione dell'esposizione
Ottieni 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 operazioni di zoom e altre operazioni CameraControl dopo aver chiamato bindToLifecycle(). Dopo aver interrotto o eliminato l'attività utilizzata per associare
l'istanza della fotocamera, CameraControl non può più eseguire operazioni e
restituisce un ListenableFuture non riuscito.
CameraLifecycleOwner
Zoom
CameraControl offre due metodi per modificare il livello di zoom:
setZoomRatio()imposta lo zoom in base al fattore di zoom.Il rapporto deve essere compreso tra
CameraInfo.getZoomState().getValue().getMinZoomRatio()eCameraInfo.getZoomState().getValue().getMaxZoomRatio(). In caso contrario, la funzione restituisce unListenableFuturenon riuscito.setLinearZoom()imposta lo zoom corrente con un valore di zoom lineare compreso tra 0 e 1,0.Il vantaggio dello zoom lineare è che consente di scalare il campo visivo (FOV) in base alle modifiche dello zoom. Questo lo rende ideale per l'utilizzo con una visualizzazione
Slider.
CameraInfo.getZoomState()
restituisce un LiveData dello stato di zoom corrente. Il valore cambia quando la videocamera viene inizializzata o se il livello di zoom viene impostato utilizzando setZoomRatio() o setLinearZoom(). La chiamata di uno dei due metodi imposta i valori di supporto di
ZoomState.getZoomRatio()
e
ZoomState.getLinearZoom().
Questa opzione è utile se vuoi visualizzare il testo del rapporto di zoom accanto a un cursore.
Basta osservare ZoomState LiveData per aggiornare entrambi senza dover eseguire una conversione.
Il ListenableFuture restituito da entrambe le API offre alle applicazioni la possibilità di ricevere una notifica quando viene completata una richiesta ripetuta con il valore di zoom specificato. Inoltre, se imposti un nuovo valore di zoom mentre l'operazione precedente
è ancora in esecuzione, l'oggetto ListenableFuture dell'operazione di zoom precedente non va a buon fine
immediatamente.
Torch
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 l'oggetto ListenableFuture restituito venga completato immediatamente con un risultato non riuscito e imposta lo stato della torcia su TorchState.OFF.
Quando la torcia è attiva, rimane accesa durante l'acquisizione di foto e video, indipendentemente dall'impostazione di flashMode. flashMode in
ImageCapture funziona solo quando la torcia è disattivata.
Messa a fuoco e misurazione
CameraControl.startFocusAndMetering()
attiva la messa a fuoco automatica e la misurazione dell'esposizione impostando le regioni di misurazione AF/AE/AWB in base all'azione FocusMeteringAction specificata. Questa funzionalità viene spesso utilizzata per implementare la funzionalità "Tocca per mettere a fuoco" in molte applicazioni della fotocamera.
MeteringPoint
Per iniziare, crea un
MeteringPoint utilizzando
MeteringPointFactory.createPoint(float x, float y, float
size).
Un MeteringPoint rappresenta un singolo punto sulla fotocamera
Surface. Viene archiviato in un formato normalizzato in modo da poter essere facilmente convertito in coordinate del sensore per specificare le regioni AF/AE/AWB.
La dimensione di 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 un'area rettangolare centrata su (x, y) per l'oggetto size fornito.
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)
startFocusAndMetering e FocusMeteringAction
Per richiamare
startFocusAndMetering(),
le applicazioni devono creare un
FocusMeteringAction,
che consiste in uno o più MeteringPoints con combinazioni di modalità di misurazione facoltative da
FLAG_AF,
FLAG_AE,
FLAG_AWB. Il seguente codice mostra 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()
accetta un FocusMeteringAction composto 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 al meglio delle sue possibilità. CameraX utilizza il numero massimo di MeteringPoint supportati, nell'ordine in cui sono stati aggiunti. Tutti i MeteringPoint aggiunti dopo il numero massimo vengono ignorati. Ad esempio, se un FocusMeteringAction viene fornito con 3 MeteringPoint su una piattaforma che ne supporta solo 2, vengono utilizzati solo i primi 2 MeteringPoint. L'ultimo MeteringPoint viene ignorato da CameraX.
Compensazione dell'esposizione
La compensazione dell'esposizione è utile quando le applicazioni devono perfezionare i valori di esposizione (EV) oltre il risultato dell'output dell'esposizione automatica (AE). I valori di compensazione dell'esposizione vengono combinati nel seguente modo per determinare l'esposizione necessaria per le condizioni dell'immagine corrente:
Exposure = ExposureCompensationIndex * ExposureCompensationStep
CameraX fornisce la funzione Camera.CameraControl.setExposureCompensationIndex() per impostare la compensazione dell'esposizione come valore di indice.
I valori positivi dell'indice rendono l'immagine più luminosa, mentre i valori negativi la attenuano. Le applicazioni possono eseguire query sull'intervallo supportato tramite
CameraInfo.ExposureState.exposureCompensationRange()
descritto nella sezione successiva. Se il valore è supportato, l'oggetto ListenableFuture restituito viene completato quando il valore viene attivato correttamente nella richiesta di acquisizione; se l'indice specificato non rientra nell'intervallo supportato, setExposureCompensationIndex() fa sì che l'oggetto ListenableFuture restituito venga completato immediatamente con un risultato non riuscito.
CameraX conserva solo l'ultima richiesta setExposureCompensationIndex() in sospeso e la chiamata della funzione più volte prima dell'esecuzione della richiesta precedente comporta l'annullamento.
Il seguente snippet imposta un indice di compensazione dell'esposizione e registra un callback per quando la richiesta di modifica dell'esposizione è stata eseguita:
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'oggettoExposureStatecorrente, tra cui:- La supportabilità del controllo della compensazione dell'esposizione.
- L'indice di compensazione dell'esposizione attuale.
- L'intervallo dell'indice di compensazione dell'esposizione.
- Il passaggio 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 i valori ExposureState
correnti:
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 scoprire di più su CameraX, consulta le seguenti risorse aggiuntive.
Codelab
Esempio di codice
Community di sviluppatori
Gruppo di discussione di Android CameraX