python的opencv操作记录(七)——短时傅里叶变换(stft)

news/2024/4/29 5:53:21/文章来源:https://blog.csdn.net/pcgamer/article/details/127391282

文章目录

  • DCT-傅立叶变换的局限性
  • STFT 短时傅里叶变换
    • 从另一个角度来理解图像的“时域”数据
      • 看看fs和t这两个参数
      • 再看看怎么划分窗口
      • 最后看另外两个出参
      • Zxx返回结构
  • 图像的stft

DCT-傅立叶变换的局限性

接上一篇DCT的文章,DCT只提取了整个信号域的频率信息,但是没有时间信息,或者说没有位置信息,也就是说不知道这个频率是发生在哪个位置。
如果在图像处理的语境下的话,那就是不知道这个像素变换发生在什么位置。
我们来写段代码作一个实验:

    img1 = np.zeros((100, 100, 3), dtype="uint8")cv2.rectangle(img1, (60, 20), (70, 70), (255, 255, 255), 1)cv2.rectangle(img1, (80, 20), (90, 70), (255, 255, 255), 1)img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)dft1 = cv2.dft(np.float32(img1), flags=cv2.DFT_COMPLEX_OUTPUT)print(dft1)cv2.imshow("img_ori1", img1)img2 = np.zeros((100, 100, 3), dtype="uint8")cv2.rectangle(img2, (20, 20), (30, 70), (255, 255, 255), 1)cv2.rectangle(img2, (40, 20), (50, 70), (255, 255, 255), 1)img2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)dft2 = cv2.dft(np.float32(img2), flags=cv2.DFT_COMPLEX_OUTPUT)print(dft2)cv2.imshow("img_ori2", img2)

图像显示如下:
在这里插入图片描述

两个dft的输出结果一模一样,都是下面的一串:
[[[ 6.1200000e+04 0.0000000e+00]
[ 0.0000000e+00 4.7354695e+04]
[-1.5694755e+04 -1.2207031e-04]

[ 1.1026633e-03 -1.1961035e+04]
[-1.5694755e+04 1.2207031e-04]
[ 0.0000000e+00 -4.7354695e+04]]

从上面的这个小实验就可以看出来,两个方框造成的图像像素值变换的频率是一样的,但是出现的位置是不一样的,但是在普通的dft中无法得出(前一篇文章中提到,dft的两个维度,一个是频率,另外一个是像素值,但是没有出现的位置)

STFT 短时傅里叶变换

所谓的“短时”,就是把整个信号域划分成一个一个的小段,就可以得到每一个段的频率和相位谱,再加上每个时间窗这个“时间”维度,就知道了这个“位置-信号中的位置”数据了。当然,还有一个好处就是,可以细分一个时间窗口到某一个稳定信号变换域,就不会受频率变换的影响了。

这里面有任何一个滑动窗口函数涉及到的问题,就是这个窗口到底划多宽合适。同样,写点代码来试试看。

代码是用的python中的scipy框架库里的signal子库:

  scipy.signal.stft(x,fs = 1.0,window =‘hann’,nperseg = 256,noverlap = None,nfft = None,detrend = False,return_oneside = True,boundary =‘zeros’,padded = True,axis = -1
  • 输入参数

    • x: STFT变换的时域信号
    • fs: 时域信号的采样频率
    • window: 时域信号分割需要的窗函数,可以自定义窗函数(但是这个方面没有尝试,需要自定义的话请自己尝试)
    • nperseg: 窗函数长度
    • noverlap: 窗函数重叠数,默认为50%。
    • nfft: FFT的长度,默认为nperseg。如大于nperseg会自动进行零填充
    • return_oneside : True返回复数实部,None返回复数。
      剩下的参数一般不会涉及,采用默认的参数。
  • 输出参数

    • f: 频率
    • t: 时间
    • Zxx: STFT时频数据

从另一个角度来理解图像的“时域”数据

我在网上找了很多资料,都没有解释上面几个入参和出参的具体物理含义,也就是这些参数在整个变换过程中起到了什么作用。所以我就先从简单一维数组信号开始作实验,来仔细说说这些参数到底代表什么含义。

看看fs和t这两个参数

一段最基本的代码,在这段代码中,信号就是一个直流信号,没有任何变化。

x = [1, 1, 1, 1]
fs = 1f, t, Zxx = signal.stft(x, fs, nperseg=1)

我们来看一下输出:
在这里插入图片描述

首先来看一下这个fs这个入参和t这个出参。

还是把x这个信号看成是一个完整信号的采样结果,代码中的[1, 1, 1, 1]就是对这个信号采样结果,我们这个例子中的 fs = 1,表示这一个数据表示一个信号周期,而t这个出参就是这四个数据是在第几个时间周期内。

如果fs=1,那么上面就是4个周期:1,2,3,4;
如果fs=2,那么上面就是2个周期:1,2。因为每个周期里面有两次采样,也就是采样频率是2;
以此类推

我们改一下参数fs试试看上面的这段描述。

x = [1, 1, 1, 1]
fs = 2f, t, Zxx = signal.stft(x, fs, nperseg=1)

在这里插入图片描述

在这个demo中,因为采样频率为2,所以总共才两个周期,4个数据也就是总共4个采样点,分布在2个信号周期内,t就变成[0, 0.5, 1, 1.5]了。

再看看怎么划分窗口

stft对dft的最大的改进就是对信号进行了窗口的划分,对每个窗口内的“短时”信号进行单独的dft变换。
控制窗口的主要由两个参数来控制:
nperseg:表示多少个采样点来组成一个窗口。
noverlap:表示窗口与窗口之间有多少个采样点重合,默认值就是nperseg / 2,这里要做整除。

窗口输出后,同样会在出参t上体现。

x = [1, 1, 1, 1, 1, 1, 1, 1]
fs = 1f, t, Zxx = signal.stft(x, fs, nperseg=4)

在这里插入图片描述

我理解,t这个出参实际上是记录了每个窗口的起始周期(时间维度),那么在这个小demo中,总共分成了4个窗口,共5个轴(axis,5个线形成4个区段,每个轴就是一个时间点)。这是因为窗口与窗口之间必须有2个采样点的重合,所以5个轴的时间点就是0, 2, 4, 6, 8。

为什么说是其实周期呢,我们把fs改成2试一下。

x = [1, 1, 1, 1, 1, 1, 1, 1]
fs = 2f, t, Zxx = signal.stft(x, fs, nperseg=4)

t的输出结果就变成了[0. 1. 2. 3. 4.],因为2个采样点在一个周期内,所以结果就是原来的一半。

另外,如果分窗的时候不能整除,那么剩下的采样点部分就需要进行补充。
补充的规则由另外两个参数来确定:

scipy官网上的描述如下:

  • boundarystr or None, optional
    Specifies whether the input signal is extended at both ends, and how to generate the new values, in order to center the first windowed segment on the first input point. This has the benefit of enabling reconstruction of the first input point when the employed window function starts at zero. Valid options are [‘even’, ‘odd’, ‘constant’, ‘zeros’, None]. Defaults to ‘zeros’, for zero padding extension. I.e. [1, 2, 3, 4] is extended to [0, 1, 2, 3, 4, 0] for nperseg=3.

  • paddedbool, optional
    Specifies whether the input signal is zero-padded at the end to make the signal fit exactly into an integer number of window segments, so that all of the signal is included in the output. Defaults to True. Padding occurs after boundary extension, if boundary is not None, and padded is True, as is the default.

另外,补充边缘还需要满足下列的条件。

  • In order to enable inversion of an STFT via the inverse STFT in istft, the signal windowing must obey the constraint of “Nonzero OverLap Add” (NOLA), and the input signal must have complete windowing coverage (i.e. (x.shape[axis] - nperseg) % (nperseg-noverlap) == 0). The padded argument may be used to accomplish this.

最后看另外两个出参

以下面这demo为例:

x = [1, 1, 1, 1, 1, 1, 1, 1]
fs = 1f, t, Zxx = signal.stft(x, fs, nperseg=4)

先看下t,这个数组上面说到了,这就是多少个时间窗,这个例子中就是:
[0. 2. 4. 6. 8.]
表示总共有5个时间窗。

先看看频率,在signal的库中,f是一个数组,我自己的理解,这里的频率是指一个时间周期内的样本梯度。

输出的f为:
[0. 0.25 0.5 ],这表示总共有三种频率。我们拆开了看这个过程:
nperseg = 4的话,那么overlap就等于2,上面看到了总共是5个时间窗,那么我理解补充完边界的结构是:
[0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0]
时间窗就是:
[0, 0, 1, 1]
[1, 1, 1, 1]
[1, 1, 1, 1]
[1, 1, 1, 1]
[1, 0, 0, 0]

上面几个时间窗中的样本梯度分布就是:0.5,0.25,0

Zxx返回结构

Zxx结构就是一个二维数组:
[[ 0.75+0.j 1. +0.j 1. +0.j 1. +0.j 0.25+0.j ]
[-0.5 +0.25j -0.5 +0.j -0.5 +0.j -0.5 +0.j 0. -0.25j]
[ 0.25+0.j 0. +0.j 0. +0.j 0. +0.j -0.25+0.j ]]

横着的就是时间窗,竖着的就是梯度分布。

plt.pcolormesh(t, f, np.abs(Zxx), vmin=0, vmax=amp, shading='gouraud')plt.title('STFT Magnitude')
plt.ylabel('Frequency [Hz]')
plt.xlabel('Time [sec]')
plt.show()

使用上面的代码就可以画出一个时域-频域的分布图。每个交叉点上就是Zxx二维数组中的频率+相位的值。
在这里插入图片描述

图像的stft

图像是个二维数据,而上面的过程的输入都是一个一维数组,二维数组的是stft是对每行数据作一次stft,然后保存在zxx数据结构中。

# 分别作stft
f1, t1, Zxx1 = signal.stft(img1, fs=1, nperseg=100)
f2, t2, Zxx2 = signal.stft(img2, fs=1, nperseg=100)# 第二十行有区别
plt.pcolormesh(t1, f1, np.abs(Zxx2[20]), vmin=0, vmax=200, shading='gouraud')plt.pcolormesh(t2, f2, np.abs(Zxx2[20]), vmin=0, vmax=200, shading='gouraud')

结果如下:
在这里插入图片描述
在这里插入图片描述

从分布上就能看出来,stft可以按照窗口来区分不同的频率,从而达到区分两者的目的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_25471.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python——HTTP代理 Proxy

大佬勿喷 链接: https://pan.baidu.com/s/1Wm0JepiZa9iPn4WoQU3Qdg 提取码: p09g

【计算机毕业设计】基于微信小程序的校园生活服务平台

提供了一些今年最新计算机毕业设计源代码、文档及帮助指导,公众号:一点毕设,领取更多毕设资料。 一.课题概述 随着互联网时代的到来,移动端应用的发展十分迅猛,校园服务类应用 也是不计其数。但大多功能单一&#xf…

Word处理控件Aspose.Words功能演示:使用 Java 将 RTF 转换为 PDF

RTF 格式由 Microsoft 引入,用于创建富文本文档。RTF 的互操作性使得在不同的 Microsoft 产品以及异构操作系统之间交换内容成为可能。但是,有时可能需要将 RTF 转换为 PDF 以用于打印、共享或其他目的。因此,本文介绍了 如何使用 Java 以编程…

干净的代码——一种实用的方法

在对干净代码进行了一些讨论之后,我决定在一篇文章中总结最重要的事情。因为网上有很多关于清洁代码的帖子和信息,我认为一篇新的文章谈论它只是解释一些原则是不值得的。在本文中,我将尝试为您提供清洁代码的实用方法。我不会深入理论&#…

海康大华等录像机、摄像头无法通过GB28181注册到LiveGBS国标平台问题排查方法

LiveGBS常见问题-海康大华宇视华为NVR摄像头无法注册到平台国标平台看不到设备的时候如何抓包及排查1、设备注册后查看不到1.1、防火墙排查1.2、端口排查1.3、IP地址排查1.4、设备TCP/IP配置排查1.5、设备多网卡排查1.6、设备接入配置参数排查1.7、设备尝试修改本地SIP端口1.8、…

Biotin-PEG-Alk,Biotin-PEG-Alkyne,生物素-聚乙二醇-炔烃科研用试剂供应

An English name:Biotin-PEG-Alk,Biotin-PEG-Alkyne Chinese name:生物素-聚乙二醇-炔烃 Item no:X-GF-0267-10k CAS:N/A Formula:N/A MW:Biotin-PEG1-Alkyne/Biotin-PEG2-Alkyne/Biotin-P…

uni-app实战之单击菜单发布->H5的Promise 化在工程项目的实战演练项目心得

H5 开发注意 H5发布到服务器注意: 配置发布后的路径(在网站的根目录中发布是可选的),例如发布网站的路径为www.xxx Com/html5,在manifest中编辑json文件中的h5节点,并将base属性添加到路由器下的html5 单…

基于PHP的蔬菜价格查询管理系统设计与实现

目 录 1 引言 1 1.1 课题背景与意义 1 1.2 课题现状与可研究性 1 1.3 本论文研究内容和结构安排 1 2 系统基础概述 2 2.1 软件开发环境 2 2.2 L,Linux操作系统 2 2.3 A,Apache服务器 2 2.4 M,Mysql数据库 3 2.5 P,PHP语言 3 2.5.1…

EXCEL表格-VLOOKUP多对一结果匹配方法(通配符)

❤关注我,不迷路❤ 点击进入EXCEL综合应用场景专栏 在实际使用场景中,通过一个值去匹配另一个值的案例很常见,比如一份学校的信息表,通过姓名查找班级、家长姓名等,均用VLOOKUP函数可以实现,正向查找、逆…

【Coel.学习笔记】莫比乌斯反演

冷知识:百度百科里甚至没有对反演的准确定义……闲话 记得在差不多一年前写扩展欧拉定理的时候我提了一句这周终于把古代猪文搞定了,数论这块的内容就只剩个博弈论了 别提莫比乌斯反演之类的东西,我不想搞甚至刚开始写的时候还笔误把莫反写成了莫队…… 转眼一年过去了,来填…

leetcode 123买卖股票的最佳时机III

买卖股票的最佳时机III 动态规划-分两小组分别计算&#xff08;超时&#xff09; class Solution { public:int partprofit( vector<int>& prices , int start , int end ){if((end-start)<1) return 0;vector<int> dp(end - start , 0);int min prices[s…

视觉检测工作台设计

目 录 摘 要 I Abstract II 第1章 引言 1 1.1研究背景及意义 1 1.2国内外研究现状 2 第2章 总体方案的确定 4 2.1方案拟定 4 2.1.1机械结构 4 2.1. 2控制工艺要求 5 2.1. 3总体方案 5 2.2 设计参数 7 第3章 视觉检测工作台机械系统设计 8 3.1 X-Y数控工作台总体方案的确定 8 3.…

微信公众号查题搜题平台

微信公众号查题搜题平台 本平台优点&#xff1a; 多题库查题、独立后台、响应速度快、全网平台可查、功能最全&#xff01; 1.想要给自己的公众号获得查题接口&#xff0c;只需要两步&#xff01; 2.题库&#xff1a; 题库&#xff1a;题库后台&#xff08;点击跳转&#xf…

物联网、区块链、元宇宙和虚拟数字人离普罗大众有多远?

首先&#xff0c;我们最早理解的数字人就是数字虚拟的一个假人&#xff0c;可能看起来很像二次元玩偶的样子。今天我觉得数字人是一种虚拟的数字身份&#xff0c;无所谓你的形象是仿真或是任何形象&#xff0c;包括你在现实中无法实现的形象&#xff0c;你在梦想中所渴望的概念…

【数据结构与算法分析】0基础带你学数据结构与算法分析01--基础数学知识

&#x1f353;个人主页&#xff1a;个人主页 &#x1f4ac;推荐一款模拟面试、刷题神器&#xff0c;从基础到大厂面试题&#xff1a;点击跳转进入网站 &#x1f4e9;如果你想学习算法&#xff0c;以及一些语言基础的知识&#xff0c;那就来这里&#xff1a;​​​​刷题网站 跟…

无公网IP远程黑群晖【内网穿透】

无公网IP远程黑群晖【内网穿透】1. 安装cpolar群晖套件2、打开cpolar套件3. 创建远程访问隧道4. 获取公网地址访问由于黑群晖没办法用QuickConnect&#xff0c;洗白也比较麻烦&#xff0c;所以这里用内网穿透的方法来实现远程。 这里推荐一款免费不限制流量的内网穿透工具cpol…

二维数组(理论)

二维数组的定义和操作 学习目标&#xff1a; 1、理解二维数组及其存储结构。 2、掌握二维数组的初始化、输入输出等基本操作。 引入&#xff1a; 由前面介绍可知&#xff0c;一维数组的元素可以是任何基本数据类型&#xff0c;也可以是结构体。那么&#xff0c;如果一维数组的…

新闻订阅及新闻内容展示系统(Python+Django+scrapy)

目录 摘 要 1 Abstract 2 第一章 引言 3 1.1 项目的背景和意义 3 1.2.1 个性化新闻服务现状 4 1.2.2 网络爬虫研究现状 4 1.2.3 项目的范围和预期结果 4 第二章 技术与原理 5 2.1 技术选型 5 2.2 相关原理介绍 7 第三章 系统需求分析 10 3. 1 新闻订阅系统用例析取 10 3.2 新闻…

干扰管理学习日志4-------信道估计方法 LS(最小二乘)、MMSE(最小均方误差)

目录一、信道估计定义二、LS估计(最小二乘法)1.定义2.系统模型3.损失函数4.模型求解三、MMSE估计(最小均方误差)1.定义2.系统模型3.损失函数4.模型求解5.模型结果一、信道估计定义 信道估计&#xff0c;就是从接收数据中将假定的某个信道模型的模型参数估计出来的过程。如果信…

【每日算法题】合并两个有序数组(简单)

前言 给大家分享一个小技巧✔&#xff0c;当我们刷题的时候&#xff0c;最好就是集中刷某一类型的题目&#xff0c;不要刷一道排序&#xff0c;又一道数组&#xff0c;这种混乱刷题&#xff0c;不利于我们记忆&#xff0c;集中刷题可以保证刷题的效果&#xff0c;保证效率&…