文章正文
使用Python进行语音识别三
最后的语音识别
本来想发完第二篇的时候就隔天发第三篇的,但是发现一个问题要想使用K临近需要具有相同的向量长度,这个问题想了一天,本来想定一个标准的长度,然后用线性插值(采样频率比较高所以影响不大,采样率低时可以使用非线性插值),但是算法写了一天,最后发现scipy中有这个库,代码如下,白写了很大的一段代码。
def normal_time(data,windowsNum): '''规整到的窗口数目''' voiceLen=windows*windowsNum x=np.linspace(0,voiceLen,len(data)) f_linear = interpolate.interp1d(x, data) result=f_linear(range(voiceLen)) return result
第二点要说明一下,上一篇文章中的一个问题,那就是在得mel频率间隔的时候的frequency的选取,这个频率最好是16000左右,因为声音的信息基本在这个以下,如果选取的太高,反而会使加入噪声频率,使得有效频率被淹没。
第三就是要获得MFCC系数了,这个就是按照论文中的算法做了:
1、 对窗口做FFT,取模
2、 通过mel滤波器
3、 取对数,做DCT
def get_MFCC(mel,data,windows,vec): for i in range(windowsNum): yn=data[i*windows:(i+1)*windows] #pl.plot(range(len(yn)),yn) #pl.show() #print 'yn',len(yn) ssn=np.fft.fft(yn) sn=[] for tmp in ssn: sn.append((tmp*tmp.conjugate()).real) vectmp=[] for j in xrange(filterNum): sum=0 for k in range(len(sn)): fs=k*samprate*1.0/(len(sn)-1) #if j==3: # print 'fs',fs,sn[k],mel[0][j],mel[1][j],mel[2][j] if mel[0][j]<fs and fs<mel[1][j]: sum+=sn[k]*(fs-mel[0][j])/(mel[1][j]-mel[0][j]) elif mel[1][j]<fs and fs<mel[2][j]: sum+=sn[k]*(fs-mel[1][j])/(mel[2][j]-mel[1][j]) vectmp.append(np.log(sum)) for tt in fftpack.dct(vectmp,norm='ortho')[1:]: #print tt vec.append(tt)
最后要说的是训练了,这个倒是没什么,直接贴代码:
sample0vec=[] for jj in xrange(42): print 'excise0:',str(jj) wf=wave.open(str(jj)+"_00.wav",'rb') nchannels,sampwidth,framerate,nframes=wf.getparams()[:4] str_data=wf.readframes(nframes) wave_data1=np.fromstring(str_data,dtype=np.short) wave_data=normal_time(wave_data1,windowsNum) maxvalue=max(wave_data) data=normalization(wave_data,maxvalue) vec=[] get_MFCC(mel,data,windows,vec) sample0vec.append(vec)
当然识别和训练的代码一样就是,多加一个欧氏距离的判断,如下
distsum0=0 for j in xrange(len(sample0vec)): dist=np.linalg.norm(np.array(sample0vec[j]) - np.array(voicevec)) distsum0+=dist #print '0 dist:',distsum0 plotvalue0.append(distsum0/len(sample0vec)) distsum1=0 for j in xrange(len(sample1vec)): dist=np.linalg.norm(np.array(sample1vec[j]) - np.array(voicevec)) distsum1+=dist #print '1 dist:' ,distsum1 plotvalue1.append(distsum1/len(sample1vec)) if distsum1/len(sample1vec)>distsum0/len(sample0vec): print 'voice is : 0' else: print 'voice is : 1' num=raw_input("input right num:") print 'you input:',int(num) if int(num)==1: sample1vec.append(voicevec) else: sample0vec.append(voicevec)
现在看看我识别的效果吧,这是我识别0和1的效果,由于样本不多只有40个,基本上在刚开始识别的时候可能出错,但是看到上面的代码有一定的自学习的功能(比较烂),所以在识别20个左右的时候基本可以达到95%。还有一个要注意的地方,就是滤波器数目窗口大小,以及规整到窗口数目的设定,一般滤波器设的越多越准但是计算量越大,窗口大小不要太大或太小,一般根据采样频率设定,一个窗口要包含一个正弦,规整到的窗口数目也要做相应的变化。下面是我的设定:采样频率是44100,filterNum=32、windows=1024、windowsNum=16
April 12, 2015, 10:24 p.m. 作者:zachary 分类:语音识别 阅读(1690) 评论(0)