Convolve2d 仅使用 Numpy [英] Convolve2d just by using Numpy

查看:42
本文介绍了Convolve2d 仅使用 Numpy的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在研究使用 Numpy 的图像处理,并面临使用卷积过滤的问题.

我想对灰度图像进行卷积.(将二维数组与较小的二维数组进行卷积)

有人想改进我的方法吗?

我知道

接下来,我将每个子矩阵与过滤器相乘.

conv_filter = np.array([[0,-1,0],[-1,4,-1],[0,-1,0]])multiplied_subs = np.einsum('ij,ijkl->ijkl',conv_filter,submatrices)

并将它们相加.

np.sum(np.sum(multiplied_subs,axis = -3),axis = -3)#array([[ 6, 7, 8],# [11, 12, 13],# [16, 17, 18]])

因此这个程序可以称为我的 convolve2d.

def my_convolve2d(a, conv_filter):子矩阵 = 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)返回 np.sum(np.sum(multiplied_subs,axis = -3),axis = -3)

但是,我觉得 my_convolve2d 很麻烦,原因有 3 个.

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

感谢您阅读到这里.

一种更新.我为自己写了一个 conv3d.我会将其保留为公共领域.

def convolve3d(img, kernel):# 计算子矩阵数组的大小sub_shape = tuple(np.subtract(img.shape, kernel.shape) + 1)# 函数别名strd = np.lib.stride_tricks.as_strided# 创建一个子矩阵数组子矩阵 = strd(img,kernel.shape + sub_shape,img.strides * 2)# 对子矩阵和内核求和convolved_matrix = np.einsum('hij,hijklm->klm', kernel, submatrices)返回 convolved_matrix

解决方案

您可以使用 as_strided:

将 numpy 导入为 npa = 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步幅 = a.strides + a.stridessub_matrices = np.lib.stride_tricks.as_strided(a,view_shape,strides)

摆脱你的第二个丑陋"总和,改变你的 einsum 以便输出数组只有 jk.这意味着您的第二次求和.

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]]

I am studying image-processing using Numpy and facing a problem with filtering with convolution.

I would like to convolve a gray-scale image. (convolve a 2d Array with a smaller 2d Array)

Does anyone have an idea to refine my method ?

I know that scipy supports convolve2d but I want to make a convolve2d only by using Numpy.

What I have done

First, I made a 2d array the submatrices.

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:]]])

the submatrices seems complicated but what I am doing is shown in the following drawing.

Next, I multiplied each submatrices with a filter.

conv_filter = np.array([[0,-1,0],[-1,4,-1],[0,-1,0]])
multiplied_subs = np.einsum('ij,ijkl->ijkl',conv_filter,submatrices)

and summed them.

np.sum(np.sum(multiplied_subs, axis = -3), axis = -3)
#array([[ 6,  7,  8],
#       [11, 12, 13],
#       [16, 17, 18]])

Thus this procudure can be called my convolve2d.

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)

However, I find this my_convolve2d troublesome for 3 reasons.

  1. Generation of the submatrices is too awkward that is difficult to read and can only be used when the filter is 3*3
  2. The size of the varient submatrices seems to be too big, since it is approximately 9 folds bigger than the original matrix.
  3. The summing seems a little non intuitive. Simply said, ugly.

Thank you for reading this far.

Kind of update. I wrote a conv3d for myself. I will leave this as a public domain.

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

解决方案

You could generate the subarrays using as_strided:

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)

To get rid of your second "ugly" sum, alter your einsum so that the output array only has j and k. This implies your second summation.

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]]

这篇关于Convolve2d 仅使用 Numpy的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆