|
Point Cloud Library (PCL)
1.6.0
|
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_
1.7.6.1