sac_model.h
Go to the documentation of this file.
00001 /*
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Point Cloud Library (PCL) - www.pointclouds.org
00005  *  Copyright (c) 2010-2011, Willow Garage, Inc.
00006  *  
00007  *  All rights reserved.
00008  *
00009  *  Redistribution and use in source and binary forms, with or without
00010  *  modification, are permitted provided that the following conditions
00011  *  are met:
00012  *
00013  *   * Redistributions of source code must retain the above copyright
00014  *     notice, this list of conditions and the following disclaimer.
00015  *   * Redistributions in binary form must reproduce the above
00016  *     copyright notice, this list of conditions and the following
00017  *     disclaimer in the documentation and/or other materials provided
00018  *     with the distribution.
00019  *   * Neither the name of Willow Garage, Inc. nor the names of its
00020  *     contributors may be used to endorse or promote products derived
00021  *     from this software without specific prior written permission.
00022  *
00023  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00024  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00025  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00026  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00027  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00028  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00029  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00030  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00031  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00032  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00033  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00034  *  POSSIBILITY OF SUCH DAMAGE.
00035  *
00036  * $Id: sac_model.h 6214 2012-07-06 19:31:29Z rusu $
00037  *
00038  */
00039 
00040 #ifndef PCL_SAMPLE_CONSENSUS_MODEL_H_
00041 #define PCL_SAMPLE_CONSENSUS_MODEL_H_
00042 
00043 #include <cfloat>
00044 #include <ctime>
00045 #include <limits.h>
00046 #include <set>
00047 #include <boost/random.hpp>
00048 
00049 #include <pcl/console/print.h>
00050 #include <pcl/point_cloud.h>
00051 #include <pcl/sample_consensus/model_types.h>
00052 
00053 #include <pcl/search/search.h>
00054 
00055 namespace pcl
00056 {
00057   template<class T> class ProgressiveSampleConsensus;
00058 
00064   template <typename PointT>
00065   class SampleConsensusModel
00066   {
00067     public:
00068       typedef typename pcl::PointCloud<PointT> PointCloud;
00069       typedef typename pcl::PointCloud<PointT>::ConstPtr PointCloudConstPtr;
00070       typedef typename pcl::PointCloud<PointT>::Ptr PointCloudPtr;
00071       typedef typename pcl::search::Search<PointT>::Ptr SearchPtr;
00072 
00073       typedef boost::shared_ptr<SampleConsensusModel> Ptr;
00074       typedef boost::shared_ptr<const SampleConsensusModel> ConstPtr;
00075 
00076     protected:
00080       SampleConsensusModel (bool random = false) : 
00081         input_ (),
00082         indices_ (),
00083         radius_min_ (-std::numeric_limits<double>::max()), radius_max_ (std::numeric_limits<double>::max()), samples_radius_ (0.),
00084         shuffled_indices_ (),
00085         rng_alg_ (),
00086         rng_dist_ (new boost::uniform_int<> (0, std::numeric_limits<int>::max ())),
00087         rng_gen_ ()
00088       {
00089         // Create a random number generator object
00090         if (random)
00091           rng_alg_.seed (static_cast<unsigned> (std::time(0)));
00092         else
00093           rng_alg_.seed (12345u);
00094 
00095         rng_gen_.reset (new boost::variate_generator<boost::mt19937&, boost::uniform_int<> > (rng_alg_, *rng_dist_)); 
00096        }
00097 
00098     public:
00103       SampleConsensusModel (const PointCloudConstPtr &cloud, bool random = false) : 
00104         input_ (),
00105         indices_ (),
00106         radius_min_ (-std::numeric_limits<double>::max()), radius_max_ (std::numeric_limits<double>::max()), samples_radius_ (0.),
00107         shuffled_indices_ (),
00108         rng_alg_ (),
00109         rng_dist_ (new boost::uniform_int<> (0, std::numeric_limits<int>::max ())),
00110         rng_gen_ ()
00111       {
00112         if (random)
00113           rng_alg_.seed (static_cast<unsigned> (std::time(0)));
00114         else
00115           rng_alg_.seed (12345u);
00116 
00117         // Sets the input cloud and creates a vector of "fake" indices
00118         setInputCloud (cloud);
00119 
00120         // Create a random number generator object
00121         rng_gen_.reset (new boost::variate_generator<boost::mt19937&, boost::uniform_int<> > (rng_alg_, *rng_dist_)); 
00122        }
00123 
00129       SampleConsensusModel (const PointCloudConstPtr &cloud, const std::vector<int> &indices, bool random = false) :
00130                             input_ (cloud),
00131                             indices_ (new std::vector<int> (indices)),
00132                             radius_min_ (-std::numeric_limits<double>::max()), radius_max_ (std::numeric_limits<double>::max()), samples_radius_ (0.),
00133                             shuffled_indices_ (),
00134                             rng_alg_ (),
00135                             rng_dist_ (new boost::uniform_int<> (0, std::numeric_limits<int>::max ())),
00136                             rng_gen_ ()
00137       {
00138         if (random)
00139           rng_alg_.seed (static_cast<unsigned> (std::time(0)));
00140         else
00141           rng_alg_.seed (12345u);
00142 
00143         if (indices_->size () > input_->points.size ())
00144         {
00145           PCL_ERROR ("[pcl::SampleConsensusModel] Invalid index vector given with size %zu while the input PointCloud has size %zu!\n", indices_->size (), input_->points.size ());
00146           indices_->clear ();
00147         }
00148         shuffled_indices_ = *indices_;
00149 
00150         // Create a random number generator object
00151         rng_gen_.reset (new boost::variate_generator<boost::mt19937&, boost::uniform_int<> > (rng_alg_, *rng_dist_)); 
00152        };
00153 
00155       virtual ~SampleConsensusModel () {};
00156 
00162       void 
00163       getSamples (int &iterations, std::vector<int> &samples)
00164       {
00165         // We're assuming that indices_ have already been set in the constructor
00166         if (indices_->size () < getSampleSize ())
00167         {
00168           PCL_ERROR ("[pcl::SampleConsensusModel::getSamples] Can not select %zu unique points out of %zu!\n",
00169                      samples.size (), indices_->size ());
00170           // one of these will make it stop :)
00171           samples.clear ();
00172           iterations = INT_MAX - 1;
00173           return;
00174         }
00175 
00176         // Get a second point which is different than the first
00177         samples.resize (getSampleSize ());
00178         for (unsigned int iter = 0; iter < max_sample_checks_; ++iter)
00179         {
00180           // Choose the random indices
00181           if(samples_radius_ < std::numeric_limits<double>::epsilon())
00182                   SampleConsensusModel<PointT>::drawIndexSample (samples);
00183           else
00184                   SampleConsensusModel<PointT>::drawIndexSampleRadius (samples);
00185 
00186           // If it's a good sample, stop here
00187           if (isSampleGood (samples))
00188             return;
00189         }
00190         PCL_DEBUG ("[pcl::SampleConsensusModel::getSamples] WARNING: Could not select %d sample points in %d iterations!\n", getSampleSize (), max_sample_checks_);
00191         samples.clear ();
00192       }
00193 
00201       virtual bool 
00202       computeModelCoefficients (const std::vector<int> &samples, 
00203                                 Eigen::VectorXf &model_coefficients) = 0;
00204 
00215       virtual void 
00216       optimizeModelCoefficients (const std::vector<int> &inliers, 
00217                                  const Eigen::VectorXf &model_coefficients,
00218                                  Eigen::VectorXf &optimized_coefficients) = 0;
00219 
00225       virtual void 
00226       getDistancesToModel (const Eigen::VectorXf &model_coefficients, 
00227                            std::vector<double> &distances) = 0;
00228 
00237       virtual void 
00238       selectWithinDistance (const Eigen::VectorXf &model_coefficients, 
00239                             const double threshold,
00240                             std::vector<int> &inliers) = 0;
00241 
00251       virtual int
00252       countWithinDistance (const Eigen::VectorXf &model_coefficients, 
00253                            const double threshold) = 0;
00254 
00263       virtual void 
00264       projectPoints (const std::vector<int> &inliers, 
00265                      const Eigen::VectorXf &model_coefficients,
00266                      PointCloud &projected_points, 
00267                      bool copy_data_fields = true) = 0;
00268 
00277       virtual bool 
00278       doSamplesVerifyModel (const std::set<int> &indices, 
00279                             const Eigen::VectorXf &model_coefficients, 
00280                             const double threshold) = 0;
00281 
00285       inline virtual void
00286       setInputCloud (const PointCloudConstPtr &cloud)
00287       {
00288         input_ = cloud;
00289         if (!indices_)
00290           indices_.reset (new std::vector<int> ());
00291         if (indices_->empty ())
00292         {
00293           // Prepare a set of indices to be used (entire cloud)
00294           indices_->resize (cloud->points.size ());
00295           for (size_t i = 0; i < cloud->points.size (); ++i) 
00296             (*indices_)[i] = static_cast<int> (i);
00297         }
00298         shuffled_indices_ = *indices_;
00299        }
00300 
00302       inline PointCloudConstPtr 
00303       getInputCloud () const { return (input_); }
00304 
00308       inline void 
00309       setIndices (const boost::shared_ptr <std::vector<int> > &indices) 
00310       { 
00311         indices_ = indices; 
00312         shuffled_indices_ = *indices_;
00313        }
00314 
00318       inline void 
00319       setIndices (const std::vector<int> &indices) 
00320       { 
00321         indices_.reset (new std::vector<int> (indices));
00322         shuffled_indices_ = indices;
00323        }
00324 
00326       inline boost::shared_ptr <std::vector<int> > 
00327       getIndices () const { return (indices_); }
00328 
00330       virtual SacModel 
00331       getModelType () const = 0;
00332 
00334       inline unsigned int 
00335       getSampleSize () const 
00336       { 
00337         std::map<pcl::SacModel, unsigned int>::const_iterator it = SAC_SAMPLE_SIZE.find (getModelType ());
00338         if (it == SAC_SAMPLE_SIZE.end ())
00339           throw InvalidSACModelTypeException ("No sample size defined for given model type!\n");
00340         return (it->second);
00341       }
00342 
00349       inline void
00350       setRadiusLimits (const double &min_radius, const double &max_radius)
00351       {
00352         radius_min_ = min_radius;
00353         radius_max_ = max_radius;
00354       }
00355 
00362       inline void
00363       getRadiusLimits (double &min_radius, double &max_radius)
00364       {
00365         min_radius = radius_min_;
00366         max_radius = radius_max_;
00367       }
00368       
00372       inline void
00373       setSamplesMaxDist (const double &radius, SearchPtr search)
00374       {
00375         samples_radius_ = radius;
00376         samples_radius_search_ = search;
00377       }
00378 
00383       inline void
00384       getSamplesMaxDist (double &radius)
00385       {
00386         radius = samples_radius_;
00387       }
00388 
00389       friend class ProgressiveSampleConsensus<PointT>;
00390 
00391                 protected:
00395       inline void
00396       drawIndexSample (std::vector<int> &sample)
00397       {
00398         size_t sample_size = sample.size ();
00399         size_t index_size = shuffled_indices_.size ();
00400         for (unsigned int i = 0; i < sample_size; ++i)
00401           // The 1/(RAND_MAX+1.0) trick is when the random numbers are not uniformly distributed and for small modulo
00402           // elements, that does not matter (and nowadays, random number generators are good)
00403           //std::swap (shuffled_indices_[i], shuffled_indices_[i + (rand () % (index_size - i))]);
00404           std::swap (shuffled_indices_[i], shuffled_indices_[i + (rnd () % (index_size - i))]);
00405         std::copy (shuffled_indices_.begin (), shuffled_indices_.begin () + sample_size, sample.begin ());
00406       }
00407 
00412       inline void
00413       drawIndexSampleRadius (std::vector<int> &sample)
00414       {
00415         size_t sample_size = sample.size ();
00416         size_t index_size = shuffled_indices_.size ();
00417 
00418         std::swap (shuffled_indices_[0], shuffled_indices_[0 + (rnd () % (index_size - 0))]);
00419         //const PointT& pt0 = (*input_)[shuffled_indices_[0]];
00420 
00421         std::vector<int> indices;
00422         std::vector<float> sqr_dists;
00423 
00424         samples_radius_search_->radiusSearch (shuffled_indices_[0], samples_radius_,
00425                                               indices, sqr_dists );
00426 
00427         if (indices.size () < sample_size - 1)
00428         {
00429           // radius search failed, make an invalid model
00430           for(unsigned int i = 1; i < sample_size; ++i)
00431                 shuffled_indices_[i] = shuffled_indices_[0];
00432         }
00433         else
00434         {
00435           for (unsigned int i = 0; i < sample_size-1; ++i)
00436             std::swap (indices[i], indices[i + (rnd () % (indices.size () - i))]);
00437           for (unsigned int i = 1; i < sample_size; ++i)
00438             shuffled_indices_[i] = indices[i-1];
00439         }
00440 
00441         std::copy (shuffled_indices_.begin (), shuffled_indices_.begin () + sample_size, sample.begin ());
00442       }
00443 
00447       virtual inline bool
00448       isModelValid (const Eigen::VectorXf &model_coefficients) = 0;
00449 
00454       virtual bool
00455       isSampleGood (const std::vector<int> &samples) const = 0;
00456 
00458       PointCloudConstPtr input_;
00459 
00461       boost::shared_ptr <std::vector<int> > indices_;
00462 
00464       static const unsigned int max_sample_checks_ = 1000;
00465 
00469       double radius_min_, radius_max_;
00470 
00472       double samples_radius_;
00473 
00475       SearchPtr samples_radius_search_;
00476 
00478       std::vector<int> shuffled_indices_;
00479 
00481       boost::mt19937 rng_alg_;
00482 
00484       boost::shared_ptr<boost::uniform_int<> > rng_dist_;
00485 
00487       boost::shared_ptr<boost::variate_generator< boost::mt19937&, boost::uniform_int<> > > rng_gen_;
00488 
00490       inline int
00491       rnd ()
00492       {
00493         return ((*rng_gen_) ());
00494       }
00495     public:
00496       EIGEN_MAKE_ALIGNED_OPERATOR_NEW
00497  };
00498 
00502   template <typename PointT, typename PointNT>
00503   class SampleConsensusModelFromNormals //: public SampleConsensusModel<PointT>
00504   {
00505     public:
00506       typedef typename pcl::PointCloud<PointNT>::ConstPtr PointCloudNConstPtr;
00507       typedef typename pcl::PointCloud<PointNT>::Ptr PointCloudNPtr;
00508 
00509       typedef boost::shared_ptr<SampleConsensusModelFromNormals> Ptr;
00510       typedef boost::shared_ptr<const SampleConsensusModelFromNormals> ConstPtr;
00511 
00513       SampleConsensusModelFromNormals () : normal_distance_weight_ (0.0), normals_ () {};
00514 
00516       virtual ~SampleConsensusModelFromNormals () {}
00517 
00523       inline void 
00524       setNormalDistanceWeight (const double w) 
00525       { 
00526         normal_distance_weight_ = w; 
00527       }
00528 
00530       inline double 
00531       getNormalDistanceWeight () { return (normal_distance_weight_); }
00532 
00538       inline void 
00539       setInputNormals (const PointCloudNConstPtr &normals) 
00540       { 
00541         normals_ = normals; 
00542       }
00543 
00545       inline PointCloudNConstPtr 
00546       getInputNormals () { return (normals_); }
00547 
00548     protected:
00552       double normal_distance_weight_;
00553 
00557       PointCloudNConstPtr normals_;
00558   };
00559 
00564   template<typename _Scalar, int NX=Eigen::Dynamic, int NY=Eigen::Dynamic>
00565   struct Functor
00566   {
00567     typedef _Scalar Scalar;
00568     enum 
00569     {
00570       InputsAtCompileTime = NX,
00571       ValuesAtCompileTime = NY
00572     };
00573 
00574     typedef Eigen::Matrix<Scalar,ValuesAtCompileTime,1> ValueType;
00575     typedef Eigen::Matrix<Scalar,InputsAtCompileTime,1> InputType;
00576     typedef Eigen::Matrix<Scalar,ValuesAtCompileTime,InputsAtCompileTime> JacobianType;
00577 
00579     Functor () : m_data_points_ (ValuesAtCompileTime) {}
00580 
00584     Functor (int m_data_points) : m_data_points_ (m_data_points) {}
00585   
00586     virtual ~Functor () {}
00587 
00589     int
00590     values () const { return (m_data_points_); }
00591 
00592     private:
00593       const int m_data_points_;
00594   };
00595 }
00596 
00597 #endif  //#ifndef PCL_SAMPLE_CONSENSUS_MODEL_H_


pcl
Author(s): Open Perception
autogenerated on Mon Oct 6 2014 03:17:43