Python复现逆滤波去模糊算法效果不符预期问题咨询
逆滤波Python实现问题排查
你的代码和参考Matlab逻辑存在几个核心不一致点,按影响优先级排序:
- 输入图像数值范围不匹配:参考Matlab代码读取的是无压缩raw格式灰度图,像素值范围为0255;你调用的`rgb2gray`会自动将输入图像归一化到01的浮点范围,后续如果直接加10倍标准差的噪声,噪声幅值会远大于信号本身,完全淹没图像内容。即便你暂时注释了噪声代码,0~1范围的信号和原代码设置的阈值
n=0.2的适配关系也和参考逻辑不一致。 - 频域核修改逻辑存在隐患:原Matlab代码中对频域响应做阈值截断时,由于4x4均值核的频域响应相位特性,直接赋值实数n不会产生明显异常,但如果后续替换为其他模糊核(比如运动模糊、高斯模糊),直接给复数频域响应赋值实数会强制将对应位置相位置0,引入明显的重建伪影。稳妥的实现应该保留原有相位,仅对幅值做截断:
B_abs = np.abs(B) B_phase = np.angle(B) B_abs[B_abs < n] = n B = B_abs * np.exp(1j * B_phase) - 显示未固定像素值范围:
matplotlib的imshow默认会自动对输入数组做对比度拉伸,将数组最小值映射为纯黑、最大值映射为纯白。逆滤波输出如果存在零星极值点,会导致整体画面发灰、对比度完全异常。显示时必须手动指定和原图一致的像素范围,比如0~255范围图像加参数vmin=0, vmax=255,0~1范围图像加参数vmin=0, vmax=1。 - 冗余FFT计算引入误差:你在显示模糊图像时,对已经是空域退化图的
g又做了一次fft2+ifft2,虽然理论上变换是无损的,但浮点计算累积的误差会被后续显示拉伸放大,直接显示g即可。另外ifft2的输出存在浮点误差带来的微小虚部,取实部np.real()比取绝对值np.abs()更合理,避免负误差被翻转为正值引入亮度偏移。
修正后可运行代码
import numpy as np import matplotlib.pyplot as plt from skimage.color import rgb2gray from numpy.fft import fft2, ifft2 # 初始化画布 f, axes = plt.subplots(1, 3, figsize=(15, 5)) # 读取并预处理图像,对齐Matlab 0~255数值范围 img = plt.imread('lena256.jpg') if len(img.shape) == 3: img = rgb2gray(img) # 把rgb2gray输出的0~1范围映射回0~255 if img.max() <= 1: img = (img * 255).astype(np.float64) N = 256 # 强制裁剪图像到256x256,避免尺寸不匹配问题 f_orig = img[:N, :N] axes[0].imshow(f_orig, cmap='gray', vmin=0, vmax=255) axes[0].set_title('Original') axes[0].axis('off') # 构造4x4均值模糊核 b = np.ones((4, 4)) / (4 ** 2) F = fft2(f_orig) B = fft2(b, s=(N, N)) G = F * B # 生成模糊加噪退化图,噪声标准差10适配0~255像素范围 g = np.real(ifft2(G)) + 10 * np.random.randn(N, N) axes[1].imshow(g, cmap='gray', vmin=0, vmax=255) axes[1].set_title('Blurred + Noisy') axes[1].axis('off') # 逆滤波计算 G_freq = fft2(g) # 修正频域核:保留相位,截断过小的幅值避免除零爆炸 B_abs = np.abs(B) B_phase = np.angle(B) B_abs[B_abs < 0.2] = 0.2 B_fixed = B_abs * np.exp(1j * B_phase) H = 1 / B_fixed I_freq = G_freq * H im = np.real(ifft2(I_freq)) # 裁剪像素值到合法显示范围 im = np.clip(im, 0, 255) axes[2].imshow(im, cmap='gray', vmin=0, vmax=255) axes[2].set_title('Inverse Filter') axes[2].axis('off') plt.tight_layout() plt.show()
调试建议:先注释掉加噪声的代码,把截断阈值
n设为1e-3,无噪声条件下逆滤波应该能几乎完美还原模糊图像,确认基础流程跑通后,再依次添加噪声、替换为维纳滤波逻辑即可。维纳滤波只需将逆滤波核H替换为np.conj(B) / (np.abs(B)**2 + K),其中K是和噪声水平相关的正则化参数,相比硬阈值截断的逆滤波抗噪性会有明显提升。
内容的提问来源于stack exchange,提问作者Mr. Meeseeks
相关产品推荐
相关产品推荐

