1

我有一个2d numpy array包含从到的greyscale像素值。我想做的是从头开始创建一个. 我已经编写了一个生成高斯函数的函数:0255gaussian filter normalizedkernel

def gaussianKernel(size, sigma):
    kernel =  np.fromfunction(lambda x, y: (1/(2*math.pi*sigma**2)) * math.e ** ((-1*((x-(size-1)/2)**2+(y-(size-1)/2)**2))/(2*sigma**2)), (size, size))
    return kernel / np.sum(kernel)

效果很好:

>>> vision.gaussianKernel(5, 1.5)
array([[ 0.01441882,  0.02808402,  0.0350727 ,  0.02808402,  0.01441882],
       [ 0.02808402,  0.05470021,  0.06831229,  0.05470021,  0.02808402],
       [ 0.0350727 ,  0.06831229,  0.08531173,  0.06831229,  0.0350727 ],
       [ 0.02808402,  0.05470021,  0.06831229,  0.05470021,  0.02808402],
       [ 0.01441882,  0.02808402,  0.0350727 ,  0.02808402,  0.01441882]])

因此,我创建了一个基本convolution函数来将其kernel应用于每个函数pixel并产生gaussian模糊:

def gaussianBlurOld(img, kSize, kSigma):
    kernel = gaussianKernel(kSize, kSigma)
    d = int((kSize-1)/2)
    gaussian = np.zeros((img.shape[0]-2*d, img.shape[1]-2*d))
    for y in range(d, img.shape[0]-d):
        for x in range(d, img.shape[1]-d):
            gaussian[y-d][x-d] = np.sum(np.multiply(img[y-d:y+d+1, x-d:x+d+1], kernel))
    return gaussian

它工作正常并且模糊了图像,但是,由于这段代码最终将在树莓派上运行,我需要它高效并且速度更快。因此,感谢我昨天提出的关于如何加速边缘检测器的问题的答案Sobel,我尝试将他给出的相同逻辑应用于gaussian过滤器。但是,由于function将接受 的variable大小参数kernel,因此与设置的Sobel内核大小(即3x3.

如果我正确理解了解释,我需要首先将内核分成xy组件,这可以通过使用原始的顶部row和左侧来完成(显然它们是相同的,但我决定将它们分开,因为我有内核已经计算)。下面是分离的矩阵:columnkernel2d

分离式过滤器

从这些rowcolumn向量中,我需要遍历每个值并将'window'数组的值乘以它的元素。在每个之后,将减小的窗口大小沿数组向右移动。为了更清楚地显示我认为我需要做的事情,这些是'windows'我正在谈论的 3 个不同kernel大小的小图像3x3

          _______3_______
     _____|_2_______    |
_____|_1__|____|    |   |
|    |    |    |    |   |
|123,|213,|124,|114,|175|
|235,|161,|127,|215,|186|
|128,|215,|111,|141,|221|
|224,|171,|193,|127,|117|
|146,|245,|129,|213,|221|
|152,|131,|150,|112,|171|

因此,对于每个'window',您乘以index内核中该窗口的 并将其添加到总数中。

然后,获取已应用内核x组件的img 并对组件执行相同操作。gaussiany

这些是我认为我可以gaussian比使用上述方法更快地计算模糊的步骤nested for-loops,这是我编写的尝试执行此操作的代码:

def gaussianBlur(img, kSize, kSigma):
    kernel = gaussianKernel(kSize, kSigma)
    gausX = np.zeros((img.shape[0], img.shape[1] - kSize + 1))
    for i, v in enumerate(kernel[0]):
        gausX += v * img[:, i : img.shape[1] - kSize + i + 1]
    gausY = np.zeros((gausX.shape[0] - kSize + 1, gausX.shape[1]))
    for i, v in enumerate(kernel[:,0]):
        gausY += v * gausX[i : img.shape[0]  - kSize + i + 1]
    return gausY

我的问题是这个函数产生了正确的“模糊效果”,但由于某种原因0,输出值都介于两者之间。幸运的是,由于某些其他原因,仍然可以正常显示输出,因此我可以检查它是否正确模糊了图像。3floatsmatplotlib

问题很简单:为什么像素值输出在0和之间3

我已经调试了几个小时,但找不到原因。我很确定某处只有一点缩放细节,但我就是找不到。任何帮助将非常感激!

4

1 回答 1

1

对于任何有兴趣的人来说,问题出在函数gaussianKernel返回2d kernel normalisedfor use 作为2d kernel. 这意味着,当我通过取顶部和左侧将其拆分为它的row和组件时,这些组件不是columnrowcolumn normalised

为了解决这个问题,我只是在gaussianKernel函数中添加了一个参数来选择2尺寸或1尺寸(都normalised正确):

def gaussianKernel(size, sigma, twoDimensional=True):
    if twoDimensional:
        kernel = np.fromfunction(lambda x, y: (1/(2*math.pi*sigma**2)) * math.e ** ((-1*((x-(size-1)/2)**2+(y-(size-1)/2)**2))/(2*sigma**2)), (size, size))
    else:
        kernel = np.fromfunction(lambda x: math.e ** ((-1*(x-(size-1)/2)**2) / (2*sigma**2)), (size,))
    return kernel / np.sum(kernel)

所以现在我可以得到1d kernelwith gaussianKernel(size, sigma, False),并让它normalised正确。这意味着我最终可以在没有scaled pixel值的情况下获得正确的模糊效果。

于 2017-10-05T12:40:13.667 回答