19

I was looking for a helper function to calculate the intersection of two lines in OpenCV. I have searched the API Documentation, but couldn't find a useful resource.

Are there basic geometric helper functions for intersection/distance calculations on lines/line segments in OpenCV?

tisch
  • 1,098
  • 3
  • 13
  • 30

6 Answers6

44

There are no function in OpenCV API to calculate lines intersection, but distance is:

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

If you need a piece of code to calculate line intersections then here it is:

// 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;
}
Andrey Kamaev
  • 29,582
  • 6
  • 94
  • 88
  • Just for clarification. Are the lines in your example defined by two points, or as a point and a direction vector? – tisch Sep 17 '11 at 09:15
  • They are defined by two points. `d1` and `d2` calculated inside the function are direction vectors. – Andrey Kamaev Sep 17 '11 at 09:30
  • why `cross` variable is float type (why not double)? and why we use `abs` instead of `fabs` (or maybe it's `std::abs`)? why `EPS` variable is not from numerical limits something like `std::numeric_limits::epsilon()`? – mrgloom Dec 22 '15 at 11:49
  • 3
    see also [min_enclosing_triangle.cpp](https://github.com/Itseez/opencv/blob/master/modules/imgproc/src/min_enclosing_triangle.cpp#L1380-L1424) – sturkmen Jan 16 '16 at 19:45
  • @AndreyKamaev does t1 signifies anything? – arvind.mohan Aug 07 '16 at 08:32
  • Does this code check for the intersection of line or line segment? – kHarshit Jan 19 '21 at 10:34
11

There's one cool trick in 2D geometry which I find to be very useful to calculate lines intersection. In order to use this trick we represent each 2D point and each 2D line in homogeneous 3D coordinates.

At first let's talk about 2D points:

  1. Each 2D point (x, y) corresponds to a 3D line that passes through points (0, 0, 0) and (x, y, 1).
  2. So (x, y, 1) and (α•x, α•y, α) and (β•x, β•y, β) correspond to the same point (x, y) in 2D space.
  3. Here's formula to convert 2D point into homogeneous coordinates: (x, y) -> (x, y, 1)
  4. Here's formula to convert homogeneous coordinates into 2D point: (x, y, ω) -> (x / ω, y / ω). If ω is zero that means "point at infinity". It doesn't correspond to any point in 2D space.
  5. In OpenCV you may use convertPointsToHomogeneous() and convertPointsFromHomogeneous()

Now let's talk about 2D lines:

  1. Each 2D line can be represented with three coordinates (a, b, c) which corresponds to 2D line equation: a•x + b•y + c = 0
  2. So (a, b, c) and (ω•a, ω•b, ω•c) correspond to the same 2D line.
  3. Also, (a, b, c) corresponds to (nx, ny, d) where (nx, ny) is unit length normal vector and d is distance from the line to (0, 0)
  4. Also, (nx, ny, d) is (cos φ, sin φ, ρ) where (φ, ρ) are polar coordinates of the line.

There're two interesting formulas that link together points and lines:

  1. Cross product of two distinct points in homogeneous coordinates gives homogeneous line coordinates: (α•x₁, α•y₁, α) ✕ (β•x₂, β•y₂, β) = (a, b, c)
  2. Cross product of two distinct lines in homogeneous coordinates gives homogeneous coordinate of their intersection point: (a₁, b₁, c₁) ✕ (a₂, b₂, c₂) = (x, y, ω). If ω is zero that means lines are parallel (have no single intersection point in Euclidean geometry).
  3. In OpenCV you may use either Mat::cross() or numpy.cross() to get cross product

If you're still here, you've got all you need to find lines given two points and intersection point given two lines.

Maksym Ganenko
  • 1,288
  • 15
  • 11
4

An algorithm for finding line intersection is described very well in the post How do you detect where two line segments intersect?

The following is my openCV c++ implementation. It uses the same notation as in above post

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;
}
Community
  • 1
  • 1
Thorbjorn
  • 317
  • 2
  • 8
2

Here is my implementation for 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);
}
Gqqnbig
  • 5,845
  • 10
  • 45
  • 86
2

Using homogeneous coordinates makes your life easier:

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));
}

Note that if the third coordinate is 0 the lines are parallel and there is not solution in R² but in P^2, and then the point means a direction in 2D.

marcos.nieto
  • 374
  • 2
  • 6
1

my implementation in Python (using numpy array) with line1 = [[x1, y1],[x2, y2]] & 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)
afiah
  • 507
  • 5
  • 12