我找到了一个使用scipy制作圆形过滤器的代码片段,我想了解它是如何工作的。我知道在skimage中有一个更好的,但我对这个中发生的事情很感兴趣。
from scipy.ndimage.filters import generic_filter as gf
# Define physical shape of filter mask
def circular_filter(image_data, radius):
kernel = np.zeros((2*radius+1, 2*radius+1))
y, x = np.ogrid[-radius:radius+1, -radius:radius+1]
mask = x**2 + y**2 <= radius**2
kernel[mask] = 1
filtered_image = gf(image_data, np.median, footprint = kernel)
return filtered_image
但我不确定我完全理解发生了什么。特别是,行是什么
y, x = np.ogrid[-radius:radius+1, -radius:radius+1]
mask = x**2 + y**2 <= radius**2
kernel[mask] = 1
办?
我发布此作为我之前的一个问题的答案,但没有回复,所以我将其作为一个新问题发布。
答案 0 :(得分:1)
详细查看您的代码:
kernel = np.zeros((2*radius+1, 2*radius+1))
y, x = np.ogrid[-radius:radius+1, -radius:radius+1]
mask = x**2 + y**2 <= radius**2
kernel[mask] = 1
第一行:
kernel = np.zeros((2*radius+1, 2*radius+1))
创建一个2-d的零数组,中心点和两侧的“半径”点。对于radius = 2,您将获得:
# __r__ +1 __r__
[ 0, 0, 0, 0, 0, ] #\
[ 0, 0, 0, 0, 0, ] #_} r
[ 0, 0, 0, 0, 0, ] # +1
[ 0, 0, 0, 0, 0, ] #\
[ 0, 0, 0, 0, 0, ] #_} r
接下来,您将从numpy.ogrid
创建的打开网格网格中获取两个数组。网格网格是numpy中的“技巧”,涉及存储“并行”数组或矩阵,该数组或矩阵将特定单元格的x或y坐标保存在该单元格的位置。
例如,y
- 网格网格可能如下所示:
[ 0, 0, 0, 0, 0, ]
[ 1, 1, 1, 1, 1, ]
[ 2, 2, 2, 2, 2, ]
[ 3, 3, 3, 3, 3, ]
[ 4, 4, 4, 4, 4, ]
x
- 网格可能如下所示:
[ 0, 1, 2, 3, 4, ]
[ 0, 1, 2, 3, 4, ]
[ 0, 1, 2, 3, 4, ]
[ 0, 1, 2, 3, 4, ]
[ 0, 1, 2, 3, 4, ]
如果你看一下它们,你会发现Y_grid[x][y] == y
和X_grid[x][y] == x
通常很有用,它有多个numpy函数来支持它。 ; - )
打开网格类似于封闭网格,只是它只有“一维”。也就是说,不是一对(例如)5x5数组,而是获得1x5数组和5x1数组。这就是ogrid
所做的 - 它返回两个开放的网格。根据python规则(意味着半径+ 1被省略),值从-radius到radius + 1:
y, x = np.ogrid[-radius:radius+1, -radius:radius+1]
所以y是一个 numpy数组,存储自例如-2..2(含),而x是-2..2(含)的数组。下一步是构建一个布尔掩码 - 即一个充满布尔值的数组。如你所知,当你在一个numpy数组上运行时,你会得到另一个numpy数组。因此,在具有常量的表达式中涉及两个数组会产生另一个数组:
mask = x**2 + y**2 <= radius**2
mask的值将是一个2色位图,其中一种颜色为“True”,另一种颜色为“False”。位图将描述实心圆或磁盘。 (因为<=
关系。记住x和y包含-2..2,而不是0..4。)
最后,通过使用掩蔽数组作为kernel
数组(零)的覆盖,将类型Boolean转换为int,只要掩码为“True”,就将零设置为1:
kernel[mask] = 1
此时,内核看起来像:
# __r__ +1 __r__
[ 0, 0, 1, 0, 0, ] #\
[ 0, 1, 1, 1, 0, ] #_} r
[ 1, 1, 1, 1, 1, ] # +1
[ 0, 1, 1, 1, 0, ] #\
[ 0, 0, 1, 0, 0, ] #_} r
答案 1 :(得分:0)
我对SciPy并不熟悉,但我会尝试解释基本概念。
整个功能的目的是通过应用滤镜来改变原始图像。这个过滤器可以做很多事情,从改变图像的对比度,或添加特殊效果等。
让我们看看不同的路线:
kernel = np.zeros((2*radius+1, 2*radius+1))
在此行中,正在创建图像数据的副本,但所有数据都为零(因此正在使用零功能)。这样掩模可以在以后应用到它上面。
y, x = np.ogrid[-radius:radius+1, -radius:radius+1]
这创建了所谓的“网格”或多维网格。这是为了创建圆形“面具”。就像在图表上的方式一样,x和y轴具有均匀间隔的缩放比例,这在网格网格中也是必要的。 在这种情况下,x和y变量存储均匀间隔的值,用作轴的缩放。
mask = x**2 + y**2 <= radius**2
这里,正在创建一个“掩码”。掩码将用作图像中要保护免受滤波器影响的区域,以便不改变任何原始数据。注意如何在毕达哥拉斯不等式中使用x和y变量(重要的是看它不仅仅是圆形而是磁盘),就像它们在数学意义上的方式一样。这将创建一个具有给定半径的磁盘,该磁盘现在被视为掩码。 mask变量现在包含不应更改原始数据值的所有坐标(x,y)。
kernel[mask] = 1
这是掩码现在应用于先前创建的图像副本的位置。现在,有一个完美的图像副本(即相同的尺寸),但有一个类似磁盘的“掩码”,“保护”原始数据不被改变。这就是为什么磁盘覆盖的所有点都设置为1.另外,请注意kernel
和mask
的维度是如何匹配的。两者都是多维的。图像副本中的其余值仍设置为零,如第一行中所做的那样。
filtered_image = gf(image_data, np.median, footprint = kernel)
这是最后一部分,一切都拼凑在一起。原始数据存储在image_data
中,并且存在kernel
,它是应用了蒙版的图像副本,指示不应更改数据的位置。它们都作为参数传递给实际的过滤函数gf
(代表通用过滤器),输出是一个新的过滤图像。
这是图像过滤的核心概念,如果您想了解更多信息,我建议您先学习基本的信号处理概念。信号处理课程涵盖了这些概念如何工作的数学,但通常用真正抽象的数学来解释,因为这个概念可以应用于许多不同的例子。