执行此时,floodFill的不同方法 [英] Different Methods of Performing FloodFill

查看:157
本文介绍了执行此时,floodFill的不同方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

OK大家我有执行此时,floodFill几种不同的方法。所有这些导致问题。我将列出3种方法,并解释与每个人发生了什么。如果任何人都可以给我一些指点,将是巨大的。我已经看到了一些类似的职位,但他们都没有进行过C#,Java或VB.net(我知道的唯一语言)。

OK everyone I have several different methods of performing a FloodFill. All of them cause problems. I will list the 3 methods and explain what happens with each one. If anyone could give me some pointers that would be great. I have seen some similar posts but none of them have been for C#, java, or VB.net (the only languages I know).

这样做的吉文斯是我有一个名为PixelData取出类存储在CellColor成员变量的颜色。我有一个数组,其尺寸PixelData取出对象的50×50称为像素。我也有一个称为CANVAS_SIZE常数这是在这种情况下,50。这里有三种方法我已经尝试使用。

The givens for this are that I have a class called PixelData which stores a Color in a CellColor member variable. I have an array that is 50x50 of PixelData objects in size called "pixels". I also have a constant called CANVAS_SIZE which is 50 in this case. Here are the three methods I have tried using.

这一个是递归的。这是非常容易出现堆栈溢出。我已经尝试设置一个计时器,启用CanFill会员后,这种方法就完成了。这仍然不能防止溢出:

This one is recursive. It is EXTREMELY prone to stack overflows. I have tried settings a timer that enabled a CanFill member after this method is complete. This still does not prevent the overflows:

private void FloodFill(Point node, Color targetColor, Color replaceColor)
{
  //perform bounds checking X
  if ((node.X >= CANVAS_SIZE) || (node.X < 0))
    return; //outside of bounds

  //perform bounds checking Y
  if ((node.Y >= CANVAS_SIZE) || (node.Y < 0))
    return; //ouside of bounds

  //check to see if the node is the target color
  if (pixels[node.X, node.Y].CellColor != targetColor)
    return; //return and do nothing
  else
  {
    pixels[node.X, node.Y].CellColor = replaceColor;

    //recurse
    //try to fill one step to the right
    FloodFill(new Point(node.X + 1, node.Y), targetColor, replaceColor);
    //try to fill one step to the left
    FloodFill(new Point(node.X - 1, node.Y), targetColor, replaceColor);
    //try to fill one step to the north
    FloodFill(new Point(node.X, node.Y - 1), targetColor, replaceColor);
    //try to fill one step to the south
    FloodFill(new Point(node.X, node.Y + 1), targetColor, replaceColor);

    //exit method
    return;
  }
}



接下来我有一个使用基于队列填充的方法。此方法会导致内存不足的异常在运行时和填充整个画布时极为缓慢。如果只是填充画布的一小部分,却是有些有效的:

Next I have a method that uses a Queue based fill. This method causes OutOfMemory Exceptions at runtime and is EXTREMELY slow when filling the entire canvas. If just filling a small portion of the canvas, it is somewhat effective:

private void QueueFloodFill(Point node, Color targetColor, Color replaceColor)
{
  Queue<Point> points = new Queue<Point>();
  if (pixels[node.X, node.Y].CellColor != targetColor)
    return;

  points.Enqueue(node);

  while (points.Count > 0)
  {
    Point n = points.Dequeue();
    if (pixels[n.X, n.Y].CellColor == targetColor)
      pixels[n.X, n.Y].CellColor = replaceColor;

    if (n.X != 0)
    {
      if (pixels[n.X - 1, n.Y].CellColor == targetColor)
        points.Enqueue(new Point(n.X - 1, n.Y));
    }

    if (n.X != CANVAS_SIZE - 1)
    {
      if (pixels[n.X + 1, n.Y].CellColor == targetColor)
        points.Enqueue(new Point(n.X + 1, n.Y));
    }

    if (n.Y != 0)
    {
      if (pixels[n.X, n.Y - 1].CellColor == targetColor)
        points.Enqueue(new Point(n.X, n.Y - 1));
    }

    if (n.Y != CANVAS_SIZE - 1)
    {
      if (pixels[n.X, n.Y + 1].CellColor == targetColor)
        points.Enqueue(new Point(n.X, n.Y + 1));
    }
  }
  DrawCanvas();
  return;
}

这是我自己也尝试最后的方法使用基于队列此时,floodFill。这种方法要比前面的队列基础此时,floodFill更快,但也最终导致在运行时内存不足异常。再次,我已经尝试设置一个计时器FillDelay将阻止用户点击很快,但是这仍然没有发生停止例外。这一个另一个bug是,它也很难正确填写一小块区域。我看到在解决这个毫无意义的,直到我可以得到它不会崩溃。

The final method that I have tried also uses a queue based floodfill. This method is MUCH faster than the previous queue based floodfill but also eventually causes OutOfMemory exceptions at runtime. Again, I have tried setting a FillDelay timer that would prevent the user from rapidly clicking but this still doesn't stop the exceptions from occurring. Another bug with this one is that it has a hard time properly filling small areas. I see no point in fixing this until I can get it to not crash.

private void RevisedQueueFloodFill(Point node, Color targetColor, Color replaceColor)
{
  Queue<Point> q = new Queue<Point>();
  if (pixels[node.X, node.Y].CellColor != targetColor)
    return;

  q.Enqueue(node);
  while (q.Count > 0)
  {
    Point n = q.Dequeue();
    if (pixels[n.X, n.Y].CellColor == targetColor)
    {
      Point e = n;
      Point w = n;
      while ((w.X != 0) && (pixels[w.X, w.Y].CellColor == targetColor))
      {
        pixels[w.X, w.Y].CellColor = replaceColor;
        w = new Point(w.X - 1, w.Y);
      }

      while ((e.X != CANVAS_SIZE - 1) && (pixels[e.X, e.Y].CellColor == targetColor))
      {
        pixels[e.X, e.Y].CellColor = replaceColor;
        e = new Point(e.X + 1, e.Y);
      }

      for (int i = w.X; i <= e.X; i++)
      {
        Point x = new Point(i, e.Y);
        if (e.Y + 1 != CANVAS_SIZE - 1)
        {
          if (pixels[x.X, x.Y + 1].CellColor == targetColor)
            q.Enqueue(new Point(x.X, x.Y + 1));
        }
        if (e.Y - 1 != -1)
        {
          if (pixels[x.X, x.Y - 1].CellColor == targetColor)
            q.Enqueue(new Point(x.X, x.Y - 1));
        }
      }
    }
  }
}

感谢大家的帮助!所有这些方法都是基于对维基百科的伪代码

Thanks for everyone's help! All of these methods are based on pseudo code on wikipedia.

编辑:

我选择了RevisedQueueFloodFill和修改所建议的,使得没有变量在循环内声明。一个内存溢出仍会生成。即使有filldelay计时器。

I selected the RevisedQueueFloodFill and modified as suggested so that no variables are declared within the loops. An OutOfMemory is still generated. Even with a filldelay timer.

private void RevisedQueueFloodFill(Point node, Color targetColor, Color replaceColor)
{
  Queue<Point> q = new Queue<Point>();

  if (pixels[node.X, node.Y].CellColor != targetColor)
    return;

  q.Enqueue(node);

  Point n, e, w, x;
  while (q.Count > 0)
  {
    n = q.Dequeue();
    if (pixels[n.X, n.Y].CellColor == targetColor)
    {
      e = n;
      w = n;
      while ((w.X != 0) && (pixels[w.X, w.Y].CellColor == targetColor))
      {
        pixels[w.X, w.Y].CellColor = replaceColor;
        w = new Point(w.X - 1, w.Y);
      }

      while ((e.X != CANVAS_SIZE - 1) && (pixels[e.X, e.Y].CellColor == targetColor))
      {
        pixels[e.X, e.Y].CellColor = replaceColor;
        e = new Point(e.X + 1, e.Y);
      }

      for (int i = w.X; i <= e.X; i++)
      {
        x = new Point(i, e.Y);
        if (e.Y + 1 != CANVAS_SIZE - 1)
        {
          if (pixels[x.X, x.Y + 1].CellColor == targetColor)
            q.Enqueue(new Point(x.X, x.Y + 1));
        }
        if (e.Y - 1 != -1)
        {
          if (pixels[x.X, x.Y - 1].CellColor == targetColor)
            q.Enqueue(new Point(x.X, x.Y - 1));
        }
      }
    }
  }
}


推荐答案

我不知道这是否会工作,但我自己怀疑的是,很多更多的内存正在使用超过必要的,因为所有的'新'运营商,或许是由于该算法的密集性质,垃圾收集器没有机会在踢?

I have no idea if this will work, but my own suspicion is that a lot more memory is being used than necessary due to all the 'new' operators, and perhaps due to the intensive nature of the algorithm, the garbage collector didn't have a chance to kick in?

我已经重写了算法,使得所有的点变量先手而重复使用,但我目前没有得到这个测试的一种方式。

I've rewritten the algorithm so that all the Point variables just get reused rather, but I've not currently got a way of testing this.

我也考虑改变代码的前几行的自由,但这是因为我的一个忌讳,大部分洪水填写你发现有算法需要用户指定目标颜色的时候,其实你可以简单地自动从参数给出的点获得目标色彩。

I've also taken the liberty of altering the first few lines of code, but this is because of a pet peeve of mine that most flood-fill algorithms you find out there need the user to specify the target colour, when in fact you can simply get the target colour automatically from the point given in the argument.

总之,必须在使用这个,否则只是嘲笑它一个尝试:

Anyway, have a try at using this, or otherwise just laugh at it:

private void RevisedQueueFloodFill(Point node, Color replaceColor)
{
    Color targetColor = pixels[node.X, node.Y].CellColor;
    if (targetColor == replaceColor) return;

    Queue<Point> q = new Queue<Point>();
    q.Enqueue(node);

    Point n, t, u;

    while (q.Count > 0)
    {
        n = q.Dequeue();
        if (pixels[n.X, n.Y].CellColor == targetColor)
        {

            t = n;
            while ((t.X > 0) && (pixels[t.X, t.Y].CellColor == targetColor))
            {
                pixels[t.X, t.Y].CellColor = replaceColor;
                t.X--;
            }
            int XMin = t.X + 1;


            t = n;
            t.X++;
            while ((t.X < CANVAS_SIZE - 1) &&
                   (pixels[t.X, t.Y].CellColor == targetColor))
            {
                pixels[t.X, t.Y].CellColor = replaceColor;
                t.X++;
            }
            int XMax = t.X - 1;

            t = n;
            t.Y++;

            u = n;
            u.Y--;

            for (int i = XMin; i <= XMax; i++)
            {
                t.X = i;
                u.X = i;

                if ((t.Y < CANVAS_SIZE - 1) &&
                    (pixels[t.X, t.Y].CellColor == targetColor)) q.Enqueue(t);

                if ((u.Y >= 0) &&
                    (pixels[u.X, u.Y].CellColor == targetColor)) q.Enqueue(u);
            }
        }
    }
}

这篇关于执行此时,floodFill的不同方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆