当前位置: 首页 > news >正文

OpenCV入门(二十四)快速学会OpenCV 23 傅里叶变换

OpenCV入门(二十四)快速学会OpenCV 23 傅里叶变换

  • 1.傅里叶变换理论概述
  • 2.Numpy实现傅里叶变换
    • 2.1 傅里叶变换
    • 2.2 傅里叶逆变换
    • 2.3 高通滤波
  • 3.OpenCV实现傅里叶变换
    • 3.1 实现傅里叶变换
    • 3.2 实现傅里叶逆变换
    • 3.3 低通滤波

作者:Xiou

1.傅里叶变换理论概述

图像处理一般分为空间域处理和频率域处理。空间域处理是直接对图像内的像素进行处理。空间域处理主要划分为灰度变换和空间滤波两种形式。灰度变换是对图像内的单个像素进行处理,比如调节对比度和处理阈值等。空间滤波涉及图像质量的改变,例如图像平滑处理。空间域处理的计算简单方便,运算速度更快。

频率域处理是先将图像变换到频率域,然后在频率域对图像进行处理,最后再通过反变换将图像从频率域变换到空间域。傅里叶变换是应用最广泛的一种频域变换,它能够将图像从空间域变换到频率域,而逆傅里叶变换能够将频率域信息变换到空间域内。傅里叶变换在图像处理领域内有着非常重要的作用。

在图像处理过程中,傅里叶变换就是将图像分解为正弦分量和余弦分量两部分,即将图像从空间域转换到频率域(以下简称频域)。数字图像经过傅里叶变换后,得到的频域值是复数。因此,显示傅里叶变换的结果需要使用实数图像(real image)加虚数图像(complex image),或者幅度图像(magnitude image)加相位图像(phase image)的形式。

因为幅度图像包含了原图像中我们所需要的大部分信息,所以在图像处理过程中,通常仅使用幅度图像。当然,如果希望先在频域内对图像进行处理,再通过逆傅里叶变换得到修改后的空域图像,就必须同时保留幅度图像和相位图像。对图像进行傅里叶变换后,我们会得到图像中的低频和高频信息。

低频信息对应图像内变化缓慢的灰度分量。高频信息对应图像内变化越来越快的灰度分量,是由灰度的尖锐过渡造成的。例如,在一幅大草原的图像中有一头狮子,低频信息就对应着广袤的颜色趋于一致的草原等细节信息,而高频信息则对应着狮子的轮廓等各种边缘及噪声信息。

傅里叶变换的目的,就是为了将图像从空域转换到频域,并在频域内实现对图像内特定对象的处理,然后再对经过处理的频域图像进行逆傅里叶变换得到空域图像。傅里叶变换在图像处理领域发挥着非常关键的作用,可以实现图像增强、图像去噪、边缘检测、特征提取、图像压缩和加密等。

高频 vs 低频
高频 vs 低频:

高频: 变换剧烈的灰度分量, 例如边界。
低频: 变换缓慢的灰度分量, 例如一片大海。

滤波:
低通滤波器: 只保留低频, 会使得图像模糊。
高通滤波器: 只保留高频, 会使得图像细节增强。

傅里叶变化 (Fourier Transform) 是一种分析信号的方法. 傅里叶变化可分析信号的成分, 也可以用这些成分合成信号。

在这里插入图片描述
在这里插入图片描述

2.Numpy实现傅里叶变换

2.1 傅里叶变换

Numpy模块提供了傅里叶变换功能,Numpy模块中的fft2()函数可以实现图像的傅里叶变换。本节介绍如何用Numpy模块实现图像的傅里叶变换,以及在频域内过滤图像的低频信息,保留高频信息,实现高通滤波。

Numpy提供的实现傅里叶变换的函数是numpy.fft.fft2(),它的语法格式是:

        返回值 = numpy.fft.fft2(原始图像)

这里需要注意的是,参数“原始图像”的类型是灰度图像,函数的返回值是一个复数数组(complex ndarray)。

经过该函数的处理,就能得到图像的频谱信息。此时,图像频谱中的零频率分量位于频谱图像(频域图像)[插图]的左上角,为了便于观察,通常会使用numpy.fft.fftshift()函数将零频率成分移动到频域图像的中心位置。如图所示

在这里插入图片描述

函数numpy.fft.fftshift()的语法格式是:

        返回值=numpy.fft.fftshift(原始频谱)

使用该函数处理后,图像频谱中的零频率分量会被移到频域图像的中心位置,对于观察傅里叶变换后频谱中的零频率部分非常有效。对图像进行傅里叶变换后,得到的是一个复数数组。为了显示为图像,需要将它们的值调整到[0,255]的灰度空间内,使用的公式为:

        像素新值=20*np.log(np.abs(频谱值))

式中np是“numpy”的缩写,来源于“import numpy as np”,后面不再对此进行说明。

代码实例:用Numpy实现傅里叶变换,观察得到的频谱图像。

import cv2
import numpy as np
import matplotlib.pyplot as pltimg = cv2.imread('girl1.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()

输出结果:

在这里插入图片描述

2.2 傅里叶逆变换

需要注意的是,如果在傅里叶变换过程中使用了numpy.fft.fftshift()函数移动零频率分量,那么在逆傅里叶变换过程中,需要先使用numpy.fft.ifftshift()函数将零频率分量移到原来的位置,再进行逆傅里叶变换,该过程如图

在这里插入图片描述

函数numpy.fft.ifftshift()是numpy.fft.fftshift()的逆函数,其语法格式为:

        调整后的频谱 = numpy.fft.ifftshift(原始频谱)

numpy.fft.ifft2()函数可以实现逆傅里叶变换,返回空域复数数组。它是numpy.fft.fft2()的逆函数,该函数的语法格式为:

        返回值=numpy.fft.ifft2(频域数据)

函数numpy.fft.ifft2()的返回值仍旧是一个复数数组(complex ndarray)。逆傅里叶变换得到的空域信息是一个复数数组,需要将该信息调整至[0, 255]灰度空间内,使用的公式为:

        iimg = np.abs(逆傅里叶变换结果)

代码实例:在Numpy内实现傅里叶变换、逆傅里叶变换,观察逆傅里叶变换的结果图像。

        import cv2import numpy as npimport matplotlib.pyplot as pltimg = cv2.imread('girl1.jpg',0)f = np.fft.fft2(img)fshift = np.fft.fftshift(f)ishift = np.fft.ifftshift(fshift)iimg = np.fft.ifft2(ishift)#print(iimg)iimg = np.abs(iimg)#print(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()

输出结果:

在这里插入图片描述

2.3 高通滤波

在Numpy内对图像进行傅里叶变换,得到其频域图像。然后,在频域内将低频分量的值处理为0,实现高通滤波。最后,对图像进行逆傅里叶变换,得到恢复的原始图像。观察傅里叶变换前后图像的差异。

代码实例:

        import cv2import numpy as npimport matplotlib.pyplot as pltimg = cv2.imread('image\\boat.bmp',0)f = np.fft.fft2(img)fshift = np.fft.fftshift(f)rows, cols = img.shapecrow, ccol = int(rows/2) , int(cols/2)fshift[crow-30:crow+30, ccol-30:ccol+30] = 0ishift = np.fft.ifftshift(fshift)iimg = np.fft.ifft2(ishift)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()

输出结果:

在这里插入图片描述

3.OpenCV实现傅里叶变换

OpenCV提供了函数cv2.dft()和cv2.idft()来实现傅里叶变换和逆傅里叶变换,下面分别展开介绍。

3.1 实现傅里叶变换

函数cv2.dft()的语法格式为:

返回结果=cv2.dft(原始图像,转换标识)

代码实例:用OpenCV函数对图像进行傅里叶变换,并展示其频谱信息。

        import numpy as npimport cv2import matplotlib.pyplot as pltimg = cv2.imread('girl1.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]))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()

输出结果:
在这里插入图片描述

3.2 实现傅里叶逆变换

在OpenCV中,使用函数cv2.idft()实现逆傅里叶变换,该函数是傅里叶变换函数cv2.dft()的逆函数。其语法格式为:

        返回结果=cv2.idft(原始数据)

对图像进行傅里叶变换后,通常会将零频率分量移至频谱图像的中心位置。如果使用函数numpy.fft.fftshift()移动了零频率分量,那么在进行逆傅里叶变换前,要使用函数numpy.fft.ifftshift()将零频率分量恢复到原来位置。

代码实例:用OpenCV函数对图像进行傅里叶变换、逆傅里叶变换,并展示原始图像及经过逆傅里叶变换后得到的图像。

        import numpy as npimport cv2import matplotlib.pyplot as pltimg = cv2.imread('girl1.jpg',0)dft = cv2.dft(np.float32(img), flags = cv2.DFT_COMPLEX_OUTPUT)dftShift = np.fft.fftshift(dft)ishift = np.fft.ifftshift(dftShift)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()

输出结果:
在这里插入图片描述

3.3 低通滤波

前面讲过,在一幅图像内,低频信号对应图像内变化缓慢的灰度分量。例如,在一幅大草原的图像中,低频信号对应着颜色趋于一致的广袤草原。低通滤波器让高频信号衰减而让低频信号通过,图像进行低通滤波后会变模糊。

代码实例:使用函数cv2.dft()对图像进行傅里叶变换,得到其频谱图像。然后,在频域内将其高频分量的值处理为0,实现低通滤波。最后,对图像进行逆傅里叶变换,得到恢复的原始图像。观察傅里叶变换前后图像的差异。

        import numpy as npimport cv2import matplotlib.pyplot as pltimg = cv2.imread('girl1.jpg',0)dft = cv2.dft(np.float32(img), flags = cv2.DFT_COMPLEX_OUTPUT)dftShift = np.fft.fftshift(dft)rows, cols = img.shapecrow, ccol = int(rows/2) , int(cols/2)mask = np.zeros((rows, cols,2), np.uint8)#两个通道,与频域图像匹配mask[crow-30:crow+30, ccol-30:ccol+30] = 1fShift = dftShift*maskishift = 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入门(二十四)快速学会OpenCV 23 傅里叶变换

OpenCV入门(二十四)快速学会OpenCV 23 傅里叶变换1.傅里叶变换理论概述2.Numpy实现傅里叶变换2.1 傅里叶变换2.2 傅里叶逆变换2.3 高通滤波3.OpenCV实现傅里叶变换3.1 实现傅里叶变换3.2 实现傅里叶逆变换3.3 低通滤波作者:Xiou 1.傅里叶变换…...

线段树合并

前置知识:权值线段树,动态开点。 引入 我们先来看一道题: 永无乡包含 nnn 座岛,给出每座岛的重要度的排名,名次用 111 到 nnn 来表示。一开始有 mmm 条边连接,接下来有 qqq 次操作。操作分两种&#xff…...

研发效能 | DevOps如何改变游戏公司工作方式?

如果你是游戏开发者,那么在过去几年里,你可能会觉得有人给了你一把双刃剑。 整个行业不断蓬勃发展,但玩家的预期值也越来越高。玩家们总是希望游戏体验能够更快、更真实、更具创造性。此外,他们还希望能够定期推出新的游戏和更新…...

Mongo聚合和Springboot整合Mongo聚合

聚合(aggregate)是基于数据处理的聚合管道,每个文档通过一个由多个阶段(stage)组成的管道,可以对每个阶段的管道进行分组、过滤等功能,然后经过一系列的处理,输出相应的结果。 语法格式:db.集合名称.aggregate({管道:{表达式}}) 常用管道如下: $group: 将集合中的⽂…...

第06章_索引的数据结构

第06章_索引的数据结构 🏠个人主页:shark-Gao 🧑个人简介:大家好,我是shark-Gao,一个想要与大家共同进步的男人😉😉 🎉目前状况:23届毕业生,目…...

不确定的市场,确定的增长,海尔智家2022全球再逆增

文|螳螂观察 作者| 余一 上市公司2022年年报逐渐进入密集披露期,在当前的年报季窗口,各家公司的业绩情况被高度关注。 3月30日晚,海尔智家发布了2022年财报。财报显示,2022年海尔智家实现收入2435.14亿元,同比增长7…...

测试老鸟手把手教你python接口自动化测试项目实战演示

目录 前言 一、项目准备 二、项目流程 三、完整代码 四、总结 前言 在进行接口自动化测试项目实战之前,我们需要先了解什么是接口自动化测试。接口自动化测试是通过自动化脚本模拟用户请求和服务器响应的过程,以检测接口是否符合预期,确…...

一起来学5G终端射频标准(Coherent UL-MIMO测试要求)

01 — Coherent UL-MIMO测试要求 首先什么是Coherent?它的英文释义是:(of ideas, thoughts, argument, theory, or policy) logical and consistent,翻译过来就是:(看法、思想、论证、理论或政策等&…...

计算广告(五)

Nobid Nobid(在某手有时也叫MCB,在Facebook叫Lowest Cost)是指广告主不用(也不能)对转化成本进行出价,而是出一个预算(大多数是日预算),然后投放平台的目标是在时间范围…...

排序输入的高效霍夫曼编码 | 贪心算法 3

前面我们讲到了 贪心算法的哈夫曼编码规则,原理图如下: 如果我们知道给定的数组已排序(按频率的非递减顺序),我们可以在 O(n) 时间内生成霍夫曼代码。以下是用于排序输入的 O(n) 算法。1.创建两个空队列。2.为每个唯一…...

奇异值分解(SVD)和图像压缩

在本文中,我将尝试解释 SVD 背后的数学及其几何意义,还有它在数据科学中的最常见的用法,图像压缩。 奇异值分解是一种常见的线性代数技术,可以将任意形状的矩阵分解成三个部分的乘积:U、S、V。原矩阵A可以表示为&#…...

Java如何从yml文件获取对象

目录一、背景二、application.yml三、ChinaPersonFactory.java四、使用示例一、背景 在 SpringBoot 中,我们可以使用 Value 注解从属性文件(例如 application.yml 或 application.properties)中获取配置信息,但是只能获取简单的字…...

vue使用tinymce实现富文本编辑器

安装两个插件tinymce和 tinymce/tinymce-vue npm install tinymce5.10.3 tinymce/tinymce-vue5.0.0 -S 注意: tinymce/tinymce-vue 是对tinymce进行vue的包装,主要作用当作vue组件使用-S保存到package.json文件 2. 把node_modules/tinymce下的目录&a…...

yolov4实战训练数据

1、克隆项目文件 项目Github地址:https://github.com/AlexeyAB/darknet 打开终端,克隆项目 git clone https://github.com/AlexeyAB/darknet.git无法克隆的话,把https修改为git git clone git://github.com/AlexeyAB/darknet.git修改Makef…...

第十四章 DOM的Diff算法与key

React使用Diff算法来比较虚拟DOM树和真实DOM树之间的差异,并仅更新必要的部分,以提高性能。key的作用是在Diff算法中帮助React确定哪些节点已更改,哪些节点已添加或删除。 我们以案例来说明。 使用索引值和唯一ID作为key的效果 1、使用索引…...

MySQL调优

MySQL调优常见的回答如何回答效果更好业务层的优化如果只能用mysql该如何优化代码层的优化SQL层面优化总结常见的回答 SQL层面的优化——创建索引,创建联合索引,减少回表。再有就是少使用函数查询。 回表指的是数据库根据索引(非主键&#…...

《Flutter进阶》flutter升级空安全遇到的一些问题及解决思路

空安全出来挺久了,由于业务需求较紧,一直没时间去升级空安全,最近花了几天去升级,发现其实升级也挺简单的,不要恐惧,没有想象中的多BUG。 flutter版本从1.22.4升到3.0.5; compileSdkVersion从1…...

最值得入手的五款骨传导耳机,几款高畅销的骨传导耳机

骨传导耳机是一种声音传导方式,主要通过颅骨、骨骼把声波传递到内耳,属于非入耳式的佩戴方式。相比传统入耳式耳机,骨传导耳机不会堵塞耳道,使用时可以开放双耳,不影响与他人的正常交流。骨传导耳机不会对耳朵产生任何…...

HashMap源码分析 (1.基础入门) 学习笔记

本章为 《HashMap全B站最细致源码分析课程》 拉钩教育HashMap 学习笔记 文章目录1. HashMap的数据结构1. 数组2. 链表3. 哈希表3.1 Hash1. HashMap的数据结构 数据结构中有数组和链表来实现对数据的存储,但这两者基本上是两个极端。 1. 数组 在生成数组的时候数…...

6 使用强制类型转换的注意事项

概述 在C语言中,强制类型转换是通过直接转换为特定类型的方式来实现的,类似于下面的代码。 float fNumber = 66.66f; // C语言的强制类型转换 int nData = (int)fNumber; 这种方式可以在任意两个类型间进行转换,太过随意和武断,很容易带来一些难以发现的隐患和问题。C++为…...

边缘计算医疗风险自查APP开发方案

核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止

<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet&#xff1a; https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...

【配置 YOLOX 用于按目录分类的图片数据集】

现在的图标点选越来越多&#xff0c;如何一步解决&#xff0c;采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集&#xff08;每个目录代表一个类别&#xff0c;目录下是该类别的所有图片&#xff09;&#xff0c;你需要进行以下配置步骤&#x…...

select、poll、epoll 与 Reactor 模式

在高并发网络编程领域&#xff0c;高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表&#xff0c;以及基于它们实现的 Reactor 模式&#xff0c;为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。​ 一、I…...

selenium学习实战【Python爬虫】

selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列&#xff0c;以便知晓哪些列包含有价值的数据&#xff0c;…...

【从零学习JVM|第三篇】类的生命周期(高频面试题)

前言&#xff1a; 在Java编程中&#xff0c;类的生命周期是指类从被加载到内存中开始&#xff0c;到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期&#xff0c;让读者对此有深刻印象。 目录 ​…...

纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join

纯 Java 项目&#xff08;非 SpringBoot&#xff09;集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...

vulnyx Blogger writeup

信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面&#xff0c;gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress&#xff0c;说明目标所使用的cms是wordpress&#xff0c;访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...

解读《网络安全法》最新修订,把握网络安全新趋势

《网络安全法》自2017年施行以来&#xff0c;在维护网络空间安全方面发挥了重要作用。但随着网络环境的日益复杂&#xff0c;网络攻击、数据泄露等事件频发&#xff0c;现行法律已难以完全适应新的风险挑战。 2025年3月28日&#xff0c;国家网信办会同相关部门起草了《网络安全…...