Point Cloud Library (PCL)  1.5.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
rift.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) 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: rift.hpp 4702 2012-02-23 09:39:33Z gedikli $
00037  *
00038  */
00039 
00040 #ifndef PCL_FEATURES_IMPL_RIFT_H_
00041 #define PCL_FEATURES_IMPL_RIFT_H_
00042 
00043 #include "pcl/features/rift.h"
00044 
00046 template <typename PointInT, typename GradientT, typename PointOutT> void
00047 pcl::RIFTEstimation<PointInT, GradientT, PointOutT>::computeRIFT (
00048       const PointCloudIn &cloud, const PointCloudGradient &gradient, 
00049       int p_idx, float radius, const std::vector<int> &indices, 
00050       const std::vector<float> &sqr_distances, Eigen::MatrixXf &rift_descriptor)
00051 {
00052   if (indices.empty ())
00053   {
00054     PCL_ERROR ("[pcl::RIFTEstimation] Null indices points passed!\n");
00055     return;
00056   }
00057 
00058   // Determine the number of bins to use based on the size of rift_descriptor
00059   int nr_distance_bins = rift_descriptor.rows ();
00060   int nr_gradient_bins = rift_descriptor.cols ();
00061 
00062   // Get the center point
00063   pcl::Vector3fMapConst p0 = cloud.points[p_idx].getVector3fMap ();
00064 
00065   // Compute the RIFT descriptor
00066   rift_descriptor.setZero ();
00067   for (size_t idx = 0; idx < indices.size (); ++idx)
00068   {
00069     // Compute the gradient magnitude and orientation (relative to the center point)
00070     pcl::Vector3fMapConst point = cloud.points[indices[idx]].getVector3fMap ();
00071     Eigen::Map<const Eigen::Vector3f> gradient_vector (& (gradient.points[indices[idx]].gradient[0]));
00072 
00073     float gradient_magnitude = gradient_vector.norm ();
00074     float gradient_angle_from_center = acos (gradient_vector.dot ((point - p0).normalized ()) / gradient_magnitude);
00075     if (!pcl_isfinite (gradient_angle_from_center))
00076     {
00077       gradient_angle_from_center = 0.0;
00078     }
00079 
00080     // Normalize distance and angle values to: 0.0 <= d,g < nr_distances_bins,nr_gradient_bins
00081     const float eps = std::numeric_limits<float>::epsilon ();
00082     float d = nr_distance_bins * sqrt (sqr_distances[idx]) / (radius + eps);
00083     float g = nr_gradient_bins * gradient_angle_from_center / (M_PI + eps);
00084 
00085     // Compute the bin indices that need to be updated
00086     int d_idx_min = (std::max)((int) ceil (d - 1), 0);
00087     int d_idx_max = (std::min)((int) floor (d + 1), nr_distance_bins - 1);
00088     int g_idx_min = (int) ceil (g - 1);
00089     int g_idx_max = (int) floor (g + 1);
00090 
00091     // Update the appropriate bins of the histogram 
00092     for (int g_idx = g_idx_min; g_idx <= g_idx_max; ++g_idx)  
00093     {
00094       // Because gradient orientation is cyclical, out-of-bounds values must wrap around
00095       int g_idx_wrapped = ((g_idx + nr_gradient_bins) % nr_gradient_bins); 
00096 
00097       for (int d_idx = d_idx_min; d_idx <= d_idx_max; ++d_idx)
00098       {
00099         // To avoid boundary effects, use linear interpolation when updating each bin 
00100         float w = (1 - fabs (d - d_idx)) * (1 - fabs (g - g_idx));
00101 
00102         rift_descriptor (d_idx, g_idx_wrapped) += w * gradient_magnitude;
00103       }
00104     }
00105   }
00106 
00107   // Normalize the RIFT descriptor to unit magnitude
00108   rift_descriptor.normalize ();
00109 }
00110 
00111 
00113 template <typename PointInT, typename GradientT, typename PointOutT> void
00114 pcl::RIFTEstimation<PointInT, GradientT, PointOutT>::computeFeature (PointCloudOut &output)
00115 {
00116   // Make sure a search radius is set
00117   if (search_radius_ == 0.0)
00118   {
00119     PCL_ERROR ("[pcl::%s::computeFeature] The search radius must be set before computing the feature!\n",
00120                getClassName ().c_str ());
00121     output.width = output.height = 0;
00122     output.points.clear ();
00123     return;
00124   }
00125 
00126   // Make sure the RIFT descriptor has valid dimensions
00127   if (nr_gradient_bins_ <= 0)
00128   {
00129     PCL_ERROR ("[pcl::%s::computeFeature] The number of gradient bins must be greater than zero!\n",
00130                getClassName ().c_str ());
00131     output.width = output.height = 0;
00132     output.points.clear ();
00133     return;
00134   }
00135   if (nr_distance_bins_ <= 0)
00136   {
00137     PCL_ERROR ("[pcl::%s::computeFeature] The number of distance bins must be greater than zero!\n",
00138                getClassName ().c_str ());
00139     output.width = output.height = 0;
00140     output.points.clear ();
00141     return;
00142   }
00143 
00144   // Check for valid input gradient
00145   if (!gradient_)
00146   {
00147     PCL_ERROR ("[pcl::%s::computeFeature] No input gradient was given!\n", getClassName ().c_str ());
00148     output.width = output.height = 0;
00149     output.points.clear ();
00150     return;
00151   }
00152   if (gradient_->points.size () != surface_->points.size ())
00153   {
00154     PCL_ERROR ("[pcl::%s::computeFeature] ", getClassName ().c_str ());
00155     PCL_ERROR ("The number of points in the input dataset differs from the number of points in the gradient!\n");
00156     output.width = output.height = 0;
00157     output.points.clear ();
00158     return;
00159   }
00160 
00161   Eigen::MatrixXf rift_descriptor (nr_distance_bins_, nr_gradient_bins_);
00162   std::vector<int> nn_indices;
00163   std::vector<float> nn_dist_sqr;
00164  
00165   // Iterating over the entire index vector
00166   for (size_t idx = 0; idx < indices_->size (); ++idx)
00167   {
00168     // Find neighbors within the search radius
00169     tree_->radiusSearch ((*indices_)[idx], search_radius_, nn_indices, nn_dist_sqr);
00170 
00171     // Compute the RIFT descriptor
00172     computeRIFT (*surface_, *gradient_, (*indices_)[idx], search_radius_, nn_indices, nn_dist_sqr, rift_descriptor);
00173 
00174     // Copy into the resultant cloud
00175     int bin = 0;
00176     for (int g_bin = 0; g_bin < rift_descriptor.cols (); ++g_bin)
00177       for (int d_bin = 0; d_bin < rift_descriptor.rows (); ++d_bin)
00178         output.points[idx].histogram[bin++] = rift_descriptor (d_bin, g_bin);
00179   }
00180 }
00181 
00183 template <typename PointInT, typename GradientT> void
00184 pcl::RIFTEstimation<PointInT, GradientT, Eigen::MatrixXf>::computeFeatureEigen (pcl::PointCloud<Eigen::MatrixXf> &output)
00185 {
00186   // These should be moved into initCompute ()
00187   {
00188     // Make sure a search radius is set
00189     if (search_radius_ == 0.0)
00190     {
00191       PCL_ERROR ("[pcl::%s::computeFeature] The search radius must be set before computing the feature!\n",
00192                  getClassName ().c_str ());
00193       output.width = output.height = 0;
00194       output.points.resize (0, 0);
00195       return;
00196     }
00197 
00198     // Make sure the RIFT descriptor has valid dimensions
00199     if (nr_gradient_bins_ <= 0)
00200     {
00201       PCL_ERROR ("[pcl::%s::computeFeature] The number of gradient bins must be greater than zero!\n",
00202                  getClassName ().c_str ());
00203       output.width = output.height = 0;
00204       output.points.resize (0, 0);
00205       return;
00206     }
00207     if (nr_distance_bins_ <= 0)
00208     {
00209       PCL_ERROR ("[pcl::%s::computeFeature] The number of distance bins must be greater than zero!\n",
00210                  getClassName ().c_str ());
00211       output.width = output.height = 0;
00212       output.points.resize (0, 0);
00213       return;
00214     }
00215 
00216     // Check for valid input gradient
00217     if (!gradient_)
00218     {
00219       PCL_ERROR ("[pcl::%s::computeFeature] No input gradient was given!\n", getClassName ().c_str ());
00220       output.width = output.height = 0;
00221       output.points.resize (0, 0);
00222       return;
00223     }
00224     if (gradient_->points.size () != surface_->points.size ())
00225     {
00226       PCL_ERROR ("[pcl::%s::computeFeature] ", getClassName ().c_str ());
00227       PCL_ERROR ("The number of points in the input dataset differs from the number of points in the gradient!\n");
00228       output.width = output.height = 0;
00229       output.points.resize (0, 0);
00230       return;
00231     }
00232   }
00233   
00234   output.points.resize (indices_->size (), nr_gradient_bins_ * nr_distance_bins_);
00235   Eigen::MatrixXf rift_descriptor (nr_distance_bins_, nr_gradient_bins_);
00236   std::vector<int> nn_indices;
00237   std::vector<float> nn_dist_sqr;
00238  
00239   output.is_dense = true;
00240   // Iterating over the entire index vector
00241   for (size_t idx = 0; idx < indices_->size (); ++idx)
00242   {
00243     // Find neighbors within the search radius
00244     if (tree_->radiusSearch ((*indices_)[idx], search_radius_, nn_indices, nn_dist_sqr) == 0)
00245     {
00246       output.points.row (idx).setConstant (std::numeric_limits<float>::quiet_NaN ());
00247       output.is_dense = false;
00248       continue;
00249     }
00250 
00251     // Compute the RIFT descriptor
00252     this->computeRIFT (*surface_, *gradient_, (*indices_)[idx], search_radius_, nn_indices, nn_dist_sqr, 
00253                        rift_descriptor);
00254 
00255     // Copy into the resultant cloud
00256     int bin = 0;
00257     for (int g_bin = 0; g_bin < rift_descriptor.cols (); ++g_bin)
00258       for (int d_bin = 0; d_bin < rift_descriptor.rows (); ++d_bin)
00259         output.points (idx, bin++) = rift_descriptor (d_bin, g_bin);
00260 
00261   }
00262 }
00263 
00264 #define PCL_INSTANTIATE_RIFTEstimation(T,NT,OutT) template class PCL_EXPORTS pcl::RIFTEstimation<T,NT,OutT>;
00265 
00266 #endif    // PCL_FEATURES_IMPL_RIFT_H_ 
00267