11

Does Python or any of its modules have an equivalent of MATLAB's conv2 function? More specifically, I'm interested in something that does the same computation as conv2(A, B, 'same') in MATLAB.

gnovice
  • 125,304
  • 15
  • 256
  • 359
Ryan
  • 4,517
  • 7
  • 30
  • 34
  • @aaa carp - No problem! Thanks anyway – Ryan Sep 16 '10 at 22:02
  • Duplicate question with answers here: https://stackoverflow.com/questions/2448015/2d-convolution-using-python-and-numpy The answer from Guillaume Mougeot is a fast implementation: https://stackoverflow.com/a/64776128/364818 – Mark Lakata Apr 15 '22 at 02:34

4 Answers4

10

While the other answers already mention scipy.signal.convolve2d as an equivalent, i found that the results do differ when using mode='same'.

While Matlab's conv2 results in artifacts on the bottom and right of an image, scipy.signal.convolve2d has the same artifacts on the top and left of an image.

See these links for plots showing the behaviour (not enough reputation to post the images directly):

Upper left corner of convoluted Barbara

Lower right corner of convoluted Barbara

The following wrapper might not be very efficient, but solved the problem in my case by rotating both input arrays and the output array, each by 180 degrees:

import numpy as np
from scipy.signal import convolve2d

def conv2(x, y, mode='same'):
    return np.rot90(convolve2d(np.rot90(x, 2), np.rot90(y, 2), mode=mode), 2)
Martin Valgur
  • 5,793
  • 1
  • 33
  • 45
jowlo
  • 101
  • 1
  • 3
6

Looks like scipy.signal.convolve2d is what you're looking for.

gnovice
  • 125,304
  • 15
  • 256
  • 359
  • 3
    When using `same` mode, I don't think they're actually the same. SciPy centers differently from Matlab. Matlab says "If there are an odd number of rows or columns, the "center" leaves one more at the beginning than the end." SciPy seems to do the opposite. – endolith Dec 16 '12 at 07:00
1

You must provide an offset for each non-singleton dimension to reproduce the results of Matlab's conv2. A simple implementation supporting the 'same' option, only, could be made like this

import numpy as np
from scipy.ndimage.filters import convolve

def conv2(x,y,mode='same'):
    """
    Emulate the function conv2 from Mathworks.

    Usage:

    z = conv2(x,y,mode='same')

    TODO: 
     - Support other modes than 'same' (see conv2.m)
    """

    if not(mode == 'same'):
        raise Exception("Mode not supported")

    # Add singleton dimensions
    if (len(x.shape) < len(y.shape)):
        dim = x.shape
        for i in range(len(x.shape),len(y.shape)):
            dim = (1,) + dim
        x = x.reshape(dim)
    elif (len(y.shape) < len(x.shape)):
        dim = y.shape
        for i in range(len(y.shape),len(x.shape)):
            dim = (1,) + dim
        y = y.reshape(dim)

    origin = ()

    # Apparently, the origin must be set in a special way to reproduce
    # the results of scipy.signal.convolve and Matlab
    for i in range(len(x.shape)):
        if ( (x.shape[i] - y.shape[i]) % 2 == 0 and
             x.shape[i] > 1 and
             y.shape[i] > 1):
            origin = origin + (-1,)
        else:
            origin = origin + (0,)

    z = convolve(x,y, mode='constant', origin=origin)

    return z
Jens Munk
  • 4,627
  • 1
  • 25
  • 40
1
scipy.ndimage.convolve

does it in n dimensions.

static_rtti
  • 53,760
  • 47
  • 136
  • 192