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. [C++]Qt程式异常崩溃处理技巧(Win)

    文章转载来自     http://www.cnblogs.com/lcchuguo/p/5177715.html     作者 lcchuguo https://blog.csdn.net/baid ...

  2. 基于jQuery 3D旋转明星人物展示特效

    分享一款基于jQuery 3D旋转明星人物展示特效.这是一款来自百度换肤活动的明星旋转展示效果.效果图如下: 在线预览   源码下载 实现的代码. html代码: <div class=&quo ...

  3. windows安装centos7子系统

    Windows的Linux子系统(wsl ) 自从有了wsl后,基本上虚拟机都省了,对于离不开Windows的便捷,Linux对开发的友好的人来说,真是一大利器.可惜默认的系统没有centos,幸运的 ...

  4. js this 引起的祸

    注意:这里的 this 指向已经改变了. 所以不能再次使用 this 需在上面自定义变量. 那些年踩过的坑,记录一下.

  5. Centos7.0下Nexus私服搭建

    1.下载nexus wget https://sonatype-download.global.ssl.fastly.net/nexus/oss/nexus-2.11.2-03-bundle.tar. ...

  6. The client and server cannot communicate, because they do not possess a common algorithm

    The client and server cannot communicate, because they do not possess a common algorithm This was re ...

  7. 2单一职责原则SRP

    一.什么是单一职责原则 单一职责原则(Single Responsibility Principle ): 就一个类而言,应该仅有一个引起它变化的 原因. 二.多功能的山寨手机 山寨手机的功能: 拍照 ...

  8. react项目使用bootstrap

    曾经对于react项目怎么使用bootstrap纠结了很久,网上也查了好多的资料,有的用react-bootstrap,只要npm install 以后,import就可以使用里面的css了.但是这个 ...

  9. MSF实现RID劫持和MSF实现PsExec执行命令

    msf实现rid劫持 rid劫持原理: 每个帐户都有一个指定的RID来标识它.与域控制器不同,Windows工作站和服务器会将大部分数据存储在HKLM\SAM\SAM\Domains\Account\ ...

  10. xcode8 iOS函数返回值使用警告

    没有使用返回值时, 警告 swift: @warn_unused_result func doSomething() -> Bool { return true } OC: - (BOOL)do ...