Android ML Kit条码扫描:降低图像分辨率提升检测性能
CameraX+MLKit条码扫描提速方案:固定分析流分辨率
你的代码检测速度慢核心原因是构建ImageAnalysis实例时没有指定输出分辨率,CameraX默认会选择相机支持的最高分辨率输出给分析器,高像素机型上单帧像素可达千万级,MLKit处理延迟自然会升高。通过以下修改即可将分析帧分辨率限制在合理范围,大幅提升检测速度,且不会影响预览清晰度。
具体修改步骤
1. 为ImageAnalysis配置目标分辨率
修改ScanCameraFragment.kt里startCamera()方法中的ImageAnalysis构建逻辑,添加分辨率配置,你当前使用的CameraX 1.1.0-beta01版本原生支持该配置,无需升级依赖:
// Image analyzer val imageAnalyzer = ImageAnalysis.Builder() .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST) // 指定分析帧目标分辨率为1024*768,总像素约78万,远低于MLKit推荐的200万性能阈值 .setTargetResolution(Size(1024, 768)) // 对齐预览旋转角度,减少额外坐标转换计算 .setTargetRotation(binding.previewView.display.rotation) .build() .also { it.setAnalyzer(cameraExecutor, QrCodeAnalyzer(context, binding.barcodeBoxView, binding.previewView.width.toFloat(), binding.previewView.height.toFloat() ) ) }
说明:该配置仅作用于条码分析用的图像流,不会影响相机预览的清晰度,用户看到的取景画面会保持正常分辨率。CameraX不会强制输出你填写的固定尺寸,会自动匹配设备相机支持的、和指定值最接近的分辨率,不存在设备兼容问题。如果测试发现小条码识别率不足,可以把分辨率改为
Size(1600,1200),总像素约192万,刚好卡在MLKit推荐的200万阈值内,速度和识别率的平衡表现最好。
2. 修复现有代码的性能损耗与逻辑bug
你当前的QrCodeAnalyzer存在两个拖慢速度的问题,同时有帧泄漏、坐标计算错误的隐患,直接替换为以下实现即可:
class QrCodeAnalyzer(private val context: Context, private val barcodeBoxView: BarcodeBoxView, private val previewViewWidth: Float, private val previewViewHeight: Float) : ImageAnalysis.Analyzer { private var scaleX = 1f private var scaleY = 1f // 扫码客户端提为类成员,只初始化一次,避免每帧新建实例的性能损耗 private val options = BarcodeScannerOptions.Builder().build() private val scanner = BarcodeScanning.getClient(options) private fun translateX(x: Float) = x * scaleX private fun translateY(y: Float) = y * scaleY private fun adjustBoundingRect(rect: Rect) = RectF( translateX(rect.left.toFloat()), translateY(rect.top.toFloat()), translateX(rect.right.toFloat()), translateY(rect.bottom.toFloat()) ) @SuppressLint("UnsafeOptInUsageError") override fun analyze(image: ImageProxy) { val img = image.image if (img != null) { val rotationDegrees = image.imageInfo.rotationDegrees // 根据帧旋转角度修正缩放系数,避免扫码框位置错位 scaleX = if (rotationDegrees == 0 || rotationDegrees == 180) { previewViewWidth / img.width.toFloat() } else { previewViewWidth / img.height.toFloat() } scaleY = if (rotationDegrees == 0 || rotationDegrees == 180) { previewViewHeight / img.height.toFloat() } else { previewViewHeight / img.width.toFloat() } val inputImage = InputImage.fromMediaImage(img, rotationDegrees) scanner.process(inputImage) .addOnSuccessListener { barcodes -> var hasValidBarcode = false for (barcode in barcodes) { barcode?.rawValue?.let { if (it.trim().isNotBlank()) { hasValidBarcode = true Scanner.updateBarcode(it) barcode.boundingBox?.let { rect -> barcodeBoxView.setRect(adjustBoundingRect(rect)) } return@addOnSuccessListener } } } if (!hasValidBarcode) { barcodeBoxView.setRect(RectF()) } } .addOnCompleteListener { // 无论处理成功失败都关闭帧,避免帧队列堵塞 image.close() } } else { image.close() } } }
修改完成后,高像素机型上的单帧处理耗时通常会降到30ms以内,完全满足实时扫码的流畅度要求。
内容的提问来源于stack exchange,提问作者Krishnabhadra
相关产品推荐
相关产品推荐

