Point Cloud Library (PCL)  1.5.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
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-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: kdtree_flann.h 4702 2012-02-23 09:39:33Z gedikli $
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 <flann/flann.hpp>
00046 #include <pcl/kdtree/kdtree.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         dim_ (0), total_nr_points_ (0),
00089         param_k_ (flann::SearchParams (-1 , (float) epsilon_)),
00090         param_radius_ (flann::SearchParams (-1, (float) epsilon_, sorted))
00091       {
00092       }
00093 
00097       inline void
00098       setEpsilon (double eps)
00099       {
00100         epsilon_ = eps;
00101         param_k_ = flann::SearchParams (-1 , (float) epsilon_);
00102         param_radius_ = flann::SearchParams (-1 , (float) epsilon_, sorted_);
00103       }
00104 
00105       inline void setSortedResults (bool sorted)
00106       {
00107         sorted_ = sorted;
00108         param_k_ = flann::SearchParams (-1 ,epsilon_);
00109         param_radius_ = flann::SearchParams (-1 ,epsilon_, sorted_);
00110       }
00111       
00112       inline Ptr makeShared () { return Ptr (new KdTreeFLANN<PointT> (*this)); } 
00113 
00117       virtual ~KdTreeFLANN ()
00118       {
00119         cleanup ();
00120       }
00121 
00126       void 
00127       setInputCloud (const PointCloudConstPtr &cloud, const IndicesConstPtr &indices = IndicesConstPtr ());
00128 
00143       int 
00144       nearestKSearch (const PointT &point, int k, 
00145                       std::vector<int> &k_indices, std::vector<float> &k_sqr_distances) const;
00146 
00163       int 
00164       radiusSearch (const PointT &point, double radius, std::vector<int> &k_indices,
00165                     std::vector<float> &k_sqr_distances, unsigned int max_nn = 0) const;
00166 
00167     private:
00169       void 
00170       cleanup ();
00171 
00176       void 
00177       convertCloudToArray (const PointCloud &cloud);
00178 
00184       void 
00185       convertCloudToArray (const PointCloud &cloud, const std::vector<int> &indices);
00186 
00187     private:
00189       virtual std::string 
00190       getName () const { return ("KdTreeFLANN"); }
00191 
00193       FLANNIndex* flann_index_;
00194 
00196       float* cloud_;
00197       
00199       std::vector<int> index_mapping_;
00200       
00202       bool identity_mapping_;
00203 
00205       int dim_;
00206 
00208       int total_nr_points_;
00209 
00211       flann::SearchParams param_k_;
00212 
00214       flann::SearchParams param_radius_;
00215   };
00216 
00223   template <>
00224   class KdTreeFLANN <Eigen::MatrixXf>
00225   {
00226     public:
00227       typedef pcl::PointCloud<Eigen::MatrixXf> PointCloud;
00228       typedef PointCloud::ConstPtr PointCloudConstPtr;
00229 
00230       typedef boost::shared_ptr<std::vector<int> > IndicesPtr;
00231       typedef boost::shared_ptr<const std::vector<int> > IndicesConstPtr;
00232 
00233       typedef flann::Index<flann::L2_Simple<float> > FLANNIndex;
00234 
00235       typedef pcl::PointRepresentation<Eigen::MatrixXf> PointRepresentation;
00236       typedef boost::shared_ptr<const PointRepresentation> PointRepresentationConstPtr;
00237 
00238       // Boost shared pointers
00239       typedef boost::shared_ptr<KdTreeFLANN<Eigen::MatrixXf> > Ptr;
00240       typedef boost::shared_ptr<const KdTreeFLANN<Eigen::MatrixXf> > ConstPtr;
00241 
00247       KdTreeFLANN (bool sorted = true) : 
00248         input_(), indices_(), epsilon_(0.0), sorted_(sorted), flann_index_(NULL), cloud_(NULL)
00249       {
00250         param_k_ = flann::SearchParams (-1, (float) epsilon_);
00251         param_radius_ = flann::SearchParams (-1, (float) epsilon_, sorted);
00252         cleanup ();
00253       }
00254 
00258       inline void
00259       setEpsilon (double eps)
00260       {
00261         epsilon_ = eps;
00262         param_k_ = flann::SearchParams (-1 , (float) epsilon_);
00263         param_radius_ = flann::SearchParams (-1, (float) epsilon_, sorted_);
00264       }
00265 
00266       inline Ptr 
00267       makeShared () { return Ptr (new KdTreeFLANN<Eigen::MatrixXf> (*this)); } 
00268 
00272       virtual ~KdTreeFLANN ()
00273       {
00274         cleanup ();
00275       }
00276 
00281       void 
00282       setInputCloud (const PointCloudConstPtr &cloud, const IndicesConstPtr &indices = IndicesConstPtr ())
00283       {
00284         cleanup ();   // Perform an automatic cleanup of structures
00285 
00286         if (cloud == NULL)
00287           return;
00288 
00289         epsilon_ = 0.0;   // default error bound value
00290         input_   = cloud;
00291         indices_ = indices;
00292         dim_ = (int) cloud->points.cols (); // Number of dimensions = number of columns in the eigen matrix
00293         
00294         // Allocate enough data
00295         if (indices != NULL)
00296         {
00297           total_nr_points_ = (int) indices_->size ();
00298           convertCloudToArray (*input_, *indices_);
00299         }
00300         else
00301         {
00302           // get the number of points as the number of rows
00303           total_nr_points_ = (int) cloud->points.rows ();
00304           convertCloudToArray (*input_);
00305         }
00306 
00307         flann_index_ = new FLANNIndex (flann::Matrix<float> (cloud_, index_mapping_.size (), dim_),
00308                                        flann::KDTreeSingleIndexParams (15)); // max 15 points/leaf
00309         flann_index_->buildIndex ();
00310       }
00311 
00313       inline IndicesConstPtr const
00314       getIndices ()
00315       {
00316         return (indices_);
00317       }
00318 
00320       inline PointCloudConstPtr
00321       getInputCloud ()
00322       {
00323         return (input_);
00324       }
00325 
00334       template <typename T> int 
00335       nearestKSearch (const T &point, int k, 
00336                       std::vector<int> &k_indices, std::vector<float> &k_sqr_distances) const
00337       {
00338         assert (isRowValid (point) && "Invalid (NaN, Inf) point coordinates given to nearestKSearch!");
00339 
00340         if (k > total_nr_points_)
00341         {
00342           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_);
00343           k = total_nr_points_;
00344         }
00345 
00346         k_indices.resize (k);
00347         k_sqr_distances.resize (k);
00348 
00349         size_t dim = point.size ();
00350         std::vector<float> query (dim);
00351         for (size_t i = 0; i < dim; ++i)
00352           query[i] = point[i];
00353 
00354         flann::Matrix<int> k_indices_mat (&k_indices[0], 1, k);
00355         flann::Matrix<float> k_distances_mat (&k_sqr_distances[0], 1, k);
00356         // Wrap the k_indices and k_distances vectors (no data copy)
00357         flann_index_->knnSearch (flann::Matrix<float> (&query[0], 1, dim), 
00358                                  k_indices_mat, k_distances_mat,
00359                                  k, param_k_);
00360 
00361         // Do mapping to original point cloud
00362         if (!identity_mapping_) 
00363         {
00364           for (size_t i = 0; i < (size_t)k; ++i)
00365           {
00366             int& neighbor_index = k_indices[i];
00367             neighbor_index = index_mapping_[neighbor_index];
00368           }
00369         }
00370 
00371         return (k);
00372       }
00373 
00383       inline int 
00384       nearestKSearch (const PointCloud &cloud, int index, int k, 
00385                       std::vector<int> &k_indices, std::vector<float> &k_sqr_distances) const
00386       {
00387         assert (index >= 0 && index < (int)cloud.points.size () && "Out-of-bounds error in nearestKSearch!");
00388         return (nearestKSearch (cloud.points.row (index), k, k_indices, k_sqr_distances));
00389       }
00390 
00400       inline int 
00401       nearestKSearch (int index, int k, 
00402                       std::vector<int> &k_indices, std::vector<float> &k_sqr_distances) const
00403       {
00404         if (indices_ == NULL)
00405         {
00406           assert (index >= 0 && index < (int)input_->points.size () && "Out-of-bounds error in nearestKSearch!");
00407           return (nearestKSearch (input_->points.row (index), k, k_indices, k_sqr_distances));
00408         }
00409         else
00410         {
00411           assert (index >= 0 && index < (int)indices_->size () && "Out-of-bounds error in nearestKSearch!");
00412           return (nearestKSearch (input_->points.row ((*indices_)[index]), k, k_indices, k_sqr_distances));
00413         }
00414       }
00415 
00426       template <typename T> int 
00427       radiusSearch (const T &point, double radius, std::vector<int> &k_indices,
00428                     std::vector<float> &k_sqr_dists, unsigned int max_nn = 0) const
00429       {
00430         assert (isRowValid (point) && "Invalid (NaN, Inf) point coordinates given to radiusSearch!");
00431 
00432         size_t dim = point.size ();
00433         std::vector<float> query (dim);
00434         for (size_t i = 0; i < dim; ++i)
00435           query[i] = point[i];
00436 
00437         int neighbors_in_radius = 0;
00438 
00439         // If the user pre-allocated the arrays, we are only going to 
00440         if (k_indices.size () == (size_t)total_nr_points_ && k_sqr_dists.size () == (size_t)total_nr_points_)
00441         {
00442           flann::Matrix<int> k_indices_mat (&k_indices[0], 1, k_indices.size ());
00443           flann::Matrix<float> k_distances_mat (&k_sqr_dists[0], 1, k_sqr_dists.size ());
00444           neighbors_in_radius = flann_index_->radiusSearch (flann::Matrix<float> (&query[0], 1, dim),
00445                                                             k_indices_mat,
00446                                                             k_distances_mat,
00447                                                             (float) (radius * radius), 
00448                                                             param_radius_);
00449         }
00450         else
00451         {
00452           // Has max_nn been set properly?
00453           if (max_nn == 0 || max_nn > (unsigned int)total_nr_points_)
00454             max_nn = total_nr_points_;
00455 
00456           static flann::Matrix<int> indices_empty;
00457           static flann::Matrix<float> dists_empty;
00458           neighbors_in_radius = flann_index_->radiusSearch (flann::Matrix<float> (&query[0], 1, dim),
00459                                                             indices_empty,
00460                                                             dists_empty,
00461                                                             (float) (radius * radius), 
00462                                                             param_radius_);
00463           neighbors_in_radius = std::min ((unsigned int)neighbors_in_radius, max_nn);
00464 
00465           k_indices.resize (neighbors_in_radius);
00466           k_sqr_dists.resize (neighbors_in_radius);
00467           if(neighbors_in_radius != 0)
00468           {
00469             flann::Matrix<int> k_indices_mat (&k_indices[0], 1, k_indices.size ());
00470             flann::Matrix<float> k_distances_mat (&k_sqr_dists[0], 1, k_sqr_dists.size ());
00471             flann_index_->radiusSearch (flann::Matrix<float> (&query[0], 1, dim),
00472                                         k_indices_mat,
00473                                         k_distances_mat,
00474                                         (float) (radius * radius), 
00475                                         param_radius_);
00476           }
00477         }
00478 
00479         // Do mapping to original point cloud
00480         if (!identity_mapping_) 
00481         {
00482           for (int i = 0; i < neighbors_in_radius; ++i)
00483           {
00484             int& neighbor_index = k_indices[i];
00485             neighbor_index = index_mapping_[neighbor_index];
00486           }
00487         }
00488 
00489         return (neighbors_in_radius);
00490       }
00491 
00503       inline int 
00504       radiusSearch (const PointCloud &cloud, int index, double radius, 
00505                     std::vector<int> &k_indices, std::vector<float> &k_sqr_distances, 
00506                     unsigned int max_nn = 0) const
00507       {
00508         assert (index >= 0 && index < (int)cloud.points.size () && "Out-of-bounds error in radiusSearch!");
00509         return (radiusSearch (cloud.points.row (index), radius, k_indices, k_sqr_distances, max_nn));
00510       }
00511 
00523       inline int 
00524       radiusSearch (int index, double radius, std::vector<int> &k_indices,
00525                     std::vector<float> &k_sqr_distances, unsigned int max_nn = 0) const
00526       {
00527         if (indices_ == NULL)
00528         {
00529           assert (index >= 0 && index < (int)input_->points.size () && "Out-of-bounds error in radiusSearch!");
00530           return (radiusSearch (input_->points.row (index), radius, k_indices, k_sqr_distances, max_nn));
00531         }
00532         else
00533         {
00534           assert (index >= 0 && index < (int)indices_->size () && "Out-of-bounds error in radiusSearch!");
00535           return (radiusSearch (input_->points.row ((*indices_)[index]), radius, k_indices, k_sqr_distances, max_nn));
00536         }
00537       }
00538 
00540       inline double
00541       getEpsilon ()
00542       {
00543         return (epsilon_);
00544       }
00545 
00546     private:
00548       void 
00549       cleanup ()
00550       {
00551         if (flann_index_)
00552           delete flann_index_;
00553 
00554         // Data array cleanup
00555         if (cloud_)
00556         {
00557           free (cloud_);
00558           cloud_ = NULL;
00559         }
00560         index_mapping_.clear ();
00561 
00562         if (indices_)
00563           indices_.reset ();
00564       }
00565 
00569       template <typename Expr> bool
00570       isRowValid (const Expr &pt) const
00571       {
00572         for (size_t i = 0; i < (size_t)pt.size (); ++i)
00573           if (!pcl_isfinite (pt[i]))
00574            return (false);
00575 
00576         return (true);
00577       }
00578 
00583       void 
00584       convertCloudToArray (const PointCloud &cloud)
00585       {
00586         // No point in doing anything if the array is empty
00587         if (cloud.empty ())
00588         {
00589           cloud_ = NULL;
00590           return;
00591         }
00592 
00593         int original_no_of_points = cloud.points.rows ();
00594 
00595         cloud_ = (float*)malloc (original_no_of_points * dim_ * sizeof (float));
00596         float* cloud_ptr = cloud_;
00597         index_mapping_.reserve (original_no_of_points);
00598         identity_mapping_ = true;
00599 
00600         for (int cloud_index = 0; cloud_index < original_no_of_points; ++cloud_index)
00601         {
00602           // Check if the point is invalid
00603           if (!isRowValid (cloud.points.row (cloud_index)))
00604           {
00605             identity_mapping_ = false;
00606             continue;
00607           }
00608 
00609           index_mapping_.push_back (cloud_index);
00610 
00611           for (size_t i = 0; i < (size_t)dim_; ++i)
00612           {
00613             *cloud_ptr = cloud.points.coeffRef (cloud_index, i);
00614             cloud_ptr++;
00615           }
00616         }
00617       }
00618 
00624       void 
00625       convertCloudToArray (const PointCloud &cloud, const std::vector<int> &indices)
00626       {
00627         // No point in doing anything if the array is empty
00628         if (cloud.empty ())
00629         {
00630           cloud_ = NULL;
00631           return;
00632         }
00633 
00634         int original_no_of_points = (int) indices.size ();
00635 
00636         cloud_ = (float*)malloc (original_no_of_points * dim_ * sizeof (float));
00637         float* cloud_ptr = cloud_;
00638         index_mapping_.reserve (original_no_of_points);
00639         identity_mapping_ = true;
00640 
00641         for (int indices_index = 0; indices_index < original_no_of_points; ++indices_index)
00642         {
00643           int cloud_index = indices[indices_index];
00644           // Check if the point is invalid
00645           if (!isRowValid (cloud.points.row (cloud_index)))
00646           {
00647             identity_mapping_ = false;
00648             continue;
00649           }
00650 
00651           index_mapping_.push_back (indices_index);  // If the returned index should be for the indices vector
00652 
00653           for (size_t i = 0; i < (size_t)dim_; ++i)
00654           {
00655             *cloud_ptr = cloud.points.coeffRef (cloud_index, i);
00656             cloud_ptr++;
00657           }
00658         }
00659       }
00660 
00661     protected:
00663       PointCloudConstPtr input_;
00664 
00666       IndicesConstPtr indices_;
00667 
00669       double epsilon_;
00670 
00672       bool sorted_;
00673 
00674     private:
00676       std::string 
00677       getName () const { return ("KdTreeFLANN"); }
00678 
00680       FLANNIndex* flann_index_;
00681 
00683       float* cloud_;
00684       
00686       std::vector<int> index_mapping_;
00687       
00689       bool identity_mapping_;
00690 
00692       int dim_;
00693 
00695       flann::SearchParams param_k_;
00696 
00698       flann::SearchParams param_radius_;
00699 
00701       int total_nr_points_;
00702     };
00703 }
00704 
00705 #endif