2013-06-03 5 views
6

Soweit ich gesehen habe, sind diese Methoden beide als C-Funktionen in den jeweiligen DLLs implementiert, und es scheint, dass die ndimage Version schneller ist (keine Implementierung verwendet parallelisierten Code, wie Aufrufe von Blas oder MKL).Was ist der Unterschied zwischen scipy.ndimage.filters.convolve und scipy.signal.convolve?

Auch wenn ich versuchte zu überprüfen, dass sie die gleichen Ergebnisse durch Ausführen des folgenden Codes zurückgegeben, die Assertion der Gleichheit fehlgeschlagen. Ich konnte aus der Dokumentation nicht herausfinden, was genau die funktionellen Unterschiede zwischen den beiden Methoden sein sollten (die Dokumentation ist nicht sehr klar darüber, was 0 bedeutet relativ zur Position des Ursprungs des Kernels; von Beispielen habe ich abgeleitet, dass es in der Zentrum, aber ich könnte falsch liegen).

from numpy import random, allclose 
from scipy.ndimage.filters import convolve as convolveim 
from scipy.signal import convolve as convolvesig 

a = random.random((100, 100, 100)) 
b = random.random((10,10,10)) 

conv1 = convolveim(a,b, mode = 'constant') 
conv2 = convolvesig(a,b, mode = 'same') 

assert(allclose(conv1,conv2)) 

Vielen Dank!

+1

Ich kenne die Implementierungen nicht, aber wahrscheinlich verwendet die Implementierung von ndimage den Convolution-Theorem, d. H. Faltung ist gleich Multiplikation im Fourier-Raum. Das ist, was scipy.signal.fftconvolve tut. Aber auch wenn diese Methode verwendet wird, anstatt zu falten, schlägt die Assertion fehl. –

+1

Es scheint mir, dass beide direkte Implementierungen verwenden. Ich glaube, dass der Code, der am Ende aufgerufen wird, [hier] (https://github.com/scipy/scipy/blob/master/scipy/signal/correlate_nd.c.src#L105) und [hier] (https : //github.com/scipy/scipy/blob/master/scipy/ndimage/src/ni_filters.c#L132). Ich habe versucht, die Methoden auf Integer-Arrays aufzurufen, um Rundungsfehler usw. auszuschließen, aber die Assertion schlägt ebenfalls fehl. – bbudescu

+1

Die Assertion schlägt auch auf 2d-Arrays fehl, aber nur, wenn der Kernel größer als eine bestimmte Größe ist, z. 'a = random.random_integers (0,10, (100, 100)); b = random.random_integers (0,10, (7, 7))' scheitert nicht, aber wenn 'b = random.random_integers (0 , 10, (8, 8)) ', tut es. Irgendwelche Gedanken? – bbudescu

Antwort

9

Die beiden Funktionen haben unterschiedliche Konventionen für den Umgang mit der Grenze. Um Ihre Anrufe funktionell gleich, fügen Sie das Argument origin=-1 oder origin=(-1,-1,-1) auf den Aufruf zu convolveim zu machen:

In [46]: a = random.random((100,100,100)) 

In [47]: b = random.random((10,10,10)) 

In [48]: c1 = convolveim(a, b, mode='constant', origin=-1) 

In [49]: c2 = convolvesig(a, b, mode='same') 

In [50]: allclose(c1,c2) 
Out[50]: True 

nur verschieben, um den Ursprung, wenn die Abmessungen von b selbst sind. Wenn sie ungerade sind, stimmen die Funktionen, wenn der Standard origin=0 verwendet wird:

In [88]: b = random.random((11,11,11)) 

In [89]: c1 = convolveim(a, b, mode='constant') 

In [90]: c2 = convolvesig(a, b, mode='same') 

In [91]: allclose(c1,c2) 
Out[91]: True 
+0

Wenn a und b unterschiedliche Größen haben (Modulo 2), z.B. Wenn a Größe (100,100) und b Größe (11,11) hat, ist die obige Lösung falsch. In diesem Fall sollte der Ursprung sein (0,0) für die beiden Funktionen –

+0

zustimmen @JensMunk Was genau haben Sie testen? Wenn ich eine (1000,1000) Array mit einem (11,11) Array mit 'origin = 0 'convolve, sind die Ergebnisse sehr nahe (im Wesentlichen die gleiche genaue einige numerische Genauigkeit). Dies ist, was die Antwort sagt, wenn "b" ungerade ist. – user3731622

+0

Das stimmt.Wenn sie die gleiche Größe Modulo 2 haben, sollte der Ursprung (1,1) sein, soweit ich mich erinnere. –

3

Es gibt einen sehr wichtigen Unterschied ist. Die Implementierung in dem Bildpaket scheint die typische eingeschränkte Version zu sein, die in der Bildverarbeitung verwendet wird, um die gleiche Größe des Bildes nach der Faltung zu erreichen. Es stimmt also mit der "gleichen" Option im Signalverarbeitungspaket überein, wenn wir wie in den obigen Beispielen mode = 'constant' verwenden. Das Signalverarbeitungspaket scheint die wirklich strenge Definition des Faltungsoperators zu implementieren. Vielleicht ist es deshalb langsamer. Hier finden Sie einige Beispiele mit völlig anderen Ergebnissen.

In [13]: a=array([[1,2,1]]) 
In [14]: b=array([[1],[2],[1]]) 

In [17]: convolveim(a,b) 
Out[17]: array([[4, 8, 4]]) 

In [18]: convolveim(b,a) 
Out[18]: 
array([[4], 
     [8], 
     [4]]) 

In [19]: convolvesig(a,b) 
Out[19]: 
array([[1, 2, 1], 
     [2, 4, 2], 
     [1, 2, 1]]) 

In [20]: convolvesig(b,a) 
Out[20]: 
array([[1, 2, 1], 
     [2, 4, 2], 
     [1, 2, 1]]) 

Beachten Sie, dass die Implementierung des Signalverarbeitungspakets conmutative ist, wie für eine korrekte Faltung erwartet. Die Implementierung im Image-Paket ist jedoch nicht möglich und bietet eine Lösung mit den gleichen Dimensionen wie der erste Parameter.