Point Cloud Library (PCL)  1.6.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
sac_model.h
Go to the documentation of this file.
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Point Cloud Library (PCL) - www.pointclouds.org
5  * Copyright (c) 2010-2011, Willow Garage, Inc.
6  *
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * * Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  * * Redistributions in binary form must reproduce the above
16  * copyright notice, this list of conditions and the following
17  * disclaimer in the documentation and/or other materials provided
18  * with the distribution.
19  * * Neither the name of Willow Garage, Inc. nor the names of its
20  * contributors may be used to endorse or promote products derived
21  * from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34  * POSSIBILITY OF SUCH DAMAGE.
35  *
36  * $Id: sac_model.h 6214 2012-07-06 19:31:29Z rusu $
37  *
38  */
39 
40 #ifndef PCL_SAMPLE_CONSENSUS_MODEL_H_
41 #define PCL_SAMPLE_CONSENSUS_MODEL_H_
42 
43 #include <cfloat>
44 #include <ctime>
45 #include <limits.h>
46 #include <set>
47 #include <boost/random.hpp>
48 
49 #include <pcl/console/print.h>
50 #include <pcl/point_cloud.h>
52 
53 #include <pcl/search/search.h>
54 
55 namespace pcl
56 {
57  template<class T> class ProgressiveSampleConsensus;
58 
64  template <typename PointT>
66  {
67  public:
72 
73  typedef boost::shared_ptr<SampleConsensusModel> Ptr;
74  typedef boost::shared_ptr<const SampleConsensusModel> ConstPtr;
75 
76  protected:
80  SampleConsensusModel (bool random = false) :
81  input_ (),
82  indices_ (),
83  radius_min_ (-std::numeric_limits<double>::max()), radius_max_ (std::numeric_limits<double>::max()), samples_radius_ (0.),
84  shuffled_indices_ (),
85  rng_alg_ (),
86  rng_dist_ (new boost::uniform_int<> (0, std::numeric_limits<int>::max ())),
87  rng_gen_ ()
88  {
89  // Create a random number generator object
90  if (random)
91  rng_alg_.seed (static_cast<unsigned> (std::time(0)));
92  else
93  rng_alg_.seed (12345u);
94 
95  rng_gen_.reset (new boost::variate_generator<boost::mt19937&, boost::uniform_int<> > (rng_alg_, *rng_dist_));
96  }
97 
98  public:
103  SampleConsensusModel (const PointCloudConstPtr &cloud, bool random = false) :
104  input_ (),
105  indices_ (),
106  radius_min_ (-std::numeric_limits<double>::max()), radius_max_ (std::numeric_limits<double>::max()), samples_radius_ (0.),
107  shuffled_indices_ (),
108  rng_alg_ (),
109  rng_dist_ (new boost::uniform_int<> (0, std::numeric_limits<int>::max ())),
110  rng_gen_ ()
111  {
112  if (random)
113  rng_alg_.seed (static_cast<unsigned> (std::time(0)));
114  else
115  rng_alg_.seed (12345u);
116 
117  // Sets the input cloud and creates a vector of "fake" indices
118  setInputCloud (cloud);
119 
120  // Create a random number generator object
121  rng_gen_.reset (new boost::variate_generator<boost::mt19937&, boost::uniform_int<> > (rng_alg_, *rng_dist_));
122  }
123 
129  SampleConsensusModel (const PointCloudConstPtr &cloud, const std::vector<int> &indices, bool random = false) :
130  input_ (cloud),
131  indices_ (new std::vector<int> (indices)),
132  radius_min_ (-std::numeric_limits<double>::max()), radius_max_ (std::numeric_limits<double>::max()), samples_radius_ (0.),
133  shuffled_indices_ (),
134  rng_alg_ (),
135  rng_dist_ (new boost::uniform_int<> (0, std::numeric_limits<int>::max ())),
136  rng_gen_ ()
137  {
138  if (random)
139  rng_alg_.seed (static_cast<unsigned> (std::time(0)));
140  else
141  rng_alg_.seed (12345u);
142 
143  if (indices_->size () > input_->points.size ())
144  {
145  PCL_ERROR ("[pcl::SampleConsensusModel] Invalid index vector given with size %zu while the input PointCloud has size %zu!\n", indices_->size (), input_->points.size ());
146  indices_->clear ();
147  }
148  shuffled_indices_ = *indices_;
149 
150  // Create a random number generator object
151  rng_gen_.reset (new boost::variate_generator<boost::mt19937&, boost::uniform_int<> > (rng_alg_, *rng_dist_));
152  };
153 
155  virtual ~SampleConsensusModel () {};
156 
162  void
163  getSamples (int &iterations, std::vector<int> &samples)
164  {
165  // We're assuming that indices_ have already been set in the constructor
166  if (indices_->size () < getSampleSize ())
167  {
168  PCL_ERROR ("[pcl::SampleConsensusModel::getSamples] Can not select %zu unique points out of %zu!\n",
169  samples.size (), indices_->size ());
170  // one of these will make it stop :)
171  samples.clear ();
172  iterations = INT_MAX - 1;
173  return;
174  }
175 
176  // Get a second point which is different than the first
177  samples.resize (getSampleSize ());
178  for (unsigned int iter = 0; iter < max_sample_checks_; ++iter)
179  {
180  // Choose the random indices
181  if(samples_radius_ < std::numeric_limits<double>::epsilon())
183  else
185 
186  // If it's a good sample, stop here
187  if (isSampleGood (samples))
188  return;
189  }
190  PCL_DEBUG ("[pcl::SampleConsensusModel::getSamples] WARNING: Could not select %d sample points in %d iterations!\n", getSampleSize (), max_sample_checks_);
191  samples.clear ();
192  }
193 
201  virtual bool
202  computeModelCoefficients (const std::vector<int> &samples,
203  Eigen::VectorXf &model_coefficients) = 0;
204 
215  virtual void
216  optimizeModelCoefficients (const std::vector<int> &inliers,
217  const Eigen::VectorXf &model_coefficients,
218  Eigen::VectorXf &optimized_coefficients) = 0;
219 
225  virtual void
226  getDistancesToModel (const Eigen::VectorXf &model_coefficients,
227  std::vector<double> &distances) = 0;
228 
237  virtual void
238  selectWithinDistance (const Eigen::VectorXf &model_coefficients,
239  const double threshold,
240  std::vector<int> &inliers) = 0;
241 
251  virtual int
252  countWithinDistance (const Eigen::VectorXf &model_coefficients,
253  const double threshold) = 0;
254 
263  virtual void
264  projectPoints (const std::vector<int> &inliers,
265  const Eigen::VectorXf &model_coefficients,
266  PointCloud &projected_points,
267  bool copy_data_fields = true) = 0;
268 
277  virtual bool
278  doSamplesVerifyModel (const std::set<int> &indices,
279  const Eigen::VectorXf &model_coefficients,
280  const double threshold) = 0;
281 
285  inline virtual void
287  {
288  input_ = cloud;
289  if (!indices_)
290  indices_.reset (new std::vector<int> ());
291  if (indices_->empty ())
292  {
293  // Prepare a set of indices to be used (entire cloud)
294  indices_->resize (cloud->points.size ());
295  for (size_t i = 0; i < cloud->points.size (); ++i)
296  (*indices_)[i] = static_cast<int> (i);
297  }
298  shuffled_indices_ = *indices_;
299  }
300 
302  inline PointCloudConstPtr
303  getInputCloud () const { return (input_); }
304 
308  inline void
309  setIndices (const boost::shared_ptr <std::vector<int> > &indices)
310  {
311  indices_ = indices;
312  shuffled_indices_ = *indices_;
313  }
314 
318  inline void
319  setIndices (const std::vector<int> &indices)
320  {
321  indices_.reset (new std::vector<int> (indices));
322  shuffled_indices_ = indices;
323  }
324 
326  inline boost::shared_ptr <std::vector<int> >
327  getIndices () const { return (indices_); }
328 
330  virtual SacModel
331  getModelType () const = 0;
332 
334  inline unsigned int
335  getSampleSize () const
336  {
337  std::map<pcl::SacModel, unsigned int>::const_iterator it = SAC_SAMPLE_SIZE.find (getModelType ());
338  if (it == SAC_SAMPLE_SIZE.end ())
339  throw InvalidSACModelTypeException ("No sample size defined for given model type!\n");
340  return (it->second);
341  }
342 
349  inline void
350  setRadiusLimits (const double &min_radius, const double &max_radius)
351  {
352  radius_min_ = min_radius;
353  radius_max_ = max_radius;
354  }
355 
362  inline void
363  getRadiusLimits (double &min_radius, double &max_radius)
364  {
365  min_radius = radius_min_;
366  max_radius = radius_max_;
367  }
368 
372  inline void
373  setSamplesMaxDist (const double &radius, SearchPtr search)
374  {
375  samples_radius_ = radius;
376  samples_radius_search_ = search;
377  }
378 
383  inline void
384  getSamplesMaxDist (double &radius)
385  {
386  radius = samples_radius_;
387  }
388 
390 
391  protected:
395  inline void
396  drawIndexSample (std::vector<int> &sample)
397  {
398  size_t sample_size = sample.size ();
399  size_t index_size = shuffled_indices_.size ();
400  for (unsigned int i = 0; i < sample_size; ++i)
401  // The 1/(RAND_MAX+1.0) trick is when the random numbers are not uniformly distributed and for small modulo
402  // elements, that does not matter (and nowadays, random number generators are good)
403  //std::swap (shuffled_indices_[i], shuffled_indices_[i + (rand () % (index_size - i))]);
404  std::swap (shuffled_indices_[i], shuffled_indices_[i + (rnd () % (index_size - i))]);
405  std::copy (shuffled_indices_.begin (), shuffled_indices_.begin () + sample_size, sample.begin ());
406  }
407 
412  inline void
413  drawIndexSampleRadius (std::vector<int> &sample)
414  {
415  size_t sample_size = sample.size ();
416  size_t index_size = shuffled_indices_.size ();
417 
418  std::swap (shuffled_indices_[0], shuffled_indices_[0 + (rnd () % (index_size - 0))]);
419  //const PointT& pt0 = (*input_)[shuffled_indices_[0]];
420 
421  std::vector<int> indices;
422  std::vector<float> sqr_dists;
423 
424  samples_radius_search_->radiusSearch (shuffled_indices_[0], samples_radius_,
425  indices, sqr_dists );
426 
427  if (indices.size () < sample_size - 1)
428  {
429  // radius search failed, make an invalid model
430  for(unsigned int i = 1; i < sample_size; ++i)
431  shuffled_indices_[i] = shuffled_indices_[0];
432  }
433  else
434  {
435  for (unsigned int i = 0; i < sample_size-1; ++i)
436  std::swap (indices[i], indices[i + (rnd () % (indices.size () - i))]);
437  for (unsigned int i = 1; i < sample_size; ++i)
438  shuffled_indices_[i] = indices[i-1];
439  }
440 
441  std::copy (shuffled_indices_.begin (), shuffled_indices_.begin () + sample_size, sample.begin ());
442  }
443 
447  virtual inline bool
448  isModelValid (const Eigen::VectorXf &model_coefficients) = 0;
449 
454  virtual bool
455  isSampleGood (const std::vector<int> &samples) const = 0;
456 
458  PointCloudConstPtr input_;
459 
461  boost::shared_ptr <std::vector<int> > indices_;
462 
464  static const unsigned int max_sample_checks_ = 1000;
465 
469  double radius_min_, radius_max_;
470 
472  double samples_radius_;
473 
475  SearchPtr samples_radius_search_;
476 
478  std::vector<int> shuffled_indices_;
479 
481  boost::mt19937 rng_alg_;
482 
484  boost::shared_ptr<boost::uniform_int<> > rng_dist_;
485 
487  boost::shared_ptr<boost::variate_generator< boost::mt19937&, boost::uniform_int<> > > rng_gen_;
488 
490  inline int
491  rnd ()
492  {
493  return ((*rng_gen_) ());
494  }
495  public:
496  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
497  };
498 
502  template <typename PointT, typename PointNT>
503  class SampleConsensusModelFromNormals //: public SampleConsensusModel<PointT>
504  {
505  public:
508 
509  typedef boost::shared_ptr<SampleConsensusModelFromNormals> Ptr;
510  typedef boost::shared_ptr<const SampleConsensusModelFromNormals> ConstPtr;
511 
513  SampleConsensusModelFromNormals () : normal_distance_weight_ (0.0), normals_ () {};
514 
517 
523  inline void
524  setNormalDistanceWeight (const double w)
525  {
526  normal_distance_weight_ = w;
527  }
528 
530  inline double
531  getNormalDistanceWeight () { return (normal_distance_weight_); }
532 
538  inline void
540  {
541  normals_ = normals;
542  }
543 
545  inline PointCloudNConstPtr
546  getInputNormals () { return (normals_); }
547 
548  protected:
552  double normal_distance_weight_;
553 
557  PointCloudNConstPtr normals_;
558  };
559 
564  template<typename _Scalar, int NX=Eigen::Dynamic, int NY=Eigen::Dynamic>
565  struct Functor
566  {
567  typedef _Scalar Scalar;
568  enum
569  {
572  };
573 
574  typedef Eigen::Matrix<Scalar,ValuesAtCompileTime,1> ValueType;
575  typedef Eigen::Matrix<Scalar,InputsAtCompileTime,1> InputType;
576  typedef Eigen::Matrix<Scalar,ValuesAtCompileTime,InputsAtCompileTime> JacobianType;
577 
579  Functor () : m_data_points_ (ValuesAtCompileTime) {}
580 
584  Functor (int m_data_points) : m_data_points_ (m_data_points) {}
585 
586  virtual ~Functor () {}
587 
589  int
590  values () const { return (m_data_points_); }
591 
592  private:
593  const int m_data_points_;
594  };
595 }
596 
597 #endif //#ifndef PCL_SAMPLE_CONSENSUS_MODEL_H_