图像处理一般分为空间域处理和频率域处理。 空间域处理是直接对图像内的像素进行处理。空间域处理主要划分为灰度变换和空间滤波两种形式。灰度变换是对图像内的单个像素进行处理,比如调节对比度和处理阈值等。空间滤波涉及图像质量的改变,例如图像平滑处理。空间域处理的计算简单方便,运算速度更快。
关于傅里叶变换的讲解请看这篇文章:
深入浅出的讲解傅里叶变换(真正的通俗易懂)
在图像处理过程中,傅里叶变换就是将图像分解为正弦分量和余弦分量两部分,即将图像 从空间域转换到频率域(以下简称频域)。数字图像经过傅里叶变换后,得到的频域值是复数。 因此,显示傅里叶变换的结果需要使用实数图像(real image)加虚数图像(complex image), 或者幅度图像(magnitude image)加相位图像(phase image)的形式。
因为幅度图像包含了原图像中我们所需要的大部分信息,所以在图像处理过程中,通常仅使用幅度图像。当然,如果希望先在频域内对图像进行处理,再通过逆傅里叶变换得到修改后的空域图像,就必须同时保留幅度图像和相位图像。
对图像进行傅里叶变换后,我们会得到图像中的低频和高频信息。低频信息对应图像内变 化缓慢的灰度分量。高频信息对应图像内变化越来越快的灰度分量,是由灰度的尖锐过渡造成的。例如,在一幅大草原的图像中有一头狮子,低频信息就对应着广袤的颜色趋于一致的草原等细节信息,而高频信息则对应着狮子的轮廓等各种边缘及噪声信息。
傅里叶变换的目的,就是为了将图像从空域转换到频域,并在频域内实现对图像内特定对 象的处理,然后再对经过处理的频域图像进行逆傅里叶变换得到空域图像。傅里叶变换在图像处理领域发挥着非常关键的作用,可以实现图像增强、图像去噪、边缘检测、特征提取、图像压缩和加密等。
OpenCV 提供了函数 cv2.dft()和 cv2.idft()来实现傅里叶变换和逆傅里叶变换,下面分别展 开介绍。
返回结果=cv2.dft(原始图像,转换标识)
经过函数 cv2.dft() 的变换后,我们得到了原始图像的频谱信息。此时,零频率分量并不在中心位置,为了处理方便需要将其移至中心位置,可以用函数 numpy.fft.fftshift() 实现。例如, 如下语句将频谱图像 dft 中的零频率分量移到频谱中心,得到了零频率分量位于中心的频谱图像 dftshift。
dftShift = np.fft.fftshift(dft)
经过上述处理后,频谱图像还只是一个由实部和虚部构成的值。要将其显示出来,还要做进一步的处理才行。
函数 cv2.magnitude()可以计算频谱信息的幅度。该函数的语法格式为:
返回值=cv2.magnitude(参数1,参数2)
函数 cv2.magnitude()的返回值是参数 1 和参数 2 的平方和的平方根,公式为:
式中, I 表示原始图像,dst 表示目标图像。
得到频谱信息的幅度后,通常还要对幅度值做进一步的转换,以便将频谱信息以图像的形式展示出来。
简单来说,就是需要将幅度值映射到灰度图像的灰度空间[0, 255]内,使其以灰度图像的形式显示出来。 这里使用的公式为:
result = 20*np.log(cv2.magnitude(实部,虚部))
下面对一幅图像进行傅里叶变换,帮助读者观察上述处理过程。如下代码针对图像“lena” 进行傅里叶变换,并且计算了幅度值,对幅度值进行了规范化处理:
import numpy as np
import cv2
img = cv2.imread('image\\lena.bmp',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 plt
img = cv2.imread('image\\lena.bmp',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()
在 OpenCV 中,使用函数 cv2.idft() 实现逆傅里叶变换,该函数是傅里叶变换函数 cv2.dft() 的逆函数。其语法格式为:
返回结果=cv2.idft(原始数据)
对图像进行傅里叶变换后,通常会将零频率分量移至频谱图像的中心位置。如果使用函数 numpy.fft.fftshift() 移动了零频率分量,那么在进行逆傅里叶变换前,要使用函数 numpy.fft.ifftshift() 将零频率分量恢复到原来位置。
还要注意,在进行逆傅里叶变换后,得到的值仍旧是复数,需要使用函数 cv2.magnitude() 计算其幅度。
import numpy as np
import cv2 import matplotlib.pyplot as plt
img = cv2.imread('image\\lena.bmp',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()
在一幅图像内,同时存在着高频信号和低频信号。
滤波器能够允许一定频率的分量通过或者拒绝其通过,按照其作用方式可以划分为低通滤波器和高通滤波器。
在实现低通滤波时,可以专门构造一个如图 14-18 中左图所示的图像,用它与原图的傅里叶变换频谱图像进行与运算,就能将频谱图像中的高频信号过滤掉。
import numpy as np
import cv2 import matplotlib.pyplot as plt
img = cv2.imread('image\\lena.bmp',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()
允许高频信号通过的滤波器称为高通滤波器。高通滤波器使低频信号衰减而让高频信号 通过,将增强图像中尖锐的细节,但是会导致图像的对比度降低。
import cv2
import numpy as np import matplotlib.pyplot as plt
img = cv2.imread('image\\boat.bmp',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()