避免循环的多个序列的互相关

时间:2013-12-18 11:05:44

标签: python opencv numpy cross-correlation

阅读this并尝试了np.correlate和cv2.matchTemplate我仍然有一个我似乎无法解决的问题。

我有两个numpy数组,每个数组的形状为(6000,50)。 6000个序列,每个50个值。现在我想对这个数组的两个1维序列进行互相关以检测时移。我简单地尝试了openCV,但对我来说这会返回一个数字(我期望最高的相关性),所以现在我使用像这样的numpy.correlate:

np.correlate(x[2500], y[2500], mode='same')

(在互相关图中,我不是在寻找最高峰,但我正在寻找使用this的第一个峰值。参见情节示例)

enter image description here

正如您所料,我想为所有6000个序列执行此操作,但希望避免迭代。我希望这会奏效:

np.correlate(x, y, mode='same')

但是这给了我以下错误:ValueError: object too deep for desired array

NumPy或OpenCV是否有任何变化。或者我必须这样做:(

for i in range(x.shape[0]):
    np.correlate(x[i], y[i], mode='same')

1 个答案:

答案 0 :(得分:3)

scipy.ndimage.correlate1d似乎就像你所追求的那样,但它只在第一个阵列上广播,第二个必须严格1D,所以那里没有运气。并且scipy.signal中的函数执行多维关联,而不是像您所追求的那样1D。因此,堆栈中似乎没有任何东西可以解决您的问题。

只是为了它的乐趣,你总是可以使用FFT和cross-correlation theorem来做到这一点:

def correlate1(a, b):
    c = np.empty_like(a)
    for j in range(len(a)):
        c[j] = np.correlate(a[j], b[j], 'same')
    return c

def correlate2(a, b):
    n = a.shape[-1]
    a_fft = np.fft.fft(a, n=2*n)
    b_fft = np.fft.fft(b, n=2*n)
    cc = np.fft.ifft(a_fft * b_fft.conj()).real
    return np.concatenate((cc[..., -n//2:], cc[..., :(n-1)//2 + 1]), axis=-1)

根据您的使用案例,这不是一个好主意:

In [11]: a = np.random.rand(6000, 50)
    ...: b = np.random.rand(6000, 50)
    ...: 

In [12]: np.allclose(correlate1(a, b), correlate2(a, b))
Out[12]: True

In [13]: %timeit correlate1(a, b)
10 loops, best of 3: 37.5 ms per loop

In [14]: %timeit correlate2(a, b)
10 loops, best of 3: 71.8 ms per loop

但这种方法确实有其优点,主要用于较大的序列:

In [15]: a = np.random.rand(50, 6000)
    ...: b = np.random.rand(50, 6000)
    ...: 

In [16]: %timeit correlate1(a, b)
1 loops, best of 3: 516 ms per loop

In [17]: %timeit correlate2(a, b)
10 loops, best of 3: 89.2 ms per loop