C++版本OpenCv教程(四十三)直线拟合

前面介绍的函数都是寻找图像或者点集中是否存在直线,而有时我们明确已知获取到的数据在一条直线上,此时需要将所有数据拟合出一条直线,但是由于噪声的存在,这条直线可能不会通过大多数的数据,因此需要保证所有的数据点距离直线的距离最小,如图7-10所示。相比于直线检测,直线拟合的最大特点是将所有数据只拟合出一条直线。
在这里插入图片描述

OpenCV 4中提供了利用最小二乘M-estimator方法拟合直线的**fitLine()**函数,该函数的函数原型在代码清单7-7中给出。

void cv::fitLine(InputArray  points,
	             OutputArray  line,
	             int  distType,
	             double  param,
	             double  reps,
	             double  aeps 
	             )
  • points:输入待拟合直线的2D或者3D点集。
  • line:输出描述直线的参数,2D点集描述参数为Vec4f类型,3D点集描述参数为Vec6f类型。
  • distType:M-estimator算法使用的距离类型标志,可以选择的距离类型在表7-1中给出。
  • param:某些类型距离的数值参数(C)。如果数值为0,则自动选择最佳值。
  • reps:坐标原点与直线之间的距离精度,数值0表示选择自适应参数,一般常选择0.01。
  • aeps:直线角度精度,数值0表示选择自适应参数,一般常选择0.01。

该函数利用最小二乘法拟合出距离所有点距离最小的直线,直线的描述形式可以转化成点斜式。函数第一个参数是待拟合直线的2D或者3D点集,可以存放在vector<>或者Mat类型的变量中赋值给参数。函数第二个参数是拟合直线的描述参数,如果是2D点集,输出量为Vec4f类型的(vx vy x0 y0),其中**(vx vy)是与直线共线的归一化向量**,(x0 y0)是拟合直线上的随意一点,根据这四个量可以计算得到2维平面直线的点斜式解析式,表示形式如式(7.6)所示。
在这里插入图片描述

如果输入参数是3D点集,输出量为Vec6f类型的(vx vy vz x0 y0 z0),其中(vx vy vz)是与直线共线的归一化向量,(x0 y0 z0)是拟合直线上的随意一点。函数第三个参数是M-estimator算法使用的距离类型标志,可以选择的距离类型在表7-1中给出。函数第四个参数是某些距离类型中的数值参数C,如果数值0表示选择最佳值。函数第五个参数表示坐标原点与拟合直线之间的距离精度,数值0表示选择自适应参数;函数第六个参数表示拟合直线的角度精度,数值0表示选择自适应参数。第五个参数和第六个参数一般取值0.01。
在这里插入图片描述
为了了解该函数的使用方法,在代码清单7-8中给出了利用fitLine()函数拟合直线的示例程序。程序中给出了 直线上的坐标点,为了模拟采集数据过程中产生的噪声,在部分坐标中添加了噪声。程序拟合出的直线很好的逼近了真实的直线,程序运行的结果在图7-11给出。

#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>

using namespace cv;
using namespace std;

int main()
{
    
    
    system("color F0");  //更改输出界面颜色
    Vec4f lines;//存放拟合后的直线
    vector<Point2f>point;//待检测是否存在直线的所有点
    const static float Points[20][2]={
    
    
            {
    
    0.0f,0.0f},{
    
    10.0f,11.0f},{
    
    21.0f,20.0f},{
    
    30.0f,30.0f},
            {
    
    40.0f,42.0f},{
    
    50.0f,50.0f},{
    
    60.0f,60.0f},{
    
    70.0f,70.0f},
            {
    
    80.0f,80.0f},{
    
    90.0f,92.0f},{
    
    100.0f,100.0f},{
    
    110.0f,110.0f},
            {
    
    120.f,120.0f},{
    
    136.0f,130.0f},{
    
    138.0f,140.0f},{
    
    150.0f,150.0f},
            {
    
    160.0f,163.0f},{
    
    175.0f,170.0f},{
    
    181.0f,180.0f},{
    
    200.0f,190.0f}
    };
    //将所有点存放在vector中,用于输入函数中
    for(int i=0;i<20;++i){
    
    
        point.push_back(Point2f(Points[i][0],Points[i][1]));
    }
    //参数设置
    double param=0;//距离模型中的数值参数C
    double reps=0.01;//坐标原点与直线之间的距离
    double aeps=0.01;//角度精度
    fitLine(point,lines,DIST_L1,0,0.01,0.01);
    double k=lines[1]/lines[0];//直线斜率
    cout<<"直线斜率: "<<k<<endl;
    cout<<"直线上一点坐标x: "<<lines[2]<<",y: "<<lines[3]<<endl;
    cout<<"直线解析式: y="<<k<<"(x-"<<lines[2]<<")+"<<lines[3]<<endl;
    return 0;
}

运行结果:

直线斜率: 0.999955
直线上一点坐标x: 76.7907,y: 76.7907
直线解析式: y=0.999955(x-76.7907)+76.7907

猜你喜欢

转载自blog.csdn.net/qq_33287871/article/details/112847431