You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python加权中值滤波器异常:未滤除椒盐噪声反而色彩校正

加权中值滤波器实现问题:未滤除椒盐噪声反而色彩校正

我尝试在Python中实现加权中值滤波器,发现该滤波器并未滤除我添加到原始图像中的椒盐噪声,反而对整幅图像进行了色彩校正。以下是我的实现代码及运行结果:

import numpy as np
from skimage import io
from matplotlib import pyplot as plt


def add_zg_impuls(img, ratio):
    H, W, ch = img.shape
    length = int(H*W*ch*ratio)
    lin = np.random.randint(0, H, length)
    col = np.random.randint(0, W, length)
    val = np.random.randint(0, 2, length)
    img_impuls = img.copy()
    for i in range(length):
        img_impuls[lin[i], col[i], np.random.randint(0, 3)] = 255 * val[i]
    return img_impuls


def apply_L_filter(img, size, weights):
    h, w,c = img.shape
    cap = size // 2
    new_img = np.zeros_like(img)
   
    for i in range(cap, h - cap):
        for j in range(cap, w - cap):
            for canal in range(c):
                vec = img[i-cap:i+cap+1, j-cap:j+cap+1, canal]
                values = np.reshape(vec, size*size)
                sorted_values = np.sort(values)
                weighted_values = sorted_values * weights.flatten()
                new_img[i, j, canal] = np.sum(weighted_values)
    
    return new_img

image = io.imread("tiffany.bmp")
plt.figure(), plt.imshow(image), plt.title("原始图像"), plt.show()

image_noise= add_zg_impuls(image,0.1)
plt.figure(), plt.imshow(image_noise), plt.title("添加10%椒盐噪声后的图像"), plt.show()

filter_size = 5
filter_weights = np.array([[1, 1, 1, 1, 1], [1, 2, 2, 2, 1], [1, 2, 3, 2, 1], [1, 2, 2, 2, 1], [1, 1, 1, 1, 1]])

filtered_image = apply_L_filter(image_noise, filter_size, filter_weights)
plt.figure(), plt.imshow(filtered_image), plt.title("加权滤波后的图像"), plt.show()

运行结果如图:
运行结果

问题原因

当前的apply_L_filter函数并非加权中值滤波,而是加权求和的线性滤波:你将排序后的像素值与权重相乘后求和,这本质是类似高斯模糊的平滑操作,线性滤波无法有效抑制椒盐噪声——噪声值会被加权平均到周围像素,导致图像模糊而非去除噪声。

正确的加权中值滤波实现

加权中值滤波的核心逻辑是:给邻域内每个像素赋予权重,等效于将该像素值重复对应权重次数,然后取这个扩展序列的中值;或者找到排序后累计权重超过总权重一半的那个值。

修正后的代码如下:

import numpy as np
from skimage import io
from matplotlib import pyplot as plt


def add_zg_impuls(img, ratio):
    H, W, ch = img.shape
    length = int(H*W*ch*ratio)
    lin = np.random.randint(0, H, length)
    col = np.random.randint(0, W, length)
    val = np.random.randint(0, 2, length)
    img_impuls = img.copy()
    for i in range(length):
        img_impuls[lin[i], col[i], np.random.randint(0, 3)] = 255 * val[i]
    return img_impuls


def apply_weighted_median_filter(img, size, weights):
    h, w, c = img.shape
    cap = size // 2
    new_img = np.zeros_like(img)
    # 计算总权重
    total_weight = np.sum(weights)
    # 扁平化权重
    flat_weights = weights.flatten()
    
    for i in range(cap, h - cap):
        for j in range(cap, w - cap):
            for canal in range(c):
                # 获取当前邻域的像素值
                vec = img[i-cap:i+cap+1, j-cap:j+cap+1, canal]
                values = vec.flatten()
                # 按权重扩展像素序列后取中值
                expanded = np.repeat(values, flat_weights)
                median_val = np.median(expanded)
                new_img[i, j, canal] = median_val
    
    return new_img

image = io.imread("tiffany.bmp")
plt.figure(), plt.imshow(image), plt.title("原始图像"), plt.show()

image_noise= add_zg_impuls(image,0.1)
plt.figure(), plt.imshow(image_noise), plt.title("添加10%椒盐噪声后的图像"), plt.show()

filter_size = 5
filter_weights = np.array([[1, 1, 1, 1, 1], [1, 2, 2, 2, 1], [1, 2, 3, 2, 1], [1, 2, 2, 2, 1], [1, 1, 1, 1, 1]])

filtered_image = apply_weighted_median_filter(image_noise, filter_size, filter_weights)
plt.figure(), plt.imshow(filtered_image), plt.title("加权中值滤波后的图像"), plt.show()

优化说明

若邻域较大,np.repeat生成大数组会影响效率,可改用累计权重的方式直接定位中值位置:

# 替代np.repeat的高效实现
sorted_indices = np.argsort(values)
sorted_values = values[sorted_indices]
sorted_weights = flat_weights[sorted_indices]
cum_weights = np.cumsum(sorted_weights)
median_idx = np.argmax(cum_weights >= total_weight / 2)
median_val = sorted_values[median_idx]

内容的提问来源于stack exchange,提问作者Camelia Birlea

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 01:50:34