logo

Android Camera2 全屏预览与实时帧处理全攻略

作者:rousong2025.09.19 11:23浏览量:5

简介:本文详细讲解如何利用Android Camera2 API实现全屏预览,并实时获取预览帧进行图像处理,包括环境配置、关键代码实现及优化建议。

一、引言

在Android应用开发中,摄像头功能是许多场景的核心需求,如实时滤镜、人脸识别、AR应用等。Android Camera2 API提供了比旧版Camera API更灵活、强大的控制能力,支持全屏预览、多摄像头切换、实时帧处理等高级功能。本文将深入探讨如何使用Camera2 API实现全屏预览,并实时获取预览帧进行图像处理,为开发者提供一套完整的解决方案。

二、环境准备与权限配置

1. 环境要求

  • Android 5.0(API 21)及以上版本。
  • 支持Camera2 API的设备(可通过CameraManager.getCameraCharacteristics()检查)。

2. 权限配置

AndroidManifest.xml中添加摄像头和存储权限(如需保存处理后的图像):

  1. <uses-permission android:name="android.permission.CAMERA" />
  2. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

对于Android 6.0及以上版本,需在运行时动态请求权限。

三、Camera2全屏预览实现

1. 初始化CameraManager与CameraDevice

  1. private CameraManager cameraManager;
  2. private String cameraId;
  3. // 初始化CameraManager
  4. cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
  5. // 选择后置摄像头(可根据需求调整)
  6. for (String id : cameraManager.getCameraIdList()) {
  7. CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(id);
  8. Integer lensFacing = characteristics.get(CameraCharacteristics.LENS_FACING);
  9. if (lensFacing != null && lensFacing == CameraCharacteristics.LENS_FACING_BACK) {
  10. cameraId = id;
  11. break;
  12. }
  13. }

2. 打开CameraDevice

  1. private CameraDevice cameraDevice;
  2. private CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
  3. @Override
  4. public void onOpened(@NonNull CameraDevice camera) {
  5. cameraDevice = camera;
  6. createCaptureSession(); // 创建CaptureSession
  7. }
  8. @Override
  9. public void onDisconnected(@NonNull CameraDevice camera) {
  10. camera.close();
  11. cameraDevice = null;
  12. }
  13. @Override
  14. public void onError(@NonNull CameraDevice camera, int error) {
  15. camera.close();
  16. cameraDevice = null;
  17. }
  18. };
  19. // 打开摄像头
  20. try {
  21. cameraManager.openCamera(cameraId, stateCallback, null);
  22. } catch (CameraAccessException e) {
  23. e.printStackTrace();
  24. }

3. 创建CaptureSession与SurfaceView

使用SurfaceViewTextureView实现全屏预览,这里以SurfaceView为例:

  1. private SurfaceView surfaceView;
  2. private Surface surface;
  3. // 在布局文件中添加SurfaceView
  4. // <SurfaceView android:id="@+id/surfaceView" android:layout_width="match_parent" android:layout_height="match_parent" />
  5. surfaceView = findViewById(R.id.surfaceView);
  6. surface = surfaceView.getHolder().getSurface();
  7. // 创建CaptureSession
  8. private void createCaptureSession() {
  9. try {
  10. List<Surface> outputSurfaces = new ArrayList<>();
  11. outputSurfaces.add(surface); // 添加预览Surface
  12. cameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() {
  13. @Override
  14. public void onConfigured(@NonNull CameraCaptureSession session) {
  15. startPreview(session); // 开始预览
  16. }
  17. @Override
  18. public void onConfigureFailed(@NonNull CameraCaptureSession session) {
  19. // 处理配置失败
  20. }
  21. }, null);
  22. } catch (CameraAccessException e) {
  23. e.printStackTrace();
  24. }
  25. }

4. 开始预览

  1. private void startPreview(CameraCaptureSession session) {
  2. try {
  3. CaptureRequest.Builder previewRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
  4. previewRequestBuilder.addTarget(surface); // 设置预览Surface
  5. // 可选:设置自动对焦、曝光等参数
  6. previewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
  7. previewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
  8. CaptureRequest previewRequest = previewRequestBuilder.build();
  9. session.setRepeatingRequest(previewRequest, null, null); // 重复请求实现预览
  10. } catch (CameraAccessException e) {
  11. e.printStackTrace();
  12. }
  13. }

四、实时获取预览帧进行图像处理

1. 添加ImageReader用于获取帧

  1. private ImageReader imageReader;
  2. private static final int IMAGE_WIDTH = 1280;
  3. private static final int IMAGE_HEIGHT = 720;
  4. // 初始化ImageReader
  5. imageReader = ImageReader.newInstance(IMAGE_WIDTH, IMAGE_HEIGHT, ImageFormat.YUV_420_888, 2);
  6. imageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
  7. @Override
  8. public void onImageAvailable(ImageReader reader) {
  9. Image image = reader.acquireLatestImage();
  10. if (image != null) {
  11. // 处理图像帧
  12. processImage(image);
  13. image.close(); // 释放资源
  14. }
  15. }
  16. }, null);
  17. // 将ImageReader的Surface添加到CaptureSession
  18. List<Surface> outputSurfaces = new ArrayList<>();
  19. outputSurfaces.add(surface); // 预览Surface
  20. outputSurfaces.add(imageReader.getSurface()); // 图像处理Surface

2. 图像处理示例(YUV转RGB)

  1. private void processImage(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[] nv21 = new byte[ySize + uSize + vSize];
  10. yBuffer.get(nv21, 0, ySize);
  11. vBuffer.get(nv21, ySize, vSize);
  12. uBuffer.get(nv21, ySize + vSize, uSize);
  13. // YUV420转RGB(示例,实际需根据格式调整)
  14. // 可使用RenderScript、OpenCV或自定义算法实现转换
  15. // 这里简化为打印日志(实际应处理图像)
  16. Log.d("Camera2", "Received image frame: " + nv21.length + " bytes");
  17. }

3. 优化建议

  • 性能优化:使用ImageFormat.JPEGImageFormat.RGB_565减少数据量,或降低分辨率。
  • 线程管理:在后台线程处理图像,避免阻塞UI线程。
  • 内存管理:及时关闭Image对象,避免内存泄漏。
  • 格式选择:根据需求选择YUV_420_888(通用)、JPEG(压缩)或RGB_565(简单处理)。

五、完整流程总结

  1. 初始化:获取CameraManager,选择摄像头ID。
  2. 打开摄像头:通过CameraManager.openCamera()打开设备。
  3. 配置Surface:使用SurfaceViewTextureView显示预览,添加ImageReader的Surface用于获取帧。
  4. 创建CaptureSession:将预览和图像处理Surface添加到会话。
  5. 开始预览:发送重复请求实现全屏预览。
  6. 实时处理:在ImageReader.OnImageAvailableListener中处理每一帧。

六、结语

通过Android Camera2 API实现全屏预览与实时帧处理,能够满足大多数高级摄像头应用的需求。开发者需注意权限管理、线程安全、内存优化等细节,以确保应用的稳定性和性能。本文提供的代码示例和优化建议,可作为实际开发的参考基础。

相关文章推荐

发表评论

活动