傅立叶变换用于分析各种滤波器的频率特性。图像中的振幅在边缘点或噪声急剧变化。因此,可以说边缘和噪声是图像中的高频内容。如果幅度没有太大变化,则它是低频分量。
主要使用np.fft.fft2()、np.fft.fftshift()以及20*np.log(np.abs(fshift))函数来实现。
np.fft.fft2()
numpy.fft.fft2(img, s=None, axes=(-2, -1), norm=None)
参数如下:
np.fft.fftshift()
函数参数主要是np.fft.fft2()函数的输出,即复数数组。此函数可以将零频率分量移到频谱中心。变换之后的频谱显示范围从[0, N]变为:[-N/2,N/2-1](N为偶数)或[-(N-1)/2,(N-1)/2](N为奇数)。
20*np.log(np.abs(fshift))
函数参数主要是np.fft.fftshift()函数的输出,傅里叶变换得到的结果是一个复数数组,不能直接用于显示图像,要想得到频谱灰度图像,需要一个映射,把复数映射[0, 255]之间。
代码示例:
from matplotlib import pyplot as plt
import numpy as np
import cv2 as cv
img = cv.imread('C:\\Users\\dell\\Desktop\\prac files\\prac1.jpg')
img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
f = np.fft.fft2(img_gray)
f_shift = np.fft.fftshift(f)
f_shift_log = 20*np.log(np.abs(f_shift))
plt.subplot(1, 2, 1)
plt.imshow(img_gray, cmap = "gray")
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(1, 2, 2)
plt.imshow(f_shift_log, cmap = "gray")
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
plt.show()
逆傅里叶变换
利用频率变换可以在频域中进行一些操作,例如高通滤波和重建图像,即找到逆DFT。需用尺寸为60x60的矩形窗口遮罩即可消除低频。然后,使用np.fft.ifftshift()应用反向移位,以使DC分量再次出现在左上角。然后使用np.ifft2()函数找到逆FFT。同样,结果将是一个复数,可以采用其实部或绝对值。
代码示例:
from matplotlib import pyplot as plt
import numpy as np
import cv2 as cv
img = cv.imread('C:\\Users\\dell\\Desktop\\prac files\\prac1.jpg')
img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
#傅里叶
f = np.fft.fft2(img_gray)
f_shift = np.fft.fftshift(f)
f_shift_log = 20*np.log(np.abs(f_shift))
#逆傅里叶
rows, cols = img_gray.shape
crow, ccol = rows//2 , cols//2
f_shift[crow-30:crow+31, ccol-30:ccol+31] = 0
f_ishift = np.fft.ifftshift(f_shift)
img_back = np.fft.ifft2(f_ishift)
img_back = np.real(img_back)
#显示
plt.subplot(1, 3, 1)
plt.imshow(img_gray, cmap = "gray")
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(1, 3, 2)
plt.imshow(f_shift_log, cmap = "gray")
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
plt.subplot(1, 3, 3)
plt.imshow(img_back, cmap = "gray")
plt.title('Result in JET'), plt.xticks([]), plt.yticks([])
plt.show()
主要使用cv.dft()函数来实现。
cv.dft(src, dst, flags, nonzeroRows)
参数如下:
np.float32
标识符名称 | 意义 |
---|---|
DFT_INVERSE | 用一维或二维逆变换代替默认的正向变换 |
DFT_SCALE | 缩放比例标识符,输出的结果都会以 1/N进行缩放,通常会结合DFT_INVERSE一起使用 |
DFT_ROWS | 对输入矩阵的每行进行正向或反向的变换,此标识符可以在处理多种矢量的时候用于减小资源开销,这些处理常常是三维或高维变换等复杂操作 |
DFT_COMPLEX_OUTPUT | 进行一维或二维实数数组正变换。这样的结果虽然是复数阵列,但拥有复数的共扼对称性(CCS),所以可以被写成一个拥有同样尺寸的实数阵列 |
DFT_REAL_OUTPUT | 进行一维或二维复数数组反变换。这样的结果通常是一个大小相同的复矩阵。如果输入的矩阵有复数的共轭对称性(比如是一个带有DFT_COMPLEX_OUTPUT标识符的正变换结果),便会输出实矩阵 |
代码示例:
from matplotlib import pyplot as plt
import numpy as np
import cv2 as cv
img = cv.imread("C:\\Users\\dell\\Desktop\\prac files\\prac1.jpg", 0)
f = cv.dft(np.float32(img), flags = cv.DFT_COMPLEX_OUTPUT)
f_shift = np.fft.fftshift(f)
f_shift_log = 20*np.log(cv.magnitude(f_shift[:,:,0], f_shift[:,:,1]))
plt.subplot(1, 2, 1)
plt.imshow(img, cmap="gray")
plt.title("Input Image"), plt.xticks([]), plt.yticks([])
plt.subplot(1, 2, 2)
plt.imshow(f_shift_log, cmap="gray")
plt.title("Magnitude Spectrum"), plt.xticks([]), plt.yticks([])
plt.show()
其中cv.magnitude()函数用来计算二维矢量的幅值。
cv.magnitude(x, y, magnitude)
参数如下:
也可以使用cv.cartToPolar()函数,参数同上,此函数在单个镜头中同时返回幅值和相位。
逆傅里叶变换
删除图像中的高频内容,即将LPF应用到图像中。它实际上模糊了图像。首先创建一个高值(1)在低频部分,即我们过滤低频内容,0在高频区。
代码示例:
from matplotlib import pyplot as plt
import numpy as np
import cv2 as cv
img = cv.imread("C:\\Users\\dell\\Desktop\\prac files\\prac1.jpg", 0)
#傅里叶
f = cv.dft(np.float32(img), flags = cv.DFT_COMPLEX_OUTPUT)
f_shift = np.fft.fftshift(f)
f_shift_log = 20*np.log(cv.magnitude(f_shift[:,:,0], f_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 = f_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(1, 3, 1)
plt.imshow(img, cmap="gray")
plt.title("Input Image"), plt.xticks([]), plt.yticks([])
plt.subplot(1, 3, 2)
plt.imshow(f_shift_log, cmap="gray")
plt.title("Magnitude Spectrum"), plt.xticks([]), plt.yticks([])
plt.subplot(1, 3, 3)
plt.imshow(img_back, cmap="gray")
plt.title("Result in JET"), plt.xticks([]), plt.yticks([])
plt.show()
对于某些数组尺寸,DFT的计算性能较好。当数组大小为2的幂时,速度最快。对于大小为2、3和 5的乘积的数组,也可以非常有效地进行处理。如果担心代码的性能,可以在找到DFT之前将数组的大小修改为任何最佳大小(通过填充零)。对于OpenCV,必须手动填充零。但是对于Numpy,指定FFT计算的新大小,它将自动填充零。主要使用cv.getOptimalDFTSize()函数来实现,同时适用于cv.dft()和np.fft.fft2()函数。
代码示例:
from matplotlib import pyplot as plt
import numpy as np
import cv2 as cv
img = cv.imread("C:\\Users\\dell\\Desktop\\prac files\\prac1.jpg", 0)
rows, cols = img.shape
print(rows, cols)
nrows = cv.getOptimalDFTSize(rows)
ncols = cv.getOptimalDFTSize(cols)
print(nrows, ncols)
之后我们使用OpenCV对图像进行填充。
代码示例:
#填充图像方法一
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)
之后再对图像’nimg’进行傅里叶变换等操作即可。
通过傅里叶变化得到的频谱图,(零频率分量即DC分量已经平移到了频谱图的中心位置)中心为低频区域,从中心往外缘扩散,越往外频率越大。HPF为高通滤波器,可以滤掉低频信号,LPF为低通滤波器,可以滤掉高频信号。以下为拉普拉斯变换的结果,可以很好的解释为什么拉普拉斯变换是高通滤波器。其余的同理。