OpenCV 直线拟合及应用

来源:互联网 发布:战千雄源码 编辑:程序博客网 时间:2024/04/30 09:54

直线拟合顾名思义就是根据多个有限个数的点这里写图片描述确定一条直线。依据为:
这里写图片描述
其中这里写图片描述为第i个点到直线的距离,p(d)则为确定最小值的函数。而不同的p(d)对应着不同的直线拟合方法:

OpenCV提供了7种(-1为用户定义)直线拟合方法,如下:

CV_DIST_USER    =-1,  /* User defined distance */CV_DIST_L1      =1,   /* distance = |x1-x2| + |y1-y2| */CV_DIST_L2      =2,   /* the simple euclidean distance */CV_DIST_C       =3,   /* distance = max(|x1-x2|,|y1-y2|) */CV_DIST_L12     =4,   /* L1-L2 metric: distance = 2(sqrt(1+x*x/2) - 1)) */CV_DIST_FAIR    =5,   /* distance = c^2(|x|/c-log(1+|x|/c)), c = 1.3998 */CV_DIST_WELSCH  =6,   /* distance = c^2/2(1-exp(-(x/c)^2)), c = 2.9846 */CV_DIST_HUBER   =7    /* distance = |x|<c ? x^2/2 : c(|x|-c/2), c=1.345 */

OpenCV直线拟合函数:

CV_EXPORTS_W void fitLine( InputArray points, OutputArray line, int distType,double param, double reps, double aeps );

points为2D的点:
distType即为上面提到的算法;
param 是 上述公式中的常数C。如果取 0,则程序自动选取合适的值;
reps 表示直线到原点距离的精度,建议取 0.01;
aeps 表示直线角度的精度,建议取 0.01;
拟合结果即为函数的输出 line,为Vec4f类型,line[0]、line[1] 存放的是直线的方向向量。line[2]、line[3] 存放的是直线上一个点的坐标。
所以 ,直线的斜率即为:line[1]/line[0]。

直线拟合的应用:

#include <iostream>  #include <opencv2/core/core.hpp>  #include <opencv2/highgui/highgui.hpp>  #include <opencv2/opencv.hpp>  #define  PI 3.141592653using namespace cv;  using namespace std;  int main(){       Mat SrcImage, thresholdImage,grayImage;    SrcImage = imread("2.jpg");    cvtColor(SrcImage,grayImage,CV_BGR2GRAY);    threshold(grayImage,thresholdImage, 0, 255, CV_THRESH_OTSU+CV_THRESH_BINARY);    imshow("threshold",thresholdImage);    vector<Point2f> onefitlinepoints,twofitlinepoints;   //从上自下选择点    for (int i =SrcImage.cols/2-SrcImage.cols/5;i<SrcImage.cols/2+SrcImage.cols/5;i++)     { for (int j=0;j<SrcImage.rows-1;j++)        {if ((int)thresholdImage.at<uchar>(j,i)==255)            {  circle(thresholdImage,Point(i,j),2,Scalar(0,255,0));                onefitlinepoints.push_back(Point(i,j));                break;              }}}             //从下自上选择点     for (int k =SrcImage.cols/2-SrcImage.cols/5;k<SrcImage.cols/2+SrcImage.cols/5;k++)      {  for (int l=SrcImage.rows-1;l>0;l--)         {if ((int)thresholdImage.at<uchar>(l,k)==255)            { circle(thresholdImage,Point(k,l),2,Scalar(0,255,0));               twofitlinepoints.push_back(Point(k,l));               break;              }}}         //计算第一次拟合角度     Vec4f oneline;     fitLine(onefitlinepoints, oneline, CV_DIST_L1, 0, 0.01, 0.01);     cout<<oneline[0]<<endl;     cout<<oneline[1]<<endl;    //求角度     double  onefitlineradian =  atan(oneline[1]/oneline[0]);     double  onefitlineangle = (onefitlineradian*180)/CV_PI;     cout<<"直线拟合角度="<<onefitlineangle<<endl;    //计算第二次拟合角度    Vec4f twoline;    fitLine(twofitlinepoints, twoline, CV_DIST_L1, 0, 0.01, 0.01);    cout<<twoline[0]<<endl;    cout<<twoline[1]<<endl;    //求角度    double  twofitlineradian =  atan(twoline[1]/twoline[0]);    double  twofitlineangle = (twofitlineradian*180)/CV_PI;    cout<<"直线拟合角度="<<twofitlineangle<<endl;    double averagefitlineangle = (onefitlineangle+twofitlineangle)/2;    cout<<"直线拟合平均角度="<<averagefitlineangle<<endl;    //画出直线    Point2f point1,point2,point3;    point2.x = oneline[2];    point2.y = oneline[3];    point1.x = 0;    point1.y = oneline[1]*(point1.x-oneline[2])/oneline[0]+oneline[3];    point3.x = SrcImage.cols;    point3.y = oneline[1]*(point3.x-oneline[2])/oneline[0]+oneline[3];    line(SrcImage,point1,point3,Scalar(0,0,255));    imshow("直线拟合",SrcImage);    waitKey(0);    getchar();    return 0;}

这里写图片描述

这里写图片描述

2 0
原创粉丝点击