我有一个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
。
如果我正确理解了解释,我需要首先将内核分为 x
和 y
组件,这可以通过使用顶部 row< 来完成
和原始 kernel
的左 column
(显然它们是相同的,但我决定将它们分开,因为我有 2d
> 内核已计算)。下面是分离的矩阵:
从这些 row
和 column
向量中,我需要遍历每个值并将数组的 '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
我的问题是这个函数产生了正确的“模糊效果”,但输出值都在 0
和 3
之间,作为 floats
因为某些原因。幸运的是,由于某些其他原因,matplotlib
仍然可以很好地显示输出,这样我就可以检查它是否正确模糊了图像。
问题很简单:为什么输出的像素值在0
和3
之间???
我已经调试了几个小时但找不到原因。我很确定某个地方只有一点缩放细节,但我就是找不到它。任何帮助将不胜感激!
最佳答案
对于任何感兴趣的人来说,问题在于函数 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/