CameraX图像分析中按需获取高分辨率图像的方案(TensorFlow Lite场景)
解决方案:按需触发高分辨率图像捕获
核心思路是分离实时检测与高分辨率捕获逻辑:用低分辨率的ImageAnalysis维持实时检测性能,仅在检测到目标时,通过CameraX的ImageCapture用例触发高分辨率图像拍摄,再将检测到的目标坐标映射到高分辨率图像上提取细节。
步骤1:初始化高分辨率ImageCapture用例
在原有的Preview和ImageAnalysis初始化代码后,添加高分辨率的ImageCapture配置:
// 高分辨率图像捕获用例,按需触发 val imageCapture = ImageCapture.Builder() .setTargetAspectRatio(AspectRatio.RATIO_4_3) .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY) // 降低捕获延迟 .setTargetResolution(Size(3264, 2448)) // 根据设备支持的高分辨率设置,比如4:3的最高分辨率 .build() // 将所有用例绑定到CameraProvider CameraX.bindToLifecycle( this, cameraSelector, preview, imageAnalyzer, imageCapture )
步骤2:修改检测逻辑,按需触发高分辨率捕获
在detectObjects方法中,当检测到有效目标时,调用imageCapture.takePicture获取高分辨率图像,同时将低分辨率图像中的目标坐标映射到高分辨率图像:
private fun detectObjects(image: ImageProxy) { // 原有的检测逻辑:运行TFLite模型,得到检测结果(包含目标的bounding box:left, top, right, bottom) val detectionResults = runTFLiteDetection(image) if (detectionResults.isNotEmpty()) { // 计算低分辨率与高分辨率的比例 val lowResWidth = image.width.toFloat() val lowResHeight = image.height.toFloat() val highResWidth = imageCapture.targetResolution?.width?.toFloat() ?: lowResWidth val highResHeight = imageCapture.targetResolution?.height?.toFloat() ?: lowResHeight val widthScale = highResWidth / lowResWidth val heightScale = highResHeight / lowResHeight // 触发高分辨率图像捕获 imageCapture.takePicture( cameraExecutor, object : ImageCapture.OnImageCapturedCallback() { override fun onCaptureSuccess(imageProxy: ImageProxy) { // 将低分辨率的检测框转换为高分辨率坐标 detectionResults.forEach { result -> val scaledLeft = result.left * widthScale val scaledTop = result.top * heightScale val scaledRight = result.right * widthScale val scaledBottom = result.bottom * heightScale // 从高分辨率imageProxy中提取目标区域细节,比如转成Bitmap后裁剪 val highResBitmap = imageProxy.toBitmap() val croppedBitmap = Bitmap.createBitmap( highResBitmap, scaledLeft.toInt(), scaledTop.toInt(), (scaledRight - scaledLeft).toInt(), (scaledBottom - scaledTop).toInt() ) // 处理裁剪后的特写图,比如显示、保存等 processCroppedDetail(croppedBitmap) } imageProxy.close() // 必须关闭ImageProxy释放资源 } override fun onError(exception: ImageCaptureException) { // 处理捕获错误 exception.printStackTrace() } } ) } image.close() // 释放低分辨率ImageProxy }
步骤3:添加辅助工具方法(可选)
为了方便ImageProxy转Bitmap,可以添加扩展函数:
private fun ImageProxy.toBitmap(): Bitmap { val buffer = planes[0].buffer buffer.rewind() val bytes = ByteArray(buffer.capacity()) buffer.get(bytes) return BitmapFactory.decodeByteArray(bytes, 0, bytes.size) }
关键注意事项
- 避免频繁触发捕获:可以添加防抖逻辑(比如1秒内只触发一次),防止短时间内多次捕获导致性能下降。
- 分辨率兼容性:
setTargetResolution设置的分辨率需要是设备相机支持的尺寸,建议先通过CameraProvider获取支持的分辨率列表,选择最优的高分辨率4:3尺寸。 - 资源释放:必须确保所有
ImageProxy都被调用close(),否则会导致相机资源泄漏。 - 线程调度:捕获和图像处理都要在后台线程(
cameraExecutor)执行,避免阻塞主线程。
内容的提问来源于stack exchange,提问作者antun
相关产品推荐
相关产品推荐

