Android Camera2 全屏预览与实时帧处理全攻略
2025.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中添加摄像头和存储权限(如需保存处理后的图像):
<uses-permission android:name="android.permission.CAMERA" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
对于Android 6.0及以上版本,需在运行时动态请求权限。
三、Camera2全屏预览实现
1. 初始化CameraManager与CameraDevice
private CameraManager cameraManager;private String cameraId;// 初始化CameraManagercameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);// 选择后置摄像头(可根据需求调整)for (String id : cameraManager.getCameraIdList()) {CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(id);Integer lensFacing = characteristics.get(CameraCharacteristics.LENS_FACING);if (lensFacing != null && lensFacing == CameraCharacteristics.LENS_FACING_BACK) {cameraId = id;break;}}
2. 打开CameraDevice
private CameraDevice cameraDevice;private CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {@Overridepublic void onOpened(@NonNull CameraDevice camera) {cameraDevice = camera;createCaptureSession(); // 创建CaptureSession}@Overridepublic void onDisconnected(@NonNull CameraDevice camera) {camera.close();cameraDevice = null;}@Overridepublic void onError(@NonNull CameraDevice camera, int error) {camera.close();cameraDevice = null;}};// 打开摄像头try {cameraManager.openCamera(cameraId, stateCallback, null);} catch (CameraAccessException e) {e.printStackTrace();}
3. 创建CaptureSession与SurfaceView
使用SurfaceView或TextureView实现全屏预览,这里以SurfaceView为例:
private SurfaceView surfaceView;private Surface surface;// 在布局文件中添加SurfaceView// <SurfaceView android:id="@+id/surfaceView" android:layout_width="match_parent" android:layout_height="match_parent" />surfaceView = findViewById(R.id.surfaceView);surface = surfaceView.getHolder().getSurface();// 创建CaptureSessionprivate void createCaptureSession() {try {List<Surface> outputSurfaces = new ArrayList<>();outputSurfaces.add(surface); // 添加预览SurfacecameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() {@Overridepublic void onConfigured(@NonNull CameraCaptureSession session) {startPreview(session); // 开始预览}@Overridepublic void onConfigureFailed(@NonNull CameraCaptureSession session) {// 处理配置失败}}, null);} catch (CameraAccessException e) {e.printStackTrace();}}
4. 开始预览
private void startPreview(CameraCaptureSession session) {try {CaptureRequest.Builder previewRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);previewRequestBuilder.addTarget(surface); // 设置预览Surface// 可选:设置自动对焦、曝光等参数previewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);previewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);CaptureRequest previewRequest = previewRequestBuilder.build();session.setRepeatingRequest(previewRequest, null, null); // 重复请求实现预览} catch (CameraAccessException e) {e.printStackTrace();}}
四、实时获取预览帧进行图像处理
1. 添加ImageReader用于获取帧
private ImageReader imageReader;private static final int IMAGE_WIDTH = 1280;private static final int IMAGE_HEIGHT = 720;// 初始化ImageReaderimageReader = ImageReader.newInstance(IMAGE_WIDTH, IMAGE_HEIGHT, ImageFormat.YUV_420_888, 2);imageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {@Overridepublic void onImageAvailable(ImageReader reader) {Image image = reader.acquireLatestImage();if (image != null) {// 处理图像帧processImage(image);image.close(); // 释放资源}}}, null);// 将ImageReader的Surface添加到CaptureSessionList<Surface> outputSurfaces = new ArrayList<>();outputSurfaces.add(surface); // 预览SurfaceoutputSurfaces.add(imageReader.getSurface()); // 图像处理Surface
2. 图像处理示例(YUV转RGB)
private void processImage(Image image) {Image.Plane[] planes = image.getPlanes();ByteBuffer yBuffer = planes[0].getBuffer();ByteBuffer uBuffer = planes[1].getBuffer();ByteBuffer vBuffer = planes[2].getBuffer();int ySize = yBuffer.remaining();int uSize = uBuffer.remaining();int vSize = vBuffer.remaining();byte[] nv21 = new byte[ySize + uSize + vSize];yBuffer.get(nv21, 0, ySize);vBuffer.get(nv21, ySize, vSize);uBuffer.get(nv21, ySize + vSize, uSize);// YUV420转RGB(示例,实际需根据格式调整)// 可使用RenderScript、OpenCV或自定义算法实现转换// 这里简化为打印日志(实际应处理图像)Log.d("Camera2", "Received image frame: " + nv21.length + " bytes");}
3. 优化建议
- 性能优化:使用
ImageFormat.JPEG或ImageFormat.RGB_565减少数据量,或降低分辨率。 - 线程管理:在后台线程处理图像,避免阻塞UI线程。
- 内存管理:及时关闭
Image对象,避免内存泄漏。 - 格式选择:根据需求选择
YUV_420_888(通用)、JPEG(压缩)或RGB_565(简单处理)。
五、完整流程总结
- 初始化:获取
CameraManager,选择摄像头ID。 - 打开摄像头:通过
CameraManager.openCamera()打开设备。 - 配置Surface:使用
SurfaceView或TextureView显示预览,添加ImageReader的Surface用于获取帧。 - 创建CaptureSession:将预览和图像处理Surface添加到会话。
- 开始预览:发送重复请求实现全屏预览。
- 实时处理:在
ImageReader.OnImageAvailableListener中处理每一帧。
六、结语
通过Android Camera2 API实现全屏预览与实时帧处理,能够满足大多数高级摄像头应用的需求。开发者需注意权限管理、线程安全、内存优化等细节,以确保应用的稳定性和性能。本文提供的代码示例和优化建议,可作为实际开发的参考基础。

发表评论
登录后可评论,请前往 登录 或 注册