python - 线性分离高斯滤波器并使用 Numpy 进行计算

标签 python numpy convolution gaussianblur

我有一个2d numpy array,其中包含来自0灰度像素值到255。我想做的是高斯滤波器从头开始创建一个。我已经编写了一个函数来生成归一化高斯内核:

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

然后我创建了一个基本的卷积函数,将此内核应用于每个像素并产生高斯模糊:

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

它工作得很好,并且使图像模糊,但是,由于该代码最终将在树莓派上运行,我需要它高效且速度更快。感谢this answer关于我昨天问的关于如何加速 Sobel 边缘检测器的问题,我尝试应用他为高斯滤波器提供的相同逻辑。但是,由于函数将接受内核可变大小参数,因此它使事情稍微复杂化了Sobel的设置大小 内核只是 3x3

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

separated filter

从这些 rowcolumn 向量中,我需要遍历每个值并将数组的 'window' 乘以它的元素-明智的。在每一个之后,将窗口的缩小尺寸沿着数组向右移动。为了更清楚地展示我认为我需要做的事情,这些是我正在谈论的 3 个不同的 'windows',用于 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|

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

然后,获取已应用了 gaussian 内核的 x 组件的 img,并对 y 组件执行相同的操作.

这些是我认为可以比使用上面和这里的嵌套 for循环更快地计算高斯模糊的步骤是我编写的尝试执行此操作的代码:

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

我的问题是这个函数产生了正确的“模糊效果”,但输出值都在 03 之间,作为 floats因为某些原因。幸运的是,由于某些其他原因,matplotlib 仍然可以很好地显示输出,这样我就可以检查它是否正确模糊了图像。

问题很简单:为什么输出的像素值在03之间???

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

最佳答案

对于任何感兴趣的人来说,问题在于函数 gaussianKernel 返回了 2d kernel 归一化用作2d内核。这意味着当我通过获取顶部的和左侧的将其分成组件时,这些组件标准化

为了解决这个问题,我只是向 gaussianKernel 函数添加了一个参数来选择 2 维度或 1 维度(都是标准化的) 正确):

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)

现在我可以使用 gaussianKernel(size, sigma, False) 获得 1d kernel ,并将其设置为 正确标准化。这意味着我终于可以在没有缩放像素值的情况下获得正确的模糊效果。

关于python - 线性分离高斯滤波器并使用 Numpy 进行计算,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46533210/

相关文章:

python - 为 nose2 输出添加颜色

Python:ufunc 'add' 不包含具有签名匹配类型的循环 dtype ('S21' ) dtype ('S21' ) dtype ('S21' )

python - ctc 损失错误 - sequence_length(0) <= 3

python keras如何改变卷积层到lstm层后输入的大小

python - 当前在 Django 模板中获取主页 URL(域)的方法?

python - sns.regplot 显示了一个没有意义的回归阴影区域

python - 如何从 extract_first() 输出中删除 xpath?

python - numpy 是否为此积累了正确的东西?

python - 从 numpy 数组中删除元素时跟踪删除的索引

neural-network - 对象检测和对象分类有什么区别?