DIP的第三周|图像空域滤波

前言

本周学习的是图像的空域滤波。按照功能来分类,空域滤波可以分为平滑滤波和锐化滤波。本篇报告会根据不同的滤波效果来对图像进行对比。同时也会用opencv库来进行编写。.

一.图像噪声的生成

首先使用 OpenCV 读取图像,并利用 skimage.util.random_noise 函数添加两种常见噪声:

  • 高斯噪声: 参数设定均值为0,方差为0.05
  • 椒盐噪声(salt noise):
import skimage
import cv2
import matplotlib.pylab as plt
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']  # 设置中文字体为黑体
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题
# 添加椒盐噪声

img=cv2.imread('001.bmp', 0)
img=img/255
img_g=skimage.util.random_noise(img,'gaussian',mean=0,var=0.05)
img_s=skimage.util.random_noise(img,'s&p',amount=0.1, salt_vs_pepper=0.5)
plt.subplot(131)
plt.imshow(img,'gray')
plt.title('原图')
plt.subplot(132)
plt.imshow(img_g,'gray')
cv2.imwrite('001_g.png',img_g)
plt.title('加入高斯噪声后图像')
plt.subplot(133)
plt.imshow(img_s,'gray')
plt.title('加入椒盐噪声后图像')
cv2.imwrite('001_s.png',img_s)
plt.show()

关键说明:

  • 对图像进行归一化处理有助于保证在添加噪声时各像素值在[0,1]内,更容易控制噪声幅度。
  • 使用
    skimage.util.random_noise(image, mode='gaussian', seed=None, clip=True, **kwargs)
    可以轻松模拟多种噪声类型:
  • image
    • 输入图像,可以是 2D 或 3D 的 NumPy 数组。

    • 图像的像素值范围通常在 [0, 1] 或 [0, 255],具体取决于图像的类型。

  • mode

    • 噪声类型,可选值包括:

      • 'gaussian':高斯噪声(默认)。

      • 'localvar':局部方差高斯噪声。

      • 'poisson':泊松噪声(适用于模拟光子计数)。

      • 'salt':盐噪声(白色噪声)。

      • 'pepper':胡椒噪声(黑色噪声)。

      • 's&p':椒盐噪声(同时包含盐和胡椒噪声)。

      • 'speckle':乘性高斯噪声。

 结果如下:

二、空域滤波介绍

空域滤波通过模板对图像进行处理,达到图像增强的目的。空域滤波器以模板中心像素点为 参考,逐像素进行移动,并通过计算获得新的像素值,即模板中心所处像素点的值。当模板遍历过 所有像素后,滤波完成,得到增强后的图像。简单的空域滤波可用公式表示如下:

其中,f(x,y)表示输入的图片,g(x,y)表示输出的过滤图像,w(s,t)表示m×n 的空域滤波器。 空域滤波的过程就是不断地用一个卷积核在图像上与同样大小的局部作用,作用结果更新在中心 点上,所以需要m 和n为奇数,通常情况下使用的模板大小为3×3、5×5或者7×7。

三、平滑滤波介绍

1.均值滤波

均值滤波是最简单的平滑滤波。旨在消除图像中的噪声,让图像更平滑。其原理是,对于图像中的每个像素,取以它为中心的一个邻域内像素值的平均值,来替换该像素原来的值。比如在一个 3×3 的邻域内,将 9 个像素值相加后除以 9,得到的均值就是中心像素的新值。

均值滤波计算简单,能有效降低高斯噪声。但它也有缺点,过度使用会模糊图像细节,边缘信息也会被削弱。在实际应用中,常用于对图像质量要求不太高,仅需初步降噪的场景,像对监控视频做预处理,以减少噪点干扰 。

具体代码如下:

import cv2
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] #使用黑体
plt.rcParams['axes.unicode_minus'] = False #解决负号显示问题
img = cv2.imread('004.bmp', 0)
img_g = cv2.imread('004_g.bmp', 0)
img_s = cv2.imread('004_s.bmp', 0)
# 检查图像是否成功读取
if img is None or img_g is None or img_s is None:
    raise FileNotFoundError("部分图像文件未找到,请检查文件路径和文件名。")
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))
# 创建子图布局
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()

关键说明:

均值滤波利用邻域内像素的算术平均值来代替中心像素,可以在一定程度上减少噪声,但容易使边缘变得模糊。

对比不同模板大小的效果,可以观察到模板越大,模糊效果越明显。

从图中可以看到两种噪声在均值滤波后都一定程度上减少了噪声,但是也带来了模糊效应。同时也可以看出,随着滤波器变大,虽然去噪效果更好,但是模糊程度也更大

2.高斯滤波

高斯滤波是一种数字图像处理技术。它主要用于图像去噪,通过对图像中的每个像素点及其邻域进行加权平均来实现。其原理是利用高斯函数生成一个二维的滤波模板,模板中的系数与像素点到中心的距离有关,距离越近权重越大。这样可以在去除噪声的同时,尽可能地保留图像的细节信息。在实际应用中,它对于服从正态分布的噪声有很好的抑制效果,广泛应用于计算机视觉、医学图像处理等领域,能有效提高图像质量,为后续的图像分析和处理提供更好的基础。

代码如下(示例):

import cv2
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] #使用黑体
plt.rcParams['axes.unicode_minus'] = False #解决负号显示问题
img = cv2.imread('004.bmp.bmp', 0)
img_g = cv2.imread('004_g.bmp', 0)
img_s = cv2.imread('004_s.bmp', 0)
img_g_l = cv2.GaussianBlur(img_g, (3, 3), 0, 5)
img_s_l = cv2.GaussianBlur(img_s, (3, 3), 0, 5)
img_g_l1 = cv2.GaussianBlur(img_g, (5, 5), 0, 5)
img_s_l1 = cv2.GaussianBlur(img_s, (5, 5), 0, 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()

关键说明:

  • 通过调整核的尺寸,可以获得不同程度的平滑效果。
  • 参数中的 0 表示让系统自动计算标准差,确保效果合理。

结果如下:

从中可以看到和均值滤波类似的结论,同时也可发现,高斯滤波后图像清晰度要比均值滤波的高。

3.中值滤波

中值滤波是一种非线性数字滤波技术,在图像处理等领域应用广泛。其原理是对一个以当前像素为中心的邻域窗口内像素值进行排序,取中间值来替换当前像素值。例如在3×3窗口中,对9个像素值排序,用第5大的值更新中心像素。相比均值滤波,它能更好地保留图像边缘信息,有效去除椒盐噪声等脉冲干扰。在图像去噪过程中,若采用均值滤波,边缘可能会模糊;而中值滤波能让边缘清晰,使图像在去除噪声的同时,保持原本的轮廓和细节,维持图像质量。

import cv2
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] #使用黑体
plt.rcParams['axes.unicode_minus'] = False #解决负号显示问题
img = cv2.imread('004.bmp', 0)
img_g = cv2.imread('004_g.bmp', 0)
img_s = cv2.imread('004_s.bmp', 0)
img_g_l = cv2.medianBlur(img_g, 3)
img_s_l = cv2.medianBlur(img_s, 3)
img_g_l1 = cv2.medianBlur(img_g, 5)
img_s_l1 = 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()

关键说明:

  • 中值滤波对于去除孤立的噪点(如椒盐噪声)有显著优势,能够较好地保持图像边缘。
  • 同样可调整滤波窗口的尺寸,窗口越大则平滑效果越明显,同时可能损失更多细节。

结果如下:

四、锐化滤波介绍

锐化滤波是一种在数字图像处理中广泛应用的技术,用于增强图像的边缘和细节,使图像看起来更加清晰。图像的锐化滤波主要是通过增强图像中的高频成分来实现的。在频域中,图像的边缘和细节信息通常对应着高频分量,而低频分量则主要对应图像的平滑区域。锐化滤波器通过对图像的高频分量进行加权放大,相对抑制低频分量,从而突出图像的边缘和细节,达到锐化的效果。

以下有三种常见算子:

  • 拉普拉斯算子:这是一种常用的二阶微分算子,对图像中的阶跃变化(如边缘)非常敏感。它通过计算图像在水平和垂直方向上的二阶导数来增强边缘。其模板通常有多种形式,例如经典的 3×3 模板,中心系数为 4,周围系数为 - 1。拉普拉斯算子能很好地突出图像中的细节,但对噪声也较为敏感,可能会放大噪声。
  • 索贝尔算子:主要用于检测图像中的边缘。它结合了图像的一阶导数信息,通过在水平和垂直方向上分别使用不同的模板进行卷积运算,然后将两个方向的结果组合起来得到边缘强度。索贝尔算子对噪声有一定的抑制作用,同时能够较好地检测出图像中的水平和垂直边缘。
  • 罗伯特算子:是一种简单的一阶差分算子,通过计算图像中相邻像素之间的灰度差异来检测边缘。它使用两个 2×2 的模板,分别检测水平和垂直方向上的边缘。罗伯特算子计算速度快,但对噪声的鲁棒性相对较差。
import cv2
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams['font.sans-serif'] = ['SimHei'] #使用黑体
plt.rcParams['axes.unicode_minus'] = False #解决负号显示问题
img = cv2.imread('004.bmp', 0)
# Roberts
Robertx = np.array([[-1, 0], [0, 1]])
Roberty = np.array([[0, -1], [1, 0]])
img_x = cv2.filter2D(img, -1, Robertx)
img_y = cv2.filter2D(img, -1, Roberty)
img_r = abs(img_x) + abs(img_y)
# Prewitt
Prewittx = np.array([[1, 1, 1], [0, 0, 0], [-1, -1, -1]])
Prewitty = np.array([[-1, 0, 1], [-1, 0, 1], [-1, 0, 1]])
img_x = cv2.filter2D(img, -1, Prewittx)
img_y = cv2.filter2D(img, -1, Prewitty)
img_p = abs(img_x) + abs(img_y)
# Sobel
img_s = cv2.Sobel(img, -1, 1, 1)
plt.subplot(141)
plt.imshow(img, 'gray')
plt.title('原图')
plt.subplot(142)
plt.imshow(img_r, 'gray')
plt.title('Roberts 算子滤波后图')
plt.subplot(143)
plt.imshow(img_p, 'gray')
plt.title('Prewitt 算子滤波后图')
plt.subplot(144)
plt.imshow(img_s, 'gray')
plt.title('Sobel 算子滤波后图')
plt.show()

关键说明:

  • 对于每种算子,都通过卷积操作提取图像的边缘信息。
  • 比较不同算子的检测效果时,可以看到各自对噪声敏感度、边缘锐度的不同特点。

结果如下:

五、对比分析

import cv2
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] #使用黑体
plt.rcParams['axes.unicode_minus'] = False #解决负号显示问题
 
# 读取均匀噪声与椒盐噪声
img_g = cv2.imread('005.bmp', 0)
img_s = cv2.imread('006.bmp', 0)
 
# 均值滤波
img_g_1 = cv2.blur(img_g, (3, 3))
img_s_1 = cv2.blur(img_s, (3, 3))
 
# 高斯滤波
img_g_2 = cv2.GaussianBlur(img_g, (3, 3), 0, 5)
img_s_2 = cv2.GaussianBlur(img_s, (3, 3), 0, 5)
 
# 中值滤波
img_g_3 = cv2.medianBlur(img_g, 3)
img_s_3 = cv2.medianBlur(img_s, 3)
 
plt.subplot(2, 4, 1)
plt.imshow(img_g, 'gray')
plt.title('带均匀噪声图片')
 
plt.subplot(2, 4, 2)
plt.imshow(img_g_1, 'gray')
plt.title('均值滤波后图像(3*3)')
 
plt.subplot(2, 4, 3)
plt.imshow(img_g_2, 'gray')
plt.title('高斯滤波后图像(3*3)')
 
plt.subplot(2, 4, 4)
plt.imshow(img_g_3, 'gray')
plt.title('中值滤波后图像(3*3)')
 
# 第二行:椒盐噪声图片及滤波结果
plt.subplot(2, 4, 5)
plt.imshow(img_s, 'gray')
plt.title('带椒盐噪声图片')
 
plt.subplot(2, 4, 6)
plt.imshow(img_s_1, 'gray')
plt.title('均值滤波后图像(3*3)')
 
plt.subplot(2, 4, 7)
plt.imshow(img_s_2, 'gray')
plt.title('高斯滤波后图像(3*3)')
 
plt.subplot(2, 4, 8)
plt.imshow(img_s_3, 'gray')
plt.title('中值滤波后图像(3*3)')
 
plt.show()

关键说明:

  • 该部分通过对同一噪声图像采用三种不同的滤波方法,可直观感受每种方法在降噪与细节保留上的平衡效果。
  • 从结果可以看出,中值滤波在处理椒盐噪声时表现尤为突出,而Gaussian滤波则较好地保留了图像平滑的同时保持了边缘信息。

结果如下:

这里有一个小问题需要注意,就是subplot操作,意思是把显示出的图像放到指定的位置。要设置好后面的三个参数:(行,列,序号)

六、opencv实现

在本次实验中,我们系统地完成了从图像噪声生成到多种滤波处理方法的综合实验。最初,我们使用了 matplotlibskimage 库来实现这些功能,但在实验过程中,我突然想到:是否可以用 OpenCV 来实现这一切呢?于是,我尝试用 OpenCV 来完成这些操作,并取得了良好的效果。以下是基于 OpenCV 的实现过程和总结。

我问了一下deepseek,他是这样回答的:

import cv2
 
# 读取带均匀噪声和椒盐噪声的图像
img_g = cv2.imread('005.bmp', 0)  # 以灰度模式读取带均匀噪声图像
img_s = cv2.imread('006.bmp', 0)  # 以灰度模式读取带椒盐噪声图像
 
# 均值滤波
kernel_size = 3  # 定义滤波核大小为3x3
img_g_mean = cv2.blur(img_g, (kernel_size, kernel_size))
img_s_mean = cv2.blur(img_s, (kernel_size, kernel_size))
 
# 中值滤波
img_g_median = cv2.medianBlur(img_g, kernel_size)
img_s_median = cv2.medianBlur(img_s, kernel_size)
 
# 显示滤波后的图像(可选,若不想显示可注释掉)
cv2.imshow('img_g_mean', img_g_mean)
cv2.imshow('img_s_mean', img_s_mean)
cv2.imshow('img_g_median', img_g_median)
cv2.imshow('img_s_median', img_s_median)
cv2.waitKey(0)

我们可以看到他已经设置好均值滤波和中值滤波的函数,我们可以直接调用,但是能不能写出他的底层代码呢?

当然可以!

# 自定义均值滤波函数
def custom_mean_filter(image, kernel_size):
    rows, cols = image.shape
    pad_size = kernel_size // 2
    padded_image = np.pad(image, pad_size, mode='constant')
    filtered_image = np.zeros_like(image)
    for i in range(rows):
        for j in range(cols):
            sum_val = 0
            for x in range(kernel_size):
                for y in range(kernel_size):
                    sum_val += padded_image[i + x][j + y]
            filtered_image[i][j] = sum_val / (kernel_size * kernel_size)
    return filtered_image
 
 
# 自定义中值滤波函数
def custom_median_filter(image, kernel_size):
    rows, cols = image.shape
    pad_size = kernel_size // 2
    padded_image = np.pad(image, pad_size, mode='constant')
    filtered_image = np.zeros_like(image)
    for i in range(rows):
        for j in range(cols):
            neighborhood = []
            for x in range(kernel_size):
                for y in range(kernel_size):
                    neighborhood.append(padded_image[i + x][j + y])
            neighborhood.sort()
            filtered_image[i][j] = neighborhood[len(neighborhood) // 2]
    return filtered_image

自定义均值滤波函数 custom_mean_filter

  1. 首先对图像进行边界填充,使用np.pad函数,填充模式为'constant' ,填充大小为kernel_size // 2。
  2. 然后遍历图像的每个像素点,对于每个像素点,遍历其对应的滤波核覆盖区域内的像素,将这些像素值累加起来,最后除以滤波核的像素个数(kernel_size * kernel_size),得到均值滤波后的像素值。

自定义中值滤波函数 custom_median_filter

  1. 同样先对图像进行边界填充。
  2. 遍历图像的每个像素点,获取其滤波核覆盖区域内的所有像素值,将这些像素值存入列表neighborhood,然后对列表进行排序,取中间位置的元素作为中值滤波后的像素值。

总结

在本次实验中,我们系统地完成了从图像噪声生成到多种滤波处理方法的综合实验。通过实验,我们对图像处理技术有了更深入的理解,以下是主要体会:

1. 噪声模拟
   利用 `skimage` 库,我们能够方便地生成多种类型的噪声(如高斯噪声、椒盐噪声等),为后续的降噪处理实验提供了数据。这种噪声生成方式不仅操作简便,还能模拟真实场景中的噪声分布,为后续算法验证提供了可靠的测试基础。

2. 滤波效果对比

  •    均值滤波:虽然实现简单且能有效平滑图像,但容易导致图像细节模糊,尤其在处理边缘信息时效果不佳。  
  •    高斯滤波:通过加权平均的方式,在平滑图像的同时较好地保护了边缘信息,适用于处理高斯噪声。  
  •    中值滤波:对椒盐噪声的处理效果尤为显著,同时能有效保留图像的边缘细节,是处理脉冲噪声的首选方法。

3. 边缘检测  
   不同的边缘检测算子(如 Sobel、Laplacian、Canny 等)在噪声环境下的表现各有优劣。实验表明,选择合适的边缘检测算法需要综合考虑噪声类型、图像特征以及应用需求。

4. 手工实现算法
   通过自定义滤波算法,我们对图像处理的底层运算有了更直观的理解。这种实践不仅加深了对算法原理的认识,还帮助我们更好地滤理解波器的设计思路,对初学者尤其有益。

5. 总结与展望 
   本次实验不仅帮助我们理解了噪声生成和滤波技术的基本原理,还通过对比分析加深了对不同图像处理方法在实际场景中应用效果的认识。未来,我们可以进一步研究更复杂的滤波方法,例如双边滤波、小波去噪等,以应对更加复杂的图像降噪问题。这些方法在保留图像细节的同时,能够更有效地去除噪声,为图像处理领域提供更强大的工具。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值