【OpenCV 例程 300 篇】101. 自适应中值滤波器

专栏地址:『youcans 的 OpenCV 例程 300篇 - 总目录』

【第 7 章:图像复原与重建】
100. 自适应局部降噪滤波器
101. 自适应中值滤波器
102. 陷波带阻滤波器的传递函数

【youcans 的 OpenCV 例程 300 篇】101. 自适应中值滤波器


3.8 自适应中值滤波器(Adaptive median filter)

中值滤波器的窗口尺寸是固定大小不变的,不能同时兼顾去噪和保护图像的细节,在噪声的密度较小时的性能较好,当噪声概率较高时的性能就会劣化。

自适应中值滤波器根据预先设定的条件,在滤波的过程中动态改变滤波器的窗口尺寸大小;进一步地,根据条件判断当前像素是否噪声,由此决定是否用邻域中值替换当前像素。

自适应中值滤波器可以处理较大概率的脉冲噪声,平滑非脉冲噪声,尽可能保护图像细节信息,避免图像边缘的细化或者粗化。

S x y Sxy Sxy 表示中心在点 ( x , y ) (x,y) (x,y) 、大小为 m ∗ n m*n mn 的矩形子窗口(邻域),滤波器在由 S x y Sxy Sxy 定义的邻域操作。

Z m i n 、 Z m a x 、 Z m e d Zmin、Zmax、Zmed ZminZmaxZmed 表示 S x y Sxy Sxy 中的最小灰度值、最大灰度值和灰度值的中值, Z x y Zxy Zxy 是点 ( x , y ) (x,y) (x,y) 的灰度值, S m a x Smax Smax 是允许的最大窗口尺寸。

自适应中值滤波器分为两个过程:

  • Step A:

    • A1 = Zmed - Zmin
    • A2 = Zmed - Zmax
    • 如果 A1>0 且 A2<0,则跳转到 Step B;否则,增大窗口尺寸
    • 如果增大后的尺寸 ≤ Smax,则重复 A;否则,输出 Zmed
  • Step B:

    • B1 = Zxy - Zmin
    • B2 = Zxy - Zmax
    • 如果 B1>0 且 B2<0,则输出 Zxy;否则,输出 Zmed

StepA 的目的是确定当前窗口内得到的中值 Zmed 是否是噪声。如果 Zmin<Zmed<Zmax,则中值 Zmed 不是噪声,转到StepB。如果Zmin<Zxy<Zmax,则 Zxy 不是噪声,滤波器输出 Zxy。如果不满足上述条件,则判定 Zxy 是噪声,输出中值 Zmed。

如果在StepA中,Zmed 不满足条件 Zmin<Zmed<Zmax,则可判断得到的中值 Zmed 是噪声。这时要增大滤波器的窗口尺寸,在更大的范围内寻找一个非噪声点的中值。

因此,如果图像中噪声的概率较低,自适应中值滤波器可以使用较小的窗口尺寸,以提高计算速度;反之,如果噪声的概率较高,则需要增大滤波器的窗口尺寸,以改善滤波效果。


例程 9.15:自适应中值滤波器

    # # 9.15: 自适应中值滤波器 (Adaptive median filter)
    img = cv2.imread("../images/Fig0514a.tif", 0)  # flags=0 读取为灰度图像
    hImg = img.shape[0]
    wImg = img.shape[1]

    smax = 7  # 允许最大窗口尺寸
    m, n = smax, smax
    imgAriMean = cv2.boxFilter(img, -1, (m, n))  # 算术平均滤波

    # 边缘填充
    hPad = int((m-1) / 2)
    wPad = int((n-1) / 2)
    imgPad = np.pad(img.copy(), ((hPad, m-hPad-1), (wPad, n-wPad-1)), mode="edge")

    imgMedianFilter = np.zeros(img.shape)  # 中值滤波器
    imgAdaMedFilter = np.zeros(img.shape)  # 自适应中值滤波器
    for i in range(hPad, hPad+hImg):
        for j in range(wPad, wPad+wImg):
            # 1. 中值滤波器 (Median filter)
            ksize = 3
            k = int(ksize/2)
            pad = imgPad[i-k:i+k+1, j-k:j+k+1]  # 邻域 Sxy, m*n
            imgMedianFilter[i-hPad, j-wPad] = np.median(pad)

            # 2. 自适应中值滤波器 (Adaptive median filter)
            ksize = 3
            k = int(ksize/2)
            pad = imgPad[i-k:i+k+1, j-k:j+k+1]
            zxy = img[i-hPad][j-wPad]
            zmin = np.min(pad)
            zmed = np.median(pad)
            zmax = np.max(pad)

            if zmin < zmed < zmax:
                if zmin < zxy < zmax:
                    imgAdaMedFilter[i-hPad, j-wPad] = zxy
                else:
                    imgAdaMedFilter[i-hPad, j-wPad] = zmed
            else:
                while True:
                    ksize = ksize + 2
                    if zmin < zmed < zmax or ksize > smax:
                        break
                    k = int(ksize / 2)
                    pad = imgPad[i-k:i+k+1, j-k:j+k+1]
                    zmed = np.median(pad)
                    zmin = np.min(pad)
                    zmax = np.max(pad)
                if zmin < zmed < zmax or ksize > smax:
                    if zmin < zxy < zmax:
                        imgAdaMedFilter[i-hPad, j-wPad] = zxy
                    else:
                        imgAdaMedFilter[i-hPad, j-wPad] = zmed

    plt.figure(figsize=(9, 6))
    plt.subplot(131), plt.axis('off'), plt.title("Original")
    plt.imshow(img, cmap='gray', vmin=0, vmax=255)
    plt.subplot(132), plt.axis('off'), plt.title("Median filter")
    plt.imshow(imgMedianFilter, cmap='gray', vmin=0, vmax=255)
    plt.subplot(133), plt.axis('off'), plt.title("Adaptive median filter")
    plt.imshow(imgAdaMedFilter, cmap='gray', vmin=0, vmax=255)
    plt.tight_layout()
    plt.show()

在这里插入图片描述


(本节完)


版权声明:
youcans@xupt 原创作品,转载必须标注原文链接:(https://blog.csdn.net/youcans/article/details/122839526)
Copyright 2022 youcans, XUPT
Crated:2022-2-1


以下是使用Python实现自适应中值滤波去除椒盐噪声的示例代码: ```python import numpy as np from scipy.signal import medfilt2d def adaptive_median_filter(image, kernel_size=3, max_kernel_size=7): """ 自适应中值滤波 :param image: 输入图像 :param kernel_size: 初始核大小 :param max_kernel_size: 最大核大小 :return: 滤波后的图像 """ height, width = image.shape[:2] filtered_image = np.zeros((height, width), dtype=np.uint8) for i in range(height): for j in range(width): # 当前像素点的领域范围 kernel_half_size = kernel_size // 2 kernel_range = range(-kernel_half_size, kernel_half_size + 1) kernel_pixels = [] for k in kernel_range: for l in kernel_range: # 越界处理 if i + k < 0 or i + k >= height or j + l < 0 or j + l >= width: continue kernel_pixels.append(image[i + k, j + l]) # 中值滤波 kernel_pixels.sort() median_value = kernel_pixels[len(kernel_pixels) // 2] # 判断是否是椒盐噪声 if median_value == 0 or median_value == 255: # 滑动窗口扩大 kernel_size += 2 # 达到最大核大小时停止扩大 if kernel_size > max_kernel_size: filtered_image[i, j] = median_value else: continue else: # 中值滤波 filtered_image[i, j] = median_value return filtered_image # 测试 import cv2 # 读取图像 image = cv2.imread('lena.png', cv2.IMREAD_GRAYSCALE) # 添加椒盐噪声 noise_image = image.copy() noise_density = 0.05 noise_num = int(noise_density * image.shape[0] * image.shape[1]) for i in range(noise_num): x, y = np.random.randint(0, image.shape[0]), np.random.randint(0, image.shape[1]) noise_image[x, y] = 255 if np.random.rand() > 0.5 else 0 # 自适应中值滤波 filtered_image = adaptive_median_filter(noise_image) # 中值滤波 median_filtered_image = medfilt2d(noise_image, kernel_size=3) # 显示结果 cv2.imshow('Original image', image) cv2.imshow('Noisy image', noise_image) cv2.imshow('Filtered image', filtered_image) cv2.imshow('Median filtered image', median_filtered_image) cv2.waitKey(0) cv2.destroyAllWindows() ``` 注意:在实现过程中,当中值滤波结果为0或255时,需要将滑动窗口扩大,直到达到最大核大小时停止扩大。这个过程需要注意边界判断和核大小的变化。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

youcans_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值