洪水填充实施

时间:2013-01-31 19:52:42

标签: c# flood-fill

这是我基于堆栈的泛洪填充算法的C#实现(我基于维基百科的定义)。在编码之前,我只想看到它的工作原理。它确实如此。然后,我想知道实际上填充的像素数。所以在我的代码中,我将返回类型更改为int并返回“ctr”变量。但是然后 ctr 大约是填充像素的实际数量的两倍(我制作了一个单独的函数,其唯一目的是计算这些像素 - 只是为了确切知道)。

任何人都可以启发变量“ctr”如何以及为什么会增加两倍?

* Pixel 类仅用作位图中像素的x,y和颜色值的容器。

public Bitmap floodfill(Bitmap image, int x, int y, Color newColor)
{
    Bitmap result = new Bitmap(image.Width, image.Height);
    Stack<Pixel> pixels = new Stack<Pixel>();
    Color oldColor = image.GetPixel(x, y);
    int ctr = 0;

    pixels.Push(new Pixel(x, y, oldColor));

    while (pixels.Count > 0)
    {
        Pixel popped = pixels.Pop();

        if (popped.color == oldColor)
        {
            ctr++;
            result.SetPixel(popped.x, popped.y, newColor);

            pixels.Push(new Pixel(popped.x - 1, popped.y, image.GetPixel(x - 1, y));
            pixels.Push(new Pixel(popped.x + 1, popped.y, image.GetPixel(x + 1, y));
            pixels.Push(new Pixel(popped.x, popped.y - 1, image.GetPixel(x, y - 1));
            pixels.Push(new Pixel(popped.x, popped.y + 1, image.GetPixel(x, y + 1));
        }
    }

    return result;
}

2 个答案:

答案 0 :(得分:7)

您可以在此处检查像素的颜色:

if (popped.color == oldColor)

但是popped.color可能(并且显然在50%的情况下)过时了。因为在将像素插入堆栈时不检查重复项,所以会有重复项。 弹出这些重复项后,很久以前就会保存颜色属性。

使用绘图可能会更清楚:

graphical explanation

作为一个例子,我拍摄了一个9像素的位图。在第一个窗格中,您有像素的编号,在右侧,您有堆栈。

从像素5开始,并在像素上推动像素2,4,6和8。然后你关闭像素2并按下1和3.在下一步中你弹出1然后按2和4(再次!)。然后你可以拿2,并意识到它在推动时已经获得了新的颜色。 (有点晚了,但迟到总比没有好) 但是:像素没有。 4是两次,并记住旧颜色两次。所以你取4号像素并给它着色。

稍后您会在图片中填充图像,但仍会在图像堆栈中显示一些项目。由于旧的颜色值仍存储在这些项目中,因此会再次计算。

虽然我可能在堆栈中排序错误,但该点仍然有效。

解决您的问题: 快速而肮脏(因为它仍然效率低下)

if (image.GetPixel(popped.x, popped.y) == oldColor)

仅当当前颜色错误时才计算像素,而不是记住的颜色。

建议:检查您的像素是否需要着色才能将它们推入堆叠。

答案 1 :(得分:0)

如果所有Pixel都保持传递给其构造函数的颜色,则在填充像素后它不会更新颜色,因此每个像素可以多次增加ctr。

如果更改Pixel以在其构造函数中获取指向图像的指针,则可以重新读取颜色(即使颜色成为读取当前颜色的get属性),或者跟踪已填充的坐标并且不要推动那是第二次。

[编辑]

如果从接受的答案中看不出来,GetPixel会返回一个颜色 - 值类型。可以把它想象成一个int,它编码那时像素的RGB值。

如果要快速执行填充,请查找Graphics.FloodFill示例。

如果您的目标是学习,我建议您将图像数据复制到阵列进行处理,然后再回来 - 大多数经典图像算法使用GetPixel()并不是很有趣。