打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Ransac
随机一致性采样RANSAC是一种鲁棒的模型拟合算法,能够从有外点的数据中拟合准确的模型。
RANSAC过程中用到的参数
N-- 拟合模型所需要的最少的样本个数
K--算法的迭代次数
t--用于判断数据是否是内点
d--判定模型是否符合使用于数据集,也就是判断是否是好的模型
RANSAC算法过程
1  for K 次迭代
2     从数据中均匀随机采样N个点
3     利用采样的N个点拟合你个模型
4     for 对于除采样点外的每一个样本点
5          利用t检测样本点到模型的距离,如果小于t则认为是一致,否则认为是外点
6     end
7     如果有d或者更多的一致点,则认为拟合的模型是好的
8 end
9 使用拟合误差作为标准,选择最好的拟合模型
迭代次数的计算
假设 r = 内点个数/所有点的个数
则:
p0 = pow(r, N) 表示采样的N个点全为内点,也就是是一次有效采样的概率
p1 = 1 - pow(r, N) 表示采样的N个点中至少有一个外点,即一次无效采样的概率
p2 = pow(p1, K) 表示K次无效采样的概率
假设p表示K次采样中至少一次采样是有效采样,则有1-p = pow(p1, K), 两边取对数
则有 K = log(1- p )/log(1-p1).
附一份来自google 的RANSAC的代码框架
[cpp] view plain copy
#ifndef FVISION_RANSAC_H_
#define FVISION_RANSAC_H_
#include <fvision/utils/random_utils.h>
#include <fvision/utils/misc.h>
#include <vector>
#include <iostream>
#include <cassert>
namespace fvision {
class RANSAC_SamplesNumber {
public:
RANSAC_SamplesNumber(int modelSampleSize) {
this->s = modelSampleSize;
this->p = 0.99;
}
~RANSAC_SamplesNumber(void) {}
public:
long calcN(int inliersNumber, int samplesNumber) {
double e = 1 - (double)inliersNumber / samplesNumber;
//cout<<"e: "<<e<<endl;
if (e > 0.9) e = 0.9;
//cout<<"pow: "<<pow((1 - e), s)<<endl;
//cout<<log(1 - pow((1 - e), s))<<endl;
long N = (long)(log(1 - p) / log(1 - pow((1 - e), s)));
if (N < 0) return (long)1000000000;
else return N;
}
private:
int s;      //samples size for fitting a model
double p;   //probability that at least one of the random samples if free from outliers
//usually 0.99
};
//fit a model to a set of samples
template <typename M, typename S>
class GenericModelCalculator {
public:
typedef std::vector<S> Samples;
virtual M compute(const Samples& samples) = 0;
virtual ~GenericModelCalculator<M, S>() {}
//the model calculator may only use a subset of the samples for computing
//default return empty for both
virtual const std::vector<int>& getInlierIndices() const { return defaultInlierIndices; };
virtual const std::vector<int>& getOutlierIndices() const { return defaultOutlierIndices; };
// if the subclass has a threshold parameter, it need to override the following three functions
// this is used for algorithms which have a normalization step on input samples
virtual bool hasThreshold() const { return false; }
virtual void setThreshold(double threshold) {}
virtual double getThreshold() const { return 0; }
protected:
std::vector<int> defaultInlierIndices;
std::vector<int> defaultOutlierIndices;
};
//evaluate a model to samples
//using a threshold to distinguish inliers and outliers
template <typename M, typename S>
class GenericErrorCaclculator {
public:
virtual ~GenericErrorCaclculator<M, S>() {}
typedef std::vector<S> Samples;
virtual double compute(const M& model, const S& sample) const = 0;
double computeAverage(const M& model, const Samples& samples) const {
int n = (int)samples.size();
if (n == 0) return 0;
double sum = 0;
for (int i = 0; i < n; i++) {
sum += compute(model, samples[i]);
}
return sum / n;
}
double computeInlierAverage(const M& model, const Samples& samples) const {
int n = (int)samples.size();
if (n == 0) return 0;
double sum = 0;
double error = 0;
int inlierNum = 0;
for (int i = 0; i < n; i++) {
error = compute(model, samples[i]);
if (error <= threshold) {
sum += error;
inlierNum++;
}
}
if (inlierNum == 0) return 1000000;
return sum / inlierNum;
}
public:
/** set a threshold for classify inliers and outliers
*/
void setThreshold(double v) { threshold = v; }
double getThreshold() const { return threshold; }
/** classify all samples to inliers and outliers
*
*/
void classify(const M& model, const Samples& samples, Samples& inliers, Samples& outliers) const {
inliers.clear();
outliers.clear();
Samples::const_iterator iter = samples.begin();
for (; iter != samples.end(); ++iter) {
if (isInlier(model, *iter)) inliers.push_back(*iter);
else outliers.push_back(*iter);
}
}
/** classify all samples to inliers and outliers, output indices
*
*/
void classify(const M& model, const Samples& samples, std::vector<int>& inlierIndices, std::vector<int>& outlierIndices) const {
inlierIndices.clear();
outlierIndices.clear();
Samples::const_iterator iter = samples.begin();
int i = 0;
for (; iter != samples.end(); ++iter, ++i) {
if (isInlier(model, *iter)) inlierIndices.push_back(i);
else outlierIndices.push_back(i);
}
}
/** classify all samples to inliers and outliers
*
*/
void classify(const M& model, const Samples& samples,
std::vector<int>& inlierIndices, std::vector<int>& outlierIndices,
Samples& inliers, Samples& outliers) const {
inliers.clear();
outliers.clear();
inlierIndices.clear();
outlierIndices.clear();
Samples::const_iterator iter = samples.begin();
int i = 0;
for (; iter != samples.end(); ++iter, ++i) {
if (isInlier(model, *iter)) {
inliers.push_back(*iter);
inlierIndices.push_back(i);
}
else {
outliers.push_back(*iter);
outlierIndices.push_back(i);
}
}
}
int calcInliersNumber(const M& model, const Samples& samples) const {
int n = 0;
for (int i = 0; i < (int)samples.size(); i++) {
if (isInlier(model, samples[i])) ++n;
}
return n;
}
bool isInlier(const M& model, const S& sample) const {
return (compute(model, sample) <= threshold);
}
private:
double threshold;
};
/** generic RANSAC framework
* make use of a model calculator and an error calculator
* M is the model type, need to support copy assignment operator and default constructor
* S is the sample type.
*
* Interface:
*  M compute(samples); input a set of samples, output a model.
*  after compute, inliers and outliers can be retrieved
*
*/
template <typename M, typename S>
class Ransac : public GenericModelCalculator<M, S> {
public:
typedef std::vector<S> Samples;
/** Constructor
*
* @param pmc a GenericModelCalculator object
* @param modelSampleSize how much samples are used to fit a model
* @param pec a GenericErrorCaclculator object
*/
Ransac(GenericModelCalculator<M, S>* pmc, int modelSampleSize, GenericErrorCaclculator<M, S>* pec) {
this->pmc = pmc;
this->modelSampleSize = modelSampleSize;
this->pec = pec;
this->maxSampleCount = 500;
this->minInliersNum = 1000000;
this->verbose = false;
}
const GenericErrorCaclculator<M, S>* getErrorCalculator() const { return pec; }
virtual ~Ransac() {
delete pmc;
delete pec;
}
void setMaxSampleCount(int n) {
this->maxSampleCount = n;
}
void setMinInliersNum(int n) {
this->minInliersNum = n;
}
virtual bool hasThreshold() const { return true; }
virtual void setThreshold(double threshold) {
pec->setThreshold(threshold);
}
virtual double getThreshold() const {
return pec->getThreshold();
}
public:
/** Given samples, compute a model that has most inliers. Assume the samples size is larger or equal than model sample size
* inliers, outliers, inlierIndices and outlierIndices are stored
*
*/
M compute(const Samples& samples) {
clear();
int pointsNumber = (int)samples.size();
assert(pointsNumber >= modelSampleSize);
long N = 100000;
int sampleCount = 0;
RANSAC_SamplesNumber ransac(modelSampleSize);
M bestModel;
int maxInliersNumber = 0;
bool stop = false;
while (sampleCount < N && sampleCount < maxSampleCount && !stop) {
Samples nsamples;
randomlySampleN(samples, nsamples, modelSampleSize);
M sampleModel = pmc->compute(nsamples);
if (maxInliersNumber == 0) bestModel = sampleModel;  //init bestModel
int inliersNumber = pec->calcInliersNumber(sampleModel, samples);
if (verbose) std::cout<<"inliers number: "<<inliersNumber<<std::endl;
if (inliersNumber > maxInliersNumber) {
bestModel = sampleModel;
maxInliersNumber = inliersNumber;
N = ransac.calcN(inliersNumber, pointsNumber);
if (maxInliersNumber > minInliersNum) stop = true;
}
if (verbose) std::cout<<"N: "<<N<<std::endl;
sampleCount ++;
}
if (verbose) std::cout<<"sampleCount: "<<sampleCount<<std::endl;
finalModel = computeUntilConverge(bestModel, maxInliersNumber, samples);
pec->classify(finalModel, samples, inlierIndices, outlierIndices, inliers, outliers);
inliersRate = (double)inliers.size() / samples.size();
return finalModel;
}
const Samples& getInliers() const { return inliers; }
const Samples& getOutliers() const { return outliers; }
const std::vector<int>& getInlierIndices() const { return inlierIndices; }
const std::vector<int>& getOutlierIndices() const { return outlierIndices; }
double getInliersAverageError() const {
return pec->computeAverage(finalModel, inliers);
}
double getInliersRate() const {
return inliersRate;
}
void setVerbose(bool v) {
verbose = v;
}
private:
void randomlySampleN(const Samples& samples, Samples& nsamples, int sampleSize) {
std::vector<int> is = ranis((int)samples.size(), sampleSize);
for (int i = 0; i < sampleSize; i++) {
nsamples.push_back(samples[is[i]]);
}
}
/** from initial model, iterate to find the best model.
*
*/
M computeUntilConverge(M initModel, int initInliersNum, const Samples& samples) {
if (verbose) {
std::cout<<"iterate until converge...."<<std::endl;
std::cout<<"init inliers number: "<<initInliersNum<<std::endl;
}
M bestModel = initModel;
M newModel = initModel;
int lastInliersNum = initInliersNum;
Samples newInliers, newOutliers;
pec->classify(initModel, samples, newInliers, newOutliers);
double lastInlierAverageError = pec->computeAverage(initModel, newInliers);
if (verbose) std::cout<<"init inlier average error: "<<lastInlierAverageError<<std::endl;
while (true && (int)newInliers.size() >= modelSampleSize) {
//update new model with new inliers, the new model does not necessarily have more inliers
newModel = pmc->compute(newInliers);
pec->classify(newModel, samples, newInliers, newOutliers);
int newInliersNum = (int)newInliers.size();
double newInlierAverageError = pec->computeAverage(newModel, newInliers);
if (verbose) {
std::cout<<"new inliers number: "<<newInliersNum<<std::endl;
std::cout<<"new inlier average error: "<<newInlierAverageError<<std::endl;
}
if (newInliersNum < lastInliersNum) break;
if (newInliersNum == lastInliersNum && newInlierAverageError >= lastInlierAverageError) break;
//update best model with the model has more inliers
bestModel = newModel;
lastInliersNum = newInliersNum;
lastInlierAverageError = newInlierAverageError;
}
return bestModel;
}
void clear() {
inliers.clear();
outliers.clear();
inlierIndices.clear();
outlierIndices.clear();
}
private:
GenericModelCalculator<M, S>* pmc;
GenericErrorCaclculator<M, S>* pec;
int modelSampleSize;
int maxSampleCount;
int minInliersNum;
M finalModel;
Samples inliers;
Samples outliers;
std::vector<int> inlierIndices;
std::vector<int> outlierIndices;
double inliersRate;
private:
bool verbose;
};
}
#endif // FVISION_RANSAC_H_
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
(学习笔记)摄像机模型与标定——单应性
利用RANSAC算法稳健估计平面模型参数和圆柱模型参数
PCL采样一致性算法
自动驾驶:基于PCL的激光雷达感知
14.7 自增操作符和自减操作符
Linux netfilter源码分析
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服