这是我基于堆栈的泛洪填充算法的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;
}
答案 0 :(得分:7)
您可以在此处检查像素的颜色:
if (popped.color == oldColor)
但是popped.color可能(并且显然在50%的情况下)过时了。因为在将像素插入堆栈时不检查重复项,所以会有重复项。 弹出这些重复项后,很久以前就会保存颜色属性。
使用绘图可能会更清楚:
作为一个例子,我拍摄了一个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()并不是很有趣。