0

I'm constructing a flood fill algorithm that will hopefully, eventually, find a face in the center of a photograph based on the color at the exact center, and similar colors surrounding that. At the moment, however, my algorithm should take in any color within the bounds of the int array and transfer it over to a holder array, essentially making a copy of the original image. But this isn't working, and is resulting in a black image when I run it. Can anyone see the problem I'm missing?

public class TemplateMaker {

public static void main(String[] args) throws IOException {
    importPhoto();
}

public static void importPhoto() throws IOException {
    File imgPath = new File("/Pictures/BaseImage.JPG");
    BufferedImage bufferedImage = ImageIO.read(imgPath);
    establishArray(bufferedImage);
}

public static void establishArray(BufferedImage bufferedImage) throws IOException {
    //byte[] pixels = hugeImage.getData();
    int width = bufferedImage.getWidth();
    System.out.println(width);
    int height = bufferedImage.getHeight();
    System.out.println(height);
    int[][] result = new int[height][width];
    for (int i = 0; i < height; i++)
        for (int j = 0; j < width; j++) {
            result[i][j] = bufferedImage.getRGB(j, i);
        }
    findFace(result);
}

public static void findFace(int[][] image) throws IOException {
    int height = image.length;
    int width = image[0].length;
    Color centerStart = new Color(image[height / 2][width / 2], true);
    System.out.println(centerStart.getRGB());
    System.out.println(Color.blue.getRGB());

    int[][] filled = new int[height][width];

    floodFill(height / 2, width / 2, centerStart, image, filled, height, width);

    //construct the filled array as image.
    BufferedImage bufferImage2 = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
    for (int x = 0; x < height; x++) {
        for (int y = 0; y < width; y++) {
            bufferImage2.setRGB(y, x, filled[x][y]);
        }
    }
    //save filled array as image file
    File outputfile = new File("/Pictures/saved.jpg");
    ImageIO.write(bufferImage2, "jpg", outputfile);
}

public static int[][] floodFill(int x, int y, Color targetColor, int[][] image, int[][] filled, int height, int width) {

    //execute something similar once algorithm works. 
    // if (image[x][y] < targetColor.getRGB()/2 || image[x][y] > targetColor.getRGB()*2) return filled;

    if (image[x][y] == Color.blue.getRGB()) {
        return filled;
    }
    if (image.length < 0 || image[0].length < 0 || image.length >= height || image[0].length >= width) {
        return filled;
    }
    filled[x][y] = image[x][y];
    image[x][y] = Color.blue.getRGB();

    floodFill(x - 1, y, targetColor, image, filled, height, width);
    floodFill(x + 1, y, targetColor, image, filled, height, width);
    floodFill(x, y - 1, targetColor, image, filled, height, width);
    floodFill(x, y + 1, targetColor, image, filled, height, width);
    return filled;
}

}

  • The biggest problem is using a recursive flood filling algorithm. While this would work on small images it would definitely fail for moderate to large sized images. I would suggest to use a scanline approach to the algorithm. See ***[this](http://en.wikipedia.org/wiki/Flood_fill)*** page for more info. – Extreme Coders Jun 25 '13 at 16:47

1 Answers1

0

You create int[][] called filled and then call floodFill(...) which returns without doing anything to the array. image.length is always equal to height and image[0].length is always equal to width, so it always returns from the second if statement.

You then build a BufferedImage from that blank array and write it to a file. All of the values in the array are initialized to 0, which gives you black.

Changing the for loop in findFace(..) to the below will save out the original image from your holder array.

        for (int x = 0; x < height; x++) {
        for (int y = 0; y < width; y++) {
            bufferImage2.setRGB(y, x, image[x][y]);
        }
    }

But I'm not sure if this is what you're asking or not.

Edit: Try this out and see if it sends you in the right direction:

    public static int[][] floodFill(int x, int y, Color targetColor, int[][] image, int[][] filled, int height, int width) {

    //execute something similar once algorithm works. 
    // if (image[x][y] < targetColor.getRGB()/2 || image[x][y] > targetColor.getRGB()*2) return filled;

    if (image[x][y] == Color.blue.getRGB()) {
        System.out.println("returned if 1");
        return filled;
    }
    /*if (image.length < 0 || image[0].length < 0 || image.length >= height || image[0].length >= width) {
        return filled;
    }*/
    filled[x][y] = image[x][y];
    image[x][y] = Color.blue.getRGB();

    if (x - 1 <= 0 && y < width) {
        floodFill(x - 1, y, targetColor, image, filled, height, width);
    }

    if(x + 1 < height && y >= 0 && y < width) {
        floodFill(x + 1, y, targetColor, image, filled, height, width);
    }

    if(x >= 0 && x < height && y - 1 <= 0) {
        floodFill(x, y - 1, targetColor, image, filled, height, width);
    }

    if(x >= 0 && x < height && y + 1 < width) {
        floodFill(x, y + 1, targetColor, image, filled, height, width);
    }

    return filled;
}
MaxAlexander
  • 460
  • 3
  • 10
  • Oh, you're totally right about the second if statment. I don't know why I wrote that, it should be checking the position of x and y to make sure they're not out of bounds. I'm getting an ArrayIndexOutOfBoundsException error now, but it's a step forward. Thanks! – user2506643 Jun 25 '13 at 17:29
  • I will edit the above to include a method that... sort of works. I don't have time right now to investigate further but it might be enough to get you started. – MaxAlexander Jun 25 '13 at 17:38
  • Holy crud, thanks for the help. That works really well. I appreciate it. – user2506643 Jun 25 '13 at 17:59
  • Just make sure to test it on an image that doesn't have the same width and height to make sure I didn't put them backwards in the if statements ;) – MaxAlexander Jun 25 '13 at 18:05