Point Cloud Library (PCL)  1.6.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
kdtree_flann.h
Go to the documentation of this file.
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Point Cloud Library (PCL) - www.pointclouds.org
5  * Copyright (c) 2010-2012, Willow Garage, Inc.
6  *
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * * Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  * * Redistributions in binary form must reproduce the above
16  * copyright notice, this list of conditions and the following
17  * disclaimer in the documentation and/or other materials provided
18  * with the distribution.
19  * * Neither the name of Willow Garage, Inc. nor the names of its
20  * contributors may be used to endorse or promote products derived
21  * from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34  * POSSIBILITY OF SUCH DAMAGE.
35  *
36  * $Id: kdtree_flann.h 6024 2012-06-26 05:31:03Z rusu $
37  *
38  */
39 
40 #ifndef PCL_KDTREE_KDTREE_FLANN_H_
41 #define PCL_KDTREE_KDTREE_FLANN_H_
42 
43 #include <cstdio>
45 #include <pcl/kdtree/kdtree.h>
46 #include <pcl/kdtree/flann.h>
47 
48 namespace pcl
49 {
56  template <typename PointT, typename Dist = flann::L2_Simple<float> >
57  class KdTreeFLANN : public pcl::KdTree<PointT>
58  {
59  public:
67 
70 
71  typedef boost::shared_ptr<std::vector<int> > IndicesPtr;
72  typedef boost::shared_ptr<const std::vector<int> > IndicesConstPtr;
73 
74  typedef flann::Index<Dist> FLANNIndex;
75 
76  // Boost shared pointers
77  typedef boost::shared_ptr<KdTreeFLANN<PointT> > Ptr;
78  typedef boost::shared_ptr<const KdTreeFLANN<PointT> > ConstPtr;
79 
85  KdTreeFLANN (bool sorted = true) :
86  pcl::KdTree<PointT> (sorted),
87  flann_index_ (NULL), cloud_ (NULL),
88  index_mapping_ (), identity_mapping_ (false),
89  dim_ (0), total_nr_points_ (0),
90  param_k_ (flann::SearchParams (-1 , epsilon_)),
91  param_radius_ (flann::SearchParams (-1, epsilon_, sorted))
92  {
93  }
94 
99  pcl::KdTree<PointT> (false),
100  flann_index_ (NULL), cloud_ (NULL),
101  index_mapping_ (), identity_mapping_ (false),
102  dim_ (0), total_nr_points_ (0),
103  param_k_ (flann::SearchParams (-1 , epsilon_)),
104  param_radius_ (flann::SearchParams (-1, epsilon_, false))
105  {
106  *this = k;
107  }
108 
112  inline KdTreeFLANN<PointT>&
114  {
116  flann_index_ = k.flann_index_;
117  cloud_ = k.cloud_;
118  index_mapping_ = k.index_mapping_;
119  identity_mapping_ = k.identity_mapping_;
120  dim_ = k.dim_;
121  total_nr_points_ = k.total_nr_points_;
122  param_k_ = k.param_k_;
123  param_radius_ = k.param_radius_;
124  return (*this);
125  }
126 
130  inline void
131  setEpsilon (float eps)
132  {
133  epsilon_ = eps;
134  param_k_ = flann::SearchParams (-1 , epsilon_);
135  param_radius_ = flann::SearchParams (-1 , epsilon_, sorted_);
136  }
137 
138  inline void
139  setSortedResults (bool sorted)
140  {
141  sorted_ = sorted;
142  param_k_ = flann::SearchParams (-1, epsilon_);
143  param_radius_ = flann::SearchParams (-1, epsilon_, sorted_);
144  }
145 
146  inline Ptr makeShared () { return Ptr (new KdTreeFLANN<PointT> (*this)); }
147 
151  virtual ~KdTreeFLANN ()
152  {
153  cleanup ();
154  }
155 
160  void
161  setInputCloud (const PointCloudConstPtr &cloud, const IndicesConstPtr &indices = IndicesConstPtr ());
162 
177  int
178  nearestKSearch (const PointT &point, int k,
179  std::vector<int> &k_indices, std::vector<float> &k_sqr_distances) const;
180 
197  int
198  radiusSearch (const PointT &point, double radius, std::vector<int> &k_indices,
199  std::vector<float> &k_sqr_distances, unsigned int max_nn = 0) const;
200 
201  private:
203  void
204  cleanup ();
205 
210  void
211  convertCloudToArray (const PointCloud &cloud);
212 
218  void
219  convertCloudToArray (const PointCloud &cloud, const std::vector<int> &indices);
220 
221  private:
223  virtual std::string
224  getName () const { return ("KdTreeFLANN"); }
225 
227  FLANNIndex* flann_index_;
228 
230  float* cloud_;
231 
233  std::vector<int> index_mapping_;
234 
236  bool identity_mapping_;
237 
239  int dim_;
240 
242  int total_nr_points_;
243 
245  flann::SearchParams param_k_;
246 
248  flann::SearchParams param_radius_;
249  };
250 
257  template <>
258  class KdTreeFLANN <Eigen::MatrixXf>
259  {
260  public:
263 
264  typedef boost::shared_ptr<std::vector<int> > IndicesPtr;
265  typedef boost::shared_ptr<const std::vector<int> > IndicesConstPtr;
266 
267  typedef flann::Index<flann::L2_Simple<float> > FLANNIndex;
268 
270  typedef boost::shared_ptr<const PointRepresentation> PointRepresentationConstPtr;
271 
272  // Boost shared pointers
273  typedef boost::shared_ptr<KdTreeFLANN<Eigen::MatrixXf> > Ptr;
274  typedef boost::shared_ptr<const KdTreeFLANN<Eigen::MatrixXf> > ConstPtr;
275 
281  KdTreeFLANN (bool sorted = true) :
282  input_(), indices_(), epsilon_(0.0f), sorted_(sorted), flann_index_(NULL), cloud_(NULL),
283  index_mapping_ (), identity_mapping_ (false), dim_ (0),
284  param_k_ (flann::SearchParams (-1, epsilon_)),
285  param_radius_ (flann::SearchParams (-1, epsilon_, sorted)),
286  total_nr_points_ (0)
287  {
288  cleanup ();
289  }
290 
295  input_(), indices_(), epsilon_(0.0f), sorted_(false), flann_index_(NULL), cloud_(NULL),
296  index_mapping_ (), identity_mapping_ (false), dim_ (0),
297  param_k_ (flann::SearchParams (-1, epsilon_)),
298  param_radius_ (flann::SearchParams (-1, epsilon_, sorted_)),
299  total_nr_points_ (0)
300  {
301  *this = k;
302  }
303 
307  inline KdTreeFLANN&
309  {
310  input_ = k.input_;
311  indices_ = k.indices_;
312  epsilon_ = k.epsilon_;
313  sorted_ = k.sorted_;
314  flann_index_ = k.flann_index_;
315  cloud_ = k.cloud_;
316  index_mapping_ = k.index_mapping_;
317  identity_mapping_ = k.identity_mapping_;
318  dim_ = k.dim_;
319  param_k_ = k.param_k_;
320  param_radius_ = k.param_radius_;
321  total_nr_points_ = k.total_nr_points_;
322  return (*this);
323  }
324 
328  inline void
329  setEpsilon (float eps)
330  {
331  epsilon_ = eps;
332  param_k_ = flann::SearchParams (-1 , epsilon_);
333  param_radius_ = flann::SearchParams (-1, epsilon_, sorted_);
334  }
335 
336  inline Ptr
337  makeShared () { return Ptr (new KdTreeFLANN<Eigen::MatrixXf> (*this)); }
338 
342  virtual ~KdTreeFLANN ()
343  {
344  cleanup ();
345  }
346 
351  void
353  {
354  cleanup (); // Perform an automatic cleanup of structures
355 
356  if (cloud == NULL)
357  return;
358 
359  epsilon_ = 0.0f; // default error bound value
360  input_ = cloud;
361  indices_ = indices;
362  dim_ = static_cast<int> (cloud->points.cols ()); // Number of dimensions = number of columns in the eigen matrix
363 
364  // Allocate enough data
365  if (indices != NULL)
366  {
367  total_nr_points_ = static_cast<int> (indices_->size ());
368  convertCloudToArray (*input_, *indices_);
369  }
370  else
371  {
372  // get the number of points as the number of rows
373  total_nr_points_ = static_cast<int> (cloud->points.rows ());
374  convertCloudToArray (*input_);
375  }
376 
377  flann_index_ = new FLANNIndex (flann::Matrix<float> (cloud_, index_mapping_.size (), dim_),
378  flann::KDTreeSingleIndexParams (15)); // max 15 points/leaf
379  flann_index_->buildIndex ();
380  }
381 
383  inline IndicesConstPtr
384  getIndices () const
385  {
386  return (indices_);
387  }
388 
390  inline PointCloudConstPtr
391  getInputCloud () const
392  {
393  return (input_);
394  }
395 
404  template <typename T> int
405  nearestKSearch (const T &point, int k,
406  std::vector<int> &k_indices, std::vector<float> &k_sqr_distances) const
407  {
408  assert (isRowValid (point) && "Invalid (NaN, Inf) point coordinates given to nearestKSearch!");
409 
410  if (k > total_nr_points_)
411  {
412  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_);
413  k = total_nr_points_;
414  }
415 
416  k_indices.resize (k);
417  k_sqr_distances.resize (k);
418 
419  size_t dim = point.size ();
420  std::vector<float> query (dim);
421  for (size_t i = 0; i < dim; ++i)
422  query[i] = point[i];
423 
424  flann::Matrix<int> k_indices_mat (&k_indices[0], 1, k);
425  flann::Matrix<float> k_distances_mat (&k_sqr_distances[0], 1, k);
426  // Wrap the k_indices and k_distances vectors (no data copy)
427  flann_index_->knnSearch (flann::Matrix<float> (&query[0], 1, dim),
428  k_indices_mat, k_distances_mat,
429  k, param_k_);
430 
431  // Do mapping to original point cloud
432  if (!identity_mapping_)
433  {
434  for (size_t i = 0; i < static_cast<size_t> (k); ++i)
435  {
436  int& neighbor_index = k_indices[i];
437  neighbor_index = index_mapping_[neighbor_index];
438  }
439  }
440 
441  return (k);
442  }
443 
453  inline int
454  nearestKSearch (const PointCloud &cloud, int index, int k,
455  std::vector<int> &k_indices, std::vector<float> &k_sqr_distances) const
456  {
457  assert (index >= 0 && index < static_cast<int> (cloud.size ()) && "Out-of-bounds error in nearestKSearch!");
458  return (nearestKSearch (cloud.points.row (index), k, k_indices, k_sqr_distances));
459  }
460 
470  inline int
471  nearestKSearch (int index, int k,
472  std::vector<int> &k_indices, std::vector<float> &k_sqr_distances) const
473  {
474  if (indices_ == NULL)
475  {
476  assert (index >= 0 && index < static_cast<int> (input_->size ()) && "Out-of-bounds error in nearestKSearch!");
477  return (nearestKSearch (input_->points.row (index), k, k_indices, k_sqr_distances));
478  }
479  else
480  {
481  assert (index >= 0 && index < static_cast<int> (indices_->size ()) && "Out-of-bounds error in nearestKSearch!");
482  return (nearestKSearch (input_->points.row ((*indices_)[index]), k, k_indices, k_sqr_distances));
483  }
484  }
485 
496  template <typename T> int
497  radiusSearch (const T &point, double radius, std::vector<int> &k_indices,
498  std::vector<float> &k_sqr_dists, unsigned int max_nn = 0) const
499  {
500  assert (isRowValid (point) && "Invalid (NaN, Inf) point coordinates given to radiusSearch!");
501 
502  size_t dim = point.size ();
503  std::vector<float> query (dim);
504  for (size_t i = 0; i < dim; ++i)
505  query[i] = point[i];
506 
507  // Has max_nn been set properly?
508  if (max_nn == 0 || max_nn > static_cast<unsigned int> (total_nr_points_))
509  max_nn = total_nr_points_;
510 
511  std::vector<std::vector<int> > indices(1);
512  std::vector<std::vector<float> > dists(1);
513 
514  flann::SearchParams params(param_radius_);
515  if (max_nn == static_cast<unsigned int>(total_nr_points_))
516  params.max_neighbors = -1; // return all neighbors in radius
517  else
518  params.max_neighbors = max_nn;
519 
520  int neighbors_in_radius = flann_index_->radiusSearch (flann::Matrix<float> (&query[0], 1, dim_),
521  indices,
522  dists,
523  static_cast<float> (radius * radius),
524  params);
525 
526  k_indices = indices[0];
527  k_sqr_dists = dists[0];
528 
529  // Do mapping to original point cloud
530  if (!identity_mapping_)
531  {
532  for (int i = 0; i < neighbors_in_radius; ++i)
533  {
534  int& neighbor_index = k_indices[i];
535  neighbor_index = index_mapping_[neighbor_index];
536  }
537  }
538 
539  return (neighbors_in_radius);
540  }
541 
553  inline int
554  radiusSearch (const PointCloud &cloud, int index, double radius,
555  std::vector<int> &k_indices, std::vector<float> &k_sqr_distances,
556  unsigned int max_nn = 0) const
557  {
558  assert (index >= 0 && index < static_cast<int> (cloud.size ()) && "Out-of-bounds error in radiusSearch!");
559  return (radiusSearch (cloud.points.row (index), radius, k_indices, k_sqr_distances, max_nn));
560  }
561 
573  inline int
574  radiusSearch (int index, double radius, std::vector<int> &k_indices,
575  std::vector<float> &k_sqr_distances, unsigned int max_nn = 0) const
576  {
577  if (indices_ == NULL)
578  {
579  assert (index >= 0 && index < static_cast<int> (input_->size ()) && "Out-of-bounds error in radiusSearch!");
580  return (radiusSearch (input_->points.row (index), radius, k_indices, k_sqr_distances, max_nn));
581  }
582  else
583  {
584  assert (index >= 0 && index < static_cast<int> (indices_->size ()) && "Out-of-bounds error in radiusSearch!");
585  return (radiusSearch (input_->points.row ((*indices_)[index]), radius, k_indices, k_sqr_distances, max_nn));
586  }
587  }
588 
590  inline float
591  getEpsilon () const
592  {
593  return (epsilon_);
594  }
595 
596  private:
598  void
599  cleanup ()
600  {
601  if (flann_index_)
602  delete flann_index_;
603 
604  // Data array cleanup
605  if (cloud_)
606  {
607  free (cloud_);
608  cloud_ = NULL;
609  }
610  index_mapping_.clear ();
611 
612  if (indices_)
613  indices_.reset ();
614  }
615 
619  template <typename Expr> bool
620  isRowValid (const Expr &pt) const
621  {
622  for (size_t i = 0; i < static_cast<size_t> (pt.size ()); ++i)
623  if (!pcl_isfinite (pt[i]))
624  return (false);
625 
626  return (true);
627  }
628 
633  void
634  convertCloudToArray (const PointCloud &cloud)
635  {
636  // No point in doing anything if the array is empty
637  if (cloud.empty ())
638  {
639  cloud_ = NULL;
640  return;
641  }
642 
643  int original_no_of_points = static_cast<int> (cloud.points.rows ());
644 
645  cloud_ = static_cast<float*> (malloc (original_no_of_points * dim_ * sizeof (float)));
646  float* cloud_ptr = cloud_;
647  index_mapping_.reserve (original_no_of_points);
648  identity_mapping_ = true;
649 
650  for (int cloud_index = 0; cloud_index < original_no_of_points; ++cloud_index)
651  {
652  // Check if the point is invalid
653  if (!isRowValid (cloud.points.row (cloud_index)))
654  {
655  identity_mapping_ = false;
656  continue;
657  }
658 
659  index_mapping_.push_back (cloud_index);
660 
661  for (size_t i = 0; i < static_cast<size_t> (dim_); ++i)
662  {
663  *cloud_ptr = cloud.points.coeffRef (cloud_index, i);
664  cloud_ptr++;
665  }
666  }
667  }
668 
674  void
675  convertCloudToArray (const PointCloud &cloud, const std::vector<int> &indices)
676  {
677  // No point in doing anything if the array is empty
678  if (cloud.empty ())
679  {
680  cloud_ = NULL;
681  return;
682  }
683 
684  int original_no_of_points = static_cast<int> (indices.size ());
685 
686  cloud_ = static_cast<float*> (malloc (original_no_of_points * dim_ * sizeof (float)));
687  float* cloud_ptr = cloud_;
688  index_mapping_.reserve (original_no_of_points);
689  identity_mapping_ = true;
690 
691  for (int indices_index = 0; indices_index < original_no_of_points; ++indices_index)
692  {
693  int cloud_index = indices[indices_index];
694  // Check if the point is invalid
695  if (!isRowValid (cloud.points.row (cloud_index)))
696  {
697  identity_mapping_ = false;
698  continue;
699  }
700 
701  index_mapping_.push_back (indices_index); // If the returned index should be for the indices vector
702 
703  for (size_t i = 0; i < static_cast<size_t> (dim_); ++i)
704  {
705  *cloud_ptr = cloud.points.coeffRef (cloud_index, i);
706  cloud_ptr++;
707  }
708  }
709  }
710 
711  protected:
713  PointCloudConstPtr input_;
714 
716  IndicesConstPtr indices_;
717 
719  float epsilon_;
720 
722  bool sorted_;
723 
724  private:
726  std::string
727  getName () const { return ("KdTreeFLANN"); }
728 
730  FLANNIndex* flann_index_;
731 
733  float* cloud_;
734 
736  std::vector<int> index_mapping_;
737 
739  bool identity_mapping_;
740 
742  int dim_;
743 
745  flann::SearchParams param_k_;
746 
748  flann::SearchParams param_radius_;
749 
751  int total_nr_points_;
752  };
753 }
754 
755 #endif