哪种泛洪填充算法更适合性能?

时间:2012-02-16 20:22:58

标签: algorithm graphics recursion flood-fill

我正在尝试实现类似洪泛的算法。问题是我不知道我应该以什么方式实现它,例如递归 - 非递归 我知道每个都有缺陷,但其中一个必须比另一个快。当非递归每次分配4个新点时,递归在堆栈上打开新函数 非迭代的例子:

Stack<Point> stack = new Stack<Point>();
    stack.Push(q);
    while (stack.Count > 0)
    {
        Point p = stack.Pop();
        int x = p.X;
        int y = p.Y;
        if (y < 0 || y > h - 1 || x < 0 || x > w - 1)
                continue;
        byte val = vals[y, x];
        if (val == SEED_COLOR)
        {
                vals[y, x] = COLOR;
                stack.Push(new Point(x + 1, y));
                stack.Push(new Point(x - 1, y));
                stack.Push(new Point(x, y + 1));
                stack.Push(new Point(x, y - 1));
        }
    }

编辑:我将在600X600像素的地图上应用以下算法。尽管洪水填充不会应用于整个地图,但每次迭代它应覆盖约30%-80%的地图。我的观点是发现高度图中的边缘并标记这些边缘以供进一步使用。

4 个答案:

答案 0 :(得分:2)

this似乎是我发现的洪水填充最有效的实现......

我提到this answer中提到的边界填充技术是一个很好的技术,但不如quickfill好。

答案 1 :(得分:1)

制作一个掩码 - 一个平行的2-dim字节数组。未经检查的区域字节为0,对于洪水区域的新鲜边界,它将具有值1.对于洪水区域的内部 - 值2.并保留当前边界点的列表。

在外循环的任何一端,您都有具有标记的当前边界,内部和外部区域以及边界点阵列的蒙版。因此,您将仅在边框上检查新点。在检查边界点的第一个arraylist时,您正在创建第二个边框arraylist和第二个mask。在下一步中,您将重新创建第一个边框数组和蒙版。这样,我们可以使用简单的while循环而不是递归,因为您在任何步骤检查的数据结构都非常简单。

顺便说一句,你忘记检查新点的坐标是否在绘制的边框上或整个矩形的边框上。

至于在所有相邻点骑行,请查看我的算法here

答案 2 :(得分:0)

如果图像很复杂,递归填充可能会溢出堆栈。使用非递归填充。

如果您关心分配,可以将一个点表示为long类型的打包值,并编写自己的LongStack,在内部将long值存储在数组中。

答案 3 :(得分:0)

计算机非常高效地处理XY循环和2D阵列。

如果您可以使用XY循环和2D数组扫描泛洪,而不是使用各种逐步逻辑,则可能会很快。

最简单的逐步逻辑是泛洪递归函数,该函数仅检查4个邻居。这就是我过去在2017 i7处理器上实现每秒900万像素的原因。这是一段解释逻辑简单性的视频。它使用2D数组而不是内存(非常有效)并循环: https://www.youtube.com/watch?v=Xddws-50Igs enter image description here

这是一个带有视频的页面,该视频证明我在2012 FX处理器上以这种算法每秒获得400万个体素。(7秒钟内填充了3300万个体素) https://unity3dmc.blogspot.com/2017/02/ultimate-3d-floodfill-scanline.html?showComment=1537614917045#c9221615743847221048