TooN Algorithm Library - tag  0.2
ransac.h
Go to the documentation of this file.
1 #ifndef TAG_RANSAC_H_
2 #define TAG_RANSAC_H_
3 
4 #include <vector>
5 #include <algorithm>
6 
7 namespace tag {
8 
9 #ifdef WIN32
10 
11 inline double drand48(void) {
12  const double RS_SCALE = (1.0 / (1.0 + RAND_MAX));
13 
14  double d;
15  do {
16  d = (((rand () * RS_SCALE) + rand ()) * RS_SCALE + rand ()) * RS_SCALE;
17  } while (d >= 1); /* Round off */
18  return d;
19 }
20 #endif
21 
27 
28  template <class T, class I> void randomTuple(const std::vector<T>& cdf, std::vector<I>& t, T maxp) {
29  for (size_t i=0; i<t.size(); i++) {
30  try_again:
31  double x = drand48()* maxp;
32  size_t r = std::min(cdf.size()-1, (size_t)(std::lower_bound(cdf.begin(), cdf.end(), (T)x) - cdf.begin()));
33  for (size_t j=0; j<i; j++)
34  if (r == t[j])
35  goto try_again;
36  t[i] = r;
37  }
38  }
39 
40  template <class T> void randomTuple(T& t, unsigned int bound)
41  {
42  for (size_t i=0; i<t.size(); i++) {
43  try_again:
44  size_t r = (size_t)(drand48() * bound);
45  for (size_t j=0; j<i; j++)
46  if (r == t[j])
47  goto try_again;
48  t[i] = r;
49  }
50  }
51 
52 
75 
76 template <class Obs, class Trans, class Tol> size_t find_RANSAC_inliers(const std::vector<Obs>& observations, const Tol& tolerance, size_t N,
77  Trans& best, std::vector<bool>& inlier, int sample_size = Trans::hypothesis_size )
78 {
79  std::vector<bool> thisInlier(observations.size());
80  size_t bestScore = 0;
81  std::vector<size_t> sample_index(sample_size);
82  std::vector<Obs> sample(sample_size);
83  while (N--) {
84  randomTuple(sample_index, observations.size());
85  for (int i=0;i<sample_size; i++)
86  sample[i] = observations[sample_index[i]];
87  Trans thisT(best);
88  thisT.estimate(sample.begin(), sample.end());
89  size_t score = 0;
90  for (size_t i=0; i<observations.size(); i++) {
91  const Obs& o = observations[i];
92  if (thisT.isInlier(o, tolerance)) {
93  thisInlier[i] = true;
94  score++;
95  } else
96  thisInlier[i] = false;
97  }
98  if (score > bestScore) {
99  bestScore = score;
100  inlier = thisInlier;
101  best = thisT;
102  }
103  }
104  return bestScore;
105 }
106 
110 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,
111  Trans& best, std::vector<bool>& inlier)
112 {
113  return find_RANSAC_inliers(observations, tolerance, N, best, inlier, sample_size);
114 }
115 
138 template <class Obs, class Trans, class Tol> double find_MSAC_inliers(const std::vector<Obs>& observations, const Tol& tolerance, size_t N,
139  Trans& best, std::vector<bool>& inlier, int sample_size = Trans::hypothesis_size)
140 {
141  std::vector<bool> thisInlier(observations.size());
142  const double toleranceSquared = tolerance * tolerance;
143  double bestScore = observations.size() * toleranceSquared;
144 
145  std::vector<size_t> sample_index(sample_size);
146  std::vector<Obs> sample(sample_size);
147  while (N--) {
148  randomTuple(sample_index, observations.size());
149  for (int i=0;i<sample_size; i++)
150  sample[i] = observations[sample_index[i]];
151  Trans thisT(best);
152  thisT.estimate(sample.begin(), sample.end());
153  double score = 0;
154  for (size_t i=0; i<observations.size(); i++) {
155  const Obs& o = observations[i];
156  const double s = thisT.score(o);
157  if (s < toleranceSquared) {
158  thisInlier[i] = true;
159  score += s;
160  } else {
161  thisInlier[i] = false;
162  score += toleranceSquared;
163  }
164  }
165  if (score < bestScore) {
166  bestScore = score;
167  inlier = thisInlier;
168  best = thisT;
169  }
170  }
171  return bestScore;
172 }
173 
177 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,
178  Trans& best, std::vector<bool>& inlier)
179 {
180  return find_MSAC_inliers(observations, tolerance, N, best, inlier, sample_size);
181 }
182 
183 
184 inline double getShrinkRatio(unsigned int H, unsigned int N, unsigned int B)
185 {
186  return pow(double(H), -double(B)/N);
187 }
188 
216 template <class Obs, class Trans, class Tol, class Prob>
217 size_t find_RANSAC_inliers_guided_breadth_first(const std::vector<Obs>& observations, const Prob& prob, const Tol& tolerance, size_t N, size_t block_size,
218  Trans& best, std::vector<bool>& inlier, int sample_size = Trans::hypothesis_size)
219  {
220  std::vector<Trans> hypotheses(N,best);
221  std::vector<std::pair<int,size_t> > score(N);
222  std::vector<size_t> sample_index(sample_size);
223  std::vector<Obs> sample(sample_size);
224  std::vector<double> cdf(observations.size());
225  cdf[0] = prob(observations[0]);
226  for (size_t i=1; i<observations.size(); ++i)
227  cdf[i] = cdf[i-1] + prob(observations[i]);
228  const double psum = cdf.back();
229 
230  for (size_t i=0; i<hypotheses.size(); i++) {
231  do {
232  randomTuple(cdf, sample_index, psum);
233  for (int s=0; s<sample_size; ++s)
234  sample[s] = observations[sample_index[s]];
235  }
236  while (!hypotheses[i].estimate(sample.begin(), sample.end()));
237  score[i] = std::make_pair(0,i);
238  }
239  size_t m = 0;
240  const double factor = getShrinkRatio(N, observations.size(), block_size);
241  while (m < observations.size()) {
242  size_t end = std::min(observations.size(), m+block_size);
243  for (size_t i=0; i<score.size(); i++) {
244  const Trans& thisT = hypotheses[score[i].second];
245  size_t s = 0;
246  for (size_t j=m; j!=end; j++) {
247  if (thisT.isInlier(observations[j], tolerance))
248  ++s;
249  }
250  score[i].first += s;
251  }
252  unsigned int cutoff = (unsigned int)(score.size() * factor);
253  if (cutoff == 0)
254  break;
255  std::nth_element(score.begin(), score.end(), score.begin()+cutoff, std::greater<std::pair<int,size_t> >());
256  score.resize(cutoff);
257  m = end;
258  }
259  size_t best_index = std::max_element(score.begin(), score.end())->second;
260  best = hypotheses[best_index];
261  size_t count = 0;
262  inlier.resize(observations.size());
263  for (size_t i=0; i<observations.size(); i++) {
264  if (best.isInlier(observations[i], tolerance)) {
265  inlier[i] = true;
266  ++count;
267  } else
268  inlier[i] = false;
269  }
270  return count;
271  }
272 
276 template <class Obs, class Trans, class Tol, class Prob>
277 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,
278  Trans& best, std::vector<bool>& inlier)
279 {
280  return find_RANSAC_inliers_guided_breadth_first(observations, prob, tolerance, N, block_size, best, inlier, sample_size);
281 }
282 
307 template <class Obs, class Trans, class Tol> size_t find_RANSAC_inliers_breadth_first(const std::vector<Obs>& observations, const Tol& tolerance, size_t N, size_t block_size,
308  Trans& best, std::vector<bool>& inlier, int sample_size = Trans::hypothesis_size)
309  {
310  std::vector<Trans> hypotheses(N,best);
311  std::vector<std::pair<int,size_t> > score(N);
312  std::vector<size_t> sample_index(sample_size);
313  std::vector<Obs> sample(sample_size);
314  for (size_t i=0; i<hypotheses.size(); i++) {
315  do {
316  randomTuple(sample_index, observations.size());
317  for (int s=0; s<sample_size; ++s)
318  sample[s] = observations[sample_index[s]];
319  }
320  while (!hypotheses[i].estimate(sample.begin(), sample.end()));
321  score[i] = std::make_pair(0,i);
322  }
323  size_t m = 0;
324  const double factor = getShrinkRatio(N, observations.size(), block_size);
325  while (m < observations.size()) {
326  size_t end = std::min(observations.size(), m+block_size);
327  for (size_t i=0; i<score.size(); i++) {
328  const Trans& thisT = hypotheses[score[i].second];
329  size_t s = 0;
330  for (size_t j=m; j!=end; j++) {
331  if (thisT.isInlier(observations[j], tolerance))
332  ++s;
333  }
334  score[i].first += s;
335  }
336  unsigned int cutoff = (unsigned int)(score.size() * factor);
337  if (cutoff == 0)
338  break;
339  std::nth_element(score.begin(), score.end(), score.begin()+cutoff, std::greater<std::pair<int,size_t> >());
340  score.resize(cutoff);
341  m = end;
342  }
343  size_t best_index = std::max_element(score.begin(), score.end())->second;
344  best = hypotheses[best_index];
345  size_t count = 0;
346  inlier.resize(observations.size());
347  for (size_t i=0; i<observations.size(); i++) {
348  if (best.isInlier(observations[i], tolerance)) {
349  inlier[i] = true;
350  ++count;
351  } else
352  inlier[i] = false;
353  }
354  return count;
355  }
356 
360 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,
361  Trans& best, std::vector<bool>& inlier)
362 {
363  return find_RANSAC_inliers_breadth_first(observations, tolerance, N, block_size, best, inlier, sample_size);
364 }
365 
372 template <class T, class U>
373 void remove_if_false(std::vector<T>& v, const std::vector<U>& flag) {
374  assert(v.size() <= flag.size());
375  unsigned int i=0,j;
376  while (i<v.size() && flag[i])
377  i++;
378  j = i++;
379  for (;i<v.size();i++) {
380  if (flag[i])
381  v[j++] = v[i];
382  }
383  v.erase(v.begin() + j, v.end());
384 }
385 
386 } // namespace tag
387 
388 #endif