logo

Android Camera2 实战:全屏预览与实时帧处理全解析

作者:很酷cat2025.09.19 11:23浏览量:22

简介:本文深入解析Android Camera2 API实现全屏预览与实时获取预览帧进行图像处理的技术要点,涵盖配置优化、帧捕获机制及图像处理流程,助力开发者构建高性能相机应用。

一、Camera2 API 基础与优势

Camera2 API 是 Android 5.0(API 21)引入的全新相机接口,相比已废弃的 Camera1 API,其核心优势在于更精细的控制能力更低的延迟。Camera2 将相机操作拆解为多个可配置的请求(CaptureRequest),开发者能独立控制对焦、曝光、白平衡等参数,同时支持多摄像头同步和动态分辨率调整。

在全屏预览场景中,Camera2 的输出目标(Surface)配置机制尤为关键。通过将预览 Surface 设置为与屏幕分辨率匹配的 TextureView 或 SurfaceView,可避免画面拉伸或黑边。例如,在配置预览请求时,需明确指定输出尺寸:

  1. // 创建预览用的Surface
  2. TextureView textureView = findViewById(R.id.texture_view);
  3. SurfaceTexture surfaceTexture = textureView.getSurfaceTexture();
  4. surfaceTexture.setDefaultBufferSize(previewWidth, previewHeight);
  5. Surface previewSurface = new Surface(surfaceTexture);
  6. // 配置CaptureRequest.Builder
  7. CaptureRequest.Builder previewBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
  8. previewBuilder.addTarget(previewSurface); // 绑定预览Surface

二、全屏预览的实现要点

1. 屏幕适配与分辨率匹配

全屏预览的核心是确保相机输出的图像比例与设备屏幕比例一致。需通过 CameraCharacteristics 获取相机支持的分辨率列表,并筛选出与屏幕宽高比最接近的尺寸:

  1. StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
  2. Size[] previewSizes = map.getOutputSizes(SurfaceTexture.class);
  3. // 根据屏幕宽高比筛选最优尺寸
  4. Size optimalSize = findOptimalPreviewSize(previewSizes, screenWidth, screenHeight);

2. 自动对焦与曝光控制

为提升预览体验,需配置持续自动对焦(CONTINUOUS_PICTURE)和自动曝光:

  1. previewBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
  2. previewBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);

3. 横竖屏切换处理

通过监听 TextureView.SurfaceTextureListeneronSurfaceTextureSizeChanged 方法,动态调整预览方向:

  1. @Override
  2. public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
  3. int rotation = getWindowManager().getDefaultDisplay().getRotation();
  4. cameraDevice.createCaptureSession(Arrays.asList(previewSurface),
  5. new CameraCaptureSession.StateCallback() {
  6. @Override
  7. public void onConfigured(@NonNull CameraCaptureSession session) {
  8. // 根据旋转角度更新预览请求
  9. }
  10. }, backgroundHandler);
  11. }

三、实时获取预览帧的机制

1. ImageReader 的配置与使用

通过 ImageReader 捕获预览帧是实时处理的关键。需配置与预览尺寸相同的 ImageFormat.YUV_420_888 格式,并设置最大图像数:

  1. ImageReader imageReader = ImageReader.newInstance(
  2. previewWidth, previewHeight,
  3. ImageFormat.YUV_420_888,
  4. 2 // 缓冲区数量
  5. );
  6. // 添加到CaptureRequest
  7. previewBuilder.addTarget(imageReader.getSurface());

2. 帧到达回调处理

通过 ImageReader.OnImageAvailableListener 接收帧数据,转换为可处理的 Image 对象:

  1. imageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
  2. @Override
  3. public void onImageAvailable(ImageReader reader) {
  4. Image image = reader.acquireLatestImage();
  5. if (image != null) {
  6. processImage(image); // 自定义处理逻辑
  7. image.close();
  8. }
  9. }
  10. }, backgroundHandler);

3. YUV 数据转换与处理

原始 YUV 数据需转换为 RGB 或 Bitmap 进行算法处理。以下示例展示 YUV420 到 RGB 的转换:

  1. private void yuvToRgb(Image image) {
  2. Image.Plane[] planes = image.getPlanes();
  3. ByteBuffer yBuffer = planes[0].getBuffer();
  4. ByteBuffer uBuffer = planes[1].getBuffer();
  5. ByteBuffer vBuffer = planes[2].getBuffer();
  6. int ySize = yBuffer.remaining();
  7. int uSize = uBuffer.remaining();
  8. int vSize = vBuffer.remaining();
  9. byte[] yData = new byte[ySize];
  10. byte[] uData = new byte[uSize];
  11. byte[] vData = new byte[vSize];
  12. yBuffer.get(yData);
  13. uBuffer.get(uData);
  14. vBuffer.get(vData);
  15. // 使用RenderScript或OpenCV进行YUV到RGB转换
  16. // 示例省略具体转换代码
  17. }

四、图像处理流水线优化

1. 异步处理架构

为避免阻塞相机线程,需将图像处理放在独立线程:

  1. ExecutorService executor = Executors.newSingleThreadExecutor();
  2. private void processImage(Image image) {
  3. executor.execute(() -> {
  4. // 1. YUV转换
  5. // 2. 应用图像处理算法(如美颜、滤镜)
  6. // 3. 显示或保存结果
  7. });
  8. }

2. 性能关键点

  • 减少内存拷贝:直接操作 ImageByteBuffer,避免 byte[] 转换。
  • 降低分辨率:对实时性要求高的场景,可降低处理分辨率。
  • 算法优化:使用 RenderScript 或 NDK 加速计算密集型操作。

3. 帧率控制

通过 CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE 限制帧率,平衡性能与功耗:

  1. Range<Integer> fpsRange = new Range<>(15, 30); // 15-30FPS
  2. previewBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, fpsRange);

五、常见问题与解决方案

1. 预览卡顿

  • 原因:UI线程阻塞或处理耗时过长。
  • 解决:将所有图像处理移至后台线程,使用 HandlerThread 管理。

2. 内存泄漏

  • 原因:未关闭 ImageSurface
  • 解决:在 onImageAvailable 中确保调用 image.close(),并在 onPause 中释放 ImageReader

3. 权限问题

  • 动态权限:Android 6.0+ 需请求 CAMERAWRITE_EXTERNAL_STORAGE
  • 运行时检查
    1. if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
    2. != PackageManager.PERMISSION_GRANTED) {
    3. ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA);
    4. }

六、进阶优化方向

  1. 多摄像头同步:通过 CameraManager 同时打开前后摄像头。
  2. HEIF 格式支持:使用 ImageFormat.HEIC 减少存储占用。
  3. 机器学习集成:结合 ML Kit 或 TensorFlow Lite 实现实时人脸检测。

通过系统掌握 Camera2 的全屏预览与帧捕获机制,开发者能够构建出流畅、低延迟的相机应用,为图像处理、AR 等场景提供坚实基础。实际开发中需结合设备兼容性测试(如使用 Camera2Compat 库)和性能监控工具(如 Android Profiler)持续优化。

相关文章推荐

发表评论