在Python中编写循环过滤器

时间:2017-07-31 22:13:12

标签: python

我找到了一个使用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

办?

我发布此作为我之前的一个问题的答案,但没有回复,所以我将其作为一个新问题发布。

2 个答案:

答案 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] == yX_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.另外,请注意kernelmask的维度是如何匹配的。两者都是多维的。图像副本中的其余值仍设置为零,如第一行中所做的那样。

     filtered_image = gf(image_data, np.median, footprint = kernel)

这是最后一部分,一切都拼凑在一起。原始数据存储在image_data中,并且存在kernel,它是应用了蒙版的图像副本,指示不应更改数据的位置。它们都作为参数传递给实际的过滤函数gf(代表通用过滤器),输出是一个新的过滤图像。

这是图像过滤的核心概念,如果您想了解更多信息,我建议您先学习基本的信号处理概念。信号处理课程涵盖了这些概念如何工作的数学,但通常用真正抽象的数学来解释,因为这个概念可以应用于许多不同的例子。