文章正文
使用Python进行语音识别三
最后的语音识别
本来想发完第二篇的时候就隔天发第三篇的,但是发现一个问题要想使用K临近需要具有相同的向量长度,这个问题想了一天,本来想定一个标准的长度,然后用线性插值(采样频率比较高所以影响不大,采样率低时可以使用非线性插值),但是算法写了一天,最后发现scipy中有这个库,代码如下,白写了很大的一段代码。
1 2 3 4 5 6 7 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 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) |
最后要说的是训练了,这个倒是没什么,直接贴代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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) |
当然识别和训练的代码一样就是,多加一个欧氏距离的判断,如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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 分类:语音识别 阅读(1841) 评论(0)
评论: