首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >只需使用Numpy即可实现Convolve2d

只需使用Numpy即可实现Convolve2d
EN

Stack Overflow用户
提问于 2017-03-29 15:03:20
回答 4查看 59.7K关注 0票数 40

我正在学习使用Numpy进行图像处理,并且面临着一个使用卷积进行过滤的问题。

我想要卷积一个灰度图像。,。(将二维阵列与较小的二维阵列进行卷积)

有没有人有办法refine my method?

我知道scipy支持convolve2d,但我只想用Numpy制作一个convolve2d。

我所做的一切

首先,我制作了一个二维子矩阵数组。

代码语言:javascript
复制
a = np.arange(25).reshape(5,5) # original matrix

submatrices = np.array([
     [a[:-2,:-2], a[:-2,1:-1], a[:-2,2:]],
     [a[1:-1,:-2], a[1:-1,1:-1], a[1:-1,2:]],
     [a[2:,:-2], a[2:,1:-1], a[2:,2:]]])

子矩阵看起来很复杂,但我正在做的事情如下图所示。

接下来,我将每个子矩阵与一个滤波器相乘。

代码语言:javascript
复制
conv_filter = np.array([[0,-1,0],[-1,4,-1],[0,-1,0]])
multiplied_subs = np.einsum('ij,ijkl->ijkl',conv_filter,submatrices)

并对它们进行了汇总。

代码语言:javascript
复制
np.sum(np.sum(multiplied_subs, axis = -3), axis = -3)
#array([[ 6,  7,  8],
#       [11, 12, 13],
#       [16, 17, 18]])

因此,这个过程可以称为my convolve2d。

代码语言:javascript
复制
def my_convolve2d(a, conv_filter):
    submatrices = np.array([
         [a[:-2,:-2], a[:-2,1:-1], a[:-2,2:]],
         [a[1:-1,:-2], a[1:-1,1:-1], a[1:-1,2:]],
         [a[2:,:-2], a[2:,1:-1], a[2:,2:]]])
    multiplied_subs = np.einsum('ij,ijkl->ijkl',conv_filter,submatrices)
    return np.sum(np.sum(multiplied_subs, axis = -3), axis = -3)

然而,我发现这个my_convolve2d很麻烦,有三个原因。

  1. 生成子矩阵太笨拙,难以阅读,只能在滤波器为3*3
  2. 时使用。变量子矩阵的大小似乎太大,因为它大约比原始矩阵大9倍。
  3. 求和看起来有点不直观。简单地说,丑陋。

感谢你读到这里。

有点更新了。我为自己写了一个conv3d。我将把它作为一个公共领域。

代码语言:javascript
复制
def convolve3d(img, kernel):
    # calc the size of the array of submatracies
    sub_shape = tuple(np.subtract(img.shape, kernel.shape) + 1)

    # alias for the function
    strd = np.lib.stride_tricks.as_strided

    # make an array of submatracies
    submatrices = strd(img,kernel.shape + sub_shape,img.strides * 2)

    # sum the submatraces and kernel
    convolved_matrix = np.einsum('hij,hijklm->klm', kernel, submatrices)

    return convolved_matrix
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2017-03-29 15:51:32

您可以使用as_strided生成子数组

代码语言:javascript
复制
import numpy as np

a = np.array([[ 0,  1,  2,  3,  4],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14],
       [15, 16, 17, 18, 19],
       [20, 21, 22, 23, 24]])

sub_shape = (3,3)
view_shape = tuple(np.subtract(a.shape, sub_shape) + 1) + sub_shape
strides = a.strides + a.strides

sub_matrices = np.lib.stride_tricks.as_strided(a,view_shape,strides)

为了去掉第二个“丑陋”的sum,修改你的einsum,使输出数组只有jk。这意味着你的第二个总结。

代码语言:javascript
复制
conv_filter = np.array([[0,-1,0],[-1,5,-1],[0,-1,0]])
m = np.einsum('ij,ijkl->kl',conv_filter,sub_matrices)

# [[ 6  7  8]
#  [11 12 13]
#  [16 17 18]]
票数 31
EN

Stack Overflow用户

发布于 2017-03-29 16:04:12

使用上面的as_strided和@Crispin的einsum技巧进行了清理。强制将过滤器大小添加到展开的形状中。如果索引兼容,甚至应该允许非正方形输入。

代码语言:javascript
复制
def conv2d(a, f):
    s = f.shape + tuple(np.subtract(a.shape, f.shape) + 1)
    strd = numpy.lib.stride_tricks.as_strided
    subM = strd(a, shape = s, strides = a.strides * 2)
    return np.einsum('ij,ijkl->kl', f, subM)
票数 14
EN

Stack Overflow用户

发布于 2017-12-26 22:14:20

您也可以使用fft (一种执行卷积的较快方法)

代码语言:javascript
复制
from numpy.fft import fft2, ifft2
import numpy as np

def fft_convolve2d(x,y):
    """ 2D convolution, using FFT"""
    fr = fft2(x)
    fr2 = fft2(np.flipud(np.fliplr(y)))
    m,n = fr.shape
    cc = np.real(ifft2(fr*fr2))
    cc = np.roll(cc, -m/2+1,axis=0)
    cc = np.roll(cc, -n/2+1,axis=1)
    return cc

干杯,丹

票数 14
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43086557

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档