OpenCV迭代求椭圆与直线交点(C++实现)

        首先定义了一个椭圆类用来存放一个一般化的椭圆的参数,然后构建一个椭圆方程,至于为什么需要这些参数可以参考上一篇博客:https://blog.csdn.net/qq_41685265/article/details/104267256

class Ellipse {
public:
    double a;
    double b;
    double angle;
    Point center;
    Ellipse():a(0), b(0), angle(0), center(Point(0,0)) {}
    Ellipse(double a_, double b_, double angle_, Point center_) :
        a(a_), b(b_), angle(angle_), center(center_) {}
};

迭代的主要思想是:

  • 从一个初始点开始
  • 向正斜率和负斜率方向分别以一定步长进行逼近
  • 一但到达了椭圆外,就改变步长反复迭代
  • 终止条件是步长小于指定值

1、初始点选择

        初始点选为椭圆中心与直线的垂足,这个垂足大概率是在椭圆内的,要注意的是,如果垂足在椭圆外,这个算法是不成立的。

2、判断点是否在椭圆内

        可以带入椭圆方程看坐标是否小于1:,上代码:

bool fun(Ellipse& e, double x,double y) {
    double a = e.a;
    double b = e.b;
    double angle = e.angle;
    double m = e.center.x;
    double n = e.center.y;
    double t1 = pow((x - m) * cos(angle) + (y - n) * sin(angle), 2);
    double t2 = pow((m - x) * sin(angle) + (y - n) * cos(angle), 2);
    return t1 / (a * a) + t2 / (b * b) < 1;
}

3、求解交点

        因为要求两个交点,所以要迭代两次,flag为1是正斜率,flag为0是负斜率,k和b是直线的两个参数,看代码:

Point solve_edge_pionts(Ellipse& e, double &k, double &b,int flag) {
    //初始点
    double x = (e.center.x / k + e.center.y - b) / (1 / k + k);
    double y = k * x + b;
    double step = 5;
    if (!flag)step = -step;
    double minstep = 0.01;
    while (abs(step)>minstep) {
        while (fun(e, x + step, k * (x + step) + b)) {
            x = x + step;
        }
        step = step / 2;
    }
    Point p;
    p.x = x;
    p.y = k * x + b;
    return p;
}

 4、主函数调用

        因为这是我做的项目的一部分,所以把主函数中相关的摆在下边了:

int main() {
    string img = "test1.jpg";
    Mat src = imread(img);
    //椭圆参数自己获取,我这里省略了
    vector<Ellipse>Ellipses;
    
    //直线参数自己获取,我这里也省略了
    double k, b;

    //获取交点
    vector<Point>keyPoints;
    Point t;
    for (auto c : Ellipses) {
        t = solve_edge_pionts(c, k, b, 1);
        keyPoints.push_back(t);
        t = solve_edge_pionts(c, k, b, 0);
        keyPoints.push_back(t);
    }

    //画出交点
    for (auto c : keyPoints) {
        circle(src, c, 2, Scalar(0, 255, 0), 2);
    }
    imshow("src", src);
    waitKey(0);
	return 0;
}

        最后可以放一个示意图,是做项目中的中间结果:

发布了31 篇原创文章 · 获赞 38 · 访问量 5025

猜你喜欢

转载自blog.csdn.net/qq_41685265/article/details/104274982