第1章:均值滤波与高斯滤波——原理详解与实战

各位同学,欢迎来到《手机摄影去噪算法实战手册》的第一章。

今天咱们聊点最基础、但也最核心的东西——均值滤波高斯滤波

你可能会想:“这俩不是课本上老掉牙的算法吗?” 嗯,我当年也这么想。直到我在一个夜景项目里,被噪声折磨得死去活来,才发现——基础不牢,地动山摇

核心观点:均值滤波和高斯滤波,是所有去噪算法的“地基”。搞懂它们,你才能理解更高级的算法(比如双边滤波、NLM)。

本章知识体系:均值滤波 vs 高斯滤波 图像去噪基础 均值滤波 原理:邻域像素取平均 特点:简单、模糊、保边差 高斯滤波 原理:加权平均(中心权重高) 特点:平滑、更自然、保边稍好 核大小的影响 核越大 → 越模糊 → 细节丢失

1.1 均值滤波:最简单的去噪方式

原理是什么?

说白了,均值滤波就是“拉帮结派”。

对于图像中的每个像素,我把它周围一圈像素的RGB值加起来,然后除以像素总数。这个平均值,就是新像素的值。

举个例子:一个3x3的窗口,中心像素原来值是100,周围8个像素分别是90、110、95、105... 平均下来可能变成102。嗯,噪声就被“平均”掉了。

我的经验:均值滤波在去除高斯噪声时效果还行,但遇到椒盐噪声就抓瞎了。为什么?因为椒盐噪声是极端值(0或255),一平均会把整个区域都带偏。

OpenCV实现

代码其实就一行。我习惯用 cv2.blur() 或者 cv2.boxFilter()

import cv2
import numpy as np

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

# 均值滤波,核大小为5x5
result = cv2.blur(img, (5, 5))

# 或者用 boxFilter,效果一样
# result = cv2.boxFilter(img, -1, (5, 5))

cv2.imshow('Original', img)
cv2.imshow('Mean Filter', result)
cv2.waitKey(0)
cv2.destroyAllWindows()

核大小的影响

核大小,就是那个“窗口”的尺寸。3x3、5x5、7x7... 越大,参与平均的像素越多,平滑效果越强。

但代价也很明显——图像会变模糊。我做过一个测试:

核大小 去噪效果 细节保留 适用场景
3x3 较弱 较好 轻度噪声
5x5 中等 一般 日常使用
7x7 较强 较差 噪声严重
9x9及以上 极强 几乎丢失 不推荐

避坑指南:我曾经在一个项目里,为了去噪把核设成了15x15。结果图像糊得像打了马赛克,被领导骂了一顿。记住:核大小不是越大越好,够用就行。

1.2 高斯滤波:更聪明的平均

为什么需要高斯滤波?

你想想看,均值滤波对每个邻居都一视同仁,这合理吗?

当然不合理!离中心像素越近的像素,应该和中心像素关系更密切。高斯滤波就是基于这个想法——距离越近,权重越大

原理详解

高斯滤波的核心是高斯核。这个核里的数值,服从二维高斯分布。中心值最大,越往外越小。

举个例子,一个3x3的高斯核(σ=1.0)大概长这样:

[[0.075, 0.124, 0.075],
 [0.124, 0.204, 0.124],
 [0.075, 0.124, 0.075]]

看到没?中心是0.204,四个角只有0.075。这样加权平均下来,中心像素的“话语权”更大,边缘像素的影响被削弱。

关键区别:均值滤波是“平均主义”,高斯滤波是“精英主义”。高斯滤波保留的细节更多,图像看起来更自然。

OpenCV实现

cv2.GaussianBlur() 就行。注意,核大小必须是奇数。

import cv2
import numpy as np

img = cv2.imread('noisy_image.jpg')

# 高斯滤波,核大小5x5,sigmaX=1.0
result = cv2.GaussianBlur(img, (5, 5), 1.0)

# sigmaX 控制高斯分布的形状
# sigmaX 越大,权重分布越平缓,平滑效果越强
# sigmaX 越小,中心权重越集中,平滑效果越弱

cv2.imshow('Original', img)
cv2.imshow('Gaussian Filter', result)
cv2.waitKey(0)
cv2.destroyAllWindows()

核大小 vs sigma

这里有个小坑:核大小和sigma是相互关联的。我个人的习惯是:

  • 核大小 = 3x3 时,sigma 设 0.5 ~ 0.8
  • 核大小 = 5x5 时,sigma 设 1.0 ~ 1.5
  • 核大小 = 7x7 时,sigma 设 1.5 ~ 2.0

当然,OpenCV 也允许你只设核大小,不设 sigma。它会自动计算一个合理的值。

我的小技巧:如果你不确定 sigma 设多少,直接用 cv2.GaussianBlur(img, (5,5), 0)。OpenCV 会根据核大小自动计算 sigma,效果通常还不错。

1.3 实战:去除高斯噪声

生成噪声图像

咱们先模拟一张带高斯噪声的图,然后分别用均值滤波和高斯滤波去噪,看看效果。

import cv2
import numpy as np
import matplotlib.pyplot as plt

# 读取图像
img = cv2.imread('lena.jpg', cv2.IMREAD_GRAYSCALE)

# 添加高斯噪声
mean = 0
sigma = 25  # 噪声强度
noise = np.random.normal(mean, sigma, img.shape).astype(np.uint8)
noisy_img = cv2.add(img, noise)

# 均值滤波
mean_filtered = cv2.blur(noisy_img, (5, 5))

# 高斯滤波
gaussian_filtered = cv2.GaussianBlur(noisy_img, (5, 5), 1.0)

# 显示结果
plt.figure(figsize=(12, 4))
plt.subplot(1, 4, 1), plt.imshow(img, cmap='gray'), plt.title('Original')
plt.subplot(1, 4, 2), plt.imshow(noisy_img, cmap='gray'), plt.title('Noisy')
plt.subplot(1, 4, 3), plt.imshow(mean_filtered, cmap='gray'), plt.title('Mean Filter')
plt.subplot(1, 4, 4), plt.imshow(gaussian_filtered, cmap='gray'), plt.title('Gaussian Filter')
plt.show()

效果对比

跑完代码你会发现:

  • 均值滤波:噪声被去掉了,但图像有点“糊”,边缘不清晰。
  • 高斯滤波:噪声去得干净,图像更自然,边缘保留得更好。

为什么会这样?因为高斯滤波给了中心像素更高的权重,所以边缘信息被保留得更多。

结论:对于高斯噪声,高斯滤波是比均值滤波更好的选择。但如果你追求速度(比如实时视频处理),均值滤波更快,因为计算量更小。

1.4 总结与思考

这一章咱们聊了均值滤波和高斯滤波的原理、实现和实战。

说白了,这两个算法都是“局部平均”的思路,区别在于权重分配。均值滤波是“人人平等”,高斯滤波是“能者多劳”。

嗯,这里要注意:没有完美的算法。均值滤波快但模糊,高斯滤波好但慢一点。实际项目中,要根据需求选。

我记得有一次做手机相机的实时预览去噪,为了帧率,我不得不选了均值滤波。虽然效果差一点,但用户感觉不到延迟,这才是关键。

专注资料整理