00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
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
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
00118 setInputCloud (cloud);
00119
00120
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
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
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
00171 samples.clear ();
00172 iterations = INT_MAX - 1;
00173 return;
00174 }
00175
00176
00177 samples.resize (getSampleSize ());
00178 for (unsigned int iter = 0; iter < max_sample_checks_; ++iter)
00179 {
00180
00181 if(samples_radius_ < std::numeric_limits<double>::epsilon())
00182 SampleConsensusModel<PointT>::drawIndexSample (samples);
00183 else
00184 SampleConsensusModel<PointT>::drawIndexSampleRadius (samples);
00185
00186
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
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
00402
00403
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
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
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
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_