Google ML Kit条码扫描性能优化与反向条码识别问题咨询
识别性能优化方案
- 复用扫描器实例:你当前代码每次调用
analyze方法都会新建BarcodeScanner实例,该对象初始化开销极高,直接拖慢识别速度。将扫描器改为分析器的全局成员变量,只在类初始化时创建一次即可。 - 修复
ImageProxy关闭逻辑:你当前代码在异步scanner.process任务还没执行完成时,就直接在方法末尾调用了imageProxy.close(),导致扫描器拿到的帧资源已经被释放,只能等待后续新帧输入,拉长了识别耗时。需要将关闭逻辑移到异步任务的完成回调中,无论识别成功失败都要关闭帧资源,避免内存泄漏。 - 给ImageAnalysis设置目标分辨率:你当前只给Preview和ImageCapture设置了720P的分辨率,ImageAnalysis默认会使用设备支持的最高分辨率,高分辨率帧的处理耗时是720P的数倍,给
ImageAnalysis.Builder也加上setTargetResolution(Size(720, 1280))即可,识别Data Matrix码完全不需要更高的分辨率。 - 移除不必要的相机用例:你同时绑定了预览、拍照、图像分析三个用例,多数中低端设备同时跑三个用例会大幅降低输出帧率,如果你不需要在扫码页面实时拍照,绑定用例时可以先去掉
imageCapture,需要拍照时再动态绑定即可。
反向条码识别(反色处理)解决方案
你拿不到image.bitmapInternal或者image.byteBuffer是因为CameraX输出的mediaImage是YUV_420_888格式的多平面帧数据,本身没有单一ByteBuffer或者内置Bitmap属性,需要先将YUV帧转换为Bitmap再做反色处理,步骤如下:
- 引入YUV转Bitmap的工具方法,将
ImageProxy实例转换为ARGB格式的Bitmap - 对Bitmap做反色处理
- 将处理后的Bitmap转为
InputImage喂给条码扫描器
修改后的分析器参考代码
private class BarCodeAnalyzer(private val listener: BarCodeListener) : ImageAnalysis.Analyzer { // 扫描器改成成员变量,只初始化一次 private val options = BarcodeScannerOptions.Builder() .setBarcodeFormats(Barcode.FORMAT_DATA_MATRIX) .build() private val scanner = BarcodeScanning.getClient(options) @SuppressLint("UnsafeOptInUsageError") override fun analyze(imageProxy: ImageProxy) { val mediaImage = imageProxy.image ?: run { imageProxy.close() return } // 先转Bitmap,YuvToRgbConverter可直接使用官方公开的工具类实现 val yuvToRgbConverter = YuvToRgbConverter(context) // 自行传入可用的Context实例 val bitmap = Bitmap.createBitmap(imageProxy.width, imageProxy.height, Bitmap.Config.ARGB_8888) yuvToRgbConverter.yuvToRgb(mediaImage, bitmap) // 反色处理(支持反向条码) val colorMatrix = ColorMatrix(floatArrayOf( -1f, 0f, 0f, 0f, 255f, 0f, -1f, 0f, 0f, 255f, 0f, 0f, -1f, 0f, 255f, 0f, 0f, 0f, 1f, 0f )) val paint = Paint().apply { colorFilter = ColorMatrixColorFilter(colorMatrix) } val canvas = Canvas(bitmap) canvas.drawBitmap(bitmap, 0f, 0f, paint) // 转InputImage,注意要传入正确的旋转角度 val inputImage = InputImage.fromBitmap(bitmap, imageProxy.imageInfo.rotationDegrees) scanner.process(inputImage) .addOnSuccessListener { barcodes -> barcodes.firstOrNull()?.rawValue?.let { barcode -> Log.d(TAG, barcode) listener(barcode) } } .addOnCompleteListener { // 无论成功失败都关闭帧资源 imageProxy.close() } } }
如果需要同时支持普通和反向条码,可以先对原图做识别,未识别到结果再用反色后的Bitmap做二次识别即可。
内容的提问来源于stack exchange,提问作者Bruce Wayne
相关产品推荐
相关产品推荐

