简介:
RANSAC的流程是:
1.随机取一组点model_points,求解出模型方程;model_points为求取模型的最小点数;
2.计算满足该模型方程的点数占总点数的比例(即内点占比);
3.若内点占比满足一定阈值,或者当前迭代次数大于最大值,则停止迭代;
4.若当前内点占比大于当前统计得到的最大内点占比,则根据内点占比更新最大迭代次数;
5.继续迭代;
那么最大迭代次数是如何更新的?
首先,RANSAC的目的是找出内点占比最大的模型;
假设当前统计的最大内点占比是(1-ep),也就是对应的外点占比是ep;对应的模型是model S
我们并不确定当前的最大内点占比是否就是实际内点占比最大的模型;假设实际内点占比最大的模型是model Max;我们假设Model S和Model Max不是同一个模型,计算当求取出S的时候,我们离求取出Max还需要多少次迭代;首先Max的内点占比肯定要大于S,那么找出Max模型的迭代次数肯定小于S;所以我们先以S的内点占比为基准计算出找出model S所需要的迭代次数是多少;
仅根据现有信息我们知道:
对于单次迭代,找出modelS的概率是
(
1
−
e
p
)
m
o
d
e
l
p
o
i
n
t
s
(1-ep)^{modelpoints}
(1−ep)modelpoints
那么找到除S以外其他模型的概率是
1
−
(
1
−
e
p
)
m
o
d
e
l
p
o
i
n
t
s
1-(1-ep)^{modelpoints}
1−(1−ep)modelpoints
iters次迭代每次都找到除S以外其他模型的概率是
(
1
−
(
1
−
e
p
)
m
o
d
e
l
p
o
i
n
t
s
)
i
t
e
r
{(1-(1-ep)^{modelpoints})}^{iter}
(1−(1−ep)modelpoints)iter
iters次迭代只要有一次及一次以上都找到过S模型的概率是
1
−
(
1
−
(
1
−
e
p
)
m
o
d
e
l
p
o
i
n
t
s
)
i
t
e
r
1-{(1-(1-ep)^{modelpoints})}^{iter}
1−(1−(1−ep)modelpoints)iter
然后我们希望这个概率大于一定的置信度p,则可以得到:
1
−
(
1
−
(
1
−
e
p
)
m
o
d
e
l
p
o
i
n
t
s
)
i
t
e
r
>
=
p
1-{(1-(1-ep)^{modelpoints})}^{iter}>=p
1−(1−(1−ep)modelpoints)iter>=p
将以上公式进行化简得到:
i
t
e
r
>
=
(
l
o
g
(
1
−
p
)
/
l
o
g
(
1
−
(
1
−
e
p
)
m
o
d
e
l
p
o
i
n
t
s
)
)
iter>=(log(1-p)/log(1-(1-ep)^{modelpoints}))
iter>=(log(1−p)/log(1−(1−ep)modelpoints))
其对应的代码如下图所示:
RANSAC更新迭代次数源码:
CV_IMPL int
cvRANSACUpdateNumIters( double p, double ep,
int model_points, int max_iters )
{//p--置信度,ep---外点占比,model_points---模型点数 max_iers--迭代次数
if( model_points <= 0 )
CV_Error( CV_StsOutOfRange, "the number of model points should be positive" );
p = MAX(p, 0.);
p = MIN(p, 1.);
ep = MAX(ep, 0.);
ep = MIN(ep, 1.);
// avoid inf's & nan's
double num = MAX(1. - p, DBL_MIN);
double denom = 1. - pow(1. - ep,model_points);
if( denom < DBL_MIN )
return 0;
num = log(num);
denom = log(denom);
return denom >= 0 || -num >= max_iters*(-denom) ?
max_iters : cvRound(num/denom);
}
整个RANSAC流程的整体代码如下图所示:
bool CvModelEstimator2::runRANSAC( const CvMat* m1, const CvMat* m2, CvMat* model,
CvMat* mask0, double reprojThreshold,
double confidence, int maxIters )
{
bool result = false;
cv::Ptr<CvMat> mask = cvCloneMat(mask0);
cv::Ptr<CvMat> models, err, tmask;
cv::Ptr<CvMat> ms1, ms2;
int iter, niters = maxIters;
//count --图像总点数,总的候选点数
int count = m1->rows*m1->cols, maxGoodCount = 0;
CV_Assert( CV_ARE_SIZES_EQ(m1, m2) && CV_ARE_SIZES_EQ(m1, mask) );
if( count < modelPoints )
return false;
models = cvCreateMat( modelSize.height*maxBasicSolutions, modelSize.width, CV_64FC1 );
err = cvCreateMat( 1, count, CV_32FC1 );
tmask = cvCreateMat( 1, count, CV_8UC1 );
if( count > modelPoints )
{
ms1 = cvCreateMat( 1, modelPoints, m1->type );
ms2 = cvCreateMat( 1, modelPoints, m2->type );
}
else
{
niters = 1;
ms1 = cvCloneMat(m1);
ms2 = cvCloneMat(m2);
}
for( iter = 0; iter < niters; iter++ )
{
int i, goodCount, nmodels;
if( count > modelPoints )
{
bool found = getSubset( m1, m2, ms1, ms2, 300 );
if( !found )
{
if( iter == 0 )
return false;
break;
}
}
nmodels = runKernel( ms1, ms2, models );
if( nmodels <= 0 )
continue;
for( i = 0; i < nmodels; i++ )
{
CvMat model_i;
cvGetRows( models, &model_i, i*modelSize.height, (i+1)*modelSize.height );
goodCount = findInliers( m1, m2, &model_i, err, tmask, reprojThreshold );
if( goodCount > MAX(maxGoodCount, modelPoints-1) )
{//每次找到更优的模型的时候都需要更新迭代次数
std::swap(tmask, mask);
cvCopy( &model_i, model );
maxGoodCount = goodCount;
niters = cvRANSACUpdateNumIters( confidence,
(double)(count - goodCount)/count, modelPoints, niters );
}
}
}
if( maxGoodCount > 0 )
{
if( mask != mask0 )
cvCopy( mask, mask0 );
result = true;
}
return result;
}