Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/373.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何找到矩形的角点像素?_Java_Bitmap_Geometry_Geometry Surface - Fatal编程技术网

Java 如何找到矩形的角点像素?

Java 如何找到矩形的角点像素?,java,bitmap,geometry,geometry-surface,Java,Bitmap,Geometry,Geometry Surface,给定一个简单的单色位图,其中包含一个随机旋转的矩形。如何在位图中找到矩形的左/上、左/下、右/下和右/上角位置 例如,这是位图的外观,其中X标记有问题的像素: ......... ......... ......... ......... .X11111X. ....X.... ..X11.... ....11X.. .1111111. ...111... ..11111X. X111111.. .1111111. ..X111X.. ..111111. .111111.. .X11111X.

给定一个简单的单色位图,其中包含一个随机旋转的矩形。如何在位图中找到矩形的左/上、左/下、右/下和右/上角位置

例如,这是位图的外观,其中X标记有问题的像素:

......... ......... ......... .........
.X11111X. ....X.... ..X11.... ....11X..
.1111111. ...111... ..11111X. X111111..
.1111111. ..X111X.. ..111111. .111111..
.X11111X. ...111... .1111111. .1111111.
......... ....X.... .111111.. ..111111.
......... ......... .X11111.. ..11111X.
......... ......... ....11X.. ..X11....
......... ......... ......... .........
请原谅这不好的艺术。 对于第二个示例,顶部的角点像素可以是矩形左/上角或右/上角。两者都可以


在上述示例中,需要哪些步骤来确定角点像素/位置

角点像素是相距最远的像素。查找最上面的行和最下面的行。在这些区域中始终会有一个角像素

角点像素只能是最顶层行中的第一个或最后一个像素(如果只有一个,则两者都可以)

因此,比较最上面一行的第一个像素和最下面一行的最后一个像素之间的距离。最后一个像素位于最顶部,第一个像素位于最底部。那里的角是相距最远的角

因为它们在Y轴上的距离都相同,所以需要在x轴位置上差异最大的像素。角点是abs(x0-x1)最大的像素,其中x0位于最上面的行,x1位于最下面的行

对最右边和最左边的行重复此操作

如果最上面的角位于左侧,则最左边的角位于底部,最下面的角位于右侧,最右边的角位于顶部。一旦你有了顶行、底行、左行和右行,实际上只有两种可能性可以在if语句中解决。但是,由于最上面一行有一个像素,最右边一行有两个像素的边缘条件,因此最好使用转置的x和ys再次运行该算法,以解决其他两个角点,而不是尝试使用if语句

  • 从矩形的边框开始
  • 对于每个角,顺时针移动它,直到有一个黑色正方形

    public class Test {
    
        String[][] squares = {
            {
                ".........",
                ".X11111X.",
                ".1111111.",
                ".1111111.",
                ".X11111X.",
                ".........",
                ".........",
                ".........",
                ".........",},
            {
                ".........",
                "....X....",
                "...111...",
                "..X111X..",
                "...111...",
                "....X....",
                ".........",
                ".........",
                ".........",},
            {
                ".........",
                "..X11....",
                "..11111X.",
                "..111111.",
                ".1111111.",
                ".111111..",
                ".X11111..",
                "....11X..",
                ".........",},
            {
                ".........",
                "....11X..",
                "X111111..",
                ".111111..",
                ".1111111.",
                "..111111.",
                "..11111X.",
                "..X11....",
                ".........",}};
    
        private static final int WHITE = 0;
        private static final int BLACK = 1;
    
        class Point {
    
            private final int x;
            private final int y;
    
            public Point(Point p) {
                this.x = p.x;
                this.y = p.y;
            }
    
            public Point(int x, int y) {
                this.x = x;
                this.y = y;
            }
    
            @Override
            public String toString() {
                return "{" + x + "," + y + '}';
            }
    
            // What colour is there?
            public int colour(int[][] bmp) {
                // Make everything off-bmp black.
                if (x < 0 || y < 0 || y >= bmp.length || x >= bmp[y].length) {
                    return BLACK;
                }
                return bmp[y][x];
            }
    
            private Point step(Point d) {
                return new Point(x + d.x, y + d.y);
            }
    
        }
    
        class Rectangle {
    
            private final Point[] corners = new Point[4];
    
            public Rectangle(Point[] corners) {
                // Points are immutable but corners are not.
                System.arraycopy(corners, 0, this.corners, 0, corners.length);
            }
    
            public Rectangle(Rectangle r) {
                this(r.corners());
            }
    
            public Rectangle(Point a, Point b, Point c, Point d) {
                corners[0] = a;
                corners[1] = b;
                corners[2] = c;
                corners[3] = d;
            }
    
            private Rectangle(Point tl, Point br) {
                this(tl, new Point(br.x, tl.y), br, new Point(tl.x, br.y));
            }
    
            public Point[] corners() {
                return Arrays.copyOf(corners, corners.length);
            }
    
            @Override
            public String toString() {
                return Arrays.toString(corners);
            }
    
        }
    
        private Rectangle getBoundingBox(int[][] bmp) {
            int minX = Integer.MAX_VALUE, minY = Integer.MAX_VALUE, maxX = 0, maxY = 0;
            for (int r = 0; r < bmp.length; r++) {
                for (int c = 0; c < bmp[r].length; c++) {
                    if (bmp[r][c] != WHITE) {
                        if (minX > c) {
                            minX = c;
                        }
                        if (minY > r) {
                            minY = r;
                        }
                        if (maxX < c) {
                            maxX = c;
                        }
                        if (maxY < r) {
                            maxY = r;
                        }
                    }
                }
            }
            return new Rectangle(new Point(minX, minY), new Point(maxX, maxY));
        }
    
        Point[] clockwise = new Point[]{
            new Point(1, 0),
            new Point(0, 1),
            new Point(-1, 0),
            new Point(0, -1)};
    
        private void test(int[][] bmp) {
            // Find the bounding box.
            Rectangle bBox = getBoundingBox(bmp);
            System.out.println("bbox = " + bBox);
            Point[] corners = bBox.corners();
            // Move each corner clockwise until it is black.
            for (int p = 0; p < corners.length; p++) {
                while (corners[p].colour(bmp) == WHITE) {
                    corners[p] = corners[p].step(clockwise[p]);
                }
            }
            System.out.println("rect = " + new Rectangle(corners));
        }
    
        private void test(String[] square) {
            // Build the int[][].
            // . -> White
            // X/1 -> Black
            int[][] bmp = new int[square.length][];
            for (int r = 0; r < square.length; r++) {
                bmp[r] = new int[square[r].length()];
                for (int c = 0; c < bmp[r].length; c++) {
                    switch (square[r].charAt(c)) {
                        case '.':
                            bmp[r][c] = WHITE;
                            break;
                        case 'X':
                        case '1':
                            bmp[r][c] = BLACK;
                            break;
                    }
                }
            }
            test(bmp);
        }
    
        public void test() {
            for (String[] square : squares) {
                test(square);
            }
        }
    
        public static void main(String args[]) {
            try {
                new Test().test();
            } catch (Throwable t) {
                t.printStackTrace(System.err);
            }
        }
    
    }
    

    可以通过查找黑色跑步并选择跑步中间部分来改善。从顶部逐行扫描图像,直到找到黑色跑步

    重复四种方法,从下到上,从左到右,给你八个候选角


    在顶行和底行中取距离最远的梯段端点。这会告诉您垂直选择哪个端点。

    并不是每个单色位图都能给出答案。完整的算法需要输出“不存在唯一角点”。下图给出了该问题的示例:

    。。。。。。。。。。
    ……XX。。。。十。。。。二十、 。。。。
    …X11X。。。111... ...1111...
    ..X11X。。X111X。。X1111X。。
    ……XX。。。111... ..X1111X。。
    ......... ....X。。。X11X。。。
    ......... ......... ....二十、 。。。。
    ......... ......... ..........


    当矩形的斜率为+1和-1且中心位置为半整数时,会发生退化。坡度和位置的其他组合也可能发生这种情况。一般答案需要包含像素对作为顶点的最佳近似。

    查找顶部、底部、右侧和左侧行可以在对数(n)时间内完成。但是,我不推荐它。这个问题不是你需要扮演战舰的东西™ 具有你弄沉了我的长方形!“查找顶部、底部、右侧和左侧行可以在对数(n)时间内完成”:如何?玩战舰找到矩形斑点。然后进行二进制搜索以找到边。形状必须在右边、左边或上面有一个黑色像素,直到它位于最上面的一行。我不认为这个问题比检查大约一半的位图、在运行时记录8个候选像素、然后应用基本整数数学并输出解更值得。很明显,我的解决方案减少了寻找第一个黑色像素的时间。但是,是的,如果是关键任务,检查中心像素,然后检查每个象限,I、II、III、IV,然后对每个点重复,并递归,直到找到一个黑色像素或查看整个位图。当你找到一个黑色像素时,你可以做一种泛光填充来找到相关的行。因为即使是变换后的矩形也不能有次优解。你朝那个方向走,然后在那一行或那一列的每一点上再往那个方向走,你就完成了。当形状不对称或倾斜时,没有精确的解决方案。你想要一个精确的矩形,还是接受一个四边形?我正在尝试在图像中找到一个四边形。然后你应该重新旋转帖子。一旦你发现黑色像素从顶部开始运行,如果你发现一行像素在该标记下方没有黑色像素,那么最底部的一行一定在该行上方。至少,我们最好从顶部开始,直到到达一排,然后继续向下,直到到达一排纯白色。然后是最下面一排。假设矩形不超过位图的一半。正确地说,您应该从顶部循环浏览位图,直到碰到第一个黑色像素,直到碰到一行所有白色像素,然后将它们与一系列快速if语句中最右、最左、最上、最下的运行列表进行比较。o(n*m/2)@Tatarize:我的解决方案是o(n-m),其中n是图像的面积,m是矩形边框的面积。您没有指定不通过搜索最顶部和最左侧来重新检查左上象限。是的,如果你找到了底部和顶部,你只搜索顶部行下方和底部行上方的中间部分,那么你就不会复制N中的像素。我的方法应该是O(N/2+m*log(N))左右,但大部分都不需要
        bbox = [{1,1}, {7,1}, {7,4}, {1,4}]
        rect = [{1,1}, {7,1}, {7,4}, {1,4}]
        bbox = [{2,1}, {6,1}, {6,5}, {2,5}]
        rect = [{4,1}, {6,3}, {4,5}, {2,3}]
        bbox = [{1,1}, {7,1}, {7,7}, {1,7}]
        rect = [{2,1}, {7,2}, {6,7}, {1,6}]
        bbox = [{0,1}, {7,1}, {7,7}, {0,7}]
        rect = [{4,1}, {7,4}, {4,7}, {0,2}]