识别2d空间中多边形的角

时间:2009-08-22 12:56:19

标签: image-processing geometry

给出四个(x,y)对代表2d空间中任意多边形(四边形)的四个角,我想确定:

  1. 多边形是否凸起
  2. 如果是凸面,哪个特定点代表左上角,右上角,左下角和右下角
  3. 我正在将此作为图像处理程序的一部分,因此假设Y轴被翻转(即正值从顶部向下移动)。


    我的第一个想法是获取多边形的边界框,然后测量每个顶点距边界框角落的距离。然后,对于多边形的每个顶点,确定它最接近的边界框的哪个角并相应地标记它。这对多边形不起作用,例如:

    http://matt.bridges.name/polygon.png

    多边形的左上角顶点最靠近边界框的右上角。它也不是最接近边界框左上角的顶点。

3 个答案:

答案 0 :(得分:4)

为了确定多边形是否是凸的,你可以使用与Graham scan中使用的类似的东西,并通过这些点,检查你是否每次都有一个右转(或左转)。

为了确定哪个角落在哪里,你可以看看哪个点的x和y最小;并选择其中一个作为左下角。他们可能会合作,这很好,但如果没有,那么,并不总是很容易分辨出应该在左下角,例如:

"Bottom left corner" is quite ambiguous http://a.imagehost.org/0894/bottomleftiswhich.png

一旦你确定了你的左下角哪一个,你可以简单地按顺序浏览角落并相应地标记它们。要了解他们的订单,只需检查您是否通过上述检查做出了正确或全部左转。

答案 1 :(得分:1)

现在我已经明确地说明了这个问题了另一个解决方案:

  1. 在每个顶点之间绘制线条
  2. 通过检查剩余的两个点是否位于线的相对侧或同一侧来确定哪条线是对角线
  3. 如果使用此方法找到两个对角线,则多边形是凸的。
  4. 带有负斜率的对角线连接左下角和右上角,带有正斜率的对角线连接左上角和右下角。
  5. 有更简单的方法吗?

答案 2 :(得分:1)

如果两个对角线都在四边形内并因此相交,则四边形是凸的。左下角是交叉点下方和左侧的点。模拟条件适用于其他三个角落。

如果您事先不知道点的顺序,则不知道对角,因此对角线。在这种情况下,您必须计算所有可能的六个段的交叉点。如果多边形是凸的,您将获得一个交叉点,您可以使用它来确定四个角。如果多边形不是凸面,则没有交点。

<强>更新

我创建了一个小型的C#程序来测试我的建议。凸凹检测的工作方式与预期相同,但仍存在角点检测失败的情况(参见代码中的测试用例3)。但解决这个问题应该很简单。

<强> CODE

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading;

namespace Quadrilaterals
{
    public class Program
    {
        public static void Main()
        {
            Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;

            Int32[,] tests = { { 0, 1, 2, 3 }, { 0, 2, 1, 3 }, { 0, 3, 1, 2 } };

            PointF[] points = { new PointF(4, -2), new PointF(2, 5), new PointF(8, -6), new PointF(10, 7) };
            //PointF[] points = { new PointF(0, 0), new PointF(10, 0), new PointF(5, 10), new PointF(5, 3) };
            //PointF[] points = { new PointF(4, -2), new PointF(3, -1), new PointF(0, 0), new PointF(1, 0) };

            PointF? p = null;

            for (Int32 i = 0; i < 3; i++)
            {
                Console.WriteLine("Intersecting segments ({0}|{1}) and ({2}|{3}).", tests[i, 0], tests[i, 1], tests[i, 2], tests[i, 3]);

                Single? f1 = IntersectLines(points[tests[i, 0]], points[tests[i, 1]], points[tests[i, 2]], points[tests[i, 3]]);
                Single? f2 = IntersectLines(points[tests[i, 2]], points[tests[i, 3]], points[tests[i, 0]], points[tests[i, 1]]);

                if ((f1 != null) && (f2 != null))
                {
                    PointF pp = PointOnLine(points[tests[i, 0]], points[tests[i, 1]], f1.Value);

                    Console.WriteLine("  Lines intersect at ({0}|{1}) with factors {2} and {3}.", pp.X, pp.Y, f1, f2);

                    if ((f1 > 0) && (f1 < 1) && (f2 > 0) && (f2 < 1))
                    {
                        Console.WriteLine("  Segments intersect.");

                        p = pp;
                    }
                    else
                    {
                        Console.WriteLine("  Segments do not intersect.");
                    }
                }
                else
                {
                    Console.WriteLine("  Lines are parallel.");
                }
            }

            if (p == null)
            {
                Console.WriteLine("The quadrilateral is concave.");
            }
            else
            {
                Console.WriteLine("The quadrilateral is convex.");

                for (Int32 j = 0; j < 4; j++)
                {
                    Console.WriteLine("   Point {0} ({3}|{4}) is the {1} {2} corner.", j, (points[j].Y < p.Value.Y) ? "bottom" : "top", (points[j].X < p.Value.X) ? "left" : "right", points[j].X, points[j].Y);
                }
            }

            Console.ReadLine();
        }

        private static Single? IntersectLines(PointF a1, PointF a2, PointF b1, PointF b2)
        {
            PointF r = Difference(a1, b1);
            PointF a = Difference(a2, a1);
            PointF b = Difference(b2, b1);

            Single p = r.X * b.Y - r.Y * b.X;
            Single q = a.Y * b.X - a.X * b.Y;

            return (Math.Abs(q) > Single.Epsilon) ? (p / q) : (Single?)null;
        }

        private static PointF Difference(PointF a, PointF b)
        {
            return new PointF(a.X - b.X, a.Y - b.Y);
        }

        private static PointF PointOnLine(PointF a, PointF b, Single f)
        {
            return new PointF(a.X + f * (b.X - a.X), a.Y + f * (b.Y - a.Y));
        }
    }
}

<强>输出

Intersecting segments (0|1) and (2|3).
  Lines intersect at (7|-12.5) with factors -1.5 and -0.5.
  Segments do not intersect.
Intersecting segments (0|2) and (1|3).
  Lines intersect at (-2|4) with factors -1.5 and -0.5.
  Segments do not intersect.
Intersecting segments (0|3) and (1|2).
  Lines intersect at (5|-0.4999999) with factors 0.1666667 and 0.5.
  Segments intersect.
The quadrilateral is convex.
   Point 0 (4|-2) is the bottom left corner.
   Point 1 (2|5) is the top left corner.
   Point 2 (8|-6) is the bottom right corner.
   Point 3 (10|7) is the top right corner.