Java 如何在二维地图中找到多边形,只要一个等高线标记?

Java 如何在二维地图中找到多边形,只要一个等高线标记?,java,geometry,dbscan,Java,Geometry,Dbscan,给定一个二维点阵列,我如何找到所有多边形,其中多边形坐标的每个点都与下一个点(对角邻接) 例如,此图像: 我感兴趣的是淹没由闭合点链(每个坐标与下一个坐标相邻,形成一个闭合环)包围的区域,关于其形状。我对识别单个多边形不感兴趣,只对填充多边形感兴趣。每个点都有一个标签(1、2、3、+等),其中0未设置,例如: 黄色是中心点被填充的正方形 橙色是一个更大的正方形,但四个角只是对角邻接 绿色是一种形状,如果你沿着点链走,你就不能总是向右拐 红色不是有效形状,因为其点链未闭合 蓝色不是有效形状,因

给定一个二维点阵列,我如何找到所有多边形,其中多边形坐标的每个点都与下一个点(对角邻接)

例如,此图像:

我感兴趣的是淹没由闭合点链(每个坐标与下一个坐标相邻,形成一个闭合环)包围的区域,关于其形状。我对识别单个多边形不感兴趣,只对填充多边形感兴趣。每个点都有一个标签(1、2、3、+等),其中0未设置,例如:

  • 黄色是中心点被填充的正方形
  • 橙色是一个更大的正方形,但四个角只是对角邻接
  • 绿色是一种形状,如果你沿着点链走,你就不能总是向右拐
  • 红色不是有效形状,因为其点链未闭合
  • 蓝色不是有效形状,因为其点链未闭合,边未闭合
我看过凸壳,但这给了我所有点的壳,这不是我感兴趣的

夫妻规则: -每个点都有一个从1到10的值。 -仅当闭合的点链具有相同标签时,才能填充区域。 -未闭合的点链是无效的面域。 -点的x/y坐标是整数

我正在用Java实现它,并尝试了以下方法:

但如果有这样一张地图:

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 1, 0, 1, 0, 1, 0, 2, 2, 0, 0, 0, 0, 2, 0
0, 1, 0, 0, 0, 1, 2, 0, 0, 2, 0, 0, 0, 0, 0
0, 0, 1, 0, 1, 0, 2, 0, 0, 2, 0, 0, 0, 0, 0
0, 0, 0, 1, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 3, 3, 3, 0, 0, 3, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0
它将此作为输出:

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 1, 0, 0, 0, 1, 0, 2, 2, 0, 0, 0, 0, 2, 0
0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0
我还尝试了DBSCAN,结果无法忽略同一标签的大集群旁边的小集群

更新:

简单的整体填充不起作用,因为要求多边形的所有周围像素具有相同的值:

    public static void floodFill(int[][] map, int fill, Point loc) {
        if (loc.x < 0 || loc.x >= map[0].length || loc.y < 0 || loc.y >= map.length) throw new IllegalArgumentException();

        int old = map[loc.y][loc.x];

        // Checks trivial case where loc is of the fill color
        if (fill == old) return;

        floodLoop(map, loc.x, loc.y, fill, old);
    }

    // Recursively fills surrounding pixels of the old color
    private static void floodLoop(int[][] map, int x, int y, int fill, int old) {

        int[] aux = {255, 255, 255, 255};

        // finds the left side, filling along the way
        int fillL = x;
        do {
            map[y][fillL] = fill;
            fillL--;
        } while (fillL >= 0 && map[y][fillL] == old);
        fillL++;

        // find the right right side, filling along the way
        int fillR = x;
        do {
            map[y][fillR] = fill;
            fillR++;
        } while (fillR <= map[0].length - 1 && map[y][fillR] == old);
        fillR--;

        // checks if applicable up or down
        for (int i = fillL; i <= fillR; i++) {
            if (y > 0 && map[y-1][i] == old) floodLoop(map, i, y - 1,
                    fill, old);
            if (y < map.length - 1 && map[y+1][i] == old) floodLoop(
                    map, i, y + 1, fill, old);
        }
    }

    public static int[][] map = new int[][]
    {
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0},
            {0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 0, 0},
            {0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0},
            {0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 2, 2, 2, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0},
            {0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 2, 0, 2, 0, 0, 3, 0, 0, 0, 0, 3, 0, 0, 3, 0, 0},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 3, 0, 0, 0, 3, 0, 3, 0, 3, 0, 0},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 0, 0, 3, 3, 0, 0},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 0, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 4, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 4, 0, 4, 0, 0, 0, 0, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

    };

    public static int[][] expected_result = new int[][]
    {
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0},
            {0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0},
            {0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0},
            {0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 2, 2, 2, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0},
            {0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 2, 2, 2, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 3, 3, 3, 3, 3, 0, 3, 3, 3, 0, 0},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 0, 0, 3, 3, 0, 0},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 0, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 4, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 4, 0, 4, 0, 0, 0, 0, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

    };


    private static void printMap(int[][] map)
    {
        for (int y = 0; y < map.length; y++)
        {
            for (int x = 0; x < map[0].length; x++)
            {
                System.out.print(map[y][x] +  " ,");
            }
            System.out.println();
        }
    }
    public static void main(String[] args)
    {
        int[][] copy = map.clone();

        floodFill(copy, 1, new Point(0,0));

        printMap(copy);
    }
public static void floodFill(int[]map,int fill,Point loc){
如果(loc.x<0 | | loc.x>=map[0].length | | loc.y<0 | | loc.y>=map.length)抛出新的IllegalArgumentException();
int old=地图[loc.y][loc.x];
//检查loc为填充颜色的普通情况
如果(填充==旧)返回;
洪水循环(地图,位置x,位置y,填充,旧);
}
//递归地填充旧颜色的周围像素
私有静态空泛洪循环(int[][]映射,int x,int y,int fill,int old){
int[]aux={255,255,255};
//找到左侧,沿途填充
int fillL=x;
做{
映射[y][fillL]=填充;
填充--;
}而(fillL>=0&&map[y][fillL]==old);
fillL++;
//找到右边,沿路填充
int fillR=x;
做{
映射[y][fillR]=填充;
fillR++;

}而(fillR这不是一个基于密度的聚类问题,因此DBSCAN根本不是这个任务的正确算法

您需要的是一种非常简单的整体填充方法。识别外部,将其填充为白色。找到一个未填充但有邻居的像素。使用邻居颜色开始整体填充


除了一些角盒(接触形状)这可能就是您所需要的。这些可能会在地板填充期间被检测到,并填充为白色。

为了更好地帮助您,请尽快发布一篇适当的文章,展示您的问题以及您解决问题的努力。顺便问一下,您使用的是哪种Java框架?Swing?我没有使用任何Java框架。DBSCAN来自apache math3库。我不是f熟悉DBSCAN或math3,但任何人都需要查看您的代码。请将其作为代码格式的文本发布在问题内部,而不是外部links@Wesley如果你对多边形本身不感兴趣,我很确定使用一个专门的工具会比实际找到多边形容易得多。你考虑过使用这个工具吗g it?你可以使用不同的颜色进行多次泛光填充,并检查填充是否只接触一个多边形。@Gilles PhilippePaillé我添加了一个我无法开始工作的示例。我只对填充瓷砖感兴趣,只对它们完全封闭的值以及该值相同的情况下进行填充重新计算是指未设置为空(0)的像素值为了填充形状,必须具有相同的值。简单。进行泛光填充,但检查是否找到多个相邻颜色。我相信有一种更有效的算法比循环每个标签的可能性,对设置为0的每个区域进行泛光填充,并检查泛光填充是否有效。您可以轻松地执行有效性编辑在填充过程中进行y检查。填充很便宜,而且你只需要很少的填充,如果你有n个标签,通常在n+1左右。你预计这会便宜多少?你基准测试了吗?作为额外的加速,你可以将填充限制在每个标签的边界框内,但我怀疑这会有多大的区别。基本上每个像素都会be填充一次,运行时为O(n),总共n个像素。