Point Cloud Library (PCL)  1.4.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
kdtree_flann.hpp
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) 2009-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  */
00037 
00038 #ifndef PCL_KDTREE_KDTREE_IMPL_FLANN_H_
00039 #define PCL_KDTREE_KDTREE_IMPL_FLANN_H_
00040 
00041 #include "pcl/kdtree/kdtree_flann.h"
00042 #include <pcl/console/print.h>
00043 
00045 template <typename PointT, typename Dist> void 
00046 pcl::KdTreeFLANN<PointT, Dist>::setInputCloud (const PointCloudConstPtr &cloud, const IndicesConstPtr &indices)
00047 {
00048   cleanup ();   // Perform an automatic cleanup of structures
00049 
00050   if (!initParameters())
00051     return;
00052 
00053   input_   = cloud;
00054   indices_ = indices;
00055   
00056   if (input_ == NULL)
00057     return;
00058 
00059   m_lock_.lock ();
00060   // Allocate enough data
00061   if (!input_)
00062   {
00063     PCL_ERROR ("[pcl::KdTreeANN::setInputCloud] Invalid input!\n");
00064     return;
00065   }
00066   if (indices != NULL)
00067     convertCloudToArray (*input_, *indices_);
00068   else
00069     convertCloudToArray (*input_);
00070 
00071   initData ();
00072   m_lock_.unlock ();
00073 }
00074 
00076 template <typename PointT, typename Dist> int 
00077 pcl::KdTreeFLANN<PointT, Dist>::nearestKSearch (const PointT &point, int k, 
00078                                                 std::vector<int> &k_indices, 
00079                                                 std::vector<float> &k_distances)
00080 {
00081   if (!point_representation_->isValid (point))
00082   {
00083     //PCL_ERROR_STREAM ("[pcl::KdTreeFLANN::nearestKSearch] Invalid query point given!" << point);
00084     return (0);
00085   }
00086 
00087   // Pay the price of resizing the arrays the first time nearestKSearch gets called
00088   if (k_indices.size () < (size_t)k)
00089     k_indices.resize (k);
00090   if (k_distances.size () < (size_t)k) 
00091     k_distances.resize (k);
00092 
00093   // Wrap the k_indices and k_distances vectors (no data copy)
00094   flann::Matrix<int> k_indices_mat (&k_indices[0], 1, k);
00095   flann::Matrix<float> k_distances_mat (&k_distances[0], 1, k);
00096 
00097   std::vector<float> tmp (dim_);
00098   point_representation_->vectorize ((PointT)point, tmp);
00099 
00100   flann_index_->knnSearch (flann::Matrix<float>(&tmp[0], 1, dim_), k_indices_mat, k_distances_mat, k, param_k_);
00101 
00102   // Do mapping to original point cloud
00103   if (!identity_mapping_) 
00104   {
00105     for (size_t i = 0; i < (size_t)k; ++i)
00106     {
00107       int& neighbor_index = k_indices[i];
00108       neighbor_index = index_mapping_[neighbor_index];
00109     }
00110   }
00111 
00112   return (k);
00113 }
00114 
00116 template <typename PointT, typename Dist> int 
00117 pcl::KdTreeFLANN<PointT, Dist>::radiusSearch (const PointT &point, double radius, std::vector<int> &k_indices,
00118                                               std::vector<float> &k_squared_distances, int max_nn) const
00119 {
00120   static flann::Matrix<int> indices_empty;
00121   static flann::Matrix<float> dists_empty;
00122 
00123   if (!point_representation_->isValid (point))
00124   {
00125     //PCL_ERROR_STREAM ("[pcl::KdTreeFLANN::radiusSearch] Invalid query point given!" << point);
00126     return (0);
00127   }
00128 
00129   std::vector<float> tmp(dim_);
00130   point_representation_->vectorize ((PointT)point, tmp);
00131   radius *= radius; // flann uses squared radius
00132 
00133   size_t size;
00134   if (indices_ == NULL) // no indices set, use full size of point cloud:
00135     size = input_->points.size ();
00136   else
00137     size = indices_->size ();
00138 
00139   int neighbors_in_radius = 0;
00140   if (k_indices.size () == size && k_squared_distances.size () == size)  // preallocated vectors
00141   {
00142     // if using preallocated vectors we ignore max_nn as we are sure to have enought space
00143     // to store all neighbors found in radius
00144     flann::Matrix<int> k_indices_mat (&k_indices[0], 1, k_indices.size());
00145     flann::Matrix<float> k_distances_mat (&k_squared_distances[0], 1, k_squared_distances.size());
00146     neighbors_in_radius = flann_index_->radiusSearch (flann::Matrix<float>(&tmp[0], 1, dim_),
00147                                                       k_indices_mat, k_distances_mat, radius, 
00148                                                       param_radius_);
00149   }
00150   else // need to do search twice, first to find how many neighbors and allocate the vectors
00151   {
00152     neighbors_in_radius = flann_index_->radiusSearch (flann::Matrix<float>(&tmp[0], 1, dim_),
00153                                                       indices_empty, dists_empty, radius, 
00154                                                       param_radius_);
00155 
00156     // If the number of maximum nearest neighbors is given, use it to cap the return
00157     if (max_nn > 0) 
00158       neighbors_in_radius = std::min (neighbors_in_radius, max_nn);
00159 
00160     k_indices.resize (neighbors_in_radius);
00161     k_squared_distances.resize (neighbors_in_radius);
00162 
00163     if (neighbors_in_radius == 0)
00164       return (0);
00165 
00166     flann::Matrix<int> k_indices_mat (&k_indices[0], 1, k_indices.size ());
00167     flann::Matrix<float> k_distances_mat (&k_squared_distances[0], 1, k_squared_distances.size ());
00168     flann_index_->radiusSearch (flann::Matrix<float>(&tmp[0], 1, dim_),
00169                                 k_indices_mat, k_distances_mat, radius, 
00170                                 param_radius_);
00171   }
00172 
00173   // Do mapping to original point cloud
00174   if (!identity_mapping_) 
00175   {
00176     for (int i = 0; i < neighbors_in_radius; ++i)
00177     {
00178       int& neighbor_index = k_indices[i];
00179       neighbor_index = index_mapping_[neighbor_index];
00180     }
00181   }
00182 
00183   return (neighbors_in_radius);
00184 }
00185 
00187 template <typename PointT, typename Dist> void 
00188 pcl::KdTreeFLANN<PointT, Dist>::cleanup ()
00189 {
00190   delete flann_index_;
00191 
00192   m_lock_.lock ();
00193   // Data array cleanup
00194   free (cloud_);
00195   cloud_ = NULL;
00196   index_mapping_.clear();
00197 
00198   if (indices_)
00199     indices_.reset ();
00200 
00201   m_lock_.unlock ();
00202 }
00203 
00205 template <typename PointT, typename Dist> bool 
00206 pcl::KdTreeFLANN<PointT, Dist>::initParameters ()
00207 {
00208   epsilon_ = 0.0;   // default error bound value
00209   dim_ = point_representation_->getNumberOfDimensions (); // Number of dimensions - default is 3 = xyz
00210   // Create the kd_tree representation
00211   return (true);
00212 }
00213 
00215 template <typename PointT, typename Dist> void 
00216 pcl::KdTreeFLANN<PointT, Dist>::initData ()
00217 {
00218   flann_index_ = new FLANNIndex (flann::Matrix<float> (cloud_, index_mapping_.size (), dim_),
00219                                  flann::KDTreeSingleIndexParams (15)); // max 15 points/leaf
00220   flann_index_->buildIndex ();
00221 }
00222 
00224 template <typename PointT, typename Dist> void 
00225 pcl::KdTreeFLANN<PointT, Dist>::convertCloudToArray (const PointCloud &cloud)
00226 {
00227   // No point in doing anything if the array is empty
00228   if (cloud.points.empty ())
00229   {
00230     cloud_ = NULL;
00231     return;
00232   }
00233 
00234   int original_no_of_points = cloud.points.size ();
00235 
00236   cloud_ = (float*)malloc (original_no_of_points * dim_ * sizeof(float));
00237   float* cloud_ptr = cloud_;
00238   index_mapping_.reserve (original_no_of_points);
00239   identity_mapping_ = true;
00240 
00241   for (int cloud_index = 0; cloud_index < original_no_of_points; ++cloud_index)
00242   {
00243     const PointT point = cloud.points[cloud_index];
00244     // Check if the point is invalid
00245     if (!point_representation_->isValid (point))
00246     {
00247       identity_mapping_ = false;
00248       continue;
00249     }
00250 
00251     index_mapping_.push_back(cloud_index);
00252 
00253     point_representation_->vectorize (point, cloud_ptr);
00254     cloud_ptr += dim_;
00255   }
00256 }
00257 
00259 template <typename PointT, typename Dist> void 
00260 pcl::KdTreeFLANN<PointT, Dist>::convertCloudToArray (const PointCloud &cloud, const std::vector<int> &indices)
00261 {
00262   // No point in doing anything if the array is empty
00263   if (cloud.points.empty ())
00264   {
00265     cloud_ = NULL;
00266     return;
00267   }
00268 
00269   int original_no_of_points = indices.size ();
00270 
00271   cloud_ = (float*)malloc (original_no_of_points * dim_ * sizeof (float));
00272   float* cloud_ptr = cloud_;
00273   index_mapping_.reserve (original_no_of_points);
00274   identity_mapping_ = true;
00275 
00276   for (int indices_index = 0; indices_index < original_no_of_points; ++indices_index)
00277   {
00278     int cloud_index = indices[indices_index];
00279     const PointT point = cloud.points[cloud_index];
00280     // Check if the point is invalid
00281     if (!point_representation_->isValid (point))
00282     {
00283       identity_mapping_ = false;
00284       continue;
00285     }
00286 
00287     index_mapping_.push_back (indices_index);  // If the returned index should be for the indices vector
00288     //index_mapping_.push_back(cloud_index);  // If the returned index should be for the ros cloud
00289     
00290     point_representation_->vectorize (point, cloud_ptr);
00291     cloud_ptr += dim_;
00292   }
00293 }
00294 
00295 #define PCL_INSTANTIATE_KdTreeFLANN(T) template class PCL_EXPORTS pcl::KdTreeFLANN<T>;
00296 
00297 #endif  //#ifndef _PCL_KDTREE_KDTREE_IMPL_FLANN_H_
00298 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines