直线拟合(Ransac+Opencv)
直线拟合(Ransac+Opencv)
Ransac原理
Ransac直线拟合原理(待补充)
OpenCV Error: Assertion failed (npoints2 >= 0 || npoints3 >= 0) in fitLine
原因
代码错误表明问题出现在fitLine(),下⾯是Opencv提供的源码 void cv::fitLine( InputArray _points, OutputArray _line, int distType, double param, double reps, double aeps )
{
CV_INSTRUMENT_REGION();
Mat points = _Mat();
float linebuf[6]={0.f};
int npoints2 = points.checkVector(2, -1, false);
int npoints3 = points.checkVector(3, -1, false);
CV_Assert( npoints2 >= 0 || npoints3 >= 0 );
if( points.depth() != CV_32F || !points.isContinuous() )
{
Mat temp;
points = temp;
}
if( npoints2 >= 0 )
fitLine2D( points.ptr<Point2f>(), npoints2, distType,
(float)param, (float)reps, (float)aeps, linebuf);
else
fitLine3D( points.ptr<Point3f>(), npoints3, distType,
(float)param, (float)reps, (float)aeps, linebuf);
Mat(npoints2 >= 0 ? 4 : 6, 1, CV_32F, linebuf).copyTo(_line);
}
可以发现错误提⽰来⾃CV_Assert(npoints2 >= 0 || npoints3 >= 0)
研究函数 checkVector() 的定义
int cv::Mat::checkVector
( int elemChannels,
int depth = -1,
bool requireContinuous = true
)const
调⽤checkVector() 的矩阵,我的理解是⽤checkVector() 来检查矩阵的通道数和连续性,⽆误时可以返回矩阵的维数,⼆维Mat返回2,三维Mat返回3,否则返回-1
再看⼀下矩阵points是由以下代码⽣成的
Mat points = _Mat();
由此可以判断出我代码中出现问题的部分是 进⼊fitLIine()时_points传参的时候出现了问题
进⽽检查代码(如下)
detectangle_step = 4;
detectangle_width = 30;
for (int i = 0 ; i < 1080/detectangle_step; i++){
std::vector<Point2d>::const_iterator first1 = ptSet_original.begin() + i*detectangle_step;
拟合直线std::vector<Point2d>::const_iterator last1 = ptSet_original.begin() + i*detectangle_step + detectangle_width;
std::vector<Point2d> ptSet(first1, last1);
fitLineRANSAC(ptSet, A, B, C, inliers);
...(省略)
}
产⽣问题的是遍历器数据出现了越界情况
在代码中,ptSet⼀共只有1080个数据,⽽最开始的代码版本由于编写的问题,i最⼤可能出现超过1080的情况正是由于这个原因,导致代码在运⾏初始和运⾏阶段,必然由于遍历器超过数据实际长度
引发assert
解决⽅案
更改代码为
detectangle_step = 4;
detectangle_width = 30;
for (int i = 0 ; i < (1080 - detectangle_width)/detectangle_step; i++){
std::vector<Point2d>::const_iterator first1 = ptSet_original.begin() + i*detectangle_step;
std::vector<Point2d>::const_iterator last1 = ptSet_original.begin() + i*detectangle_step + detectangle_width;
std::vector<Point2d> ptSet(first1, last1);
fitLineRANSAC(ptSet, A, B, C, inliers);
...(省略)
}
成功!不再报错了