OpenCV 2d 线交点辅助函数
Posted
技术标签:
【中文标题】OpenCV 2d 线交点辅助函数【英文标题】:OpenCV 2d line intersection helper function 【发布时间】:2011-09-16 14:22:23 【问题描述】:我正在寻找一个辅助函数来计算 OpenCV 中两条线的交点。我搜索了 API 文档,但找不到有用的资源。
OpenCV中是否有基本的几何辅助函数用于线/线段的交点/距离计算?
【问题讨论】:
【参考方案1】: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;
【讨论】:
只是为了澄清。您的示例中的线是由两个点定义的,还是由一个点和一个方向向量定义的? 它们由两点定义。函数内部计算的d1
和d2
是方向向量。
为什么cross
变量是浮点类型(为什么不是双精度)?为什么我们使用abs
而不是fabs
(或者可能是std::abs
)?为什么EPS
变量不是来自像std::numeric_limits<T>::epsilon()
这样的数值限制?
另见min_enclosing_triangle.cpp
@AndreyKamaev t1 表示什么?【参考方案2】:
在 2D 几何中有一个很酷的技巧,我发现它对于计算线的交点非常有用。为了使用这个技巧,我们在齐次 3D 坐标中表示每个 2D 点和每条 2D 线。
首先让我们谈谈二维点:
-
每个 2D 点
(x, y)
对应于通过点 (0, 0, 0)
和 (x, y, 1)
的 3D 线。
所以(x, y, 1)
和(α•x, α•y, α)
和(β•x, β•y, β)
对应于二维空间中的同一点(x, y)
。
这是将二维点转换为齐次坐标的公式:(x, y) -> (x, y, 1)
这是将齐次坐标转换为二维点的公式:(x, y, ω) -> (x / ω, y / ω)
。如果 ω 为零,则表示“指向无穷远”。它不对应二维空间中的任何点。
在 OpenCV 中,您可以使用 convertPointsToHomogeneous()
和 convertPointsFromHomogeneous()
现在我们来谈谈二维线:
-
每条二维线可以用三个坐标
(a, b, c)
表示,对应二维线方程:a•x + b•y + c = 0
所以(a, b, c)
和(ω•a, ω•b, ω•c)
对应同一条二维线。
另外,(a, b, c)
对应于(nx, ny, d)
,其中(nx, ny)
是单位长度法线向量,d 是直线到(0, 0)
的距离
另外,(nx, ny, d)
是 (cos φ, sin φ, ρ)
,其中 (φ, ρ)
是直线的极坐标。
有两个有趣的公式将点和线联系在一起:
-
齐次坐标中两个不同点的叉积得到齐次线坐标:
(α•x₁, α•y₁, α) ✕ (β•x₂, β•y₂, β) = (a, b, c)
齐次坐标中两条不同线的叉积给出了它们交点的齐次坐标:(a₁, b₁, c₁) ✕ (a₂, b₂, c₂) = (x, y, ω)
。如果 ω 为零,则表示线是平行的(在欧几里得几何中没有单个交点)。
在 OpenCV 中,您可以使用 Mat::cross()
或 numpy.cross()
来获得叉积
如果你还在这里,你已经拥有了在给定两点的情况下找到线和给定两条线的交点所需的一切。
【讨论】:
太棒了,点到线的距离在这里:en.wikipedia.org/wiki/Distance_from_a_point_to_a_line【参考方案3】:这是我对 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】:使用齐次坐标让您的生活更轻松:
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中的方向。
【讨论】:
point
的形状是什么?此函数不返回任何内容。【参考方案5】:
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;
【讨论】:
【参考方案6】:我在 Python 中的实现(使用 numpy 数组) 与 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)
【讨论】:
x1, y1 & x2,y2 必须像 (0.0, 1.0) & (2.0, 1.0) 一样浮动 此代码在存在垂直线的情况下不起作用,因为 (si[0] - ei[0]) 的划分以上是关于OpenCV 2d 线交点辅助函数的主要内容,如果未能解决你的问题,请参考以下文章