【Python】基于高斯噪声与椒盐噪声的滤波方法性能对比
-
目录
-
实验目的及原理:
-
目的:
(1)掌握均值滤波、高斯滤波、中值滤波三种经典空域滤波算法的原理与应用场景。
(2)对比不同滤波算法在处理高斯噪声和椒盐噪声时的效果差异,分析滤波核大小对结果的影响。
(3)通过手动实现均值滤波和中值滤波,深入理解滤波算法的底层逻辑,并与 OpenCV 库函数的实现进行对比分析。
-
原理:
(1)均值滤波:
用一个像素点周围的像素值的平均值来替换该像素点的值。遍历图像中的每个像素点,对每个点周围的一个小邻域内的所有像素值求平均后作为新的像素点,从而达到平滑图像的效果。利用cv2.blur(img_g,(ksize,ksize))得到结果。(ksize,ksize)表示每次有ksize*ksize的核(正方形)进行计算。
(2)高斯滤波:
核中的权重值遵循⾼斯分布,即离中⼼像素越近的像素权重越⼤。与均值滤波相比,相当于计算时都加上个权重。利用cv2.GaussianBlur(img_g,(ksize,ksize),signmaX,sigmaY=5)得到结果(signmaX为X方向高斯核标准差:signmaY为Y方向高斯核标准差)。前三个必需!!
(3)中值滤波:
将邻域(ksize*ksize)内所有像素的灰度值进⾏排序(排序不改变图像),然后取中间值作为中⼼像素的新值(改变图像)。利用cv2.medianBlur(img_s,ksize)来接收结果。
-
程序代码
-
均值滤波、高斯滤波、中值滤波比较:
-
import cv2 import matplotlib.pylab as plt plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['axes.unicode_minus'] = False img=cv2.imread('001.png',0) img_g=cv2.imread('001_g.png',0) img_s=cv2.imread('001_s.png',0) #均值滤波 img_g_l=cv2.blur(img_g,(3,3)) img_s_l=cv2.blur(img_s,(3,3)) img_g_l1=cv2.blur(img_g,(5,5)) img_s_l1=cv2.blur(img_s,(5,5)) #高斯滤波 img_g_l_1=cv2.GaussianBlur(img_g,(3,3),0,sigmaY=5) img_s_l_1=cv2.GaussianBlur(img_s,(3,3),0,sigmaY=5) img_g_l1_1=cv2.GaussianBlur(img_g,(5,5),0,sigmaY=5) img_s_l1_1 = cv2.GaussianBlur(img_s, (5,5), 0, sigmaY=5) #中值滤波 img_g_l_2=cv2.medianBlur(img_g,3) img_s_l_2=cv2.medianBlur(img_s,3) img_g_l1_2=cv2.medianBlur(img_g,5) img_s_l1_2=cv2.medianBlur(img_s,5) plt.subplot(231) plt.imshow(img_g,'gray') plt.title('带高斯噪声图片') plt.subplot(234) plt.imshow(img_s,'gray') plt.title('带椒盐噪声图片') plt.subplot(232) plt.imshow(img_g_l,'gray') plt.title('均值滤波后图像(3*3)') plt.subplot(233) plt.imshow(img_g_l1,'gray') plt.title('均值滤波后图像(5*5)') plt.subplot(235) plt.imshow(img_s_l,'gray') plt.title('均值滤波后图像(3*3)') plt.subplot(236) plt.imshow(img_s_l1,'gray') plt.title('均值滤波后图像(5*5)') plt.show() plt.subplot(231) plt.imshow(img_g,'gray') plt.title('带高斯噪声图片') plt.subplot(234) plt.imshow(img_s,'gray') plt.title('带椒盐噪声图片') plt.subplot(232) plt.imshow(img_g_l_1,'gray') plt.title('高斯滤波后图像(3*3)') plt.subplot(233) plt.imshow(img_g_l1_1,'gray') plt.title('高斯滤波后图像(5*5)') plt.subplot(235) plt.imshow(img_s_l_1,'gray') plt.title('高斯滤波后图像(3*3)') plt.subplot(236) plt.imshow(img_s_l1_1,'gray') plt.title('高斯滤波后图像(5*5)') plt.show() plt.subplot(231) plt.imshow(img_g,'gray') plt.title('带高斯噪声图片') plt.subplot(234) plt.imshow(img_s,'gray') plt.title('带椒盐噪声图片') plt.subplot(232) plt.imshow(img_g_l_2,'gray') plt.title('中值滤波后图像(3*3)') plt.subplot(233) plt.imshow(img_g_l1_2,'gray') plt.title('中值滤波后图像(5*5)') plt.subplot(235) plt.imshow(img_s_l_2,'gray') plt.title('中值滤波后图像(3*3)') plt.subplot(236) plt.imshow(img_s_l1_2,'gray') plt.title('中值滤波后图像(5*5)') plt.show()手动实现均值滤波和中值滤波:
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 手动实现均值滤波器
def manual_mean_filter(image, kernel_size):
h, w = image.shape
pad = kernel_size // 2 # 计算边缘填充大小
# 边缘填充(避免边界像素处理问题)
padded = np.pad(image, pad, mode='edge')
result = np.zeros_like(image, dtype=np.uint8)
for i in range(h):
for j in range(w):
kernel_area = padded[i:i + kernel_size, j:j + kernel_size]
result[i, j] = np.mean(kernel_area).astype(np.uint8)
return result
# 手动实现中值滤波器
def manual_median_filter(image, kernel_size):
h, w = image.shape
pad = kernel_size // 2
padded = np.pad(image, pad, mode='edge')
result = np.zeros_like(image, dtype=np.uint8)
for i in range(h):
for j in range(w):
kernel_area = padded[i:i + kernel_size, j:j + kernel_size]
result[i, j] = np.median(kernel_area).astype(np.uint8)
return result
# 读取图像
def load_image(path):
img = Image.open(path).convert('L') # 转为灰度图
return np.array(img, dtype=np.uint8)
def main():
img = load_image('001.png')
# 手动实现滤波
manual_mean_3 = manual_mean_filter(img, 3)
manual_mean_5 = manual_mean_filter(img, 5)
manual_median_3 = manual_median_filter(img, 3)
manual_median_5 = manual_median_filter(img, 5)
# OpenCV实现滤波(用于对比)
try:
import cv2
cv_mean_3 = cv2.blur(img, (3, 3))
cv_median_3 = cv2.medianBlur(img, 3)
use_opencv = True
except ImportError:
use_opencv = False
print("未安装OpenCV,仅展示手动实现结果")
# 显示结果
plt.figure(figsize=(15, 10))
# 原始图像
plt.subplot(3, 3, 1)
plt.imshow(img, cmap='gray')
plt.title('原始图像')
plt.axis('off')
# 手动实现结果
plt.subplot(3, 3, 2)
plt.imshow(manual_mean_3, cmap='gray')
plt.title('手动均值滤波(3x3)')
plt.axis('off')
plt.subplot(3, 3, 3)
plt.imshow(manual_mean_5, cmap='gray')
plt.title('手动均值滤波(5x5)')
plt.axis('off')
plt.subplot(3, 3, 5)
plt.imshow(manual_median_3, cmap='gray')
plt.title('手动中值滤波(3x3)')
plt.axis('off')
plt.subplot(3, 3, 6)
plt.imshow(manual_median_5, cmap='gray')
plt.title('手动中值滤波(5x5)')
plt.axis('off')
# OpenCV实现结果(如果可用)
if use_opencv:
plt.subplot(3, 3, 8)
plt.imshow(cv_mean_3, cmap='gray')
plt.title('OpenCV均值滤波(3x3)')
plt.axis('off')
plt.subplot(3, 3, 9)
plt.imshow(cv_median_3, cmap='gray')
plt.title('OpenCV中值滤波(3x3)')
plt.axis('off')
plt.tight_layout()
plt.show()
if __name__ == '__main__':
main()
-
实验结果与分析:
-
均值滤波:

-
高斯滤波:

中值滤波:

手动实现:

-
高斯噪声处理结果:
均值滤波:3×3核可去除部分噪声,但图像轻微模糊;5×5 核去噪效果更强,但细节(如边缘、纹理)模糊更明显。
高斯滤波:对高斯噪声的抑制效果优于均值滤波,3×3核在去噪的同时保留了更多边缘细节;5×5核去噪更彻底,但仍存在一定模糊。
中值滤波:对高斯噪声的处理效果较差,即使使用 5×5核,噪声残留较明显,且易导致图像细节失真。
-
椒盐噪声处理结果:
均值滤波:对椒盐噪声抑制效果有限,3×3核仅能弱化噪声,5×5核会将噪声扩散,导致图像整体模糊。
高斯滤波:无法有效去除椒盐噪声,噪声点仅被轻微平滑,仍清晰可见。
中值滤波:处理椒盐噪声效果显著,3×3核即可去除大部分噪声,且边缘保留较好;5×5核去噪更彻底,但部分细纹理会丢失。
-
手动实现与OpenCV实现的对比:
视觉效果:两种实现的滤波结果整体一致,因边界填充方式不同,但边缘区域存在细微差异。
性能差异:用OpenCV实现程序明显更快,而手动实现程序运行要慢很多。
灵活性:手动实现可灵活修改边界填充方式、核形状等;OpenCV封装完善,适合快速部署,但不能自己修改一些参数。
-
不足及改进
1.不足:未测试不同噪声强度(如低、中、高噪声密度)下算法的鲁棒性,实验场景单一,无法全面验证算法适应性。
改进:编写噪声生成函数,生成不同强度的高斯噪声和椒盐噪声图像,对比算法在极端条件下的表现。
2.不足:实验仅通过视觉效果评估滤波性能,缺乏定量指标的支撑,主观判断易存在偏差。
改进:引入 PSNR 和 SSIM 计算函数,对不同滤波结果进行量化对比,客观衡量去噪效果与细节保留程度。
-
个人收获与体会:
- 深入理解了图像空域滤波的核心原理,包括均值滤波、高斯滤波和中值滤波各自的数学逻辑与实现机制,明确了不同滤波算法适用的噪声场景。
- 通过手动实现均值滤波和中值滤波算法,从底层掌握了滤波过程中像素邻域处理、边界填充等关键细节,同时也对比感受到 OpenCV 库函数在工程应用中的高效性与便捷性。
- 核越大去噪越强但细节损失越多,这种“矛盾”让我意识到实际处理中需结合场景需求动态调整参数。
-
思考:
1.如果图片中同时含有多种噪声时,那么选择才更好?
2.如果对一张图片进行多次不同的滤波处理,结果会不会改善一点?如果可以结合的话顺序的差异是不是也会变成关键影响因素?
3.已知经过处理后噪声会消失,但图像会模糊,怎么操作才能让图像的细节部分也不会受到影响?
更多推荐


所有评论(0)