Nota: questa pagina si riferisce al pacchetto Camera2. A meno che la tua app non richieda funzionalità specifiche di basso livello di Camera2, ti consigliamo di usare CameraX. Sia CameraX che Camera2 supportano Android 5.0 (livello API 21) e versioni successive.
La funzionalità multicamera è stata introdotta con Android 9 (livello API 28). Dalla sua uscita, sul mercato vengono lanciati dispositivi che supportano l'API. Molti casi d'uso multicamera sono strettamente legate a una specifica configurazione hardware. In altre parole, non tutti i casi d'uso sono compatibili con tutti i dispositivi, il che rende la fotocamera multicamera presenta un buon candidato per la funzionalità di Google Play Consegna.
Alcuni casi d'uso tipici includono:
- Zoom: passaggio da una fotocamera all'altra in base all'area ritagliata o alla focale desiderata lunghezza.
- Profondità: utilizzo di più fotocamere per creare una mappa di profondità.
- Bokeh: uso di informazioni sulla profondità dedotti per simulare un corpus restringente simile a una fotocamera DSLR intervallo di messa a fuoco.
La differenza tra fotocamere logiche e fisiche
Comprendere l'API multi-camera richiede di comprendere la differenza tra fotocamere logiche e fisiche. Come riferimento, consideriamo un dispositivo con tre fotocamere posteriori. In questo esempio, ciascuna delle tre fotocamere posteriori considerata una fotocamera fisica. Una videocamera logica è quindi un raggruppamento di due o più di quelle fotocamere fisiche. L'output del comando videocamera può essere uno stream proveniente da una delle fotocamere fisiche sottostanti o uno stream confuso proveniente da più di una videocamera fisica sottostante contemporaneamente. In ogni caso, lo stream viene gestito dall'hardware della videocamera Abstraction Layer (HAL).
Molti produttori di telefoni sviluppano applicazioni proprietarie per le fotocamere, che in genere sono preinstallati sui loro dispositivi. Per utilizzare tutte le funzionalità dell'hardware, possono utilizzare API private o nascoste o ricevere un trattamento speciale l'implementazione del driver a cui le altre applicazioni non hanno accesso. Alcune dispositivi implementano il concetto di telecamere logiche fornendo un flusso confuso fotogrammi da diverse fotocamere fisiche, ma solo per alcuni privilegi diverse applicazioni. Spesso, solo una delle fotocamere fisiche è esposta al il modello di machine learning. La situazione per gli sviluppatori di terze parti precedenti ad Android 9 è illustrato nel seguente diagramma:
![](https://developer.android.google.cn/static/images/training/camera/camera2/multi-camera-1.png?authuser=9&hl=it)
A partire da Android 9, le API private non sono più consentite nelle app per Android. Con l'inclusione del supporto multicamera nel framework, Android ha consigliamo vivamente ai produttori di telefoni di esporre una fotocamera logica di tutte le fotocamere fisiche rivolte nella stessa direzione. Di seguito viene illustrato cosa gli sviluppatori di terze parti dovrebbero aspettarsi di trovare dispositivi con Android 9 e superiore:
![](https://developer.android.google.cn/static/images/training/camera/camera2/multi-camera-2.png?authuser=9&hl=it)
Ciò che fornisce la fotocamera logica dipende interamente dall'implementazione dell'OEM di Camera HAL. Ad esempio, un dispositivo come Pixel 3 implementa la sua logica videocamera in modo tale da scegliere una delle proprie fotocamere fisiche in base alla la lunghezza focale e l'area di ritaglio richieste.
API multi-camera
La nuova API aggiunge le nuove costanti, classi e metodi seguenti:
CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA
CameraCharacteristics.getPhysicalCameraIds()
CameraCharacteristics.getAvailablePhysicalCameraRequestKeys()
CameraDevice.createCaptureSession(SessionConfiguration config)
CameraCharacteritics.LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE
OutputConfiguration
eSessionConfiguration
A causa delle modifiche al Compatibility Definition Document (CDD) di Android, la l'API multi-camera soddisfa anche alcune aspettative degli sviluppatori. Dispositivi con doppia fotocamera esisteva prima di Android 9, ma l'apertura di più di una fotocamera contemporaneamente tentativi ed errori. Su Android 9 e versioni successive, modalità multicamera offre un insieme di regole per specificare quando è possibile aprire che fanno parte della stessa videocamera logica.
Nella maggior parte dei casi, i dispositivi con Android 9 e versioni successive espongono tutte le informazioni fisiche (ad eccezione dei sensori meno comuni come gli infrarossi) insieme una fotocamera logica più facile da usare. Per ogni combinazione di stream funzionare, uno stream appartenente a una videocamera logica può essere sostituito due stream provenienti dalle videocamere fisiche sottostanti.
Stream multipli contemporaneamente
Utilizzare più videocamere in streaming contemporaneamente
copre le regole per l'utilizzo di più stream contemporaneamente in una singola videocamera.
Con un'aggiunta degna di nota, le stesse regole si applicano a più videocamere.
CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA
spiega come sostituire uno stream logico YUV_420_888 o uno stream non elaborato con due
in streaming fisici. Ciò significa che ogni flusso di tipo YUV o RAW può essere sostituito con
due flussi di dimensioni e tipo identici. Puoi iniziare con uno stream della videocamera
la seguente configurazione garantita per i dispositivi con una sola videocamera:
- Stream 1: tipo YUV,
MAXIMUM
dimensione dalla fotocamera logicaid = 0
Quindi, un dispositivo con supporto multicamera ti consente di creare una sessione sostituendo lo stream logico YUV con due flussi fisici:
- Stream 1: tipo YUV,
MAXIMUM
dimensione dalla videocamera fisicaid = 1
- Stream 2: tipo YUV,
MAXIMUM
dimensione dalla videocamera fisicaid = 2
È possibile sostituire uno stream YUV o RAW con due stream equivalenti se e solo se
queste due videocamere fanno parte di un raggruppamento logico delle videocamere,
CameraCharacteristics.getPhysicalCameraIds()
Le garanzie fornite dal framework sono solo il minimo indispensabile per ottenere fotogrammi da più di una fotocamera fisica contemporaneamente. Stream aggiuntivi sono supportati nella maggior parte dei dispositivi, a volte consente anche l'apertura di più fotocamere in modo indipendente. Poiché non è una garanzia rigida dal di Google Cloud, la procedura richiede l'esecuzione di test e ottimizzazioni per dispositivo utilizzando per tentativi.
Creazione di una sessione con più videocamere fisiche
Se utilizzi fotocamere fisiche su un dispositivo con più fotocamere, apri un singolo
CameraDevice
(la fotocamera logica) e interagire con quest'ultima all'interno di una singola
durante la sessione. crea la sessione singola utilizzando l'API
CameraDevice.createCaptureSession(SessionConfiguration config)
, che è
aggiunta al livello API 28. La configurazione della sessione ha una serie
configurazioni, ciascuna delle quali ha un insieme di target di output e, facoltativamente, un
l'ID fisico desiderato della fotocamera.
![](https://developer.android.google.cn/static/images/training/camera/camera2/multi-camera-3.png?authuser=9&hl=it)
Alle richieste di acquisizione è associata una destinazione di output. Il framework determina la videocamera fisica (o logica) a cui vengono inviate le richieste in base la destinazione di output collegata. Se il target di output corrisponde a uno dei target di output inviati come configurazione di output insieme a una dell'ID videocamera, la videocamera fisica riceve ed elabora la richiesta.
Con un paio di fotocamere fisiche
Un'altra aggiunta alle API per videocamere per la modalità multicamera è la capacità di identificare fotocamere logiche e trovare quelle fisiche alle loro spalle. Puoi definire per identificare le potenziali coppie di fotocamere fisiche che puoi utilizzare per sostituire uno degli stream logici della videocamera:
Kotlin
/** * Helper class used to encapsulate a logical camera and two underlying * physical cameras */ data class DualCamera(val logicalId: String, val physicalId1: String, val physicalId2: String) fun findDualCameras(manager: CameraManager, facing: Int? = null): List{ val dualCameras = MutableList () // Iterate over all the available camera characteristics manager.cameraIdList.map { Pair(manager.getCameraCharacteristics(it), it) }.filter { // Filter by cameras facing the requested direction facing == null || it.first.get(CameraCharacteristics.LENS_FACING) == facing }.filter { // Filter by logical cameras // CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA requires API >= 28 it.first.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES)!!.contains( CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA) }.forEach { // All possible pairs from the list of physical cameras are valid results // NOTE: There could be N physical cameras as part of a logical camera grouping // getPhysicalCameraIds() requires API >= 28 val physicalCameras = it.first.physicalCameraIds.toTypedArray() for (idx1 in 0 until physicalCameras.size) { for (idx2 in (idx1 + 1) until physicalCameras.size) { dualCameras.add(DualCamera( it.second, physicalCameras[idx1], physicalCameras[idx2])) } } } return dualCameras }
Java
/** * Helper class used to encapsulate a logical camera and two underlying * physical cameras */ final class DualCamera { final String logicalId; final String physicalId1; final String physicalId2; DualCamera(String logicalId, String physicalId1, String physicalId2) { this.logicalId = logicalId; this.physicalId1 = physicalId1; this.physicalId2 = physicalId2; } } ListfindDualCameras(CameraManager manager, Integer facing) { List dualCameras = new ArrayList<>(); List cameraIdList; try { cameraIdList = Arrays.asList(manager.getCameraIdList()); } catch (CameraAccessException e) { e.printStackTrace(); cameraIdList = new ArrayList<>(); } // Iterate over all the available camera characteristics cameraIdList.stream() .map(id -> { try { CameraCharacteristics characteristics = manager.getCameraCharacteristics(id); return new Pair<>(characteristics, id); } catch (CameraAccessException e) { e.printStackTrace(); return null; } }) .filter(pair -> { // Filter by cameras facing the requested direction return (pair != null) && (facing == null || pair.first.get(CameraCharacteristics.LENS_FACING).equals(facing)); }) .filter(pair -> { // Filter by logical cameras // CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA requires API >= 28 IntPredicate logicalMultiCameraPred = arg -> arg == CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA; return Arrays.stream(pair.first.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES)) .anyMatch(logicalMultiCameraPred); }) .forEach(pair -> { // All possible pairs from the list of physical cameras are valid results // NOTE: There could be N physical cameras as part of a logical camera grouping // getPhysicalCameraIds() requires API >= 28 String[] physicalCameras = pair.first.getPhysicalCameraIds().toArray(new String[0]); for (int idx1 = 0; idx1 < physicalCameras.length; idx1++) { for (int idx2 = idx1 + 1; idx2 < physicalCameras.length; idx2++) { dualCameras.add( new DualCamera(pair.second, physicalCameras[idx1], physicalCameras[idx2])); } } }); return dualCameras; }
La gestione dello stato delle telecamere fisiche è controllata dalla fotocamera logica. A apri una "doppia fotocamera" aprire la fotocamera logica corrispondente al videocamere:
Kotlin
fun openDualCamera(cameraManager: CameraManager, dualCamera: DualCamera, // AsyncTask is deprecated beginning API 30 executor: Executor = AsyncTask.SERIAL_EXECUTOR, callback: (CameraDevice) -> Unit) { // openCamera() requires API >= 28 cameraManager.openCamera( dualCamera.logicalId, executor, object : CameraDevice.StateCallback() { override fun onOpened(device: CameraDevice) = callback(device) // Omitting for brevity... override fun onError(device: CameraDevice, error: Int) = onDisconnected(device) override fun onDisconnected(device: CameraDevice) = device.close() }) }
Java
void openDualCamera(CameraManager cameraManager, DualCamera dualCamera, Executor executor, CameraDeviceCallback cameraDeviceCallback ) { // openCamera() requires API >= 28 cameraManager.openCamera(dualCamera.logicalId, executor, new CameraDevice.StateCallback() { @Override public void onOpened(@NonNull CameraDevice cameraDevice) { cameraDeviceCallback.callback(cameraDevice); } @Override public void onDisconnected(@NonNull CameraDevice cameraDevice) { cameraDevice.close(); } @Override public void onError(@NonNull CameraDevice cameraDevice, int i) { onDisconnected(cameraDevice); } }); }
Oltre a selezionare la videocamera da aprire, la procedura è la stessa dell'apertura una videocamera nelle versioni precedenti di Android. Creazione di una sessione di acquisizione utilizzando il nuovo l'API di configurazione della sessione indica al framework a cui associare determinati target ID fotocamera fisica specifici:
Kotlin
/** * Helper type definition that encapsulates 3 sets of output targets: * * 1. Logical camera * 2. First physical camera * 3. Second physical camera */ typealias DualCameraOutputs = Triple<MutableList?, MutableList?, MutableList?> fun createDualCameraSession(cameraManager: CameraManager, dualCamera: DualCamera, targets: DualCameraOutputs, // AsyncTask is deprecated beginning API 30 executor: Executor = AsyncTask.SERIAL_EXECUTOR, callback: (CameraCaptureSession) -> Unit) { // Create 3 sets of output configurations: one for the logical camera, and // one for each of the physical cameras. val outputConfigsLogical = targets.first?.map { OutputConfiguration(it) } val outputConfigsPhysical1 = targets.second?.map { OutputConfiguration(it).apply { setPhysicalCameraId(dualCamera.physicalId1) } } val outputConfigsPhysical2 = targets.third?.map { OutputConfiguration(it).apply { setPhysicalCameraId(dualCamera.physicalId2) } } // Put all the output configurations into a single flat array val outputConfigsAll = arrayOf( outputConfigsLogical, outputConfigsPhysical1, outputConfigsPhysical2) .filterNotNull().flatMap { it } // Instantiate a session configuration that can be used to create a session val sessionConfiguration = SessionConfiguration( SessionConfiguration.SESSION_REGULAR, outputConfigsAll, executor, object : CameraCaptureSession.StateCallback() { override fun onConfigured(session: CameraCaptureSession) = callback(session) // Omitting for brevity... override fun onConfigureFailed(session: CameraCaptureSession) = session.device.close() }) // Open the logical camera using the previously defined function openDualCamera(cameraManager, dualCamera, executor = executor) { // Finally create the session and return via callback it.createCaptureSession(sessionConfiguration) } }
Java
/** * Helper class definition that encapsulates 3 sets of output targets: ** 1. Logical camera * 2. First physical camera * 3. Second physical camera */ final class DualCameraOutputs { private final List
logicalCamera; private final List firstPhysicalCamera; private final List secondPhysicalCamera; public DualCameraOutputs(List logicalCamera, List firstPhysicalCamera, List third) { this.logicalCamera = logicalCamera; this.firstPhysicalCamera = firstPhysicalCamera; this.secondPhysicalCamera = third; } public List getLogicalCamera() { return logicalCamera; } public List getFirstPhysicalCamera() { return firstPhysicalCamera; } public List getSecondPhysicalCamera() { return secondPhysicalCamera; } } interface CameraCaptureSessionCallback { void callback(CameraCaptureSession cameraCaptureSession); } void createDualCameraSession(CameraManager cameraManager, DualCamera dualCamera, DualCameraOutputs targets, Executor executor, CameraCaptureSessionCallback cameraCaptureSessionCallback) { // Create 3 sets of output configurations: one for the logical camera, and // one for each of the physical cameras. List outputConfigsLogical = targets.getLogicalCamera().stream() .map(OutputConfiguration::new) .collect(Collectors.toList()); List outputConfigsPhysical1 = targets.getFirstPhysicalCamera().stream() .map(s -> { OutputConfiguration outputConfiguration = new OutputConfiguration(s); outputConfiguration.setPhysicalCameraId(dualCamera.physicalId1); return outputConfiguration; }) .collect(Collectors.toList()); List outputConfigsPhysical2 = targets.getSecondPhysicalCamera().stream() .map(s -> { OutputConfiguration outputConfiguration = new OutputConfiguration(s); outputConfiguration.setPhysicalCameraId(dualCamera.physicalId2); return outputConfiguration; }) .collect(Collectors.toList()); // Put all the output configurations into a single flat array List outputConfigsAll = Stream.of( outputConfigsLogical, outputConfigsPhysical1, outputConfigsPhysical2 ) .filter(Objects::nonNull) .flatMap(Collection::stream) .collect(Collectors.toList()); // Instantiate a session configuration that can be used to create a session SessionConfiguration sessionConfiguration = new SessionConfiguration( SessionConfiguration.SESSION_REGULAR, outputConfigsAll, executor, new CameraCaptureSession.StateCallback() { @Override public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) { cameraCaptureSessionCallback.callback(cameraCaptureSession); } // Omitting for brevity... @Override public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) { cameraCaptureSession.getDevice().close(); } }); // Open the logical camera using the previously defined function openDualCamera(cameraManager, dualCamera, executor, (CameraDevice c) -> // Finally create the session and return via callback c.createCaptureSession(sessionConfiguration)); }
Consulta
createCaptureSession
per informazioni sulle combinazioni di flussi supportate. Combinazione di flussi
è per più flussi su una singola videocamera logica. La compatibilità si estende a
utilizzando la stessa configurazione sostituendo uno di questi stream con due
da due fotocamere fisiche che fanno parte della stessa fotocamera logica.
Con sessione con la videocamera pronto, invia richieste di acquisizione. Ciascuna della richiesta di acquisizione riceve i dati dal suo indirizzo fisico videocamera logica, se sono in uso.
Esempio di caso d'uso di Zoom
È possibile utilizzare l'unione di videocamere fisiche in un unico stream in modo che che gli utenti possono passare da una fotocamera fisica all'altra per sperimentare un campo visivo diverso, consentendo di acquisire un "livello di zoom" diverso.
![](https://developer.android.google.cn/static/images/training/camera/camera2/multi-camera-4.gif?authuser=9&hl=it)
Inizia selezionando la coppia di fotocamere fisiche per consentire agli utenti di effettuare il passaggio tra di loro. Per ottenere il massimo effetto, puoi scegliere la coppia di videocamere che forniscono la lunghezza focale minima e massima disponibile.
Kotlin
fun findShortLongCameraPair(manager: CameraManager, facing: Int? = null): DualCamera? { return findDualCameras(manager, facing).map { val characteristics1 = manager.getCameraCharacteristics(it.physicalId1) val characteristics2 = manager.getCameraCharacteristics(it.physicalId2) // Query the focal lengths advertised by each physical camera val focalLengths1 = characteristics1.get( CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS) ?: floatArrayOf(0F) val focalLengths2 = characteristics2.get( CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS) ?: floatArrayOf(0F) // Compute the largest difference between min and max focal lengths between cameras val focalLengthsDiff1 = focalLengths2.maxOrNull()!! - focalLengths1.minOrNull()!! val focalLengthsDiff2 = focalLengths1.maxOrNull()!! - focalLengths2.minOrNull()!! // Return the pair of camera IDs and the difference between min and max focal lengths if (focalLengthsDiff1 < focalLengthsDiff2) { Pair(DualCamera(it.logicalId, it.physicalId1, it.physicalId2), focalLengthsDiff1) } else { Pair(DualCamera(it.logicalId, it.physicalId2, it.physicalId1), focalLengthsDiff2) } // Return only the pair with the largest difference, or null if no pairs are found }.maxByOrNull { it.second }?.first }
Java
// Utility functions to find min/max value in float[] float findMax(float[] array) { float max = Float.NEGATIVE_INFINITY; for(float cur: array) max = Math.max(max, cur); return max; } float findMin(float[] array) { float min = Float.NEGATIVE_INFINITY; for(float cur: array) min = Math.min(min, cur); return min; } DualCamera findShortLongCameraPair(CameraManager manager, Integer facing) { return findDualCameras(manager, facing).stream() .map(c -> { CameraCharacteristics characteristics1; CameraCharacteristics characteristics2; try { characteristics1 = manager.getCameraCharacteristics(c.physicalId1); characteristics2 = manager.getCameraCharacteristics(c.physicalId2); } catch (CameraAccessException e) { e.printStackTrace(); return null; } // Query the focal lengths advertised by each physical camera float[] focalLengths1 = characteristics1.get( CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS); float[] focalLengths2 = characteristics2.get( CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS); // Compute the largest difference between min and max focal lengths between cameras Float focalLengthsDiff1 = findMax(focalLengths2) - findMin(focalLengths1); Float focalLengthsDiff2 = findMax(focalLengths1) - findMin(focalLengths2); // Return the pair of camera IDs and the difference between min and max focal lengths if (focalLengthsDiff1 < focalLengthsDiff2) { return new Pair<>(new DualCamera(c.logicalId, c.physicalId1, c.physicalId2), focalLengthsDiff1); } else { return new Pair<>(new DualCamera(c.logicalId, c.physicalId2, c.physicalId1), focalLengthsDiff2); } }) // Return only the pair with the largest difference, or null if no pairs are found .max(Comparator.comparing(pair -> pair.second)).get().first; }
Un'architettura sensata per farlo sarebbe avere due
SurfaceViews
: uno per ogni stream.
Questi SurfaceViews
vengono scambiati in base all'interazione dell'utente, in modo che solo uno sia
visibili in qualsiasi momento.
Il seguente codice mostra come aprire la fotocamera logica e configurare la fotocamera crea una sessione di videocamera e avvia due stream di anteprima:
Kotlin
val cameraManager: CameraManager = ... // Get the two output targets from the activity / fragment val surface1 = ... // from SurfaceView val surface2 = ... // from SurfaceView val dualCamera = findShortLongCameraPair(manager)!! val outputTargets = DualCameraOutputs( null, mutableListOf(surface1), mutableListOf(surface2)) // Here you open the logical camera, configure the outputs and create a session createDualCameraSession(manager, dualCamera, targets = outputTargets) { session -> // Create a single request which has one target for each physical camera // NOTE: Each target receive frames from only its associated physical camera val requestTemplate = CameraDevice.TEMPLATE_PREVIEW val captureRequest = session.device.createCaptureRequest(requestTemplate).apply { arrayOf(surface1, surface2).forEach { addTarget(it) } }.build() // Set the sticky request for the session and you are done session.setRepeatingRequest(captureRequest, null, null) }
Java
CameraManager manager = ...; // Get the two output targets from the activity / fragment Surface surface1 = ...; // from SurfaceView Surface surface2 = ...; // from SurfaceView DualCamera dualCamera = findShortLongCameraPair(manager, null); DualCameraOutputs outputTargets = new DualCameraOutputs( null, Collections.singletonList(surface1), Collections.singletonList(surface2)); // Here you open the logical camera, configure the outputs and create a session createDualCameraSession(manager, dualCamera, outputTargets, null, (session) -> { // Create a single request which has one target for each physical camera // NOTE: Each target receive frames from only its associated physical camera CaptureRequest.Builder captureRequestBuilder; try { captureRequestBuilder = session.getDevice().createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); Arrays.asList(surface1, surface2).forEach(captureRequestBuilder::addTarget); // Set the sticky request for the session and you are done session.setRepeatingRequest(captureRequestBuilder.build(), null, null); } catch (CameraAccessException e) { e.printStackTrace(); } });
Tutto ciò che devi fare è fornire all'utente un'interfaccia utente per passare da uno all'altro
come un pulsante o il doppio tocco di SurfaceView
. Potresti persino
eseguire un'analisi della scena e passare da un flusso all'altro
automaticamente.
Distorsione dell'obiettivo
Tutti gli obiettivi producono una certa quantità di distorsione. In Android, puoi eseguire query
distorsione creata da obiettivi utilizzando
CameraCharacteristics.LENS_DISTORTION
,
che sostituisce l'ormai deprecato
CameraCharacteristics.LENS_RADIAL_DISTORTION
.
Per le fotocamere logiche, la distorsione è minima e l'applicazione può utilizzare
i fotogrammi più o meno come provengono dalla fotocamera. Per le fotocamere fisiche
ci sono configurazioni di obiettivi potenzialmente molto diverse, soprattutto per i modelli grandangolare
lenti.
Alcuni dispositivi possono implementare la correzione automatica delle distorsioni tramite
CaptureRequest.DISTORTION_CORRECTION_MODE
Per impostazione predefinita, la correzione della distorsione è attiva per la maggior parte dei dispositivi.
Kotlin
val cameraSession: CameraCaptureSession = ... // Use still capture template to build the capture request val captureRequest = cameraSession.device.createCaptureRequest( CameraDevice.TEMPLATE_STILL_CAPTURE ) // Determine if this device supports distortion correction val characteristics: CameraCharacteristics = ... val supportsDistortionCorrection = characteristics.get( CameraCharacteristics.DISTORTION_CORRECTION_AVAILABLE_MODES )?.contains( CameraMetadata.DISTORTION_CORRECTION_MODE_HIGH_QUALITY ) ?: false if (supportsDistortionCorrection) { captureRequest.set( CaptureRequest.DISTORTION_CORRECTION_MODE, CameraMetadata.DISTORTION_CORRECTION_MODE_HIGH_QUALITY ) } // Add output target, set other capture request parameters... // Dispatch the capture request cameraSession.capture(captureRequest.build(), ...)
Java
CameraCaptureSession cameraSession = ...; // Use still capture template to build the capture request CaptureRequest.Builder captureRequestBuilder = null; try { captureRequestBuilder = cameraSession.getDevice().createCaptureRequest( CameraDevice.TEMPLATE_STILL_CAPTURE ); } catch (CameraAccessException e) { e.printStackTrace(); } // Determine if this device supports distortion correction CameraCharacteristics characteristics = ...; boolean supportsDistortionCorrection = Arrays.stream( characteristics.get( CameraCharacteristics.DISTORTION_CORRECTION_AVAILABLE_MODES )) .anyMatch(i -> i == CameraMetadata.DISTORTION_CORRECTION_MODE_HIGH_QUALITY); if (supportsDistortionCorrection) { captureRequestBuilder.set( CaptureRequest.DISTORTION_CORRECTION_MODE, CameraMetadata.DISTORTION_CORRECTION_MODE_HIGH_QUALITY ); } // Add output target, set other capture request parameters... // Dispatch the capture request cameraSession.capture(captureRequestBuilder.build(), ...);
L'impostazione di una richiesta di acquisizione in questa modalità può influire sulla frequenza fotogrammi prodotto dalla fotocamera. Puoi scegliere di impostare la correzione delle distorsioni solo su acquisizioni di immagini statiche.