簡體   English   中英

Convolve2d 只需使用 Numpy

[英]Convolve2d just by using Numpy

我正在研究使用 NumPy 進行圖像處理,並面臨卷積過濾的問題。

我想對灰度圖像進行卷積。 (將 2d 數組與較小的 2d 數組卷積)

有人想改進我的方法嗎?

我知道SciPy支持 convolve2d 但我只想通過使用 NumPy 來制作 convolve2d。

我做了什么

首先,我為子矩陣制作了一個二維數組。

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

子矩陣看起來很復雜,但我正在做的事情如下圖所示。

子矩陣

接下來,我將每個子矩陣與一個過濾器相乘。

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

multiplied_subs

並將它們相加。

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):
    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 很麻煩,原因有 3 個。

  1. 子矩陣的生成太笨拙,難以閱讀,只能在filter為3*3時使用
  2. 變體子矩陣的大小似乎太大了,因為它比原始矩陣大約大 9 倍。
  3. 求和似乎有點不直觀。 簡單地說,丑。

謝謝你讀到這里。

一種更新。 我為自己寫了一個conv3d。 我將把它作為一個公共領域。

def convolve3d(img, kernel):
    # calc the size of the array of submatrices
    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 submatrices
    submatrices = strd(img,kernel.shape + sub_shape,img.strides * 2)

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

    return convolved_matrix

您可以使用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)

為了擺脫你的第二個“丑陋”的總和,改變你的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]]

從上面使用as_strided和 @Crispin 的einsum技巧進行清理。 將過濾器尺寸強制為擴展形狀。 如果索引兼容,甚至應該允許非方形輸入。

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)

您還可以使用 fft(執行卷積的更快方法之一)

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

干杯,丹

https://laurentperrinet.github.io/sciblog/posts/2017-09-20-the-fastest-2d-convolution-in-the-world.html

在此處查看所有卷積方法及其各自的性能。 另外,我發現下面的代碼片段更簡單。

from numpy.fft  import fft2, ifft2
def np_fftconvolve(A, B):
    return np.real(ifft2(fft2(A)*fft2(B, s=A.shape)))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM