我在我的图像和卷积核周围使用零填充,将它们转换到傅立叶域,并将它们反转回来以获得卷积图像,请参阅下面的代码。然而,结果是错误的。我本来以为会有模糊的图像,但输出是四个移位的四分之一。为什么输出是错误的,我如何修复代码?
输入图像:
的数据
卷积结果:
的
from PIL import Image,ImageDraw,ImageOps,ImageFilter
import numpy as np
from scipy import fftpack
from copy import deepcopy
import imageio
## STEP 1 ##
im1=Image.open("pika.jpeg")
im1=ImageOps.grayscale(im1)
im1.show()
print("s",im1.size)
## working on this image array
im_W=np.array(im1).T
print("before",im_W.shape)
if(im_W.shape[0]%2==0):
im_W=np.pad(im_W, ((1,0),(0,0)), 'constant')
if(im_W.shape[1]%2==0):
im_W=np.pad(im_W, ((0,0),(1,0)), 'constant')
print("after",im_W.shape)
Boxblur=np.array([[1/9,1/9,1/9],[1/9,1/9,1/9],[1/9,1/9,1/9]])
dim=Boxblur.shape[0]
##padding before frequency domain multipication
pad_size=(Boxblur.shape[0]-1)/2
pad_size=int(pad_size)
##padded the image(starts here)
p_im=np.pad(im_W, ((pad_size,pad_size),(pad_size,pad_size)), 'constant')
t_b=(p_im.shape[0]-dim)/2
l_r=(p_im.shape[1]-dim)/2
t_b=int(t_b)
l_r=int(l_r)
##padded the image(ends here)
## padded the kernel(starts here)
k_im=np.pad(Boxblur, ((t_b,t_b),(l_r,l_r)), 'constant')
print("hjhj",k_im)
print("kernel",k_im.shape)
##fourier transforms image and kernel
fft_im = fftpack.fftshift(fftpack.fft2(p_im))
fft_k = fftpack.fftshift(fftpack.fft2(k_im))
con_in_f=fft_im*fft_k
ifft2 = abs(fftpack.ifft2(fftpack.ifftshift(con_in_f)))
convolved=(np.log(abs(ifft2))* 255 / np.amax(np.log(abs(ifft2)))).astype(np.uint8)
final=Image.fromarray(convolved.T)
final.show()
u=im1.filter(ImageFilter.Kernel((3,3), [1/9,1/9,1/9,1/9,1/9,1/9,1/9,1/9,1/9], scale=None, offset=0))
u.show()
字符串
1条答案
按热度按时间zvokhttg1#
离散傅里叶变换(DFT)以及扩展的FFT(计算DFT)在输入和输出的第一个元素(对于图像,左上角的像素)中具有原点。这就是为什么我们经常在输出上使用
fftshift
函数,以便将原点移动到我们更熟悉的位置(图像的中间)。这意味着我们需要将一个3x3均匀加权的模糊核变换成这样,然后将其传递给FFT函数:
字符串
也就是说,内核的中间(其原点)位于图像的左上角,中间上方和左侧的像素环绕并出现在图像的右端和底端。
我们可以使用
ifftshift
函数来实现这一点,该函数在填充后应用于内核。当填充内核时,我们需要注意原点(内核的中间)位于内核图像k_im
中的位置k_im.shape // 2
(整数除法)。初始原点为[3,3]//2 == [1,1]
。通常,我们匹配的图像大小是偶数,例如[256,256]
。原点在[256,256]//2 == [128,128]
。这意味着我们需要向左和向右(以及底部和顶部)填充不同的量。我们需要仔细计算这个padding:型
请注意,输入图像
img
不需要填充(尽管如果您想强制使用FFT更便宜的大小,可以这样做)。也不需要在乘法之前将fftshift
应用于FFT的结果,然后立即反转该移位,这些移位是冗余的。仅当要显示傅立叶域图像时,才应使用fftshift
。最后,对滤波图像应用对数缩放是错误的。生成的代码是(我使用pyplot进行显示,根本没有使用PIL):
型
注意,我取的是逆FFT的真实的部。虚部应仅包含非常接近零的值,这是计算中舍入误差的结果。取绝对值,虽然很常见,但是不正确的。例如,您可能希望将滤镜应用于包含负值的图像,或应用产生负值的滤镜。在这里取绝对值会产生假象。如果逆FFT的输出包含与零显著不同的虚值,则在填充滤波内核的方式中存在误差。
还要注意,这里的内核很小,因此模糊效果也很小。为了更好地看到模糊的效果,可以使用更大的内核,例如
np.ones((7,7)) / 49
。