网上很多关于FFT变换的应用,但是对其性质的探索并不多。
我做了一个简单的实验,来探讨平移,缩放,旋转的性质。
由于我浅薄的知识,如有不对的地方,请各位大佬指正。
- 平移:FFT具有平移不变性,在空域平移图像,频域的信号不发生变换。
- 旋转:旋转同一性,空域图像的旋转,也会带动频域图像的旋转。
- 缩放:在空域缩小图像,频域的信号会相应的缩小信息量,视觉上体现为放大频谱图。
代码实现
先写一些准备代码,这里要注意,需要将fft2
变换的结果,进行后续处理,方便展示。
1.abs
傅里叶变换的结果是复数,需要取模转为实数
2. +(1 ** 10)
防止矩阵为0,无法进行
l
o
g
log
log运算
3. log
傅里叶变换的结果,范围很大,例如对于lena来说,变化范围为
[
−
1
0
7
,
1
0
9
]
[-10^7, 10^9]
[−107,109],所以我们需要用
l
o
g
log
log函数进行缩小范围,提升视觉观感
4. fftshift
:将直流分量变化到中间,提升观感
fft2
变化函数:
def fft2_log(data):
res = np.fft.fft2(data)
res = np.log(np.abs(res) + (1 ** -10))
res = np.fft.fftshift(res)
return res
显示图像函数:
def show_imgs(imgs, titles):
fig, axs = plt.subplots(nrows = 1,ncols = len(imgs), figsize = [20,20])
for i in range(len(imgs)):
axs[i].imshow(imgs[i], cmap = plt.cm.gray)
axs[i].set_xlabel(titles[i])
平移
I = Image.open('lena.png').convert('L')
I = np.array(I)
img = np.pad(I, ((0,512),(0,512)))
img_fft = fft2_log(img)
res = np.pad(I, ((512,0),(0,512)))
res_fft = fft2_log(res)
show_imgs([img,img_fft, res,res_fft],['img','img_fft','move','move_fft'])
我们可以看出,空域图像从左上移到左下,频率域的图像没有变化
我们应当将频率域的图像理解为很多波的集合,是一个无限延展的空间
我们只是截取了其中一块,这对理解后面的缩放很重要。
空域图像平移,并不会影响到这些波相位,幅度,频率的变换(其只和空域图像的起伏有关)。
所以,在空域平移不会影响频域的变换。
旋转
I = Image.open('lena.png').convert('L')
img = np.array(I)
img = np.pad(I, ((256,256),(256,256)))
img_fft = fft2_log(img)
res = Image.fromarray(img).rotate(45)
res = np.array(res)
res_fft = fft2_log(res)
show_imgs([img,img_fft, res,res_fft],['img','img_fft','rotate','rotate_fft'])
旋转很好理解,在空域的旋转,会影响到频率域的相位,所以频域的图像也同样跟着旋转
缩放
I = Image.open('lena.png').convert('L')
img = np.array(I)
img = np.pad(I, ((256,256),(256,256)))
img_fft = fft2_log(img)
res = I.resize([1024,1024])
res = np.array(res)
res_fft = fft2_log(res)
show_imgs([img,img_fft, res,res_fft],['img','img_fft','scale','scale_fft'])
缩放是FFT最有趣的一个性质,我们换一个角度,从信息量的角度去考虑。
从右边的大图看起,当图像缩小时,所包含的信息量也会同样的缩小,
所以,我们可以去按照缩小的比例,截取同样的信息量。
同时,我们知道,图像缩小时,损失的都是高频的信息量,保留的是低频的信息量,
所以,我们需要保留频率域的中间一部分,即低频的信息量。
然后,我们将保留的频域信息铺满(放大),即可得到缩小后的频率图像。
这在视觉上体现为,空域缩小,频域放大的效果。