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