图像处理中FFT零填充卷积问题:虚数结果是否正常及处理
问题
我是图像处理新手,这个问题偏理论性。假设我有一张5×5图像和一个3×3卷积核,想用FFT2实现卷积。我理解需要对图像做零填充,填充后形式如下:
0000000 0iiiii0 0iiiii0 0iiiii0 0iiiii0 0iiiii0 0000000
同时对卷积核做如下填充:
0000000 0000000 00kkk00 00kkk00 00kkk00 0000000 0000000
之后我用np.fft.fft2把二者转成傅里叶域,相乘后用np.fft.ifft2逆变换,却得到了虚数结果。请问这个现象正常吗?如果正常,下一步该怎么处理?
生成虚数结果的代码:
conv_kernel = np.zeros(image.shape) for i in range(len(kernel)): for j in range(len(kernel[0])): conv_kernel[i,j] = kernel[i,j] fourier_domain_img = np.fft.fft2(image) fourier_domain_kernel = np.fft.fft2(conv_kernel) multiplication_result = np.multiply(fourier_domain_img, fourier_domain_kernel) output = np.fft.ifft2(multiplication_result)
注:图像已按前述方式在边缘填充零,卷积核已移至左上角并保存于conv_kernel中。
output的虚数结果片段:
0.34701525+7.90350302e-19j 0.24993464-1.97207468e-17j 0.25917211-7.08625583e-17j 0.26527233-7.02379773e-17j 0.25986928-8.79273688e-17j 0.30030501-1.20158599e-16j 0.41908497-6.28590074e-17j 0.56592593-7.59364420e-17j 0.66858388-1.28485529e-17j 0.63956427+1.46374819e-17j 0.52383442-2.31376484e-17j 0.30623094-7.88434060e-18j]] complex128
解答
1. 虚数结果是否正常?
完全正常。你看到的虚部是浮点计算误差导致的,量级在1e-17左右,远低于机器浮点精度的阈值,本质上是计算过程中舍入误差的残留,不是真正的复数信号成分。
2. 下一步处理方法
- 提取实部即可:直接用
np.real(output)获取结果的实数部分,这些极小的虚部可以完全忽略,不会影响卷积结果的正确性。 - 修正卷积核的填充方式:你当前把卷积核放在填充数组的左上角,这会导致FFT实现的是循环卷积,而图像处理中我们需要的是线性卷积。正确的做法是把3x3的卷积核放在填充后7x7数组的中心位置,这样才能得到和直接卷积一致的结果。
修正后的代码示例
import numpy as np # 假设image是已填充好的7x7图像,kernel是3x3卷积核 conv_kernel = np.zeros(image.shape) # 计算卷积核的中心偏移 kernel_h, kernel_w = kernel.shape pad_h = (image.shape[0] - kernel_h) // 2 pad_w = (image.shape[1] - kernel_w) // 2 # 将卷积核放在中心位置 conv_kernel[pad_h:pad_h+kernel_h, pad_w:pad_w+kernel_w] = kernel # 傅里叶变换与相乘 f_img = np.fft.fft2(image) f_kernel = np.fft.fft2(conv_kernel) f_result = f_img * f_kernel # 逆变换并提取实部,同时可以用np.round处理微小误差 output = np.real(np.fft.ifft2(f_result)) # 可选:如果需要整数图像,可进一步取整 output = np.round(output).astype(np.uint8)
内容的提问来源于stack exchange,提问作者Vihaan
相关产品推荐
相关产品推荐

