[OpenCV]直线拟合
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直线拟合fitLine
转载请注明出处 http://www.cnblogs.com/darkknightzh/p/5486234.html 参考网址: http://blog.csdn.net/thefutureisour ...
- opencv: 线性拟合
opencv提供了fitline函数用于直线拟合,原型为: C++: void fitLine(InputArray points, OutputArray line, int distType, d ...
- OpenCV2马拉松第25圈——直线拟合与RANSAC算法
计算机视觉讨论群162501053 转载请注明:http://blog.csdn.net/abcd1992719g/article/details/28118095 收入囊中 最小二乘法(least ...
- opencv直线检测在c#、Android和ios下的实现方法
opencv直线检测在c#.Android和ios下的实现方法 本文为作者原创,未经允许,不得转载 :原文由作者发表在博客园:http://www.cnblogs.com/panxiaochun/p/ ...
- 基于EM的多直线拟合
作者:桂. 时间:2017-03-22 06:13:50 链接:http://www.cnblogs.com/xingshansi/p/6597796.html 声明:欢迎被转载,不过记得注明出处哦 ...
- 基于EM的多直线拟合实现及思考
作者:桂. 时间:2017-03-22 06:13:50 链接:http://www.cnblogs.com/xingshansi/p/6597796.html 声明:欢迎被转载,不过记得注明出处哦 ...
- 2d-Lidar 点云多直线拟合算法
具体步骤: EM+GMM(高斯模糊模型) 点云分割聚类算法的实现. 基于RANSAC单帧lidar数据直线拟合算法实现. 多帧lidar数据实时直线优化算法实现. 算法实现逻辑: Struct lin ...
- OpenCV 最小二乘拟合方法求取直线倾角
工业相机拍摄的图像中,由于摄像质量的限制,图像中的直线经过处理后,会表现出比较严重的锯齿.在这种情况下求取直线的倾角(其实就是直线的斜率),如果是直接选取直线的开始点和结束点来计算,或是用opencv ...
- OpenCV:直线拟合——cv::fitLine()详解
实现目的:有一系列的点,需要拟合出一条直线. cv::fitLine()的具体调用形式如下: void cv::fitLine( cv::InputArray points, // 二维点的数组或ve ...
随机推荐
- vim常用技巧
# vim常用技巧 ## 行操作------------------------------ 行首 0- 行尾 $- 第一个非空字符 ^ ## 列编辑模式----------------------- ...
- 关于VMware Linux 虚拟机忘记root 密码找回
因为昨天新安装过虚拟机设置了新的密码,再加上我好长时间没有用自己旧的虚拟机,导致忘记了密码,原来虽然知道在单用模式下,找回密码,但是确实是自己从来都没有做过,还好我们组大手飞翔哥告诉了我,怎么找回ro ...
- sql 时间转换格式 convert(varchar(10),字段名,转换格式)
convert(varchar(10),字段名,转换格式) CONVERT(nvarchar(10),count_time,121) CONVERT为日期转换函数,一般就是在时间类型(datetime ...
- 在Android中使用FFmpeg(android studio环境)
1.首先我们需要一个已经编译好的libffmpeg.so文件.(怎么编译是个大坑,可以参考windows环境下编译android中使用的FFmpeg,也可以用网上下载的现成的,本文相关的github项 ...
- c 时间转移函数
/* @param date @param formart of date @ ...
- [译] 理解 LSTM(Long Short-Term Memory, LSTM) 网络
本文译自 Christopher Olah 的博文 Recurrent Neural Networks 人类并不是每时每刻都从一片空白的大脑开始他们的思考.在你阅读这篇文章时候,你都是基于自己已经拥有 ...
- 卷积神经网络(Convolutional Neural Network, CNN)简析
目录 1 神经网络 2 卷积神经网络 2.1 局部感知 2.2 参数共享 2.3 多卷积核 2.4 Down-pooling 2.5 多层卷积 3 ImageNet-2010网络结构 4 DeepID ...
- win10 安装node.js node.js 安装成功但npm -v 报错问题解决
错误症状官网下载node-v8 .node-v10 的msi 安装进行安装. npm -v 错误如下 0 info it worked if it ends with ok 1 verbose cli ...
- linux配置 数据库主从同步
数据库的读写分离能很大程度上减轻数据库的压力,读写分离的前提就是主从数据同步,然后在主库做增删改,从库做查询. 例如: 主库:192.168.0.1 从库:192.168.0.2 两个数据库都安装了M ...
- Ubuntu命令行快捷启动Matlab
转载:https://blog.csdn.net/striker_v/article/details/52884485 Matlab R2015b默认安装目录/usr/local/MATLAB/R20 ...