使用OpenCV C++获取霍夫线的交点

3

这与此帖不相似,因为在Python中我们有numpy来解决所有问题。我已经用C++编写了一段代码来查找霍夫线的交点。

vector<Point2f> new_intersection(vector<Vec2f> lines) {
    vector<Point2f> intersections;
    float m1, c1, m2, c2;
    float x1, y1, x2, y2;
    float dx, dy, dx1, dy1;
    for (auto&& i : combinations(lines, 2)) {
        Point pt;
        float rho = i[0][0], theta = i[0][1];
        Point pt1, pt2;
        double a = cos(theta), b = sin(theta);
        double x0 = a * rho, y0 = b * rho;
        pt1.x = cvRound(x0 + 1000 * (-b));
        pt1.y = cvRound(y0 + 1000 * (a));
        pt2.x = cvRound(x0 - 1000 * (-b));
        pt2.y = cvRound(y0 - 1000 * (a));

        Point pt3, pt4;
        float rho1 = i[1][0], theta1 = i[1][1];
        double a1 = cos(theta1), b1 = sin(theta1);
        double x01 = a1 * rho1, y01 = b1 * rho1;
        pt3.x = cvRound(x01 + 1000 * (-b1));
        pt3.y = cvRound(y01 + 1000 * (a1));
        pt4.x = cvRound(x01 - 1000 * (-b1));
        pt4.y = cvRound(y01 - 1000 * (a1));

        dx = pt2.x - pt1.x;
        dy = pt2.y - pt1.y;
        m1 = dy / dx;
        c1 = pt1.y - m1 * pt1.x;

        dx1 = pt4.x - pt3.x;
        dy1 = pt4.y - pt3.y;
        m2 = dy1 / dx1;
        c2 = pt3.y - m2 * pt3.x;

        if (m1 == m2)
            continue;
        else{
            pt.x = (c2 - c1) / (m1 - m2);
            pt.y = m1 * pt.x + c1;
            intersections.push_back(pt);
        }
    }
    return intersections;
}

我已经使用简单的数学公式找到了所有线条之间的交点,但是这种方法并不能给出所有正确的交点。请查看下面的原始、霍夫和交点图像。

Original Hough Intersections

这些是我得到的交点:

交点1:[-3345,116]

交点2:[163,177]

交点3:[-1527,115]

交点4:[164,87]

交点5:[163,116]

交点6:[-2.14748e+09,-2.14748e+09]

从数学上讲,这些公式是正确的,并应该给出正确的交点。


测试m1==m2假设线是完全平行的,这实际上并不是这种情况,因此会报告一个非常遥远的交点。您应该考虑在m1m2周围设置一个阈值。此外,当dxdx1非常小时,m1m2变得非常不稳定。 - prog-fh
在将候选点推入向量后,您可以过滤掉那些超出图像边界的点。 - frogatto
你可以打印出所有“continue”情况,并自行查找它们为何会被意外跳过或某些行根本未被处理。如果5行不是完全平行的话,我期望会有20个交点。 - Micka
1个回答

1
你不应该依赖公式c = y - m * x,因为尽管这个数学公式是正确的,但它无法正确地表示垂直线(例如theta = 0),所以你的计算要么变得不稳定(如果直线非常靠近垂直线,则由于精度有限),要么完全失败,因为如果pt1.x == pt2.x,则m变为无穷大。

相反,你应该使用向量来计算交点。这个计算可能会更加复杂,但不会出现任何垂直线的问题。使用向量,你可以解决pt1 + lambda * (pt2 - pt1) = pt3 + alpha * (pt4 - pt3),并将该值放入相应的一侧。在代码中,这会像这样:

float dx0 = pt2.x - pt1.x;
float dx1 = pt4.x - pt3.x;
float dy0 = pt2.y - pt1.y;
float dy1 = pt4.y - pt3.y;
//Solve for lambda:
float div = (dy0 * dx1) - (dx0 * dy1);
if(abs(div) < EPSILON) { continue; } //lines are parallel
float lambda = (((pt1.x - pt3.x) * dx1) + ((pt1.y - pt3.y) * dy1)) / div;
//put lambda back into pt1 + lambda * (pt2 - pt1) to calculate intersection point:
pt.x = pt1.x + (lambda * dx0);
pt.y = pt1.y + (lambda * dy0);

如果您更喜欢,也可以直接使用theta和rho计算交点的公式。


你能否分享(链接)Theta-Rho公式? - trogper
2
请参见 https://dev59.com/IHRC5IYBdhLWcg3wMd9S,其中包含该公式的数学和代码答案。 - Bizzarrus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接