【问题标题】:Linearly separating a Gaussian Filter and calculating with Numpy线性分离高斯滤波器并用 Numpy 计算
【发布时间】:2017-10-02 20:25:55
【问题描述】:

我有一个2d numpy array 包含从0255greyscale 像素值。我想做的是创建一个gaussian filter 从头开始。我已经写了一个函数来生成一个normalized gaussian kernel

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

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

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

从这些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|

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

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

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

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之间输出???

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

【问题讨论】:

  • 检查数据类型。如果可能的话,使用扩展的 dtypes-uint64/int64/float64。
  • @Divakar 我尝试将gausX 更改为每个dtypes,但是当设置为int dtypefloat64 时,它无法与内核进行乘法运算没有改变任何东西。
  • 我尝试了一个简化的示例,似乎可以正常工作:image = np.zeros((30,30))image[:,15:] = 10000.0i2 = gaussianBlurOld(image, 9, 3.0)plt.imshow(i2) - 这会提供具有更高值的输出图像。
  • @VBB 抱歉,如果我不清楚,函数 gaussianBlurOld 工作正常,但非常,因为它正在循环通过 array。函数gaussianBlur 不会循环通过array,所以应该更快,但产生的值太小...

标签: python numpy convolution gaussianblur


【解决方案1】:

对于任何感兴趣的人来说,问题在于函数 gaussianKernel 返回了 2d kernel normalised 以用作 2d kernel。这意味着当我将其拆分为 rowcolumn 组件时,将顶部 row 和左侧 column 分开,这些组件不是 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 kernelgaussianKernel(size, sigma, False) ,并正确设置为 normalised 。这意味着我终于可以在没有scaledpixel 值的情况下获得正确的模糊效果。

【讨论】:

    猜你喜欢
    • 2011-02-02
    • 2013-03-29
    • 2020-05-25
    • 2012-12-13
    • 1970-01-01
    • 1970-01-01
    • 2018-10-03
    • 2018-01-26
    相关资源
    最近更新 更多