Java 使用最少颜色数的彩色政治地图

Java 使用最少颜色数的彩色政治地图,java,bufferedimage,Java,Bufferedimage,我试图用最少的颜色来给政治地图上色。我现在实现目标的方式是: 我用洪水算法填充地图上的空白。然后,我通过检查像素的颜色是否与白色和颜色列表中的颜色不同来检查是否到达边界。如果颜色不同,那么我将以与之前相同的方向进一步遍历像素,直到从列表中获得颜色像素或白色像素。当它是白色或在列表中,但与当前颜色不相同时,我打破循环,当边框后面的颜色与当前颜色相同时,我用列表中的下一种颜色再次填充国家。 问题是我使用的地图通常有这样的边界: 边框后面的像素不是真正的白色。我的代码只是通过这些像素返回到它来自的同

我试图用最少的颜色来给政治地图上色。我现在实现目标的方式是:

我用洪水算法填充地图上的空白。然后,我通过检查像素的颜色是否与白色和颜色列表中的颜色不同来检查是否到达边界。如果颜色不同,那么我将以与之前相同的方向进一步遍历像素,直到从列表中获得颜色像素或白色像素。当它是白色或在列表中,但与当前颜色不相同时,我打破循环,当边框后面的颜色与当前颜色相同时,我用列表中的下一种颜色再次填充国家。 问题是我使用的地图通常有这样的边界:

边框后面的像素不是真正的白色。我的代码只是通过这些像素返回到它来自的同一个国家,结果是从列表中获得下一种颜色,然后是越界异常。 我如何解决这个问题?我不想为我的代码创建特殊的地图,我希望它能与任何等高线地图一起工作

这是我的密码。这是相当粗糙的,因为我正在尝试不同的方法。因此,任何建议都是可以接受的:)

公共类图像着色{
私人最终int北=0;
南部私人最终int=1;
私人最终int WEST=2;
私人最终int东=3;
私有最终整数[]颜色={-16726785,-65536,-15073025,-16711757,-16711919,-256,-417268,-455455,-5741663,-14194369,-14730152,-9885900};
私人名单;
专用int彩色计数器;
私有布尔值shouldbarkerecursion=false;
私有缓冲图像;
公共图像着色(BuffereImage图像){
这个图像=图像;
colorList=newarraylist();
对于(int i=0;i0;i--){
if(image.getRGB(x,i)=颜色[颜色计数器]){
彩色计数器++;
填充(x,y+1,南部);
返回;
}
if(image.getRGB(x,i)=-1 | | colorList.contains(image.getRGB(x,i)))返回;
}
}否则,如果(方向==南){

对于(inti=y+1;i所有@AJNeufeld说的都是真的。但是……如果你真的必须处理所描述的地图数据(基本上你没有访问矢量地图的权限),那么你可以尝试的一件事就是改进你如何检测边界

根据您的图像,边框是以#555555(亮度33%)绘制的一条1px宽的线。只要您垂直或水平穿过该边框,就可以保证至少穿过该颜色的50%(约亮度66%,或#a8a8a8)

注意,我稍微简化了抗锯齿的效果,但我认为在本例中,这还不足以引起问题

因此,我特别将#55555和#a8a8a8之间的任何灰色阴影视为边框,而忽略较浅的灰色阴影(将它们视为白色)


正如@AJNeufeld所指出的,这可能会创建一个边界,该边界在其自身上循环会挤压一个区域的一部分,但如果没有矢量数据,您可能无法将其与单独的区域区分开来。

在所有情况下,您尝试的任何方法都不起作用。您的地图边界可能比红色圆圈示例pi更接近将小区域分割成完全由黑色轮廓像素包围的区域。你可以尝试的方法是对图像进行锐化过滤;这可能只适用于部分问题情况。用于跟踪区域的边缘跟踪算法也会被模糊的、接近触摸的边界弄糊涂。你真的需要这样做吗以获取作为路径对象的边框,例如从SVG文件。位图图像总是有问题的。
public class ImageColoring {

    private final int NORTH = 0;
    private final int SOUTH = 1;
    private final int WEST = 2;
    private final int EAST = 3;


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

    private int colorCounter;
    private boolean shouldBreakRecursion = false;


    private BufferedImage image;

    public ImageColoring(BufferedImage image) {
        this.image = image;
        colorList = new ArrayList<>();
        for(int i = 0;i<COLORS.length;i++){
            colorList.add(COLORS[i]);
        }
    }

    public BufferedImage colorImage(){


        try{
            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, EAST);
                        colorCounter = 1;
                        //incrementCounter();
                    }

                }
            }
        }catch (StackOverflowError e){

        }

        return image;
    }


    private void fill(int x, int y, int direction){
        if(x<0 || y<0 || x>=image.getWidth() || y>=image.getHeight() || shouldBreakRecursion){
            return;
        }
        //if(image.getRGB(x,y)!=-1) return;
        if(image.getRGB(x,y)!=-1 && !colorList.contains(image.getRGB(x,y))){
            if(direction == NORTH){
                for(int i = y-1;i>0;i--){
                    if(image.getRGB(x,i) == COLORS[colorCounter]){
                        colorCounter++;
                        fill(x,y+1,SOUTH);
                        return;
                    }
                    if(image.getRGB(x,i) == -1  || colorList.contains(image.getRGB(x,i))) return;
                }
            }else if(direction == SOUTH){
                for(int i = y+1;i<image.getHeight();i++){
                    if(image.getRGB(x,i) == COLORS[colorCounter]){
                        colorCounter++;
                        fill(x,y-1,NORTH);
                        return;
                    }
                    if(image.getRGB(x,i) == -1  || colorList.contains(image.getRGB(x,i))) return;

                }
            }else if(direction == EAST){
                for(int i = x+1;i<image.getWidth();i++){

                    if(image.getRGB(i,y) == COLORS[colorCounter]){
                        System.out.println(image.getRGB(i,y) +" : "+COLORS[colorCounter]);
                        colorCounter++;
                        fill(x-1,y,WEST);
                        return;
                    }
                    if(image.getRGB(i,y) == -1  || colorList.contains(image.getRGB(i,y))) return;
                }
            }else if(direction == WEST){
                for(int i = x-1;i>0;i--){
                    if(image.getRGB(i,y) == COLORS[colorCounter]){
                        colorCounter++;
                        fill(x+1,y,EAST);
                        return;
                    }
                    if(image.getRGB(i,y) == -1  || colorList.contains(image.getRGB(i,y))) return;
                }
            }
            return;
        }else if(image.getRGB(x,y)!=-1) return;
        image.setRGB(x,y,COLORS[colorCounter]);



        fill(x+1,y, EAST);
        //fill(x-1,y,WEST);
        fill(x,y-1,NORTH);
        fill(x,y+1,SOUTH);

    }

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