2 二维离散傅里叶变换DFT

2 二维离散傅里叶变换DFT

一、DFT的基本思想

​ 傅里叶变换方法的基本思想是图像可以看作二位函数f,这个函数可以表示成在二个维度上正弦和余弦(傅里叶基本函数)的加权和。

​ 使用DFT可将(空间域/时域)图像中的一组灰度像素值转换为一组(频域)傅里叶系数,而且它是离散的(因为空间和变换变量只可以使用离散连续整数的值)。

​ 类似地,频域中的傅里叶系数二维数组可以通过离散傅里叶逆变换(IDFT) 变换至空间域。这种变换也称为利用傅里叶系数重建图像。DFT和IDFT的数学定义在这里不作展开。

二、DFT的作用

​ 由于通常情况下图像是平滑的,大多数图像可以用少量的DFT系数表示,而其余所有较高的系数几乎可以被忽略或为0。因此,DFT对于图像压缩非常有用,尤其是对于稀疏傅里叶图像。只有少数的傅里叶系数用于重建图像,因此只有这些频率可以被存储,其他的可以丢弃,这可以用于高压缩,例如,在JPEG图像(即常见的.jpg格式图像)压缩算法中使用了类似于变换的离散余弦变换(DCT)

​ 此外,在频域中使用DFT滤波比在空间域中进行滤波快得多。

三、用快速傅里叶变换算法计算DFT

​ 快速傅里叶变换(FFT)运用了分治的思想,对于一幅n*n的图像,它递归计算的时间复杂度为O(NlogN),而离散傅里叶变换计算的速度慢得多(时间复杂度为O(N^2))。

​ 在Python中,numpy和scipy库中都提供了使用FFT算法计算2D DFT/IDFT的函数。

1.运用scipy.fftpack模块计算

利用scipy.fftpack模块的fft2()/ifft2()函数来计算DFT/IDFT,代码如下:

from PIL import Image
import numpy as np
import matplotlib.pylab as pylab
import scipy.fftpack as fp


def signaltonoise(a, axis, ddof=0):  # scipy1.1中计算信噪比的函数signaltonoise已废除,故须自己实现,大家可自行保存,方便日后使用
    a = np.asanyarray(a)
    m = a.mean(axis)
    sd = a.std(axis=axis, ddof=ddof)
    return np.where(sd == 0, 0, m/sd)


im = np.array(Image.open(r'.../3.jpg').convert('L'))  # 打开图像转换成灰度图像并将其转换为numpy数组。
snr = signaltonoise(im, axis=None)
print('SNR for the original image = ' + str(snr))
freq = fp.fft2(im)
im1 = fp.ifft2(freq).real
print('SNR for the image obtained after reconstruction = ' + str(snr))

assert(np.allclose(im, im1))  # 运用断言函数确保原始图像和重建图像彼此接近
pylab.figure(figsize=(20, 10))
pylab.subplot(121), pylab.imshow(im, cmap='gray'), pylab.axis('off')
pylab.title('Original Image', size=20)
pylab.subplot(122), pylab.imshow(im1, cmap='gray'), pylab.axis('off')
pylab.title('Image obtained after reconstruction', size=20)
pylab.show()

# calculate frequencies and then get 2D fourier-transformed image.
freq2 = fp.fftshift(freq)
pylab.figure(figsize=(10, 10)), pylab.imshow((20 * np.log10(0.1 + freq2)).astype(int)), pylab.show()
# 最后一行代码在运行时会收到警告“ComplexWarning: Casting complex values to real discards the imaginary part”
# 是因为我们将虚数转换为实数时丢失虚部,不用理会

结果如下:

SNR for the original image = 1.9233909074007256
SNR for the image obtained after reconstruction = 1.9233909074007256

在这里插入图片描述

​ 由内联输出的信噪比和输入与重建图像的视觉差异可以看出,重建图像丢失了一些信息。如果把得到的所有系数都用在重建上,这些差异就可以忽略不计。

在这里插入图片描述

​ 由于傅里叶系数是复数,因此我们可以直观地看出其幅度。显示傅里叶变换的幅度称为变换的频谱。DFT的F值[0,0]称为直流系数(DC coefficient)。DC系数对于其他系数值而言太大,因此看不到,多以我们需要通过显示变换的对数来增大变换值。此外为了显示方便,变换系数被移位(使用fftshift()),使直流分量在中间。

2.运用numpy.fft模块计算

计算DFT的幅值和相位 利用fft2()得到傅里叶系数的实分量和虚分量;然后计算幅值、频谱和相位,最后用ifft2()重建图像,代码如下:

import numpy as np
from skimage.color import rgb2gray
from skimage.io import imread
import matplotlib.pylab as pylab
import numpy.fft as fp


im1 = rgb2gray(imread(r'.../4.jpg'))
pylab.figure(figsize=(12, 10))
freq1 = fp.fft2(im1)
im1_ = fp.ifft2(freq1).real
pylab.subplot(2, 2, 1), pylab.imshow(im1, cmap='gray'),
pylab.title('Original Image', size=20)
pylab.subplot(2, 2, 2), pylab.imshow(20*np.log10(0.01 + np.abs(fp.fftshift(freq1))), cmap='gray')
pylab.title('FFT Spectrum Magnitude', size=20)
pylab.subplot(2, 2, 3), pylab.imshow(np.angle(fp.fftshift(freq1)), cmap='gray')
pylab.title('FFT Phase', size=20)
pylab.subplot(2, 2, 4), pylab.imshow(np.clip(im1_, 0, 255), cmap='gray')
pylab.title('Reconstructed Image', size=20)
pylab.show()

输出结果如下:

在这里插入图片描述

虽然FFT相位的信息不像幅值那么丰富,但也很重要,如果相位不可用或使用不同的相位阵列,就无法重建图像

猜你喜欢

转载自blog.csdn.net/Westbrood/article/details/112862636