我试图使用numpy / scipy对图像做一些模糊的过滤器(我认为)。我想要的本质上是一个窗口概率分布。我从灰度图像开始。对于给定像素和NxN
内核,N
奇数,我想计算相对于内核中其他像素的像素值的概率。此外,我想尽快进行此计算。
因此,例如给定图像的3x3区域:
[0, 0, 0;
0, 0, 0;
255, 255, 255]
中心像素应从0
转换为0.66
,因为它在该3x3区域中有2/3的可能性。在代码中,我可以执行以下操作,但它太慢了:
# loops through calculating probability distributions for each window
# generates new_image
for yi in range(0, height):
for xi in range(0, width):
window = kernel_region(image, yi, xi, ksize)
hist = np.histogram(window.ravel(), 256, [0, 256])
pdf = hist / np.size(window)
pixel_value = image[yi, xi]
new_image[yi, xi] = pdf[pixel_value]
# gives ksize x ksize slice of the image (smaller on the edges)
def kernel_region(image, yi, xi, ksize):
height, width = image.shape[:2]
offset = math.floor(ksize / 2)
yStart = max(0, yi - offset)
yEnd = min(height - 1, yi + offset)
xStart = max(0, xi - offset)
xEnd = min(width - 1, xi + offset)
return image[yStart:yEnd, xStart:xEnd]
我可以在循环中进行一些优化,但我想避免使用循环。是否可以使用" pure" numpy功能?
答案 0 :(得分:1)
有趣的数学问题,似乎会有Scikit-image's view_as_windows
的简单解决方案来获取(3,3)
滑动窗口,然后与中心像素进行比较,以便在窗口中获取其出现次数并最终划分按内核大小9
。
因此,图像a
的实现将是 -
from skimage.util.shape import view_as_windows
(view_as_windows(a,(3,3)) == a[1:-1,1:-1,None,None]).sum((-2,-1))/9.0
这为我们提供了非边界元素的结果。为了覆盖所有元素,我们可以使用无效的说明符填充图像,在它周围说-1
,然后使用建议的方法。
示例运行 -
In [61]: a
Out[61]:
array([[ 1, 0, 0, 0, 3, 4],
[ 2, 0, 0, 0, 6, 0],
[ 4, 255, 255, 255, 8, 2],
[ 0, 5, 0, 5, 6, 2]])
In [76]: (view_as_windows(a,(3,3)) == a[1:-1,1:-1,None,None]).sum((-2,-1))/9.0
Out[76]:
array([[ 0.44, 0.67, 0.44, 0.11],
[ 0.22, 0.33, 0.22, 0.11]])
涵盖所有元素 -
In [74]: a1 = np.pad(a, (1,1), 'constant', constant_values=(-1, -1))
In [75]: (view_as_windows(a1,(3,3)) == a1[1:-1,1:-1,None,None]).sum((-2,-1))/9.0
Out[75]:
array([[ 0.11, 0.44, 0.67, 0.44, 0.11, 0.11],
[ 0.11, 0.44, 0.67, 0.44, 0.11, 0.11],
[ 0.11, 0.22, 0.33, 0.22, 0.11, 0.22],
[ 0.11, 0.11, 0.11, 0.11, 0.11, 0.22]])