Nota: Esta página hace referencia al paquete Camera2. A menos que la app requiera funciones específicas y de bajo nivel de Camera2, te recomendamos que uses CameraX. CameraX y Camera2 admiten Android 5.0 (nivel de API 21) y versiones posteriores.
El uso de varias cámaras se introdujo en Android 9 (nivel de API 28). Desde su lanzamiento, llegaron al mercado dispositivos compatibles con la API. Muchos casos de uso de varias cámaras tienen acoplamiento alto con una configuración de hardware específica. En otras palabras, no Todos los casos de uso son compatibles con todos los dispositivos, por lo que el uso de varias cámaras una buena candidata para las funciones de Play Publicación.
Estos son algunos casos prácticos típicos:
- Zoom: Cambiar de cámara según la región de recorte o el enfoque deseado del conjunto de datos.
- Profundidad: Cómo usar varias cámaras para crear un mapa de profundidad
- Bokeh: Uso de información de profundidad inferida para simular una cámara angosta similar a una DSLR. de enfoque.
Diferencias entre una cámara lógica y una física
Para entender la API de varias cámaras, es necesario entender la diferencia entre cámaras físicas y lógicas. A modo de referencia, considera un dispositivo con tres y las cámaras posteriores. En este ejemplo, cada una de las tres cámaras traseras está una cámara física. Entonces, una cámara lógica es un grupo de dos o más de esas cámaras físicas. El resultado de la lógica cámara puede ser una transmisión que proviene de una de las cámaras físicas subyacentes, o una transmisión fusionada que proviene de más de una cámara física subyacente al mismo tiempo. De cualquier manera, el hardware de la cámara controla la transmisión. Capa de abstracción (HAL).
Muchos fabricantes de teléfonos desarrollan aplicaciones de cámara propias, que suelen vienen preinstaladas en sus dispositivos. Para usar todas las capacidades del hardware, pueden usar APIs ocultas o privadas, o recibir un tratamiento especial de la implementación del controlador a la que otras aplicaciones no tienen acceso. Algunos para implementar el concepto de cámaras lógicas, ya que proporcionan una transmisión fusionada de fotogramas de las distintas cámaras físicas, pero solo a ciertos aplicaciones. A menudo, solo una de las cámaras físicas se expone al en un framework de aplicaciones. La situación de los desarrolladores externos antes de Android 9 es ilustradas en el siguiente diagrama:
A partir de Android 9, ya no se permiten las APIs privadas en las apps para Android. Con la compatibilidad con varias cámaras en el framework, Android recomienda que los fabricantes de teléfonos expongan una cámara lógica para todas las cámaras físicas orientadas en la misma dirección. Esto es lo que desarrolladores externos deberían esperar ver en los dispositivos con Android 9 y mayor:
Lo que proporcione la cámara lógica depende por completo de la implementación del OEM de la HAL de la cámara. Por ejemplo, un dispositivo como el Pixel 3 implementa su lógica cámara de tal manera que elige una de sus cámaras físicas en función del la longitud focal y la región de recorte solicitadas.
La API de varias cámaras
La nueva API agrega las siguientes constantes, clases y métodos nuevos:
CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA
CameraCharacteristics.getPhysicalCameraIds()
CameraCharacteristics.getAvailablePhysicalCameraRequestKeys()
CameraDevice.createCaptureSession(SessionConfiguration config)
CameraCharacteritics.LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE
OutputConfiguration
ySessionConfiguration
Debido a cambios en el Documento de definición de compatibilidad de Android (CDD), el de varias cámaras también conlleva ciertas expectativas de los desarrolladores. Dispositivos con cámaras dobles existían antes de Android 9, pero la apertura de más de una cámara al mismo tiempo que implican prueba y error. En Android 9 y versiones posteriores, utiliza varias cámaras ofrece un conjunto de reglas para especificar cuándo es posible abrir un par de cámaras que son parte de la misma cámara lógica.
En la mayoría de los casos, los dispositivos con Android 9 y versiones posteriores exponen todas las (excepto en el caso de los tipos de sensores menos comunes, como los infrarrojos), junto con una cámara lógica fácil de usar. Para cada combinación de transmisiones que sean que funcione, se puede reemplazar una transmisión que pertenezca a una cámara lógica dos transmisiones desde las cámaras físicas subyacentes.
Varias transmisiones a la vez
Cómo usar varias transmisiones de cámara a la vez
abarca las reglas para usar varias transmisiones simultáneas en una sola cámara.
Con una adición importante, se aplican las mismas reglas para varias cámaras.
CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA
explica cómo reemplazar un flujo lógico YUV_420_888 o sin procesar por dos
transmisiones físicas. Es decir, cada transmisión de tipo YUV o RAW se puede reemplazar por
dos flujos del mismo tipo y tamaño. Puedes comenzar con una transmisión de la cámara de
la siguiente configuración garantizada para dispositivos con una sola cámara:
- Transmisión 1: Tipo YUV, tamaño
MAXIMUM
de la cámara lógicaid = 0
Un dispositivo compatible con varias cámaras te permite crear una sesión. y reemplaza esa transmisión lógica YUV con dos transmisiones físicas:
- Transmisión 1: Tipo YUV, tamaño
MAXIMUM
de la cámara físicaid = 1
- Transmisión 2: Tipo YUV, tamaño
MAXIMUM
de la cámara físicaid = 2
Puedes reemplazar una transmisión YUV o RAW con dos transmisiones equivalentes solo si
esas dos cámaras son parte de una agrupación de cámaras lógica, que aparece en
CameraCharacteristics.getPhysicalCameraIds()
Las garantías que proporciona el framework son solo las mínimas requeridas para obtener fotogramas de más de una cámara física a la vez. Transmisiones adicionales son compatibles con la mayoría de los dispositivos y, a veces, incluso se permiten abrir varias dispositivos de cámara de forma independiente. Ya que no es una garantía sólida de la Para ello, se deben realizar pruebas y ajustes por dispositivo mediante ensayo y error.
Crea una sesión con varias cámaras físicas
Cuando uses cámaras físicas en un dispositivo compatible con varias cámaras, abre una sola
CameraDevice
(la cámara lógica) e interactuar con ella en una sola
sesión. Crea la sesión única con la API
CameraDevice.createCaptureSession(SessionConfiguration config)
, que era
agregado en el nivel de API 28. La configuración de la sesión tiene varias salidas
de cada configuración, cada una de las cuales tiene un conjunto de objetivos de salida y, opcionalmente, un
el ID de la cámara física deseada.
Las solicitudes de captura tienen un objetivo de salida asociado. El marco de trabajo determina a qué cámara física (o lógica) se envían las solicitudes según y qué destino de salida se adjunta. Si el destino de salida corresponde a uno de objetivos de salida que se envió como una configuración de salida junto con una el ID de la cámara y, luego, esa cámara física recibe y procesa la solicitud.
Usar un par de cámaras físicas
Otra adición a las API de cámara para varias cámaras es la capacidad de identificar cámaras lógicas y encuentra las cámaras físicas detrás de ellas. Puedes definir para identificar posibles pares de cámaras físicas que puedes usar para reemplazar una de las transmisiones de cámara lógicas:
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 cámara lógica controla el manejo del estado de las cámaras físicas. Para abrir una "cámara doble" abre la cámara lógica correspondiente a la cámaras:
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); } }); }
Además de seleccionar qué cámara abrir, el proceso es el mismo que abrir. una cámara en versiones anteriores de Android. Crear una sesión de captura con el nuevo La API de configuración de sesiones le indica al framework que asocie ciertos destinos con IDs específicos de la cámara física:
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 ?> 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
para obtener información sobre qué combinación de transmisiones es compatible. Combinar transmisiones
es para varias transmisiones en una sola cámara lógica. La compatibilidad se extiende a
usando la misma configuración y reemplazando una de esas transmisiones por dos
de dos cámaras físicas que forman parte de la misma cámara lógica.
Con la sesión de cámara listo, envía el estado deseado solicitudes de captura. Cada objetivo de la solicitud de captura recibe sus datos de su ubicación física cámara, si alguna está en uso, o recurrir a la cámara lógica.
Caso de uso de ejemplo de zoom
Es posible combinar cámaras físicas en una sola transmisión para que los usuarios puedan alternar entre las diferentes cámaras físicas para experimentar un un campo visual diferente, lo que captura eficazmente un “nivel de zoom” diferente.
Primero, selecciona el par de cámaras físicas para permitir que los usuarios cambien en el medio. Para lograr el máximo efecto, puedes elegir el par de cámaras que proporcionan la longitud focal mínima y máxima disponible.
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; }
Una arquitectura razonable para esto sería tener dos
SurfaceViews
: uno para cada transmisión.
Estos SurfaceViews
se intercambian según la interacción del usuario, de manera que solo uno
visibles en cualquier momento.
En el siguiente código, se muestra cómo abrir la cámara lógica y configurar la cámara resultados, crea una sesión de cámara y, luego, inicia dos transmisiones de vista previa:
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(); } });
Lo único que queda por hacer es proporcionar una IU para que el usuario cambie entre los dos.
plataformas, como un botón o presionar dos veces el SurfaceView
. Incluso podrías
realizar algún tipo de análisis de escena y alternar entre las dos transmisiones
automáticamente.
Distorsión del lente
Todos los lentes producen cierta distorsión. En Android, puedes consultar
distorsión creada por las lentes con
CameraCharacteristics.LENS_DISTORTION
:
que reemplaza la versión obsoleta
CameraCharacteristics.LENS_RADIAL_DISTORTION
Para cámaras lógicas, la distorsión es mínima y tu aplicación puede usar
los fotogramas en mayor o menor medida
a medida que salen de la cámara. Para las cámaras físicas,
existen posibles configuraciones de lentes muy diferentes, especialmente en modelos
con lentes inteligentes.
Algunos dispositivos pueden implementar la corrección automática de distorsión mediante
CaptureRequest.DISTORTION_CORRECTION_MODE
La corrección de distorsión está activada de forma predeterminada en la mayoría de los dispositivos.
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(), ...);
Configurar una solicitud de captura en este modo puede afectar la velocidad de fotogramas que se puede producidos por la cámara. Puedes elegir establecer la corrección de distorsión únicamente en capturas de imágenes fijas.