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
相关产品推荐
相关产品推荐

