深度學(xué)習(xí)和機器學(xué)習(xí)在圖像和視覺方面有很多的研究,而且取得了很好的效果,但是在音頻處理方面還是比較弱,還有很大的提升空間。圖像上有openCV這個強大的庫,而在音頻方面有哪些比較合適的庫呢?這里說的是python支持的庫,因為本人接觸的主要還是python。所以今天就介紹一下python處理音頻的庫。 進入正題:Python有一些很棒的音頻處理庫,比如Librosa和PyAudio,今天著重學(xué)習(xí)一下librosa庫,這個庫的安裝非常簡單,和其它庫安裝一樣,直接pip install librosa就行了。以下代碼在jupyter notebook中完成。 In[1]: import librosa as lr audio_path = './data/js.wav' x, sr = lr.load(audio_path) #sr-sample rate采樣率 print(type(x),type(sr)) print(x.shape,sr) Out[2]: <class 'numpy.ndarray'> <class 'int'> (127200,) 22050 #這會將音頻時間序列作為numpy數(shù)組返回,默認采樣率sr為22KHZ mono我們可以通過以下方式更改: lr.load(audio_path, sr = 44100) #以44.1KHZ重新采樣,或者禁重新采樣。采樣率是每秒傳輸?shù)囊纛l樣本數(shù)。 lr.load(audio_path, sr=None) Out[3]: (array([-3.0517578e-04, -2.7465820e-04, -3.6621094e-04, ..., -1.2207031e-04, -9.1552734e-05, -9.1552734e-05], dtype=float32), 44100) In [4]: #使用Ipython.display.Audio播放音頻 import IPython.display as ipd ipd.Audio(audio_path) 可視化音頻: 可視化音頻的目的主要讓你更直觀的理解音頻特征 In [5]: #波形:我們可以繪制音頻數(shù)組librosa.display.waveplot: %matplotlib inline import matplotlib.pyplot as plt import librosa.display plt.figure(figsize = (14,5)) librosa.display.waveplot(x, sr = sr) <matplotlib.collections.PolyCollection at 0x1fac21 In[8] #譜圖:譜圖是通過視覺表示頻譜的頻率,聲音或其它信號,因為它隨時間變化。頻譜圖有時被稱為聲紋或語音圖。當(dāng)數(shù)據(jù)在3D中表示時,它們可以稱為waterfalls。 #在二維陣列中,第一軸是頻率,第二軸是時間。我們可以使用顯示頻譜圖:librosa.display.specshow: X = librosa.stft(x) #對信號進行短時傅里葉變換 Xdb = librosa.amplitude_to_db(abs(X)) plt.figure(figsize=(14,5)) librosa.display.specshow(Xdb, sr=sr, x_axis='time', y_axis='hz') plt.colorbar() <matplotlib.colorbar.Colorbar at 0x1fac2234c50> In[9] #從軸表示頻率(從0到10kHZ),橫軸表示剪輯的時間,由于我們看到的所有動作都發(fā)生在頻譜的底部,我們可以將頻譜軸轉(zhuǎn)換為對數(shù)軸。 plt.figure(figsize=(14,5)) librosa.display.specshow(Xdb, sr=sr, x_axis='time', y_axis='log') plt.colorbar() <matplotlib.colorbar.Colorbar at 0x1fac5077080> In[10]: #寫音頻:librosa.output.write_wav 將Numpy數(shù)組保存到wav文件, 下面舉例說明它的用法。 librosa.output.write_wav('example.wav', x, sr) #創(chuàng)建音頻信號:現(xiàn)在讓我們創(chuàng)建一個220Hz的音頻信號,音頻信號是一個numpy數(shù)組,所以我們將創(chuàng)建一個并將其傳遞給音頻函數(shù) import numpy as np #sample rate sr = 22050 #seconds T = 5.0 #time variable,linspace()產(chǎn)生一個固定間隔的一個序列的一維數(shù)組 t = np.linspace(0, T, int(T*sr), endpoint=False) #pure sine wave at 220Hz x = 0.5*np.sin(2*np.pi*220*t) #播放這個音頻 ipd.Audio(x, rate=sr) In [11 ]: #保存這個音頻信號 librosa.output.write_wav('tone_220.wav', x, sr) 音頻特征提?。?/strong> 每個音頻信號都包含許多特征。但是,我們必須提取與我們試圖解決的問題相關(guān)的特征,提取要使用它們進行分析的特征的過程稱為特征提取 接下來我們詳細了解一下我們感興趣的特征: 過零率: 該特征在語音識別和音樂信息檢索中被經(jīng)常使用。 過零率(Zero Crossing Rate,ZCR)是指在每幀中,語音信號通過零點(從正變?yōu)樨摶驈呢撟優(yōu)檎┑拇螖?shù)。 這個特征已在語音識別和音樂信息檢索領(lǐng)域得到廣泛使用,比如敲擊聲音的分類,過零率是分類的關(guān)鍵特征。 特性: 一般而言,清音(unvoiced sound)和環(huán)境噪音的ZCR都大于濁音(voiced sound);由于清音和環(huán)境噪音的ZCR大小相近,因而不能夠通過ZCR來區(qū)分它們;在實際當(dāng)中,過零率經(jīng)常與短時能量特性相結(jié)合來進行端點檢測,尤其是ZCR用來檢測清音的起止點;有時也可以用ZCR來進行粗略的基頻估算,但這是非常不可靠的,除非有后續(xù)的修正(refine)處理過程。 那我們看看如何計算音頻片段的過零率: In [12]: #過零率的計算 #導(dǎo)入音頻文件 x, sr = librosa.load('./data/js.wav') plt.figure(figsize=(14,5)) librosa.display.waveplot(x, sr=sr) #放大局部查看 n0 = 9000 n1 = 9100 plt.figure(figsize=(14,5)) plt.plot(x[n0:n1]) plt.grid() #這里舉一個不需要librosa庫來實現(xiàn)過零率的計算方法 import math import numpy as np def ZeroCR(waveData,frameSize,overLap): wlen = len(waveData) step = frameSize - overLap frameNum = math.ceil(wlen/step) zcr = np.zeros((frameNum,1)) for i in range(frameNum): curFrame = waveData[np.arange(i*step,min(i*step+frameSize,wlen))] curFrame = curFrame - np.mean(curFrame) # 過零點判斷 zcr[i] = sum(curFrame[0:-1]*curFrame[1::]<=0) return zcr #通過上面定義的函數(shù)來計算過零率 import math import wave import numpy as np import pylab as pl # ============ 測試一下算法 ============= # 讀取音頻 fw = wave.open('./data/js.wav','rb') params = fw.getparams() print(params) nchannels, sampwidth, framerate, nframes = params[:4] str_data = fw.readframes(nframes) wave_data = np.frombuffer(str_data, dtype=np.short) wave_data.shape = -1, 1 #wave_data = wave_data.T fw.close() # 計算過零率 frameSize = 256 overLap = 0 zcr = ZeroCR(wave_data,frameSize,overLap) # 可視化結(jié)果 time = np.arange(0, len(wave_data)) * (1.0 / framerate) time2 = np.arange(0, len(zcr)) * (len(wave_data)/len(zcr) / framerate) pl.figure(figsize=(14,10)) pl.subplot(211) pl.plot(time, wave_data) pl.ylabel('Amplitude') pl.subplot(212) pl.plot(time2, zcr) pl.ylabel('ZCR') pl.xlabel('time (seconds)') pl.show() _wave_params(nchannels=1, sampwidth=2, framerate=4 In[13]: #驗證一下有幾個過零點, 本例中的片段含有3個 zero_crossings = librosa.zero_crossings(x[n0:n1], pad=False) print(sum(zero_crossings)) 3 光譜質(zhì)心: 譜質(zhì)心(Spectral Centroid)是描述音色屬性的重要物理參數(shù)之一,是頻率成分的重心,是在一定頻率范圍內(nèi)通過能量加權(quán)平均的頻率,其單位是Hz。它是聲音信號的頻率分布和能量分布的重要信息。在主觀感知領(lǐng)域,譜質(zhì)心描述了聲音的明亮度,具有陰暗、低沉品質(zhì)的聲音傾向有較多低頻內(nèi)容,譜質(zhì)心相對較低,具有明亮、歡快品質(zhì)的多數(shù)集中在高頻,譜質(zhì)心相對較高。該參數(shù)常用于對樂器聲色的分析研究。 如果有兩首曲子,一首來自布魯斯類型,另一首屬于金屬。與長度相同的布魯斯流派歌曲相比,金屬歌曲在最后有更多的頻率。因此,布魯斯歌曲的光譜質(zhì)心將位于其光譜中間附近,而金屬歌曲的光譜質(zhì)心將朝向它的末端。 librosa.feature.spectral_centroid計算信號中每幀的光譜質(zhì)心: In [14]: #計算光譜質(zhì)心 spectral_centroids = librosa.feature.spectral_centroid(x, sr=sr)[0] spectral_centroids.shape (249,) In [15]: #可視化每一幀的質(zhì)心 import sklearn frames = range(len(spectral_centroids)) t = librosa.frames_to_time(frames) #歸一化光譜質(zhì)心 def normalize(x, axis=0): return sklearn.preprocessing.minmax_scale(x, axis=axis) #沿著音頻波形繪制光譜質(zhì)心 plt.figure(figsize=(14,5)) librosa.display.waveplot(x, sr=sr, alpha=0.4) plt.plot(t, normalize(spectral_centroids), color='r') [<matplotlib.lines.Line2D at 0x1fac68cfef0>] 光譜衰減: 它是信號形狀的度量。librosa.feature.spectral_rolloff計算信號中每幀的滾降系數(shù): In [16]: #計算光譜衰減: spectral_rolloff = librosa.feature.spectral_rolloff(x+0.01, sr=sr)[0] plt.figure(figsize=(14,5)) librosa.display.waveplot(x, sr=sr, alpha=0.4) plt.plot(t, normalize(spectral_rolloff), color='r') [<matplotlib.lines.Line2D at 0x1fac6855748>] 梅爾頻率倒譜系數(shù): 聲音信號是連續(xù)變化的,為了將連續(xù)變化信號簡化,我們假設(shè)在一個短時間尺度內(nèi),音頻信號不發(fā)生改變。因此將信號以多個采樣點集合成一個單位,稱為'''訊框'''。一個訊框多為20-40毫秒,如果訊框長度更短,那每個訊框內(nèi)的采樣點將不足以做出可靠的頻譜計算,但若長度太長,則每個訊框信號會變化太大。 預(yù)強化的目的就是為了消除發(fā)聲過程中,聲帶和嘴唇造成的效應(yīng),來補償語音信號受到發(fā)音系統(tǒng)所壓抑的高頻部分。并且能突顯高頻的共振峰。 由于信號在時域上的變化通常很難看出信號的特性,所以通常透過傅里葉變換將它變換成頻域上的能量分布來觀察,不同的能量分布,就能代表不同語音的特性。 由于能量頻譜中還存在大量的無用訊息,尤其人耳無法分辨高頻的頻率變化,因此讓頻譜通過梅爾濾波器。梅爾濾波器,也就是一組20個非線性分布的三角帶通濾波器(Triangular Bandpass Filters),能求得每一個濾波器輸出的對數(shù)能量。必須注意的是:這 20 個三角帶通濾波器在'''梅爾刻度'''的頻率上是平均分布的。 梅爾頻率代表一般人耳對于頻率的感受度,由此也可以看出人耳對于頻率 f 的感受是呈對數(shù)變化的。 MFCC特征在加性噪聲的情況下并不穩(wěn)定,因此在語音識別系統(tǒng)中通常要對其進行歸一化處理(normalise)以降低噪聲的影響。一些研究人員對MFCC算法進行修改以提升其魯棒性,如在進行DCT之前將log-mel-amplitudes提升到一個合適的能量(2到3之間),以此來降低低能量成分的影響。 信號的Mel頻率倒譜系數(shù)(MFCC)是一小組特征(通常約10-20),其簡明地描述了頻譜包絡(luò)的整體形狀,它模擬了人聲的特征。 In [17]: #MFCC計算 x, sr = librosa.load('./data/js.wav') #通過音頻信號計算MFCC mfccs = librosa.feature.mfcc(x, sr=sr) print(mfccs.shape) (20, 249) In [18]: #顯示MFCC圖譜 plt.figure(figsize=(14,5)) librosa.display.specshow(mfccs, sr=sr, x_axis='time') <matplotlib.axes._subplots.AxesSubplot at 0x1fac51 In[19]: #以上計算了249幀的20個MFCC。我們還可以執(zhí)行特征縮放,使得每個系數(shù)維度具有零均值和單位方差: #import sklearn mfccs = sklearn.preprocessing.scale(mfccs, axis=1) print(mfccs.mean(axis=1)) print(mfccs.var(axis=1)) plt.figure(figsize=(14,5)) librosa.display.specshow(mfccs, sr=sr, x_axis='time') [-4.3087693e-09 1.9150086e-09 -4.7875215e-09 -1.1968804e-10 -4.2489257e-09 5.7929011e-08 -9.5750430e-09 4.5481454e-09 2.3937607e-09 1.6905936e-09 4.7875215e-09 -6.8222183e-09 4.2190034e-09 7.1812827e-09 4.0693933e-09 -8.1387865e-09 -9.9640296e-09 5.9844023e-09 1.7833518e-08 5.0268976e-09] [1.0000001 1.0000001 1.0000001 1.0000001 0.9999998 1.0000001 1.0000001 1.0000001 1.0000001 1.0000001 1.0000001 1.0000001 1.0000001 1.0000001 1. 0.99999994 1.0000002 1.0000001 0.99999976 0.9999999 ] <matplotlib.axes._subplots.AxesSubplot at 0x1fac69 色度頻率 色度頻率是音樂音頻有趣且強大的表示,其中整個頻譜被投影到12個區(qū)間,代表音樂八度音的12個不同的半音(或色度), librosa.feature.chroma_stft用于計算色度頻率: In [20]: #色度頻率 x, sr = librosa.load('./data/cut.wav') hop_length = 512 chromagram = librosa.feature.chroma_stft(x, sr=sr, hop_length=hop_length) plt.figure(figsize=(15,5)) librosa.display.specshow(chromagram, x_axis='time', y_axis='chroma', hop_length=hop_length, cmap='coolwarm') <matplotlib.axes._subplots.AxesSubplot at 0x1facc5 In[21]: #導(dǎo)入pydub庫用于音頻文件的截取,上面用到的片段就是從piano中截取的5秒的片段。 from pydub import AudioSegment main_wav_path = './data/piano.wav' # 取出.wav后綴的文件名 sound = AudioSegment.from_wav(main_wav_path) start_time = 0 end_time = 5000 word = sound[start_time:end_time] word.export('./data/cut1.wav', format='wav') <_io.BufferedRandom name='./data/cut1.wav'> 關(guān)于音頻特征處理的一般性方法介紹完了,基于這些知識,接下來可以考慮進一步研究聲紋匹配或者音樂分類項目。 著作權(quán)歸作者所有
|
|