首页
学习
活动
专区
圈层
工具
发布

Android Camera2API预览获取当前曝光时间

Android Camera2API 获取当前曝光时间详解

基础概念

Camera2 API 是 Android 5.0 (Lollipop) 引入的新相机框架,取代了旧的 Camera API。它提供了更精细的控制能力,包括手动控制曝光时间、ISO、对焦等参数。

曝光时间是指相机传感器暴露在光线下的时间长度,通常以纳秒(ns)为单位。较长的曝光时间可以让更多光线进入,适合低光环境,但可能导致运动模糊;较短的曝光时间适合明亮环境或快速移动的物体。

获取当前曝光时间的方法

要获取 Camera2 API 的当前曝光时间,需要通过 CameraCharacteristics 和 CaptureResult 来获取相关信息。

1. 检查设备是否支持手动曝光控制

首先需要检查设备是否支持手动曝光控制:

代码语言:txt
复制
CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId);
boolean isManualExposureSupported = characteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES) != null 
    && Arrays.asList(characteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES))
        .contains(CameraMetadata.CONTROL_AE_MODE_OFF);

2. 获取当前曝光时间

在预览过程中,可以通过 CaptureResult 获取当前的曝光时间:

代码语言:txt
复制
private CameraCaptureSession.CaptureCallback captureCallback = new CameraCaptureSession.CaptureCallback() {
    @Override
    public void onCaptureCompleted(@NonNull CameraCaptureSession session,
                                   @NonNull CaptureRequest request,
                                   @NonNull TotalCaptureResult result) {
        Long exposureTime = result.get(CaptureResult.SENSOR_EXPOSURE_TIME);
        if (exposureTime != null) {
            // 曝光时间以纳秒为单位
            Log.d("Camera2API", "当前曝光时间: " + exposureTime + " ns");
            // 转换为更常用的单位,如毫秒
            double exposureTimeMs = exposureTime / 1_000_000.0;
            Log.d("Camera2API", "当前曝光时间: " + exposureTimeMs + " ms");
        }
    }
};

3. 完整示例代码

以下是获取并显示当前曝光时间的完整示例:

代码语言:txt
复制
public class Camera2Activity extends AppCompatActivity {
    private CameraManager cameraManager;
    private String cameraId;
    private CameraDevice cameraDevice;
    private CameraCaptureSession cameraCaptureSession;
    private TextureView textureView;
    private TextView exposureTimeTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_camera2);
        
        textureView = findViewById(R.id.textureView);
        exposureTimeTextView = findViewById(R.id.exposureTimeTextView);
        
        cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
    }

    private void openCamera() {
        try {
            cameraId = cameraManager.getCameraIdList()[0]; // 通常使用后置摄像头
            
            // 检查手动曝光支持
            CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId);
            boolean isManualExposureSupported = characteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES) != null 
                && Arrays.asList(characteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES))
                    .contains(CameraMetadata.CONTROL_AE_MODE_OFF);
            
            if (!isManualExposureSupported) {
                Log.w("Camera2API", "设备不支持手动曝光控制");
            }
            
            if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
                return;
            }
            cameraManager.openCamera(cameraId, stateCallback, null);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    private CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
        @Override
        public void onOpened(@NonNull CameraDevice camera) {
            cameraDevice = camera;
            createCameraPreview();
        }

        @Override
        public void onDisconnected(@NonNull CameraDevice camera) {
            cameraDevice.close();
        }

        @Override
        public void onError(@NonNull CameraDevice camera, int error) {
            cameraDevice.close();
            cameraDevice = null;
        }
    };

    private void createCameraPreview() {
        try {
            SurfaceTexture texture = textureView.getSurfaceTexture();
            assert texture != null;
            texture.setDefaultBufferSize(640, 480); // 设置预览尺寸
            
            Surface surface = new Surface(texture);
            CaptureRequest.Builder captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            captureRequestBuilder.addTarget(surface);
            
            // 设置自动曝光模式
            captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
            
            cameraDevice.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback() {
                @Override
                public void onConfigured(@NonNull CameraCaptureSession session) {
                    if (cameraDevice == null) {
                        return;
                    }
                    cameraCaptureSession = session;
                    try {
                        session.setRepeatingRequest(captureRequestBuilder.build(), captureCallback, null);
                    } catch (CameraAccessException e) {
                        e.printStackTrace();
                    }
                }

                @Override
                public void onConfigureFailed(@NonNull CameraCaptureSession session) {
                    Toast.makeText(Camera2Activity.this, "配置失败", Toast.LENGTH_SHORT).show();
                }
            }, null);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    private CameraCaptureSession.CaptureCallback captureCallback = new CameraCaptureSession.CaptureCallback() {
        @Override
        public void onCaptureCompleted(@NonNull CameraCaptureSession session,
                                       @NonNull CaptureRequest request,
                                       @NonNull TotalCaptureResult result) {
            Long exposureTime = result.get(CaptureResult.SENSOR_EXPOSURE_TIME);
            if (exposureTime != null) {
                double exposureTimeMs = exposureTime / 1_000_000.0;
                runOnUiThread(() -> {
                    exposureTimeTextView.setText(String.format("曝光时间: %.3f ms", exposureTimeMs));
                });
            }
        }
    };

    @Override
    protected void onResume() {
        super.onResume();
        if (textureView.isAvailable()) {
            openCamera();
        } else {
            textureView.setSurfaceTextureListener(textureListener);
        }
    }

    @Override
    protected void onPause() {
        closeCamera();
        super.onPause();
    }

    private void closeCamera() {
        if (cameraCaptureSession != null) {
            cameraCaptureSession.close();
            cameraCaptureSession = null;
        }
        if (cameraDevice != null) {
            cameraDevice.close();
            cameraDevice = null;
        }
    }

    private TextureView.SurfaceTextureListener textureListener = new TextureView.SurfaceTextureListener() {
        @Override
        public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
            openCamera();
        }

        @Override
        public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
        }

        @Override
        public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
            return false;
        }

        @Override
        public void onSurfaceTextureUpdated(SurfaceTexture surface) {
        }
    };
}

常见问题及解决方案

1. 获取的曝光时间为 null 或 0

原因

  • 设备不支持曝光时间查询
  • 自动曝光模式未稳定(刚启动相机时可能需要几帧才能稳定)
  • 在自动曝光模式下,某些设备可能不报告曝光时间

解决方案

  • 等待几帧后再读取曝光时间
  • 检查设备是否支持手动曝光控制
  • 尝试切换到手动曝光模式

2. 曝光时间不准确

原因

  • 设备可能有自己的曝光时间限制和步进值
  • 自动曝光算法可能会动态调整曝光时间

解决方案

  • 查询设备的曝光时间范围:
  • 查询设备的曝光时间范围:
  • 如果需要精确控制,切换到手动曝光模式

3. 手动设置曝光时间无效

原因

  • 未正确关闭自动曝光
  • 设置的曝光时间超出设备支持范围

解决方案

代码语言:txt
复制
// 关闭自动曝光
captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_OFF);
// 设置手动曝光时间(单位:纳秒)
captureRequestBuilder.set(CaptureRequest.SENSOR_EXPOSURE_TIME, desiredExposureTimeInNs);

应用场景

  1. 专业摄影应用:需要精确控制曝光参数的应用
  2. 低光摄影:在弱光环境下可能需要延长曝光时间
  3. 高速摄影:需要极短曝光时间捕捉快速移动物体
  4. 科学成像:需要精确记录曝光参数的科研应用
  5. HDR摄影:在不同曝光时间下拍摄多张照片合成

注意事项

  1. 不同设备的支持程度不同,某些低端设备可能不支持手动曝光控制
  2. 长时间曝光可能导致设备发热或图像噪声增加
  3. 在自动曝光模式下,曝光时间会动态变化以适应环境光线
  4. 曝光时间与ISO感光度密切相关,调整时需要综合考虑
页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

没有搜到相关的文章

领券