1. 理论基础
图像处理一般分为空间域处理和频率域处理。
空间域处理是直接对图像内的像素进行处理。空间域处理主要划分为灰度变换和空间滤波两种形式。灰度变换是对图像内的单个像素进行处理,比如调节对比度和处理阈值等;空间滤波涉及图像质量的改变,例如图像平滑、图像锐化等。空间域处理的计算简单方便,运算速度更快。
频率域处理是先将图像变换到频率域,然后在频率域对图像进行处理,最后再通过反变换将图像从频率域变换到空间域。 傅里叶变换 是应用最广泛的一种频域变换,它能够将图像从空间域变换到频率域,而 逆傅里叶变换 能够将频率域信息变换到空间域内。
在图像处理过程中,傅里叶变换就是将图像分解为正弦分量和余弦分量两部分,数字图像经过傅里叶变换后,得到的频域值是复数。显示傅里叶变换的结果需要使用实数图像加虚数图像的形式,或者幅度图像加相位图像的形式。因为幅度图像包含了原图像中我们所需要的大部分信息,所以在图像处理过程中, 通常仅使用幅度图像。 如果需要通过逆傅里叶变换恢复到原有的空域图像,就必须同时保留幅度图像和相位图像。
对图像进行傅里叶变换后,我们会得到图像中的 低频信息 和 高频信息 。低频信息对应图像内变化缓慢的灰度分量,高频信息对应图像内变化越来越快的灰度分量。
傅里叶变换在图像处理领域发挥着非常关键的作用,可以实现图像增强、图像去噪、边缘检测、特征提取、图像压缩和加密等。
2. Numpy实现傅里叶变换
2.1 傅里叶变换
numpy.fft.fft2()
- 通过函数
numpy.fft.fft2(),实现傅里叶变换。 - 函数原型:
complex_ndarray = numpy.fft.fft2( gray_img ) - 参数说明:
- complex_ndarray:表示复数数组。
- gray_img:表示灰度图像。
numpy.fft.fftshift()
- 通过函数
numpy.fft.fftshift(),实现傅里叶变换的频谱移动。 - 函数原型:
spectrum_shift = numpy.fft.fftshift( spectrum ) - 参数说明:
- spectrum_shift :表示转变后的频谱。
- spectrum:表示原始频谱。
注意 对图像进行傅里叶变换后,得到的是一个复数数组。为了显示方便,需要将它们的值调整到[0, 255]的灰度空间内。可以使用
20 * np.log(np.abs(频谱值))进行。
2.2 逆傅里叶变换
numpy.fft.ifft2()
-
通过函数
numpy.fft.ifft2(),实现逆傅里叶变换。 -
函数原型:
complex_ndarray_output = numpy.fft.fft2( complex_ndarray_input ) -
参数说明:
- complex_ndarray_output:表示复数数组。
- complex_ndarray_input:表示灰度图像。
-
图像获取:逆傅里叶变换得到的空域信息是一个复数数组,可以通过
img = np.abs(spectrum)将该信息调整至[0, 255]灰度空间内。
numpy.fft.ifftshift()
- 通过函数
numpy.fft.ifftshift(),实现傅里叶变换的频谱移动,和函数numpy.fft.fftshift()的操作过程相反。 - 函数原型:
spectrum_shift = numpy.fft.ifftshift( spectrum ) - 参数说明:
- spectrum_shift :表示转变后的频谱。
- spectrum:表示原始频谱。
注意 如果在傅里叶变换过程中使用了
numpy.fft.fftshift()函数移动零频率分量,那么在逆傅里叶变换过程中,需要先使用numpy.fft.ifftshift()函数将零频率分量移到原来的位置,再进行逆傅里叶变换。
2.3 示例
import cv2import numpy as npimport matplotlib.pyplot as plt
img = cv2.imread("person.jpg", 0)
# FFTspectrum = np.fft.fft2(img)spectrum_shift = np.fft.fftshift(spectrum)
spectrum_show = 20 * np.log(np.abs(spectrum_shift))
# iFFTspectrum_ishift = np.fft.ifftshift(spectrum_shift)spectrum_img = np.fft.ifft2(spectrum_ishift)
fft_img = np.abs(spectrum_img)
plt.subplot(131)plt.title('img')plt.imshow(img, cmap='gray')plt.axis('off')
plt.subplot(132)plt.imshow(spectrum_show, cmap='gray')plt.title('result')plt.axis('off')
plt.subplot(133)plt.imshow(fft_img, cmap='gray')plt.title('fft_img')plt.axis('off')
plt.show()
2.4 应用
高通滤波器:边缘提取
- 允许高频信号通过的滤波器称为高通滤波器。
import cv2import numpy as npimport matplotlib.pyplot as plt
img = cv2.imread("person.jpg", 0)center_row, center_col = int(img.shape[0]/2), int(img.shape[1]/2)delta = 45
# FFTf = np.fft.fft2(img)f_shift = np.fft.fftshift(f)fft = 20 * np.log(np.abs(f_shift))f_shift[(center_row-delta):(center_row+delta), (center_col-delta):(center_col+delta)] = 1fft_filter = 20 * np.log(np.abs(f_shift))
# iFFTf_ishift = np.fft.ifftshift(f_shift)ifft_img = np.fft.ifft2(f_ishift)
ifft_img = np.abs(ifft_img)
plt.subplot(221), plt.title('img'), plt.axis('off')plt.imshow(img, cmap='gray')
plt.subplot(222), plt.title('ifft_img'), plt.axis('off')plt.imshow(ifft_img, cmap='gray')
plt.subplot(223), plt.title('fft'), plt.axis('off')plt.imshow(fft, cmap='gray')
plt.subplot(224), plt.title('fft_filter'), plt.axis('off')plt.imshow(fft_filter, cmap='gray')
plt.show()
低通滤波器:图像模糊
- 允许低频信号通过的滤波器称为低通滤波器。
import cv2import numpy as npimport matplotlib.pyplot as plt
img = cv2.imread("person.jpg", 0)row, col = img.shapecenter_row, center_col = int(row/2), int(col/2)delta = 100
# FFTf = np.fft.fft2(img)f_shift = np.fft.fftshift(f)fft = 20 * np.log(np.abs(f_shift))
mask = np.zeros((row, col),np.uint8)mask[(center_row-delta):(center_row+delta), (center_col-delta):(center_col+delta)] = 1f_shift = f_shift * maskf_shift[f_shift==0] = 1fft_filter = 20 * np.log(np.abs(f_shift))
# iFFTf_ishift = np.fft.ifftshift(f_shift)ifft_img = np.fft.ifft2(f_ishift)
ifft_img = np.abs(ifft_img)
plt.subplot(221), plt.title('img'), plt.axis('off')plt.imshow(img, cmap='gray')
plt.subplot(222), plt.title('ifft_img'), plt.axis('off')plt.imshow(ifft_img, cmap='gray')
plt.subplot(223), plt.title('fft'), plt.axis('off')plt.imshow(fft, cmap='gray')
plt.subplot(224), plt.title('fft_filter'), plt.axis('off')plt.imshow(fft_filter, cmap='gray')
plt.show()
3. OpenCV实现傅里叶变换
3.1 傅里叶变换
cv2.dft()
- 通过函数
cv2.dft(),实现傅里叶变换。 - 函数原型:
输出数组 = cv2.dft( 原始图像, 转换标识 ) - 参数说明:
- 输出数组:格式为复数数组。
- 返回的值是双通道的。第1个通道是实数部分,第2个通道是虚数部分。
- 原始图像:首先使用
np.float32()函数将图像转换成np.float32格式。 - 转换标识:通常为cv2.DFT_COMPLEX_OUTPUT,用来输出一个复数数组。
- 输出数组:格式为复数数组。
cv2.magnitude()
- 通过函数
cv2.magnitude(),计算频谱信息的幅度。 - 函数原型:
返回值 = cv2.magnitude(参数 1,参数 2) - 参数说明:
- 参数1:浮点型的x坐标值,也就是实部。
- 参数2:浮点型的y坐标值,也就是虚部。
- 返回值:参数1和参数2平方和的平方根,即
注意 对图像进行傅里叶变换后,得到的是一个复数数组。为了显示方便,需要将它们的值调整到[0, 255]的灰度空间内。可以使用
20 * np.log(幅度值)进行
3.2 逆傅里叶变换
cv2.idft()
- 通过函数
cv2.idft(),实现逆傅里叶变换。 - 函数原型:
返回图像 = cv2.idft( 复数数组 ) - 图像获取:逆傅里叶变换得到的空域信息是一个复数数组,可以通过
img = np.abs(spectrum)将该信息调整至[0, 255]灰度空间内。
注意 如果在傅里叶变换过程中使用了
numpy.fft.fftshift()函数移动零频率分量,那么在逆傅里叶变换过程中,需要先使用numpy.fft.ifftshift()函数将零频率分量移到原来的位置,再进行逆傅里叶变换。
3.3 示例
import cv2import numpy as npimport matplotlib.pyplot as plt
img = cv2.imread("person.jpg", 0)
# DFTspectrum = cv2.dft(np.float32(img), flags=cv2.DFT_COMPLEX_OUTPUT)spectrum_shift = np.fft.fftshift(spectrum)
spectrum_magnitude = cv2.magnitude(spectrum_shift[:,:,0], spectrum_shift[:,:,1])spectrum_show = 20 * np.log(spectrum_magnitude)
# iDFTspectrum_ishift = np.fft.ifftshift(spectrum_shift)spectrum_img = cv2.idft(spectrum_ishift)
dft_img = cv2.magnitude(spectrum_img[:,:,0], spectrum_img[:,:,1])
plt.subplot(131)plt.title('img')plt.imshow(img, cmap='gray')plt.axis('off')
plt.subplot(132)plt.imshow(spectrum_show, cmap='gray')plt.title('result')plt.axis('off')
plt.subplot(133)plt.imshow(dft_img, cmap='gray')plt.title('dft_img')plt.axis('off')
plt.show()
3.4 应用
高通滤波器:边缘提取
- 允许高频信号通过的滤波器称为高通滤波器。
import cv2import numpy as npimport matplotlib.pyplot as plt
img = cv2.imread("person.jpg", 0)center_row, center_col = int(img.shape[0]/2), int(img.shape[1]/2)delta = 45
# DFTf = cv2.dft(np.float32(img), flags=cv2.DFT_COMPLEX_OUTPUT)f_shift = np.fft.fftshift(f)fft = 20 * np.log(cv2.magnitude(f_shift[:,:,0], f_shift[:,:,1]))
f_shift[(center_row-delta):(center_row+delta), (center_col-delta):(center_col+delta)] = 1fft_filter = 20 * np.log(cv2.magnitude(f_shift[:,:,0], f_shift[:,:,1]))
# iDFTf_ishift = np.fft.ifftshift(f_shift)ifft_img = cv2.idft(f_ishift)
ifft_img = cv2.magnitude(ifft_img[:,:,0], ifft_img[:,:,1])
plt.subplot(221), plt.title('img'), plt.axis('off')plt.imshow(img, cmap='gray')
plt.subplot(222), plt.title('idft_img'), plt.axis('off')plt.imshow(ifft_img, cmap='gray')
plt.subplot(223), plt.title('dft'), plt.axis('off')plt.imshow(fft, cmap='gray')
plt.subplot(224), plt.title('dft_filter'), plt.axis('off')plt.imshow(fft_filter, cmap='gray')
plt.show()
低通滤波器:图像模糊
- 允许低频信号通过的滤波器称为低通滤波器。
import cv2import numpy as npimport matplotlib.pyplot as plt
img = cv2.imread("person.jpg", 0)row, col = img.shapecenter_row, center_col = int(row/2), int(col/2)delta = 100
# DFTf = cv2.dft(np.float32(img), flags=cv2.DFT_COMPLEX_OUTPUT)f_shift = np.fft.fftshift(f)fft = 20 * np.log(cv2.magnitude(f_shift[:,:,0], f_shift[:,:,1]))
mask = np.zeros((row, col, 2),np.uint8)mask[(center_row-delta):(center_row+delta), (center_col-delta):(center_col+delta)] = 1f_shift = f_shift * maskf_shift[f_shift==0] = 1fft_filter = 20 * np.log(cv2.magnitude(f_shift[:,:,0], f_shift[:,:,1]))
# iDFTf_ishift = np.fft.ifftshift(f_shift)ifft_img = cv2.idft(f_ishift)
ifft_img = cv2.magnitude(ifft_img[:,:,0], ifft_img[:,:,1])
plt.subplot(221), plt.title('img'), plt.axis('off')plt.imshow(img, cmap='gray')
plt.subplot(222), plt.title('idft_img'), plt.axis('off')plt.imshow(ifft_img, cmap='gray')
plt.subplot(223), plt.title('dft'), plt.axis('off')plt.imshow(fft, cmap='gray')
plt.subplot(224), plt.title('dft_filter'), plt.axis('off')plt.imshow(fft_filter, cmap='gray')
plt.show()