|
Point Cloud Library (PCL)
1.5.1
|
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
1.8.0