抖音小视频背景歌名识别的学习
生活随笔
收集整理的這篇文章主要介紹了
抖音小视频背景歌名识别的学习
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- 背景
- 前言
- 基礎技術選型
- 聲紋識別
- 聲紋的定義
- 聲紋識別的特征
- 聲紋識別的流程
- 特征提取
- 語音信號分幀
- 對每幀進行傅立葉變換
- 時域與頻域
- 時域
- 頻域
- 基礎技術工具選型
- 選用python庫
- 云數據庫RDS
- 實現代碼
背景
我們使用抖音看視頻的時候,常常聽到好聽的背景音樂,但不知道歌名。我們可以用機器學習的知識來識別歌曲
前言
對于短視頻中的背景音樂,通過傅立葉變化來把聲音轉換為頻率,得到一個個數組,在由數組合成聲音指紋,從而進行音樂的識別。
基礎技術選型
聲紋識別
聲紋的定義
說話人識別,通過聲音來判斷說話人身份,具有波長、頻率、強度等特征,具有穩定性、可測量性、唯一性等特點。
聲紋識別的特征
- 共鳴特征
- 平均音高特征
- 噪音純度特征(明亮、沙啞)
- 音域特征
聲紋識別的流程
特征提取
語音信號分幀
將音頻信號分幀處理(20到40ms幀)
對每幀進行傅立葉變換
- 適用于分心穩定的音頻信號
- 對每一幀音頻信號進行處理,只記錄不接近于0的頻域信號,減少數據處理量
時域與頻域
時域
描述數學函數或物理信號對 時間 的關系,通常呈現為波形
頻域
對函數或者信號進行分析的時候,分析其和 頻率 有關的部分
基礎技術工具選型
選用python庫
- 與數據庫RDS建立連接通道
- pymysql:是python操作MySQL的模塊,可用于連接數據庫
- 將短視頻轉換為音頻格式
- Moviepy:用于視頻編輯的python模塊,將短視頻轉換為音頻格式
- 對外部輸入語音進行操作
- pyAudio: 是提供對語音操作的工具包,可以對外部輸入語音進行播放、錄制或者處理wav格式的操作
云數據庫RDS
- 儲存海量數據庫聲紋數據,建立聲紋數據庫
- 作為聲紋數據庫,進行聲紋特征匹配,實現歌名識別
實現代碼
import os import re from tkinter.tix import Tree import wave import numpy as np import pyaudio import pymysql as MySQLdbclass voice():def loaddata(self, filepath):''':param filepath: 文件路徑,為wav文件:return: 如果無異常則返回True,如果有異常退出并返回Falseself.wave_data內儲存著多通道的音頻數據,其中self.wave_data[0]代表第一通道具體有幾通道,看self.nchannels'''if type(filepath) != str:raise TypeErrorp1 = re.compile('\.wav') #正則表達式patternif p1.findall(filepath) is None:raise IOErrortry:f = wave.open(filepath, 'rb') #只讀模式'''nchannels=2, 聲道數量 sampwidth=2, 采樣字節長度framerate=44100, 采樣頻率nframes=1740627, 音頻總幀數 comptype='NONE', 壓縮類型compname='not compressed''''params = f.getparams()self.nchannels, self.sampwidth, self.framerate, self.nframes = params[:4] # 賦值str_data = f.readframes(self.nframes) #讀取波形數據,讀取并返回以 bytes 對象表示的最多 n 幀音頻self.wave_data = np.frombuffer(str_data, dtype=np.short) # 將波形數據轉換為short類型的數組self.wave_data.shape = -1, self.sampwidth #-1的意思就是沒有指定,根據另一個維度的數量進行分割,得到n行sampwidth列的數組。 self.wave_data = self.wave_data.T # 轉置f.close()self.name = os.path.basename(filepath) # 記錄下文件名return Trueexcept:raise IOError def fft(self, frames=40):'''整體指紋提取的核心方法,將整個音頻分塊后分別對每塊進行傅里葉變換,之后分子帶抽取高能量點的下標:param frames: frames是指定每秒鐘分塊數:return:'''block = []fft_blocks = []self.high_point = []blocks_size = self.framerate // frames # block_size為每一塊的frame數量blocks_num = self.nframes / blocks_size # 將音頻分塊的數量for i in range(0, len(self.wave_data[0]) - blocks_size, blocks_size):block.append(self.wave_data[0][i:i + blocks_size])# fft快速傅里葉變換 fft_blocks.append(np.abs(np.fft.fft(self.wave_data[0][i:i + blocks_size])))# 我們之前說的可是頻率序列,傅里葉變換一套上,我們就只能知道整首歌曲的頻率信息,那么我們就損失了時間的關系,我們說的“序列”也就無從談起。所以我們采用的比較折中的方法,將音頻按照時間分成一個個小塊,在這里我每秒分出了40個塊#我們在下標值為(0,40),(40,80),(80,120),(120,180)這四個區間分別取其模長最大的下標,合成一個四元組,這就是我們最核心的音頻“指紋“self.high_point.append((np.argmax(fft_blocks[-1][:40]),np.argmax(fft_blocks[-1][40:80]) + 40,np.argmax(fft_blocks[-1][80:120]) + 80,np.argmax(fft_blocks[-1][120:180]) + 120,# np.argmax(fft_blocks[-1][180:300]) + 180,))def play(self, filepath):'''音頻播放方法:param filepath:文件路徑:return:'''chunk = 1024wf = 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 == "": breakstream.write(data)stream.close()p.terminate()class memory():def __init__(self, host, port, user, passwd, db):'''初始化的方法,主要是存儲連接數據庫的參數:param host::param port::param user::param passwd::param db:'''self.host = hostself.port = portself.user = userself.passwd = passwdself.db = dbdef addsong(self, path):'''添加歌曲方法,將歌曲名和歌曲特征指紋存到數據庫:param path: 歌曲路徑:return:'''if type(path) != str:raise TypeError#, 'path need string'basename = os.path.basename(path) # 返回文件最后的名字try:conn = MySQLdb.connect(host=self.host, port=self.port, user=self.user, passwd=self.passwd, db=self.db,charset='utf8')except:print ('DataBase error') return Nonecur = conn.cursor()namecount = cur.execute("select * from fingerprint WHERE song_name = '%s'" % basename)if namecount > 0:print ('the song has been record!')return Nonev = voice()v.loaddata(path)v.fft()# 插入歌曲名字信息和指紋信息cur.execute("insert into fingerprint VALUES('%s','%s')" % (basename, v.high_point.__str__()))conn.commit()print ('已添加至數據庫:%s'%(basename))cur.close()conn.close()def fp_compare(self, search_fp, match_fp):''':param search_fp: 查詢指紋:param match_fp: 庫中指紋:return:最大相似值 float'''if len(search_fp) > len(match_fp):return 0max_similar = 0# search_fp 可能是match_fp的其中一個片段search_fp_len = len(search_fp)match_fp_len = len(match_fp)# 找到相似度最高的片段for i in range(match_fp_len - search_fp_len):temp = 0for j in range(search_fp_len):if match_fp[i + j] == search_fp[j]:temp += 1if temp > max_similar:max_similar = tempreturn max_similardef search(self, path):'''搜索方法,輸入為文件路徑:param path: 待檢索文件路徑:return: 按照相似度排序后的列表,元素類型為tuple,二元組,歌曲名和相似匹配值'''#先計算出來我們的音頻指紋v = voice()v.loaddata(path)v.fft()#嘗試連接數據庫try:conn = MySQLdb.connect(host=self.host, port=self.port, user=self.user, passwd=self.passwd, db=self.db,charset='utf8')except:raise IOErrorcur = conn.cursor()cur.execute("SELECT * FROM fingerprint")result = cur.fetchall()compare_res = []for i in result:compare_res.append((self.fp_compare(v.high_point[:-1], eval(i[1])), i[0]))compare_res.sort(reverse=True)cur.close()conn.close()print (compare_res)return compare_resdef search_and_play(self, path):'''搜索方法順帶了播放方法:param path:文件路徑:return:'''v = voice()compare_res = self.search(self,path)v.play(compare_res[0][1])return compare_res# 將提取到的音頻文件特質特征關聯到新建數據庫singdb里的表fingerprint中(即聲音指紋數據) sss = memory('彈性公網IP', 3306, 'root', '自行設置的密碼', 'singdb') sss.addsong('D:/music/小情歌.wav') # 添加歌曲指紋到數據庫 # 此時將獲取到的聲音指紋存儲在數據庫singdb的表fingerprint中(注意:代碼中的彈性公網IP、端口號、root密碼要根據實際配置的內容進行更改)。from moviepy.editor import * video = VideoFileClip('示例1.mp4') audio = video.audio audio.write_audiofile('示例1.wav') # 對抖音短視頻進行處理,提取其中的音頻信息(這里音頻格式可以為mp3、wav等,這里建議選擇wav格式)。sss = memory('彈性公網IP', 3306, 'root', '自行設置的密碼', 'singdb') res = sss.search_and_play('示例1.wav') score = max(res) if score[0]<1000:print("沒有找到") else:print("歌曲名稱:",score[1]) # 執行聲音指紋對比命令,查看在資源池中的數據是否能夠識別出“示例1”的音頻文件,實現聽歌識曲功能。總結
以上是生活随笔為你收集整理的抖音小视频背景歌名识别的学习的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: torch.squeeze
- 下一篇: java怎么提升编程能力_怎样提升jav