直线拟合(Ransac+Opencv)
Ransac原理
Ransac直线拟合原理(待补充)
代码
出现的Bug
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 = _points.getMat();
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.convertTo(temp, CV_32F);
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 = _points.getMat();
由此可以判断出我代码中出现问题的部分是 进入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);
...(省略)
}
成功!不再报错了