Point Cloud Library (PCL)  1.4.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
feature.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: feature.hpp 3755 2011-12-31 23:45:30Z rusu $
00037  *
00038  */
00039 
00040 #ifndef PCL_FEATURES_IMPL_FEATURE_H_
00041 #define PCL_FEATURES_IMPL_FEATURE_H_
00042 
00043 #include <pcl/search/pcl_search.h>
00044 
00046 inline void
00047 pcl::solvePlaneParameters (const Eigen::Matrix3f &covariance_matrix, 
00048                            const Eigen::Vector4f &point,
00049                            Eigen::Vector4f &plane_parameters, float &curvature)
00050 {
00051   // Avoid getting hung on Eigen's optimizers
00052   for (int i = 0; i < 3; ++i)
00053     for (int j = 0; j < 3; ++j)
00054       if (!pcl_isfinite (covariance_matrix (i, j)))
00055       {
00056         //PCL_WARN ("[pcl::solvePlaneParameteres] Covariance matrix has NaN/Inf values!\n");
00057         plane_parameters.setConstant (std::numeric_limits<float>::quiet_NaN ());
00058         curvature = std::numeric_limits<float>::quiet_NaN ();
00059         return;
00060       }
00061 
00062   // Extract the eigenvalues and eigenvectors
00063   //Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f> ei_symm (covariance_matrix);
00064   //EIGEN_ALIGN16 Eigen::Vector3f eigen_values  = ei_symm.eigenvalues ();
00065   //EIGEN_ALIGN16 Eigen::Matrix3f eigen_vectors = ei_symm.eigenvectors ();
00066   EIGEN_ALIGN16 Eigen::Vector3f eigen_values;
00067   EIGEN_ALIGN16 Eigen::Matrix3f eigen_vectors;
00068   pcl::eigen33 (covariance_matrix, eigen_vectors, eigen_values);
00069 
00070   // Normalize the surface normal (eigenvector corresponding to the smallest eigenvalue)
00071   // Note: Remember to take care of the eigen_vectors ordering
00072   //float norm = 1.0 / eigen_vectors.col (0).norm ();
00073 
00074   //plane_parameters[0] = eigen_vectors (0, 0) * norm;
00075   //plane_parameters[1] = eigen_vectors (1, 0) * norm;
00076   //plane_parameters[2] = eigen_vectors (2, 0) * norm;
00077 
00078   // The normalization is not necessary, since the eigenvectors from libeigen are already normalized
00079   plane_parameters[0] = eigen_vectors (0, 0);
00080   plane_parameters[1] = eigen_vectors (1, 0);
00081   plane_parameters[2] = eigen_vectors (2, 0);
00082   plane_parameters[3] = 0;
00083 
00084   // Hessian form (D = nc . p_plane (centroid here) + p)
00085   plane_parameters[3] = -1 * plane_parameters.dot (point);
00086 
00087   // Compute the curvature surface change
00088   float eig_sum = eigen_values.sum ();
00089   if (eig_sum != 0)
00090     curvature = fabs ( eigen_values[0] / eig_sum );
00091   else
00092     curvature = 0;
00093 }
00094 
00096 inline void
00097 pcl::solvePlaneParameters (const Eigen::Matrix3f &covariance_matrix,
00098                            float &nx, float &ny, float &nz, float &curvature)
00099 {
00100   // Avoid getting hung on Eigen's optimizers
00101   for (int i = 0; i < 3; ++i)
00102     for (int j = 0; j < 3; ++j)
00103       if (!pcl_isfinite (covariance_matrix (i, j)))
00104       {
00105         //PCL_WARN ("[pcl::solvePlaneParameteres] Covariance matrix has NaN/Inf values!\n");
00106         nx = ny = nz = curvature = std::numeric_limits<float>::quiet_NaN ();
00107         return;
00108       }
00109   // Extract the eigenvalues and eigenvectors
00110   //Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f> ei_symm (covariance_matrix);
00111   //EIGEN_ALIGN16 Eigen::Vector3f eigen_values  = ei_symm.eigenvalues ();
00112   //EIGEN_ALIGN16 Eigen::Matrix3f eigen_vectors = ei_symm.eigenvectors ();
00113   EIGEN_ALIGN16 Eigen::Vector3f eigen_values;
00114   EIGEN_ALIGN16 Eigen::Matrix3f eigen_vectors;
00115   pcl::eigen33 (covariance_matrix, eigen_vectors, eigen_values);
00116 
00117   // Normalize the surface normal (eigenvector corresponding to the smallest eigenvalue)
00118   // Note: Remember to take care of the eigen_vectors ordering
00119   //float norm = 1.0 / eigen_vectors.col (0).norm ();
00120 
00121   //nx = eigen_vectors (0, 0) * norm;
00122   //ny = eigen_vectors (1, 0) * norm;
00123   //nz = eigen_vectors (2, 0) * norm;
00124   
00125   // The normalization is not necessary, since the eigenvectors from libeigen are already normalized
00126   nx = eigen_vectors (0, 0);
00127   ny = eigen_vectors (1, 0);
00128   nz = eigen_vectors (2, 0);
00129 
00130   // Compute the curvature surface change
00131   float eig_sum = eigen_values.sum ();
00132   if (eig_sum != 0)
00133     curvature = fabs ( eigen_values[0] / eig_sum );
00134   else
00135     curvature = 0;
00136 }
00137 
00141 template <typename PointInT, typename PointOutT> bool
00142 pcl::Feature<PointInT, PointOutT>::initCompute ()
00143 {
00144   if (!PCLBase<PointInT>::initCompute ())
00145   {
00146     PCL_ERROR ("[pcl::%s::initCompute] Init failed.\n", getClassName ().c_str ());
00147     return (false);
00148   }
00149 
00150   // If the dataset is empty, just return
00151   if (input_->points.empty ())
00152   {
00153     PCL_ERROR ("[pcl::%s::compute] input_ is empty!\n", getClassName ().c_str ());
00154     // Cleanup
00155     deinitCompute ();
00156     return (false);
00157   }
00158 
00159   // If no search surface has been defined, use the input dataset as the search surface itself
00160   if (!surface_)
00161   {
00162     fake_surface_ = true;
00163     surface_ = input_;
00164   }
00165 
00166   // Check if a space search locator was given
00167   if (!tree_)
00168   {
00169     if (surface_->isOrganized () && input_->isOrganized ())
00170       tree_.reset (new pcl::search::OrganizedNeighbor<PointInT> ());
00171     else
00172       tree_.reset (new pcl::search::KdTree<PointInT> (false));
00173   }
00174   // Send the surface dataset to the spatial locator
00175   tree_->setInputCloud (surface_);
00176 
00177   // Do a fast check to see if the search parameters are well defined
00178   if (search_radius_ != 0.0)
00179   {
00180     if (k_ != 0)
00181     {
00182       PCL_ERROR ("[pcl::%s::compute] ", getClassName ().c_str ());
00183       PCL_ERROR ("Both radius (%f) and K (%d) defined! ", search_radius_, k_);
00184       PCL_ERROR ("Set one of them to zero first and then re-run compute ().\n");
00185       // Cleanup
00186       deinitCompute ();
00187       return (false);
00188     }
00189     else // Use the radiusSearch () function
00190     {
00191       search_parameter_ = search_radius_;
00192       if (surface_ == input_) // if the two surfaces are the same
00193       {
00194         // Declare the search locator definition
00195         int (KdTree::*radiusSearch)(int index, double radius, std::vector<int> &k_indices,
00196                                     std::vector<float> &k_distances, int max_nn) const = &KdTree::radiusSearch;
00197         search_method_ = boost::bind (radiusSearch, boost::ref (tree_), _1, _2, _3, _4, INT_MAX);
00198       }
00199 
00200       // Declare the search locator definition
00201       int (KdTree::*radiusSearchSurface)(const PointCloudIn &cloud, int index, double radius,
00202                                          std::vector<int> &k_indices, std::vector<float> &k_distances,
00203                                          int max_nn) = &pcl::search::Search<PointInT>::radiusSearch;
00204       search_method_surface_ = boost::bind (radiusSearchSurface, boost::ref (tree_), _1, _2, _3, _4, _5, INT_MAX);
00205     }
00206   }
00207   else
00208   {
00209     if (k_ != 0) // Use the nearestKSearch () function
00210     {
00211       search_parameter_ = k_;
00212       if (surface_ == input_) // if the two surfaces are the same
00213       {
00214         // Declare the search locator definition
00215         int (KdTree::*nearestKSearch)(int index, int k, std::vector<int> &k_indices, 
00216                                       std::vector<float> &k_distances) = &KdTree::nearestKSearch;
00217         search_method_ = boost::bind (nearestKSearch, boost::ref (tree_), _1, _2, _3, _4);
00218       }
00219       // Declare the search locator definition
00220       int (KdTree::*nearestKSearchSurface)(const PointCloudIn &cloud, int index, int k, std::vector<int> &k_indices, 
00221                                            std::vector<float> &k_distances) = &KdTree::nearestKSearch;
00222       search_method_surface_ = boost::bind (nearestKSearchSurface, boost::ref (tree_), _1, _2, _3, _4, _5);
00223     }
00224     else
00225     {
00226       PCL_ERROR ("[pcl::%s::compute] Neither radius nor K defined! ", getClassName ().c_str ());
00227       PCL_ERROR ("Set one of them to a positive number first and then re-run compute ().\n");
00228       // Cleanup
00229       deinitCompute ();
00230       return (false);
00231     }
00232   }
00233   return (true);
00234 }
00235 
00237 template <typename PointInT, typename PointOutT> bool
00238 pcl::Feature<PointInT, PointOutT>::deinitCompute ()
00239 {
00240   // Reset the surface
00241   if (fake_surface_)
00242   {
00243     surface_.reset ();
00244     fake_surface_ = false;
00245   }
00246   return (true);
00247 }
00248 
00250 template <typename PointInT, typename PointOutT> void
00251 pcl::Feature<PointInT, PointOutT>::compute (PointCloudOut &output)
00252 {
00253   if (!initCompute ())
00254   {
00255     output.width = output.height = 0;
00256     output.points.clear ();
00257     return;
00258   }
00259 
00260   // Copy the header
00261   output.header = input_->header;
00262 
00263   // Resize the output dataset
00264   if (output.points.size () != indices_->size ())
00265     output.points.resize (indices_->size ());
00266   // Check if the output will be computed for all points or only a subset
00267   if (indices_->size () != input_->points.size ())
00268   {
00269     output.width = (int) indices_->size ();
00270     output.height = 1;
00271   }
00272   else
00273   {
00274     output.width = input_->width;
00275     output.height = input_->height;
00276   }
00277   output.is_dense = input_->is_dense;
00278 
00279   // Perform the actual feature computation
00280   computeFeature (output);
00281 
00282   deinitCompute ();
00283 }
00284 
00286 template <typename PointInT, typename PointOutT> void
00287 pcl::Feature<PointInT, PointOutT>::compute (pcl::PointCloud<Eigen::MatrixXf> &output)
00288 {
00289   if (!initCompute ())
00290   {
00291     output.width = output.height = 0;
00292     output.points.resize (0, 0);
00293     return;
00294   }
00295 
00296   // Copy the properties
00297   output.properties.acquisition_time = input_->header.stamp;
00298   output.properties.sensor_origin = input_->sensor_origin_;
00299   output.properties.sensor_orientation = input_->sensor_orientation_;
00300   
00301   // Check if the output will be computed for all points or only a subset
00302   if (indices_->size () != input_->points.size ())
00303   {
00304     output.width = (int) indices_->size ();
00305     output.height = 1;
00306   }
00307   else
00308   {
00309     output.width = input_->width;
00310     output.height = input_->height;
00311   }
00312 
00313   output.is_dense = input_->is_dense;
00314 
00315   // Perform the actual feature computation
00316   computeFeature (output);
00317 
00318   deinitCompute ();
00319 }
00320 
00324 template <typename PointInT, typename PointNT, typename PointOutT> bool
00325 pcl::FeatureFromNormals<PointInT, PointNT, PointOutT>::initCompute ()
00326 {
00327   if (!Feature<PointInT, PointOutT>::initCompute ())
00328   {
00329     PCL_ERROR ("[pcl::%s::initCompute] Init failed.\n", getClassName ().c_str ());
00330     return (false);
00331   }
00332 
00333   // Check if input normals are set
00334   if (!normals_)
00335   {
00336     PCL_ERROR ("[pcl::%s::initCompute] No input dataset containing normals was given!\n", getClassName ().c_str ());
00337     Feature<PointInT, PointOutT>::deinitCompute();
00338     return (false);
00339   }
00340 
00341   // Check if the size of normals is the same as the size of the surface
00342   if (normals_->points.size () != surface_->points.size ())
00343   {
00344     PCL_ERROR ("[pcl::%s::initCompute] ", getClassName ().c_str ());
00345     PCL_ERROR ("The number of points in the input dataset differs from ");
00346     PCL_ERROR ("the number of points in the dataset containing the normals!\n");
00347     Feature<PointInT, PointOutT>::deinitCompute();
00348     return (false);
00349   }
00350 
00351   return (true);
00352 }
00353 
00357 template <typename PointInT, typename PointLT, typename PointOutT> bool
00358 pcl::FeatureFromLabels<PointInT, PointLT, PointOutT>::initCompute ()
00359 {
00360   if (!Feature<PointInT, PointOutT>::initCompute ())
00361   {
00362     PCL_ERROR ("[pcl::%s::initCompute] Init failed.\n", getClassName ().c_str ());
00363     return (false);
00364   }
00365 
00366   // Check if input normals are set
00367   if (!labels_)
00368   {
00369     PCL_ERROR ("[pcl::%s::initCompute] No input dataset containing labels was given!\n", getClassName ().c_str ());
00370     Feature<PointInT, PointOutT>::deinitCompute();
00371     return (false);
00372   }
00373 
00374   // Check if the size of normals is the same as the size of the surface
00375   if (labels_->points.size () != surface_->points.size ())
00376   {
00377     PCL_ERROR ("[pcl::%s::initCompute] The number of points in the input dataset differs from the number of points in the dataset containing the labels!\n", getClassName ().c_str ());
00378     Feature<PointInT, PointOutT>::deinitCompute();
00379     return (false);
00380   }
00381 
00382   return (true);
00383 }
00384 
00385 #endif  //#ifndef PCL_FEATURES_IMPL_FEATURE_H_
00386 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines