Point Cloud Library (PCL)  1.5.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
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 4702 2012-02-23 09:39:33Z gedikli $
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 namespace pcl
00054 {
00055   template<class T> class ProgressiveSampleConsensus;
00056 
00062   template <typename PointT>
00063   class SampleConsensusModel
00064   {
00065     public:
00066       typedef typename pcl::PointCloud<PointT> PointCloud;
00067       typedef typename pcl::PointCloud<PointT>::ConstPtr PointCloudConstPtr;
00068       typedef typename pcl::PointCloud<PointT>::Ptr PointCloudPtr;
00069 
00070       typedef boost::shared_ptr<SampleConsensusModel> Ptr;
00071       typedef boost::shared_ptr<const SampleConsensusModel> ConstPtr;
00072 
00073     private:
00077       SampleConsensusModel (bool random = false) : radius_min_ (-DBL_MAX), radius_max_ (DBL_MAX) 
00078       {
00079         // Create a random number generator object
00080         if (random)
00081           rng_alg_.seed (static_cast<unsigned> (std::time(0)));
00082         else
00083           rng_alg_.seed (12345u);
00084 
00085         rng_dist_.reset (new boost::uniform_int<> (0, std::numeric_limits<int>::max ()));
00086         rng_gen_.reset (new boost::variate_generator<boost::mt19937&, boost::uniform_int<> > (rng_alg_, *rng_dist_)); 
00087        }
00088 
00089     public:
00094       SampleConsensusModel (const PointCloudConstPtr &cloud, bool random = false) : 
00095         radius_min_ (-DBL_MAX), radius_max_ (DBL_MAX)
00096       {
00097         if (random)
00098           rng_alg_.seed (static_cast<unsigned> (std::time(0)));
00099         else
00100           rng_alg_.seed (12345u);
00101 
00102         // Sets the input cloud and creates a vector of "fake" indices
00103         setInputCloud (cloud);
00104 
00105         // Create a random number generator object
00106         rng_dist_.reset (new boost::uniform_int<> (0, std::numeric_limits<int>::max ()));
00107         rng_gen_.reset (new boost::variate_generator<boost::mt19937&, boost::uniform_int<> > (rng_alg_, *rng_dist_)); 
00108        }
00109 
00115       SampleConsensusModel (const PointCloudConstPtr &cloud, const std::vector<int> &indices, bool random = false) :
00116                             input_ (cloud),
00117                             radius_min_ (-DBL_MAX), radius_max_ (DBL_MAX) 
00118     
00119       {
00120         if (random)
00121           rng_alg_.seed (static_cast<unsigned> (std::time(0)));
00122         else
00123           rng_alg_.seed (12345u);
00124 
00125         indices_.reset (new std::vector<int> (indices));
00126         if (indices_->size () > input_->points.size ())
00127         {
00128           PCL_ERROR ("[pcl::SampleConsensusModel] Invalid index vector given with size %lu while the input PointCloud has size %lu!\n", (unsigned long)indices_->size (), (unsigned long)input_->points.size ());
00129           indices_->clear ();
00130         }
00131         shuffled_indices_ = *indices_;
00132 
00133         // Create a random number generator object
00134         rng_dist_.reset (new boost::uniform_int<> (0, std::numeric_limits<int>::max ()));
00135         rng_gen_.reset (new boost::variate_generator<boost::mt19937&, boost::uniform_int<> > (rng_alg_, *rng_dist_)); 
00136        };
00137 
00139       virtual ~SampleConsensusModel () {};
00140 
00146       void 
00147       getSamples (int &iterations, std::vector<int> &samples)
00148       {
00149         // We're assuming that indices_ have already been set in the constructor
00150         if (indices_->size () < getSampleSize ())
00151         {
00152           PCL_ERROR ("[pcl::SampleConsensusModel::getSamples] Can not select %lu unique points out of %lu!\n",
00153                      (unsigned long)samples.size (), (unsigned long)indices_->size ());
00154           // one of these will make it stop :)
00155           samples.clear ();
00156           iterations = INT_MAX - 1;
00157           return;
00158         }
00159 
00160         // Get a second point which is different than the first
00161         samples.resize (getSampleSize());
00162         for (unsigned int iter = 0; iter < max_sample_checks_; ++iter)
00163         {
00164           // Choose the random indices
00165           SampleConsensusModel<PointT>::drawIndexSample (samples);
00166 
00167           // If it's a good sample, stop here
00168           if (isSampleGood (samples))
00169             return;
00170         }
00171         PCL_DEBUG ("[pcl::SampleConsensusModel::getSamples] WARNING: Could not select %d sample points in %d iterations!\n", getSampleSize (), max_sample_checks_);
00172         samples.clear ();
00173       }
00174 
00182       virtual bool 
00183       computeModelCoefficients (const std::vector<int> &samples, 
00184                                 Eigen::VectorXf &model_coefficients) = 0;
00185 
00196       virtual void 
00197       optimizeModelCoefficients (const std::vector<int> &inliers, 
00198                                  const Eigen::VectorXf &model_coefficients,
00199                                  Eigen::VectorXf &optimized_coefficients) = 0;
00200 
00206       virtual void 
00207       getDistancesToModel (const Eigen::VectorXf &model_coefficients, 
00208                            std::vector<double> &distances) = 0;
00209 
00218       virtual void 
00219       selectWithinDistance (const Eigen::VectorXf &model_coefficients, 
00220                             const double threshold,
00221                             std::vector<int> &inliers) = 0;
00222 
00232       virtual int
00233       countWithinDistance (const Eigen::VectorXf &model_coefficients, 
00234                            const double threshold) = 0;
00235 
00244       virtual void 
00245       projectPoints (const std::vector<int> &inliers, 
00246                      const Eigen::VectorXf &model_coefficients,
00247                      PointCloud &projected_points, 
00248                      bool copy_data_fields = true) = 0;
00249 
00258       virtual bool 
00259       doSamplesVerifyModel (const std::set<int> &indices, 
00260                             const Eigen::VectorXf &model_coefficients, 
00261                             const double threshold) = 0;
00262 
00266       inline virtual void
00267       setInputCloud (const PointCloudConstPtr &cloud)
00268       {
00269         input_ = cloud;
00270         if (!indices_)
00271           indices_.reset (new std::vector<int> ());
00272         if (indices_->empty ())
00273         {
00274           // Prepare a set of indices to be used (entire cloud)
00275           indices_->resize (cloud->points.size ());
00276           for (size_t i = 0; i < cloud->points.size (); ++i) 
00277             (*indices_)[i] = (int) i;
00278         }
00279         shuffled_indices_ = *indices_;
00280        }
00281 
00283       inline PointCloudConstPtr 
00284       getInputCloud () const { return (input_); }
00285 
00289       inline void 
00290       setIndices (const boost::shared_ptr <std::vector<int> > &indices) 
00291       { 
00292         indices_ = indices; 
00293         shuffled_indices_ = *indices_;
00294        }
00295 
00299       inline void 
00300       setIndices (const std::vector<int> &indices) 
00301       { 
00302         indices_.reset (new std::vector<int> (indices));
00303         shuffled_indices_ = indices;
00304        }
00305 
00307       inline boost::shared_ptr <std::vector<int> > 
00308       getIndices () const { return (indices_); }
00309 
00311       virtual SacModel 
00312       getModelType () const = 0;
00313 
00315       inline unsigned int 
00316       getSampleSize () const 
00317       { 
00318         std::map<pcl::SacModel, unsigned int>::const_iterator it = SAC_SAMPLE_SIZE.find (getModelType ());
00319         if (it == SAC_SAMPLE_SIZE.end ())
00320           throw InvalidSACModelTypeException ("No sample size defined for given model type!\n");
00321         return (it->second);
00322       }
00323 
00330       inline void
00331       setRadiusLimits (const double &min_radius, const double &max_radius)
00332       {
00333         radius_min_ = min_radius;
00334         radius_max_ = max_radius;
00335       }
00336 
00343       inline void
00344       getRadiusLimits (double &min_radius, double &max_radius)
00345       {
00346         min_radius = radius_min_;
00347         max_radius = radius_max_;
00348       }
00349       
00350       friend class ProgressiveSampleConsensus<PointT>;
00351 
00352     protected:
00356       inline void
00357       drawIndexSample (std::vector<int> &sample)
00358       {
00359         size_t sample_size = sample.size ();
00360         size_t index_size = shuffled_indices_.size ();
00361         for (unsigned int i = 0; i < sample_size; ++i)
00362           // The 1/(RAND_MAX+1.0) trick is when the random numbers are not uniformly distributed and for small modulo
00363           // elements, that does not matter (and nowadays, random number generators are good)
00364           //std::swap (shuffled_indices_[i], shuffled_indices_[i + (rand () % (index_size - i))]);
00365           std::swap (shuffled_indices_[i], shuffled_indices_[i + (rnd () % (index_size - i))]);
00366         std::copy (shuffled_indices_.begin (), shuffled_indices_.begin () + sample_size, sample.begin ());
00367       }
00368 
00372       virtual inline bool
00373       isModelValid (const Eigen::VectorXf &model_coefficients) = 0;
00374 
00379       virtual bool
00380       isSampleGood (const std::vector<int> &samples) const = 0;
00381 
00383       PointCloudConstPtr input_;
00384 
00386       boost::shared_ptr <std::vector<int> > indices_;
00387 
00389       static const unsigned int max_sample_checks_ = 1000;
00390 
00394       double radius_min_, radius_max_;
00395 
00397       std::vector<int> shuffled_indices_;
00398 
00400       boost::mt19937 rng_alg_;
00401 
00403       boost::shared_ptr<boost::uniform_int<> > rng_dist_;
00404 
00406       boost::shared_ptr<boost::variate_generator< boost::mt19937&, boost::uniform_int<> > > rng_gen_;
00407 
00409       inline int
00410       rnd ()
00411       {
00412         return ((*rng_gen_) ());
00413       }
00414     public:
00415       EIGEN_MAKE_ALIGNED_OPERATOR_NEW
00416  };
00417 
00421   template <typename PointT, typename PointNT>
00422   class SampleConsensusModelFromNormals //: public SampleConsensusModel<PointT>
00423   {
00424     public:
00425       typedef typename pcl::PointCloud<PointNT>::ConstPtr PointCloudNConstPtr;
00426       typedef typename pcl::PointCloud<PointNT>::Ptr PointCloudNPtr;
00427 
00428       typedef boost::shared_ptr<SampleConsensusModelFromNormals> Ptr;
00429       typedef boost::shared_ptr<const SampleConsensusModelFromNormals> ConstPtr;
00430 
00432       SampleConsensusModelFromNormals () : normal_distance_weight_ (0.0) {};
00433 
00439       inline void 
00440       setNormalDistanceWeight (const double w) 
00441       { 
00442         normal_distance_weight_ = w; 
00443       }
00444 
00446       inline double 
00447       getNormalDistanceWeight () { return (normal_distance_weight_); }
00448 
00454       inline void 
00455       setInputNormals (const PointCloudNConstPtr &normals) 
00456       { 
00457         normals_ = normals; 
00458       }
00459 
00461       inline PointCloudNConstPtr 
00462       getInputNormals () { return (normals_); }
00463 
00464     protected:
00468       double normal_distance_weight_;
00469 
00473       PointCloudNConstPtr normals_;
00474   };
00475 
00480   template<typename _Scalar, int NX=Eigen::Dynamic, int NY=Eigen::Dynamic>
00481   struct Functor
00482   {
00483     typedef _Scalar Scalar;
00484     enum 
00485     {
00486       InputsAtCompileTime = NX,
00487       ValuesAtCompileTime = NY
00488     };
00489 
00490     typedef Eigen::Matrix<Scalar,ValuesAtCompileTime,1> ValueType;
00491     typedef Eigen::Matrix<Scalar,InputsAtCompileTime,1> InputType;
00492     typedef Eigen::Matrix<Scalar,ValuesAtCompileTime,InputsAtCompileTime> JacobianType;
00493 
00495     Functor () : m_data_points_ (ValuesAtCompileTime) {}
00496 
00500     Functor (int m_data_points) : m_data_points_ (m_data_points) {}
00501   
00503     int
00504     values () const { return (m_data_points_); }
00505 
00506     private:
00507       const int m_data_points_;
00508   };
00509 }
00510 
00511 #endif  //#ifndef PCL_SAMPLE_CONSENSUS_MODEL_H_