基于MLKit(TensorFlow)实现Camera2 API拍摄图片的模糊检测
图片模糊检测方案(替代OpenCV/基于MLKit或原生实现)
核心结论
可以通过MLKit集成轻量TensorFlow Lite模型实现模糊检测,也可以用Android原生代码计算图像方差的方式实现,两种方案都能避免OpenCV带来的APK体积暴涨问题。
方案一:Android原生实现(零额外体积)
直接通过计算图像的Laplacian算子方差判断模糊程度,方差越小图像越模糊。该方案无需依赖任何第三方库,速度快,适合大多数场景。
代码示例(Kotlin)
fun isImageBlurry(bitmap: Bitmap, threshold: Int = 100): Boolean { // 将图片转为灰度图 val grayBitmap = Bitmap.createBitmap(bitmap.width, bitmap.height, Bitmap.Config.ARGB_8888) Canvas(grayBitmap).apply { val paint = Paint().apply { colorFilter = ColorMatrixColorFilter(ColorMatrix().apply { setSaturation(0f) }) } drawBitmap(bitmap, 0f, 0f, paint) } // 计算Laplacian算子的方差 val width = grayBitmap.width val height = grayBitmap.height val pixels = IntArray(width * height) grayBitmap.getPixels(pixels, 0, width, 0, 0, width, height) var laplacianSum = 0 var validPixelCount = 0 // 遍历图像(跳过边缘像素) for (y in 1 until height - 1) { for (x in 1 until width - 1) { val index = y * width + x // 计算Laplacian值 val laplacian = -pixels[index - width - 1] - pixels[index - width] - pixels[index - width + 1] - pixels[index - 1] + 8 * pixels[index] - pixels[index + 1] - pixels[index + width - 1] - pixels[index + width] - pixels[index + width + 1] laplacianSum += laplacian * laplacian validPixelCount++ } } val variance = laplacianSum / validPixelCount // 方差低于阈值则判定为模糊 return variance < threshold }
优化建议
- 可根据实际场景调整
threshold值(比如纹理少的场景阈值设为50,纹理丰富的场景设为150); - 可以在Camera2的预览帧中实时检测,达到清晰阈值后再触发拍摄,减少无效模糊照片。
方案二:MLKit集成轻量TFLite模型
MLKit本身没有官方的模糊检测API,但可以通过集成自定义的轻量TensorFlow Lite模型实现,体积增加远小于OpenCV(模型文件通常小于1MB),且准确率可通过训练优化。
步骤1:准备TFLite模型
- 可以自己训练一个二分类模型(输入灰度图,输出「清晰/模糊」概率),或使用开源的轻量模糊检测模型;
- 确保模型输入尺寸适配移动端(比如224x224或128x128),减少计算量。
步骤2:集成MLKit依赖
在app模块的build.gradle中添加依赖:
dependencies { // MLKit TFLite核心依赖 implementation 'com.google.mlkit:tensorflow-lite:16.0.0' // TFLite支持库(简化模型加载与预处理) implementation 'com.google.mlkit:tensorflow-lite-support:1.1.0' }
步骤3:模型推理代码示例
class BlurDetector(private val context: Context) { private lateinit var interpreter: TensorFlowLite init { // 加载assets中的TFLite模型文件 val modelFile = FileUtil.loadMappedFile(context, "blur_detect.tflite") val options = TensorFlowLite.Options().apply { // 启用硬件加速(可选) setUseNnapi(true) } interpreter = TensorFlowLite.newInstance(modelFile, options) } fun detectBlurProbability(bitmap: Bitmap): Float { // 预处理:缩放为模型输入尺寸,转为灰度并归一化 val inputSize = 224 val scaledBitmap = Bitmap.createScaledBitmap(bitmap, inputSize, inputSize, true) val inputBuffer = TensorBuffer.createFixedSize(intArrayOf(1, inputSize, inputSize, 1), DataType.FLOAT32) val pixels = IntArray(inputSize * inputSize) scaledBitmap.getPixels(pixels, 0, inputSize, 0, 0, inputSize, inputSize) pixels.forEachIndexed { index, pixel -> // 转为灰度并归一化到[0,1] val grayValue = (Color.red(pixel) + Color.green(pixel) + Color.blue(pixel)) / 3.0f / 255.0f inputBuffer.loadArray(floatArrayOf(grayValue), index, 1) } // 执行推理 val outputBuffer = TensorBuffer.createFixedSize(intArrayOf(1, 2), DataType.FLOAT32) interpreter.run(inputBuffer.buffer, outputBuffer.buffer) // 假设输出数组索引1对应模糊概率(根据模型输出定义调整) return outputBuffer.floatArray[1] } fun release() { interpreter.close() } }
优化建议
- 启用NNAPI或GPU加速,提升推理速度;
- 结合Camera2的预览帧做实时检测,提前过滤模糊场景。
额外优化建议
- 优化Camera2拍摄流程:监听对焦状态,确保
CONTROL_AF_STATE变为FOCUSED_LOCKED后再触发图像捕获,从源头减少模糊照片; - 多帧验证:如果单帧检测不稳定,可以连续检测3-5帧,取多数结果作为最终判断;
- 动态阈值:根据场景亮度、纹理复杂度动态调整模糊判定阈值,提升准确率。
内容的提问来源于stack exchange,提问作者Kapil Rajput
相关产品推荐
相关产品推荐

