当前位置: 首页 > 知识库问答 >
问题:

将矩形的四个点重新排序为正确的顺序

邢烨烨
2023-03-14

纵横比=高度/宽度总是

我有一个RotatedRect对象在OpenCV/Java。
我可以得到它的一个数组,其中包含4个类型为Point和Point定义的x/y值的对象。

现在我想对这4个点进行排序,使左上角的点是数组的第一个元素,然后顺时针方向,使上下角的点是第四个元素。

我假设矩形没有旋转太多(只是一些小角度),例如。

我已经在例子中指出了哪个点是左上(TL)。

怎么做呢?

你不需要特别告诉我OpenCV等,只要假设你有两个数组

int[] x = new int[4];
int[] y = new int[4];

而第n-点的坐标为(x[n-1],y[n-2])。然后我可以为OpenCV做这件事,特别是我自己。

共有3个答案

衡子琪
2023-03-14

搜索具有最高y值的2个点,其中一个始终是您定义中的TL(宽度

按 y 值的降序对数组进行排序,并获取具有第二个最高 y 值的元素。

如果此点具有最低的x值,则定义您的右图(1)。其他值最高的点是您的TL并定义您的左图(2)。

现在得到了顺时针顺序,其中TL是第一个元素

在案例 (1) 中:更改排序数组的最后 2 个 elemnt 的位置 在案例 (2) 中:更改前 2 个 elemnt 的位置。

这是真的,因为你的定义,但我不能用适当的数学方法解释它。

司徒良哲
2023-03-14

编辑:如果您可以自由假设矩形没有旋转太多,您可以直接前进,通过使用上面的公式长度=((y1-y2)^2(x1-x2)^2)^(0.5)计算与原点的距离,找到左上角的点,原点为(0,0)。距离最小的点将位于左上角。然后你可以继续使用我在下面给出的步骤。

如果你不能假设这一点,一旦你确定了矩形的左上角,还有另一种更优雅的方法(因此前三个步骤保持不变)。一旦你确定了左上角:

>

  • 使用毕达哥拉斯公式,长度=((y1-y2)^2(x1-x2)^2)^(0.5)
  • 现在有三个长度对应于从左上角点开始的每个顶点的长度
  • 顶点的位置可以很容易地找到(按顺时针顺序):

    shortest distance = top right point 
    longest distance = bottom right point 
    middle distance = bottom left point
    

    您不需要使用if条件。

    注意:只要保持高度总是大于宽度的条件,这就成立。

  • 赖浩荡
    2023-03-14

    有一个非常简单的解决方案,如果你知道:

      < li > <代码>-45

    如果这是真的,那么这些点,按顺时针顺序,将永远是这样的顺序:

    pts[0], pts[3], pts[2], pts[1]
    

    顺便说一句,如果这不会对你的程序造成太大的伤害,点数是按逆时针顺序传递的,从左上角开始……那么你就不必进行任何重新排序/排序了。

    其他情况:

    • 高度
    • 从左上角开始的顺时针顺序为 3,2,1,0
    • 左上角的逆时针顺序为 3,0,1,2
    • 从左上角开始的顺时针顺序为1,0,3,2
    • 从左上角开始的逆时针顺序为1,2,3,0

    其余情况都意味着矩形从左到右比从上到下大,这在您的场景中不会发生。此外,如果角度在这些范围之外,您可以连续加减360以获得其中一个范围内的角度。

    (TL;博士)

    我们从OpenCV如何计算这些点的值中知道这一点。你可以通过一些实验来解决这个问题。这是我写的一个小程序来演示它:

    import java.awt.BorderLayout;
    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.Graphics;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    
    import javax.swing.JComponent;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.Timer;
    
    import org.opencv.core.Point;
    import org.opencv.core.RotatedRect;
    import org.opencv.core.Size;
    
    public class TestFrame extends JFrame {
        public static void main(String... args) {
            final TestFrame frame = new TestFrame();
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    frame.setVisible(true);
                }
            });
        }
    
        private RectComponent rect;
    
        public TestFrame() {
            JPanel containerPane = new JPanel(new BorderLayout());
            setDefaultCloseOperation(EXIT_ON_CLOSE);
            rect = new RectComponent();
            containerPane.add(rect);
            setContentPane(containerPane);
            setSize(400,400);
            new Timer(100, rect).start();
        }
    
        public class RectComponent extends JComponent implements ActionListener {
            private RotatedRect rect = new RotatedRect(new Point(0,0), new Size(1, 3), 0);
    
            private final Point[] pts = new Point[4];
    
            @Override
            protected void paintComponent(Graphics g) {
                rect.points(pts);
                printPoints();
                Dimension size = getSize();
                drawRectLine(g, pts[0], pts[1], size);
                drawRectLine(g, pts[1], pts[2], size);
                drawRectLine(g, pts[2], pts[3], size);
                drawRectLine(g, pts[0], pts[3], size);
            }
    
            private void printPoints() {
                System.out.format("A: %d, TL: %s, TR: %s, BR: %s, BL%s%n",
                        (int) (rect.angle + (rect.angle < 0 ? -1e-6 : 1e-6)), // Stupid doubles, stupid rounding error
                        pointToString(pts[0]),
                        pointToString(pts[3]),
                        pointToString(pts[2]),
                        pointToString(pts[1]));
            }
    
            private String pointToString(Point p) {
                return String.format("{%.2f,%.2f}",p.x, p.y);
            }
    
            private void drawRectLine(Graphics g, Point left, Point right, Dimension size) {
                g.drawLine(scale(left.x, size.width), scale(left.y, size.height),
                        scale(right.x, size.width), scale(right.y, size.height));
            }
    
    
            private int scale(double value, int coord) {
                return (int) (value * coord) / 4 + coord / 2;
            }
    
    
            @Override
            public void actionPerformed(ActionEvent e) {
                rect.angle += 1;
                if(rect.angle > 44) rect.angle = -44;
                repaint();
            }
        }
    }
    

     类似资料:
    • 我有一个mongo收藏,大约有60万份文档。我正在枚举集合,按_id排序。但是,文档不会按排序顺序返回。它们似乎是根据ObjectId的时间戳部分正确排序的,但不是根据pid字段。 这是我用来重现的c#代码: 在某个时刻,断言被触发。我可以看到新的id具有与前一个相同的时间戳,但pid较低。 我本来以为使用{“_id”:1}进行排序将使用ObjectId的所有组件进行排序,而不仅仅是时间戳。 服务

    • 在上面的图片中,我展示了两个矩形 矩形1,其x可以从-900到13700不等,Y可以从-600到6458 矩形2,其坐标X可以从0到3000变化,而y可以从0到2000变化 同样:矩形2的起点位于左上角位置(0,0),而矩形1的起点位于左上角位置(宽度/2,高度/2)。 我需要做的是:使用缩放或平移将矩形1的点转换为矩形2的点。 那么,为了将矩形1的坐标转换为矩形2的坐标,< code>x和< c

    • 问题内容: df =DataFrame({‘a’:[1,2,3,4],’b’:[2,4,6,8]}) >>> df[‘x’]=df.a + df.b >>> df[‘y’]=df.a - df.b >>> df a b x y 0 1 2 3 -1 1 2 4 6 -2 2 3 6 9 -3 3 4 8 12 -4 现在,我想重新排列列顺序,按如下方式使“ x”,“ y”列成为第一列和第二列: 但

    • 对于我正在编写的游戏,我在非正方形地图上使用四叉树。四叉树用于查找给定最大半径(圆)内的相邻单位的冲突检测、要攻击的敌人、最近的基地等。 我想知道的是,如果将四边形树由矩形而不是正方形制成,是否存在性能问题?矩形地图不是将正方形地图划分为正方形,而是在四边形树中划分为大小相等的矩形。 矩形地图上的方形四叉树:将创建一个四叉树,填充整个地图,但左侧或底部有空白/未使用区域,具体取决于地图的方向(水平

    • 本文向大家介绍检查给定的四个点是否形成正方形,包括了检查给定的四个点是否形成正方形的使用技巧和注意事项,需要的朋友参考一下 在二维平面中,给出了四个点。该算法将检查四个点是否形成正方形。 检查正方形我们必须匹配这些条件- 给定点形成的所有四个边都相同。 所有两个连接侧都是直角的。 输入输出 算法 在此过程中,我们将使用方法squareDist(p1,p2),它将返回两个给定点的平方距离。 输入: 

    • 问题内容: 我确信这个问题以前可能已经被问过,但我似乎找不到正确的答案。如果我有两个清单 我正在尝试使用_list1重新排列_list2中的元素,以便它们完全匹配顺序。什么是最干净的方法?所需的输出: 很抱歉,如果这是重复的,但到目前为止,我只能使用压缩的sorted()方法找到数字列表的答案。 如果_list2是列表列表怎么办? 所需输出: 还有一个假设:如果我想使用_list1作为键对其他任何