我正在创建一个程序来比较使用类似算法的音频文件http://www.ee.columbia.edu/~dpwe/papers/Wang03-shazam.pdf。我正在绘制两首被比较的歌曲之间的匹配时间,并找到该情节的最小二乘线。 href = http://imgur.com/fGu7jhX&yOeMSK0是匹配文件的示例图。该图太杂乱,即使图中有明显的线,最小二乘回归线也不会产生高相关系数。我可以用什么其他算法来识别这一行?
答案 0 :(得分:5)
这是一个有趣的问题,但它一直很安静。也许这个答案 会引发更多的活动。
用于识别具有任意斜率的线和集合内的截距 对于点,霍夫变换将是一个很好的起点。对于你的音频 但是,看起来坡度应该始终为1,所以你不应该这样 需要霍夫变换的完整普遍性。
相反,您可以将问题视为聚类差异x - y
之一,其中x
和y
是包含点的x和y坐标的向量。
一种方法是计算x - y
的直方图。接近于具有斜率1的同一行中的点将在直方图中的相同仓中具有差异。具有最大计数的仓对应于近似对齐的最大点集合。在这种方法中要处理的一个问题是选择直方图箱的边界。一个糟糕的选择可能会导致应该组合在一起的点被拆分成相邻的区域。
一种简单的蛮力方法是想象一个具有给定宽度的对角窗口,在(x,y)平面上从左向右滑动。线条的最佳候选对应于包含最多点的窗口的位置。这类似于x - y
的直方图,但不是有一组不相交的箱子,而是有重叠的箱子,每个点一个。所有箱子的宽度都相同,每个点都决定了箱子的左边缘。
下面代码中的函数count_diag_groups
执行该计算。对于每个点,它计算当窗口的左边缘在该点上时对角线窗口中有多少个点。一条线的最佳候选者是得分最多的窗口。这是脚本生成的图。顶部是数据的散点图。瓶底是相同的散点图,突出显示最佳候选点。
此方法的一个很好的功能是只有一个参数,窗口宽度。一个不太好的功能是它具有时间复杂度O(n ** 2),其中n是点数。肯定有时间复杂度更高的算法可以做类似的事情;您链接的文章讨论了这一点。然而,要判断替代品的质量,将需要更具体的规范,以确定线路识别必须“良好”或强大。
import numpy as np
import matplotlib.pyplot as plt
def count_diag_groups(x, y, width):
"""
Returns a list of arrays. The length of the list is the same
as the length of x. The k-th array holds the indices into x
(and y) of a set of points that are in a "diagonal" window with
the given width whose left edge includes the point (x[k], y[k]).
"""
d = x - y
result = []
for i in range(d.size):
delta = d - d[i]
neighbors = np.where((delta >= 0) & (delta <= width))[0]
result.append(neighbors)
return result
def generate_demo_data():
# Generate some data.
np.random.seed(123)
xmin = 0
xmax = 100
ymin = 0
ymax = 25
nrnd = 175
xrnd = xmin + (xmax - xmin)*np.random.rand(nrnd)
yrnd = ymin + (ymax - ymin)*np.random.rand(nrnd)
n = 25
xx = xmin + 0.1*(xmax - xmin) + ymax*np.random.rand(n)
yy = (xx - xx.min()) + 0.2*np.random.randn(n)
x = np.concatenate((xrnd, xx))
y = np.concatenate((yrnd, yy))
return x, y
def plot_result(x, y, width, selection):
xmin = x.min()
xmax = x.max()
ymin = y.min()
ymax = y.max()
xsel = x[selection]
ysel = y[selection]
# Plot...
plt.figure(1)
plt.clf()
ax = plt.subplot(2,1,1)
plt.plot(x, y, 'o', mfc='b', mec='b', alpha=0.5)
plt.xlim(xmin - 1, xmax + 1)
plt.ylim(ymin - 1, ymax + 1)
plt.subplot(2,1,2, sharex=ax, sharey=ax)
plt.plot(x, y, 'o', mfc='b', mec='b', alpha=0.5)
plt.plot(xsel, ysel, 'o', mfc='w', mec='w')
plt.plot(xsel, ysel, 'o', mfc='r', mec='r', alpha=0.65)
xi = np.array([xmin, xmax])
d = x - y
yi1 = xi - d[imax]
yi2 = yi1 - width
plt.plot(xi, yi1, 'r-', alpha=0.25)
plt.plot(xi, yi2, 'r-', alpha=0.25)
plt.xlim(xmin - 1, xmax + 1)
plt.ylim(ymin - 1, ymax + 1)
plt.show()
if __name__ == "__main__":
x, y = generate_demo_data()
# Find a selection of points that are close to being aligned
# with a slope of 1.
width = 0.75
r = count_diag_groups(x, y, width)
# Find the largest group.
sz = np.array(list(len(f) for f in r))
imax = sz.argmax()
# k holds the indices of the selected points.
selection = r[imax]
plot_result(x, y, width, selection)
答案 1 :(得分:4)
这看起来像Random Sampling Consensus (RANSAC)的任务的一个很好的例子。 维基百科的文章甚至以您的问题为例!
粗略的轮廓是这样的。
查看维基百科文章以获取更多信息。