【问题标题】:Flood filling of 3-dimensional polygon3维多边形的洪水填充
【发布时间】:2011-09-30 18:20:29
【问题描述】:

这是给你的一个问题;)

我有一个用 1 和 0 填充的 3 维数组。 1 代表 3 维复杂多边形(不是简单多边形)。只有多边形的边界值为 1,内部填充为 0。现在问题来了:

我需要一个快速算法来用 1 填充这些多边形。数组的维度通常约为。 512x512x100。

提前致谢!

这是 2d 中的示例:

0000111110000
0000100010000
0000100010000
0000111110000

应该会导致

0000111110000
0000111110000
0000111110000
0000111110000


这是@Mikolas 算法的正确 3 维解决方案吗?

    void scan_polygon(int frames, int rows, int cols, char data[][][], char result[][][]){
for(int f=0; f < frames; ++f)
for(int r=0; r<rows; ++r)
for(int s = 0, c=0; c<cols-1; ++c)
{
    s ^= s ? ( data[f][r][c] && !data[f][r][c+1]) :
             (!data[f][r][c] &&  data[f][r][c-1]);

    result[f][r][c] = s;
}

for(int f=0; f < frames; ++f)
for(int c=0; c<cols; ++c)
for(int s = 0, r=0; r<rows-1; ++r)
{
    s ^= s ? ( data[f][r][c] && !data[f][r+1][c]) :
             (!data[f][r][c] &&  data[f][r-1][c]);

    result[f][r][c] &= s;
}

}

最好的问候,

斯特夫

【问题讨论】:

  • 当您说“flood-fill”时,您的意思是要将整个数组初始化为值1吗?或者您只是想要一种快速的方法将边界点设置为1,并将数组的其余部分设置为0
  • 每个数组代表一个多边形吗?
  • 我同意@6502; 3 空间中的复杂多边形甚至没有 明确定义的“内部!”如果您发布一个小数组的示例和所需的输出,我们将有更好的机会帮助您。 -1 直到那时。
  • 我认为他的意思是多面体,而不是多边形。 IIUC FACES 的内部都是 1,但多面体是“空的”
  • 哇,你们真快。到目前为止谢谢!

标签: c++ math polygon computational-geometry flood-fill


【解决方案1】:

如果您假设您的多边形是多方面的,您可以在单个 for 循环中执行此操作。只需从左上​​角开始,并在越过边缘时跟踪奇偶校验。

一个简单的 2D 版本(添加了转置案例):

void scan_polygon(int rows, int cols, char** data, char** result)
{
    for(int r=0; r<rows; ++r)
    for(int s = 0, c=0; c<cols-1; ++c)
    {
        s ^= s ? ( data[r][c] && !data[r][c+1]) :
                 (!data[r][c] &&  data[r][c-1]);

        result[r][c] = s;
    }


    for(int c=0; c<cols; ++c)
    for(int s = 0, r=0; r<rows-1; ++r)
    {
        s ^= s ? ( data[r][c] && !data[r+1][c]) :
                 (!data[r][c] &&  data[r-1][c]);

        result[r][c] &= s;
    }
}

如果您有一个悬空像素或沿扫描线突出的边缘,则可能会出现这种情况,例如:

00000000000000000000        
00000000*11111111111   <--- Whoops!
000000*111*000000000
00000*11111*00000000

要解决此问题,您只需在转置数组上重复该过程,然后将所有结果组合在一起。 Sud 等人使用了类似的方法在 GPU 上对网格进行体素化。它并非完美无缺,因为您可以配置多个非流形顶点,它们的嘈杂圆锥相交,但如果您能保证不会发生这种情况(或者如果它很少发生),它就是其中之一我知道的最简单的方法可以快速获得结果。

编辑:修改后的解决方案显示如何在迭代后将数组重新组合在一起。

【讨论】:

  • 太棒了!这也应该在 3D 中工作,尽管 OP 必须弄清楚在这种情况下“转置 ... AND”是什么意思。
  • 是的,这看起来确实是一个不错的解决方案。克里斯是对的,您能否解释一下“与转置数组进行与运算”的含义。到目前为止,谢谢,你很棒!
  • @stef:当然,我刚刚更新了解决方案。在 3D 中,您可能希望对 3 个轴中的每一个都执行此操作。
  • @stef 因为您需要了解在 3D 中实现此功能的过程,所以让我详细说明一下:当您从 Mikola 的“左上角”开始运行它时示例数据,您的其中一行将有一个00000000*11111111111。如果你从“右下角”运行 if,你会得到 11111111*00000000000 。由于他们不同意,实际上整个事情应该是0。您将需要尝试一些具有锯齿边缘的示例多面体,以确定如何在 3D 中实现这一点。
  • 另请注意,即使您在每个轴上进行遍历,这种技术在存在非流形点时仍然会失败。可靠地解决这些问题的唯一方法是过滤数据以去除这些角落,或者修改扫描线过程以跳过它们。
【解决方案2】:

我认为在这种情况下可以使用标准的填充方法:

active_cells = [seed]
while active_cells:
    new_active_cells = []
    for cell in active_cells:
        for nh in neighbor(cell):
            if not filled(nh):
                fill(nh)
                new_active_cells.append(nh)
    active_cells = new_active_cells

如果您不确定内部或外部是否已连接(因此无法找到单个“种子”),那么您可以做的是遍历所有单元格,一旦找到一个为零的单元格然后你可以调用上面的floodfill代码来计算连通分量。对其他发现为零的单元格重复此操作,您最终将得到所有连接区域,这些区域将面划分为空间。

当然,要使上面的代码正常工作,就选择的连通性而言,面是紧密的。

【讨论】:

  • 也许我理解错了,但这不会把边界外的东西和边界内的东西都填满吗?
  • 如果种子在里面并且边界很细(取决于所使用的连接性的定义),那么油漆将无法逃脱多面体。请注意,这假定多面体具有实心面,而不仅仅是边缘。就像我之前说的那样,问题不是很好。
  • 哦!我完全错过了你在这里所做的事情,从一粒种子开始。由于这是一个复杂的区域,并且可能有多个“内部”位,因此他实际上需要先用 2s 或其他东西填充 outside,因为我认为外部肯定是一个连接区域,然后将所有剩余的 0 替换为 1。顺便说一下+1。 :P
  • 根据拓扑结构,实际上甚至“外部”都没有连接。例如,考虑另一个球体内的一个球体......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-02-26
  • 1970-01-01
  • 2021-12-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-02
相关资源
最近更新 更多