8

Is there a way to do convolution matrix operation using numpy?

The numpy.convolve only operates on 1D arrays, so this is not the solution.

I rather want to avoid using scipy, since it appears to be more difficult getting installed on Windows.

1

5 Answers 5

15

You have scipy's ndimage which allows you to perform N-dimensional convolution with convolve:

from scipy.ndimage import convolve
convolve(data, kernel)

I know that you said that you want to avoid scipy... but I would advise against it. Scipy is great in so many ways. If you want to install it on windows, try Anaconda Distribution, which already comes with scipy installed.

Anaconda is a multiplatform python distribution that comes with all the essential libraries (including a lot of scientific computing libraries) preinstalled, and tools like pip or conda to install new ones. And no, they don't pay me to advertise it :/ but makes your multiplatform life much easier.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for the suggestion, but the SciPy approach is less viable, since what I develop is to be used by others, so I would much prefer an easy way to install any prerequisites, and pip install [package] is a well known approach that is reasonable to require people to use, but installing something like Anaconda Distribution is another ball game.
@EquipDev Scipy is considered one of the core python packages. Maybe python is not the language for you. Using python for data analysis without scipy/numpy is like using matlab without toolboxes.
4

I would highly recommend using openCV for this purpose. However in principle you can almost directly use the "pseudo-code" on the wiki-article on kernel convolution to create your own function...

ks = (kl-1)/2 ## kernels usually square with odd number of rows/columns
kl = len(kernel)
imx = len(matrix)
imy = len(matrix[0])
for i in range(imx):
  for j in range(imy):
    acc = 0
    for ki in range(kl): ##kernel is the matrix to be used
      for kj in range(kl):
        if 0 <= i-ks <= kl: ## make sure you don't get out of bound error
          acc = acc + (matrix[i-ks+ki][j-ks+kj] * kernel[ki][kj]) 
  matrix[i][j] = acc

this should in principle do the trick (but I have not yet tested it...)

I hope this is helpful.

Comments

3

I used the example on the wikipedia article and extrapolated it for every element in the matrix:

def image_convolution(matrix, kernel):
    # assuming kernel is symmetric and odd
    k_size = len(kernel)
    m_height, m_width = matrix.shape
    padded = np.pad(matrix, (k_size-1, k_size-1))
    
    # iterates through matrix, applies kernel, and sums
    output = []
    for i in range(m_height):
        for j in range(m_width):
            output.append(np.sum(padded[i:k_size+i, j:k_size+j]*kernel))

    output=np.array(output).reshape((m_height, m_width))
    return output

padded[i:k_size+i, j:k_size+j] is a slice of the array the same size as the kernel.

Hope this is clear and helps.

Comments

0

An alternate numpy way to perform using matrix adds instead of cells reduces the looping.

def zConv(m,K):
#input assumed to be numpy arrays Kr<=mrow, Kc<=mcol, Kernal odd
#edges wrap Top/Bottom, Left/Right
#Zero Pad m by kr,kc if no wrap desired
  mc=m*0
  Kr,Kc= K.shape
  kr=Kr//2 #kernel center
  kc=Kc//2
  for dr in range(-kr,kr+1):
    mr=np.roll(m,dr,axis=0)
    for dc in range(-kc,kc+1):
      mrc=np.roll(mr,dc,axis=1)
      mc=mc+K[dr+kr,dc+kc]*mrc
  return mc

Comments

0

If your kernel is not symmetric (adjusted from the other answers):

def image_convolution(matrix, kernel):
    # kernel can be asymmetric but still needs to be odd
    k_height, k_width = kernel.shape
    m_height, m_width = matrix.shape
    k_size = max(k_height, k_width)
    padded = np.pad(matrix, (int(k_size/2), int(k_size/2)))

    if k_size > 1:
        if k_height == 1:
            padded = padded[1:-1,:]
        elif k_width == 1:
            padded = padded[:,1:-1]

    # iterates through matrix, applies kernel, and sums
    output = []
    for i in range(m_height):
        for j in range(m_width):
            between = padded[i:k_height+i, j:k_width+j]*kernel
            output.append(np.sum(between))

    output=np.array(output).reshape((m_height, m_width))
    return output

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.