0

I'm trying to implement flood fill on connected binary image regions, however I get StackOverflow error. Furthermore, how can I color each region with different color.

Thanks

public  void FloodFill(int x, int y)
{
    Bitmap bitmap = (Bitmap)pictureBox1.Image;

    if ((x < 0) || (y < 0) || (x >= bitmap.Width) || (y >= bitmap.Height)) { return; }

    Color cl = bitmap.GetPixel(x, y); // error An unhandled exception of type 'System.StackOverflowException' occurred in System.Drawing.dll

    if ((cl.R != 255) || (cl.G != 255) || (cl.B != 255)) { return; }
    if ((cl.R == 255) && (cl.G == 255) && (cl.B == 255)) {
        bitmap.SetPixel(x, y, Color.FromArgb(255, 255, 0, 0));
    }
    FloodFill(x, y - 1);
    FloodFill(x + 1, y - 1);
    FloodFill(x + 1, y);
    FloodFill(x + 1, y + 1);
    FloodFill(x, y + 1);
    FloodFill(x - 1, y + 1);
    FloodFill(x - 1, y);
    FloodFill(x - 1, y - 1);
}
for (int i = 0; i < pictureBox1.Width; i++)
{
    for (int j = 0; j < pictureBox1.Height; j++) {
        Point p = new Point(i, j);
        FloodFill(p.X, p.Y);
    }
}
Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • What another algorithm you suggest to use? And where can I find the code for it? thanks – Hannah Solomons Jan 04 '14 at 16:28
  • I'm using 8-connected neighbor method,I will use 4-connected neighbor instead. I followed this article pseudo-code : http://www.mcs.csueastbay.edu/~grewe/CS6825/Mat/BinaryImageProcessing/BlobDetection.htm – Hannah Solomons Jan 04 '14 at 16:44
  • @Adriano, the infinite recursion problem will not actually occur. FloodFill(0,0) will set pixel (0,0) to cyan, and then call FloodFill(0,1) which will then call FloodFill(0,0) which will return because pixel (0,0) is cyan, not white. The algorithm is ineficient, but shouldn't recurse indefinitely. – Gavin S. Yancey Jan 04 '14 at 17:17
  • The code works well on small image areas, but it get error on bigger images, still not solved – Hannah Solomons Jan 04 '14 at 17:23
  • @g.rocket you're right! Hannah: then you're simply running out of stack space. – Adriano Repetti Jan 04 '14 at 17:35
  • If you have two questions then *ask two questions*. Don't try to put two questions into one; the second question usually goes unanswered. – Eric Lippert Jan 04 '14 at 17:52

2 Answers2

4

PMF is correct; you should be using an iterative algorithm for this.

The iterative algorithm is:

Fill(coordinate)
    stack = new Stack<Coordinate>()
    stack.Push(coordinate)
    while !stack.IsEmpty
        current = stack.Pop();
        if bitmap[current] is not white then continue
        bitmap[current] = black
        stack.Push(current.NorthNeighbour)            
        stack.Push(current.SouthNeighbour)
        etc.

Do you see how that works? The idea is that rather than using the call stack as your temporary storage, you actually allocate your own stack.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
3

I guess the problem has to do with the order of the recursion. In the worst case, you're (almost) going to process the whole image depth-first. The recursion could be as deep as there are total pixels in the image.

Lets assume we start at the bottom left of an image of 10x10. The first few steps are:

  • We're entering the first FloodFill(x, y-1) recursively until y = 0 => Stack depth 10
  • Backtracking one step, the next we can do is FloodFill(x+1, y) until x = 9, y = 0 => Stack depth 19
  • Backtracking again, the next we do is FloodFill(x-1, y) until x = 1, y = 0 => Stack depth 27
  • Now is the first time we need to go more than one level up in the stack.

So you need a stack size of at least 2*width+2*height of the image - and the above is just a quick analysis. This might be to much.

Suggestion: Use an iterative algorithm.

PMF
  • 14,535
  • 3
  • 23
  • 49