简介:本文深入解析Android Camera2 API实现全屏预览与实时获取预览帧进行图像处理的技术要点,涵盖配置优化、帧捕获机制及图像处理流程,助力开发者构建高性能相机应用。
Camera2 API 是 Android 5.0(API 21)引入的全新相机接口,相比已废弃的 Camera1 API,其核心优势在于更精细的控制能力和更低的延迟。Camera2 将相机操作拆解为多个可配置的请求(CaptureRequest),开发者能独立控制对焦、曝光、白平衡等参数,同时支持多摄像头同步和动态分辨率调整。
在全屏预览场景中,Camera2 的输出目标(Surface)配置机制尤为关键。通过将预览 Surface 设置为与屏幕分辨率匹配的 TextureView 或 SurfaceView,可避免画面拉伸或黑边。例如,在配置预览请求时,需明确指定输出尺寸:
// 创建预览用的SurfaceTextureView textureView = findViewById(R.id.texture_view);SurfaceTexture surfaceTexture = textureView.getSurfaceTexture();surfaceTexture.setDefaultBufferSize(previewWidth, previewHeight);Surface previewSurface = new Surface(surfaceTexture);// 配置CaptureRequest.BuilderCaptureRequest.Builder previewBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);previewBuilder.addTarget(previewSurface); // 绑定预览Surface
全屏预览的核心是确保相机输出的图像比例与设备屏幕比例一致。需通过 CameraCharacteristics 获取相机支持的分辨率列表,并筛选出与屏幕宽高比最接近的尺寸:
StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);Size[] previewSizes = map.getOutputSizes(SurfaceTexture.class);// 根据屏幕宽高比筛选最优尺寸Size optimalSize = findOptimalPreviewSize(previewSizes, screenWidth, screenHeight);
为提升预览体验,需配置持续自动对焦(CONTINUOUS_PICTURE)和自动曝光:
previewBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);previewBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
通过监听 TextureView.SurfaceTextureListener 的 onSurfaceTextureSizeChanged 方法,动态调整预览方向:
@Overridepublic void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {int rotation = getWindowManager().getDefaultDisplay().getRotation();cameraDevice.createCaptureSession(Arrays.asList(previewSurface),new CameraCaptureSession.StateCallback() {@Overridepublic void onConfigured(@NonNull CameraCaptureSession session) {// 根据旋转角度更新预览请求}}, backgroundHandler);}
通过 ImageReader 捕获预览帧是实时处理的关键。需配置与预览尺寸相同的 ImageFormat.YUV_420_888 格式,并设置最大图像数:
ImageReader imageReader = ImageReader.newInstance(previewWidth, previewHeight,ImageFormat.YUV_420_888,2 // 缓冲区数量);// 添加到CaptureRequestpreviewBuilder.addTarget(imageReader.getSurface());
通过 ImageReader.OnImageAvailableListener 接收帧数据,转换为可处理的 Image 对象:
imageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {@Overridepublic void onImageAvailable(ImageReader reader) {Image image = reader.acquireLatestImage();if (image != null) {processImage(image); // 自定义处理逻辑image.close();}}}, backgroundHandler);
原始 YUV 数据需转换为 RGB 或 Bitmap 进行算法处理。以下示例展示 YUV420 到 RGB 的转换:
private void yuvToRgb(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[] yData = new byte[ySize];byte[] uData = new byte[uSize];byte[] vData = new byte[vSize];yBuffer.get(yData);uBuffer.get(uData);vBuffer.get(vData);// 使用RenderScript或OpenCV进行YUV到RGB转换// 示例省略具体转换代码}
为避免阻塞相机线程,需将图像处理放在独立线程:
ExecutorService executor = Executors.newSingleThreadExecutor();private void processImage(Image image) {executor.execute(() -> {// 1. YUV转换// 2. 应用图像处理算法(如美颜、滤镜)// 3. 显示或保存结果});}
Image 的 ByteBuffer,避免 byte[] 转换。通过 CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE 限制帧率,平衡性能与功耗:
Range<Integer> fpsRange = new Range<>(15, 30); // 15-30FPSpreviewBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, fpsRange);
HandlerThread 管理。Image 或 Surface。onImageAvailable 中确保调用 image.close(),并在 onPause 中释放 ImageReader。CAMERA 和 WRITE_EXTERNAL_STORAGE。
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)!= PackageManager.PERMISSION_GRANTED) {ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA);}
CameraManager 同时打开前后摄像头。ImageFormat.HEIC 减少存储占用。通过系统掌握 Camera2 的全屏预览与帧捕获机制,开发者能够构建出流畅、低延迟的相机应用,为图像处理、AR 等场景提供坚实基础。实际开发中需结合设备兼容性测试(如使用 Camera2Compat 库)和性能监控工具(如 Android Profiler)持续优化。