在numpy中如何进行卷积矩阵运算?

8

有没有一种使用numpy进行卷积矩阵操作的方法?

numpy.convolve只能对1D数组进行操作,因此这不是解决方案。

我更想避免使用scipy,因为在Windows上安装似乎更困难。


如果您在Windows上安装scipy时遇到困难,请使用此whl文件。http://www.lfd.uci.edu/~gohlke/pythonlibs/#scipy - Marlon Abeykoon
5个回答

15
你有Scipy的ndimage,可以使用convolve进行N维卷积:

你有Scipy的ndimage,允许您使用convolve执行N维卷积:

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

我知道你说你想避免使用scipy,但我建议不要这样做。Scipy 在很多方面都非常棒。如果你想在 Windows 上安装它,可以尝试Anaconda Distribution,它已经预装了 Scipy。

Anaconda 是一个跨平台的 Python 发行版,预装了所有必要的库(包括许多科学计算库)和工具,如pipconda 来安装新的库。而且,不,他们没有支付我来宣传 :/ 但是可以让你的跨平台生活更加轻松。


谢谢您的建议,但SciPy方法不太可行,因为我开发的东西将被他人使用,所以我更喜欢一种简单的安装任何先决条件的方法,而pip install [package]是一个众所周知的方法,合理要求人们使用,但安装类似Anaconda Distribution这样的东西就是另外一回事了。 - EquipDev
3
Scipy被认为是Python的核心包之一。如果没有Scipy / Numpy,使用Python进行数据分析就像使用没有工具箱的Matlab一样。也许Python不适合您。 - Imanol Luengo

4

我强烈建议使用openCV来实现这个目的。然而,原则上您可以几乎直接使用核卷积维基文章上的“伪代码”来创建自己的函数...

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

原则上这应该可以解决问题(但我还没有测试过...)

希望这对你有所帮助。


2

我使用了wikipedia article上的例子,并将其推广到矩阵中的每个元素:

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] 是一个与卷积核大小相同的数组切片。

希望这样清楚明了并有所帮助。


0

如果您的内核不对称(与其他答案有所调整):

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

0
一种使用矩阵加法而不是单元格减法来执行的替代numpy方法可以减少循环。
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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接