python nn 聲音辨識 -1 傅立葉轉換
辨識環境聲音判斷出這是甚麼聲音
主要想法是用頻域赫茲分布做判斷首先先錄三種聲音的聲音檔,我每一種聲音重複錄製九個sample,所以有27個wav檔
讀取wav檔案,作正規劃處理,在做傅立葉轉換
一開始由於自己做的fft_domyself() function跟其他聲音處理軟體做出來的不一樣,數值非常小,之後找到有內建的spectrogram() function,使用也是數值很小,最後才想到要20log(),但由於內建的覺得不適合自由調整,所以還是修改自己的function。
import matplotlib.pyplot as plt from scipy.fftpack import fft from scipy.io import wavfile # get the api import numpy as np from scipy import signal import math import pyaudio import wave import time #buf=[] #讀入單一檔案測試 def init(): fs, data = wavfile.read('0106.wav') # load the data b=[(ele/2**16.) for ele in data] # this is 16-bit track, b is now normalized on [-1,1) c = fft(b) # calculate fourier transform (complex numbers list) d = len(c)/2 # you only need half of the fft list (real signal symmetry) plt.subplot(211) plt.plot(b,'b') plt.title('time line') plt.subplot(212) plt.plot(abs(c[:(d-1)]),'r') plt.title('fft') plt.show() return fs, b #取樣率 data #轉成頻域 def fft_domyself(b, fs, plotshow=None): global ftmap #set value one_second_block_num = 21*2 #one second 擷取次數 second = len(b)/44100 second_len = int(one_second_block_num*second) fft_num = int(fs/one_second_block_num) #one second 間格點數 #2100 ftmap = np.zeros((int(fft_num/2),second_len)) #建立fft陣列的圖片大小 startime = 0#362000 #轉成fft 並儲存在fft陣列 for i in range(0,second_len): endtime = startime + fft_num ffttemp = abs(fft(b[startime:endtime])) ftmap[0:fft_num,i] = ffttemp[0:int(len(ffttemp)/2)] startime = endtime #做20log() for i in range(0, len(ftmap[:,1])): for j in range(0, len(ftmap[1,:])): try: #ftmap[i,j] = 20*math.log10(ftmap[i,j]) ftmap[i,j] = 20*math.log(ftmap[i,j], 10) except: #由於 log(0) 輸入0會error print('log error with ftmap: ', ftmap[i,j]) ftmap = ftmap + abs(np.min(ftmap)) lineft = np.median(ftmap, axis=1) #用二維的方式,查看頻域的整體資料情況 if plotshow: if plotshow == 'linefft': plt.plot(lineft, 'b') plt.show() else: plt.plot(lineft,'g') plt.show() plt.imshow(ftmap) plt.xlabel('Frequency [Hz]') plt.ylabel('Time [sec]') plt.colorbar() plt.show() return ftmap, lineft #使用內建的function將聲音轉成頻域 def spectrogram_(b, fs, plotshow=None): #x1 = np.array(b, dtype = float) f, t, Sxx = signal.spectrogram(b, fs) #output 時頻譜 for i in range(0, len(Sxx[:,1])): for j in range(0, len(Sxx[1,:])): Sxx[i,j] = 20*math.log10(Sxx[i,j]) #print('do') Sxx = Sxx + abs(np.min(Sxx)) if plotshow: plt.pcolormesh(t, f, Sxx) #draw 時頻譜 plt.ylabel('Frequency [Hz]') plt.xlabel('Time [sec]') plt.colorbar() plt.show() return Sxx if __name__ == '__main__': fs, b = init() fftmap = fft_domyself(b, fs, plotshow = True) #自己做的 sx = spectrogram_(b, fs, plotshow = True) #內建function2018/2/24更新(添加註解)
img
lineft
ftmap
spectrogram_()
讀多個聲音檔,並轉換成fft矩陣
我是用三個鈴鐺做的,無聲音檔就是沒有鈴鐺聲只有背景聲
2018/2/24更新
輸出:
linef = [0~20000Hz頻域的大小 , 0~20000Hz頻域的大小 , 0~20000Hz頻域的大小 ......]
answer = [ [0.0 , 1.0 , 0.0 , 0.0] , [0.0 , 0.0 , 1.0 , 0.0] , [0.0 , 0.0 , 0.0 , 1.0] ......]
[0.0 , 1.0 , 0.0 , 0.0] 代表是第一類聲音
def read_file(filename, plotshow=None): fs, data = wavfile.read(filename) # load the data b=[(ele/2**16.) for ele in data] # this is 16-bit track if plotshow: plt.plot(b,'b') plt.title('time line') plt.show() return b, fs def read_to_mat(): file_road = './train_data/' filehead = ['00', '01', '02', '03'] linef = [] answer = [] for i in range(1, 10): #last two number for j in range(0, len(filehead)): #first two number readURL = file_road + filehead[j] + '%02d'%(i) + '.wav' x = [0.0, 0.0, 0.0, 0.0] x[int(filehead[j])] = 1.0 audio_value, fs = read_file(readURL) fftmap, linefft = fft_domyself(audio_value, fs) normalized_linefft = (linefft - np.mean(linefft)) / np.std(linefft) answer.append(x) linef.append(normalized_linefft.tolist()) print(readURL, x) return linef, answer錄製聲音
def recoder(recoder_second, filename = None, plotshow=None): NUM_SAMPLES = 100 # pyAudio內部緩存的塊的大小 SAMPLING_RATE = 44100 #取樣頻率 #recoder_second = 1 ''' LEVEL = 1500 #聲音保存的閾值 COUNT_NUM = 20 # NUM_SAMPLES個取樣之內出現COUNT_NUM個大於LEVEL的取樣則記錄聲音 SAVE_LENGTH = 8 #聲音記錄的最小長度:SAVE_LENGTH * NUM_SAMPLES個取樣 skip_second = 0.07 swidth = 2 ''' #開啟聲音輸入 save_buffer = [] pa = pyaudio.PyAudio () stream = pa . open ( format = pyaudio.paInt16 , channels = 1 , rate = SAMPLING_RATE , input = True , #output = True, frames_per_buffer = NUM_SAMPLES ) #,stream_callback = callback time.sleep(0.1) stream.start_stream() skip_buffer = [] num = 3500 / NUM_SAMPLES#SAMPLING_RATE / NUM_SAMPLES * skip_second for i in range(0, int(num)): string_audio_data = stream.read ( NUM_SAMPLES) skip_buffer.append(np.fromstring(string_audio_data, np.int16)) #stream.read ( NUM_SAMPLES) print('star recoder') num = SAMPLING_RATE / NUM_SAMPLES * recoder_second for i in range(0, int(num)): #讀入NUM_SAMPLES個取樣 string_audio_data = stream.read ( NUM_SAMPLES ) save_buffer.append(np.fromstring(string_audio_data, np.int16)) #stream.write(string_audio_data, NUM_SAMPLES) print("* done recording") stream.stop_stream() stream.close() pa.terminate() numpydata = np.hstack(save_buffer) skipnp = np.hstack(skip_buffer).tolist() ''' #直接存檔 WAVE_OUTPUT_FILENAME = filename + ".wav" wf = wave.open(WAVE_OUTPUT_FILENAME, 'wb') wf.setnchannels(1) wf.setsampwidth(pa.get_sample_size(pyaudio.paInt16)) wf.setframerate(SAMPLING_RATE) wf.writeframes(b''.join(save_buffer)) wf.close() ''' if plotshow: if plotshow == 'line': plt.plot(numpydata,'r') plt.show() else: plt.subplot(311) plt.plot(skipnp,'g') plt.subplot(312) plt.plot(save_buffer,'b') plt.subplot(313) plt.plot(numpydata,'r') plt.show() return numpydata, SAMPLING_RATE if __name__ == '__main__': buffer = [] recoder_second = 0.5 buffer, fs = recoder(recoder_second, plotshow=True) fttmap, linef = fft_domyself(buffer, fs, plotshow = True)
開始錄音時發現會有一個雜訊,那個雜訊值非常大,以下是跳過雜訊再錄音0.05秒,green line是跳過的雜訊,blue line是接續綠色後面的0.05秒錄音
green line:跳過的雜訊
blue line:原始錄到的資料,每一點的資料量跟 (NUM_SAMPLES = 100 # pyAudio內部緩存的塊的大小) 有關
red line:將blue line的資料串接起來
請問如何辨識出來~然後自動分類....
回覆刪除我到第25行的地方就不太行了
求高手教QAQ
自動分類?! 類神經網路就直接讓他學習就好 他會自己處理
刪除但是你給他訓練的資料(聲音檔)要自己分類喔
抱歉!!~我不知道你指的第25行是指哪一段的25行
作者已經移除這則留言。
刪除我是不知道轉速的聲音有沒有差別 但最好能擷取較無雜訊的音訊
刪除其實我真正用程式錄音方式下去做其實誤差非常大 我是用鈴鐺聲音 用程式錄音就沒辦法把前後雜音的部份去掉 我先前的錄音檔是有經過去除無鈴鐺聲音的部分 所以成功機率較高
所以基本上要將聲音去頭去尾 只留下真正需要的部分
我這個其實是很陽春版的 只是用來實驗 聲音也能分類
其實他主要還是用圖像的方式做神經網路 你可以以圖像的角度去看待它會比較清楚 網上有很多對於圖像的範例
有沒有不經過圖像,直接用FFT轉換後數字化,用全數字的檔案辨識的方法
回覆刪除你所說的全數字的檔案跟我說的圖像意思其實是一樣的,一張黑白照片其實就是一個全數字檔
刪除FFT轉換後一定會轉成我第四張圖那樣,一個二維的圖每一個像素點就是一個數字啊!!
版主你好~想請問第一段第二張做出來紅色的圖的Y軸的數值代表什麼意思?為什麼需要透過abs讓他全部都為正的?還有第三張綠色的圖的X軸和Y軸又分別代表什麼意思呢?謝謝
回覆刪除有點久了幾乎忘記當初在做甚麼,回答可能不一定正確先跟你說聲抱歉了。
刪除我想紅色的Y軸應該是傅立葉轉換出來的大小,abs轉正是為了視覺上的習慣,像是音樂撥放器或是收音設備上的頻譜都沒有顯示負值,所以就習慣看沒有負值。
綠色的圖 (lineft) 應該跟 ftmap 是一樣的意思,在ftmap上有軸的說明,所以綠色的圖 (lineft) X軸應該是Hz吧!? Y軸應該就是值的大小了。
最近研究雜音捕捉看到這篇,16-bit wav 有一位是符號,b=ele/2^16結果應該是-0.5~0.5才對,才會有數值非常小的問題。
刪除20log()是音壓,據我理解,如果是處理錄製結果,資料數值應該是變回音強。