stereo
ransac.hpp
Go to the documentation of this file.
1 #ifndef __STEREO_RANSAC_HPP__
2 #define __STEREO_RANSAC_HPP__
3 
4 #include <stdlib.h>
5 #include <iostream>
6 #include <vector>
7 #include <Eigen/LU>
8 #include <Eigen/Eigenvalues>
9 
10 namespace stereo
11 {
12 namespace ransac
13 {
14 
15 typedef std::vector<size_t> vector_size_t;
16 
17 
18 class Pairs
19 {
20 public:
21  const static unsigned int MIN_PAIRS = 3;
22 
25  void add( const Eigen::Vector3d& a, const Eigen::Vector3d& b, double dist );
26 
30  double trim( size_t n_po );
31 
35  Eigen::Affine3d getTransform();
36 
37  double getMeanSquareError() const;
38 
41  size_t size() const;
42 
44  void clear();
45 
46 public:
47  std::vector<Eigen::Vector3d> x, p;
48 
49  struct pair
50  {
51  size_t index;
52  double distance;
53 
54  bool operator < ( const pair other ) const
55  {
56  return distance < other.distance;
57  }
58  };
59  std::vector<pair> pairs;
60 
61  double mse;
62 };
63 
65 {
66  typedef Eigen::Affine3d Model;
67  typedef double Real;
68 
69  const std::vector<Eigen::Vector3d>& x, p;
71 
72  FitTransform( const std::vector<Eigen::Vector3d>& x, const std::vector<Eigen::Vector3d>& p, double errorThreshold = 0.1 )
73  : x( x ), p( p ), errorThreshold( errorThreshold )
74  {
75  assert( x.size() == p.size() );
76  }
77 
78  virtual ~FitTransform() {};
79 
80  size_t getSampleCount( void ) const
81  {
82  return x.size();
83  }
84 
85  bool fitModel( const vector_size_t& useIndices, Eigen::Affine3d& model ) const
86  {
87  if( useIndices.size() < 3 )
88  {
89  std::cout << useIndices.size() << std::endl;
90  return false;
91  }
92 
94  for( size_t i = 0; i < useIndices.size(); i++ )
95  {
96  const size_t index = useIndices[i];
97  const Eigen::Vector3d& v1 = x[index];
98  const Eigen::Vector3d& v2 = p[index];
99  pairs.add( v1, v2, (v2-v1).norm() );
100  }
101 
102  // get the model
103  Eigen::Affine3d m = pairs.getTransform();
104 
105  // test if the model is valid
106  for( size_t i = 0; i < useIndices.size(); i++ )
107  {
108  double dist = testSample( useIndices[i], m );
109  if( dist > errorThreshold )
110  {
111  return false;
112  }
113  }
114 
115  model = m;
116  return true;
117  }
118 
119  virtual double testSample( size_t index, const Eigen::Affine3d& model ) const
120  {
121  const Eigen::Vector3d& v1 = x[index];
122  const Eigen::Vector3d& v2 = model * p[index];
123 
124  const double dist = (v2-v1).norm();
125  return dist;
126  }
127 };
128 
130 {
131  const std::vector<float>& x_e, p_e;
132 
133  FitTransformUncertain( const std::vector<Eigen::Vector3d>& x, const std::vector<Eigen::Vector3d>& p,
134  const std::vector<float>& x_e, const std::vector<float>& p_e, double errorThreshold = 0.1 )
135  : FitTransform( x, p, errorThreshold ), x_e( x_e ), p_e( p_e )
136  {
137  }
138 
140 
141  virtual double testSample( size_t index, const Eigen::Affine3d& model ) const
142  {
143  const Eigen::Vector3d& v1 = x[index];
144  const Eigen::Vector3d& v2 = model * p[index];
145 
146  const float e1 = x_e[index];
147  const float e2 = p_e[index];
148 
149  // TODO this is a very crude normalization for the error
150  const double dist = (v2-v1).norm() / sqrt(pow(e1,2) + pow(e2,2));
151  return dist;
152  }
153 };
154 
155 //
156 // pickRandomIndex and ransacSingleModel are copied from MRPT:
157 //
158 // http://code.google.com/p/mrpt/
159 //
160 
161 template <typename T>
162 void pickRandomIndex( T p_size, T p_pick, vector_size_t& p_ind )
163 {
164  assert( p_size >= p_pick );
165 
166  vector_size_t a( p_size );
167  for( size_t i = 0; i < p_size; i++ )
168  a[i] = i;
169 
170  std::random_shuffle( a.begin(), a.end() );
171  p_ind.resize( p_pick );
172  for( size_t i = 0 ; i < p_pick; i++ )
173  p_ind[i] = a[i];
174 }
175 
176 template<typename TModelFit>
177 bool ransacSingleModel( const TModelFit& p_state,
178  size_t p_kernelSize,
179  const typename TModelFit::Real& p_fitnessThreshold,
180  typename TModelFit::Model& p_bestModel,
181  vector_size_t& p_inliers,
182  size_t hardIterLimit = 100 )
183 {
184  size_t bestScore = 0;
185  size_t iter = 0;
186  size_t softIterLimit = 1; // will be updated by the size of inliers
187  size_t nSamples = p_state.getSampleCount();
188  vector_size_t ind( p_kernelSize );
189 
190  while ( iter < softIterLimit && iter < hardIterLimit )
191  {
192  bool degenerate = true;
193  typename TModelFit::Model currentModel;
194  size_t i = 0;
195  while ( degenerate )
196  {
197  pickRandomIndex( nSamples, p_kernelSize, ind );
198  degenerate = !p_state.fitModel( ind, currentModel );
199  i++;
200  if( i > hardIterLimit )
201  return false;
202  }
203 
204  vector_size_t inliers;
205 
206  for( size_t i = 0; i < nSamples; i++ )
207  {
208  if( p_state.testSample( i, currentModel ) < p_fitnessThreshold )
209  inliers.push_back( i );
210  }
211  assert( inliers.size() > 0 );
212 
213  // Find the number of inliers to this model.
214  const size_t ninliers = inliers.size();
215 
216  if ( ninliers > bestScore )
217  {
218  bestScore = ninliers;
219  p_bestModel = currentModel;
220  p_inliers = inliers;
221 
222  // Update the estimation of maxIter to pick dataset with no outliers at propability p
223  float f = ninliers / static_cast<float>( nSamples );
224  float p = 1 - pow( f, static_cast<float>( p_kernelSize ) );
225  float eps = std::numeric_limits<float>::epsilon();
226  p = std::max( eps, p); // Avoid division by -Inf
227  p = std::min( 1-eps, p); // Avoid division by 0.
228  softIterLimit = log(1-p) / log(p);
229  }
230 
231  iter++;
232  }
233 
234  return true;
235 }
236 
237 }
238 }
239 
240 #endif
void pickRandomIndex(T p_size, T p_pick, vector_size_t &p_ind)
Definition: ransac.hpp:162
double errorThreshold
Definition: ransac.hpp:70
std::vector< pair > pairs
Definition: ransac.hpp:59
bool fitModel(const vector_size_t &useIndices, Eigen::Affine3d &model) const
Definition: ransac.hpp:85
const std::vector< Eigen::Vector3d > p
Definition: ransac.hpp:69
const std::vector< Eigen::Vector3d > & x
Definition: ransac.hpp:69
const std::vector< float > & x_e
Definition: ransac.hpp:131
double mse
Definition: ransac.hpp:61
void add(const Eigen::Vector3d &a, const Eigen::Vector3d &b, double dist)
Definition: ransac.cpp:9
virtual ~FitTransform()
Definition: ransac.hpp:78
FitTransformUncertain(const std::vector< Eigen::Vector3d > &x, const std::vector< Eigen::Vector3d > &p, const std::vector< float > &x_e, const std::vector< float > &p_e, double errorThreshold=0.1)
Definition: ransac.hpp:133
Definition: ransac.hpp:49
double distance
Definition: ransac.hpp:52
FitTransform(const std::vector< Eigen::Vector3d > &x, const std::vector< Eigen::Vector3d > &p, double errorThreshold=0.1)
Definition: ransac.hpp:72
Definition: ransac.hpp:129
virtual ~FitTransformUncertain()
Definition: ransac.hpp:139
double getMeanSquareError() const
Definition: ransac.cpp:106
virtual double testSample(size_t index, const Eigen::Affine3d &model) const
Definition: ransac.hpp:119
Eigen::Affine3d Model
Definition: ransac.hpp:66
size_t size() const
Definition: ransac.cpp:101
std::vector< Eigen::Vector3d > p
Definition: ransac.hpp:47
Definition: ransac.hpp:18
size_t getSampleCount(void) const
Definition: ransac.hpp:80
void clear()
Definition: ransac.cpp:111
std::vector< Eigen::Vector3d > x
Definition: ransac.hpp:47
double Real
Definition: ransac.hpp:67
Definition: ransac.hpp:64
double trim(size_t n_po)
Definition: ransac.cpp:20
Eigen::Affine3d getTransform()
Definition: ransac.cpp:40
size_t index
Definition: ransac.hpp:51
bool operator<(const pair other) const
Definition: ransac.hpp:54
virtual double testSample(size_t index, const Eigen::Affine3d &model) const
Definition: ransac.hpp:141
static const unsigned int MIN_PAIRS
Definition: ransac.hpp:21
const std::vector< float > p_e
Definition: ransac.hpp:131
std::vector< size_t > vector_size_t
Definition: ransac.hpp:15
bool ransacSingleModel(const TModelFit &p_state, size_t p_kernelSize, const typename TModelFit::Real &p_fitnessThreshold, typename TModelFit::Model &p_bestModel, vector_size_t &p_inliers, size_t hardIterLimit=100)
Definition: ransac.hpp:177