android 设置拍照参数

99ANYc3cd6
预计阅读时长 37 分钟
位置: 首页 参数 正文

核心概念:CameraCaptureSessionCaptureRequest

Camera2 API 中,你并不是直接“告诉”相机拍一张照,而是创建一个“捕获请求”(CaptureRequest),并将其发送给一个“捕获会话”(CameraCaptureSession)。

android 设置拍照参数
(图片来源网络,侵删)
  1. CameraCaptureSession: 这是相机与你的应用之间的桥梁,一旦你配置好这个会话,你就可以向它发送各种捕获请求(比如预览、拍照、录像)。
  2. CaptureRequest: 这是核心对象,它包含了你希望相机在下次捕获时使用的所有参数,你可以把它想象成一个“拍照指令单”,上面详细列明了 ISO、快门速度、对焦模式等所有设置。

设置参数的基本流程

  1. 获取相机实例: 获取 CameraDevice 对象。
  2. 创建 CameraCaptureSession: 使用 CameraDevice 创建一个用于处理捕获请求的会话。
  3. 构建 CaptureRequest.Builder: 从 CameraCaptureSessionCameraDevice 创建一个 CaptureRequest.Builder 对象,这个构建器就像一个模板,你可以往里面添加参数。
  4. 设置参数: 使用 Builder 提供的方法(如 set(CaptureKey, value))来设置你想要的参数。
  5. 应用请求: 将构建好的 CaptureRequest 通过 CameraCaptureSession 发送给相机。

详细步骤与代码示例

下面是一个完整的流程,展示了如何打开相机、创建会话,并在拍照时设置自定义参数。

添加权限和依赖

确保你的 AndroidManifest.xml 中有必要的相机权限。

<!-- AndroidManifest.xml -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera.any" />
<!-- 如果需要写入文件 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
    android:maxSdkVersion="28" />

获取相机管理器和打开相机

// 在你的 Activity 或 Fragment 中
private CameraManager cameraManager;
private CameraDevice cameraDevice;
private String cameraId; // "0" 表示后置摄像头
// ...
// 在 Activity 的 onCreate 或 Fragment 的 onActivityCreated 中
cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
    // 获取所有可用的摄像头 ID
    String[] cameraIds = cameraManager.getCameraIdList();
    if (cameraIds.length > 0) {
        cameraId = cameraIds[0]; // 选择第一个摄像头(通常是后置)
        // 打开相机设备
        cameraManager.openCamera(cameraId, stateCallback, null);
    }
} catch (CameraAccessException e) {
    e.printStackTrace();
}
// CameraDevice.StateCallback 用于监听相机设备状态
private final CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
    @Override
    public void onOpened(@NonNull CameraDevice camera) {
        cameraDevice = camera;
        // 相机打开成功,可以创建捕获会话了
        createCameraCaptureSession();
    }
    @Override
    public void onDisconnected(@NonNull CameraDevice camera) {
        camera.close();
        cameraDevice = null;
    }
    @Override
    public void onError(@NonNull CameraDevice camera, int error) {
        camera.close();
        cameraDevice = null;
    }
};

创建 CameraCaptureSession

private CameraCaptureSession captureSession;
private void createCameraCaptureSession() {
    try {
        // 这里我们只关注拍照,所以先创建一个用于拍照的 Surface
        // 实际应用中,你可能还需要一个用于预览的 Surface
        ImageReader imageReader = ImageReader.newInstance(/* 宽度 */, /* 高度 */, ImageFormat.JPEG, /* 最大图片数量 */2);
        Surface captureSurface = imageReader.getSurface();
        // 创建捕获会话
        cameraDevice.createCaptureSession(Arrays.asList(captureSurface),
                new CameraCaptureSession.StateCallback() {
                    @Override
                    public void onConfigured(@NonNull CameraCaptureSession session) {
                        if (cameraDevice == null) return;
                        captureSession = session;
                        // 会话配置完成,可以开始拍照了
                        takePicture();
                    }
                    @Override
                    public void onConfigureFailed(@NonNull CameraCaptureSession session) {
                        // 会话配置失败
                    }
                }, null);
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
}

构建并应用 CaptureRequest (核心部分)

这是设置参数的关键步骤,我们将在 takePicture() 方法中实现。

private void takePicture() {
    if (cameraDevice == null || captureSession == null) return;
    try {
        // 1. 创建一个用于拍照的 CaptureRequest.Builder
        // 我们传入 TEMPLATE_STILL_CAPTURE,这是一个专门为静态拍照优化的模板
        CaptureRequest.Builder captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
        // 2. 设置目标 Surface
        // 这个 Surface 来自于 ImageReader,用于接收拍照后的 JPEG 数据
        captureRequestBuilder.addTarget(imageReader.getSurface());
        // 3. 设置各种拍照参数 (重点!)
        // -----------------------------------------------------------------
        // 设置闪光灯模式
        captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_AUTO);
        // 设置曝光模式
        captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
        // 设置对焦模式
        // 如果设备支持连续对焦,可以在拍照前先对焦
        captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
        // 在拍照瞬间,可以切换为自动对焦
        // captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO);
        // 或者锁定对焦
        // captureRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_START);
        // 设置白平衡模式
        captureRequestBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CaptureRequest.CONTROL_AWB_MODE_AUTO);
        // 设置感光度 (ISO)
        // 注意:ISO 通常由 AE (自动曝光) 模式控制,手动设置需要特定的 AE 模式
        // captureRequestBuilder.set(CaptureRequest.SENSOR_SENSITIVITY, 800); // 例如设置为 ISO 800
        // 设置曝光时间 (快门速度)
        // 同样,这通常也由 AE 模式控制
        // captureRequestBuilder.set(CaptureRequest.SENSOR_EXPOSURE_TIME, 1000000); // 1/1000 秒 (单位: 纳秒)
        // 设置 JPEG 质量 (0-100)
        captureRequestBuilder.set(CaptureRequest.JPEG_QUALITY, (byte) 90); // 90% 质量
        // 设置照片的旋转角度,确保照片方向正确
        int rotation = getWindowManager().getDefaultDisplay().getRotation();
        int sensorOrientation = cameraManager.getCameraCharacteristics(cameraId).get(CameraCharacteristics.SENSOR_ORIENTATION);
        int jpegRotation = (sensorOrientation + rotation * 90) % 360;
        captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, jpegRotation);
        // 如果需要锁定 AE 和 AF,在拍照前调用
        // captureRequestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, true);
        // captureRequestBuilder.set(CaptureRequest.CONTROL_AF_LOCK, true);
        // -----------------------------------------------------------------
        // 4. 发送捕获请求
        // 使用 REPEATABLE 模式,这样如果会话没有重建,这个请求可以被重复使用
        // 对于单次拍照,使用 CAPTURE_MODE_ONE_SHOT 也可以
        captureSession.capture(captureRequestBuilder.build(), new CameraCaptureSession.CaptureCallback() {
            @Override
            public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
                // 拍照完成,可以在这里处理结果,例如释放锁
                // request.set(CaptureRequest.CONTROL_AE_LOCK, false);
                // request.set(CaptureRequest.CONTROL_AF_LOCK, false);
                Log.d("Camera", "Picture captured successfully!");
            }
        }, null);
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
}

常用参数一览表

参数类别 CaptureRequest 值类型 说明
曝光 CONTROL_AE_MODE int 自动曝光模式。ON_AUTO_FLASH, ON_ALWAYS_FLASH, OFF 等。
CONTROL_AE_LOCK boolean 锁定自动曝光。
SENSOR_EXPOSURE_TIME long 曝光时间(纳秒),手动模式时有效。
SENSOR_SENSITIVITY int 感光度,手动模式时有效。
对焦 CONTROL_AF_MODE int 自动对焦模式。CONTINUOUS_PICTURE, AUTO, MACRO 等。
CONTROL_AF_TRIGGER int 触发对焦。AF_TRIGGER_START, AF_TRIGGER_CANCEL
CONTROL_AF_LOCK boolean 锁定自动对焦。
闪光灯 FLASH_MODE int 闪光灯模式。FLASH_MODE_OFF, FLASH_MODE_AUTO, FLASH_MODE_ON
白平衡 CONTROL_AWB_MODE int 自动白平衡模式。AUTO, INCANDESCENT, DAYLIGHT 等。
CONTROL_AWB_LOCK boolean 锁定自动白平衡。
输出 JPEG_QUALITY byte JPEG 图像质量 (0-100)。
JPEG_ORIENTATION int JPEG 图像的旋转角度 (0, 90, 180, 270)。
JPEG_THUMBNAIL_QUALITY byte JPEG 缩略图质量 (0-100)。
控制 CONTROL_MODE int 同时控制 AE 和 AF,通常设为 USE_SCENE_MODEOFF

重要注意事项

  1. 异步操作: Camera2 API 是完全异步的,所有耗时操作(如打开相机、配置会话)都必须通过回调来完成,绝不能在主线程中调用。
  2. 模板: createCaptureRequest() 需要一个模板参数,不同的模板(TEMPLATE_PREVIEW, TEMPLATE_STILL_CAPTURE, TEMPLATE_RECORD)会预置一组不同的参数,这能让你更快地达到预期的效果。
    • TEMPLATE_PREVIEW: 优化预览速度和帧率。
    • TEMPLATE_STILL_CAPTURE: 优化静态照片的质量,通常会牺牲一些速度。
    • TEMPLATE_RECORD: 优化视频录制。
  3. 设备能力检查: 不是所有设备都支持所有参数,在设置参数前,应该先检查设备是否支持。
    CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId);
    // 检查是否支持手动曝光
    if (characteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES).contains(CaptureRequest.CONTROL_AE_MODE_OFF)) {
        // 设备支持手动模式,可以设置 SENSOR_EXPOSURE_TIME 和 SENSOR_SENSITIVITY
    }
  4. 资源管理: 在 Activity/Fragment 销毁时,必须正确关闭所有相机资源,否则会导致内存泄漏和崩溃。
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (captureSession != null) {
            captureSession.close();
            captureSession = null;
        }
        if (cameraDevice != null) {
            cameraDevice.close();
            cameraDevice = null;
        }
        // 关闭 ImageReader
        if (imageReader != null) {
            imageReader.close();
            imageReader = null;
        }
    }

替代方案:CameraX (推荐给新项目)

如果你觉得 Camera2 API 太复杂,Google 推荐了 CameraX 库,它是对 Camera2 的一层高级封装,极大地简化了代码。

android 设置拍照参数
(图片来源网络,侵删)

使用 CameraX 设置参数非常简单:

// 1. 创建 Preview 用例
Preview preview = new Preview.Builder().build();
// 2. 创建 ImageCapture 用例
ImageCapture imageCapture = new ImageCapture.Builder()
        .setFlashMode(ImageCapture.FLASH_MODE_AUTO) // 设置闪光灯
        .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY) // 设置捕获模式
        .setJpegQuality(90) // 设置 JPEG 质量
        .build();
// 3. 绑定到生命周期
CameraX.bindToLifecycle(this, preview, imageCapture);
// 4. 拍照
imageCapture.takePicture(executor, new ImageCapture.OnImageCapturedCallback() {
    @Override
    public void onCaptureSuccess(@NonNull ImageProxy image) {
        // 获取到图片数据,进行处理或保存
        // ...
    }
    @Override
    public void onError(@NonNull ImageCaptureException exc) {
        // 处理错误
    }
});
  • 对于需要精细控制、高性能或兼容旧设备的项目,直接使用 Camera2 API 是必经之路。
  • 对于大多数新项目,尤其是想快速开发、减少复杂性的项目,强烈推荐使用 CameraX,它提供了更简洁、更现代的 API,但底层仍然是 Camera2
android 设置拍照参数
(图片来源网络,侵删)
-- 展开阅读全文 --
头像
智能拼音输入法免费下载
« 上一篇 今天
Surface Pro 4拆机图解,内部结构如何?
下一篇 » 今天

相关文章

取消
微信二维码
支付宝二维码

最近发表

标签列表

目录[+]