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

server/2024/11/30 18:09:46/

在这里插入图片描述

简介:本文围绕傅里叶变换在图像处理中的应用展开。先是以通俗易懂的方式详细阐释了傅里叶变换的核心理论,涵盖为何选用正弦和余弦、空间域到频率域的转换以及幅度图像和相位图像的含义等内容,帮助读者理解其原理。接着通过具体代码示例,分别展示了如何利用 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/server/146212.html

相关文章

mybatis02——Mapper代理开发

以上配置完后在mybatis-config.xml文件里改resources&#xff08;见后面&#xff1a;可以直接将整个mapper包导进来&#xff09; <mappers><mapper resource"com/test/mapper/UserMapper.xml"/></mappers> 在接口&#xff08;与xxxMapper.xml文件…

Linux xattr 命令详解

简介 Linux 中的 xattr 命令用于管理文件的扩展属性。扩展属性存储标准属性中未包含的附加元数据&#xff08;如权限、所有者和时间戳&#xff09;。它们通常由特定的应用程序或文件系统&#xff08;例如&#xff0c;acl、SELinux 标签&#xff09;使用。 关键概念 扩展属性&…

【docker】docker的起源与容器的由来、docker容器的隔离机制

Docker 的起源与容器的由来 1. 虚拟机的局限&#xff1a;容器的需求萌芽 在 Docker 出现之前&#xff0c;开发和部署软件主要依赖虚拟机&#xff08;VMs&#xff09;&#xff1a; 虚拟机通过模拟硬件运行操作系统&#xff0c;每个应用程序可以运行在自己的独立环境中。虽然虚…

26届JAVA 学习日记——Day17

2024.11.29 周五 今天把苍穹外卖的项目做完啦&#xff0c;准备开始做新的AI项目&#xff0c;今天的时间主要在修改简历&#xff0c;超级简历现在要收费&#xff0c;自己Word慢慢改真的很耗时间。 八股 今日暂无该内容学习。 算法 今日暂无该内容学习。 项目 苍穹外卖-完结…

AI开发-自然语言处理工具包-NumPy

1 需求 NLTK :: Natural Language Toolkit 2 接口 3 示例 4 参考资料

【机器学习】机器学习的基本分类-监督学习-逻辑回归-对数似然损失函数(Log-Likelihood Loss Function)

对数似然损失函数&#xff08;Log-Likelihood Loss Function&#xff09; 对数似然损失函数是机器学习和统计学中广泛使用的一种损失函数&#xff0c;特别是在分类问题&#xff08;例如逻辑回归、神经网络&#xff09;中应用最为广泛。它基于最大似然估计原理&#xff0c;通过…

智能云在线编辑网站(完结篇)

开始及初步计划 1.前端tiptip编辑器框架vue3 2.后端Pythonflaskmysql 3.大模型调用&#xff1a;飞桨系列&#xff08;ppasr&#xff09; 前言&#xff1a;以此篇谨记从软件杯到天津生成式ai答辩过程及结束。 『如蚍蜉见青天&#xff0c;双肩难挑日月』&#xff0c;感叹世事多…

【Linux】指令合集

Linux指令合集 一、基本操作指令 ls&#xff1a;罗列出当前路径下所有的文件名。 常见选项&#xff1a; ls -a&#xff1a;显示所有文件&#xff0c;包括隐藏文件&#xff08;以“.”开头的文件&#xff09;。例如&#xff0c;在查看包含配置文件&#xff08;通常为隐藏文件&a…