梅尔频率倒谱系数(mfcc)及Python实现

语音识别系统的第一步是进行特征提取,mfcc是描述短时功率谱包络的一种特征,在语音识别系统中被广泛应用。

一、mel滤波器

每一段语音信号被分为多帧,每帧信号都对应一个频谱(通过FFT变换实现),频谱表示频率与信号能量之间的关系。mel滤波器是指多个带通滤波器,在mel频率中带通滤波器的通带是等宽的,但在赫兹(Hertz)频谱内mel滤波器在低频处较密集切通带较窄,高频处较稀疏且通带较宽,旨在通过在较低频率处更具辨别性并且在较高频率处较少辨别性来模拟非线性人类耳朵对声音的感知。

赫兹频率和梅尔频率之间的关系为:

假设在梅尔频谱内,有M 个带通滤波器Hm (k),0≤m<M,每个带通滤波器的中心频率为F(m) F(m)F(m)每个带通滤波器的传递函数为:

下图为赫兹频率内的mel滤波器,带通滤波器个数为24:

二、mfcc特征

MFCC系数提取步骤:

(1)语音信号分帧处理
(2)每一帧傅里叶变换---->功率谱
(3)将短时功率谱通过mel滤波器
(4)滤波器组系数取对数
(5)将滤波器组系数的对数进行离散余弦变换(DCT)
(6)一般将第2到底13个倒谱系数保留作为短时语音信号的特征

Python实现

import wave
import numpy as np
import math
import matplotlib.pyplot as plt
from scipy.fftpack import dct

def read(data_path):
 '''读取语音信号
 '''
 wavepath = data_path
 f = wave.open(wavepath,'rb')
 params = f.getparams()
 nchannels,sampwidth,framerate,nframes = params[:4] #声道数、量化位数、采样频率、采样点数
 str_data = f.readframes(nframes) #读取音频,字符串格式
 f.close()
 wavedata = np.fromstring(str_data,dtype = np.short) #将字符串转化为浮点型数据
 wavedata = wavedata * 1.0 / (max(abs(wavedata))) #wave幅值归一化
 return wavedata,nframes,framerate

def enframe(data,win,inc):
 '''对语音数据进行分帧处理
 input:data(一维array):语音信号
   wlen(int):滑动窗长
   inc(int):窗口每次移动的长度
 output:f(二维array)每次滑动窗内的数据组成的二维array
 '''
 nx = len(data) #语音信号的长度
 try:
  nwin = len(win)
 except Exception as err:
  nwin = 1
 if nwin == 1:
  wlen = win
 else:
  wlen = nwin
 nf = int(np.fix((nx - wlen) / inc) + 1) #窗口移动的次数
 f = np.zeros((nf,wlen)) #初始化二维数组
 indf = [inc * j for j in range(nf)]
 indf = (np.mat(indf)).T
 inds = np.mat(range(wlen))
 indf_tile = np.tile(indf,wlen)
 inds_tile = np.tile(inds,(nf,1))
 mix_tile = indf_tile + inds_tile
 f = np.zeros((nf,wlen))
 for i in range(nf):
  for j in range(wlen):
   f[i,j] = data[mix_tile[i,j]]
 return f

def point_check(wavedata,win,inc):
 '''语音信号端点检测
 input:wavedata(一维array):原始语音信号
 output:StartPoint(int):起始端点
   EndPoint(int):终止端点
 '''
 #1.计算短时过零率
 FrameTemp1 = enframe(wavedata[0:-1],win,inc)
 FrameTemp2 = enframe(wavedata[1:],win,inc)
 signs = np.sign(np.multiply(FrameTemp1,FrameTemp2)) # 计算每一位与其相邻的数据是否异号,异号则过零
 signs = list(map(lambda x:[[i,0] [i>0] for i in x],signs))
 signs = list(map(lambda x:[[i,1] [i<0] for i in x], signs))
 diffs = np.sign(abs(FrameTemp1 - FrameTemp2)-0.01)
 diffs = list(map(lambda x:[[i,0] [i<0] for i in x], diffs))
 zcr = list((np.multiply(signs, diffs)).sum(axis = 1))
 #2.计算短时能量
 amp = list((abs(enframe(wavedata,win,inc))).sum(axis = 1))
# # 设置门限
# print('设置门限')
 ZcrLow = max([round(np.mean(zcr)*0.1),3])#过零率低门限
 ZcrHigh = max([round(max(zcr)*0.1),5])#过零率高门限
 AmpLow = min([min(amp)*10,np.mean(amp)*0.2,max(amp)*0.1])#能量低门限
 AmpHigh = max([min(amp)*10,np.mean(amp)*0.2,max(amp)*0.1])#能量高门限
 # 端点检测
 MaxSilence = 8 #最长语音间隙时间
 MinAudio = 16 #最短语音时间
 Status = 0 #状态0:静音段,1:过渡段,2:语音段,3:结束段
 HoldTime = 0 #语音持续时间
 SilenceTime = 0 #语音间隙时间
 print('开始端点检测')
 StartPoint = 0
 for n in range(len(zcr)):
  if Status ==0 or Status == 1:
   if amp[n] > AmpHigh or zcr[n] > ZcrHigh:
    StartPoint = n - HoldTime
    Status = 2
    HoldTime = HoldTime + 1
    SilenceTime = 0
   elif amp[n] > AmpLow or zcr[n] > ZcrLow:
    Status = 1
    HoldTime = HoldTime + 1
   else:
    Status = 0
    HoldTime = 0
  elif Status == 2:
   if amp[n] > AmpLow or zcr[n] > ZcrLow:
    HoldTime = HoldTime + 1
   else:
    SilenceTime = SilenceTime + 1
    if SilenceTime < MaxSilence:
     HoldTime = HoldTime + 1
    elif (HoldTime - SilenceTime) < MinAudio:
     Status = 0
     HoldTime = 0
     SilenceTime = 0
    else:
     Status = 3
  elif Status == 3:
   break
  if Status == 3:
   break
 HoldTime = HoldTime - SilenceTime
 EndPoint = StartPoint + HoldTime
 return FrameTemp1[StartPoint:EndPoint]

def mfcc(FrameK,framerate,win):
 '''提取mfcc参数
 input:FrameK(二维array):二维分帧语音信号
   framerate:语音采样频率
   win:分帧窗长(FFT点数)
 output:
 '''
 #mel滤波器
 mel_bank,w2 = mel_filter(24,win,framerate,0,0.5)
 FrameK = FrameK.T
 #计算功率谱
 S = abs(np.fft.fft(FrameK,axis = 0)) ** 2
 #将功率谱通过滤波器
 P = np.dot(mel_bank,S[0:w2,:])
 #取对数
 logP = np.log(P)
 #计算DCT系数
# rDCT = 12
# cDCT = 24
# dctcoef = []
# for i in range(1,rDCT+1):
#  tmp = [np.cos((2*j+1)*i*math.pi*1.0/(2.0*cDCT)) for j in range(cDCT)]
#  dctcoef.append(tmp)
# #取对数后做余弦变换
# D = np.dot(dctcoef,logP)
 num_ceps = 12
 D = dct(logP,type = 2,axis = 0,norm = 'ortho')[1:(num_ceps+1),:]
 return S,mel_bank,P,logP,D

def mel_filter(M,N,fs,l,h):
 '''mel滤波器
 input:M(int):滤波器个数
   N(int):FFT点数
   fs(int):采样频率
   l(float):低频系数
   h(float):高频系数
 output:melbank(二维array):mel滤波器
 '''
 fl = fs * l #滤波器范围的最低频率
 fh = fs * h #滤波器范围的最高频率
 bl = 1125 * np.log(1 + fl / 700) #将频率转换为mel频率
 bh = 1125 * np.log(1 + fh /700)
 B = bh - bl #频带宽度
 y = np.linspace(0,B,M+2) #将mel刻度等间距
 print('mel间隔',y)
 Fb = 700 * (np.exp(y / 1125) - 1) #将mel变为HZ
 print(Fb)
 w2 = int(N / 2 + 1)
 df = fs / N
 freq = [] #采样频率值
 for n in range(0,w2):
  freqs = int(n * df)
  freq.append(freqs)
 melbank = np.zeros((M,w2))
 print(freq)

 for k in range(1,M+1):
  f1 = Fb[k - 1]
  f2 = Fb[k + 1]
  f0 = Fb[k]
  n1 = np.floor(f1/df)
  n2 = np.floor(f2/df)
  n0 = np.floor(f0/df)
  for i in range(1,w2):
   if i >= n1 and i <= n0:
    melbank[k-1,i] = (i-n1)/(n0-n1)
   if i >= n0 and i <= n2:
    melbank[k-1,i] = (n2-i)/(n2-n0)
  plt.plot(freq,melbank[k-1,:])
 plt.show()
 return melbank,w2

if __name__ == '__main__':
 data_path = 'audio_data.wav'
 win = 256
 inc = 80
 wavedata,nframes,framerate = read(data_path)
 FrameK = point_check(wavedata,win,inc)
 S,mel_bank,P,logP,D = mfcc(FrameK,framerate,win)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • python语音识别实践之百度语音API

    百度语音对上传的语音要求目前必须是单声道,16K采样率,采样深度可以是16位或者8位的PCM编码.其他编码输出的语音识别不出来. 语音的处理技巧: 录制为MP3的语音(通常采样率为44100),要分两步才能正确处理.第一步:使用诸如GoldWave的软件,先保存为16K采样率的MP3:第二步,打开16K采样率的MP3,另存为Wav格式,参数选择PCM,单声道即可. 另外,也可以使用ffmpeg将MP3处理为PCM.后文的程序即采用这种方法. 由于PCM编码的语音没有压缩,文件体积与语音长度成正比

  • python调用百度REST API实现语音识别

    目前,语音识别,即将语音内容转换为文字的技术已经比较成熟,遥想当时锤子发布会上展示的讯飞输入法语音识别,着实让讯飞火了一把.由于此类语音识别需要采集大量的样本,才能达到一定的准确度,个人很难从零开始搭建.但是,许多拥有语音识别技术的公司,或多或少会提供一些API或者SDK供开发者使用,这样就把语音识别的门槛降到了一个很低的程度,只需几行代码即可实现.下面我介绍以下如何使用Python调用百度的REST API实现一个简单的语音识别. 注册账号,并成为开发者 打开 http://yuyin.bai

  • 利用python提取wav文件的mfcc方法

    如下所示: import scipy.io.wavfile as wav from python_speech_features import mfcc fs, audio = wav.read("abc.wav") feature_mfcc = mfcc(audio, samplerate=fs) print(feature_mfcc) print(feature_mfcc.shape) 注:python_speech_features 不存在, 通过 pip install pyt

  • python调用百度语音识别api

    最近在处理语音检索相关的事. 其中用到语音识别,调用的是讯飞与百度的api,前者使用js是实现,后者用python3实现(因为自己使用python) 环境: python3.5 centos 7 流程 整个百度语音识别rest api 使用分为三部分: 1 (申请操作)创建应用,获取应用的 API Key 以及 Secret Key. 2 (程序实现)通过已知的 应用的 API Key 以及 Secret Key, 发送post 请求到 https://openapi.baidu.com/oau

  • Python实现简单的语音识别系统

    最近认识了一个做Python语音识别的朋友,聊天时候说到,未来五到十年,Python人工智能会在国内掀起一股狂潮,对各种应用的冲击,不下于淘宝对实体经济的冲击.在本地(江苏某三线城市)做这一行,短期可能显不出效果,但从长远来看,绝对是一个高明的选择.朋友老家山东的,毕业来这里创业,也是十分有想法啊. 将AI课上学习的知识进行简单的整理,可以识别简单的0-9的单个语音.基本方法就是利用库函数提取mfcc,然后计算误差矩阵,再利用动态规划计算累积矩阵.并且限制了匹配路径的范围.具体的技术网上很多,不

  • Python语言实现百度语音识别API的使用实例

    未来的一段时间,人工智能在市场上占有很重的位置,Python语言则是研究人工智能的最佳编程语言,下面,就让我们来感受一下它的魅力吧! 百度给的样例程序,不论C还是Java版,都分为method1和method2两种 前者称为隐式(post的是json串,音频数据编码到json里),后者称为显式(post的就是音频数据) 一开始考虑到pythonwave包处理的都是"字符串",担心跟C语言的数组不一致,所以选择低效但保险的method1, 即先将音频数据base64编码,再加上采样率.通

  • 对python中Librosa的mfcc步骤详解

    1.对语音数据归一化 如16000hz的数据,会将每个点/32768 2.计算窗函数:(*注意librosa中不进行预处理) 3.进行数据扩展填充,他进行的是镜像填充("reflect") 如原数据为 12345 -> 填充为4的,左右各填充4 即:5432123454321 即:5432-12345-4321 4.分帧 5.加窗:对每一帧进行加窗, 6.进行fft傅里叶变换 librosa中fft计算,可以使用.net中的System.Numerics MathNet.Nume

  • 对Python使用mfcc的两种方式详解

    1.Librosa import librosa filepath = "/Users/birenjianmo/Desktop/learn/librosa/mp3/in.wav" y,sr = librosa.load(filepath) mfcc = librosa.feature.mfcc( y,sr,n_mfcc=13 ) 返回结构为(13,None)的np.Array,None表示任意数量 2.python_speech_features from python_speech_

  • python实现百度语音识别api

    本文实例为大家分享了ython实现百度语音识别的具体代码,供大家参考,具体内容如下 详细百度语音识别api文档 先下载python用SDK,可以用python setup.py install安装 # 引入Speech SDK from aip import AipSpeech # 定义常量 APP_ID = '你的 App ID' API_KEY = '你的 API Key' SECRET_KEY = '你的 Secret Key' # 初始化AipSpeech对象 aipSpeech = A

  • python调用百度语音识别实现大音频文件语音识别功能

    本文为大家分享了python实现大音频文件语音识别功能的具体代码,供大家参考,具体内容如下 实现思路:先用ffmpeg将其他非wav格式的音频转换为wav格式,并转换音频的声道(百度支持声道为1),采样率(值为8000),格式转换完成后,再用ffmpeg将音频切成百度. 支持的时长(30秒和60秒2种,本程序用的是30秒). # coding: utf-8 import json import time import base64 from inc import rtysdb import ur

随机推荐