iOS中使用OpenCV进行线性拟合(直线and曲线)

先上Github地址

线性拟合的应用领域比较广泛, 如运动轨迹计算、数据分析、图像处理等领域, 故在此写一篇学习相关文章.

直线拟合

在说直线拟合前我们先来复习一下直线方程. 直线方程的表达式有以下几种(引用自百度):

  1. 一般式:Ax+By+C=0(A、B不同时为0)【适用于所有直线】
    A1/A2=B1/B2≠C1/C2←→两直线平行
    A1/A2=B1/B2=C1/C2←→两直线重合
    横截距a=-C/A
    纵截距b=-C/B
  2. 点斜式:y-y0=k(x-x0) 【适用于不垂直于x轴的直线
    表示斜率为k,且过(x0,y0)的直线
  3. 截距式:x/a+y/b=1【适用于不过原点或不垂直于x轴、y轴的直线】
    表示与x轴、y轴相交,且x轴截距为a,y轴截距为b的直线
  4. 斜截式:y=kx+b【适用于不垂直于x轴的直线
    表示斜率为k且y轴截距为b的直线
  5. 两点式:【适用于不垂直于x轴、y轴的直线】
    表示过(x1,y1)和(x2,y2)的直线
    **(y-y1)/(y2-y1)=(x-x1)/(x2-x1) **(****x1≠x2,y1≠y2****)****
  6. 交点式:f1(x,y) *m+f2(x,y)=0 【适用于任何直线】
    表示过直线f1(x,y)=0与直线f2(x,y)=0的交点的直线
  7. 点平式:f(x,y) -f(x0,y0)=0【适用于任何直线】
    表示过点(x0,y0)且与直线f(x,y)=0平行的直线
  8. 法线式:x·cosα+ysinα-p=0【适用于不平行于坐标轴的直线】
    过原点向直线做一条的垂线段,该垂线段所在直线的倾斜角为α,p是该线段的长度
  9. 点向式(x-x0)/u=(y-y0)/v (u≠0,v≠0)【适用于任何直线】
    表示过点(x0,y0)且方向向量为(u,v )的直线
  10. 法向式:a(x-x0)+b(y-y0)=0【适用于任何直线】****
    表示过点(x0,y0)且与向量(a,b)垂直的直线

在OpenCV中使用的是点向式(x-x0)/u=(y-y0)/v (u≠0,v≠0)

在OpenCV中我们可以主要使用fitLine函数进行直线拟合, 其算法基于最小二乘法实现的, 关于最小二乘法后续再作详细介绍. fitLine函数定义如下:

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

该方法可以对二维或三维的点集进行拟合, 在二维模式下返回一个Vec4f的元素, 分别是点向式中的(u,v,x,y)

参数介绍:
points
输入一个二维或三维的向量, 数据结构可以是std::vector<> 或 Mat(推荐使用).

line
二维模式下返回Vec4f的元素(u,v,x,y), 三维模式下返回Vec6f的元素(vx, vy, vz, x0, y0, z0)

distType
拟合算法, 这里的拟合算法基于M-estimators实现, 有以下几种:

enum DistanceTypes {
    DIST_USER    = -1,  //!< User defined distance
    DIST_L1      = 1,   //!< distance = |x1-x2| + |y1-y2|
    DIST_L2      = 2,   //!< the simple euclidean distance
    DIST_C       = 3,   //!< distance = max(|x1-x2|,|y1-y2|)
    DIST_L12     = 4,   //!< L1-L2 metric: distance = 2(sqrt(1+x*x/2) - 1))
    DIST_FAIR    = 5,   //!< distance = c^2(|x|/c-log(1+|x|/c)), c = 1.3998
    DIST_WELSCH  = 6,   //!< distance = c^2/2(1-exp(-(x/c)^2)), c = 2.9846
    DIST_HUBER   = 7    //!< distance = |x|<c ? x^2/2 : c(|x|-c/2), c=1.345
};

其算法主要使用的是加权最小二乘法, 分别采用如下算法:

DistanceTypes

其中CV_DIST_L2为最简单快速的最小二乘法, 推荐使用.

param
拟合算法中的的C参, 设置为0时系统自动选用最优值.

reps
算法精度radius, 官方推荐0.01

aeps
算法精度angle, 官方推荐0.01

曲线拟合

首先,曲线的函数类型有:双曲线型、对数型、指数型、多项式型等。

对于最常见的曲线, 其特征接近于多项式型, 所以这里的曲线拟合问题就变成了多项式回归求解.
一般情况下,对实际的点数据进行求解是无解的, 所以我们需要引入最小二乘法来求解.(对于最小二乘法的原理和求解过程,后续再详细介绍)

在OpenCV中没有找到拟合曲线的算子, 这里使用C++来实现. 此算法迭代次数大于10时求解均为0. 若有更优的算法可以在评论中交流.

bool fittingCurve(vector<Point2f> &vec,int times,float *p) // 输入点数据, 迭代次数, 输出多项式参数
{
    float *py = new float[vec.size()];
    float *px = new float[times*vec.size()];
    int i = 0;
    
    for(vector<Point2f>::iterator itr = vec.begin();itr!=vec.end();++itr) {
        
        py[i] = (*itr).y;
        int j=0;
        while (j<times)
        {
            px[times*i+j] = pow(((*itr).x),float(j));
            j++;
        }
        i++;
    }
    
    Mat X = Mat((int)vec.size(),times,CV_32FC1,px);
    Mat X_T;
    transpose(X,X_T);
    
    Mat Y = Mat((int)vec.size(),1,CV_32FC1,py);
    Mat para = ((X_T*X).inv())*X_T*Y;
    
    for (int s = 0; s<times;s++){
        p[s] = para.at<float>(s);
    }
    
    delete[] px;
    delete[] py;
    
    return true;
}

下面我们来验证一组数据:

        int x[]={50,100,150,200,250,300,350,400,450,500,550,600,650,700,750};
        int y[]={428,454,480,506,532,458,384,210,636,662,688,778,504,430,456};

当迭代次数为3的时候求解结果为:

381.534
0.575073
-0.000505627

即:y = 381.534 + 0.575073x + -0.000505627x², 图像如下:

当迭代次数为7的时候求解结果为:

-210.757
17.1697
-0.132375
0.000430976
-6.52814e-07
4.45947e-10
-1.06088e-13

图像如下:


以下是一些自己测试的数据:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容