2021-07-27

傅里叶变换

傅立叶变换用于分析各种滤波器的频率特性。可以将图像视为在两个方向上采样的信号。因此,在X 和Y方向都进行傅立叶变换,可以得到图像的频率表示。图像中的振幅在哪里急剧变化?在边缘点或噪声。因此,可以说边缘和噪声是图像中的高频内容。如果幅度没有太大变化,则它是低频分量。

Numpy中的傅里叶变化

Numpy函数介绍
numpy.fft.fft()

该函数计算一维傅里叶变换,它的第一个参数是一维数组。第二个参数是可选的,它决定输出数组的大小。如果它大于输入数组的大小,则在计算FFT之前用零填充输入数组。如果小于输入数组,将裁切输入数组。如果未传递任何参数,则输出数组的大小将与输入的大小相同。返回值是一个一维数组。

numpy.fft.fft2()

该函数计算二维傅里叶变换,它的第一个参数是输入图像,即灰度图像。第二个参数是可选的,它决定输出数组的大小。如果它大于输入图像的大小,则在计算FFT之前用零填充输入图像。如果小于输入图像,将裁切输入图像。如果未传递任何参数,则输出数组的大小将与输入的大小相同。返回值是一个图像。

numpy.fft.fftn()

该函数计算N维傅里叶变换,它的第一个参数是N维数组。第二个参数是可选的,它决定输出数组的大小。如果它大于输入数组的大小,则在计算FFT之前用零填充输入数组。如果小于输入数组,将裁切输入数组。如果未传递任何参数,则输出数组的大小将与输入的大小相同。返回值是一个N维数组。

numpy.fft.fftfreq()

该函数傅里叶变换的采样频率。

numpy.fft.shift()

该函数将零频点移到频谱的中间,将FFT变换之后的频谱显示范围从[0, N]变为:[-N/2,N/2-1]N为偶数或[-(N-1)/2,(N-1)/2]N为奇数。

numpy.fft.ifft2()

该函数计算逆二维傅里叶变换,它的第一个参数是输入图像,即灰度图像。第二个参数是可选的,它决定输出数组的大小。如果它大于输入图像的大小,则在计算FFT之前用零填充输入图像。如果小于输入图像,将裁切输入图像。如果未传递任何参数,则输出数组的大小将与输入的大小相同。返回值是一个图像。

注意np.fft.fft2()是用快速傅立叶变换。结果需要通过使用abs求绝对值才可以进行可视化,但是视觉效果并不理想,因为傅立叶频谱范围很大,所以要用log对数变换来改善视觉效果。在使用log函数的时候,要写成log(1 + x) 而不是直接用log(x),这是为了避开对0做对数处理。

图像傅里叶变换例子
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
aimg = cv.imread('C:\\Users\\Administrator\\Desktop\\pic\\mei.png',0)
rows,cols = aimg.shape
nrows = cv.getOptimalDFTSize(rows)
ncols = cv.getOptimalDFTSize(cols)
img = np.zeros((nrows,ncols))
img[:rows,:cols] = aimg
f = np.fft.fft2(img)
fshift = np.fft.fftshift(f)
print(fshift)
magnitude_spectrum = 20*np.log(np.abs(fshift))
print(magnitude_spectrum)
plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(magnitude_spectrum, cmap = 'gray')
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
plt.show()
图像逆傅里叶变换例子

现在发现了频率变换,您可以在频域中进行一些操作,例如高通滤波和重建图像,即找到逆离散傅里叶变换。只需用尺寸为60x60的矩形窗口遮罩即可消除低频。然后,使用np.fft.ifftshift()应用反向移位,以使DC分量再次出现在左上角。然后使用np.ifft2()函数找到逆快速。

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
aimg = cv.imread('C:\\Users\\Administrator\\Desktop\\pic\\mei.png',0)
rows,cols = aimg.shape
nrows = cv.getOptimalDFTSize(rows)
ncols = cv.getOptimalDFTSize(cols)
img = np.zeros((nrows,ncols))
img[:rows,:cols] = aimg
f = np.fft.fft2(img)
fshift = np.fft.fftshift(f)
magnitude_spectrum = 20*np.log(np.abs(fshift))

rows, cols = img.shape
crow,ccol = rows//2 , cols//2
fshift[crow-30:crow+31, ccol-30:ccol+31] = 0
f_ishift = np.fft.ifftshift(fshift)
img_back = np.fft.ifft2(f_ishift)
img_back = np.real(img_back)
img_back = 20*np.log(np.abs(img_back))
plt.subplot(131),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(132),plt.imshow(img_back, cmap = 'gray')
plt.title('Image after HPF'), plt.xticks([]), plt.yticks([])
plt.subplot(133),plt.imshow(img_back)
plt.title('Result in JET'), plt.xticks([]), plt.yticks([])
plt.show()

OpenCV中的傅里叶变换

Opencv函数介绍
cv2.dft

该函数可以计算图像的傅里叶变换,他的第一个参数是输入的图像,它有两个通
道。第一个通道是结果的实部,第二个通道是结果的虚部。输入图像首先应转换为 np.float32 ,第二个参数是运算后的图像,第三个参数是一个转换的标识符,第四个参数是int类型的nonzeroRows,默认值为0.当此参数设为非零是,函数会假设只有输入矩阵的第一个非零行包含非零元素,或只有输出矩阵的一个非零行包含非零元素。
标识符:

标识符名称意义
DFT_INVERSE用一维或二维逆变换代替默认的正向变换
DFT_SCALE缩放比例标识符,输出的结果都会以 1/N进行缩放,通常会结合DFT_INVERSE一起使用
DFT_ROWS对输入矩阵的每行进行正向或反向的变换,此标识符可以在处理多种矢量的时候用于减小资源开销,这些处理常常是三维或高维变换等复杂操作
DFT_COMPLEX_OUTPUT进行一维或二维实数数组正变换。这样的结果虽然是复数阵列,但拥有复数的共扼对称性(CCS),所以可以被写成一个拥有同样尺寸的实数阵列
DFT_REAL_OUTPUT进行一维或二维复数数组反变换。这样的结果通常是一个大小相同的复矩阵。如果输入的矩阵有复数的共辄对称性(比如是一个带有DFT_COMPLEX_OUTPUT标识符的正变换结果),n便会输出实矩阵
cv2.idft

该函数可以计算图像的傅里叶逆变换,他的第一个参数是输入的图像,它有两个通道。第一个通道是结果的实部,第二个通道是结果的虚部。输入图像首先应转换为 np.float32 ,第二个参数是运算后的图像,第三个参数是一个转换的标识符,第四个参数是int类型的nonzeroRows,默认值为0.当此参数设为非零是,函数会假设只有输入矩阵的第一个非零行包含非零元素,或只有输出矩阵的一个非零行包含非零元素。

cv2.magnitude

该函数可以返回傅里叶变换后iimg的幅值,第一个参数:表示矢量的浮点型X坐标值,也就是实部 。第二个参数:表示矢量的浮点型Y坐标值,也就是虚部 。第三个参数:OutputArray类型的magnitude,输出的幅值。,它和第一个参数X有着同样的尺寸和类型。

图像傅里叶变换例子
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
aimg = cv.imread('C:\\Users\\Administrator\\Desktop\\pic\\mei.png',0)
rows,cols = aimg.shape
nrows = cv.getOptimalDFTSize(rows)
ncols = cv.getOptimalDFTSize(cols)
img = np.zeros((nrows,ncols))
img[:rows,:cols] = aimg
dft = cv.dft(np.float32(img),flags = cv.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)
dft_shift = np.fft.fftshift(dft)
magnitude_spectrum = 20*np.log(cv.magnitude(dft_shift[:,:,0],dft_shift[:,:,1]))
plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(magnitude_spectrum, cmap = 'gray')
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
plt.show()
图像逆傅里叶变换例子

我们要做傅里叶变换的逆变换。在上一节中,我们创建了一个高通滤波器,这次我们将看到如何删除图像中的高频内容,即我们将低通滤波器应用到图像中。它实际上模糊了图像。为此,我们首先创建一个高值1在低频部分,即我们过滤低频内容,0在高频区。

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
aimg = cv.imread('C:\\Users\\Administrator\\Desktop\\pic\\mei.png',0)
rows,cols = aimg.shape
nrows = cv.getOptimalDFTSize(rows)
ncols = cv.getOptimalDFTSize(cols)
img = np.zeros((nrows,ncols))
img[:rows,:cols] = aimg
dft = cv.dft(np.float32(img),flags = cv.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)
dft_shift = np.fft.fftshift(dft)
magnitude_spectrum = 20*np.log(cv.magnitude(dft_shift[:,:,0],dft_shift[:,:,1]))
rows, cols = img.shape
crow,ccol = rows//2 , cols//2
# 首先创建一个掩码,中心正方形为1,其余全为零
mask = np.zeros((rows,cols,2),np.uint8)
mask[crow-30:crow+30, ccol-30:ccol+30] = 1
# 应用掩码和逆DFT
fshift = dft_shift*mask
f_ishift = np.fft.ifftshift(fshift)
img_back = cv.idft(f_ishift)
img_back = cv.magnitude(img_back[:,:,0],img_back[:,:,1])
plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(img_back, cmap = 'gray')
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
plt.show()

注意 通常,OpenCV函数cv.dft()和cv.idft()比Numpy函数更快。但是Numpy函数更容易使用。

离散傅里叶变换的优化

对于某些数组尺寸,DFT的计算性能较好。当数组大小为2的幂时,速度最快。对于大小为2、3和 5的乘积的数组,也可以非常有效地进行处理。因此,如果您担心代码的性能,可以在找到DFT之前将数组的大小修改为任何最佳大小(通过填充零)。对于OpenCV,您必须手动填充零。但是对于Numpy,您指定FFT计算的新大小,它将自动为您填充零。
OpenCV为此提供了一个函数来找到数组的最佳大小,cv.getOptimalDFTSize()。它同时适用于cv.dft()和np.fft.fft2()。
例子:

In [16]: img = cv.imread('messi5.jpg',0)
In [17]: rows,cols = img.shape
In [18]: print("{} {}".format(rows,cols))
342 548
In [19]: nrows = cv.getOptimalDFTSize(rows)
In [20]: ncols = cv.getOptimalDFTSize(cols)
In [21]: print("{} {}".format(nrows,ncols))
360 576

因此我们将大小 (342,548) 修改为 (360,576) 。现在让我们用零填充(对于OpenCV),并找到其DFT计算性能。可以通过创建一个新的零数组并将数据复制到其中来完成此操作,或者使用cv.copyMakeBorder()。

nimg = np.zeros((nrows,ncols))
nimg[:rows,:cols] = img
right = ncols - cols
bottom = nrows - rows
bordertype = cv.BORDER_CONSTANT #只是为了避免PDF文件中的行中断
nimg = cv.copyMakeBorder(img,0,bottom,0,right,bordertype, value = 0)
  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值