傅里叶变换简介
傅里叶变换(Fourier Transform,简称FT)的作用
GitHub - LeBron-Jian/ComputerVisionPractice
对于数字图像这种离散的信号,频率大小表示信号变换的剧烈程度或者说信号变化的快慢。频率越大,变换越剧烈,频率越小,信号越平缓,对应到的图像中,高频信号往往是图像中的边缘信号和噪声信号,而低频信号包含图像变化频繁的图像轮廓及背景灯信号。
“任何连续周期信号都可以表示成(或者无限逼近)一系列正弦信号的叠加”
需要说明的是:傅里叶变换得到的频谱图上的点与原图像上的点之间不存在一一对应的关系。
图片的高频与低频分量 初识 与 相关博客_m0_61899108的博客-CSDN博客
- 低频:对应图像中物体的亮度均匀或变化缓慢的区域,变化较缓慢的灰度分量;
- 高频:对应图像中物体的边缘、细节、噪声,变化较快的灰度分量。
![](https://i-blog.csdnimg.cn/blog_migrate/8d9d866dc3e8dc22ffd957818e3797f1.png)
滤波器
- 接受(通过)或拒绝一定频率的分量,就称为为滤波。
- 低通滤波器:只保留低频,会使得图像模糊。
- 高频滤波器:只保留高频,会使得图像细节增强。
如何使用傅里叶变换得到的频谱图?
- 傅里叶变换变换可以得到高频与低频,针对高频与低频处理,可以实现不同的目的;
- 傅里叶变换是可逆的,通过逆傅里叶变换,可以恢复原图像;
- 如果对高频与低频进行处理,再进行逆傅里叶变换,所做的处理会反映到逆变换图像上。
频域滤波
怎么在频域的基础上,对图像进行处理呢?
- 对图像进行傅里叶变换,修改频谱图像,然后逆傅里叶变换返回到图像域。
- 特殊目的:图像增强、图像去噪、边缘检测、特征提取、压缩、加密等等。
- 衰减高频而通过低频,低通滤波器,将模糊一幅图像。
- 衰减低频而通过高频,高通滤波器,将增强尖锐的边缘,但是会导致图像的对比度下降(丢失了低频细节信息)。
- 图像去噪:利用低通滤波器去除高频噪声,但会抑制图像的边缘、细节信息,变得模糊。(如:均值滤波,高斯滤波)
- 图像增强及锐化:增强图像细节,使图像变得更加清晰,需要增强图像的边缘部分(高频信息),也就是增强图像中灰度变化剧烈的部分。
傅里叶变换实验
代码:GitHub - LeBron-Jian/ComputerVisionPractice
图像处理 | 空间域与频率域滤波_只是曾路过的博客-CSDN博客_空间域滤波和频率域滤波
傅里叶变换的图像性质
- 图像经过二维傅里叶的变换后,其变换稀疏矩阵具有如下性质:若交换矩阵原点设在中心,其频谱能量集中分布在变换稀疏矩阵的中心附近。若所用的二维傅里叶变换矩阵的云巅设在左上角,那么图像信号能量将集中在系数矩阵的四个角上。这是由二维傅里叶变换本身性质决定的。同时也表明一股图像能量集中低频区域。
- 图像灰度变化缓慢的区域,对应它变换后的低频分量部分;图像灰度呈阶跃变化的区域,对应变换后的高频分量部分。除颗粒噪音外,图像细节的边缘,轮廓处都是灰度变换突变区域,他们都具有变换后的高频分量特征。
注意:无论是numpy实现,还是OpenCV实现,得到的结果中频率为0的部分都会在左上角,通常要转换到中心位置,可以通过shift变换来实现。
实验1:numpy实现 傅里叶变换
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread("Lena.jpg", 0)
# 傅里叶变换
f= np.fft.fft2(img) # 实现傅里叶变换 ,f是一个复数数组
fshift = np.fft.fftshift(f) # 将零频率分量移到频谱中央
fft_img = 20 * np.log(np.abs(fshift)) # 设置频谱的范围 [0,255],便于显示
# 组合图像
fig, ax = plt.subplots(1,2) #row = 1, col = 2
ax[0].imshow(img, cmap = "gray")
ax[1].imshow(fft_img, cmap = "gray")
ax[0].axis("off"), ax[1].axis("off")
# 保存或展示
# plt.savefig("result.jpg", dpi = 300, bbox_inches = "tight")
plt.show()
效果展示:
![](https://i-blog.csdnimg.cn/blog_migrate/f27c67e107d70ed150df50337ed22956.png)
实验2:numpy实现 逆傅里叶变换
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread("Lena.jpg", 0)
# 傅里叶变换
f= np.fft.fft2(img) # f是一个复数数组
fshift = np.fft.fftshift(f)
# fft_img = 20 * np.log(np.abs(fshift))
# 逆傅里叶变换
ishift = np.fft.ifftshift(fshift) #ishift是一个复数数组
i_img = np.fft.ifft2(ishift) #逆傅里叶变换,得到仍然是一个复数数组,不要以为直接得到图像的像素值.
i_img = np.abs(i_img)
# 组合
fig, ax = plt.subplots(1,2) #row = 1, col = 2
ax[0].imshow(img, cmap = "gray")
ax[1].imshow(i_img, cmap = "gray")
ax[0].set_title("original"), ax[1].set_title("i_img")
ax[0].axis("off"), ax[1].axis("off")
# 保存或显示
# plt.savefig("result.jpg", dpi = 300, bbox_inches = "tight")
plt.show()
效果展示:
![](https://i-blog.csdnimg.cn/blog_migrate/59089ac10edc2b3f540c569879abc3fe.png)
实验3:opencv实现 傅里叶变换
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread("Lena.jpg", 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])) # 计算幅值,参数1为实部,参数2为虚部。 幅值范围[0,255]
# 组合
fig, ax = plt.subplots(1,2) #row = 1, col = 2
ax[0].imshow(img, cmap = "gray")
ax[1].imshow(result, cmap = "gray")
ax[0].set_title("original"), ax[1].set_title("result")
ax[0].axis("off"), ax[1].axis("off")
# 保存或显示
# plt.savefig("result.jpg", dpi = 300, bbox_inches = "tight")
plt.show()
效果展示:
![](https://i-blog.csdnimg.cn/blog_migrate/7e87262302fe6b573975aece7fbe2b6a.png)
实验4:opencv实现 逆傅里叶变换
import cv2
import numpy as np
import matplot.pyplot as plt
img = cv2.imread("Lena.jpg", 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]))
# 逆傅里叶变换
idftshift = np.fft.ifftshift(dftshift) # fftshift的逆函数
idft = cv2.idft(idftshift) # idft:二维复数数组,取决于原始数据的类型和大小
i_img = cv2.magnitude(idft[:, :, 0], idft[:,:, 1]) # 转换到[0, 255]
# 组合
fig, ax = plt.subplots(1,2) # row = 1, col = 2
ax[0].imshow(img, cmap = "gray")
ax[1].imshow(i_img, cmap = "gray")
ax[0].set_title("original"), ax[1].set_title("i_img")
ax[0].axis("off"), ax[1].axis("off")
# 保存或显示
# plt.savefig("result.jpg", dpi = 300, bbox_inches = "tight")
plt.show()
效果展示:
![](https://i-blog.csdnimg.cn/blog_migrate/6516b999bca8d7ed52e032bcc80f4a99.png)
实验5:numpy实现 高通滤波
高通滤波器:去掉低频,保留高频。
频谱图像中,中间较亮的部分是低频信息(像素值比较大),可以通过设置低频部分的像素值来减弱低频,如图:
![](https://i-blog.csdnimg.cn/blog_migrate/38d4d19b0596d91c9bf6866207d520ce.png)
![](https://i-blog.csdnimg.cn/blog_migrate/20ceeefd9b70d7604fcec0b44182a331.png)
代码:
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread("Lena.jpg", 0)
# print(img)
# 傅里叶变换
f= np.fft.fft2(img)
fshift = np.fft.fftshift(f)
# fft_img = 20 * np.log(np.abs(fshift))
# 高通滤波器,去掉低频
rows, cols = img.shape
crows, ccols =int(rows/2), int(cols/2)
fshift[crows-30:crows+30, ccols-30:ccols+30] = 0
# 逆傅里叶变换
ishift = np.fft.ifftshift(fshift)
i_img = np.fft.ifft2(ishift)
i_img = np.abs(i_img)
# 组合
fig, ax = plt.subplots(1,2) #row = 1, col = 2
ax[0].imshow(img, cmap = "gray")
ax[1].imshow(i_img, cmap = "gray")
ax[0].set_title("original"), ax[1].set_title("i_img")
ax[0].axis("off"), ax[1].axis("off")
# 保存或显示
# plt.savefig("result.jpg", dpi = 300, bbox_inches = "tight")
plt.show()
效果展示:
![](https://i-blog.csdnimg.cn/blog_migrate/575f2c3ac2a9f697814a4eb1ae20fdf8.png)
实验6:opencv实现 低通滤波
低通滤波器:去掉高频,保留低频。
![](https://i-blog.csdnimg.cn/blog_migrate/d2f4e654450f1bb51f348fd4792160ff.png)
代码:
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread("Lena.jpg", 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]))
# 低通滤波
# creat a mask of LPF(Low Pass Filter)
cows, cols = img.shape
mask = np.zeros((cows, cols, 2), np.uint8)
mask[int(cows/2-30):int(cows/2+30), int(cols/2-30):int(cols/2+30)] = 1
idftshift = dftshift * mask
# 逆傅里叶变换
idftshift = np.fft.ifftshift(idftshift)
idft = cv2.idft(idftshift)
i_img = cv2.magnitude(idft[:, :, 0], idft[:,:, 1])
# 组合
fig, ax = plt.subplots(1,2) #row = 1, col = 2
ax[0].imshow(img, cmap = "gray")
ax[1].imshow(i_img, cmap = "gray")
ax[0].set_title("original"), ax[1].set_title("i_img")
ax[0].axis("off"), ax[1].axis("off")
# 保存或显示
# plt.savefig("result.jpg", dpi = 300, bbox_inches = "tight")
plt.show()
效果展示:
![](https://i-blog.csdnimg.cn/blog_migrate/c7baa714c2084301f0e060f09e435f1c.png)
numpy函数
注意:无论是numpy实现,还是OpenCV实现,得到的结果中频率为0的部分都会在左上角,通常要转换到中心位置,可以通过shift变换来实现。
numpy实现傅里叶变换
Numpy的 FFT 包提供了函数 np.fft.fft2() 可以对信号进行快速傅里叶变换,其函数原型如下所示(该函数的输出结果是一个复数数组complex ndarray)
1 |
|
参数意义:
- a表示输入图像,阵列状的复杂数组
- s表示整数序列,可以决定输出数组的大小。输出可选形状(每个转换轴的长度),其中s[0]表示轴0,s[1]表示轴1。对应fit(x,n)函数中的n,沿着每个轴,如果给定的形状小于输入形状,则将剪切输入。如果大于则输入将用零填充。如果未给定’s’,则使用沿’axles’指定的轴的输入形状
- axes表示整数序列,用于计算FFT的可选轴。如果未给出,则使用最后两个轴。“axes”中的重复索引表示对该轴执行多次转换,一个元素序列意味着执行一维FFT
- norm包括None和ortho两个选项,规范化模式(请参见numpy.fft)。默认值为无。
Numpy中fft模块有很多函数,相关函数如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
Numpy实现傅里叶逆变换
Numpy实现傅里叶逆变换,它是傅里叶变换的逆操作,将频谱图像转换为原始图像的过程。通过傅里叶变换将转换为频谱图,并对高频(边界)和低频(细节)部分进行处理,接着需要通过傅里叶逆变换恢复为原始效果图。频域上对图像的处理会反映在逆变换图像上,从而更好地进行图像处理。
图像傅里叶变换主要使用的函数如下所示:
1 2 3 4 5 6 7 8 |
|
opencv函数
OpenCV实现傅里叶变换
OpenCV中实现傅里叶变换的函数是 cv2.dft(),他和Numpy输出的结果是一样的,但是是双通道的。第一个通道是结果的实数部分,第二个通道是结果的虚数部分,并且输入图像要首先转换成 np.float32格式。其函数原型如下:
1 |
|
参数含义:
- src表示输入图像,需要通过np.float32转换格式
- dst表示输出图像,包括输出大小和尺寸flags表示转换标记,其中:
DFT _INVERSE执行反向一维或二维转换,而不是默认的正向转换;
DFT _SCALE表示缩放结果,由阵列元素的数量除以它;
DFT _ROWS执行正向或反向变换输入矩阵的每个单独的行,该标志可以同时转换多个矢量,并可用于减少开销以执行3D和更高维度的转换等;
DFT _COMPLEX_OUTPUT执行1D或2D实数组的正向转换,这是最快的选择,默认功能;
DFT _REAL_OUTPUT执行一维或二维复数阵列的逆变换,结果通常是相同大小的复数数组,但如果输入数组具有共轭复数对称性,则输出为真实数组
- nonzeroRows表示当参数不为零时,函数假定只有nonzeroRows输入数组的第一行(未设置)或者只有输出数组的第一个(设置)包含非零,因此函数可以处理其余的行更有效率,并节省一些时间;这种技术对计算阵列互相关或使用DFT卷积非常有用
注意:由于输出的频谱结果是一个复数,需要调用 cv2.magnitude() 函数将傅里叶变换的双通达结果转换为0到255的范围。其函数原型如下:
1 |
|
参数意义:
- x表示浮点型X坐标值,即实部
- y表示浮点型Y坐标值,即虚部
最终输出结果为幅值,即:
OpenCV实现傅里叶逆变换
OpenCV中,通过函数 cv2.idft()函数实现傅里叶逆变换,其返回结果取决于原始图像的类型和大小,原始图像可以为复数或实数,同时也要注意输入图像需要先转换成 np.float32格式,其函数原型如下:
1 |
|
参数意义:
- src表示输入图像,包括实数或复数
- dst表示输出图像
- flags表示转换标记
- nonzeroRows表示要处理的dst行数,其余行的内容未定义(请参阅dft描述中的卷积示例)
参考博客
OpenCV计算机视觉学习(10)——图像变换(傅里叶变换,高通滤波,低通滤波) - 战争热诚 - 博客园 (cnblogs.com)
高斯模糊的原理是什么,怎样在界面中实现? - 知乎 (zhihu.com)
附:
二维傅里叶变换的定义
用 FFT 计算二维离散傅里叶变换
图像傅里叶变换的物理意义
图像的频率是表征图像中灰度变换剧烈程度的指标,是灰度在平面空间上的梯度。如:大面积的沙漠在图像中是一片灰度变化缓慢的区域,对应的频率值很低;而对于地表属性变换剧烈的边缘区域在图像中是一片灰度变化剧烈的区域,对应的频率值较高。傅里叶变换在实际中有明显的物理意义,设f 是一个能量有限的模拟信号,则其傅里叶变换就表示 f 的频谱。从纯粹的数学意义上看,傅里叶变换是将一个函数转换为一系列周期函数来处理的。从物理效果来看,傅里叶变换是将图像从空间域转换到频率域,其逆变换是将图像从频率域转换到空间域。换句话说,傅里叶变换的物理意义是将图像的灰度分布函数变换为图像的频率分布函数。
傅里叶逆变换是将图像的频率分布函数变换为灰度分布函数傅里叶变换以前,图像(未压缩的位图)是由对在连续空间(现实空间)上的采样得到一系列的集合,通常用一个二维矩阵表示空间上各点,记为 z=f(x, y)。又因为空间是三维的,图像是二维的,因此空间中物体在另一个维度上的关系就必须由梯度来表示,这样我们才能通过观察图像得知物体在三维空间中的对应关系。
傅里叶频谱图上我们看到的明暗不一的亮点,其意义是指图像上某一点与领域点差异的强弱,即梯度的大小。也即该点的频率的大小(可以这么理解,图像中低频部分指低梯度的点,高频部分相反)。一般来说,梯度大则该点的亮度强,否则该点的亮度弱。这样通过观察傅里叶变换后的频谱图,也叫功率图,我们就可以直观的看出图像的能量分布:如果频谱图中暗的点数更多,那么实际图像是比较柔和的(因为各点与领域差异都不大,梯度相对较小);反之,如果频谱图中亮的点数多,那么实际图像一定是尖锐的,边界分明且边界两边像素差异较大的。
对频谱移频到原点以后,可以看出图像的频率分布是以原点为圆心,对称分布的。将频谱移频到圆心除了可以清晰的看出图像频率分布以外,还有一个好处,它可以分离出周期性规律的干扰信号,比如正弦干扰。一幅频谱图如果带有正弦干扰,移频到原点上就可以看出,除了中心以外还存在以另一点为中心,对称分布的亮点集合,这个集合就是干扰噪音产生的。这时可以很直观的通过在该位置放置带阻滤波器消除干扰。
二维傅里叶变换的性质
此外,与连续二维傅里叶变换一样,二维离散傅里叶变换也具有周期性,共轭对称性,线性,旋转性,相关定理,卷积定理,比例性等性质。这些性质在分析以及处理图像时有重要意义。