Python 高斯滤波器的线性分离与Numpy计算
我有一个Python 高斯滤波器的线性分离与Numpy计算,python,numpy,convolution,gaussianblur,Python,Numpy,Convolution,Gaussianblur,我有一个2dnumpy数组包含灰度像素值,从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, s
2d
numpy
数组
包含灰度
像素值,从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
这很好,模糊了一个图像,然而,由于这段代码最终将运行在一个树莓圆周率,我需要它是有效的,它要快得多。由于昨天我问了一个问题,关于如何加速Sobel
边缘检测器,我尝试将他给出的相同逻辑应用于gaussian
滤波器。但是,由于函数
将为内核
接受一个变量
大小参数,因此与Sobel
内核的设置大小相比,它稍微使事情复杂化,而内核的设置大小为3x3
如果我正确理解了解释,我需要首先将内核分为x
和y
两个组件,只需使用原始内核的顶部行和左侧列即可(显然它们是相同的,但我决定将它们分开,因为我已经计算了2d
内核)。下面是分开的矩阵:
从这些行
和列
向量中,我需要遍历每个值,并将数组的'window'
按元素相乘。在每一个值之后,将缩小的窗口沿数组向右移动。为了更清楚地显示我认为需要做的事情,以下是3个不同的'windows'
I我说的是一个内核大小为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
组件执行相同操作
这些是我认为我可以做的计算高斯
模糊的步骤,比使用嵌套
循环
要快得多
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
之间,因为由于某种原因浮动了。幸运的是,由于其他原因,matplotlib
仍然可以很好地显示输出,因此我可以检查它是否正确地模糊了图像
问题很简单:为什么像素值在0
和3
之间输出
我已经调试了几个小时,但找不到原因。我很确定某个地方有一些缩放细节,但我就是找不到。任何帮助都将不胜感激!对于任何感兴趣的人来说,问题在于函数gaussianKernel
返回了2d
内核
标准化的
用作2d
内核
。这意味着,当我通过取顶部行
和左侧列
将其拆分为行
和列
组件时,这些组件没有标准化
为了解决这个问题,我刚刚在gaussianKernel
函数中添加了一个参数,以选择2
维度或1
维度(两个均已正常化
):
因此,现在我可以使用gaussianKernel(size,sigma,False)获得1d
内核
,并将其正常化。这意味着我最终可以获得正确的模糊效果,而无需缩放像素值。检查数据类型。如果可能,使用扩展数据类型-uint64/int64/float64。@Divakar我尝试将gausX
更改为初始化为这些dtypes
,b但是,当设置为int
dtype
时,它无法与内核相乘,float64
没有任何变化。我尝试了一个简化的示例,似乎可以工作:image=np.zeros((30,30))
,image[:,15:=10000.0
,i2=gaussianblurld(image,9,3.0)
,plt.imshow(i2)
-这会使输出图像具有更高的值。@VBB如果我不清楚,很抱歉,函数GaussianBlurd
工作正常,但在数组中循环时速度非常慢。函数gaussianBlur
不会在数组中循环,因此应该更快,但产生的值太小。。。
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)