在递归时通过BufferedImage

时间:2018-06-06 14:22:20

标签: java recursion bufferedimage

我有一张政治地图图片,我想为其上的国家上色。我将图像加载到BufferedImage中,遍历像素并为白色着色。我使用递归方法来填充空格,即使它不是无限的(至少我是这么认为)我得到StackOverflowError。我使用的图像也不大,只有150x160像素。

这是我的代码。难道我做错了什么?这是不是很好的方法我应该尝试别的吗?

    private final int[] COLORS = {-65536,-15073025,-16726785,-16711757,-16711919,-256,-417268,-455455,-5741663,-14194369,-14730152,-9885900};

    private int colorCounter;


    private BufferedImage image;

    public ImageColoring(BufferedImage image) {
        this.image = image;
    }

    public BufferedImage colorImage(){
        for(int i = 0; i<image.getWidth();i++){
            for(int j =0;j<image.getHeight();j++){
                if(image.getRGB(i,j) == -1){
                    fill(i,j);
                    incrementCounter();
                }

            }
        }
        return image;
    }


    private void fill(int x, int y){
        if(x<0 || y<0 || x>=image.getWidth() || y>=image.getHeight()) return;
        if(image.getRGB(x,y)!=-1) return;
        image.setRGB(x,y,COLORS[colorCounter]);
        fill(x+1,y);
        fill(x-1,y);
        fill(x,y+1);
        fill(x,y-1);

    }

    private void incrementCounter(){
        if(++colorCounter == COLORS.length) colorCounter = 0;
    }
}

2 个答案:

答案 0 :(得分:0)

我认为你的解决方案本身听起来很好而且简短,这是一个ay = 160的图像,可以让你的代码创建一个至少160的y-1的堆栈,甚至不考虑其他情况。

我建议跳转到堆栈密集度较低的迭代使用。 你可以在彼此之下做4个不同的循环(不嵌套!)。使其可读性降低,但至少不会占用太多空间。

答案 1 :(得分:0)

通过将递归限制为处理图像的一小部分,可以避免堆栈溢出。以下代码将处理区域的大小限制为SIZE 请注意,它还减少了调用递归方法的时间(请参阅注释)。

import java.awt.GridLayout;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class ImageColoring {

    private static final int COLOR_TO_REPLACE = 0;
    private static final int NEW_COLOR = -15073025;
    private BufferedImage image;
    private static final int SIZE = 10;

    public ImageColoring(BufferedImage image) {
        this.image = image;
    }

    public BufferedImage colorImage(){

        for(int i = 0; i<image.getWidth();i++){
            for(int j =0;j<image.getHeight();j++){
                if(image.getRGB(i,j) == COLOR_TO_REPLACE){
                    fill(i,j);
                }
            }
        }
        return image;
    }

    private void fill(int x, int y){

        if((x<0) || (y<0) || (x>=image.getWidth()) || (y>=image.getHeight())) {
            return;
        }
        if(image.getRGB(x,y)!= COLOR_TO_REPLACE) {
            return;
        }

        int xMax = ((x + SIZE) > image.getWidth())  ?  image.getWidth() : x + SIZE ;
        int yMax = ((y + SIZE) > image.getHeight()) ?  image.getHeight() : y + SIZE;

        while(fill(x, xMax, y, yMax)) {

            x = xMax; y = yMax;
            xMax = ((x + SIZE) > image.getWidth())  ?  image.getWidth() : x + SIZE ;
            yMax = ((y + SIZE) > image.getHeight()) ?  image.getHeight() : y + SIZE;
        }
    }

    private boolean fill(int x, int xMax, int y, int yMax){

        if( (x>=xMax) || (y>=yMax)) {
            return false;
        }
        if(image.getRGB(x,y)!= COLOR_TO_REPLACE) {
            return false;
        }

        image.setRGB(x,y,NEW_COLOR);

        if(fill(x+1,y, xMax, yMax) ||
                //fill(x-1,y, xMax, yMax)||     not needed. it enough to progress 
                //fill(x,y-1, xMax, yMax) ||    in one direction to cover all 
                fill(x,y+1, xMax, yMax) )   { return true; };

        return false;
    }

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

        String imagePath = "https://upload.wikimedia.org/wikipedia/commons/3/3f/Crystal_Project_bug.png";
        URL url = new URL(imagePath);
        ImageColoring ic = new ImageColoring(ImageIO.read(url));
        JFrame window = new JFrame();
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JPanel grid = new JPanel(new GridLayout(1, 2, 15, 15));
        grid.add(new JLabel(new ImageIcon(ImageIO.read(url))));
        grid.add(new JLabel(new ImageIcon(ic.colorImage())));
        window.add(grid);
        window.pack();
        window.setVisible(true);
    }
}

(必须修改颜色更改逻辑)

enter image description here