4. 图像滤波与去噪:均值滤波、高斯滤波、中值滤波、双边滤波的原理与OpenCV实现
图像滤波,说白了就是给图像做「磨皮」或者「去杂质」。在工业现场,相机拍回来的图很少是干干净净的——传感器噪声、光照不均、传输干扰,都会让图像带上各种噪点。如果不处理,后续的检测、测量、识别全都会受影响。
我个人习惯把滤波分成两类:线性滤波和非线性滤波。均值、高斯属于前者,中值、双边属于后者。下面一个一个讲清楚。
4.1 均值滤波
均值滤波的原理最简单:用一个窗口扫过图像,窗口内所有像素取平均值,作为中心像素的新值。
举个例子,一个 3×3 的窗口,9 个像素值加起来除以 9,就是新值。窗口越大,平滑效果越强,但图像也越模糊。
import cv2
import numpy as np
img = cv2.imread('industrial_part.jpg', cv2.IMREAD_GRAYSCALE)
# 均值滤波:ksize 必须是奇数
blur_3 = cv2.blur(img, (3, 3))
blur_5 = cv2.blur(img, (5, 5))
blur_9 = cv2.blur(img, (9, 9))
你看,代码就一行。但参数 ksize 很关键。3×3 基本不损失细节,但去噪能力有限;9×9 去噪强,但边缘也糊得差不多了。我一般从 5×5 开始试。
4.2 高斯滤波
高斯滤波和均值滤波的区别在于「权重」。均值滤波是平均主义,高斯滤波是「中心说了算」——离中心越近的像素权重越大,权重由高斯函数决定。
为什么这样更好?因为自然图像中,中心像素和周围像素的相关性本来就更高。高斯滤波更符合直觉,效果也更自然。
ksize(核大小)和 sigmaX(标准差)。sigma 越大,权重分布越平缓,平滑效果越强。
# 高斯滤波
gauss_3 = cv2.GaussianBlur(img, (3, 3), sigmaX=0)
gauss_5 = cv2.GaussianBlur(img, (5, 5), sigmaX=1.0)
gauss_9 = cv2.GaussianBlur(img, (9, 9), sigmaX=2.0)
这里有个小细节:sigmaX=0 时,OpenCV 会根据核大小自动计算 sigma。我个人习惯手动指定 sigma,因为控制感更强。
4.3 中值滤波
中值滤波是非线性滤波的代表。它不取平均,而是取窗口内所有像素的中位数作为新值。
为什么中值滤波对椒盐噪声特别有效?你想想看,椒盐噪声是极亮或极暗的像素点,取中位数时这些极端值根本排不上号,直接被忽略掉了。
# 中值滤波
median_3 = cv2.medianBlur(img, 3)
median_5 = cv2.medianBlur(img, 5)
注意:中值滤波的核大小只用一个数字,因为窗口是正方形的。而且它必须用奇数,3、5、7……道理很简单,奇数个数字才有唯一的中位数。
4.4 双边滤波
双边滤波是「既要又要」的典型代表——既要平滑噪声,又要保留边缘。它怎么做到的?
双边滤波在计算权重时考虑两个因素:
- 空间距离:离中心越近,权重越大(和高斯一样)
- 像素值差异:和中心像素值越接近,权重越大
这样一来,在平坦区域,双边滤波像高斯一样平滑;但在边缘处,像素值差异大,边缘另一侧的像素权重被压低,边缘就保住了。
# 双边滤波
# d: 邻域直径,sigmaColor: 颜色标准差,sigmaSpace: 空间标准差
bilateral = cv2.bilateralFilter(img, d=9, sigmaColor=75, sigmaSpace=75)
d:窗口直径。越大,考虑的范围越广,计算越慢。sigmaColor:颜色差异的容忍度。越大,越多的颜色差异被平滑掉。sigmaSpace:空间距离的权重。越大,远处的像素影响越大。
双边滤波的缺点也很明显——慢。在工业实时场景下,如果图像分辨率高,双边滤波可能成为瓶颈。我曾经在一个 500 万像素的检测项目里试过双边滤波,一帧处理了 200 多毫秒,根本跑不到 30fps。后来换成了引导滤波才解决。
4.5 四种滤波对比总结
| 滤波器 | 类型 | 去噪效果 | 边缘保留 | 计算速度 | 适用噪声 |
|---|---|---|---|---|---|
| 均值滤波 | 线性 | 一般 | 差 | 快 | 高斯噪声 |
| 高斯滤波 | 线性 | 较好 | 一般 | 快 | 高斯噪声 |
| 中值滤波 | 非线性 | 好(椒盐) | 好 | 中等 | 椒盐噪声 |
| 双边滤波 | 非线性 | 好 | 极好 | 慢 | 高斯噪声 + 保边 |
4.6 实战建议:如何选择滤波器
在工业视觉项目中,我一般按这个流程来选:
- 先看噪声类型:如果是椒盐噪声(黑白点),直接上中值滤波。如果是高斯噪声(整体颗粒感),用高斯滤波。
- 再看任务需求:如果后续要做边缘检测或测量,必须保边,那就用双边滤波或中值滤波。如果只是做图像增强前的预处理,高斯滤波就够了。
- 最后考虑速度:实时检测场景(比如 30fps 以上),双边滤波基本不用想。中值滤波在核大小不超过 5 时还能接受。
嗯,滤波这部分就讲到这里。记住一句话:没有最好的滤波器,只有最合适的滤波器。多试几个参数,多看看效果图,你自然就有感觉了。