00001 #ifndef TAG_RANSAC_H_
00002 #define TAG_RANSAC_H_
00003
00004 #include <vector>
00005 #include <algorithm>
00006
00007 namespace tag {
00008
00014
00015 template <class T> void randomTuple(const std::vector<T>& cdf, std::vector<unsigned int>& t, T maxp) {
00016 for (size_t i=0; i<t.size(); i++) {
00017 try_again:
00018 double x = drand48()* maxp;
00019 size_t r = std::min(cdf.size()-1, (size_t)(std::lower_bound(cdf.begin(), cdf.end(), (T)x) - cdf.begin()));
00020 for (size_t j=0; j<i; j++)
00021 if (r == t[j])
00022 goto try_again;
00023 t[i] = r;
00024 }
00025 }
00026
00027 template <class T> void randomTuple(T& t, unsigned int bound)
00028 {
00029 for (size_t i=0; i<t.size(); i++) {
00030 try_again:
00031 size_t r = (size_t)(drand48() * bound);
00032 for (size_t j=0; j<i; j++)
00033 if (r == t[j])
00034 goto try_again;
00035 t[i] = r;
00036 }
00037 }
00038
00039
00060
00061 template <class Obs, class Trans, class Tol> size_t find_RANSAC_inliers(const std::vector<Obs>& observations, int sample_size, const Tol& tolerance, size_t N,
00062 Trans& best, std::vector<bool>& inlier)
00063 {
00064 std::vector<bool> thisInlier(observations.size());
00065 size_t bestScore = 0;
00066 std::vector<size_t> sample_index(sample_size);
00067 std::vector<Obs> sample(sample_size);
00068 while (N--) {
00069 randomTuple(sample_index, observations.size());
00070 for (int i=0;i<sample_size; i++)
00071 sample[i] = observations[sample_index[i]];
00072 Trans thisT(best);
00073 thisT.estimate(sample.begin(), sample.end());
00074 size_t score = 0;
00075 for (size_t i=0; i<observations.size(); i++) {
00076 const Obs& o = observations[i];
00077 if (thisT.isInlier(o, tolerance)) {
00078 thisInlier[i] = true;
00079 score++;
00080 } else
00081 thisInlier[i] = false;
00082 }
00083 if (score > bestScore) {
00084 bestScore = score;
00085 inlier = thisInlier;
00086 best = thisT;
00087 }
00088 }
00089 return bestScore;
00090 }
00091
00112 template <class Obs, class Trans, class Tol> double find_MSAC_inliers(const std::vector<Obs>& observations, int sample_size, const Tol& tolerance, size_t N,
00113 Trans& best, std::vector<bool>& inlier)
00114 {
00115 std::vector<bool> thisInlier(observations.size());
00116 const double toleranceSquared = tolerance * tolerance;
00117 double bestScore = observations.size() * toleranceSquared;
00118
00119 std::vector<size_t> sample_index(sample_size);
00120 std::vector<Obs> sample(sample_size);
00121 while (N--) {
00122 randomTuple(sample_index, observations.size());
00123 for (int i=0;i<sample_size; i++)
00124 sample[i] = observations[sample_index[i]];
00125 Trans thisT(best);
00126 thisT.estimate(sample.begin(), sample.end());
00127 double score = 0;
00128 for (size_t i=0; i<observations.size(); i++) {
00129 const Obs& o = observations[i];
00130 const double s = thisT.score(o);
00131 if (s < toleranceSquared) {
00132 thisInlier[i] = true;
00133 score += s;
00134 } else {
00135 thisInlier[i] = false;
00136 score += toleranceSquared;
00137 }
00138 }
00139 if (score < bestScore) {
00140 bestScore = score;
00141 inlier = thisInlier;
00142 best = thisT;
00143 }
00144 }
00145 return bestScore;
00146 }
00147
00148 inline double getShrinkRatio(unsigned int H, unsigned int N, unsigned int B)
00149 {
00150 return pow(double(H), -double(B)/N);
00151 }
00152
00178
00179
00180 template <class Obs, class Trans, class Tol, class Prob>
00181 size_t find_RANSAC_inliers_guided_breadth_first(const std::vector<Obs>& observations, const Prob& prob, int sample_size, const Tol& tolerance, size_t N, size_t block_size,
00182 Trans& best, std::vector<bool>& inlier)
00183 {
00184 std::vector<Trans> hypotheses(N,best);
00185 std::vector<std::pair<int,size_t> > score(N);
00186 std::vector<size_t> sample_index(sample_size);
00187 std::vector<Obs> sample(sample_size);
00188 std::vector<double> cdf(observations.size());
00189 cdf[0] = prob(observations[0]);
00190 for (size_t i=1; i<observations.size(); ++i)
00191 cdf[i] = cdf[i-1] + prob(observations[i]);
00192 const double psum = cdf.back();
00193
00194 for (size_t i=0; i<hypotheses.size(); i++) {
00195 do {
00196 randomTuple(cdf, sample_index, psum);
00197 for (int s=0; s<sample_size; ++s)
00198 sample[s] = observations[sample_index[s]];
00199 }
00200 while (!hypotheses[i].estimate(sample.begin(), sample.end()));
00201 score[i] = std::make_pair(0,i);
00202 }
00203 size_t m = 0;
00204 const double factor = getShrinkRatio(N, observations.size(), block_size);
00205 while (m < observations.size()) {
00206 size_t end = std::min(observations.size(), m+block_size);
00207 for (size_t i=0; i<score.size(); i++) {
00208 const Trans& thisT = hypotheses[score[i].second];
00209 size_t s = 0;
00210 for (size_t j=m; j!=end; j++) {
00211 if (thisT.isInlier(observations[j], tolerance))
00212 ++s;
00213 }
00214 score[i].first += s;
00215 }
00216 unsigned int cutoff = (unsigned int)(score.size() * factor);
00217 if (cutoff == 0)
00218 break;
00219 std::nth_element(score.begin(), score.end(), score.begin()+cutoff, std::greater<std::pair<int,size_t> >());
00220 score.resize(cutoff);
00221 m = end;
00222 }
00223 size_t best_index = std::max_element(score.begin(), score.end())->second;
00224 best = hypotheses[best_index];
00225 size_t count = 0;
00226 inlier.resize(observations.size());
00227 for (size_t i=0; i<observations.size(); i++) {
00228 if (best.isInlier(observations[i], tolerance)) {
00229 inlier[i] = true;
00230 ++count;
00231 } else
00232 inlier[i] = false;
00233 }
00234 return count;
00235 }
00236
00259
00260
00261 template <class Obs, class Trans, class Tol> size_t find_RANSAC_inliers_breadth_first(const std::vector<Obs>& observations, int sample_size, const Tol& tolerance, size_t N, size_t block_size,
00262 Trans& best, std::vector<bool>& inlier)
00263 {
00264 std::vector<Trans> hypotheses(N,best);
00265 std::vector<std::pair<int,size_t> > score(N);
00266 std::vector<size_t> sample_index(sample_size);
00267 std::vector<Obs> sample(sample_size);
00268 for (size_t i=0; i<hypotheses.size(); i++) {
00269 do {
00270 randomTuple(sample_index, observations.size());
00271 for (int s=0; s<sample_size; ++s)
00272 sample[s] = observations[sample_index[s]];
00273 }
00274 while (!hypotheses[i].estimate(sample.begin(), sample.end()));
00275 score[i] = std::make_pair(0,i);
00276 }
00277 size_t m = 0;
00278 const double factor = getShrinkRatio(N, observations.size(), block_size);
00279 while (m < observations.size()) {
00280 size_t end = std::min(observations.size(), m+block_size);
00281 for (size_t i=0; i<score.size(); i++) {
00282 const Trans& thisT = hypotheses[score[i].second];
00283 size_t s = 0;
00284 for (size_t j=m; j!=end; j++) {
00285 if (thisT.isInlier(observations[j], tolerance))
00286 ++s;
00287 }
00288 score[i].first += s;
00289 }
00290 unsigned int cutoff = (unsigned int)(score.size() * factor);
00291 if (cutoff == 0)
00292 break;
00293 std::nth_element(score.begin(), score.end(), score.begin()+cutoff, std::greater<std::pair<int,size_t> >());
00294 score.resize(cutoff);
00295 m = end;
00296 }
00297 size_t best_index = std::max_element(score.begin(), score.end())->second;
00298 best = hypotheses[best_index];
00299 size_t count = 0;
00300 inlier.resize(observations.size());
00301 for (size_t i=0; i<observations.size(); i++) {
00302 if (best.isInlier(observations[i], tolerance)) {
00303 inlier[i] = true;
00304 ++count;
00305 } else
00306 inlier[i] = false;
00307 }
00308 return count;
00309 }
00310
00311
00318 template <class T, class U>
00319 void remove_if_false(std::vector<T>& v, const std::vector<U>& flag) {
00320 assert(v.size() <= flag.size());
00321 unsigned int i=0,j;
00322 while (i<v.size() && flag[i])
00323 i++;
00324 j = i++;
00325 for (;i<v.size();i++) {
00326 if (flag[i])
00327 v[j++] = v[i];
00328 }
00329 v.resize(j);
00330 }
00331
00332 }
00333
00334 #endif