有效填充3D矩阵中的空单元格

时间:2014-06-23 04:50:10

标签: algorithm data-structures matrix

我有一个3D“立方体”矩阵,其中一些单元格填满,其他单元格为空。由填充的细胞包围的封闭区域表示中空形状。例如,矩阵可以以这样的方式填充单元,使得它们一起形成空心球的表面。现在,我想要一种有效的方法来填充这个球体的内部:如果一个单元格C0被填充的单元格在所有方向上包围(任何方向上的填充单元格都不需要是C0的直接邻居) ,然后填写C0

一种天真的方式如下: -

  

对于每个单元格,扫描+ X,-X,+ Y,-Y,+ Z,-Z方向,然后查看   如果你在每个方向都遇到一个充满细胞的细胞。

     

如果在每个方向遇到填充的单元格,则填写此单元格   细胞(因为它是某种形状内部的一部分)。

     

如果你在一个方向上到达网格的末端而没有遇到任何填充   细胞,然后考虑的细胞不是任何形状的内部,   并且应该保持未填充状态。

上述方法的复杂性为O(n^4),其中3D网格的维度为n*n*n

优化可以如下: -

  

如果对于未填充的单元格C [x] [y] [z],我们遇到一个填充的单元格   在所有6个方向中,不仅C [x] [y] [z]需要   填补后,我们也会保证扫描所有细胞   刚才(即{in + X方向,所有单元格C [x] [y] [z],C [x + 1] [y] [z],   C [x + 2] [y] [z],......,直到第一个填充的单元格},类似于-X,+ Y,   -Y,+ Z,-Z方向)必须是某种形状内部的一部分,因此必须填充。

另一个可能如下: -

  

如果对于未填充的单元格C [x] [y] [z],我们不会遇到任何填充   例如,+ X方向的单元格,那么不仅C [x] [y] [z]将保留   未填充,也保证我们扫描的所有细胞   刚才(即在+ X方向,所有单元格C [x] [y] [z],C [x + 1] [y] [z],   C [x + 2] [y] [z],......,直到网格结束)必须是外部的一部分   因此,必须保持未填充状态。

有人可以提出一个更有效的方法解决这个问题吗?即使是像上面这样简单的优化,也可能不会减少时间复杂度的顺序,这是值得欢迎的。

4 个答案:

答案 0 :(得分:2)

您正在处理3D Flood Fill。查看详细的维基百科文章http://en.m.wikipedia.org/wiki/Flood_fill

答案 1 :(得分:1)

好的,因为这是一个封闭的空心形状,我们只需使用BFSDFS来解决问题。

BFS:

从空队列开始,将任何位于内部空心形状的单元格添加到队列中。从队列的顶部,弹出一个单元格,填充此单元格并检查此单元格的其他6个邻居,如果未填充此邻居,则将其添加到队列中,否则只需忽略此单元格。继续此过程,直到队列为空。

剩下的问题是找到一个位于空心形状内的单元格,一个技巧就是你需要找到位于形状一角的单元格,它至少有三个填充的邻居

时间复杂度为O(填充单元格所需的数量* 6方向需要检查)

提示移至6方向:

int[] x = {0,0,0,0,1,-1};
int[] y = {0,0,1,-1,0,0};
int[] z = {1,-1,0,0,0,0};

Point p = // point in space with three dimension x,y,z

for(int i = 0; i < 6; i++){
     int a = p.x + x[i];
     int b = p.y + y[i];
     int c = p.z + z[i];
}

答案 2 :(得分:0)

  

对于每个单元格,扫描+ X,-X,+ Y,-Y,+ Z,-Z方向,看看是否在每个方向都遇到填充单元格。

     

如果在每个方向遇到填充的单元格,则填充此单元格(因为它是某个形状内部的一部分)。

除非您只处理convex hulls,否则上述声明不正确。下图显示有问题的点未包含在蓝色形状中,但仍会在所有(x,y,z)方向上相交。

enter image description here

相反,要处理查找挖空形状的一般情况,可以将所有单元格添加到Set中。然后从边界单元开始。如果填充边界处的单元格是空心形状的一部分,否则它是背景(非填充)形状的一部分。

然后,类似于@Pham Trung的回答,你可以向各个方向向外移动,直到你遍历了形状内的所有细胞,忽略边界处的有色细胞。在前一个形状的边界处选择另一个单元格,然后开始该过程,直到遍历所有单元格。

最后,您将每个单元格标记为空心形状或背景的一部分。

答案 3 :(得分:0)

为了完整,还有两个。 YMMV取决于很多因素。

<强> 1。找到表面

如果您正在处理大量体素,一种优化可能性是找到空心的边界表面。这可以像Pham Trung的答案那样完成,但只接受至少填充了6个邻居中的一个的单元格。

确定边界表面后,可以使用1D填充逐行填充,作为方向&#34;内部&#34;和&#34;外面&#34;众所周知。

如果你有大量的体素(比例为n ^ 2而不是n ^ 3),这种方法可以使设置的体积小得多。设置查找通常非常快,但如果设置不适合RAM,它们会慢下来。

<强> 2。切片到2D

另一种可能性是将形状切割成2D切片并逐层连接所得到的腔。然后,只需要将两个切片同时保存在内存中。

主要思想是为每个单独连接的2D区域提供自己的标识符,然后找到它与相邻层中已知区域的连接。处理完所有图层后,将保留连接的3D区域。

具有挑战性的部分是找到连接相邻层中2D区域的最佳算法。看起来这种方法很快就具有简单的形状(2D切片中的连接区域很少)但是复杂的形状很慢(&#34;树中的虫洞和#34;)。此外,需要一种快速算法来找到两组中的单个公共点。 (即,不需要完整的集合交集,只需要有关集合是否至少有一个公共点的信息。)

同样,如果您的集合大小合理,那么Pham Trung描述的平凡算法可能是最佳选择。