OpenCV实现了直线的拟合。

CV_IMPL void
cvFitLine( const CvArr* array, int dist, double param,
double reps, double aeps, float *line )
{
cv::AutoBuffer<schar> buffer; schar* points = 0;
union { CvContour contour; CvSeq seq; } header;
CvSeqBlock block;
CvSeq* ptseq = (CvSeq*)array;
int type; if( !line )
CV_Error( CV_StsNullPtr, "NULL pointer to line parameters" ); if( CV_IS_SEQ(ptseq) )
{
type = CV_SEQ_ELTYPE(ptseq);
if( ptseq->total == 0 )
CV_Error( CV_StsBadSize, "The sequence has no points" );
if( (type!=CV_32FC2 && type!=CV_32FC3 && type!=CV_32SC2 && type!=CV_32SC3) ||
CV_ELEM_SIZE(type) != ptseq->elem_size )
CV_Error( CV_StsUnsupportedFormat,
"Input sequence must consist of 2d points or 3d points" );
}
else
{
CvMat* mat = (CvMat*)array;
type = CV_MAT_TYPE(mat->type);
if( !CV_IS_MAT(mat))
CV_Error( CV_StsBadArg, "Input array is not a sequence nor matrix" ); if( !CV_IS_MAT_CONT(mat->type) ||
(type!=CV_32FC2 && type!=CV_32FC3 && type!=CV_32SC2 && type!=CV_32SC3) ||
(mat->width != 1 && mat->height != 1))
CV_Error( CV_StsBadArg,
"Input array must be 1d continuous array of 2d or 3d points" ); ptseq = cvMakeSeqHeaderForArray(
CV_SEQ_KIND_GENERIC|type, sizeof(CvContour), CV_ELEM_SIZE(type), mat->data.ptr,
mat->width + mat->height - 1, &header.seq, &block );
} if( reps < 0 || aeps < 0 )
CV_Error( CV_StsOutOfRange, "Both reps and aeps must be non-negative" ); if( CV_MAT_DEPTH(type) == CV_32F && ptseq->first->next == ptseq->first )
{
/* no need to copy data in this case */
points = ptseq->first->data;
}
else
{
buffer.allocate(ptseq->total*CV_ELEM_SIZE(type));
points = buffer;
cvCvtSeqToArray( ptseq, points, CV_WHOLE_SEQ ); if( CV_MAT_DEPTH(type) != CV_32F )
{
int i, total = ptseq->total*CV_MAT_CN(type);
assert( CV_MAT_DEPTH(type) == CV_32S ); for( i = 0; i < total; i++ )
((float*)points)[i] = (float)((int*)points)[i];
}
} if( dist == CV_DIST_USER )
CV_Error( CV_StsBadArg, "User-defined distance is not allowed" ); if( CV_MAT_CN(type) == 2 )
{
IPPI_CALL( icvFitLine2D( (CvPoint2D32f*)points, ptseq->total,
dist, (float)param, (float)reps, (float)aeps, line ));
}
else
{
IPPI_CALL( icvFitLine3D( (CvPoint3D32f*)points, ptseq->total,
dist, (float)param, (float)reps, (float)aeps, line ));
}
}

  

二维的直线拟合?

/* Takes an array of 2D points, type of distance (including user-defined
distance specified by callbacks, fills the array of four floats with line
parameters A, B, C, D, where (A, B) is the normalized direction vector,
(C, D) is the point that belongs to the line. */ static CvStatus icvFitLine2D( CvPoint2D32f * points, int count, int dist,
float _param, float reps, float aeps, float *line )
{
double EPS = count*FLT_EPSILON;
void (*calc_weights) (float *, int, float *) = 0;
void (*calc_weights_param) (float *, int, float *, float) = 0;
float *w; /* weights */
float *r; /* square distances */
int i, j, k;
float _line[6], _lineprev[6];
float rdelta = reps != 0 ? reps : 1.0f;
float adelta = aeps != 0 ? aeps : 0.01f;
double min_err = DBL_MAX, err = 0;
CvRNG rng = cvRNG(-1); memset( line, 0, 4*sizeof(line[0]) ); switch (dist)
{
case CV_DIST_L2:
return icvFitLine2D_wods( points, count, 0, line ); case CV_DIST_L1:
calc_weights = icvWeightL1;
break; case CV_DIST_L12:
calc_weights = icvWeightL12;
break; case CV_DIST_FAIR:
calc_weights_param = icvWeightFair;
break; case CV_DIST_WELSCH:
calc_weights_param = icvWeightWelsch;
break; case CV_DIST_HUBER:
calc_weights_param = icvWeightHuber;
break; /*case CV_DIST_USER:
calc_weights = (void ( * )(float *, int, float *)) _PFP.fp;
break;*/ default:
return CV_BADFACTOR_ERR;
} w = (float *) cvAlloc( count * sizeof( float ));
r = (float *) cvAlloc( count * sizeof( float )); for( k = 0; k < 20; k++ )
{
int first = 1;
for( i = 0; i < count; i++ )
w[i] = 0.f; for( i = 0; i < MIN(count,10); )
{
j = cvRandInt(&rng) % count;
if( w[j] < FLT_EPSILON )
{
w[j] = 1.f;
i++;
}
} icvFitLine2D_wods( points, count, w, _line );
for( i = 0; i < 30; i++ )
{
double sum_w = 0; if( first )
{
first = 0;
}
else
{
double t = _line[0] * _lineprev[0] + _line[1] * _lineprev[1];
t = MAX(t,-1.);
t = MIN(t,1.);
if( fabs(acos(t)) < adelta )
{
float x, y, d; x = (float) fabs( _line[2] - _lineprev[2] );
y = (float) fabs( _line[3] - _lineprev[3] ); d = x > y ? x : y;
if( d < rdelta )
break;
}
}
/* calculate distances */
err = icvCalcDist2D( points, count, _line, r );
if( err < EPS )
break; /* calculate weights */
if( calc_weights )
calc_weights( r, count, w );
else
calc_weights_param( r, count, w, _param ); for( j = 0; j < count; j++ )
sum_w += w[j]; if( fabs(sum_w) > FLT_EPSILON )
{
sum_w = 1./sum_w;
for( j = 0; j < count; j++ )
w[j] = (float)(w[j]*sum_w);
}
else
{
for( j = 0; j < count; j++ )
w[j] = 1.f;
} /* save the line parameters */
memcpy( _lineprev, _line, 4 * sizeof( float )); /* Run again... */
icvFitLine2D_wods( points, count, w, _line );
} if( err < min_err )
{
min_err = err;
memcpy( line, _line, 4 * sizeof(line[0]));
if( err < EPS )
break;
}
} cvFree( &w );
cvFree( &r );
return CV_OK;
}

调用的函数

 static CvStatus icvFitLine2D_wods( CvPoint2D32f * points, int _count, float *weights, float *line )
{
double x = , y = , x2 = , y2 = , xy = , w = ;
double dx2, dy2, dxy;
int i;
int count = _count;
float t; /* Calculating the average of x and y... */ if( weights == )
{
for( i = ; i < count; i += )
{
x += points[i].x;
y += points[i].y;
x2 += points[i].x * points[i].x;
y2 += points[i].y * points[i].y;
xy += points[i].x * points[i].y;
}
w = (float) count;
}
else
{
for( i = ; i < count; i += )
{
x += weights[i] * points[i].x;
y += weights[i] * points[i].y;
x2 += weights[i] * points[i].x * points[i].x;
y2 += weights[i] * points[i].y * points[i].y;
xy += weights[i] * points[i].x * points[i].y;
w += weights[i];
}
} x /= w;
y /= w;
x2 /= w;
y2 /= w;
xy /= w; dx2 = x2 - x * x;
dy2 = y2 - y * y;
dxy = xy - x * y; t = (float) atan2( * dxy, dx2 - dy2 ) / ;
line[] = (float) cos( t );
line[] = (float) sin( t ); line[] = (float) x;
line[] = (float) y; return CV_NO_ERR;
}

icvFitLine2D_wods

权重计算方法

 static void icvWeightL1( float *d, int count, float *w )
{
int i; for( i = ; i < count; i++ )
{
double t = fabs( (double) d[i] );
w[i] = (float)(. / MAX(t, eps));
}
} static void icvWeightL12( float *d, int count, float *w )
{
int i; for( i = ; i < count; i++ )
{
w[i] = 1.0f / (float) sqrt( + (double) (d[i] * d[i] * 0.5) );
}
} static void icvWeightHuber( float *d, int count, float *w, float _c )
{
int i;
const float c = _c <= ? 1.345f : _c; for( i = ; i < count; i++ )
{
if( d[i] < c )
w[i] = 1.0f;
else
w[i] = c/d[i];
}
} static void icvWeightFair( float *d, int count, float *w, float _c )
{
int i;
const float c = _c == ? / 1.3998f : / _c; for( i = ; i < count; i++ )
{
w[i] = / ( + d[i] * c);
}
} static void icvWeightWelsch( float *d, int count, float *w, float _c )
{
int i;
const float c = _c == ? / 2.9846f : / _c; for( i = ; i < count; i++ )
{
w[i] = (float) exp( -d[i] * d[i] * c * c );
}
}

三维的直线拟合?

/* Takes an array of 3D points, type of distance (including user-defined
distance specified by callbacks, fills the array of four floats with line
parameters A, B, C, D, E, F, where (A, B, C) is the normalized direction vector,
(D, E, F) is the point that belongs to the line. */ static CvStatus
icvFitLine3D( CvPoint3D32f * points, int count, int dist,
float _param, float reps, float aeps, float *line )
{
double EPS = count*FLT_EPSILON;
void (*calc_weights) (float *, int, float *) = 0;
void (*calc_weights_param) (float *, int, float *, float) = 0;
float *w; /* weights */
float *r; /* square distances */
int i, j, k;
float _line[6]={0,0,0,0,0,0}, _lineprev[6]={0,0,0,0,0,0};
float rdelta = reps != 0 ? reps : 1.0f;
float adelta = aeps != 0 ? aeps : 0.01f;
double min_err = DBL_MAX, err = 0;
CvRNG rng = cvRNG(-1); switch (dist)
{
case CV_DIST_L2:
return icvFitLine3D_wods( points, count, 0, line ); case CV_DIST_L1:
calc_weights = icvWeightL1;
break; case CV_DIST_L12:
calc_weights = icvWeightL12;
break; case CV_DIST_FAIR:
calc_weights_param = icvWeightFair;
break; case CV_DIST_WELSCH:
calc_weights_param = icvWeightWelsch;
break; case CV_DIST_HUBER:
calc_weights_param = icvWeightHuber;
break; /*case CV_DIST_USER:
_PFP.p = param;
calc_weights = (void ( * )(float *, int, float *)) _PFP.fp;
break;*/ default:
return CV_BADFACTOR_ERR;
} w = (float *) cvAlloc( count * sizeof( float ));
r = (float *) cvAlloc( count * sizeof( float )); for( k = 0; k < 20; k++ )
{
int first = 1;
for( i = 0; i < count; i++ )
w[i] = 0.f; for( i = 0; i < MIN(count,10); )
{
j = cvRandInt(&rng) % count;
if( w[j] < FLT_EPSILON )
{
w[j] = 1.f;
i++;
}
} icvFitLine3D_wods( points, count, w, _line );
for( i = 0; i < 30; i++ )
{
double sum_w = 0; if( first )
{
first = 0;
}
else
{
double t = _line[0] * _lineprev[0] + _line[1] * _lineprev[1] + _line[2] * _lineprev[2];
t = MAX(t,-1.);
t = MIN(t,1.);
if( fabs(acos(t)) < adelta )
{
float x, y, z, ax, ay, az, dx, dy, dz, d; x = _line[3] - _lineprev[3];
y = _line[4] - _lineprev[4];
z = _line[5] - _lineprev[5];
ax = _line[0] - _lineprev[0];
ay = _line[1] - _lineprev[1];
az = _line[2] - _lineprev[2];
dx = (float) fabs( y * az - z * ay );
dy = (float) fabs( z * ax - x * az );
dz = (float) fabs( x * ay - y * ax ); d = dx > dy ? (dx > dz ? dx : dz) : (dy > dz ? dy : dz);
if( d < rdelta )
break;
}
}
/* calculate distances */
if( icvCalcDist3D( points, count, _line, r ) < FLT_EPSILON*count )
break; /* calculate weights */
if( calc_weights )
calc_weights( r, count, w );
else
calc_weights_param( r, count, w, _param ); for( j = 0; j < count; j++ )
sum_w += w[j]; if( fabs(sum_w) > FLT_EPSILON )
{
sum_w = 1./sum_w;
for( j = 0; j < count; j++ )
w[j] = (float)(w[j]*sum_w);
}
else
{
for( j = 0; j < count; j++ )
w[j] = 1.f;
} /* save the line parameters */
memcpy( _lineprev, _line, 6 * sizeof( float )); /* Run again... */
icvFitLine3D_wods( points, count, w, _line );
} if( err < min_err )
{
min_err = err;
memcpy( line, _line, 6 * sizeof(line[0]));
if( err < EPS )
break;
}
} // Return...
cvFree( &w );
cvFree( &r );
return CV_OK;
}

  

调用的方法

 static CvStatus icvFitLine3D_wods( CvPoint3D32f * points, int count, float *weights, float *line )
{
int i;
float w0 = ;
float x0 = , y0 = , z0 = ;
float x2 = , y2 = , z2 = , xy = , yz = , xz = ;
float dx2, dy2, dz2, dxy, dxz, dyz;
float *v;
float n;
float det[], evc[], evl[]; memset( evl, , *sizeof(evl[]));
memset( evc, , *sizeof(evl[])); if( weights )
{
for( i = ; i < count; i++ )
{
float x = points[i].x;
float y = points[i].y;
float z = points[i].z;
float w = weights[i]; x2 += x * x * w;
xy += x * y * w;
xz += x * z * w;
y2 += y * y * w;
yz += y * z * w;
z2 += z * z * w;
x0 += x * w;
y0 += y * w;
z0 += z * w;
w0 += w;
}
}
else
{
for( i = ; i < count; i++ )
{
float x = points[i].x;
float y = points[i].y;
float z = points[i].z; x2 += x * x;
xy += x * y;
xz += x * z;
y2 += y * y;
yz += y * z;
z2 += z * z;
x0 += x;
y0 += y;
z0 += z;
}
w0 = (float) count;
} x2 /= w0;
xy /= w0;
xz /= w0;
y2 /= w0;
yz /= w0;
z2 /= w0; x0 /= w0;
y0 /= w0;
z0 /= w0; dx2 = x2 - x0 * x0;
dxy = xy - x0 * y0;
dxz = xz - x0 * z0;
dy2 = y2 - y0 * y0;
dyz = yz - y0 * z0;
dz2 = z2 - z0 * z0; det[] = dz2 + dy2;
det[] = -dxy;
det[] = -dxz;
det[] = det[];
det[] = dx2 + dz2;
det[] = -dyz;
det[] = det[];
det[] = det[];
det[] = dy2 + dx2; /* Searching for a eigenvector of det corresponding to the minimal eigenvalue */
#if 1
{
CvMat _det = cvMat( , , CV_32F, det );
CvMat _evc = cvMat( , , CV_32F, evc );
CvMat _evl = cvMat( , , CV_32F, evl );
cvEigenVV( &_det, &_evc, &_evl, );
i = evl[] < evl[] ? (evl[] < evl[] ? : ) : (evl[] < evl[] ? : );
}
#else
{
CvMat _det = cvMat( , , CV_32F, det );
CvMat _evc = cvMat( , , CV_32F, evc );
CvMat _evl = cvMat( , , CV_32F, evl ); cvSVD( &_det, &_evl, &_evc, , CV_SVD_MODIFY_A+CV_SVD_U_T );
}
i = ;
#endif
v = &evc[i * ];
n = (float) sqrt( (double)v[] * v[] + (double)v[] * v[] + (double)v[] * v[] );
n = (float)MAX(n, eps);
line[] = v[] / n;
line[] = v[] / n;
line[] = v[] / n;
line[] = x0;
line[] = y0;
line[] = z0; return CV_NO_ERR;
}

icvFitLine3D_wods

参考文献:

OpenCV 学习(直线拟合)

[OpenCV]直线拟合的更多相关文章

  1. (原)opencv直线拟合fitLine

    转载请注明出处 http://www.cnblogs.com/darkknightzh/p/5486234.html 参考网址: http://blog.csdn.net/thefutureisour ...

  2. opencv: 线性拟合

    opencv提供了fitline函数用于直线拟合,原型为: C++: void fitLine(InputArray points, OutputArray line, int distType, d ...

  3. OpenCV2马拉松第25圈——直线拟合与RANSAC算法

    计算机视觉讨论群162501053 转载请注明:http://blog.csdn.net/abcd1992719g/article/details/28118095 收入囊中 最小二乘法(least ...

  4. opencv直线检测在c#、Android和ios下的实现方法

    opencv直线检测在c#.Android和ios下的实现方法 本文为作者原创,未经允许,不得转载 :原文由作者发表在博客园:http://www.cnblogs.com/panxiaochun/p/ ...

  5. 基于EM的多直线拟合

    作者:桂. 时间:2017-03-22  06:13:50 链接:http://www.cnblogs.com/xingshansi/p/6597796.html 声明:欢迎被转载,不过记得注明出处哦 ...

  6. 基于EM的多直线拟合实现及思考

    作者:桂. 时间:2017-03-22  06:13:50 链接:http://www.cnblogs.com/xingshansi/p/6597796.html 声明:欢迎被转载,不过记得注明出处哦 ...

  7. 2d-Lidar 点云多直线拟合算法

    具体步骤: EM+GMM(高斯模糊模型) 点云分割聚类算法的实现. 基于RANSAC单帧lidar数据直线拟合算法实现. 多帧lidar数据实时直线优化算法实现. 算法实现逻辑: Struct lin ...

  8. OpenCV 最小二乘拟合方法求取直线倾角

    工业相机拍摄的图像中,由于摄像质量的限制,图像中的直线经过处理后,会表现出比较严重的锯齿.在这种情况下求取直线的倾角(其实就是直线的斜率),如果是直接选取直线的开始点和结束点来计算,或是用opencv ...

  9. OpenCV:直线拟合——cv::fitLine()详解

    实现目的:有一系列的点,需要拟合出一条直线. cv::fitLine()的具体调用形式如下: void cv::fitLine( cv::InputArray points, // 二维点的数组或ve ...

随机推荐

  1. atitit r9 doc on home ntpc .docx

    卷 p2soft 的文件夹 PATH 列表 卷序列号为 9AD0-D3C8 D:. │  Aittit pato 面对拒绝  的回应.docx │  Atitit  中国明星数量统计 attilax. ...

  2. pandas Series的sort_values()方法

    pandas Series的 sort_values() 方法能对Series进行排序,返回一个新的Series: s = pd.Series([np.nan, 1, 3, 10, 5]) 升序排列: ...

  3. Asp.Net WebApi接口返回值IHttpActionResult

    WebApi是微软在VS2012 MVC4版本中绑定发行的,webapi2.0同mvc5发行的 webapi一共有以下接口返回值 1.void无返回值2.IHttpActionResult Json( ...

  4. 搭建hbase1.2.5完全分布式集群

    简介 有一段时间,没写博客了,因为公司开发分布式调用链追踪系统,用到hbase,在这里记录一下搭建过程 1.集群如下: ip 主机名 角色 192.168.6.130 node1.jacky.com ...

  5. HAWQ集成Yarn HA作为资源管理服务

    一.第一步当然是配置YARN HA,这在使用ambari管理时很简单,这里不在赘述. 二.建立HAWQ的专用资源队列queue 不要手工编辑scheduler设置,最方便的当然是使用queue man ...

  6. 卸载ie

    今天卸载ie11失败,最后使用下面这个命令实现了卸载,记录下 IE11卸载命令如下: FORFILES /P %WINDIR%\servicing\Packages /M Microsoft-Wind ...

  7. [学习笔记]nodejs全局安装和本地安装的区别

    参考来源于 nodejs全局安装和本地安装的区别 1.全局安装 $ npm install gulp --global 2.作为项目的开发一开(devDependencies)安装 $ npm ins ...

  8. 新Windows本地提权漏洞学习(CVE-2019-0841)

    1.这是一个啥漏洞? 睁眼一看,妈呀本地提权,快加入本地提权漏洞利用包里,速度加入.github连接我就不发了.担心被认为是传播黑客工具,咱们在这里单纯学习一下漏洞的原理和部分源代码. 2.文件读写权 ...

  9. linux下tar命令的常用实例

    语法:tar [主选项+辅选项] 文件或者目录 使用该命令时,主选项是必须要有的,它告诉tar要做什么事情,辅选项是辅助使用的,可以选用. 主选项:c 创建新的档案文件.如果用户想备份一个目录或是一些 ...

  10. shell for循环 多个变量

    需求:需要输出以下2开头的端口号和其对应的文件 like: port and port_k8s_xxx.conf 其脚本为: #! /bash/shell #以value_name=(value1 v ...