工业粉尘检测踩坑3次后,我用"暗通道先验"搞定了

在这里插入图片描述

关于作者

我接触视觉整整 10 年

机器视觉、烟草、煤矿等行业都有深度开发经验。从硬件选型、算法开发、模型训练,到上位机开发及部署,都在一线磨过

之前是多家公司人工智能团队的技术负责人。现在自己创业了,还在继续做视觉落地这件事。


作者说

在做视觉这件事之前,我以为最难的是算法开发和模型精度。

后来发现,真正让人崩溃的从来不是算法本身,而是现场那些"没想到"的情况——

  • 摄像头突然逆光,画面一片白
  • 皮带头晃动,带动的尘雾让检测全乱
  • 机器停了,但传感器报告还在"运行"
  • 边缘设备算力不够,一运行就卡死

这些问题是实验室里遇不到的。

所以我打算写一个系列,记录我们在真实工业场景下踩过的坑、解决过的问题。不讲多么酷炫的算法,只聊怎么让算法稳定跑在客户现场

这是第二篇。


踩坑实录:粉尘上来后,我的算法全崩了

那是一个工厂项目。

客户说需求很简单:检测传送带上有没有异物。我信心满满地用 YOLO 训了一个模型,现场部署,测试——

第一天,完美。

第二天早上,现场电话打过来:模型彻底失灵了。

我一看监控画面,好家伙——粉尘全起来了,整个屏幕白茫茫一片,YOLO 框得满屏都是"异物",其实全是误检。

后来才知道,工厂车间下午生产高峰期粉尘浓度会爆表,根本无法正常检测。

这是我踩的第一个坑:没考虑粉尘干扰。


01 问题的本质:粉尘与雾霾的相似性

1.1 粉尘即"人造雾"

从成像角度看,粉尘雾霾本质上是同一类问题:

  • 都是空气中悬浮的颗粒物
  • 都会导致光线散射
  • 都会让图像出现以下特征:
    • 对比度下降:画面变"灰"
    • 细节丢失:远处物体模糊
    • 颜色偏移:色彩变淡、发白

所以,雾霾去雾的算法,可以用来检测粉尘。

1.2 传统方法的局限

在工业场景下,传统的粉尘检测方法有:

方法 原理 局限
激光散射 测量粒子散射光强 需要额外传感器
重量法 称重过滤后的粉尘 离线、无法实时
摄像头 + 阈值 简单判断画面亮度 误检率高,受光照影响大

我们需要一种纯视觉实时鲁棒的方案。


02 暗通道先验原理

2.1 什么是暗通道?

暗通道先验(Dark Channel Prior)是 2009 年何恺明等人提出的,论文标题是《Single Image Haze Removal Using Dark Channel Prior》。

核心发现:在无雾图像中,几乎每个局部区域都存在至少一个"暗通道"像素——即某个通道的强度值非常低。

简单理解:自然场景中,总有一些很暗的地方(比如树叶阴影、黑色汽车、深色建筑)。

2.2 粉尘图像的暗通道

当有粉尘时,这些暗通道的强度会显著提升——因为粉尘颗粒会让光线散射,覆盖了原本的暗细节。

因此:

暗通道强度 ≈ 粉尘程度

2.3 透射率估算

基于暗通道,可以估算出图像的透射率(Transmission)——即每个像素有多少光线是通过粉尘层到达摄像头的。

2.4 粉尘检测公式

我们的核心公式:

粉尘浓度 = f(暗通道强度, 透射率, 光照估计)

实际使用时,我们做了简化:

def estimate_dust_level(img):
    # 计算暗通道
    dark_channel = np.min(img, axis=2)
    
    # 形态学闭操作,去噪
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (15, 15))
    dark_channel = cv2.morphologyEx(dark_channel, cv2.MORPH_CLOSE, kernel)
    
    # 计算平均强度
    dust_score = np.mean(dark_channel)
    
    return dust_score

03 落地避坑指南

坑1:光照干扰

问题:开灯/关灯时,暗通道计算会误判。

解决:增加光照判断,先区分"开灯/关灯"状态,再用不同阈值。

坑2:运动物体干扰

问题:皮带上物体快速移动时,会被误判为粉尘。

解决:结合光流法,只在"静态区域"计算粉尘。

坑3:镜头脏污

问题:镜头沾灰,算法以为是粉尘。

解决:定期自检 + 差分法剔除。


04 完整代码

import cv2
import numpy as np

def preprocess_image(img):
    """图像预处理"""
    # 自动白平衡
    result = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)
    avg_a = np.average(result[:, :, 1])
    avg_b = np.average(result[:, :, 2])
    result[:, :, 1] = result[:, :, 1] - ((avg_a - 128) * (result[:, :, 0] / 255.0) * 1.1)
    result[:, :, 2] = result[:, :, 2] - ((avg_b - 128) * (result[:, :, 0] / 255.0) * 1.1)
    img = cv2.cvtColor(result, cv2.COLOR_LAB2BGR)
    return img

def dark_channel(img, window_size=15):
    """计算暗通道"""
    min_img = np.min(img, axis=2)
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (window_size, window_size))
    dark = cv2.erode(min_img, kernel)
    return dark

def estimate_atmospheric_light(img, dark):
    """估计全局光照"""
    h, w = dark.shape
    num_pixels = h * w
    num_top = int(max(num_pixels // 1000, 1))
    
    flat_dark = dark.flatten()
    flat_img = img.reshape(num_pixels, 3)
    
    idx = np.argsort(flat_dark)[-num_top:]
    
    atmospheric_light = np.max(flat_img[idx], axis=0)
    return atmospheric_light

def estimate_transmission(img, atmospheric_light, window_size=15):
    """估计透射率"""
    img = np.float64(img) / atmospheric_light
    transmission = 1 - dark_channel(img, window_size)
    transmission = np.clip(transmission, 0.1, 1.0)
    return transmission

def dust_detection(img, threshold=0.4):
    """主函数:检测粉尘浓度"""
    img = preprocess_image(img)
    dark = dark_channel(img)
    atmospheric_light = estimate_atmospheric_light(img, dark)
    transmission = estimate_transmission(img, atmospheric_light)
    
    dust_level = 1 - np.mean(transmission)
    is_dusty = dust_level > threshold
    
    return {
        'dust_level': dust_level,
        'is_dusty': is_dusty,
        'transmission': transmission,
        'atmospheric_light': atmospheric_light
    }

# 使用示例
# cap = cv2.VideoCapture(0)
# while True:
#     ret, frame = cap.read()
#     if not ret:
#         break
#     result = dust_detection(frame)
#     print(f"Dust Level: {result['dust_level']:.2f}")
#     cv2.imshow('frame', frame)
#     if cv2.waitKey(1) & 0xFF == ord('q'):
#         break

05 总结

这篇文章分享了我们在工业粉尘检测中的实战方案:

  • 核心思路:借用"暗通道先验"去雾算法,转用于粉尘检测
  • 关键优势:纯视觉、无需额外传感器、实时可用
  • 落地经验:光照自适应 + 运动过滤 + 镜头自检

如果觉得有帮助,点个赞支持一下,后面我会继续更新边缘设备部署、数据闭环实战等系列文章。

有问题评论区见!


📎 相关阅读

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐