3. 经典去噪算法(一):均值滤波、高斯滤波、中值滤波的原理与OpenCV实现
图像去噪,说白了就是给图片「洗脸」。
我刚开始做图像处理那会儿,最头疼的就是噪声。一张好好的照片,拍出来全是雪花点,你说烦不烦?后来慢慢摸清了门道,发现去噪这事儿,其实就三板斧:均值滤波、高斯滤波、中值滤波。
今天咱们就把这三兄弟掰开揉碎了讲清楚。
3.1 均值滤波:简单粗暴的平均主义
均值滤波的思路特别朴素——用周围像素的平均值代替中心像素。
你想想看,如果某个像素是噪声点,它跟周围邻居肯定不一样。那我把周围一圈的像素值加起来取个平均,噪声就被「稀释」了。
3.1.1 原理
假设我们有一个3×3的窗口,中心像素是噪声点。均值滤波的做法是:
- 把窗口内9个像素的灰度值加起来
- 除以9,得到平均值
- 把这个平均值赋给中心像素
用数学公式表达就是:
g(x,y) = (1/(m×n)) × Σ f(i,j)
其中m×n是窗口大小,f(i,j)是原始像素值。
核心要点:窗口越大,平滑效果越强,但图像也会越模糊。这是个典型的「鱼和熊掌不可兼得」的问题。
3.1.2 OpenCV实现
import cv2
import numpy as np
# 读取图像
img = cv2.imread('noisy_image.jpg')
# 均值滤波,窗口大小5×5
blurred = cv2.blur(img, (5, 5))
# 显示结果
cv2.imshow('Original', img)
cv2.imshow('Blurred', blurred)
cv2.waitKey(0)
个人经验:我建议窗口大小选奇数,比如3、5、7。为什么?因为奇数窗口有明确的中心像素,处理起来更自然。偶数窗口虽然也能用,但边界处理会麻烦一些。
3.2 高斯滤波:给邻居们分个亲疏远近
均值滤波有个明显的问题——它把窗口内所有像素一视同仁。但你想啊,离中心越近的像素,按理说应该越「靠谱」才对。
高斯滤波就是来解决这个问题的。它给每个像素分配一个权重,距离中心越近,权重越大。
3.2.1 原理
高斯滤波的核心是高斯核。这个核长什么样呢?
一个3×3的高斯核(σ=0.8):
[1, 2, 1]
[2, 4, 2]
[1, 2, 1]
你看,中心像素的权重是4,四个角上的像素权重只有1。这就是「近朱者赤,近墨者黑」的数学表达。
高斯核的生成公式:
G(x,y) = (1/(2πσ²)) × exp(-(x²+y²)/(2σ²))
其中σ是标准差,控制着权重的分布范围。
避坑指南:我曾经在项目里把σ设得太大,结果图像糊成一团。记住,σ越大,平滑效果越强,但细节丢失也越严重。一般建议σ取0.8到1.5之间。
3.2.2 OpenCV实现
# 高斯滤波,窗口5×5,σ=1.0
gaussian = cv2.GaussianBlur(img, (5, 5), 1.0)
# 也可以只指定σ,让OpenCV自动计算窗口大小
gaussian_auto = cv2.GaussianBlur(img, (0, 0), 1.0)
小技巧:如果你不确定窗口大小该设多少,可以只传σ值,把窗口设为(0,0)。OpenCV会根据σ自动计算合适的窗口大小。我个人习惯用这种方法,省心。
3.3 中值滤波:专治椒盐噪声的猛药
前面两种滤波都是线性滤波,说白了就是做加减乘除。但有些噪声,比如椒盐噪声(黑白点),用线性滤波效果很差。
为什么?因为椒盐噪声的值要么是0(黑),要么是255(白),取平均之后会把周围的像素也带偏。
中值滤波的思路完全不同——它取窗口内所有像素的中位数。
3.3.1 原理
假设窗口内有9个像素值:
[12, 15, 18, 20, 255, 22, 25, 28, 30]
排序后:
[12, 15, 18, 20, 22, 25, 28, 30, 255]
中位数是22,用它代替中心像素。你看,那个255的噪声点直接被跳过了。
核心优势:中值滤波对椒盐噪声有奇效,而且能很好地保留边缘信息。这是线性滤波做不到的。
3.3.2 OpenCV实现
# 中值滤波,窗口大小3
median = cv2.medianBlur(img, 3)
# 对于椒盐噪声严重的图像,可以加大窗口
median_strong = cv2.medianBlur(img, 5)
注意:中值滤波的窗口大小必须是奇数。我见过有人传了偶数进去,结果程序直接报错。嗯,这个坑我踩过。
3.4 三种滤波的对比
说了这么多,咱们来做个对比总结:
| 滤波类型 | 原理 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|---|
| 均值滤波 | 取平均值 | 高斯噪声 | 简单快速 | 边缘模糊严重 |
| 高斯滤波 | 加权平均 | 高斯噪声 | 边缘保留较好 | 计算量稍大 |
| 中值滤波 | 取中位数 | 椒盐噪声 | 边缘保留最好 | 对高斯噪声效果一般 |
3.5 知识体系总览
下面这张图,是我梳理的本章知识结构。你看一眼就能明白三种滤波的关系和区别:
3.6 实战建议
最后,分享几个我在项目中积累的经验:
- 先看噪声类型——如果是椒盐噪声,直接上中值滤波;如果是高斯噪声,高斯滤波更合适。
- 窗口从小试起——我习惯从3×3开始,效果不够再加大。一上来就用大窗口,容易把细节搞丢。
- 边界要处理好——OpenCV默认的边界处理方式是复制边缘像素,但如果你有特殊需求,可以用
borderType参数调整。 - 别迷信单一滤波——有时候把两种滤波组合起来用,效果反而更好。比如先中值滤波去椒盐噪声,再高斯滤波平滑细节。
一个小测试:你可以找一张带噪声的图片,分别用三种滤波处理一下,看看效果差异。我保证,亲手试过之后,你对它们的理解会深很多。