图像处理里的傅里叶变换:原理与代码实现

news/2024/11/27 16:05:15/

在这里插入图片描述

简介:本文围绕傅里叶变换在图像处理中的应用展开。先是以通俗易懂的方式详细阐释了傅里叶变换的核心理论,涵盖为何选用正弦和余弦、空间域到频率域的转换以及幅度图像和相位图像的含义等内容,帮助读者理解其原理。接着通过具体代码示例,分别展示了如何利用 numpy 和 OpenCV 实现傅里叶变换、逆傅里叶变换,以及高通滤波、低通滤波等操作,且均以 pig.JPG 图片为例进行验证,为读者呈现出从理论到实践的完整图像处理应用流程,方便读者学习掌握傅里叶变换在图像处理领域的运用方法。
如果你觉得本文对你有帮助,希望你可以点赞收藏关注,我会持续创作更多OpenCV相关的文章,我们互相学习共同进步。

图像处理里的傅里叶变换:原理与代码实现

  • 核心理论(不是人话,但是我会用很多篇幅详细解释变成人话)
    • 1.1为什么选择正弦和余弦
    • 1.2什么是从空间转化为频率
    • 1.3什么是频率图像和相位图像
  • 2 numpy实现傅里叶变换
  • 3 numpy逆傅里叶变换和高通滤波
  • 4 OpenCV实现傅里叶变换
  • 5 OpenCV实现逆傅里叶变换与低通滤波
  • 致谢

核心理论(不是人话,但是我会用很多篇幅详细解释变成人话)

图像处理过程中,傅里叶变换就是将图像分解成为正弦分量和余弦分量,将图像从空间域转化为频率域,得到复数,所以结果是实数图像+虚数图像 或者 幅度图像+相位图像(听不懂无所谓,我第一次听的时候也觉得这不是人话,请你往后看,后面都会解释的,不着急)

1.1为什么选择正弦和余弦

数学性质的优势
(1)是周期函数(2) 有规律(3) 可以用公式描述(4)对于图像而言,在求导和积分也更加方便。
正交性的关键作用
(1)在图像处理中,这种正交性使得我们可以把图像分解成不同频率的正弦和余弦分量,并且这些分量之间不会相互影响。这样我们就能清晰地分析每个频率成分对图像的贡献。比如,我们可以很容易地确定图像中的某个细节是由高频的正弦分量还是低频的余弦分量产生的。
构成任意函数的能力

更重要的是,根据傅里叶级数的理论,任何周期函数(在一定条件下)都可以用正弦和余弦函数的无穷级数来表示。这意味着,无论图像的亮度变化多么复杂,从理论上讲,都可以用正弦和余弦分量的组合来精确地描述它。
例如,一幅有复杂纹理的图像,它的亮度分布看起来毫无规律,但通过傅里叶变换分解成正弦和余弦分量后,我们可以找到这些看似混乱的纹理背后的频率规律,从而更好地理解和处理图像。
频率域分析的便利性
用正弦和余弦分量来表示图像可以方便地将图像转换到频率域。在频率域中,我们可以直观地看到图像的频率成分,比如哪些频率的成分比较多,哪些比较少。
就像听音乐一样,我们可以通过傅里叶变换把声音信号分解成不同频率的正弦和余弦分量,从而分析出音乐中的高音、低音等成分。在图像处理中,这种频率域的分析可以帮助我们增强图像的某些频率成分,比如增强高频部分来突出图像的细节,或者减弱低频部分来减少图像的模糊感。

1.2什么是从空间转化为频率

傅里叶变换就像是一个翻译器,它把我们在空间域看到的像素点的位置和亮度信息,翻译成频率域里的频率信息。
当我们对一个图像进行傅里叶变换时,它会分析图像中每个小区域(甚至是每个像素点周围)的亮度变化情况,然后把这种亮度变化的快慢用频率来表示。
比如,对于一个圆形的图像,在边缘部分亮度从有(在圆内)到无(在圆外)变化得比较快,傅里叶变换就会把这部分边缘区域识别为高频部分;而在圆的中心部分,亮度基本不变,就会被识别为低频部分。这样,整个图像就从我们熟悉的空间域(每个像素的位置和亮度)转换到了频率域(图像各个部分的频率高低)。

对于一幅图像,我们可以把它看成是由很多小的亮度变化组成的。这些亮度变化在不同的方向和频率上。傅里叶变换就像是一个超级厉害的分析工具,它能把图像中的这些亮度变化分解成一个个简单的正弦和余弦形式的亮度变化。

比如这张图,画蓝色的部分是山峦,他这个亮度变化比较少,所以可以分解成频率较低的正弦和余弦波,画红色的部分涉及到了山的阴面和阳面光度变化比较大,所以分解成频率较高的正弦和余弦波:
在这里插入图片描述

1.3什么是频率图像和相位图像

幅度图像表示的是复数的大小(幅度)。它就像是在说每个频率成分有多 “强”。如果把傅里叶变换后的结果看作是一群不同频率的小 “精灵” 在起作用,幅度图像就是在告诉我们每个小 “精灵” 的力量大小。
相位图像表示的是复数的相位。相位可以理解为这些频率成分的起始位置或者时间差。还是用小 “精灵” 来举例,相位图像就是在告诉我们每个小 “精灵” 是从什么时候开始工作的,或者它们之间的相对顺序。
幅度图像和相位图像这种表示方式在图像处理中很有用。比如,我们可以通过改变幅度图像来增强或减弱某些频率成分,从而改变图像的对比度或清晰度;通过改变相位图像,可以对图像进行平移、旋转等操作。

2 numpy实现傅里叶变换

复数数组 = numpy.fft.fft2(原始灰度图像)
经过该函数的处理,就能得到图像的频谱信息。此时会使用 numpy.fft.fttshift函数将零频率分量移动到频域图像的中心位置。
对图像进行傅里叶变换以后得到的是一个复数数组,为了显示图像,要把他们的值调整到[0,255]的灰度空间内
new = 20*np.log(np.abs(复数数组))
使用pig.JPG图片来验证傅里叶变换,大家可以复制我的图片然后重命名为pig.JPG到与自己的代码同一个文件夹下:
在这里插入图片描述

import numpy as np
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('pig.JPG',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()

在这里插入图片描述
通过运行代码可以得到右边的频率图,他把低频率的都放在了中心位置,所以我们可以通过将低频率的或者高频率的位置设置为0,再进行逆傅里叶变换,获得图像的边缘信息,因为边缘信息的频率较高。我将在第三个章节讲逆傅里叶变换和高通滤波

3 numpy逆傅里叶变换和高通滤波

(第零步):把已经已经经历过傅里叶变换的图像的中间像素赋值为 0 ,这样就没有低频率分量了。
(第一步):若之前移动过零频率分量,则先要恢复,使用numpy .fft.ifftshift()
(第二步):使用numpy.fft.ifft2()实现逆傅里叶变换
(第三步):将复数数组调整至0,255的灰度空间 np.abs()
我们可以通过代码去实现pig.JPG先傅里叶变换,再高通滤波,再逆傅里叶变换,最终获得轮廓图

import numpy as np
import matplotlib.pyplot as plt
import cv2
img = cv2.imread("pig.JPG",0)
# 傅里叶变换
f = np.fft.fft2(img)
# 将零频率分量移动到频域图像的中心位置。
fshift = np.fft.fftshift(f)
# 已经已经经历过傅里叶变换的图像的中间像素赋值为 0 ,这样就没有低频率分量了
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)
# 将复数数组调整至0,255的灰度空间
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()

在这里插入图片描述

4 OpenCV实现傅里叶变换

cv2.dft语法:
返回结果是双通道第一个是实部第二个是虚部 = cv2.dft(原始图像:必须使用np.float32()转换,转换标识通常为cv2.DFT_COMPLEX_OUTPUT用来输出一个复数阵列)
(第零步)转换成np.float32
(第一步)使用cv2.dft
(第二步)使用numpy.fft.ffshift()将零频率分量移动到中心位置
(第三步)使用cv2.magnitude(实部,虚部)获得频谱信息的幅度
(第四步)转换到灰度空间内[0,255] 20*np.log(幅度)
还是对pig.JPG进行处理

import numpy as np
import cv2
import matplotlib.pyplot as plt
img = cv2.imread("pig.JPG",0)
# 转换为np 32
npimg_32 = np.float32(img)
# 进行傅里叶变换
dft = cv2.dft(npimg_32,flags = cv2.DFT_COMPLEX_OUTPUT)
# 移动到中心值
dftshift = np.fft.fftshift(dft)
# 计算幅度
mag = cv2.magnitude(dftshift[:,:,0],dftshift[:,:,1])
# 转化灰度值
result = 20*np.log(mag)
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()

在这里插入图片描述

5 OpenCV实现逆傅里叶变换与低通滤波

cv2.idft的用法 与cv2.dft的用法一致,所以直接讲步骤
(第零步)构建一个原图shape一致,全部为0,但是中间部分设置为1的mask掩码与傅里叶变化的结果进行乘积完成低通滤波
(第一步)若傅里叶变化的时候移动了零频率分量则要先移动回去np.fft.ifftshift()
(第二步)使用cv2.idft进行逆变换获得复数数组
(第三步)将复数数组用magnitude转换为频率
还是用pig.JPG做案例:

import numpy as np
import cv2
import matplotlib.pyplot as plt
img = cv2.imread("pig.JPG",0)
# 转换为np 32
npimg_32 = np.float32(img)
# 进行傅里叶变换
dft = cv2.dft(npimg_32,flags = cv2.DFT_COMPLEX_OUTPUT)
# 移动到中心值
dftshift = np.fft.fftshift(dft)
# 构建mask并且乘积实现低通滤波
rows,cols = img.shape
center_row,center_col = int(rows/2),int(cols/2)
mask = np.zeros((rows,cols,2),np.uint8)
mask[center_row-30:center_row+30,center_col-30:center_col+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()

在这里插入图片描述

致谢

本文参考了一些博主的文章,博取了他们的长处,也结合了我的一些经验,对他们表达诚挚的感谢,使我对 傅里叶变换 有更深入的了解,也推荐大家去阅读一下他们的文章。纸上学来终觉浅,明知此事要躬行:
OpenCV中的图像变换——傅里叶变换


http://www.ppmy.cn/news/1550388.html

相关文章

POA-CNN-SVM鹈鹕算法优化卷积神经网络结合支持向量机多特征分类预测

分类预测 | Matlab实现POA-CNN-SVM鹈鹕算法优化卷积神经网络结合支持向量机多特征分类预测 目录 分类预测 | Matlab实现POA-CNN-SVM鹈鹕算法优化卷积神经网络结合支持向量机多特征分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现POA-CNN-SVM鹈鹕算法…

Java基础面试题03:简述什么是迭代器(Iterator)?

面试题:简述什么是迭代器(Iterator)? 一、什么是Iterator? 迭代器(Iterator)是一个专门用来遍历集合(如数组、列表等)中的元素的对象。它可以帮助开发者按照一定的规则顺序访问集合中的每一个…

Python绘制太极八卦

文章目录 系列目录写在前面技术需求1. 图形绘制库的支持2. 图形绘制功能3. 参数化设计4. 绘制控制5. 数据处理6. 用户界面 完整代码代码分析1. rset() 函数2. offset() 函数3. taiji() 函数4. bagua() 函数5. 绘制过程6. 技术亮点 写在后面 系列目录 序号直达链接爱心系列1Pyth…

iOS构建版本以及Hbuilder打iOS的ipa包全流程

目录 Hbuilder打ipa包 打包之前进行应用配置 应用版本号设置 使用广告标识设置 iOS-云打包 下载并转移安装包 使用Transporter提交版本 应用简介 下载应用 账号登录 提交安装包到apple store connect 在apple开发者平台上确认 总结 本篇文章详细的介绍了使用Hbuil…

【二叉树】【2.1遍历二叉树】【刷题笔记】【灵神题单】

关注二叉树的三个问题: 什么情况适合自顶向下?什么时候适合用自底向上?一般来说,DFS的递归边界是空节点,什么情况下要额外把叶子节点作为递归边界?在什么情况下,DFS需要有返回值?什…

C语言实例之9斐波那契数列实现

1. 斐波那契数列简介 斐波那契数列(Fibonacci sequence),又称黄金分割数列,因数学家莱昂纳多・斐波那契(Leonardo Fibonacci)以兔子繁殖为例子而引入,故又称为 “兔子数列”。 它的特点是从第三…

C++ 中的多继承

C 中的 多继承(Multiple Inheritance)是指一个类可以同时继承自多个父类。与单继承(Single Inheritance)不同,子类在多继承中可以从多个父类继承属性和方法。其基本语法如下: class ClassA {// ClassA 的成…

【前端学习笔记】AJAX、axios、fetch、跨域

1.介绍 AJAX(Asynchronous JavaScript and XML)异步的JS和XML。通过 AJAX 可以在浏览器中向服务器发送异步请求,最大的优势:无刷新获取数据。AJAX 不是新的编程语言,而是一种将现有的标准组合在一起使用的新方式。 X…