Point Cloud Library (PCL)  1.5.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
usc.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: usc.hpp 4702 2012-02-23 09:39:33Z gedikli $
00037  *
00038  */
00039 
00040 #ifndef PCL_FEATURES_IMPL_USC_HPP_
00041 #define PCL_FEATURES_IMPL_USC_HPP_
00042 
00043 #include <pcl/features/usc.h>
00044 #include <pcl/features/shot_common.h>
00045 #include <pcl/common/geometry.h>
00046 #include <pcl/common/angles.h>
00047 #include <pcl/common/utils.h>
00048 
00050 template <typename PointInT, typename PointOutT> bool
00051 pcl::UniqueShapeContext<PointInT, PointOutT>::initCompute ()
00052 {
00053   if (!Feature<PointInT, PointOutT>::initCompute ())
00054   {
00055     PCL_ERROR ("[pcl::%s::initCompute] Init failed.\n", getClassName ().c_str ());
00056     return (false);
00057   }
00058 
00059   if (search_radius_< min_radius_)
00060   {
00061     PCL_ERROR ("[pcl::%s::initCompute] search_radius_ must be GREATER than min_radius_.\n", getClassName ().c_str ());
00062     return (false);
00063   }
00064 
00065   // Update descriptor length
00066   descriptor_length_ = elevation_bins_ * azimuth_bins_ * radius_bins_;
00067 
00068   // Compute radial, elevation and azimuth divisions
00069   float azimuth_interval = (float) 360 / azimuth_bins_;
00070   float elevation_interval = (float) 180 / elevation_bins_;
00071 
00072   // Reallocate divisions and volume lut
00073   radii_interval_.clear ();
00074   phi_divisions_.clear ();
00075   theta_divisions_.clear ();
00076   volume_lut_.clear ();
00077 
00078   // Fills radii interval based on formula (1) in section 2.1 of Frome's paper
00079   radii_interval_.resize (radius_bins_ + 1);
00080   for (size_t j = 0; j < radius_bins_ + 1; j++)
00081     radii_interval_[j] = exp (log (min_radius_) + (((float) j / (radius_bins_)) * log (search_radius_/min_radius_)));
00082 
00083   // Fill theta didvisions of elevation
00084   theta_divisions_.resize (elevation_bins_+1);
00085   for (size_t k = 0; k < elevation_bins_+1; k++)
00086     theta_divisions_[k] = k*elevation_interval;
00087 
00088   // Fill phi didvisions of elevation
00089   phi_divisions_.resize (azimuth_bins_+1);
00090   for (size_t l = 0; l < azimuth_bins_+1; l++)
00091     phi_divisions_[l] = l*azimuth_interval;
00092 
00093   // LookUp Table that contains the volume of all the bins
00094   // "phi" term of the volume integral
00095   // "integr_phi" has always the same value so we compute it only one time
00096   float integr_phi  = pcl::deg2rad (phi_divisions_[1]) - pcl::deg2rad (phi_divisions_[0]);
00097   // exponential to compute the cube root using pow
00098   float e = 1.0 / 3.0;    
00099   // Resize volume look up table
00100   volume_lut_.resize (radius_bins_ * elevation_bins_ * azimuth_bins_);
00101   // Fill volumes look up table
00102   for (size_t j = 0; j < radius_bins_; j++)
00103   {
00104     // "r" term of the volume integral
00105     float integr_r = (radii_interval_[j+1]*radii_interval_[j+1]*radii_interval_[j+1] / 3) - (radii_interval_[j]*radii_interval_[j]*radii_interval_[j]/ 3);
00106     
00107     for (size_t k = 0; k < elevation_bins_; k++)
00108     {
00109       // "theta" term of the volume integral
00110       float integr_theta = cos (deg2rad (theta_divisions_[k])) - cos (deg2rad (theta_divisions_[k+1]));
00111       // Volume
00112       float V = integr_phi * integr_theta * integr_r;
00113       // Compute cube root of the computed volume commented for performance but left 
00114       // here for clarity
00115       // float cbrt = pow(V, e);
00116       // cbrt = 1 / cbrt;
00117       
00118       for (size_t l = 0; l < azimuth_bins_; l++)
00119         // Store in lut 1/cbrt
00120         //volume_lut_[ (l*elevation_bins_*radius_bins_) + k*radius_bins_ + j ] = cbrt;
00121         volume_lut_[(l*elevation_bins_*radius_bins_) + k*radius_bins_ + j] = 1.0 / pow (V, e);
00122     }
00123   }
00124   return (true);
00125 }
00126 
00128 template <typename PointInT, typename PointOutT> bool
00129 pcl::UniqueShapeContext<PointInT, PointOutT>::computePointRF (size_t index, float rf[9])
00130 {
00131   std::vector<int> nn_indices;
00132   std::vector<float> nn_dists;
00133   size_t nb_neighbours = searchForNeighbors ((*indices_)[index], local_radius_, nn_indices, nn_dists);
00134 
00135   // The RF is formed as the SHOT local RF
00136   if (nb_neighbours < 5)
00137   {
00138     //PCL_WARN ("[pcl::%s::computePointRF] Neighborhood has %d vertices which is less than 5, aborting description of point index %d\n!", getClassName ().c_str (), nb_neighbours, (*indices_)[index]);
00139     return (false);
00140   }
00141   std::vector<Eigen::Vector4f, Eigen::aligned_allocator<Eigen::Vector4f> > rf_ (3);
00142   Eigen::Vector4f central_point = input_->points[(*indices_)[index]].getVector4fMap ();
00143   central_point[3] = 0;
00144   pcl::getLocalRF (*surface_, local_radius_, central_point /*(*indices_)[index]*/, nn_indices, nn_dists, rf_);
00145   for (int d = 0; d < 9; ++d)
00146     rf[d] = rf_[d/3][d%3];
00147 
00148   return (true);
00149 }
00150 
00152 template <typename PointInT, typename PointOutT> void
00153 pcl::UniqueShapeContext<PointInT, PointOutT>::computePointDescriptor (size_t index, float rf[9], std::vector<float> &desc)
00154 {
00155   pcl::Vector3fMapConst origin = input_->points[(*indices_)[index]].getVector3fMap ();
00156   const Eigen::Map<Eigen::Vector3f> x_axis (rf);
00157   const Eigen::Map<Eigen::Vector3f> y_axis (rf + 3);
00158   const Eigen::Map<Eigen::Vector3f> normal (rf + 6);
00159   // Find every point within specified search_radius_
00160   std::vector<int> nn_indices;
00161   std::vector<float> nn_dists;
00162   const size_t neighb_cnt = searchForNeighbors ((*indices_)[index], search_radius_, nn_indices, nn_dists);
00163   // For each point within radius
00164   for (size_t ne = 0; ne < neighb_cnt; ne++)
00165   {
00166     if (pcl::utils::equal(nn_dists[ne], 0.0f))
00167       continue;
00168     // Get neighbours coordinates
00169     Eigen::Vector3f neighbour = surface_->points[nn_indices[ne]].getVector3fMap ();
00170 
00171     // ----- Compute current neighbour polar coordinates -----
00172     
00173     // Get distance between the neighbour and the origin
00174     float r = sqrt (nn_dists[ne]); 
00175     
00176     // Project point into the tangent plane
00177     Eigen::Vector3f proj;
00178     pcl::geometry::project (neighbour, origin, normal, proj);
00179     proj -= origin;
00180 
00181     // Normalize to compute the dot product
00182     proj.normalize ();
00183     
00184     // Compute the angle between the projection and the x axis in the interval [0,360] 
00185     Eigen::Vector3f cross = x_axis.cross (proj);
00186     float phi = rad2deg (std::atan2 (cross.norm (), x_axis.dot (proj)));
00187     phi = cross.dot (normal) < 0.f ? (360.0 - phi) : phi;
00189     Eigen::Vector3f no = neighbour - origin;
00190     no.normalize ();
00191     float theta = normal.dot (no);
00192     theta = pcl::rad2deg (acos (std::min (1.0f, std::max (-1.0f, theta))));
00193 
00195     size_t j = 0;
00196     size_t k = 0;
00197     size_t l = 0;
00198 
00200     for (size_t rad = 1; rad < radius_bins_ + 1; rad++) 
00201     {
00202       if (r <= radii_interval_[rad])
00203       {
00204         j = rad - 1;
00205         break;
00206       }
00207     }
00208 
00209     for (size_t ang = 1; ang < elevation_bins_ + 1; ang++) 
00210     {
00211       if (theta <= theta_divisions_[ang]) 
00212       {
00213         k = ang - 1;
00214         break;
00215       }
00216     }
00217 
00218     for (size_t ang = 1; ang < azimuth_bins_ + 1; ang++) 
00219     {
00220       if (phi <= phi_divisions_[ang]) 
00221       {
00222         l = ang - 1;
00223         break;
00224       }
00225     }
00226 
00228     std::vector<int> neighbour_indices;
00229     std::vector<float> neighbour_didtances;
00230     float point_density = (float) searchForNeighbors (*surface_, nn_indices[ne], point_density_radius_, neighbour_indices, neighbour_didtances);
00232     float w = (1.0 / point_density) * volume_lut_[(l*elevation_bins_*radius_bins_) + 
00233                                                   (k*radius_bins_) + 
00234                                                   j];
00235       
00236     assert (w >= 0.0);
00237     if (w == std::numeric_limits<float>::infinity ())
00238       PCL_ERROR ("Shape Context Error INF!\n");
00239     if (w != w)
00240       PCL_ERROR ("Shape Context Error IND!\n");
00242     desc[(l*elevation_bins_*radius_bins_) + (k*radius_bins_) + j] += w;
00243 
00244     assert (desc[(l*elevation_bins_*radius_bins_) + (k*radius_bins_) + j] >= 0);
00245   } // end for each neighbour
00246 }
00247 
00249 template <typename PointInT, typename PointOutT> void
00250 pcl::UniqueShapeContext<PointInT, PointOutT>::computeFeature (PointCloudOut &output)
00251 {
00252   for (size_t point_index = 0; point_index < indices_->size (); point_index++)
00253   {
00254     output[point_index].descriptor.resize (descriptor_length_);
00255     computePointRF (point_index, output[point_index].rf);
00256     computePointDescriptor (point_index, output[point_index].rf, output[point_index].descriptor);
00257   }
00258 }
00259 
00261 template <typename PointInT> void
00262 pcl::UniqueShapeContext<PointInT, Eigen::MatrixXf>::computeFeatureEigen (pcl::PointCloud<Eigen::MatrixXf> &output)
00263 {
00264   Eigen::VectorXf rf (9);
00265   output.points.resize (indices_->size (), descriptor_length_ + 9);
00266   for (size_t point_index = 0; point_index < indices_->size (); point_index++)
00267   {
00268     computePointRF (point_index, rf.data ());
00269     for (int j = 0; j < 9; ++j)
00270       output.points (point_index, j) = rf[j];
00271     std::vector<float> descriptor (descriptor_length_);
00272     computePointDescriptor (point_index, rf.data (), descriptor);
00273     for (size_t j = 0; j < descriptor_length_; ++j)
00274       output.points (point_index, 9 + j) = descriptor[j];
00275   }
00276 }
00277 
00278 #define PCL_INSTANTIATE_UniqueShapeContext(T,OutT) template class PCL_EXPORTS pcl::UniqueShapeContext<T,OutT>;
00279 
00280 #endif