【发布时间】:2017-10-02 20:25:55
【问题描述】:
我有一个2d numpy array 包含从0 到255 的greyscale 像素值。我想做的是创建一个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)相比,它稍微复杂了一些。
如果我理解正确,我需要首先将内核分成x 和y 组件,这可以通过使用原始kernel 的顶部row 和左侧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|
因此,对于每个'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
我的问题是这个函数产生了正确的“模糊效果”,但由于某种原因,输出值都在0 和3 之间,就像floats。幸运的是,由于某些其他原因,matplotlib 仍然可以正常显示输出,因此我可以检查它是否正确模糊了图像。
问题很简单:为什么像素值在0和3之间输出???
我已经调试了几个小时,但找不到原因。我很确定某处只有一点缩放细节,但我就是找不到。任何帮助将不胜感激!
【问题讨论】:
-
检查数据类型。如果可能的话,使用扩展的 dtypes-uint64/int64/float64。
-
@Divakar 我尝试将
gausX更改为每个dtypes,但是当设置为intdtype和float64时,它无法与内核进行乘法运算没有改变任何东西。 -
我尝试了一个简化的示例,似乎可以正常工作:
image = np.zeros((30,30))、image[:,15:] = 10000.0、i2 = gaussianBlurOld(image, 9, 3.0)、plt.imshow(i2)- 这会提供具有更高值的输出图像。 -
@VBB 抱歉,如果我不清楚,函数
gaussianBlurOld工作正常,但非常慢,因为它正在循环通过array。函数gaussianBlur不会循环通过array,所以应该更快,但产生的值太小...
标签: python numpy convolution gaussianblur