线性分离高斯滤波器并使用 Numpy 计算
Linearly separating a Gaussian Filter and calculating with Numpy
我有一个 2d
numpy
array
包含从 0
到 255
的 greyscale
个像素值。我想要做的是从头开始创建一个 gaussian filter
。我已经写了一个函数来生成 normalized
高斯 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
它工作正常并使图像模糊,但是,由于此代码最终将在 raspberry pi 上 运行,我需要它高效且更快。因此,感谢 我昨天提出了一个关于如何加速 Sobel
边缘检测器的问题,我尝试将他给 gaussian
过滤器的相同逻辑应用。然而,由于 function
将接受 kernel
的 variable
大小参数,它使 Sobel
内核的设置大小稍微复杂化,即 3x3
.
如果我理解正确的话,我需要先将内核分成x
和y
组件,这可以通过使用top row
和left [=]来完成原始 kernel
的 38=] (显然它们是相同的,但我决定将它们分开,因为我已经计算了 2d
内核)。下面是矩阵分离:
从这些 row
和 column
向量中,我需要遍历每个值并将数组的 'window'
逐元素乘以它。在每一个之后,将 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'
,您乘以内核中 window 的 index
,并将其加到总数中。
然后,将应用了 gaussian
内核的 x
组件的 img 应用到 y
组件。
这些是我认为我可以计算 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
我的问题是这个函数产生了正确的 'blurring effect',但由于某种原因,输出值都在 0
和 3
之间,如 floats
。幸运的是,由于某些其他原因,matplotlib
仍然可以正常显示输出,所以我可以检查它是否正确模糊了图像。
问题很简单:为什么输出的像素值在0
和3
之间???
我已经调试了几个小时,但找不到原因。我很确定某处只有一点缩放细节,但我就是找不到。任何帮助将不胜感激!
对于任何感兴趣的人,问题出在函数 gaussianKernel
返回 2d
kernel
normalised
用作 2d
kernel
。这意味着当我通过取顶部 row
和左侧 column
将其拆分为 row
和 column
组件时,这些组件是 而不是 normalised
.
为了解决这个问题,我只是在 gaussianKernel
函数中添加了一个参数到 select 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
kernel
和 gaussianKernel(size, sigma, False)
,并让它正确地成为 normalised
。这意味着我终于可以在没有 scaled
pixel
值的情况下获得正确的模糊效果。
我有一个 2d
numpy
array
包含从 0
到 255
的 greyscale
个像素值。我想要做的是从头开始创建一个 gaussian filter
。我已经写了一个函数来生成 normalized
高斯 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
它工作正常并使图像模糊,但是,由于此代码最终将在 raspberry pi 上 运行,我需要它高效且更快。因此,感谢 Sobel
边缘检测器的问题,我尝试将他给 gaussian
过滤器的相同逻辑应用。然而,由于 function
将接受 kernel
的 variable
大小参数,它使 Sobel
内核的设置大小稍微复杂化,即 3x3
.
如果我理解正确的话,我需要先将内核分成x
和y
组件,这可以通过使用top row
和left [=]来完成原始 kernel
的 38=] (显然它们是相同的,但我决定将它们分开,因为我已经计算了 2d
内核)。下面是矩阵分离:
从这些 row
和 column
向量中,我需要遍历每个值并将数组的 'window'
逐元素乘以它。在每一个之后,将 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'
,您乘以内核中 window 的 index
,并将其加到总数中。
然后,将应用了 gaussian
内核的 x
组件的 img 应用到 y
组件。
这些是我认为我可以计算 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
我的问题是这个函数产生了正确的 'blurring effect',但由于某种原因,输出值都在 0
和 3
之间,如 floats
。幸运的是,由于某些其他原因,matplotlib
仍然可以正常显示输出,所以我可以检查它是否正确模糊了图像。
问题很简单:为什么输出的像素值在0
和3
之间???
我已经调试了几个小时,但找不到原因。我很确定某处只有一点缩放细节,但我就是找不到。任何帮助将不胜感激!
对于任何感兴趣的人,问题出在函数 gaussianKernel
返回 2d
kernel
normalised
用作 2d
kernel
。这意味着当我通过取顶部 row
和左侧 column
将其拆分为 row
和 column
组件时,这些组件是 而不是 normalised
.
为了解决这个问题,我只是在 gaussianKernel
函数中添加了一个参数到 select 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
kernel
和 gaussianKernel(size, sigma, False)
,并让它正确地成为 normalised
。这意味着我终于可以在没有 scaled
pixel
值的情况下获得正确的模糊效果。