Remarque:Cette page fait référence au package Camera2. Nous vous recommandons d'utiliser CameraX, sauf si votre application nécessite des fonctionnalités spécifiques de base de Camera2. CameraX et Camera2 sont compatibles avec Android 5.0 (niveau d'API 21) ou version ultérieure.
La fonctionnalité multi-caméra a été introduite avec Android 9 (niveau d'API 28). Depuis sa sortie, de nouveaux appareils compatibles avec l'API ont été commercialisés. Nombreux cas d'utilisation des appareils photo multiples sont étroitement liés à une configuration matérielle spécifique. Autrement dit, pas tous les cas d'utilisation sont compatibles avec tous les appareils. est un bon candidat pour Play Feature Diffusion.
Voici certains cas d'utilisation types :
- Zoom: passer d'une caméra à l'autre en fonction de la zone recadrée ou de la focale souhaitée
- Profondeur: utiliser plusieurs caméras pour créer une carte de profondeur.
- Bokeh: utilisation d'informations de profondeur déduites pour simuler un passage de type reflex numérique la plage de mise au point.
Différence entre une caméra logique et une caméra physique
Pour comprendre l'API multi-caméra, il faut comprendre la différence entre les caméras logiques et physiques. Pour référence, prenons un appareil avec trois caméras arrière. Dans cet exemple, chacune des trois caméras arrière considéré comme un appareil photo physique. Une caméra logique est alors un regroupement de deux ou plusieurs de ces appareils photo physiques. La sortie de la logique Il peut s'agir d'un flux provenant de l'une des caméras physiques sous-jacentes, ou un flux fusionné provenant de plusieurs caméras physiques sous-jacentes simultanément. Dans tous les cas, le flux est géré par le matériel de la caméra. Couche d'abstraction (HAL).
De nombreux fabricants de téléphones développent des applications photo propriétaires, qui sont préinstallés sur leurs appareils. Pour utiliser toutes les capacités du matériel, ils peuvent utiliser des API privées ou cachées, ou bénéficier d'un traitement spécial de la part l'implémentation du pilote à laquelle les autres applications n'ont pas accès. Un peu les appareils implémentent le concept des caméras logiques en fournissant un flux fusionné de des différentes caméras physiques, mais uniquement pour certains applications. Souvent, une seule des caméras physiques est exposée d'infrastructure. Avant Android 9, la situation était la suivante : illustré dans le schéma suivant:
![](https://developer.android.google.cn/static/images/training/camera/camera2/multi-camera-1.png?authuser=19&hl=fr)
À partir d'Android 9, les API privées ne sont plus autorisées dans les applications Android. Grâce à la prise en charge de plusieurs caméras dans le framework, Android recommandent vivement aux fabricants de téléphones de présenter un appareil photo logique pour toutes les caméras physiques orientées dans la même direction. Voici ce que les développeurs tiers doivent s'attendre à voir sur les appareils équipés d'Android 9 et plus élevée:
![](https://developer.android.google.cn/static/images/training/camera/camera2/multi-camera-2.png?authuser=19&hl=fr)
Ce que fournit l'appareil photo logique dépend entièrement de l'implémentation de l'OEM. du HAL de la caméra. Par exemple, un appareil comme le Pixel 3 implémente sa logique caméra de telle sorte qu'elle sélectionne l'une de ses caméras physiques en fonction la distance focale et la zone recadrée requises.
L'API multi-caméra
La nouvelle API ajoute les nouvelles constantes, classes et méthodes suivantes:
CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA
CameraCharacteristics.getPhysicalCameraIds()
CameraCharacteristics.getAvailablePhysicalCameraRequestKeys()
CameraDevice.createCaptureSession(SessionConfiguration config)
CameraCharacteritics.LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE
OutputConfiguration
etSessionConfiguration
En raison des modifications apportées au document de définition de compatibilité (CDD) Android, le API multi-caméra répond également à certaines attentes des développeurs. Appareils avec deux appareils photo existaient avant Android 9, mais l'ouverture de plusieurs caméras impliquaient simultanément essai et erreur. Sur Android 9 ou version ultérieure, le mode multi-caméra donne un ensemble de règles pour spécifier quand il est possible d'ouvrir une paire de qui appartiennent à la même caméra logique.
Dans la plupart des cas, les appareils équipés d'Android 9 ou version ultérieure exposent toutes les données (à l'exception des capteurs moins courants, comme les caméras infrarouges), une caméra logique plus facile à utiliser. Pour chaque combinaison de flux fonctionne, un flux appartenant à une caméra logique peut être remplacé par deux flux provenant des caméras physiques sous-jacentes.
Diffusion simultanée de plusieurs flux
Utiliser simultanément plusieurs flux de caméra
explique comment utiliser plusieurs flux
simultanément dans une même caméra.
Avec un ajout notable, les mêmes règles s'appliquent pour plusieurs caméras.
CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA
explique comment remplacer un flux logique YUV_420_888 ou un flux brut par deux
flux physiques. Autrement dit, chaque flux de type
YUV ou RAW peut être remplacé par
deux flux de même type et de même taille. Vous pouvez commencer avec le flux de la caméra
la configuration garantie suivante pour les appareils à caméra unique:
- Flux 1: type YUV, taille
MAXIMUM
de l'appareil photo logiqueid = 0
Un appareil compatible avec plusieurs caméras vous permet ensuite de créer une session en remplaçant ce flux YUV logique par deux flux physiques:
- Flux 1: type YUV, taille
MAXIMUM
de la caméra physiqueid = 1
- Flux 2: type YUV, taille
MAXIMUM
de la caméra physiqueid = 2
Vous pouvez remplacer un flux YUV ou RAW par deux flux équivalents si et seulement si
ces deux caméras font partie d'un groupe de caméras logiques, énuméré dans
CameraCharacteristics.getPhysicalCameraIds()
Les garanties fournies par le framework ne sont que le strict minimum requis pour recevoir simultanément des images de plusieurs appareils photo physiques. Flux supplémentaires sont compatibles avec la plupart des appareils, ce qui permet même d'ouvrir plusieurs appareils de façon indépendante. Étant donné qu'il ne s'agit pas d'une garantie stricte ce qui implique d'effectuer des tests et des réglages par appareil à l'aide de par tâtonnement.
Créer une session avec plusieurs caméras physiques
Si vous utilisez des caméras physiques sur un appareil compatible avec les multicaméras, ouvrez un seul
CameraDevice
(l'appareil photo logique) et interagir avec elle dans un seul
session. Créer la session unique à l'aide de l'API
CameraDevice.createCaptureSession(SessionConfiguration config)
, qui était
(ajoutée au niveau d'API 28). La configuration de session contient un certain nombre
de configuration, chacune ayant un ensemble de cibles de sortie et, éventuellement, un
l'ID de caméra physique souhaité.
![](https://developer.android.google.cn/static/images/training/camera/camera2/multi-camera-3.png?authuser=19&hl=fr)
Les requêtes de capture sont associées à une cible de sortie. Le cadre détermine à quelle caméra physique (ou logique) les requêtes sont envoyées en fonction quelle cible de sortie est associée. Si la cible de sortie correspond à l'un des cibles de sortie envoyées en tant que configuration de sortie avec une couche l'ID de caméra, celle-ci reçoit et traite la requête.
Avec une paire d'appareils photo physiques
Un autre ajout aux API d'appareil photo pour le mode multi-caméra est la possibilité d'identifier des caméras logiques et à trouver les caméras physiques derrière elles. Vous pouvez définir pour identifier les paires potentielles d'appareils photo que vous pouvez utiliser pour remplacer l'un des flux de caméra logiques:
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 gestion de l'état des caméras physiques est contrôlée par la caméra logique. À ouvrez un « double appareil photo », ouvrez l'appareil photo logique correspondant caméras:
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); } }); }
En plus de sélectionner l'appareil photo à ouvrir, le processus est le même que pour l'ouverture un appareil photo dans les anciennes versions d'Android. Créer une session de capture à l'aide de la nouvelle l'API de configuration de session indique au framework d'associer certaines cibles identifiants de caméras physiques spécifiques:
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)); }
Voir
createCaptureSession
pour en savoir plus sur les combinaisons de flux acceptées. Combiner des flux
pour plusieurs flux sur une seule caméra logique. La compatibilité s'étend à
en utilisant la même configuration et en remplaçant l'un de ces flux par deux flux
de deux caméras physiques faisant
partie de la même caméra logique.
Avec l'attribut session caméra sont prêtes, envoyez les données demandes de capture. Chaque la cible de la demande de capture reçoit ses données de la couche appareil photo utilisé, le cas échéant, ou revenir à l'appareil photo logique.
Exemple de cas d'utilisation pour Zoom
Il est possible de fusionner des caméras physiques en un seul flux permettant aux utilisateurs de basculer entre les différentes caméras physiques un champ de vision différent, capturant efficacement un "niveau de zoom" différent.
<ph type="x-smartling-placeholder">![](https://developer.android.google.cn/static/images/training/camera/camera2/multi-camera-4.gif?authuser=19&hl=fr)
Commencez par sélectionner la paire de caméras physiques pour permettre aux utilisateurs entre les deux. Pour un effet maximal, choisissez les caméras qui offrent la distance focale minimale et maximale 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; }
Une architecture logique serait d'avoir deux
SurfaceViews
: une pour chaque flux.
Ces SurfaceViews
sont échangés en fonction de l'interaction de l'utilisateur, de sorte qu'un seul soit
visibles à tout moment.
Le code suivant montre comment ouvrir et configurer l'appareil photo logique créez une session de caméra et démarrez deux flux d'aperçu:
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(); } });
Il suffit de fournir une UI permettant à l'utilisateur de basculer entre les deux
surfaces, comme un bouton ou lorsque vous appuyez deux fois sur la SurfaceView
. Vous pourriez même
analyser la scène et passer d'un flux à l'autre
automatiquement.
Distorsion de l'objectif
Tous les objectifs produisent un certain degré de distorsion. Dans Android, vous pouvez interroger
toute distorsion créée par les objectifs
CameraCharacteristics.LENS_DISTORTION
,
qui remplace l'ancienne version
CameraCharacteristics.LENS_RADIAL_DISTORTION
Pour les caméras logiques, la distorsion est minime et votre application peut utiliser
les images plus ou moins
selon qu'elles proviennent de l'appareil photo. Pour les appareils photo physiques,
les configurations d'objectif peuvent être très différentes, en particulier sur les grands
et lentilles.
Certains appareils peuvent implémenter la correction automatique de la distorsion via
CaptureRequest.DISTORTION_CORRECTION_MODE
La correction de la distorsion est activée par défaut pour la plupart des appareils.
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(), ...);
Définir une demande de capture dans ce mode peut avoir un impact sur la fréquence d'images produit par la caméra. Vous pouvez choisir de ne régler la correction de la distorsion des captures d'images fixes.