目录

01 特征提取背景

02 常见的音频特征提取

2.1 过零率

2.2 频谱质心

2.3 声谱衰减

2.4 色度频率

03 MFCC特征提取

3.1 短时傅里叶分析

3.1.1 分帧

3.1.2 对每帧信号进行DFT

04 梅尔频谱和梅尔倒谱

4.1 梅尔尺度

4.2 梅尔滤波器

4.3 梅尔倒谱

05 本次任务中的特征提取

参考资料


01 特征提取背景

在之前的Task2中,我们初步查看了数据集的信息,并通过音频的声波图和声谱图将声音可视化了。当我们拿到这些音频数据之后,接下来就需要进行特征提取(过滤掉背景噪音等不需要的信息)筛选出我们需要的信息了。

接下来我们将简要介绍以下特征,并详细学习MFCC特征提取知识:

  • 过零率 (Zero Crossing Rate)
  • 频谱质心 (Spectral Centroid)
  • 声谱衰减 (Spectral Roll-off)
  • 梅尔频率倒谱系数 (Mel-frequency cepstral coefficients ,MFCC)
  • 色度频率 (Chroma Frequencies)

02 常见的音频特征提取

导包

import numpy as np
import sklearn
import librosa
import librosa.display
import matplotlib.pyplot as plt

2.1 过零率

过零率(zero crossing rate)是一个信号符号变化的比率,即,在每帧中,语音信号从正变为负或从负变为正的次数。 这个特征已在语音识别和音乐信息检索领域得到广泛使用,通常对类似金属、摇滚等高冲击性的声音的具有更高的价值。

一般情况下,过零率越大,频率近似越高。

x, sr = librosa.load('./train_sample/aloe/24EJ22XBZ5.wav')
#绘制声波信号
plt.figure(figsize=(14, 5))
librosa.display.waveplot(x, sr=sr)
# 放大
n0 = 9000
n1 = 9100
plt.figure(figsize=(14, 5))
plt.plot(x[n0:n1])
plt.grid()

可以看到该音频信号没有过零点,我们开源用librosa库进行验证,输出过零点个数:

# 计算过零率
zero_crossings = librosa.zero_crossings(x[n0:n1], pad=False)
print(sum(zero_crossings))

15

2.2 频谱质心

谱质心(Spectral Centroid)是描述音色属性的重要物理参数之一,是频率成分的重心,是在一定频率范围内通过能量加权平均的频率,其单位是Hz。它是声音信号的频率分布和能量分布的重要信息。在主观感知领域,谱质心描述了声音的明亮度,具有阴暗、低沉品质的声音倾向有较多低频内容,谱质心相对较低,具有明亮、欢快品质的多数集中在高频,谱质心相对较高。该参数常用于对乐器声色的分析研究。

spectral_centroids = librosa.feature.spectral_centroid(x, sr=sr)[0]
print(spectral_centroids.shape)
# (2647,)
# 计算时间变量
frames = range(len(spectral_centroids))
t = librosa.frames_to_time(frames)
# 归一化频谱质心
def normalize(x, axis=0):return sklearn.preprocessing.minmax_scale(x, axis=axis)
#沿波形绘制频谱质心
librosa.display.waveplot(x, sr=sr, alpha=0.4)
plt.plot(t, normalize(spectral_centroids), color='r')

2.3 声谱衰减

它是对声音信号形状(波形图)的一种衡量,表示低于总频谱能量的指定百分比的频率。

spectral_rolloff = librosa.feature.spectral_rolloff(x+0.01, sr=sr)[0]
librosa.display.waveplot(x, sr=sr, alpha=0.4)
plt.plot(t, normalize(spectral_rolloff), color='b')

2.4 色度频率

色度频率是音乐音频有趣且强大的表示,其中整个频谱被投影到12个区间,代表音乐八度音的12个不同的半音(或色度)

hop_length = 512
chromagram = librosa.feature.chroma_stft(x, sr=sr, hop_length=hop_length)
plt.figure(figsize=(15, 5))
librosa.display.specshow(chromagram, x_axis='time', y_axis='chroma', hop_length=hop_length, cmap='coolwarm')

03 MFCC特征提取

人的耳朵在接收信号的时候,不同的频率会引起耳蜗不同部位的震动。耳蜗就像一个频谱仪,自动在做特征提取并进行语音信号的处理。在语音识别领域中MFCC(Mel Frequency Cepstral Coefficents)特征提取是最常用的方法,也是本次音频分类任务中涉及到的特征提取方法。

具体来说,MFCC特征提取的步骤如下:

  • 对语音信号进行分帧处理
  • 用周期图(periodogram)法来进行功率谱(power spectrum)估计
  • 对功率谱用Mel滤波器组进行滤波,计算每个滤波器里的能量
  • 对每个滤波器的能量取log
  • 进行离散余弦变换(DCT)变换
  • 保留DCT的第2-13个系数,去掉其它

其中,前面两步是短时傅里叶变换,后面几步主要涉及梅尔频谱,接下来我们将分别学习这些知识。

3.1 短时傅里叶分析

声音信号本是一维时域信号(声音信号随时间变化),我们可以通过傅里叶变换将其转换到频域上,但这样又失去了时域信息,无法看出频率分布随时间的变化。短时傅里叶(STFT)就是为了解决这个问题而发明的常用手段。

所谓的短时傅里叶变换,即把一段长信号分帧、加窗,再对每一帧做快速傅里叶变换(FFT),最后把每一帧的结果沿另一个维度堆叠起来,得到类似于一幅图的二维信号形式,也就是我们task2中得到的声谱图。

3.1.1 分帧

语音信号是不稳定的时变信号,但为了便于处理,我们假设在一个很短的时间内,如20-40ms内为一个稳定的系统,也就是1帧。但是我们不能简单平均分割语音,相邻的帧之间需要有一定的重合。我们通常以25ms为1帧,帧移为10ms,因此1秒的信号会有10帧。

3.1.2 对每帧信号进行DFT

我们可以使用离散傅里叶变换(DFT)把每一帧信号变换到时域,公式是:

其中s(n)表示时域信号;si(n)是第i帧的数据,其中n的范围是1-400;当我们介绍DFT的时候,Si(k)表示的是第i帧的第k个复系数;Pi(k)是第i帧的功率谱。h(n)是一个N点的窗函数(比如Hamming窗),K是DFT的长度。有了Si(k)我们就可以估计功率谱:

这样,我们就得到了周期图的功率谱估计,即声谱图。以之前task2的芦荟音频为例,它的横坐标是帧下标,纵坐标是不同频率或者叫能量,图中颜色越深(比如红色),对应频率的能量越大。

我们可以利用 librosa库做短时傅立叶变换(STFT),通过STFT能够返回一个复数矩阵,使得:

  • 复数的实部:np.abs(D(f,t))为频率的振幅
  • 复数的虚部:np.angle(D(f,t))为频率的相位
# STFT
y, sr = librosa.load('./train_sample/aloe/24EJ22XBZ5.wav')
S =librosa.stft(y, n_fft=2048, hop_length=None, win_length=None, window='hann', center=True, pad_mode='reflect')
'''
• y:音频时间序列
• n_fft:FFT窗口大小,n_fft=hop_length+overlapping
• hop_length:帧移,如果未指定,则默认win_length / 4
• win_length:每一帧音频都由window()加窗。窗长win_length,然后用零填充以匹配n_fft默认win_length=n_fft。
• window:字符串,元组,数字,函数 shape =(n_fft, )窗口(字符串,元组或数字)窗函数,例如scipy.signal.hanning长度为n_fft的向量或数组
• center:bool如果为True,则填充信号y,以使帧 D [:, t]以y [t * hop_length]为中心如果为False,则D [:, t]从y [t * hop_length]开始
• dtype:D的复数值类型。默认值为64-bit complex复数
• pad_mode:如果center = True,则在信号的边缘使用填充模式默认情况下,STFT使用reflection padding
'''
S = np.abs(S)
print(y.shape)
print(S.shape)
(71661,)
(1025, 140)

04 梅尔频谱和梅尔倒谱

声谱图往往是很大的一张图,且依旧包含了大量无用的信息,所以我们需要通过梅尔标度滤波器组(mel-scale filter banks)将其变为梅尔频谱。

4.1 梅尔尺度

梅尔尺度(Mel Scale)是建立从人类的听觉感知的频率——Pitch到声音实际频率直接的映射。频率的单位是赫兹(Hz),人耳能听到的频率范围是20-20000Hz,但人耳对Hz这种标度单位并不是线性感知关系,例如,若把音调频率从1000Hz提高到2000Hz,我们的耳朵只能觉察到频率似乎提高了一些而不是一倍。但是通过把频率转换成美尔尺度,我们的特征就能够更好的匹配人类的听觉感知效果。从频率到梅尔频率的转换公式如下:

我们可以观察一下转换后的映射图,可以发现人耳对于低频声音的分辨率要高于高频的声音,因为赫兹到梅尔是log的关系,所以当频率较小时,mel随Hz变化较快;当频率很大时,mel的上升很缓慢,曲线的斜率很小。这说明了人耳对低频音调的感知较灵敏,在高频时人耳是很迟钝的,梅尔标度滤波器组启发于此。

4.2 梅尔滤波器

为了模拟人耳对声音的感知,人们发明的梅尔滤波器组。一组大约20-40(通常26)个三角滤波器组,它会对上一步得到的周期图的功率谱估计进行滤波。而且区间的频率越高,滤波器就越宽(但是如果把它变换到美尔尺度则是一样宽的)。为了计算方便,我们通常把26个滤波器用一个矩阵来表示,这个矩阵有26行,列数就是傅里叶变换的点数。

计算过程如下图所示,最后我们会保留这26个滤波器的能量。图(a)是26个滤波器;图(b)是滤波后的信号;图(c)是其中的第8个滤波器,它只让某一频率范围的信号通过;图(d)通过它的信号的能量;图(e)是第20个滤波器;图(f)是通过它的信号的能量。

4.3 梅尔倒谱

在梅尔频谱上做倒谱分析(取对数log,做离散余弦变换(DCT)变换)就得到了梅尔倒谱。

对上面得到的26个点的信号进行DCT,得到26个倒谱系数(Cepstral Coefficents),最后我们保留2-13这12个数字,这12个数字就叫MFCC特征。对功率谱再做DCT的目的就是为了提取信号的包络。

#梅尔频率倒谱系数 MFCC
mfccs = librosa.feature.mfcc(x, sr)
print (mfccs.shape)
# (20, 151)
#Displaying  the MFCCs:
librosa.display.specshow(mfccs, sr=sr, x_axis='time')
(20, 140)

这里mfcc计算了超过151帧的20个MFCC。我们还可以进行特征缩放,使得每个系数维度具有零均值和单位方差:

# mfcc 特征缩放
mfccs = sklearn.preprocessing.scale(mfccs, axis=1)
print(mfccs.mean(axis=1))
print(mfccs.var(axis=1))
librosa.display.specshow(mfccs, sr=sr, x_axis='time')
[-5.1089697e-09  1.2772424e-09  1.3623919e-08 -1.0217939e-08-8.5149493e-10 -5.0238199e-08 -3.6188534e-09  4.2574747e-107.4505806e-09  7.6634548e-09 -2.5544848e-09  4.2574747e-10-2.5544848e-09 -4.0446011e-09  3.8317271e-08  8.9406971e-09-3.1931060e-09  2.9802323e-09 -2.3416111e-09  3.6188534e-09]
[0.9999999  1.0000002  0.99999976 0.99999976 1.0000001  0.99999970.9999996  0.99999976 0.99999976 1.0000002  1.0000004  0.99999971.         1.0000004  1.0000002  1.0000002  1.         0.99999971.0000004  1.        ]

05 本次任务中的特征提取

feature = []
label = []
# 建立类别标签,不同类别对应不同的数字。
label_dict = {'aloe': 0, 'burger': 1, 'cabbage': 2,'candied_fruits':3, 'carrots': 4, 'chips':5,'chocolate': 6, 'drinks': 7, 'fries': 8, 'grapes': 9, 'gummies': 10, 'ice-cream':11,'jelly': 12, 'noodles': 13, 'pickles': 14, 'pizza': 15, 'ribs': 16, 'salmon':17,'soup': 18, 'wings': 19}
label_dict_inv = {v:k for k,v in label_dict.items()}

建立提取音频特征的函数

from tqdm import tqdm
def extract_features(parent_dir, sub_dirs, max_file=10, file_ext="*.wav"):c = 0label, feature = [], []for sub_dir in sub_dirs:for fn in tqdm(glob.glob(os.path.join(parent_dir, sub_dir, file_ext))[:max_file]): # 遍历数据集的所有文件# segment_log_specgrams, segment_labels = [], []#sound_clip,sr = librosa.load(fn)#print(fn)label_name = fn.split('/')[-2]label.extend([label_dict[label_name]])X, sample_rate = librosa.load(fn,res_type='kaiser_fast')mels = np.mean(librosa.feature.melspectrogram(y=X,sr=sample_rate).T,axis=0) # 计算梅尔频谱(mel spectrogram),并把它作为特征feature.extend([mels])return [feature, label]
# 自己更改目录
parent_dir = './train_sample/'
save_dir = "./"
folds = sub_dirs = np.array(['aloe','burger','cabbage','candied_fruits','carrots','chips','chocolate','drinks','fries','grapes','gummies','ice-cream','jelly','noodles','pickles','pizza','ribs','salmon','soup','wings'])# 获取特征feature以及类别的label
temp = extract_features(parent_dir,sub_dirs,max_file=100)
temp = np.array(temp)
data = temp.transpose()
# 获取特征
X = np.vstack(data[:, 0])# 获取标签
Y = np.array(data[:, 1])
print('X的特征尺寸是:',X.shape)
print('Y的特征尺寸是:',Y.shape)
X的特征尺寸是: (1000, 128)
Y的特征尺寸是: (1000,)
# 在Keras库中:to_categorical就是将类别向量转换为二进制(只有0和1)的矩阵类型表示
Y = to_categorical(Y)
# 最终数据
print(X.shape)
print(Y.shape)
(1000, 128)
(1000, 20)

参考资料

1. STFT和声谱图

2. MFCC特征提取教程

3. librosa处理音频信号

【语音识别】食物声音识别(三)音频数据特征提取相关推荐

  1. 零基础入门语音识别-食物声音识别[Task 3]

    Task3 食物声音识别之音频数据特征提取 Task1 食物声音识别之Baseline学习 Task2 食物声音识别之赛题数据介绍与分析 1 特征提取背景 在Task2中,我们已经了解了我们需要识别的 ...

  2. 【语音识别】食物声音识别(四)音频数据特征提取

    目录 01 前情摘要 1.1 导包 1.2 特征提取以及数据集的建立 02 建立模型 2.1 深度学习框架 2.1.1 网络结构搭建 2.1.2 搭建CNN网络 2.1.3 CNN基础知识 03 CN ...

  3. 零基础入门语音识别-食物声音识别[Task 1]

    Task1 食物声音识别之Baseline学习 作为零基础入门语音识别的新人赛,本次任务不涉及复杂的声音模型.语言模型,希望大家通过两种baseline的学习能体验到语音识别的乐趣. 任务说明:我们提 ...

  4. 天池学习赛 -【零基础入门语音识别-食物声音识别】Task1 食物声音识别-Baseline【代码详细手写解释】

    文章目录 一.Task1 食物声音识别-Baseline 二.对应解析 三.参考链接 一.Task1 食物声音识别-Baseline 天池对应代码链接 二.对应解析 三.参考链接 tqdm的解释 深度 ...

  5. 【组队学习】【24期】零基础入门语音识别(食物声音识别)

    零基础入门语音识别(食物声音识别) 开源内容: https://github.com/datawhalechina/team-learning-nlp/tree/master/FoodVoiceRec ...

  6. 使用Sinc卷积从原始音频数据进行轻量级的端到端语音识别

    论文: Lightweight End-to-End Speech Recognition from Raw Audio Data Using Sinc-Convolutions 摘要: 许多端到端自 ...

  7. Android 音频开发(三) 如何播放一帧音频数据上

    上一篇只要介绍了如何采集一帧音频,本篇就讲述如何播放一帧音频数据,这一篇我将分倆篇来详细介绍. Android SDK 提供了3套音频播放的API,分别是:MediaPlayer,SoundPool, ...

  8. 语音识别原理与应用 第三章 语音特征提取

    目录 第三章 语音特征提取 3.1预处理 3.2 短时傅立叶变换 3.3听觉特性 3.4线性预测 3.5倒谱分析 3.6常用的声学特征 第三章 语音特征提取 原始语音是不定长的时序信号,不适合直接作为 ...

  9. python音频特征提取_使用Python对音频进行特征提取

    写在前面 因为喜欢玩儿音乐游戏,所以打算研究一下如何用深度学习的模型生成音游的谱面.这篇文章主要目的是介绍或者总结一些音频的知识和代码. 恩.如果没玩儿过的话,音乐游戏大概是下面这个样子. 下面进入正 ...

  10. python音频特征提取_Python干货:如何使用Python对音频进行特征提取?

    写在前面 因为喜欢玩儿音乐游戏,所以打算研究一下如何用深度学习的模型生成音游的谱面.这篇文章主要目的是介绍或者总结一些音频的知识和代码. 恩.如果没玩儿过的话,音乐游戏大概是下面这个样子. 下面进入正 ...

最新文章

  1. day05:SQL_DCL ,权限控制
  2. java 对增删该查进行测试_java连接mysql增删改查测试通过
  3. ThreadLocal原理及用法详解
  4. Linux 查看磁盘分区、文件系统、磁盘的使用情况相关的命令和工具介绍
  5. PyTorch的nn.Linear()详解
  6. java 方法 示例_Java扫描仪具有示例的NextNextInt()方法
  7. 参数变化_风机盘管参数变化对性能造成的影响
  8. 线段树 B数据结构 牛客练习赛28
  9. Python【第一篇】python安装、pip基本用法、变量、输入输出、流程控制、循环
  10. sketchup作品_建环学院学生期末作品展第六站计算机辅助设计sketchup作业
  11. mysql 插入汉字出现问号 解决方法
  12. python 并行读取文件_python对文件进行并行计算初探(二)
  13. 如何使用flex布局,实现三个div垂直居中布局
  14. Netplus里的基本概念
  15. R语言实战(统计分析1)
  16. proc文件系统介绍
  17. nsga 的java实现_Java – Scala遗传算法(GA)库中的模拟二进制交叉(SBX)交叉运算符
  18. HWDB1.1数据集 | 手写汉字数据集 |.gnt 转换 .png格式图片| 【❤️有效转换❤️】
  19. 使用NSIS脚本制作一个安装包
  20. 基于J2EE人事考勤管理系统设计与实现(论文+项目源码) 运行环境: idea ,maven,mysql

热门文章

  1. linux usb摄像头驱动程序,Linux系统下USB摄像头驱动开发
  2. 剑芒罗曼史2解图片程序
  3. Could not find acceptable representation 原因探究
  4. 流程图绘制工具 yEd
  5. Cortex-M中特别实用的DWT计数器
  6. 7z怎么解压linux,7z 常用解压命令
  7. python“渡劫”进阶期(继承、多态、私有化、异常捕获、类属性和类方法)
  8. ECMAScript 2022 正式发布
  9. 用matlab进行频域分析,使用Matlab对信号进行频域分析的方法
  10. Python基础之模块(Module)和包(Package)