web-dev-qa-db-fra.com

Calcul de la fonction de corrélation croisée?

Dans R, j'utilise ccf ou acf pour calculer la fonction de corrélation croisée par paire afin de savoir quel décalage me donne la valeur maximale. À première vue, R me donne une séquence normalisée de valeurs. Y a-t-il quelque chose de similaire dans le scipy de Python ou suis-je censé le faire en utilisant le module fft? Actuellement, je le fais comme suit:

xcorr = lambda x,y : irfft(rfft(x)*rfft(y[::-1]))
x = numpy.array([0,0,1,1])
y = numpy.array([1,1,0,0])
print xcorr(x,y)
30
Legend

Pour effectuer une corrélation croisée entre les tableaux 1d, utilisez numpy.correlate .

Pour les tableaux 2D, utilisez scipy.signal.correlate2d .

Il y a aussi scipy.stsci.convolve.correlate2d .

Il y a aussi matplotlib.pyplot.xcorr qui est basé sur numpy.correlate.

Voir ce message sur la liste de diffusion SciPy pour quelques liens vers différentes implémentations.

Edit: @ user333700 a ajouté un lien vers le ticket SciPy pour ce problème dans un commentaire.

41
agf

Si vous recherchez une corrélation croisée rapide et normalisée dans une ou deux dimensions, je recommanderais la bibliothèque openCV (voir http://opencv.willowgarage.com/wiki/ http://opencv.org/ ). Le code de corrélation croisée maintenu par ce groupe est le plus rapide que vous trouverez et il sera normalisé (résultats entre -1 et 1).

Bien qu'il s'agisse d'une bibliothèque C++, le code est maintenu avec CMake et possède des liaisons python afin que l'accès aux fonctions de corrélation croisée soit pratique. OpenCV joue également bien avec numpy. Si je voulais calculer un 2 -D corrélation croisée à partir de tableaux numpy Je pourrais le faire comme suit.

import numpy
import cv

#Create a random template and place it in a larger image
templateNp = numpy.random.random( (100,100) )
image = numpy.random.random( (400,400) )
image[:100, :100] = templateNp

#create a numpy array for storing result
resultNp = numpy.zeros( (301, 301) )

#convert from numpy format to openCV format
templateCv = cv.fromarray(numpy.float32(template))
imageCv = cv.fromarray(numpy.float32(image))
resultCv =  cv.fromarray(numpy.float32(resultNp))

#perform cross correlation
cv.MatchTemplate(templateCv, imageCv, resultCv, cv.CV_TM_CCORR_NORMED)

#convert result back to numpy array
resultNp = np.asarray(resultCv)

Pour une simple corrélation croisée 1D, créez un tableau 2D avec une forme égale à (N, 1). Bien qu'il y ait du code supplémentaire à convertir au format openCV, l'accélération par rapport à scipy est assez impressionnante.

14
ncRubert

Je viens de terminer l'écriture de ma propre implémentation optimisée de corrélation croisée normalisée pour les tableaux à N dimensions. Vous pouvez l'obtenir auprès de ici.

Il calculera la corrélation croisée soit directement, en utilisant scipy.ndimage.correlate, ou dans le domaine fréquentiel, en utilisant scipy.fftpack.fftn/ifftn selon ce qui sera le plus rapide.

11
ali_m

Pour la baie 1D, numpy.correlate est plus rapide que scipy.signal.correlate, sous différentes tailles, je vois un gain de performance constant de 5x en utilisant numpy.correlate. Lorsque deux matrices sont de taille similaire (la ligne lumineuse reliant la diagonale), la différence de performances est encore plus remarquable (50x +).

# a simple benchmark
res = []
for x in range(1, 1000):
    list_x = []
    for y in range(1, 1000): 

        # generate different sizes of series to compare
        l1 = np.random.choice(range(1, 100), size=x)
        l2 = np.random.choice(range(1, 100), size=y)

        time_start = datetime.now()
        np.correlate(a=l1, v=l2)
        t_np = datetime.now() - time_start

        time_start = datetime.now()
        scipy.signal.correlate(in1=l1, in2=l2)
        t_scipy = datetime.now() - time_start

        list_x.append(t_scipy / t_np)
    res.append(list_x)
plt.imshow(np.matrix(res))

enter image description here

Par défaut, scipy.signal.correlate calcule quelques nombres supplémentaires par remplissage et cela pourrait expliquer la différence de performances.

>> l1 = [1,2,3,2,1,2,3]
>> l2 = [1,2,3]
>> print(numpy.correlate(a=l1, v=l2))
>> print(scipy.signal.correlate(in1=l1, in2=l2))

[14 14 10 10 14]
[ 3  8 14 14 10 10 14  8  3]  # the first 3 is [0,0,1]dot[1,2,3]
2
B.Mr.W.