You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 06:47:16