Python和Numpy 处理音频指纹 二

Python部落(python.freelycode.com)组织翻译,禁止转载,欢迎转发。

Python和Numpy 处理音频指纹 二

歌曲表

歌曲表比较普通,事实上,我们只是使用它存储歌曲的信息。我们需要使用song_id 来匹配歌曲的字符串名称。

blob.png

 fingerprinted字段是用于Dejavu项目内部表明是否已经做过音频指纹识别。我们设置的初始值为0,识别后设置为1(通常是两个频道)。

音频指纹比对

好的,现在我们已经听了一个音轨,在重叠窗口对整首歌进行FFT,抽取峰值,并且生成了音频指纹。接下来呢?

假设我们已经在已知的轨道上执行了音频指纹录入,即我们已经将歌曲的song_id和音频指纹数据插入数据库中,我们可以简单的进行匹配。

伪码看起来是这样的:

 blob.png

哈希值要一致是什么意思?让我们想想,我们听的样本作为原始音轨的一个片断。一旦我们这样做了,我们从样本中提取出的哈希值相对于样品的开始已经是有了偏差offset。

当然问题是,我们最初的音频指纹,记录的绝对偏移的哈希值。样本的相对哈希值与数据库中的绝对哈希值是永远不会匹配的,除非我们开始记录样本就是完全从歌曲的开头开始。这是完全不可能的。

但是,虽然他们可能不一样,我们确实知道如何匹配噪音背后的真实信息。我们知道所有的相对偏移量将是相同的距离。这需要假设的轨道是按照在相同的速度进行播放和采样的,并且是在相同工作室记录和释放。其实,我们运气不好的情况下播放速度不同,就会影响到播放的频率和谱图的峰值。假设在任何速率下播放速度都是好的(这很重要)。

在这个假设下,对于每一个匹配操作,我们计算出偏移量之间的差值:

 blob.png

这将总是生成一个正整数,因为数据库记录总是至少会是样品的长度。所有的真实匹配都会有相同的差异。因此,我们的数据库中的匹被改变,看起来像:

blob.png

 现在,我们需要简单的察看所有的匹配和有最大差值(diffrence)的歌曲编号(song_id)。这是很容易想象的,如果你把它想象成一个直方图。

这就是所有要做的!

效果如何

要真正的获得一个音频指纹系统的好处,它不能花很长的时间来指纹识别。这是一个不好的用户体验,此外,用户可能决定去尝试识别一首歌曲只有宝贵的几秒钟时间,然后收音机就要进入广告了。

为了测试Dejavu的速度和准确性,我对美国2013年6月单曲排行榜上的45首歌曲做了音频指纹记录(我知道,他们的排名方式来自其他地方)。我用了三种方式进行测试:

  1. 1.从硬盘上的原始MP3 文件到WAV数据进行读取

  2. 2.用Dejavu在笔记本电脑的麦克风中监听音箱播放的歌曲。

  3. 3.在我的手机上播放的压缩流媒体音乐

下面是测试结果。

1.从硬盘上读取

从硬盘读取完全是压倒性的100%识别,45首做过音频指纹的歌曲没有一首错误。这是因为Dejavu直接就是从歌曲中取样的(没有背景噪声),有时会有让人讨厌的惊喜出现,从硬盘上读取相同文件不是每次都成功!

2. 来自笔记本麦克风中的音频

这里,我写了一个脚本从原始MP3文件中随机选择n秒音频片段播放,让Dejavu从麦克风中监听。公平地说,我只使用超过10s的音频片段,以避免监听到无声。

此外,我的朋友甚至在说话,我在整个过程中也一直在弄出一些声响,就是为了加进一些噪音。

这里是不同的监听时长(n)的结果:

 blob.png

真是一个漂亮的弧线。按百分比计算:

blob.png

即使只有一秒,从歌曲中的随机选择任何歌曲测试,Dejavu准确率也能达到60%!再多一秒到2秒时就能达到96%左右,而完全准确只需要5秒或者5秒多。老实说,在测试时,我自己也在进行识别歌曲,不过还是Dejavu赢了,我发现没有上下文只靠听1-2秒钟识别出一首实在是太难了。在调试的时候,我一直在听这些相同的歌曲都已经连续两天了…

总之,Dejavu工作的非常好,几乎不能更好了。

3.在我的手机上播放的压缩流媒体音乐

只是想试试,我试着用iphone的扬声器播放我Spotify帐户上的音乐(160 kbit/s压缩流),然后在MacBook中用Dejavu监听的麦克风。我看到没有性能退化;1-2秒足以识别任何歌曲。

 性能:速度

在我的MacBook Pro上,用一个小的恒定的开销并且3倍监听速度完成匹配。为了测试,我尝试了不同的录音时间,并按记录时间和加上到匹配的时间绘制了点线图。由于特定的歌曲识别速度是不变的,更多是依赖于频谱创建的长度,我测试了一首歌,Daft Punk的"Get Lucky"。

 blob.png

正如你所看到的,这种关系是非常线性化的。你所看到的线是一个最小平方线性回归拟合的数据,与之相应的回归方程是:

 blob.png

当然,由于匹配本身是单线程的,匹配的时间包括记录时间。3倍速度在单纯匹配上也能说得通,如:

 blob.png

如果我们忽视极小的常数项。

寻峰开销是有瓶颈的——我用多线程实时匹配实验过,唉,这并不是说在Python中。用Java或C/C++实现等效是可能有点麻烦,应用FFT和实时寻峰。

一个重要的警告无疑是要注意进行匹配的往返时延(RTT)。由于我的MySQL实例在本地,我不需要处理把音频指纹识别转移到线上而引起的延迟问题。这将会增加RTT到整个计算的时间的常数项,但是不会影响匹配这个操作过程。

性能:存储

为了给这45首歌曲做音频指纹识别,数据库使用377 MB的空间记录了540万个音频指纹。下面是硬盘的使用情况对比:

blob.png

这里有一个在必要的记录时间和所需的存储量之间的相当直接的权衡。为了音频识别调整峰的振幅阈值将增加更多的音频指纹和在牺牲更多的空间的情况下加强准确性。

这是真的,音频指纹占用大量空间(略多于原生MP3文件)。这似乎是令人震惊的,可是你要考虑到每首歌有几十甚至几百上千的哈希值。我们没有使用.wave文件中整个音频信号的纯信息,而是用只占用了其存储的20%的音频指纹,而且我们已经能够非常可靠地在五秒内识别歌曲,所以我们的空间与速度的权衡似乎是值得的。

结论

第一次看到音频指纹我觉得很神奇。但是通过少量的信号处理学知识和基本数学知识,这是一个相当容易进入的领域。

我希望任何读到这篇文章的人能够检验Dejavu 项目或者给我加星,又或者更好的是fork 它加入贡献中来!

Dejavu 地址:

https://github.com/worldveil/dejavu

如果你喜欢这篇文章,请分享或者在Twitter上关注我


英文原文:http://willdrevo.com/fingerprinting-and-audio-recognition-with-python/
译者:Steven
 

2月15日11:00到13:00网站停机维护,13:00前恢复