【音频特征】语谱图的matlab提取和python提取

1. 前言

语谱图(spectrogram或specgram),也叫声谱图,可以简单看做一个二维矩阵,其纵轴表示频率,横轴表示时间,矩阵的值表示能量强弱。由于它拥有着频率和时间两个维度的信息,所以是比较综合地表示原语音信息的一种特征。另外,我将其看做语音和图像的一种连接,因为图像领域的模型发展得较快,所以通过这种方式把语音转换成一种特殊的图像再进一步处理。

2. 语谱图流程简介

  1. 将语音可交叉地分成多帧(由于语音的短时平稳性)
  2. 各帧加窗
  3. 各帧通过快速傅里叶变化(fft)得到频谱向量
  4. 沿着时间轴并联各频谱向量得到语谱图

3. 语谱图的提取

3.1 语谱图的matlab提取

先看一段非官方代码,结合上述步骤进行理解。

[x,Fs,nBits]=wavread('audio.wav');

s=length(x);    % 信号长度
w=256;            % 窗长
n=w;            % nfft,表示做fft变换需要的点数,一般为刚大于w的2的幂。举例,w=250,则n一般设为256
ov=w/2;            % 分帧的交叉程度,常见设为窗长的二分之一或四分之一
h=w-ov;            % 不重叠点数
win=hamming(n)';% 选了常见的汉明窗,并设置nfft
c=1;            % 指向当前帧的指针
ncols=1+fix((s-n)/h);    % 计算总共有多少帧
d=zeros((1+n/2),ncols);    % 语谱图初始化

for b=0:h:(s-n)    % 以下处理各帧
    u=win.*x((b+1):(b+n));    % 各帧加窗
    t=fft(u,n);                % 各帧进行fft,内容为u,nfft=n。对于fft,输入n个时域点,输出n个频域点
    d(:,c)=t(1:(1+n/2))';    % 并联频谱向量,注意只取1+n/2,因为负频率无意义,只留下0和正频率
    c=c+1;        % 移动指针
end
tt=[0:h:(s-n)]/Fs;    % 时间轴
ff=[0:(n/2)]*Fs/n;    % 频率轴

imagesc(tt/1000,ff/1000,20*log10(abs(d)));    % 绘制
colormap(hot);
axis xy
xlabel('时间/s');
ylabel('频率/kHz');

然而,matlab其实有封装好的函数可以直接调用。

[S,F,T]=specgram(x,nfft,Fs,windows_length,overlap_length)
% x 为整段语音
% nfft 为fft变换点数,其实可以直接用默认的刚大于窗长的2的幂。也可自定义为大于窗长的整数,会对帧进行补零操作
% Fs 语音采样频率
% windows_length 窗长
% overlap_length 交叉长度
% S 语谱图
% F 频率值,尺度为1+n/2
% T 时间值,尺度为1+fix((s-n)/h)

3.2 语谱图的python提取

有了刚才的基础,python的代码就容易理解啦。首先同样看一下不直接调用函数的写法。

import numpy as np
from scipy.io import wavfile
import matplotlib.pyplot as plt

Fs, x =  wavfile.read('audio.wav')
wave = np.array(x[:,0], dtype = "float")

frame_len = 1000
frame_off = frame_len // 2    # 非重叠点数
specg_len = 1024

# 可以想象1是代表第一帧,然后第二帧结尾超出第一帧frame_off个点,第三帧再超出第二帧frame_off个点,总共第二帧到最后一帧共有(wave.size - frame_len) // frame_off 帧
frame_num = (wave.size - frame_len) // frame_off + 1
# 生成汉明窗
hamwindow = np.hamming(frame_len)
specg = np.zeros((frame_num, specg_len // 2 + 1))
z = np.zeros(specg_len - frame_len)

for idx in range(frame_num):
    base = idx * frame_off
    frame = wave[base: base + frame_len]            # 分帧
    frame = np.append(frame * hamwindow, z)         # 加窗
    specg[idx:] = np.log10(np.abs(np.fft.rfft(frame))) # FFT,返回幅度谱

specg = np.transpose(specg)
io.savemat('specgram.mat', {'specg':specg})

# aspect设为auto即可自动拉宽图
plt.imshow(specg, origin="lower", cmap = "jet", aspect = "auto", interpolation = "none")
plt.show()
plt.xticks([])
plt.yticks([])
plt.savefig('specgram.png',bbox_inches='tight',pad_inches=0.0)
plt.close()

在这里插入图片描述
再看看已经封装好的版本。

from scipy import io
from scipy.io import wavfile
import matplotlib.pyplot as plt

Fs, x = wavfile.read('audio.wav')    # 读取音频
specg = plt.specgram(x, Fs = Fs, pad_to = 256, NFFT = 256, noverlap = 128)    # 提取语谱图,一键操作!
io.savemat('specgram.mat', {'specg':specg[0]})    # 保存语谱图
## 照例解释下参数
# x,Fs和上边一样
# pad_to为上边的nfft
# NFFT为上边的windows_length(为什么nfft不设置为上边的nfft呢,迷惑)
# noverlap为上边的overlap_length

这里补充一点,语谱图根据带通滤波器的宽窄,可分为宽带语谱图和窄带语谱图。上图为窄带语谱图。
窄带语谱图,频率轴的分辨率较细,反映频谱的精细结构,可以看到很多“横杠”,“横杠”之间的距离就是基音频率;
宽带语谱图,频率轴的分辨率较粗,反映频谱的快速时变过程,可以看到很多细竖条,这些细条之间的距离就是基音周期。

3.3 补充一个librosa版本

librosa常提取梅尔频谱图,即在频谱图基础上再进一步将各帧通过梅尔滤波器(还可加对数操作)。另外若是在此基础上再进行倒谱即获得MFCC。
还要注意到,梅尔频谱图的输出尺寸,频率等于梅尔滤波器的个数n_mels, 时间则只取决于窗移(非重叠数)hop_length(还没想明白,推测可能是进行了填充,所以尺寸上忽视了窗长的影响)。
此外,还可通过设置power参数来确定要计算梅尔频谱图(设置为1)还是梅尔功率图(设置为2)。

from matplotlib import pyplot as plt
import librosa
import librosa.display


# Load a wav file
y, sr = librosa.load('./test.wav', sr=None)
# plot a wavform
plt.figure()
librosa.display.waveplot(y, sr)
# plt.plot(y)
plt.title('wavform')
plt.show()

# extract mel spectrogram feature
melspec = librosa.feature.melspectrogram(y, sr, n_fft=1024, win_length=1024, hop_length=512, n_mels=128, power=2.0)
# convert to log scale
logmelspec = librosa.power_to_db(melspec)
# plot mel spectrogram
plt.figure()
librosa.display.specshow(logmelspec, sr=sr, x_axis='time', y_axis='mel')
plt.title('spectrogram')
plt.show()

# aspect设为auto即可自动拉宽图
plt.imshow(logmelspec, origin="lower", cmap = "jet", aspect = "auto", interpolation = "none")
plt.show()
plt.xticks([])
plt.yticks([])
plt.savefig('specgram.png',bbox_inches='tight',pad_inches=0.0)
plt.close()

下图中,第一张是梅尔频谱图,第二张是梅尔功率图,功率图的声音和噪声区分更明显。而两者都比没有梅尔滤波器的频谱图有更独特明显的能量显示。
在这里插入图片描述
在这里插入图片描述

4. 语谱图的一些可能有的小疑惑

  1. 关于nfft
    nfft既表示时域的点数也关联频域的点数。该数为2的幂数时更高效,但不是也没问题。
    nfft需要比窗长的值更大,然后加窗后的帧会被补零到nfft长度再进行fft。
  2. 关于频率分辨率
    频率轴上每一个点对应fs/nfft的频率。另外由于输出nfft/2+1个频率点,所以输出的频率范围为0到nfft/2×fs/nfft=fs/2。
  3. 关于自定义输出语谱图的尺寸问题
    时间轴尺寸为1+fix((s-n)/h), 由windows_length和overlap_length决定。实际应用时由于各语音长度不同,时间尺寸一般都要进行截断或补零到一个固定值。截断的话可以截一段(起始信息,中间信息),也可以截多段(交叉不交叉都行)。
    频率轴尺寸为1+n/2,仅决定于nfft(python中的pad_to参数),所以可以通过设置该值控制频率轴尺寸。但是也不要比窗长大太多,否则补零太多可能就没什么信息了。nfft调大时,窗长可以跟着调大,为了防止导致的时间轴太短可以调高overlap_length。
    另外,其他参数不变时,仅变换nfft,可视化出来时可能肉眼看起来一样,但实际分辨率仍然是不同的。这也导致了一个问题,送入网络的是要用单通道的直接计算出来的语谱图,还是用可视化函数绘制出来的三通道的语谱图,这就根据实际情况去尝试了。
  • 13
    点赞
  • 97
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Python提取MFCC(Mel频率倒谱系数)可以使用一些库和函数来实现。一种常用的方法是使用Librosa库。以下是一个示例代码,展示了如何使用Librosa库来提取MFCC: ```python import librosa # 读取音频文件 audio_file = 'audio.wav' signal, sr = librosa.load(audio_file) # 提取MFCC特征 mfccs = librosa.feature.mfcc(signal, sr=sr, n_mfcc=12) # 可视化MFCC特征 librosa.display.specshow(mfccs, x_axis='time') plt.colorbar(format='%+2.0f dB') plt.title('MFCC') plt.show() ``` 在这个示例中,我们首先使用`librosa.load`函数读取音频文件,并将其存储在`signal`变量中。然后,我们使用`librosa.feature.mfcc`函数提取MFCC特征,其中`sr`参数是采样率,`n_mfcc`参数是要提取的MFCC系数的数量。最后,我们使用`librosa.display.specshow`函数将MFCC特征可视化出来。 请注意,这只是一个示例代码,你可以根据自己的需求进行调整和修改。同时,你也可以使用其他的音频处理库和函数来提取MFCC特征,如Python音频处理库`pyaudio`和`scipy`等。 #### 引用[.reference_title] - *1* [MFCC特征参数提取(一)(基于MATLABPython实现)](https://blog.csdn.net/qq_39516859/article/details/80505981)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [python提取语音信号MFCC](https://blog.csdn.net/YAOHAIPI/article/details/103548674)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值