00001
00015 #ifndef DLR_COMPUTERVISION_RANSAC_H
00016 #define DLR_COMPUTERVISION_RANSAC_H
00017
00018 #include <vector>
00019 #include <dlrComputerVision/randomSampleSelector.h>
00020
00021 namespace dlr {
00022
00023 namespace computerVision {
00024
00031 enum RansacInlierStrategy {
00032 DLR_CV_NAIVE_ERROR_THRESHOLD
00033 };
00034
00035
00051 template <class Problem>
00052 class Ransac {
00053 public:
00054
00058 typedef Problem ProblemType;
00059
00060
00066 typedef typename Problem::ModelType ResultType;
00067
00068
00100 Ransac(ProblemType const& problem,
00101 size_t minimumConsensusSize = 0,
00102 double requiredConfidence = 0.99,
00103 double inlierProbability = 0.5);
00104
00105
00109 virtual
00110 ~Ransac() {}
00111
00112
00120 virtual ResultType
00121 getResult() {
00122
00123 ResultType result;
00124 this->estimate(result);
00125 return result;
00126 }
00127
00128
00129 protected:
00130
00131 void
00132 computeConsensusSet(ResultType& model, std::vector<bool>& consensusFlags);
00133
00134 bool
00135 estimate(ResultType& model);
00136
00137 bool
00138 isConverged(std::vector<bool> const& consensusFlags,
00139 std::vector<bool>& previousConsensusFlags,
00140 size_t& consensusSetSize,
00141 size_t& previousConsensusSetSize,
00142 size_t& strikes);
00143
00144
00145 size_t m_minimumConsensusSize;
00146 size_t m_numberOfRandomSampleSets;
00147 ProblemType m_problem;
00148 };
00149
00150
00171 template <class Sample, class Model>
00172 class RansacProblem
00173 : public RandomSampleSelector<Sample>
00174 {
00175 public:
00176
00177
00178
00179
00180
00185 typedef Model ModelType;
00186
00187
00192 typedef Sample SampleType;
00193
00194
00221 typedef typename RandomSampleSelector<SampleType>::SampleSequenceType
00222 SampleSequenceType;
00223
00224
00225
00226
00227
00242 virtual ModelType
00243 estimateModel(SampleSequenceType const& sampleSequence) = 0;
00244
00245
00264 template <class IterType>
00265 void
00266 computeError(ModelType const& model,
00267 SampleSequenceType const& sampleSequence,
00268 IterType ouputIter) {};
00269
00270
00286 virtual double
00287 getNaiveErrorThreshold() = 0;
00288
00289
00290
00291
00292
00293
00312 template <class IterType>
00313 RansacProblem(size_t sampleSize, IterType beginIter, IterType endIter)
00314 : RandomSampleSelector<SampleType>(beginIter, endIter),
00315 m_sampleSize(sampleSize) {}
00316
00317
00321 virtual
00322 ~RansacProblem() {}
00323
00324
00334 virtual size_t
00335 getSampleSize() {return m_sampleSize;}
00336
00337
00345 RansacInlierStrategy
00346 getInlierStrategy() {
00347 return DLR_CV_NAIVE_ERROR_THRESHOLD;
00348 }
00349
00350 protected:
00351
00352 size_t m_sampleSize;
00353
00354 };
00355
00356 }
00357
00358 }
00359
00360
00361
00362
00363
00364
00365 #include <cmath>
00366 #include <algorithm>
00367 #include <functional>
00368 #include <dlrCommon/exception.h>
00369 #include <dlrNumeric/maxRecorder.h>
00370
00371 namespace dlr {
00372
00373 namespace computerVision {
00374
00375
00376 template <class Problem>
00377 Ransac<Problem>::
00378 Ransac(Problem const& problem,
00379 size_t minimumConsensusSize,
00380 double requiredConfidence,
00381 double inlierProbability)
00382 : m_minimumConsensusSize(minimumConsensusSize),
00383 m_numberOfRandomSampleSets(),
00384 m_problem(problem)
00385 {
00386 size_t sampleSize = m_problem.getSampleSize();
00387
00388
00389 double singlePickConfidence =
00390 std::pow(inlierProbability, static_cast<double>(sampleSize));
00391
00392
00393
00394 double singlePickDisconfidence = 1.0 - singlePickConfidence;
00395
00396
00397
00398
00399 m_numberOfRandomSampleSets =
00400 std::log(1.0 - requiredConfidence) / std::log(singlePickDisconfidence);
00401
00402 if(m_minimumConsensusSize == 0) {
00403
00404
00405
00406
00407
00408
00409 int extraSamples = static_cast<int>(
00410 std::log(1.0 - requiredConfidence) / std::log(0.5) + 0.5);
00411 if(extraSamples < 0) {
00412 extraSamples = 0;
00413 }
00414 m_minimumConsensusSize = sampleSize + extraSamples;
00415 }
00416
00417 }
00418
00419
00420 template <class Problem>
00421 void
00422 Ransac<Problem>::
00423 computeConsensusSet(typename Ransac<Problem>::ResultType& model,
00424 std::vector<bool>& consensusFlags)
00425 {
00426 if(m_problem.getInlierStrategy() != DLR_CV_NAIVE_ERROR_THRESHOLD) {
00427 DLR_THROW(NotImplementedException, "Ransac::computeConsensusSet()",
00428 "Currently only naive error thresholding is supported.");
00429 }
00430 if(consensusFlags.size() != m_problem.getPoolSize()) {
00431 consensusFlags.resize(m_problem.getPoolSize());
00432 }
00433
00434
00435 typename Problem::SampleSequenceType testSet = m_problem.getPool();
00436 std::vector<double> errorMetrics(m_problem.getPoolSize());
00437 m_problem.computeError(model, testSet, errorMetrics.begin());
00438
00439
00440 double threshold = m_problem.getNaiveErrorThreshold();
00441 std::transform(
00442 errorMetrics.begin(), errorMetrics.end(), consensusFlags.begin(),
00443 std::bind2nd(std::less<double>(), threshold));
00444 }
00445
00446
00447 template <class Problem>
00448 bool
00449 Ransac<Problem>::
00450 estimate(typename Ransac<Problem>::ResultType& model)
00451 {
00452 dlr::numeric::MaxRecorder<size_t, ResultType> maxRecorder;
00453 for(size_t iteration = 0; iteration < m_numberOfRandomSampleSets;
00454 ++iteration) {
00455
00456
00457 typename ProblemType::SampleSequenceType trialSet =
00458 m_problem.getRandomSample(m_problem.getSampleSize());
00459
00460 std::vector<bool> consensusFlags(m_problem.getPoolSize());
00461 std::vector<bool> previousConsensusFlags(m_problem.getPoolSize(),
00462 false);
00463 size_t consensusSetSize = 0;
00464 size_t previousConsensusSetSize = 0;
00465 size_t strikes = 0;
00466 while(1) {
00467
00468 model = m_problem.estimateModel(trialSet);
00469
00470
00471
00472 this->computeConsensusSet(model, consensusFlags);
00473
00474
00475 if(this->isConverged(consensusFlags, previousConsensusFlags,
00476 consensusSetSize, previousConsensusSetSize,
00477 strikes)) {
00478 break;
00479 }
00480
00481
00482
00483 trialSet = m_problem.getSubset(
00484 consensusFlags.begin(), consensusFlags.end());
00485 }
00486
00487
00488
00489 if(consensusSetSize > m_minimumConsensusSize) {
00490
00491 return true;
00492 }
00493
00494
00495
00496 maxRecorder.test(consensusSetSize, model);
00497 }
00498
00499
00500
00501
00502 model = maxRecorder.getPayload();
00503 return false;
00504 }
00505
00506
00507 template <class Problem>
00508 bool
00509 Ransac<Problem>::
00510 isConverged(std::vector<bool> const& consensusFlags,
00511 std::vector<bool>& previousConsensusFlags,
00512 size_t& consensusSetSize,
00513 size_t& previousConsensusSetSize,
00514 size_t& strikes)
00515 {
00516
00517
00518 consensusSetSize = std::count(
00519 consensusFlags.begin(), consensusFlags.end(), true);
00520 if(consensusSetSize < m_problem.getSampleSize()) {
00521
00522
00523
00524 return true;
00525 }
00526
00527
00528
00529 if(consensusFlags.size() == previousConsensusFlags.size()) {
00530
00531
00532
00533 if(consensusSetSize <= previousConsensusSetSize) {
00534 ++strikes;
00535 }
00536 if(strikes > 10) {
00537 return true;
00538 }
00539
00540
00541
00542 if(std::equal(consensusFlags.begin(), consensusFlags.end(),
00543 previousConsensusFlags.begin())) {
00544 return true;
00545 }
00546 }
00547
00548
00549
00550 previousConsensusFlags = consensusFlags;
00551 previousConsensusSetSize = consensusSetSize;
00552
00553 return false;
00554 }
00555
00556 }
00557
00558 }
00559
00560 #endif