使用numpy.fft对图像进行傅里叶变换

numpy.fft——numpy中的离散傅里叶变换模块

这篇博客将简要介绍numpy.fft中对图像进行处理的函数以及简单的滤波方法

1.numpy.fft.fft2

这个函数用于计算二维的离散傅里叶变换。

fft.fft2(a,s=None,axes=(-2,-1),norm=None)

从函数定义中可以看出,fft2接收4个参数:

a: 要进行傅里叶变换的数据,需要是一个数组,可以是复数形式的;

s:int型的序列(list,tuple都可以),描述输出的大小,即输出的分辨率。非必填参数。s中的各个元素用于设置输出在各个维度上的长度,即每个维度上的像素个数,s[0]代表第一个轴,s[1]代表第二个轴,以此类推。 如果设定的大小小于输入大小,则将输入裁剪成设定大小;如果设定大小大于输入大小,则将输入用0填充成设定大小。

axes:指定要在哪两个维度上进行傅里叶变换。可选参数,默认是最后两个维度。

norm: 归一化的方式,可选'backward','ortho','forward',默认是backward。

例:

import numpy as np
from PIL import Image
from matplotlib import pyplot as plt

root = r'lena.png'
img = Image.open(root).convert('L')    #转成灰度图像
fft = np.fft.fft2(img,axes=(0,1))    # 进行傅里叶变换,axes不需要自定义
plt.subplot(121),plt.imshow(img,cmap='gray')    # 显示原图
plt.subplot(122)
plt.imshow(np.log(np.abs(fft)),cmap='gray') # 显示傅里叶变换的结果
                                            # 因为傅里叶变换的结果是复数,所以取模;
                                            # 傅里叶变换后的值过大,所以取对数以便判读
plt.show()

显示结果: 

2.傅里叶变换的图像怎么判读?

对于傅里叶变换的结果,每个轴的最前端代表频率为0的项,前半部分代表正频率项,中间部分代表奈奎斯特频率项(我也不懂这是什么),后半部分代表负频率项,即:

        从0升高到最大频率(正值)|中间| 从最小频率(负值)升高到负数中的最大值(负值)                  就像:[ 0.  1.  2.  3.  4. -5. -4. -3. -2. -1.]

那么对于图像,左上角就是频率为0的项,左上1/4就是正频率项(在两个轴都是正),右下1/4是负频率项(在两个轴都是负)。

       

numpy.fft.fftshift

前面通过fft2生成的频谱图不方便理解和处理(零频率在左(上)侧,而正频率和负频率都在零频率的右(下)侧),fftshift函数通过将频谱沿着每个维度移动一半的长度,将零频率分量移到频谱的中心位置,从而使频谱更易于理解和处理。

fft.fftshift(xaxes=None)

此函数接收2个参数:

x:输入的频谱图,需要是array;

axes: 指示在哪个轴上进行移动。非必填,默认为None,即在每个轴上都进行移动。

fft = np.fft.fft2(img,axes=(0,1))    
fft_shift = np.fft.fftshift(fft)     # shift
plt.subplot(131),plt.imshow(img,cmap='gray')    # 显示原图
plt.title('Original Image'), plt.axis('off')
plt.subplot(132)
plt.title('FFT'), plt.axis('off')
plt.imshow(np.log(np.abs(fft)),cmap='gray') 
plt.subplot(133),plt.imshow(np.log(np.abs(fft_shift)),cmap='gray')
plt.title('FFT Shifted'), plt.axis('off')
plt.show()

显示结果:

这样频谱图的中心是0频率部分,左上1/4为负频率,右下1/4为正频率。

numpy.fft.ifftshift

把fftshift转换过的频谱图再转换回去,是fftshift的逆函数。Shift过的频谱图不能直接用于反傅里叶变换,需要使用这个函数转换回原来的形式才能进行反傅里叶变换。

3.numpy.fft.ifft2

用于计算离散傅里叶逆变换

fft.ifft2(as=Noneaxes=(-2, -1)norm=None)

该函数接收4个参数,其中输入参数a是与fft2的输出有着相同排序方式的频谱图,其他参数与fft2相同,不再赘述。

ifft = np.fft.ifft2(fft)
plt.subplot(121),plt.imshow(img,cmap='gray')
plt.title('Original Image'), plt.axis('off')
plt.subplot(122),plt.imshow(np.abs(ifft),cmap='gray')
plt.title('iFFT Image'), plt.axis('off')
plt.show()

        与原图一致。

4.简单的滤波

1)用傅里叶变换实现低通和高通滤波

根据前文,频谱图(shifted)中的中间是低频部分,让中间部分通过即为低通滤波,中间部分不通过,其他部分通过则为高通滤波。

rows, cols = fft.shape[0], fft.shape[1]
mid_row, mid_col = int(rows/2), int(cols/2)    # 中间的行号、列号
low_pass_fftshift = np.zeros_like(fft_shift)
high_pass_fftshift = fft_shift.copy()
low_pass_fftshift[mid_row-20:mid_row+20,mid_col-20:mid_col+20] = fft_shift[mid_row-20:mid_row+20,mid_col-20:mid_col+20]            # 低频通过
high_pass_fftshift[mid_row-20:mid_row+20,mid_col-20:mid_col+20] = 0    # 低频设为0,则为高通
low = np.fft.ifft2(np.fft.ifftshift(np.fft.ifftshift(low_pass_fftshift,axes=(0,1))))
high = np.fft.ifft2(np.fft.ifftshift(np.fft.ifftshift(high_pass_fftshift,axes=(0,1))))
plt.subplot(221),plt.imshow(np.log(np.abs(low_pass_fftshift)),cmap='gray')
plt.title('Low Pass Filter'), plt.axis('off')
plt.subplot(222),plt.imshow(np.abs(low),cmap='gray')    
plt.title('Low Pass Image'), plt.axis('off')
plt.subplot(223),plt.imshow(np.log(np.abs(high_pass_fftshift)),cmap='gray')
plt.title('High Pass Filter'), plt.axis('off')
plt.subplot(224),plt.imshow(np.abs(high),cmap='gray')
plt.title('High Pass Image'), plt.axis('off')
plt.show()

效果: 

低通滤波即为图像模糊,高通滤波则得到图像边缘。 

2)去横、竖线条

在频域图像中可以很容易地注意到两条白色的直线,一条水平,一条竖直,在图像中央交叉。其中,水平线条代表原图中沿着水平方向变化快的部分,即为竖线条;同理,竖直线条代表原图中的横线部分。我们可以试着分别将这两部分去除。

 以上面的网格图为例。

root = r'grid.png'
img = Image.open(root).convert('L')

fft = np.fft.fft2(img)  
fft_shift = np.fft.fftshift(fft)
rows, cols = fft.shape[0],fft.shape[1]
mid_row, mid_col = int(rows/2), int(cols/2)
horizen_shift, vertical_shift = np.copy(fft_shift), np.copy(fft_shift)
horizen_shift[mid_row-10:mid_row+10,:mid_col-10] = 0
horizen_shift[mid_row-10:mid_row+10,mid_col+10:] = 0
vertical_shift[:mid_row-10,mid_col-10:mid_col+10] = 0
vertical_shift[mid_row+10:,mid_col-10:mid_col+10] = 0
plt.subplot(221),plt.imshow(np.log(np.abs(horizen_shift)),cmap='gray')
plt.title('Horizontal Shift'), plt.axis('off')
plt.subplot(222),plt.imshow(np.log(np.abs(vertical_shift)),cmap='gray')
plt.title('Vertical Shift'), plt.axis('off')
ver_ishift = np.fft.ifftshift(horizen_shift,axes=(0,1))
hor_ishift = np.fft.ifftshift(vertical_shift,axes=(0,1))
horizental_remove = np.fft.ifft2(horizen_shift)
vertical_remove = np.fft.ifft2(vertical_shift)
plt.subplot(223),plt.imshow(np.abs(horizental_remove),cmap='gray')
plt.title('Horizontal Removed'), plt.axis('off')
plt.subplot(224),plt.imshow(np.abs(vertical_remove),cmap='gray')
plt.title('Vertical Removed'), plt.axis('off')
plt.show()

去除频域图中的水平线,则原图中竖线消失;去除频域中的竖直线,则原图中横线消失。 

  • 17
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值