0

I have a Java program containing an image, and I'm trying to have a flood fill agorithm to repleace each black pixel with a white one within the enclosed area, using the following function(canvas is a BufferedImage):

public void floodFill(Point2i start, int target, int grep){
    if(start.x < 0 || start.x >= width || start.y < 0 || start.y >= height)return;
    if(canvas.getRGB(start.x, start.y) != target)return;
    canvas.setRGB(start.x, start.y, grep);
    floodFill(new Point2i(start.x+1, start.y), target, grep);
    floodFill(new Point2i(start.x-1, start.y), target, grep);
    floodFill(new Point2i(start.x, start.y+1), target, grep);
    floodFill(new Point2i(start.x, start.y-1), target, grep);
}

Problem is, I get a java.lang.StackOverflowError on the third line.... I figure there must be a better way to do this that doesn't cause this error, isn't there? I'm running the JVM with a decent amount of RAM(2 GB), so how can I write a flood fill function for a BufferedImage that works?

user2649681
  • 750
  • 1
  • 6
  • 23
  • Short answer: If a recursive call is giving you a `StackOverflowError`, then you aren't handling the base cases of your recursion correctly. Chances are, it's either an off-by-one error or a `>` vs. `>=` issue in your base case checks. – Xynariz Feb 27 '15 at 02:09
  • @Xynariz In this case I don't think so. the base case is `color==target` and that seems fine to me. – k_g Feb 27 '15 at 02:16
  • @k_g If you're using 2GB of ram, the only reasonable assumption is that your base cases are off. Maybe they hit some of the time, but I can guarantee that they don't catch every case. It only takes one thread of runaway calls to overflow. – Xynariz Feb 27 '15 at 02:20
  • 1
    @Xynariz I think the user has increased their memory but not their stack, hence the exception – k_g Feb 27 '15 at 02:21
  • @Xynariz I am of course assuming that 2 GB refers to the maximum allocation setting rather than the actual amount of memory used. "I'm running the JVM with a decent amount of RAM(2 GB)" – k_g Feb 27 '15 at 02:25
  • FWIW: Here's a good link, describing various flood fill algorithms, their strengths and weaknesses: [QuickFill: An efficient flood fill algorithm](http://www.codeproject.com/Articles/6017/QuickFill-An-efficient-flood-fill-algorithm) (code in C, but the algorithms still applies). Try implementing a non-recursive version, and you'll avoid the SOE. :-) – Harald K Feb 27 '15 at 08:31

2 Answers2

2

If target equals grep, your program always goes back to the previous point.

For example:

  • From Point(0,0) -> go to point (1,0) ...
  • From Point(1,0) -> go to point (2,0) , then Point (0,0)

So, you should check for all visited points by using a boolean array or similar. Take a look at Depth first search for more info.

You can consider switching from recursive to iterative approach, which is more memory-friendly, see Breadth first search for more info.

Increase stack size can help too, as k_g has already pointed out in his/her answer.

Pham Trung
  • 11,204
  • 2
  • 24
  • 43
  • _-1_ No it doesn't, because the value of color for that point would have changed. This answer is inaccurate – k_g Feb 27 '15 at 02:21
  • _--1_. However, I don't think the OP had `grep==target` though – k_g Feb 27 '15 at 02:32
1

Increasing memory does not increase your stack size.

Try adding -Xss64m to your VM arguments. This will increase your stack size.

Alternatively, you could create an internal stack by creating a Stack<Point2i> and adding your initial point. You'd then do a while loop that ends when your stack is empty to call your function and remove that point from the stack. The function would take the stack as an argument (alternatively, it could be a class field) and add the points to the stack rather than calling itself.

k_g
  • 4,333
  • 2
  • 25
  • 40