Point Cloud Library (PCL)  1.5.1
 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   epsilon_ = 0.0;   // default error bound value
00051   dim_ = point_representation_->getNumberOfDimensions (); // Number of dimensions - default is 3 = xyz
00052 
00053   input_   = cloud;
00054   indices_ = indices;
00055   
00056   // Allocate enough data
00057   if (!input_)
00058   {
00059     PCL_ERROR ("[pcl::KdTreeFLANN::setInputCloud] Invalid input!\n");
00060     return;
00061   }
00062   if (indices != NULL)
00063   {
00064     total_nr_points_ = (int) indices_->size ();
00065     convertCloudToArray (*input_, *indices_);
00066   }
00067   else
00068   {
00069     total_nr_points_ = (int) input_->points.size ();
00070     convertCloudToArray (*input_);
00071   }
00072 
00073   flann_index_ = new FLANNIndex (flann::Matrix<float> (cloud_, index_mapping_.size (), dim_),
00074                                  flann::KDTreeSingleIndexParams (15)); // max 15 points/leaf
00075   flann_index_->buildIndex ();
00076 }
00077 
00079 template <typename PointT, typename Dist> int 
00080 pcl::KdTreeFLANN<PointT, Dist>::nearestKSearch (const PointT &point, int k, 
00081                                                 std::vector<int> &k_indices, 
00082                                                 std::vector<float> &k_distances) const
00083 {
00084   assert (point_representation_->isValid (point) && "Invalid (NaN, Inf) point coordinates given to nearestKSearch!");
00085 
00086   if (k > total_nr_points_)
00087   {
00088     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_);
00089     k = total_nr_points_;
00090   }
00091 
00092   k_indices.resize (k);
00093   k_distances.resize (k);
00094 
00095   std::vector<float> query (dim_);
00096   point_representation_->vectorize ((PointT)point, query);
00097 
00098   flann::Matrix<int> k_indices_mat (&k_indices[0], 1, k);
00099   flann::Matrix<float> k_distances_mat (&k_distances[0], 1, k);
00100   // Wrap the k_indices and k_distances vectors (no data copy)
00101   flann_index_->knnSearch (flann::Matrix<float> (&query[0], 1, dim_), 
00102                            k_indices_mat, k_distances_mat,
00103                            k, param_k_);
00104 
00105   // Do mapping to original point cloud
00106   if (!identity_mapping_) 
00107   {
00108     for (size_t i = 0; i < (size_t)k; ++i)
00109     {
00110       int& neighbor_index = k_indices[i];
00111       neighbor_index = index_mapping_[neighbor_index];
00112     }
00113   }
00114 
00115   return (k);
00116 }
00117 
00119 template <typename PointT, typename Dist> int 
00120 pcl::KdTreeFLANN<PointT, Dist>::radiusSearch (const PointT &point, double radius, std::vector<int> &k_indices,
00121                                               std::vector<float> &k_sqr_dists, unsigned int max_nn) const
00122 {
00123   assert (point_representation_->isValid (point) && "Invalid (NaN, Inf) point coordinates given to radiusSearch!");
00124 
00125   std::vector<float> query (dim_);
00126   point_representation_->vectorize ((PointT)point, query);
00127 
00128   int neighbors_in_radius = 0;
00129 
00130   // If the user pre-allocated the arrays, we are only going to 
00131   if (k_indices.size () == (size_t)total_nr_points_ && k_sqr_dists.size () == (size_t)total_nr_points_)
00132   {
00133     flann::Matrix<int> k_indices_mat (&k_indices[0], 1, k_indices.size ());
00134     flann::Matrix<float> k_distances_mat (&k_sqr_dists[0], 1, k_sqr_dists.size ());
00135     neighbors_in_radius = flann_index_->radiusSearch (flann::Matrix<float> (&query[0], 1, dim_),
00136                                                       k_indices_mat,
00137                                                       k_distances_mat,
00138                                                       (float) (radius * radius), 
00139                                                       param_radius_);
00140   }
00141   else
00142   {
00143     // Has max_nn been set properly?
00144     if (max_nn == 0 || max_nn > (unsigned int)total_nr_points_)
00145       max_nn = total_nr_points_;
00146 
00147     static flann::Matrix<int> indices_empty;
00148     static flann::Matrix<float> dists_empty;
00149     neighbors_in_radius = flann_index_->radiusSearch (flann::Matrix<float> (&query[0], 1, dim_),
00150                                                       indices_empty,
00151                                                       dists_empty,
00152                                                       (float) (radius * radius), 
00153                                                       param_radius_);
00154     neighbors_in_radius = std::min ((unsigned int)neighbors_in_radius, max_nn);
00155 
00156     k_indices.resize (neighbors_in_radius);
00157     k_sqr_dists.resize (neighbors_in_radius);
00158     if(neighbors_in_radius != 0)
00159     {
00160       flann::Matrix<int> k_indices_mat (&k_indices[0], 1, k_indices.size ());
00161       flann::Matrix<float> k_distances_mat (&k_sqr_dists[0], 1, k_sqr_dists.size ());
00162       flann_index_->radiusSearch (flann::Matrix<float> (&query[0], 1, dim_),
00163                                   k_indices_mat,
00164                                   k_distances_mat,
00165                                   (float) (radius * radius), 
00166                                   param_radius_);
00167     }
00168   }
00169 
00170   // Do mapping to original point cloud
00171   if (!identity_mapping_) 
00172   {
00173     for (int i = 0; i < neighbors_in_radius; ++i)
00174     {
00175       int& neighbor_index = k_indices[i];
00176       neighbor_index = index_mapping_[neighbor_index];
00177     }
00178   }
00179 
00180   return (neighbors_in_radius);
00181 }
00182 
00184 template <typename PointT, typename Dist> void 
00185 pcl::KdTreeFLANN<PointT, Dist>::cleanup ()
00186 {
00187   if (flann_index_)
00188     delete flann_index_;
00189 
00190   // Data array cleanup
00191   if (cloud_)
00192   {
00193     free (cloud_);
00194     cloud_ = NULL;
00195   }
00196   index_mapping_.clear ();
00197 
00198   if (indices_)
00199     indices_.reset ();
00200 }
00201 
00203 template <typename PointT, typename Dist> void 
00204 pcl::KdTreeFLANN<PointT, Dist>::convertCloudToArray (const PointCloud &cloud)
00205 {
00206   // No point in doing anything if the array is empty
00207   if (cloud.points.empty ())
00208   {
00209     cloud_ = NULL;
00210     return;
00211   }
00212 
00213   int original_no_of_points = (int) cloud.points.size ();
00214 
00215   cloud_ = (float*)malloc (original_no_of_points * dim_ * sizeof(float));
00216   float* cloud_ptr = cloud_;
00217   index_mapping_.reserve (original_no_of_points);
00218   identity_mapping_ = true;
00219 
00220   for (int cloud_index = 0; cloud_index < original_no_of_points; ++cloud_index)
00221   {
00222     // Check if the point is invalid
00223     if (!point_representation_->isValid (cloud.points[cloud_index]))
00224     {
00225       identity_mapping_ = false;
00226       continue;
00227     }
00228 
00229     index_mapping_.push_back (cloud_index);
00230 
00231     point_representation_->vectorize (cloud.points[cloud_index], cloud_ptr);
00232     cloud_ptr += dim_;
00233   }
00234 }
00235 
00237 template <typename PointT, typename Dist> void 
00238 pcl::KdTreeFLANN<PointT, Dist>::convertCloudToArray (const PointCloud &cloud, const std::vector<int> &indices)
00239 {
00240   // No point in doing anything if the array is empty
00241   if (cloud.points.empty ())
00242   {
00243     cloud_ = NULL;
00244     return;
00245   }
00246 
00247   int original_no_of_points = (int) indices.size ();
00248 
00249   cloud_ = (float*)malloc (original_no_of_points * dim_ * sizeof (float));
00250   float* cloud_ptr = cloud_;
00251   index_mapping_.reserve (original_no_of_points);
00252 
00253   // true only identity: 
00254   //     - indices size equals cloud size
00255   //     - indices only contain values between 0 and cloud.size - 1
00256   //     - no index is multiple times in the list
00257   //     => index is complete
00258   // But we can not guarantee that => identity_mapping_ = false
00259   identity_mapping_ = false;
00260   
00261   for (std::vector<int>::const_iterator iIt = indices.begin (); iIt != indices.end (); ++iIt)
00262   {
00263     // Check if the point is invalid
00264     if (!point_representation_->isValid (cloud.points[*iIt]))
00265       continue;
00266 
00267     
00268     index_mapping_.push_back (*iIt);  // If the returned index should be for the indices vector
00269     
00270     point_representation_->vectorize (cloud.points[*iIt], cloud_ptr);
00271     cloud_ptr += dim_;
00272   }
00273 }
00274 
00275 #define PCL_INSTANTIATE_KdTreeFLANN(T) template class PCL_EXPORTS pcl::KdTreeFLANN<T>;
00276 
00277 #endif  //#ifndef _PCL_KDTREE_KDTREE_IMPL_FLANN_H_
00278