I have been trying to do Convolution of a 2D Matrix using SciPy, and Numpy but have failed. For SciPy I tried, sepfir2d and scipy.signal.convolve and Convolve2D for Numpy. Is there a simple function like conv2 in Matlab for Python?
Here is an example:
A= [ 5 4 5 4;
3 2 3 2;
5 4 5 4;
3 2 3 2 ]
I want to convolve it with [0.707 0.707]
And the result as by conv2 from Matlab is
3.5350 6.3630 6.3630 6.3630 2.8280
2.1210 3.5350 3.5350 3.5350 1.4140
3.5350 6.3630 6.3630 6.3630 2.8280
2.1210 3.5350 3.5350 3.5350 1.4140
Some function to compute this output in Python? I will be grateful for a response.
The conv2 function allows you to control the size of the output. Create a 3-by-3 random matrix A and a 4-by-4 random matrix B . Compute the full convolution of A and B , which is a 6-by-6 matrix. A = rand(3); B = rand(4); Cfull = conv2(A,B)
convolve(a, v, mode='full')[source] Returns the discrete, linear convolution of two one-dimensional sequences. The convolution operator is often seen in signal processing, where it models the effect of a linear time-invariant system on a signal [1].
The 2D convolution is a fairly simple operation at heart: you start with a kernel, which is simply a small matrix of weights. This kernel “slides” over the 2D input data, performing an elementwise multiplication with the part of the input it is currently on, and then summing up the results into a single output pixel.
w = conv( u,v ) returns the convolution of vectors u and v . If u and v are vectors of polynomial coefficients, convolving them is equivalent to multiplying the two polynomials. w = conv( u,v , shape ) returns a subsection of the convolution, as specified by shape .
There are a number of different ways to do it with scipy
, but 2D convolution isn't directly included in numpy
. (It's also easy to implement with an fft using only numpy, if you need to avoid a scipy dependency.)
scipy.signal.convolve2d
, scipy.signal.convolve
, scipy.signal.fftconvolve
, and scipy.ndimage.convolve
will all handle a 2D convolution (the last three are N-d) in different ways.
scipy.signal.fftconvolve
does the convolution in the fft domain (where it's a simple multiplication). This is much faster in many cases, but can lead to very small differences in edge effects than the discrete case, and your data will be coerced into floating point with this particular implementation. Additionally, there's unnecessary memory usage when convolving a small array with a much larger array. All in all, fft-based methods can be dramatically faster, but there are some common use cases where scipy.signal.fftconvolve
is not an ideal solution.
scipy.signal.convolve2d
, scipy.signal.convolve
, and scipy.ndimage.convolve
all use a discrete convolution implemented in C, however, they implement it in different ways.
scipy.ndimage.convolve
keeps the same data type, and gives you control over the location of the output to minimize memory usage. If you're convolving uint8
's (e.g. image data), it's often the best option. The output will always be the same shape as the first input array, which makes sense for images, but perhaps not for more general convolution. ndimage.convolve
gives you a lot of control over how edge effects are handled through the mode
kwarg (which functions completely differently than scipy.signal
's mode
kwarg).
Avoid scipy.signal.convolve
if you're working with 2d arrays. It works for the N-d case, but it's suboptimal for 2d arrays, and scipy.signal.convolve2d
exists to do the exact same thing a bit more efficiently. The convolution functions in scipy.signal
give you control over the output shape using the mode
kwarg. (By default, they'll behave just like matlab's conv2
.) This is useful for general mathematical convolution, but less useful for image processing. However, scipy.signal.convolve2d
is generally slower than scipy.ndimage.convolve
.
There are a lot of different options partly due to duplication in the different submodules of scipy
and partly because there are different ways to implement a convolution that have different performance tradeoffs.
If you can give a bit more detail about your use case, we can recommend a better solution. If you're convolving two arrays of roughly the same size, and they're already floats, fftconvolve
is an excellent choice. Otherwise, scipy.ndimage.convolve
may beat it.
scipy's convolved1d() does what you want, just treats the edges a bit differently:
sp.ndimage.filters.convolve1d(A,[0.707,0.707],axis=1,mode='constant')
will give you:
array([[ 6.363, 6.363, 6.363, 2.828],
[ 3.535, 3.535, 3.535, 1.414],
[ 6.363, 6.363, 6.363, 2.828],
[ 3.535, 3.535, 3.535, 1.414]])
If you want the exact same result, just add a column of zeros to A like this:
sp.ndimage.filters.convolve1d(np.c_[np.zeros((4,1)),A],[0.707,0.707],axis=1,mode='constant')
and you will get:
array([[ 3.535, 6.363, 6.363, 6.363, 2.828],
[ 2.121, 3.535, 3.535, 3.535, 1.414],
[ 3.535, 6.363, 6.363, 6.363, 2.828],
[ 2.121, 3.535, 3.535, 3.535, 1.414]])
From my experience you can do in scipy/numpy most of what you do in Matlab very easily (and more).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With