Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
ExampleRANSACPlane.hh
1 /*
2 This file is part of the BIAS library (Basic ImageAlgorithmS).
3 
4 Copyright (C) 2003, 2004 (see file CONTACTS for details)
5  Multimediale Systeme der Informationsverarbeitung
6  Institut fuer Informatik
7  Christian-Albrechts-Universitaet Kiel
8 
9 
10 BIAS is free software; you can redistribute it and/or modify
11 it under the terms of the GNU Lesser General Public License as published by
12 the Free Software Foundation; either version 2.1 of the License, or
13 (at your option) any later version.
14 
15 BIAS is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Lesser General Public License for more details.
19 
20 You should have received a copy of the GNU Lesser General Public License
21 along with BIAS; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24 
25 #ifndef __ExampleRANSAC_Plane_hh__
26 #define __ExampleRANSAC_Plane_hh__
27 
28 #include <Base/Common/BIASpragmaStart.hh>
29 
30 
31 #include "MathAlgo/RANSAC.hh"
32 #include "MathAlgo/SVD.hh"
33 #include "Base/Geometry/HomgPoint3D.hh"
34 #include "Base/Geometry/HomgPlane3D.hh"
35 
36 #include <string>
37 
38 namespace BIAS {
39 
40  /** @class PlaneRANSAC
41  @brief Robust fitting of 3D plane to 3D point set using RANSAC.
42 
43  This class implements an example for RANSAC class overloading.
44 
45  Method PlaneRANSAC::GetSampleSolutions picks three 3D points and
46  computes a 3D plane from them.
47 
48  Method PlaneRANSAC::EvaluateSolution evaluates how many points are
49  considered as "inliers" with respect to the computed plane, i.e.
50  their distance to the plane does not exceed a certain threshold.
51 
52  In PlaneRANSAC::RefineSolution, a linear least squares computation
53  of the plane is done using all inliers to refine the plane parameters.
54 
55  You have to set the inlier threshold (max. distance to plane to accept
56  a point as being on the plane) and the fraction of valid 3D points
57  which defines the number of samples performed by RANSAC.
58 
59  When you call PlaneRANSAC::SolveMaster then, you will get the best
60  plane according to your input.
61 
62  @author MIP
63  */
64  class PlaneRANSAC : public RANSAC<HomgPlane3D>
65  {
66 
67  public:
68 
69  PlaneRANSAC();
70 
71  ~PlaneRANSAC();
72 
73  /**
74  * @brief Initializes RANSAC. After calling the base RANSAC::Init method, the
75  * other parameters are set.
76  * @attention RANSAC::Init resets a lot of parameters to default values,
77  * for example explicitSampleCount. So setting these values before
78  * calling Init will have no effect.
79  */
80  void Init(std::vector<HomgPoint3D>& data,
81  double inlier_distance_threshold,
82  bool refine_solution,
83  double expected_inlier_fraction,
84  double solution_error_threshold);
85 
86  /** takes sample and computes solution for this sample. This is usually done
87  * in an easy way, e.g. linearly. Sometimes solutions based on a minimum
88  * sample size are not unambiguous as for example in case of the 7 point
89  * algorithm for essential matrix estimation. In those cases all possible
90  * solutions have to be returned in the solutions vector.
91  */
92  virtual int GetSampleSolutions(std::vector<unsigned int> &which_samples,
93  std::vector<HomgPlane3D> &solutions);
94 
95  /**
96  * The solution denoted by solution needs to be ranked. This is done based
97  * on the number of inliers found for this solution and based on the accuracy
98  * reached on these inliers. So some kind of measurement is needed. Here it
99  * is the absolute distance between the homogeneous 3D points and the plane. If
100  * such a distance is below the threshold, and inlier has been found. The
101  * average distance over all inliers is the evaluate_score. While the number
102  * of inliers is entered in accept_count. For more details refer to
103  * documentation of this method in RANSAC.hh.
104  */
105  virtual bool EvaluateSolution(const HomgPlane3D& solution,
106  bool existing_solution_flag,
107  std::vector<bool>& inlier,
108  int& accept_count,
109  double& evaluate_score,
110  bool& ok_to_terminate_flag);
111 
112  /** RefineSolution is only called, if the RefineSolutionFlag is set to true.
113  * In any case, it is only applied to solutions, that have been found to be good,
114  * indicated by the return value of EvaluateSolution.
115  *
116  */
117  virtual bool RefineSolution(std::vector<unsigned int>& which_samples,
118  HomgPlane3D& solution,
119  std::vector<bool>& new_inliers);
120 
121  protected:
122 
123  /// input 3D points to fit 3D plane to
124  std::vector<HomgPoint3D> _vData;
125 
126  /// 3D points with max distance _dInlierDistanceThreshold to plane are
127  /// considered as inliers
129 
130  /// if a sample yields more than _dExpectedInlierFraction inliers and
131  /// evaluate_score is lower than _dSolutionErrorThreshold, RANSAC will stop
133 
134  /// if a sample yields more than _dExpectedInlierFraction inliers and
135  /// evaluate_score is lower than _dSolutionErrorThreshold, RANSAC will stop
137  };
138 
140  {}
141 
143  {}
144 
145  void PlaneRANSAC::Init(std::vector<HomgPoint3D>& data,
146  double inlier_distance_threshold,
147  bool refine_solution,
148  double expected_inlier_fraction,
149  double solution_error_threshold)
150  {
151  RANSAC<HomgPlane3D>::Init(3, 1, refine_solution);
152  _vData = data;
153  _uiDataSize = data.size();
154  _dInlierDistanceThreshold = inlier_distance_threshold;
155  _dExpectedInlierFraction = expected_inlier_fraction;
156  _dSolutionErrorThreshold = solution_error_threshold;
157  }
158 
159  int PlaneRANSAC::
160  GetSampleSolutions(std::vector<unsigned int> &which_samples,
161  std::vector<HomgPlane3D> &solutions)
162  {
163  solutions.clear();
164 
165  // computing a plane out of three 3D points is really easy,
166  // and there is only one solution in this case
167  solutions.push_back(HomgPlane3D(_vData[which_samples[0]],
168  _vData[which_samples[1]],
169  _vData[which_samples[2]]));
170 
171  return solutions.size();
172  }
173 
175  bool existing_solution_flag,
176  std::vector<bool>& inlier,
177  int& accept_count,
178  double& evaluate_score,
179  bool& ok_to_terminate_flag)
180  {
181  bool good_flag = true;
182  inlier.clear();
183  inlier.resize(_uiDataSize);
184 
185  int my_accept_count = 0;
186  evaluate_score = 0.0;
187 
188  for (unsigned int i=0; i<_uiDataSize; i++){
189  inlier[i] = (solution.DistanceSquared(_vData[i]) <
191  if (inlier[i]) {
192  my_accept_count++;
193  evaluate_score += solution.DistanceSquared(_vData[i]);
194  }
195  }
196 
197  // determine average score
198  if (my_accept_count != 0) {
199  evaluate_score /= my_accept_count;
200  } else {
201  evaluate_score = DBL_MAX;
202  good_flag = false;
203  }
204 
205  // set new accept count
206  accept_count = my_accept_count;
207 
208  // ok_to_terminate_flag is important to set, if greedy evaluation is needed.
209  // If set to true, the algorithm will stop after this sample
210  ok_to_terminate_flag =
211  (((accept_count/(double)_uiDataSize) > _dExpectedInlierFraction) &&
212  (evaluate_score < _dSolutionErrorThreshold));
213 
214  // this return value decides if the solution will be considered further by refining it.
215  return good_flag;
216  }
217 
218  bool PlaneRANSAC::RefineSolution(std::vector<unsigned int>& which_samples,
219  HomgPlane3D& solution,
220  std::vector<bool>& new_inliers)
221  {
222  // create linear equation system A*x = 0 describing the relation between
223  // plane parameters x and 3D points A_i
224  const unsigned int nr_of_points = which_samples.size();
225  BIAS::Matrix<double> A(nr_of_points, 4);
226  for (unsigned int i = 0; i < nr_of_points; i++) {
227  A[i][0] = _vData[which_samples[i]][0];
228  A[i][1] = _vData[which_samples[i]][1];
229  A[i][2] = _vData[which_samples[i]][2];
230  A[i][3] = _vData[which_samples[i]][3];
231  }
232  A = A.Transpose()*A;
233  // get a solution (linear fit) of this equation system by its SVD
234  SVD svd(A, 1e-5, false);
235 
236  // compute plane parameters x from last null vector
237  if (svd.Rank() < 3) return false;
238  Vector4<double> x = svd.GetNullvector();
239  double norm = sqrt(x[0]*x[0] + x[1]*x[1] + x[2]*x[2]);
240  if (norm > 1e-5) x /= norm;
241  solution = HomgPlane3D(x);
242 
243  return true;
244  }
245 
246 }
247 
248 #include <Base/Common/BIASpragmaEnd.hh>
249 
250 #endif // __ExampleRANSAC_double_hh__
Vector< double > GetNullvector(const int last_offset=0)
return one of the nullvectors.
Definition: SVD.hh:404
void Init(std::vector< HomgPoint3D > &data, double inlier_distance_threshold, bool refine_solution, double expected_inlier_fraction, double solution_error_threshold)
Initializes RANSAC.
computes and holds the singular value decomposition of a rectangular (not necessarily quadratic) Matr...
Definition: SVD.hh:92
HOMGPLANE3D_TYPE DistanceSquared(const HomgPoint3D &point) const
calculates squared distance of a point from plane
Definition: HomgPlane3D.hh:184
Matrix< T > Transpose() const
transpose function, storing data destination matrix
Definition: Matrix.hh:823
double _dInlierDistanceThreshold
3D points with max distance _dInlierDistanceThreshold to plane are considered as inliers ...
Robust fitting of 3D plane to 3D point set using RANSAC.
unsigned int Rank()
returns the rank of A_
Definition: SVD.cpp:506
void Init(unsigned int sample_size, unsigned int max_solutions_per_sample=1, bool refine_solution=false, bool greedy=false)
Definition: RANSAC.hh:360
class Vector4 contains a Vector of dim.
Definition: Vector4.hh:65
virtual bool EvaluateSolution(const HomgPlane3D &solution, bool existing_solution_flag, std::vector< bool > &inlier, int &accept_count, double &evaluate_score, bool &ok_to_terminate_flag)
The solution denoted by solution needs to be ranked.
double _dSolutionErrorThreshold
if a sample yields more than _dExpectedInlierFraction inliers and evaluate_score is lower than _dSolu...
double _dExpectedInlierFraction
if a sample yields more than _dExpectedInlierFraction inliers and evaluate_score is lower than _dSolu...
Generic abstract base class for RANSAC (RANdom SAmple Consensus) estimators.
Definition: RANSAC.hh:80
virtual int GetSampleSolutions(std::vector< unsigned int > &which_samples, std::vector< HomgPlane3D > &solutions)
takes sample and computes solution for this sample.
unsigned _uiDataSize
number of data elements needed to compute a solution
Definition: RANSAC.hh:270
std::vector< HomgPoint3D > _vData
input 3D points to fit 3D plane to
virtual bool RefineSolution(std::vector< unsigned int > &which_samples, HomgPlane3D &solution, std::vector< bool > &new_inliers)
RefineSolution is only called, if the RefineSolutionFlag is set to true.
A homogeneous plane (in P^3) All points X on the plane p fulfill p &#39; * X = 0.
Definition: HomgPlane3D.hh:46