经典降噪算法(上):均值滤波、高斯滤波、中值滤波的原理与OpenCV实现

各位同学,今天我们正式进入降噪算法的核心地带。说实话,很多初学者一上来就调OpenCV的blur或GaussianBlur,参数随便填,效果不好就换下一个。这种做法,我见过太多项目翻车了。

这一章,咱们把三个最经典的滤波算法——均值、高斯、中值——彻底讲透。我会结合自己踩过的坑,告诉你什么时候该用哪个,怎么调参数才靠谱。

经典降噪算法对比 均值滤波 核心:邻域像素取平均 特点:简单快速,但边缘模糊 高斯滤波 核心:加权平均,中心权重高 特点:更自然,保留边缘更好 中值滤波 核心:取邻域中值代替 特点:去椒盐噪声极佳 适用场景速查 高斯噪声 → 高斯滤波 椒盐噪声 → 中值滤波 实时预览 → 均值滤波 纹理保留 → 高斯滤波 边缘保护 → 中值滤波 去马赛克预处理 → 高斯滤波

1. 均值滤波:最朴素的降噪方式

均值滤波的原理,说白了就是「拉兄弟一把」。把目标像素周围一圈像素的值加起来,除以总数,结果就是新像素值。

举个例子,一个3×3的窗口,中心像素原本是100,周围全是噪声点。平均之后,中心值会被拉向周围,噪声就被「抹平」了。

核心公式:

g(x,y) = (1 / (m×n)) × Σ f(i,j)

其中 m×n 是核大小,f(i,j) 是邻域像素值。

OpenCV实现非常简单:

import cv2
import numpy as np

# 读取图像
img = cv2.imread('noisy_image.jpg')

# 均值滤波,核大小5×5
blurred = cv2.blur(img, (5, 5))

# 或者用方框滤波(归一化模式)
box_filtered = cv2.boxFilter(img, -1, (5, 5), normalize=True)

我的经验:均值滤波在项目里我一般只用来做快速预览。有一次做实时视频降噪,客户要求30fps,均值滤波跑得飞快,但画面像蒙了一层雾。后来换了高斯滤波,帧率降了一点,但效果好了不止一个档次。

2. 高斯滤波:更聪明的加权平均

高斯滤波和均值滤波最大的区别在于——它不搞「平均主义」。离中心越近的像素,权重越大;越远的,权重越小。这个权重分布,就是高斯函数。

你想想看,一张照片里,中心像素和它紧挨着的邻居,相关性肯定比角落里的像素高。高斯滤波正好抓住了这个特点。

高斯核生成示例(3×3,σ=1.0):

0.0750.1240.075
0.1240.2040.124
0.0750.1240.075

看到没?中心权重0.204,是角落0.075的近3倍。

OpenCV实现:

# 高斯滤波,核大小5×5,sigma=1.5
gaussian = cv2.GaussianBlur(img, (5, 5), 1.5)

# 只指定sigma,核大小自动计算
gaussian_auto = cv2.GaussianBlur(img, (0, 0), 1.5)

注意:核大小必须是奇数。为什么?因为奇数才有明确的中心像素。我曾经见过有人传了(4,4),OpenCV直接报错,排查了半天才发现是这个问题。

关于sigma的选择,我个人的习惯是:

  • σ = 0.8 ~ 1.2:轻度降噪,保留细节
  • σ = 1.5 ~ 2.5:中度降噪,适合一般场景
  • σ > 3.0:重度降噪,图像会明显变模糊

避坑指南:我曾经在医疗影像项目里,为了去噪把sigma调到4.0,结果病灶边缘全糊了,医生根本没法看。后来改成sigma=1.8,配合后续的边缘增强,效果才达标。记住:降噪不是越狠越好,保留边缘信息才是关键。

3. 中值滤波:椒盐噪声的克星

中值滤波的思路完全不同。它不计算平均值,而是把邻域内所有像素排序,取中间那个值。

为什么要这么做?你想想看,椒盐噪声是随机出现的白点或黑点,值要么极大(255),要么极小(0)。如果取平均,这个极端值会把结果拉偏。但取中值呢?排序之后,极端值要么在头要么在尾,中间那个值大概率是正常的像素。

举个例子:

邻域像素值:[120, 125, 130, 255, 128, 122, 127, 126, 124]

排序后:[120, 122, 124, 125, 126, 127, 128, 130, 255]

中值 = 126,完美避开了255这个噪声点。

如果是均值滤波:(120+125+130+255+128+122+127+126+124)/9 ≈ 139,被拉高了13个灰度级。

OpenCV实现:

# 中值滤波,核大小5
median = cv2.medianBlur(img, 5)

# 注意:中值滤波的核大小只有一个参数(必须是奇数)
# 3×3 适合轻度椒盐噪声
# 5×5 适合中度噪声
# 7×7 以上适合重度噪声,但细节损失大

重要提醒:中值滤波的核大小越大,计算量呈平方增长。5×5比3×3慢了近3倍,7×7比5×5又慢了近2倍。在实时系统里,我一般不超过5×5。

4. 三种滤波算法的对比总结

算法 噪声类型 边缘保留 计算速度 典型应用
均值滤波 高斯噪声(一般) 差 最快 快速预览、简单预处理
高斯滤波 高斯噪声(优秀) 中等 快 通用降噪、去马赛克预处理
中值滤波 椒盐噪声(极佳) 好 较慢 椒盐噪声去除、边缘保护

5. 实战建议:如何选择?

说了这么多,到底怎么选?我总结了一个简单的决策流程:

  1. 先看噪声类型:如果是黑白点乱跳 → 中值滤波;如果是整体颗粒感 → 高斯滤波。
  2. 再看性能要求:实时系统(30fps以上)→ 优先均值或高斯,核不超过5×5。
  3. 最后看边缘重要性:需要保留边缘 → 中值滤波或小sigma高斯;边缘无所谓 → 均值滤波省事。

我的习惯:在正式项目里,我一般先用高斯滤波做基础降噪,sigma取1.5左右。如果发现还有明显的椒盐噪声,再叠加一层中值滤波,核用3×3。这样既保住了边缘,又去了两种噪声。当然,这是经验值,具体还得看你的图像质量。