文章目录
1、什么是傅里叶变换及其基础理论
1.1 傅里叶变换
1.2 基础理论
2. Numpy 实现傅里叶和逆傅里叶变换
2.1 Numpy 实现傅里叶变换
2.2 实现逆傅里叶变换
2.3 高通滤波示例
3. OpenCV 实现傅里叶变换和逆傅里叶变换及低通滤波示例
3.1 OpenCV 实现傅里叶变换
3.2 实现逆傅里叶变换
3.3 低通滤波示例
1、什么是傅里叶变换及其基础理论
1.1 傅里叶变换
图像处理一般分为直接对图像内的像素进行处理的空间域处理和频率域处理。
空间域处理主要划分为灰度变换和空间滤波两种形式。
- 灰度变换是对图像内的单个像素进行处理,比如调节对比度和处理阈值等。
- 空间滤波涉及图像质量的改变,例如图像平滑处理。空间域处理的计算简单方便,运算速度更快。
频率域处理是先将图像变换到频率域,然后在频率域对图像进行处理,最后再通过反变换将图像从频率域变换到空间域。
1.2 基础理论
时间差,在傅里叶变换里就是相位。相位表述的是与时间差相关的信息。
在图像处理过程中,傅里叶变换就是将图像分解为正弦分量和余弦分量两部分,即将图像从空间域转换到频域。
数字图像经过傅里叶变换后,得到的频域值是复数。因此,显示傅里叶变换的结果需要使用实数图像(real image)加虚数图像(complex image),或者幅度图像(magnitude image)加相位图像(phase image)的形式。因为幅度图像包含了原图像中我们所需要的大部分信息,所以在图像处理过程中,通常仅使用幅度图像。
如果希望先在频域内对图像进行处理,再通过逆傅里叶变换得到修改后的空域图像,就必须同时保留幅度图像和相位图像。对图像进行傅里叶变换后,会得到图像中的低频和高频信息。低频信息对应图像内变化缓慢的灰度分量。高频信息对应图像内变化越来越快的灰度分量,是由灰度的尖锐过渡造成的。
傅里叶变换的目的,就是为了将图像从空域转换到频域,并在频域内实现对图像内特定对象的处理,然后再对经过处理的频域图像进行逆傅里叶变换得到空域图像。
2. Numpy 实现傅里叶和逆傅里叶变换
2.1 Numpy 实现傅里叶变换
Numpy 模块中的 fft2( ) 函数可以实现图像的傅里叶变换。
Numpy 提供的实现傅里叶变换的函数是 numpy.fft.fft2( ),它的语法格式是:
返回值 = numpy.fft.fft2(原始图像)
参数“原始图像”的类型就是灰度图像,函数的返回值是一个复数数组(complex ndarray)。经过该函数的处理,就能得到图像的频谱信息。此时,图像频谱中的零频率分量位于频谱图像(频域图像)的左上角。
为了便于观察,通常会使用 numpy.fft.fftshift( ) 函数将零频率成分移动到频域图像的中心位置。
函数 numpy.fft.fftshift( ) 的语法格式是:
返回值=numpy.fft.fftshift(原始频谱)
为了显示图像,需要将它们的值调整到 [0,255] 的灰度空间内,使用的公式为:
像素新值=20*np.log(np.abs(频谱值))
用 Numpy 实现傅里叶变换,观察得到的频谱图像。
import cv2
import numpy as np
import matplotlib.pyplot as pltimg = cv2.imread('./img/hand1.png',0)
f = np.fft.fft2(img)
fshift = np.fft.fftshift(f)
magnitude_spectrum = 20*np.log(np.abs(fshift))
plt.subplot(121)
plt.imshow(img, cmap = 'gray')
plt.title('original')
plt.axis('off')
plt.subplot(122)
plt.imshow(magnitude_spectrum, cmap = 'gray')
plt.title('result')
plt.axis('off')
plt.show()
2.2 实现逆傅里叶变换
注意:如果在傅里叶变换过程中使用了 numpy.fft.fftshift( ) 函数移动零频率分量,那么在逆傅里叶变换过程中,需要先使用 numpy.fft.ifftshift( ) 函数将零频率分量移到原来的位置,再进行逆傅里叶变换。
函数 numpy.fft.ifftshift( ) 是 numpy.fft.fftshift( ) 的逆函数,其语法格式为:
调整后的频谱 = numpy.fft.ifftshift(原始频谱)
numpy.fft.ifft2( ) 函数可以实现逆傅里叶变换,返回空域复数数组。
它是 numpy.fft.fft2( ) 的逆函数,该函数的语法格式为:
返回值=numpy.fft.ifft2(频域数据)
函数 numpy.fft.ifft2( ) 的返回值仍旧是一个复数数组(complex ndarray)。
逆傅里叶变换得到的空域信息是一个复数数组,需要将该信息调整至 [0,255] 灰度空间内,使用的公式为:
iimg = np.abs(逆傅里叶变换结果)
在 Numpy 内实现傅里叶变换、逆傅里叶变换,观察逆傅里叶变换的结果图像。
import cv2
import numpy as np
import matplotlib.pyplot as pltimg = cv2.imread('./img/hand1.png',0)
f = np.fft.fft2(img)
fshift = np.fft.fftshift(f)ishift = np.fft.ifftshift(fshift)
iimg = np.fft.ifft2(ishift) iimg = np.abs(iimg) plt.subplot(121), plt.imshow(img, cmap = 'gray')
plt.title('original'), plt.axis('off')
plt.subplot(122), plt.imshow(iimg, cmap = 'gray')
plt.title('iimg'), plt.axis('off')
plt.show()
2.3 高通滤波示例
一副图像内,同时存在着高频信号和低频信号。
低频信号对应图像内变换缓慢的灰度分量。例如,在一副大草原的图像中,低频信号对应着颜色趋于一致的广袤草原。高频信号对应图像内变化越来越快的灰度分量,是由灰度的尖锐过渡造成的。如果在上面的大草原图像中还有一头狮子,那么高频信号就对应着狮子的边缘等信息。
滤波器能够允许一定频率的分量通过或者拒绝其通过,按照其作用方式可以划分为低通滤波器和高通滤波器。
允许低频信号通过的滤波器称为低通滤波器。低通滤波器使高频信号衰减而对低频信号放行,会使图像变模糊。允许高频信号通过的滤波器成为高通滤波器。高通滤波器使低频信号衰减而让高频信号通过,将增强图像中尖锐的细节,但是会导致图像的对比度降低。
傅里叶变换可以将图像的高频信号和低频信号分离。通过对图像的频域处理,可以实现图像增强、图像去噪、边缘检测、特征提取、压缩和加密等操作。
在Numpy内对图像进行傅里叶变换,得到其频域图像。然后,在频域内将低频分量的值处理为0,实现高通滤波。最后,对图像进行逆傅里叶变换,得到恢复的原始图像。
import cv2
import numpy as np
import matplotlib.pyplot as plt img = cv2.imread('./img/hand1.png',0)
f = np.fft.fft2(img)
fshift = np.fft.fftshift(f) rows, cols = img.shape crow, ccol = int(rows/2) , int(cols/2)
fshift[crow-30:crow+30, ccol-30:ccol+30] = 0
ishift = np.fft.ifftshift(fshift) iimg = np.fft.ifft2(ishift)
iimg = np.abs(iimg) plt.subplot(121), plt.imshow(img, cmap = 'gray')
plt.title('original'), plt.axis('off')
plt.subplot(122), plt.imshow(iimg, cmap = 'gray')
plt.title('iimg'), plt.axis('off')
plt.show()
3. OpenCV 实现傅里叶变换和逆傅里叶变换及低通滤波示例
3.1 OpenCV 实现傅里叶变换
OpenCV 提供了函数 cv2.dft() 和 cv2.idft() 来实现傅里叶变换和逆傅里叶变换。
函数 cv2.dft()的语法格式为:
返回结果=cv2.dft(原始图像,转换标识)
在使用函数图像时,需要注意参数的使用规范:
对于参数“原始图像”,要首先使用 np.float32()函数将原始图像转换为 np.float32 格式。“转换标识”的值通常为 “ cv2.DFT_COMPLEX_OUTPUT”,用来输出一个复数陈列。
函数 cv2.dft( ) 返回的结果与使用 Numpy 进行傅里叶变换得到的结果是一致的,但是它返回的值是双通道的,第1个通道是结果的实数部分,第2个通道是结果的虚数部分。
经过函数 cv2.dft( ) 的变换后,得到了原始图像的频谱信息。此时,零频率分量并不在中心位置,为了处理方便需要将其移至中心位置,可以用函数 numpy.fft.fftshift( ) 实现。
例如,如下语句将频谱图像 dft 中的零频率分量移到频谱中心,得到了零频率分量位于中心的频谱图像 dftshift。
dftShift = np.fft.fftshift(dft)
经过上述处理后,频谱图像还只是一个由实部和虚部构成的值。要将其显示出来,还要做进一步的处理才行。
函数 cv2.magnitude( ) 可以计算频谱信息的幅度。该函数的语法格式为:
返回值=cv2.magnitude(参数1,参数2)
参数1:浮点型 x 坐标值,也就是实部。
参数2:浮点型 y 坐标值,也就是虚部,它必须和参数 1 具有相同的size。
函数 cv2.magnitude( ) 的返回值是参数1 和参数 2 的平方和的平方根,公式为:
得到频谱信息的幅度后,通常还要对幅度值做进一步的转换,以便将频谱信息以图像的形式展示出来。简单来说,就是需要将幅度值映射到灰度图像的灰度空间 [0,255] 内,使其以灰度图像的i形式显示出来。
这里使用的公式为:
result = 20*np.log(cv2.magnitude(实部,虚部))
import numpy as np
import cv2 img = cv2.imread('./img/hand1.png',0)
dft = cv2.dft(np.float32(img), flags = cv2.DFT_COMPLEX_OUTPUT)
print(dft) dftShift = np.fft.fftshift(dft)
print(dftShift) result = 20*np.log(cv2.magnitude(dftShift[:, :,0], dftShift[:, :,1])) #两个参数,需要拆分通道
print(result)
用 OpenCV 函数对图像进行傅里叶变换,并展示频谱信息。
import numpy as np
import cv2
import matplotlib.pyplot as pltimg = cv2.imread('./img/hand1.png',0)
dft = cv2.dft(np.float32(img), flags = cv2.DFT_COMPLEX_OUTPUT)
dftShift = np.fft.fftshift(dft)
result = 20*np.log(cv2.magnitude(dftShift[:, :,0], dftShift[:, :,1]))
plt.subplot(121), plt.imshow(img, cmap = 'gray')
plt.title('original'), plt.axis('off')
plt.subplot(122), plt.imshow(result, cmap = 'gray')
plt.title('result'), plt.axis('off')
plt.show()
3.2 实现逆傅里叶变换
在 OpenCV 中,使用函数 cv2.idft( ) 实现逆傅里叶变换,该函数是傅里叶变换函数 cv2.dft( ) 的逆函数。其语法格式为:
返回结果=cv2.idft(原始数据)
对图像进行傅里叶变换后,通常会将零频率分量移至频谱图像的中心位置。如果使用函数numpy.fft.fftshift() 移动了零频率分量,那么在进行逆傅里叶变换前,要使用函数 numpy.fft.ifftshift()将零频率分量恢复到原来位置。
注意:在进行逆傅里叶变换后,得到的值仍旧是复数,需要使用函数cv2.magnitude()计算其幅度。
用OpenCV函数对图像进行傅里叶变换、逆傅里叶变换,并展示原始图像及经过逆傅里叶变换后得到的图像。
import numpy as np
import cv2
import matplotlib.pyplot as pltimg = cv2.imread('./img/hand1.png',0)
dft = cv2.dft(np.float32(img), flags = cv2.DFT_COMPLEX_OUTPUT)
dftShift = np.fft.fftshift(dft)ishift = np.fft.ifftshift(dftShift)
iImg = cv2.idft(ishift)
iImg= cv2.magnitude(iImg[:, :,0], iImg[:, :,1]) # 计算幅度
plt.subplot(121), plt.imshow(img, cmap = 'gray')
plt.title('original'), plt.axis('off')
plt.subplot(122), plt.imshow(iImg, cmap = 'gray')
plt.title('inverse'), plt.axis('off')
plt.show()
3.3 低通滤波示例
在一副图像内,低频信号对应图像内变化缓慢的灰度分量。图像进行低通滤波后会变模糊。
实现的中间步骤:
rows, cols = img.shape
crow, ccol = int(rows/2) , int(cols/2)
mask = np.zeros((rows, cols,2), np.uint8) # 二维的原因,有实部和虚部
mask[crow-30:crow+30, ccol-30:ccol+30,:] = 1
然后,将其与频谱图像进行运算,实现低通滤波。这里采用的运算形式是:
fShift = dftShift*mask
使用函数 cv2.dft()对图像进行傅里叶变换,得到其频谱图像。然后,在频域内将其高频分量的值处理为0,实现低通滤波。最后,对图像进行逆傅里叶变换,得到恢复的原始图像。
import numpy as np
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('./img/hand1.png',0)
dft = cv2.dft(np.float32(img), flags = cv2.DFT_COMPLEX_OUTPUT)
dftShift = np.fft.fftshift(dft)rows, cols = img.shape crow, ccol = int(rows/2) , int(cols/2)
mask = np.zeros((rows, cols,2), np.uint8) #两个通道,与频域图像匹配
mask[crow-30:crow+30, ccol-30:ccol+30,:] = 1
fShift = dftShift*mask ishift = np.fft.ifftshift(fShift)
iImg = cv2.idft(ishift)
iImg= cv2.magnitude(iImg[:, :,0], iImg[:, :,1])plt.subplot(121), plt.imshow(img, cmap = 'gray')
plt.title('original'), plt.axis('off')
plt.subplot(122), plt.imshow(iImg, cmap = 'gray')
plt.title('inverse'), plt.axis('off')
plt.show()
经过低通滤波后,图像的边缘信息被削弱了。
参考资料:新机器视觉