最新文章專題視頻專題問答1問答10問答100問答1000問答2000關(guān)鍵字專題1關(guān)鍵字專題50關(guān)鍵字專題500關(guān)鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關(guān)鍵字專題關(guān)鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
當(dāng)前位置: 首頁 - 科技 - 知識百科 - 正文

python利用不到一百行代碼實現(xiàn)一個小siri

來源:懂視網(wǎng) 責(zé)編:小采 時間:2020-11-27 14:12:56
文檔

python利用不到一百行代碼實現(xiàn)一個小siri

python利用不到一百行代碼實現(xiàn)一個小siri:這篇文章主要介紹了關(guān)于python利用不到一百行代碼實現(xiàn)了一個小siri的相關(guān)資料,文中介紹的很詳細(xì),對大家具有一定的參考借鑒價值,需要的朋友們下面來一起看看吧。前言如果想要容易理解核心的特征計算的話建議先去看看我之前的聽歌識曲的文章,傳送門:htt
推薦度:
導(dǎo)讀python利用不到一百行代碼實現(xiàn)一個小siri:這篇文章主要介紹了關(guān)于python利用不到一百行代碼實現(xiàn)了一個小siri的相關(guān)資料,文中介紹的很詳細(xì),對大家具有一定的參考借鑒價值,需要的朋友們下面來一起看看吧。前言如果想要容易理解核心的特征計算的話建議先去看看我之前的聽歌識曲的文章,傳送門:htt
這篇文章主要介紹了關(guān)于python利用不到一百行代碼實現(xiàn)了一個小siri的相關(guān)資料,文中介紹的很詳細(xì),對大家具有一定的參考借鑒價值,需要的朋友們下面來一起看看吧。

前言

如果想要容易理解核心的特征計算的話建議先去看看我之前的聽歌識曲的文章,傳送門:http://www.gxlcms.com/article/97305.htm

本文主要是實現(xiàn)了一個簡單的命令詞識別程序,算法核心一是提取音頻特征,二是用DTW算法進(jìn)行匹配。當(dāng)然,這樣的代碼肯定不能用于商業(yè)化,大家做出來玩玩娛樂一下還是不錯的。

設(shè)計思路

就算是個小東西,我們也要先明確思路再做。音頻識別,困難不小,其中提取特征的難度在我聽歌識曲那篇文章里能看得出來。而語音識別難度更大,因為音樂總是固定的,而人類說話常常是變化的。比如說一個“芝麻開門”,有的人就會說成“芝麻開門”,有的人會說成“芝麻開門”。而且在錄音時說話的時間也不一樣,可能很緊迫的一開始錄音就說話了,也可能不緊不慢的快要錄音結(jié)束了才把這四個字說出來。這樣難度就大了。

算法流程:


特征提取

和之前的聽歌識曲一樣,同樣是將一秒鐘分成40塊,對每一塊進(jìn)行傅里葉變換,然后取模長。只是這不像之前聽歌識曲中進(jìn)一步進(jìn)行提取峰值,而是直接當(dāng)做特征值。

看不懂我在說什么的朋友可以看看下面的源代碼,或者看聽歌識曲那篇文章。

DTW算法

DTW,Dynamic Time Warping,動態(tài)時間歸整。算法解決的問題是將不同發(fā)音長短和位置進(jìn)行最適合的匹配。

算法輸入兩組音頻的特征向量: A:[fp1,fp2,fp3,......,fpM1] B:[fp1,fp2,fp3,fp4,.....fpM2]
A組共有M1個特征,B組共有M2個音頻。每個特征向量中的元素就是之前我們將每秒切成40塊之后FFT求模長的向量。計算每對fp之間的代價采用的是歐氏距離。

設(shè)D(fpa,fpb)為兩個特征的距離代價。

那么我們可以畫出下面這樣的圖

我們需要從(1,1)點走到(M1,M2)點,這會有很多種走法,而每種走法就是一種兩個音頻位置匹配的方式。但我們的目標(biāo)是走的總過程中代價最小,這樣可以保證這種對齊方式是使我們得到最接近的對齊方式。

我們這樣走:首先兩個坐標(biāo)軸上的各個點都是可以直接計算累加代價和求出的。然后對于中間的點來說D(i,j) = Min{D(i-1,j)+D(fpi,fpj) , D(i,j-1)+D(fpi,fpj) , D(i-1,j-1) + 2 * D(fpi,fpj)}

為什么由(i-1,j-1)直接走到(i,j)這個點需要加上兩倍的代價呢?因為別人走正方形的兩個直角邊,它走的是正方形的對角線啊

按照這個原理選擇,一直算到D(M1,M2),這就是兩個音頻的距離。

源代碼和注釋

# coding=utf8
import os
import wave
import dtw
import numpy as np
import pyaudio

def compute_distance_vec(vec1, vec2):
 return np.linalg.norm(vec1 - vec2) #計算兩個特征之間的歐氏距離

class record():
 def record(self, CHUNK=44100, FORMAT=pyaudio.paInt16, CHANNELS=2, RATE=44100, RECORD_SECONDS=200,
 WAVE_OUTPUT_FILENAME="record.wav"):
 #錄歌方法
 p = pyaudio.PyAudio()
 stream = p.open(format=FORMAT,
 channels=CHANNELS,
 rate=RATE,
 input=True,
 frames_per_buffer=CHUNK)
 frames = []
 for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
 data = stream.read(CHUNK)
 frames.append(data)
 stream.stop_stream()
 stream.close()
 p.terminate()
 wf = wave.open(WAVE_OUTPUT_FILENAME, 'wb')
 wf.setnchannels(CHANNELS)
 wf.setsampwidth(p.get_sample_size(FORMAT))
 wf.setframerate(RATE)
 wf.writeframes(''.join(frames))
 wf.close()

class voice():
 def loaddata(self, filepath):
 try:
 f = wave.open(filepath, 'rb')
 params = f.getparams()
 self.nchannels, self.sampwidth, self.framerate, self.nframes = params[:4]
 str_data = f.readframes(self.nframes)
 self.wave_data = np.fromstring(str_data, dtype=np.short)
 self.wave_data.shape = -1, self.sampwidth
 self.wave_data = self.wave_data.T #存儲歌曲原始數(shù)組
 f.close()
 self.name = os.path.basename(filepath) # 記錄下文件名
 return True
 except:
 raise IOError, 'File Error'

 def fft(self, frames=40):
 self.fft_blocks = [] #將音頻每秒分成40塊,再對每塊做傅里葉變換
 blocks_size = self.framerate / frames
 for i in xrange(0, len(self.wave_data[0]) - blocks_size, blocks_size):
 self.fft_blocks.append(np.abs(np.fft.fft(self.wave_data[0][i:i + blocks_size])))
 @staticmethod
 def play(filepath):
 chunk = 1024
 wf = wave.open(filepath, 'rb')
 p = pyaudio.PyAudio()
 # 播放音樂方法
 stream = p.open(format=p.get_format_from_width(wf.getsampwidth()),
 channels=wf.getnchannels(),
 rate=wf.getframerate(),
 output=True)
 while True:
 data = wf.readframes(chunk)
 if data == "": break
 stream.write(data)
 stream.close()
 p.terminate()
if __name__ == '__main__':
 r = record()
 r.record(RECORD_SECONDS=3, WAVE_OUTPUT_FILENAME='record.wav')
 v = voice()
 v.loaddata('record.wav')
 v.fft()
 file_list = os.listdir(os.getcwd())
 res = []
 for i in file_list:
 if i.split('.')[1] == 'wav' and i.split('.')[0] != 'record':
 temp = voice()
 temp.loaddata(i)
 temp.fft()
 res.append((dtw.dtw(v.fft_blocks, temp.fft_blocks, compute_distance_vec)[0],i))
 res.sort()
 print res
 if res[0][1].find('open_qq') != -1:
 os.system('C:programTencentQQBinQQScLauncher.exe') #我的QQ路徑
 elif res[0][1].find('zhimakaimen') != -1:
 os.system('chrome.exe')#瀏覽器的路徑,之前已經(jīng)被添加到了Path中了
 elif res[0][1].find('play_music') != -1:
 voice.play('C:datamusic\audio\audio\ (9).wav') #播放一段音樂
 # r = record()
 # r.record(RECORD_SECONDS=3,WAVE_OUTPUT_FILENAME='zhimakaimen_09.wav')

事先可以先用這里的record方法錄制幾段命令詞,嘗試用不同語氣說,不同節(jié)奏說,這樣可以提高準(zhǔn)確度。然后設(shè)計好文件名,根據(jù)匹配到的最接近音頻的文件名就可以知道是哪種命令,進(jìn)而自定義執(zhí)行不同的任務(wù)

這是一段演示視頻:http://www.iqiyi.com/w_19ruisynsd.html

聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

文檔

python利用不到一百行代碼實現(xiàn)一個小siri

python利用不到一百行代碼實現(xiàn)一個小siri:這篇文章主要介紹了關(guān)于python利用不到一百行代碼實現(xiàn)了一個小siri的相關(guān)資料,文中介紹的很詳細(xì),對大家具有一定的參考借鑒價值,需要的朋友們下面來一起看看吧。前言如果想要容易理解核心的特征計算的話建議先去看看我之前的聽歌識曲的文章,傳送門:htt
推薦度:
標(biāo)簽: 一個 實現(xiàn) 代碼
  • 熱門焦點

最新推薦

猜你喜歡

熱門推薦

專題
Top