如何使用OpenCV Python找到图像的傅里叶变换?
傅里叶变换(Fourier Transform)是处理频率域信息的有力工具,可以在图像处理、信号处理和音频处理中找到很多应用。在本篇文章中,我们将介绍如何使用OpenCV Python对图像执行傅里叶变换的过程。
图像的傅里叶变换
在开始之前,我们需要先了解一下什么是傅里叶变换。
傅里叶变换是将一个函数(可以是时间域函数、空间域函数等)变换到频域的过程,它可以将图像从空间域(每个像素在x、y坐标上的位置)转换为频域(每个频率上的信号的强度)。在图片的情况下,每个像素的亮度都会在傅里叶变换中用一个频率分量表示。
以下是一幅灰度图像和它的傅里叶变换:
注:图片中间是直流分量(DC),左上角到右下角是高频分量(注意黑色和白色,用黑色表示低频,用白色表示高频),右上角到左下角也是高频分量
下面是一个简单的Python代码示例,它使用OpenCV的dft方法对图像执行傅里叶变换:
import cv2
import numpy as np
# 读入一幅灰度图像
img = cv2.imread('image.png', 0)
# 执行傅里叶变换
f = np.fft.fft2(img)
fshift = np.fft.fftshift(f)
magnitude_spectrum = 20*np.log(np.abs(fshift))
# 显示图像和傅里叶变换结果
cv2.imshow('input image', img)
cv2.imshow('magnitude spectrum', magnitude_spectrum)
cv2.waitKey(0)
cv2.destroyAllWindows()
在这个例子中,我们首先读入一幅灰度图像,并对其执行傅里叶变换。使用 np.fft.fft2()
函数可以完成这个过程,并将它赋值给一个名为f
的二维数组。接下来,我们使用np.fft.fftshift()
函数将傅里叶变换的结果转移到图像中心,并将其赋值给一个名为fshift
的新数组。最后,我们计算幅度谱,并将结果保存在一个名为magnitude_spectrum的数组中。你可以看到,在代码中,我们使用 20*np.log(np.abs(fshift))
来计算幅度谱。
逆傅里叶变换
在处理完图像的傅里叶变换后,你可能想要再将其转换回空间域。这可以通过使用逆傅里叶变换实现,OpenCV也提供了逆傅里叶变换的方法 np.fft.ifft2()
。下面是一个示例代码:
import cv2
import numpy as np
# 读入一幅灰度图像
img = cv2.imread('image.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)
# 显示原图像和逆变换结果
cv2.imshow('input image', img)
cv2.imshow('reconstructed image', iimg)
cv2.waitKey(0)
cv2.destroyAllWindows()
在这个例子中,我们使用np.fft.ifft2()
函数执行逆傅里叶变换,并将结果保存在一个名为iimg
的新数组中。你可以看到,在代码中,我们使用np.abs()
函数以获取结果的幅值。
傅里叶变换的应用
傅里叶变换的应用相当广泛,下面是一些示例:
图像去噪
傅里叶变换可以用于图像去噪。以下是一个简单的示例代码:
import cv2
import numpy as np
# 读入一幅灰度图像
img = cv2.imread('image.png', 0)
# 添加高斯噪声
mean = 0
sigma = 30
gauss = np.random.normal(mean, sigma, img.shape)
gauss = gauss.reshape(img.shape[0], img.shape[1])
noisy = img + gauss
# 执行傅里叶变换
f = np.fft.fft2(noisy)
fshift = np.fft.fftshift(f)
# 设置低通滤波器,过滤掉高频分量
rows, cols = noisy.shape
crow, ccol = rows // 2, 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)
# 显示原图像和去噪结果
cv2.imshow('noisy image', noisy)
cv2.imshow('denoised image', iimg)
cv2.waitKey(0)
cv2.destroyAllWindows()
在这个示例中,我们首先读入一幅灰度图像,并添加高斯噪声。使用 np.random.normal()
函数可以实现添加随机高斯噪声的过程。接下来,我们对图像执行傅里叶变换并进行频域操作。最后,我们使用逆傅里叶变换将结果转换回空间域并得到去噪后的图像。您可以在代码中看到,我们使用 fshift[crow-30:crow+30,ccol-30:ccol+30]=0
将高频分量过滤掉,这可以帮助我们在去除噪声的同时保留图像的清晰度。
边缘检测
傅里叶变换可以用于图像边缘检测。以下是一个简单的示例代码:
import cv2
import numpy as np
from matplotlib import pyplot as plt
# 读入一幅灰度图像
img = cv2.imread('image.png', 0)
# 执行傅里叶变换
f = np.fft.fft2(img)
fshift = np.fft.fftshift(f)
# 构建高斯拉普拉斯滤波器
rows, cols = img.shape
crow, ccol = rows // 2, cols // 2
D = 30
n = 10
hpf = np.zeros((rows, cols))
for i in range(rows):
for j in range(cols):
hpf[i, j] = 1 - np.exp(-((i - crow) ** 2 + (j - ccol) ** 2) / (2 * D ** 2))
hpf[i, j] = hpf[i, j] * hpf[i, j]
hpf[i, j] = 1 - hpf[i, j]
hpf[i, j] = hpf[i, j] ** n
# 将高斯拉普拉斯滤波器应用于傅里叶变换结果
fshift = fshift * hpf
# 将结果转回空间域
ishift = np.fft.ifftshift(fshift)
iimg = np.fft.ifft2(ishift)
iimg = np.abs(iimg)
# 显示边缘检测结果
plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(iimg, cmap = 'gray')
plt.title('Edges'), plt.xticks([]), plt.yticks([])
plt.show()
这个示例代码与之前的代码有一些类似,但是它有一些不同之处。在这个示例中,我们构建了一个高斯拉普拉斯滤波器,该滤波器可以用于检测图像中的边缘。我们使用 hpf[i,j]=1-np.exp(-((i-crow)**2+(j-ccol)**2)/(2*D**2))
构建了高斯函数,并在这个函数中加入了幂n,以增加滤波器的锐度。我们将这个滤波器应用于傅里叶变换的结果中,然后使用逆傅里叶变换将其转换回空间域。最后,我们使用 plt.imshow()
函数将边缘检测的结果显示出来。您可能想要调整滤波器中的参数以获取更好的边缘检测结果。
前景提取
傅里叶变换可以用于图像分割和前景提取。以下是一个简单的示例代码:
import cv2
import numpy as np
# 读入一幅彩色图像
img = cv2.imread('image.png')
# 转换为灰度图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 执行傅里叶变换
f = np.fft.fft2(gray)
fshift = np.fft.fftshift(f)
# 构建带通滤波器,保留图像中心和四个角的高频分量
rows, cols = img.shape[:2]
crow, ccol = rows // 2, cols // 2
mask = np.zeros_like(gray)
mask[crow - 30:crow + 30, ccol - 30:ccol + 30] = 1
mask[:30, :30] = 1
mask[:30, cols - 30:] = 1
mask[rows - 30:, :30] = 1
mask[rows - 30:, cols - 30:] = 1
# 将带通滤波器应用于傅里叶变换结果
fshift = fshift * mask
# 将结果转回空间域
ishift = np.fft.ifftshift(fshift)
iimg = np.fft.ifft2(ishift)
iimg = np.abs(iimg)
iimg = cv2.normalize(iimg, None, 0, 255, cv2.NORM_MINMAX, cv2.CV_8U)
# 使用二值化将背景变为黑色,前景变为白色
ret, thresh = cv2.threshold(iimg, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# 显示前景提取结果
cv2.imshow('input image', img)
cv2.imshow('foreground', thresh)
cv2.waitKey(0)
cv2.destroyAllWindows()
在这个示例代码中,我们读入了一幅彩色图像,并将其转换为灰度图像。接下来,我们对灰度图像执行傅里叶变换,并使用一个自定义带通滤波器保留了图像中心和四个角的高频分量。我们将过滤器应用于傅里叶变换的结果中,然后使用逆傅里叶变换将其转换回空间域。最后,我们使用二值化将背景变为黑色,前景变为白色,从而得到前景提取的结果。您可以看到,在代码中,我们使用 mask[crow-30:crow+30,ccol-30:ccol+30]=1
创建了一个带通滤波器,并使用 ret,thresh=cv2.threhold(iimg,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
将结果二值化。
结论
在本文中,我们介绍了如何使用OpenCV Python对图像进行傅里叶变换,并演示了傅里叶变换的一些应用,例如图像去噪、边缘检测和前景提取。虽然傅里叶变换在数字图像处理中有广泛的应用,但是理解它的数学原理并不容易。希望本文能够帮助您更好地理解和应用傅里叶变换。