簡體   English   中英

如何找到矩形的角點?

[英]How to find the corner pixels of a rectangle?

給定一個簡單的單色位圖,其中包含一個隨機旋轉的矩形。 如何找到位圖內矩形的左/上,左/下,右/下和右/上角位置?

例如,這就是位圖的外觀,其中X標記了有問題的像素:

......... ......... ......... .........
.X11111X. ....X.... ..X11.... ....11X..
.1111111. ...111... ..11111X. X111111..
.1111111. ..X111X.. ..111111. .111111..
.X11111X. ...111... .1111111. .1111111.
......... ....X.... .111111.. ..111111.
......... ......... .X11111.. ..11111X.
......... ......... ....11X.. ..X11....
......... ......... ......... .........

請原諒糟糕的ascii藝術。 對於第二個示例,頂部的角點像素可以是左/上或右/上角的矩形。 要么沒事。

在上面的示例中,確定角像素/位置需要哪些步驟?

角落像素是最遠的像素。 找到最頂行和最底行。 那些將始終有一個角落像素。

角點像素只能是最頂行行中的第一個或最后一個像素(如果只有一個,則兩者都是)。

因此,比較最上面一行中第一個像素與最下面一行中最后一個像素之間的距離。 並且最后一個像素在最頂部,第一個在最底部。 那里的角落是最遠的角落。

由於它們在Y中的距離都相同,因此需要與x位置差異最大的像素。 角是abs(x0-x1)最大的像素,其中x0在最頂行,x1在最底部。

對最右邊和最左邊的行重復此操作。

如果最左邊的角落在左邊,則最左邊的角落在底部,最底部的角落在右邊,最右邊的角落在頂部。 一旦你有頂行,底行,左行和右行,實際上只有兩種可能性可以在if語句中解決。 但是,由於在最上面的行上有一個像素而在最右邊的行上有兩個像素的邊緣條件,你最好再次使用轉置的x和ys運行算法來解決其他兩個角而不是試圖自己節省一個if語句。

並非每個單色位圖都能給您答案。 完整的算法需要輸出“不存在唯一角落”。 下圖給出了問題的一個示例:

......... ......... .......... ...XX.... ....X.... ....XX.... ..X11X... ...111... ...1111... ..X11X... ..X111X.. ..X1111X.. ...XX.... ...111... ..X1111X.. ......... ....X.... ...X11X... ......... ......... ....XX.... ......... ......... ..........

當矩形的斜率為+1和-1並且中心的位置是半積分時,發生簡並說明。 它也可以與斜率和位置的其他組合一起發生。 一般答案需要包含像素對作為頂點的最佳近似。

  1. 從矩形的邊界框開始。
  2. 對於每個角落,順時針移動它,直到有一個黑色方塊。

     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 = px; this.y = py; } 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 + dx, y + dy); } } 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); } } } 

版畫

    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}]

可以通過尋找一系列黑色並選擇中間運行來改進。

從頂部逐行掃描圖像,直到找到黑色運行。

重復四種方式,從下到上,左,右,給你八個角候選。

將運行端點放在頂行和底行中最遠的位置。 這告訴您垂直采用哪些端點。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM