如何在 python 中使用二维卷积生成二维高斯核?

How to generate 2d gaussian kernel using 2d convolution in python?

来自我的锻炼指导:

A 2D Gaussian can be formed by convolution of a 1D Gaussian with its transpose.

这是我的一维高斯函数:

def gauss1d(sigma, filter_length=11):
    # INPUTS
    # @ sigma         : sigma of gaussian distribution
    # @ filter_length : integer denoting the filter length
    # OUTPUTS
    # @ gauss_filter  : 1D gaussian filter without normalization

    rng = range(-int(filter_length/2),int(filter_length/2)+1)
    gauss_filter = [np.exp((-x**2) / (2*sigma**2)) for x in rng]

    # The formula used above has been given in the instruction.
    return np.array(gauss_filter)

和二维卷积函数,它在图像和滤波器之间执行二维卷积,图像是二维图像。

def myconv2(image, filt):
    # INPUTS
    # @ image         : 2D image, as numpy array of size mxn
    # @ filt          : 1D or 2D filter of size kxl
    # OUTPUTS
    # img_filtered    : 2D filtered image, of size (m+k-1)x(n+l-1)

    m, n = image.shape
    k, l = filt.shape
    offsety = k // 2
    offsetx = l // 2
    img_filtered = np.zeros((m+k-1, n+l-1), "double")
    image = np.pad(image, ((offsety,offsety),(offsetx, offsetx)), mode='constant')
    
    for i in range(offsety, m+offsety):
        for j in range(offsetx, n+offsetx):
            box_vals = image[ i - offsety : i + offsety+1, j-offsetx: j+offsetx+1]
            new_val = np.sum( filt *  box_vals)
            img_filtered[i][j] = np.sum(new_val)
    return img_filtered

简单介绍函数如何处理 5x5 输入图像和 3x3 滤波器内核:

有了以下 1d 高斯及其转置,我调用 myconv2 函数:

sigma = 3
filter_length = 5

gauss = gauss1d(sigma, filter_length).reshape(1,filter_length)
guass
array([[0.18073067, 0.20897821, 0.22058223, 0.20897821, 0.18073067]]) 

gauss_t = np.transpose(gauss)
gauss_t 
array([[0.18073067],
       [0.20897821],
       [0.22058223],
       [0.20897821],
       [0.18073067]])

myconv2(gauss, guass_t)
array([[0.        , 0.        , 0.        , 0.        , 0.        ],
       [0.        , 0.        , 0.        , 0.        , 0.        ],
       [0.03986597, 0.04609688, 0.04865652, 0.04609688, 0.03986597],
       [0.        , 0.        , 0.        , 0.        , 0.        ],
       [0.        , 0.        , 0.        , 0.        , 0.        ]])

如您所见,它实际上不是二维高斯核,并且缺少一些值。 我不知道我缺少什么以及我的代码应该考虑什么才能达到目标。 谢谢。

你可以做一个矩阵乘法。卷积也应该有效,只是要注意填充。

gaus2d = gauss.T @ gauss

您的 conv2d 实现似乎不正确。我建议你实现一个 'valid' 卷积(或互相关):

simple_valid_cross_correlation(img, filt):
    ih, iw = img.shape
    fh, fw = filt.shape
    result = np.zeros((ih - fh + 1, iw - fw + 1))
    for i in range(result.shape[0]):
        for j in range(result.shape[1]):
            result[i, j] = np.sum(filt * img[i:i+fh, j:j+fw])
    return result

gauss_pad = np.pad(gauss.T, ((0, 0), (gauss.shape[1]-1, gauss.shape[1]-1)))
gauss2d = simple_valid_cross_correlation(gauss_pad, gauss)

如果您不想实现自己的转换,也有 scipy.signal.convolve2d。我认为它可能会更快