kdtree_flann.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-2012, 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: kdtree_flann.h 6024 2012-06-26 05:31:03Z rusu $
00037  *
00038  */
00039 
00040 #ifndef PCL_KDTREE_KDTREE_FLANN_H_
00041 #define PCL_KDTREE_KDTREE_FLANN_H_
00042 
00043 #include <cstdio>
00044 #include <pcl/point_representation.h>
00045 #include <pcl/kdtree/kdtree.h>
00046 #include <pcl/kdtree/flann.h>
00047 
00048 namespace pcl
00049 {
00056   template <typename PointT, typename Dist = flann::L2_Simple<float> >
00057   class KdTreeFLANN : public pcl::KdTree<PointT>
00058   {
00059     public:
00060       using KdTree<PointT>::input_;
00061       using KdTree<PointT>::indices_;
00062       using KdTree<PointT>::epsilon_;
00063       using KdTree<PointT>::sorted_;
00064       using KdTree<PointT>::point_representation_;
00065       using KdTree<PointT>::nearestKSearch;
00066       using KdTree<PointT>::radiusSearch;
00067 
00068       typedef typename KdTree<PointT>::PointCloud PointCloud;
00069       typedef typename KdTree<PointT>::PointCloudConstPtr PointCloudConstPtr;
00070 
00071       typedef boost::shared_ptr<std::vector<int> > IndicesPtr;
00072       typedef boost::shared_ptr<const std::vector<int> > IndicesConstPtr;
00073 
00074       typedef flann::Index<Dist> FLANNIndex;
00075 
00076       // Boost shared pointers
00077       typedef boost::shared_ptr<KdTreeFLANN<PointT> > Ptr;
00078       typedef boost::shared_ptr<const KdTreeFLANN<PointT> > ConstPtr;
00079 
00085       KdTreeFLANN (bool sorted = true) : 
00086         pcl::KdTree<PointT> (sorted), 
00087         flann_index_ (NULL), cloud_ (NULL), 
00088         index_mapping_ (), identity_mapping_ (false),
00089         dim_ (0), total_nr_points_ (0),
00090         param_k_ (flann::SearchParams (-1 , epsilon_)),
00091         param_radius_ (flann::SearchParams (-1, epsilon_, sorted))
00092       {
00093       }
00094 
00098       KdTreeFLANN (const KdTreeFLANN<PointT> &k) : 
00099         pcl::KdTree<PointT> (false), 
00100         flann_index_ (NULL), cloud_ (NULL), 
00101         index_mapping_ (), identity_mapping_ (false),
00102         dim_ (0), total_nr_points_ (0),
00103         param_k_ (flann::SearchParams (-1 , epsilon_)),
00104         param_radius_ (flann::SearchParams (-1, epsilon_, false))
00105       {
00106         *this = k;
00107       }
00108 
00112       inline KdTreeFLANN<PointT>&
00113       operator = (const KdTreeFLANN<PointT>& k)
00114       {
00115         KdTree<PointT>::operator=(k);
00116         flann_index_ = k.flann_index_;
00117         cloud_ = k.cloud_;
00118         index_mapping_ = k.index_mapping_;
00119         identity_mapping_ = k.identity_mapping_;
00120         dim_ = k.dim_;
00121         total_nr_points_ = k.total_nr_points_;
00122         param_k_ = k.param_k_;
00123         param_radius_ = k.param_radius_;
00124         return (*this);
00125       }
00126 
00130       inline void
00131       setEpsilon (float eps)
00132       {
00133         epsilon_ = eps;
00134         param_k_ = flann::SearchParams (-1 , epsilon_);
00135         param_radius_ = flann::SearchParams (-1 , epsilon_, sorted_);
00136       }
00137 
00138       inline void 
00139       setSortedResults (bool sorted)
00140       {
00141         sorted_ = sorted;
00142         param_k_ = flann::SearchParams (-1, epsilon_);
00143         param_radius_ = flann::SearchParams (-1, epsilon_, sorted_);
00144       }
00145       
00146       inline Ptr makeShared () { return Ptr (new KdTreeFLANN<PointT> (*this)); } 
00147 
00151       virtual ~KdTreeFLANN ()
00152       {
00153         cleanup ();
00154       }
00155 
00160       void 
00161       setInputCloud (const PointCloudConstPtr &cloud, const IndicesConstPtr &indices = IndicesConstPtr ());
00162 
00177       int 
00178       nearestKSearch (const PointT &point, int k, 
00179                       std::vector<int> &k_indices, std::vector<float> &k_sqr_distances) const;
00180 
00197       int 
00198       radiusSearch (const PointT &point, double radius, std::vector<int> &k_indices,
00199                     std::vector<float> &k_sqr_distances, unsigned int max_nn = 0) const;
00200 
00201     private:
00203       void 
00204       cleanup ();
00205 
00210       void 
00211       convertCloudToArray (const PointCloud &cloud);
00212 
00218       void 
00219       convertCloudToArray (const PointCloud &cloud, const std::vector<int> &indices);
00220 
00221     private:
00223       virtual std::string 
00224       getName () const { return ("KdTreeFLANN"); }
00225 
00227       FLANNIndex* flann_index_;
00228 
00230       float* cloud_;
00231       
00233       std::vector<int> index_mapping_;
00234       
00236       bool identity_mapping_;
00237 
00239       int dim_;
00240 
00242       int total_nr_points_;
00243 
00245       flann::SearchParams param_k_;
00246 
00248       flann::SearchParams param_radius_;
00249   };
00250 
00257   template <>
00258   class KdTreeFLANN <Eigen::MatrixXf>
00259   {
00260     public:
00261       typedef pcl::PointCloud<Eigen::MatrixXf> PointCloud;
00262       typedef PointCloud::ConstPtr PointCloudConstPtr;
00263 
00264       typedef boost::shared_ptr<std::vector<int> > IndicesPtr;
00265       typedef boost::shared_ptr<const std::vector<int> > IndicesConstPtr;
00266 
00267       typedef flann::Index<flann::L2_Simple<float> > FLANNIndex;
00268 
00269       typedef pcl::PointRepresentation<Eigen::MatrixXf> PointRepresentation;
00270       typedef boost::shared_ptr<const PointRepresentation> PointRepresentationConstPtr;
00271 
00272       // Boost shared pointers
00273       typedef boost::shared_ptr<KdTreeFLANN<Eigen::MatrixXf> > Ptr;
00274       typedef boost::shared_ptr<const KdTreeFLANN<Eigen::MatrixXf> > ConstPtr;
00275 
00281       KdTreeFLANN (bool sorted = true) : 
00282         input_(), indices_(), epsilon_(0.0f), sorted_(sorted), flann_index_(NULL), cloud_(NULL),
00283         index_mapping_ (), identity_mapping_ (false), dim_ (0), 
00284         param_k_ (flann::SearchParams (-1, epsilon_)),
00285         param_radius_ (flann::SearchParams (-1, epsilon_, sorted)),
00286         total_nr_points_ (0)
00287       {
00288         cleanup ();
00289       }
00290 
00294       KdTreeFLANN (const KdTreeFLANN<Eigen::MatrixXf> &k) : 
00295         input_(), indices_(), epsilon_(0.0f), sorted_(false), flann_index_(NULL), cloud_(NULL),
00296         index_mapping_ (), identity_mapping_ (false), dim_ (0), 
00297         param_k_ (flann::SearchParams (-1, epsilon_)),
00298         param_radius_ (flann::SearchParams (-1, epsilon_, sorted_)),
00299         total_nr_points_ (0)
00300       {
00301         *this = k;
00302       }
00303 
00307       inline KdTreeFLANN&
00308       operator = (const KdTreeFLANN<Eigen::MatrixXf>& k)
00309       {
00310         input_ = k.input_;
00311         indices_ = k.indices_;
00312         epsilon_ = k.epsilon_;
00313         sorted_ = k.sorted_;
00314         flann_index_ = k.flann_index_;
00315         cloud_ = k.cloud_;
00316         index_mapping_ = k.index_mapping_;
00317         identity_mapping_ = k.identity_mapping_;
00318         dim_ = k.dim_;
00319         param_k_ = k.param_k_;
00320         param_radius_ = k.param_radius_;
00321         total_nr_points_ = k.total_nr_points_;
00322         return (*this);
00323       }
00324 
00328       inline void
00329       setEpsilon (float eps)
00330       {
00331         epsilon_ = eps;
00332         param_k_ = flann::SearchParams (-1 , epsilon_);
00333         param_radius_ = flann::SearchParams (-1, epsilon_, sorted_);
00334       }
00335 
00336       inline Ptr 
00337       makeShared () { return Ptr (new KdTreeFLANN<Eigen::MatrixXf> (*this)); } 
00338 
00342       virtual ~KdTreeFLANN ()
00343       {
00344         cleanup ();
00345       }
00346 
00351       void 
00352       setInputCloud (const PointCloudConstPtr &cloud, const IndicesConstPtr &indices = IndicesConstPtr ())
00353       {
00354         cleanup ();   // Perform an automatic cleanup of structures
00355 
00356         if (cloud == NULL)
00357           return;
00358 
00359         epsilon_ = 0.0f;   // default error bound value
00360         input_   = cloud;
00361         indices_ = indices;
00362         dim_ = static_cast<int> (cloud->points.cols ()); // Number of dimensions = number of columns in the eigen matrix
00363         
00364         // Allocate enough data
00365         if (indices != NULL)
00366         {
00367           total_nr_points_ = static_cast<int> (indices_->size ());
00368           convertCloudToArray (*input_, *indices_);
00369         }
00370         else
00371         {
00372           // get the number of points as the number of rows
00373           total_nr_points_ = static_cast<int> (cloud->points.rows ());
00374           convertCloudToArray (*input_);
00375         }
00376 
00377         flann_index_ = new FLANNIndex (flann::Matrix<float> (cloud_, index_mapping_.size (), dim_),
00378                                        flann::KDTreeSingleIndexParams (15)); // max 15 points/leaf
00379         flann_index_->buildIndex ();
00380       }
00381 
00383       inline IndicesConstPtr
00384       getIndices () const
00385       {
00386         return (indices_);
00387       }
00388 
00390       inline PointCloudConstPtr
00391       getInputCloud () const
00392       {
00393         return (input_);
00394       }
00395 
00404       template <typename T> int 
00405       nearestKSearch (const T &point, int k, 
00406                       std::vector<int> &k_indices, std::vector<float> &k_sqr_distances) const
00407       {
00408         assert (isRowValid (point) && "Invalid (NaN, Inf) point coordinates given to nearestKSearch!");
00409 
00410         if (k > total_nr_points_)
00411         {
00412           PCL_ERROR ("[pcl::KdTreeFLANN::nearestKSearch] An invalid number of nearest neighbors was requested! (k = %d out of %d total points).\n", k, total_nr_points_);
00413           k = total_nr_points_;
00414         }
00415 
00416         k_indices.resize (k);
00417         k_sqr_distances.resize (k);
00418 
00419         size_t dim = point.size ();
00420         std::vector<float> query (dim);
00421         for (size_t i = 0; i < dim; ++i)
00422           query[i] = point[i];
00423 
00424         flann::Matrix<int> k_indices_mat (&k_indices[0], 1, k);
00425         flann::Matrix<float> k_distances_mat (&k_sqr_distances[0], 1, k);
00426         // Wrap the k_indices and k_distances vectors (no data copy)
00427         flann_index_->knnSearch (flann::Matrix<float> (&query[0], 1, dim), 
00428                                  k_indices_mat, k_distances_mat,
00429                                  k, param_k_);
00430 
00431         // Do mapping to original point cloud
00432         if (!identity_mapping_) 
00433         {
00434           for (size_t i = 0; i < static_cast<size_t> (k); ++i)
00435           {
00436             int& neighbor_index = k_indices[i];
00437             neighbor_index = index_mapping_[neighbor_index];
00438           }
00439         }
00440 
00441         return (k);
00442       }
00443 
00453       inline int 
00454       nearestKSearch (const PointCloud &cloud, int index, int k, 
00455                       std::vector<int> &k_indices, std::vector<float> &k_sqr_distances) const
00456       {
00457         assert (index >= 0 && index < static_cast<int> (cloud.size ()) && "Out-of-bounds error in nearestKSearch!");
00458         return (nearestKSearch (cloud.points.row (index), k, k_indices, k_sqr_distances));
00459       }
00460 
00470       inline int 
00471       nearestKSearch (int index, int k, 
00472                       std::vector<int> &k_indices, std::vector<float> &k_sqr_distances) const
00473       {
00474         if (indices_ == NULL)
00475         {
00476           assert (index >= 0 && index < static_cast<int> (input_->size ()) && "Out-of-bounds error in nearestKSearch!");
00477           return (nearestKSearch (input_->points.row (index), k, k_indices, k_sqr_distances));
00478         }
00479         else
00480         {
00481           assert (index >= 0 && index < static_cast<int> (indices_->size ()) && "Out-of-bounds error in nearestKSearch!");
00482           return (nearestKSearch (input_->points.row ((*indices_)[index]), k, k_indices, k_sqr_distances));
00483         }
00484       }
00485 
00496       template <typename T> int 
00497       radiusSearch (const T &point, double radius, std::vector<int> &k_indices,
00498             std::vector<float> &k_sqr_dists, unsigned int max_nn = 0) const
00499       {
00500         assert (isRowValid (point) && "Invalid (NaN, Inf) point coordinates given to radiusSearch!");
00501 
00502         size_t dim = point.size ();
00503         std::vector<float> query (dim);
00504         for (size_t i = 0; i < dim; ++i)
00505           query[i] = point[i];
00506 
00507         // Has max_nn been set properly?
00508         if (max_nn == 0 || max_nn > static_cast<unsigned int> (total_nr_points_))
00509           max_nn = total_nr_points_;
00510 
00511         std::vector<std::vector<int> > indices(1);
00512         std::vector<std::vector<float> > dists(1);
00513 
00514         flann::SearchParams params(param_radius_);
00515         if (max_nn == static_cast<unsigned int>(total_nr_points_))
00516           params.max_neighbors = -1;  // return all neighbors in radius
00517         else
00518           params.max_neighbors = max_nn;
00519 
00520         int neighbors_in_radius = flann_index_->radiusSearch (flann::Matrix<float> (&query[0], 1, dim_),
00521             indices,
00522             dists,
00523             static_cast<float> (radius * radius), 
00524             params);
00525 
00526         k_indices = indices[0];
00527         k_sqr_dists = dists[0];
00528 
00529         // Do mapping to original point cloud
00530         if (!identity_mapping_) 
00531         {
00532           for (int i = 0; i < neighbors_in_radius; ++i)
00533           {
00534             int& neighbor_index = k_indices[i];
00535             neighbor_index = index_mapping_[neighbor_index];
00536           }
00537         }
00538 
00539         return (neighbors_in_radius);
00540       }
00541 
00553       inline int 
00554       radiusSearch (const PointCloud &cloud, int index, double radius, 
00555                     std::vector<int> &k_indices, std::vector<float> &k_sqr_distances, 
00556                     unsigned int max_nn = 0) const
00557       {
00558         assert (index >= 0 && index < static_cast<int> (cloud.size ()) && "Out-of-bounds error in radiusSearch!");
00559         return (radiusSearch (cloud.points.row (index), radius, k_indices, k_sqr_distances, max_nn));
00560       }
00561 
00573       inline int 
00574       radiusSearch (int index, double radius, std::vector<int> &k_indices,
00575                     std::vector<float> &k_sqr_distances, unsigned int max_nn = 0) const
00576       {
00577         if (indices_ == NULL)
00578         {
00579           assert (index >= 0 && index < static_cast<int> (input_->size ()) && "Out-of-bounds error in radiusSearch!");
00580           return (radiusSearch (input_->points.row (index), radius, k_indices, k_sqr_distances, max_nn));
00581         }
00582         else
00583         {
00584           assert (index >= 0 && index < static_cast<int> (indices_->size ()) && "Out-of-bounds error in radiusSearch!");
00585           return (radiusSearch (input_->points.row ((*indices_)[index]), radius, k_indices, k_sqr_distances, max_nn));
00586         }
00587       }
00588 
00590       inline float
00591       getEpsilon () const
00592       {
00593         return (epsilon_);
00594       }
00595 
00596     private:
00598       void 
00599       cleanup ()
00600       {
00601         if (flann_index_)
00602           delete flann_index_;
00603 
00604         // Data array cleanup
00605         if (cloud_)
00606         {
00607           free (cloud_);
00608           cloud_ = NULL;
00609         }
00610         index_mapping_.clear ();
00611 
00612         if (indices_)
00613           indices_.reset ();
00614       }
00615 
00619       template <typename Expr> bool
00620       isRowValid (const Expr &pt) const
00621       {
00622         for (size_t i = 0; i < static_cast<size_t> (pt.size ()); ++i)
00623           if (!pcl_isfinite (pt[i]))
00624            return (false);
00625 
00626         return (true);
00627       }
00628 
00633       void 
00634       convertCloudToArray (const PointCloud &cloud)
00635       {
00636         // No point in doing anything if the array is empty
00637         if (cloud.empty ())
00638         {
00639           cloud_ = NULL;
00640           return;
00641         }
00642 
00643         int original_no_of_points = static_cast<int> (cloud.points.rows ());
00644 
00645         cloud_ = static_cast<float*> (malloc (original_no_of_points * dim_ * sizeof (float)));
00646         float* cloud_ptr = cloud_;
00647         index_mapping_.reserve (original_no_of_points);
00648         identity_mapping_ = true;
00649 
00650         for (int cloud_index = 0; cloud_index < original_no_of_points; ++cloud_index)
00651         {
00652           // Check if the point is invalid
00653           if (!isRowValid (cloud.points.row (cloud_index)))
00654           {
00655             identity_mapping_ = false;
00656             continue;
00657           }
00658 
00659           index_mapping_.push_back (cloud_index);
00660 
00661           for (size_t i = 0; i < static_cast<size_t> (dim_); ++i)
00662           {
00663             *cloud_ptr = cloud.points.coeffRef (cloud_index, i);
00664             cloud_ptr++;
00665           }
00666         }
00667       }
00668 
00674       void 
00675       convertCloudToArray (const PointCloud &cloud, const std::vector<int> &indices)
00676       {
00677         // No point in doing anything if the array is empty
00678         if (cloud.empty ())
00679         {
00680           cloud_ = NULL;
00681           return;
00682         }
00683 
00684         int original_no_of_points = static_cast<int> (indices.size ());
00685 
00686         cloud_ = static_cast<float*> (malloc (original_no_of_points * dim_ * sizeof (float)));
00687         float* cloud_ptr = cloud_;
00688         index_mapping_.reserve (original_no_of_points);
00689         identity_mapping_ = true;
00690 
00691         for (int indices_index = 0; indices_index < original_no_of_points; ++indices_index)
00692         {
00693           int cloud_index = indices[indices_index];
00694           // Check if the point is invalid
00695           if (!isRowValid (cloud.points.row (cloud_index)))
00696           {
00697             identity_mapping_ = false;
00698             continue;
00699           }
00700 
00701           index_mapping_.push_back (indices_index);  // If the returned index should be for the indices vector
00702 
00703           for (size_t i = 0; i < static_cast<size_t> (dim_); ++i)
00704           {
00705             *cloud_ptr = cloud.points.coeffRef (cloud_index, i);
00706             cloud_ptr++;
00707           }
00708         }
00709       }
00710 
00711     protected:
00713       PointCloudConstPtr input_;
00714 
00716       IndicesConstPtr indices_;
00717 
00719       float epsilon_;
00720 
00722       bool sorted_;
00723 
00724     private:
00726       std::string 
00727       getName () const { return ("KdTreeFLANN"); }
00728 
00730       FLANNIndex* flann_index_;
00731 
00733       float* cloud_;
00734       
00736       std::vector<int> index_mapping_;
00737       
00739       bool identity_mapping_;
00740 
00742       int dim_;
00743 
00745       flann::SearchParams param_k_;
00746 
00748       flann::SearchParams param_radius_;
00749 
00751       int total_nr_points_;
00752   };
00753 }
00754 
00755 #endif


pcl
Author(s): Open Perception
autogenerated on Mon Oct 6 2014 03:15:32