OpenCV 2d线交叉辅助函数

时间:2011-09-16 14:22:24

标签: opencv

我正在寻找一个辅助函数来计算OpenCV中两条线的交集。我搜索过API文档,但找不到有用的资源。

是否有基本的几何辅助函数用于OpenCV中线/线段的交点/距离计算?

6 个答案:

答案 0 :(得分:41)

OpenCV API中没有函数来计算行交集,但距离为:

cv::Point2f start, end;
double length = cv::norm(end - start);

如果你需要一段代码来计算线交叉点,那么它就是:

// Finds the intersection of two lines, or returns false.
// The lines are defined by (o1, p1) and (o2, p2).
bool intersection(Point2f o1, Point2f p1, Point2f o2, Point2f p2,
                      Point2f &r)
{
    Point2f x = o2 - o1;
    Point2f d1 = p1 - o1;
    Point2f d2 = p2 - o2;

    float cross = d1.x*d2.y - d1.y*d2.x;
    if (abs(cross) < /*EPS*/1e-8)
        return false;

    double t1 = (x.x * d2.y - x.y * d2.x)/cross;
    r = o1 + d1 * t1;
    return true;
}

答案 1 :(得分:4)

在2D几何中有一个很酷的技巧,我发现它对于计算线交叉非常有用。为了使用这个技巧,我们在均匀的3D坐标中表示每个2D点和每个2D线。

首先让我们谈谈2D点:

  1. 每个2D点<input>对应于通过点(x, y)(0, 0, 0)的3D线。
  2. 因此(x, y, 1)(x, y, 1)以及(α•x, α•y, α)对应于2D空间中的同一点(β•x, β•y, β)
  3. 以下是将2D点转换为齐次坐标的公式:(x, y)
  4. 以下是将齐次坐标转换为2D点的公式:(x, y) -> (x, y, 1)。如果ω为零,则意味着“指向无限远”。它与2D空间中的任何点都不对应。
  5. 在OpenCV中,您可以使用(x, y, ω) -> (x / ω, y / ω)convertPointsToHomogeneous()
  6. 现在让我们谈谈2D线:

    1. 每条2D线可以用三个坐标convertPointsFromHomogeneous()表示,对应于2D线方程:(a, b, c)
    2. 因此a•x + b•y + c = 0(a, b, c)对应于相同的2D线。
    3. 此外,(ω•a, ω•b, ω•c)对应于(a, b, c),其中(nx, ny, d)是规范化的法向量,d是从该行到(nx, ny)的距离。
    4. 此外,(0, 0)(nx, ny, d),其中(cos φ, sin φ, ρ)为该行的极坐标。
    5. 有两个有趣的公式将点和线连接在一起:

      1. 齐次坐标中两个不同点的交叉积给出了齐次线坐标:(φ, ρ)
      2. 齐次坐标中两条不同线的交叉积给出了它们交点的齐次坐标:(x₁, y₁, 1) ✕ (x₂, y₂, 1) = (a, b, c)。如果ω为零,则意味着线是平行的(欧几里德几何中没有单个交叉点)。
      3. 在OpenCV中,您可以使用(a₁, b₁, c₁) ✕ (a₂, b₂, c₂) = (x, y, ω)Mat::cross()来获取跨产品
      4. 如果你还在这里,你已经得到了所需的一切,只需要两条线给出两条线和交叉点。

答案 2 :(得分:2)

使用齐次坐标可以让您的生活更轻松:

cv::Mat intersectionPoint(const cv::Mat& line1, const cv::Mat& line2)
{
   // Assume we receive lines as l=(a,b,c)^T
   assert(line1.rows == 3 && line1.cols = 1 
          && line2.rows == 3 && line2.cols == 1);

   // Point is p=(x,y,w)^T
   cv::Mat point = line1.cross(line2);

   // Normalize so it is p'=(x',y',1)^T
   if( point.at<double>(2,0) != 0)
     point = point * (1.0/point.at<double>(2,0));
}

请注意,如果第三个坐标为0,则线条是平行的,R²中没有解,但在P ^ 2中,则该点表示2D中的方向。

答案 3 :(得分:1)

这是我对EmguCV(C#)的实现。

static PointF GetIntersection(LineSegment2D line1, LineSegment2D line2)
{

    double a1 = (line1.P1.Y - line1.P2.Y) / (double)(line1.P1.X - line1.P2.X);
    double b1 = line1.P1.Y - a1 * line1.P1.X;

    double a2 = (line2.P1.Y - line2.P2.Y) / (double)(line2.P1.X - line2.P2.X);
    double b2 = line2.P1.Y - a2 * line2.P1.X;

    if (Math.Abs(a1 - a2) < double.Epsilon)
        throw new InvalidOperationException();

    double x = (b2 - b1) / (a1 - a2);
    double y = a1 * x + b1;
    return new PointF((float)x, (float)y);
}

答案 4 :(得分:1)

在帖子How do you detect where two line segments intersect?

中很好地描述了查找线交叉的算法

以下是我的openCV c ++实现。它使用与上面的帖子

相同的表示法
bool getIntersectionPoint(Point a1, Point a2, Point b1, Point b2, Point & intPnt){
    Point p = a1;
    Point q = b1;
    Point r(a2-a1);
    Point s(b2-b1);

    if(cross(r,s) == 0) {return false;}

    double t = cross(q-p,s)/cross(r,s);

    intPnt = p + t*r;
    return true;
}

double cross(Point v1,Point v2){
    return v1.x*v2.y - v1.y*v2.x;
}

答案 5 :(得分:0)

我在Python中的实现(使用numpy数组) line1 = [[x1,y1],[x2,y2]]&amp; line2 = [[x1,y1],[x2,y2]]

def getIntersection(line1, line2):
    s1 = numpy.array(line1[0])
    e1 = numpy.array(line1[1])

    s2 = numpy.array(line2[0])
    e2 = numpy.array(line2[1])

    a1 = (s1[1] - e1[1]) / (s1[0] - e1[0])
    b1 = s1[1] - (a1 * s1[0])

    a2 = (s2[1] - e2[1]) / (s2[0] - e2[0])
    b2 = s2[1] - (a2 * s2[0])

    if abs(a1 - a2) < sys.float_info.epsilon:
        return False

    x = (b2 - b1) / (a1 - a2)
    y = a1 * x + b1
    return (x, y)