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. Android Studio系列-签名打包

    本篇博客纪录使用Android Studio对项目进行签名打包,跟Eclipse大同小异,读者朋友注意其中到差别. 第一步 创建签名文件 第二步 填写签名参数 第三步 选择构建类型 第四步 查看生成第 ...

  2. .NET Core 2.1 IIS 部署 出现500.19 错误

    HTTP 错误 500.19 - Internal Server Error 无法访问请求的页面,因为该页的相关配置数据无效. 最后发现是由于项目从 .NET Core 1.0 升级到 .NET Co ...

  3. URLSearchParams和axios的post请求(防忘记)

    import axios from 'axios' Vue.prototype.axios = axios mounted () { let params = new URLSearchParams( ...

  4. JavaScript学习历程03

    一闪一闪亮晶晶 <script type="text/javascript"> var nn = Number(prompt('请输入一个1-9的正整数!')); va ...

  5. 使用Spring Cloud Feign作为HTTP客户端调用远程HTTP服务

    在Spring Cloud Netflix栈中,各个微服务都是以HTTP接口的形式暴露自身服务的,因此在调用远程服务时就必须使用HTTP客户端.我们可以使用JDK原生的URLConnection.Ap ...

  6. hibernate中的addEntity setResultTransformer的比较

    如果使用原生sql语句进行query查询时,hibernate是不会自动把结果包装成实体的.所以要手动调用addEntity(Class class)等一系列方法. 如session.createSQ ...

  7. 【转】app之YdbOnline说明文档

    概述 YdbOnline是面向网页开发者提供的网页开发工具包. 通过使用YdbOnline,网页开发者可借助YdbOnline高效地使用语音.位置等手机系统的能力,同时可以直接使用清除缓存.扫一扫等A ...

  8. 微信小程序中同步 异步的使用

    https://www.jianshu.com/p/e92c7495da76   微信小程序中使用Promise进行异步流程处理 https://www.cnblogs.com/cckui/p/102 ...

  9. [Golang] kafka集群搭建和golang版生产者和消费者

    一.kafka集群搭建 至于kafka是什么我都不多做介绍了,网上写的已经非常详尽了. 1. 下载zookeeper  https://zookeeper.apache.org/releases.ht ...

  10. nw.js---开发一个百度浏览器

    使用nw.js开发一个简单的百度浏览器就很简单了,只需要在配置里面写入: { // "main": "index.html", "main" ...