Point Cloud Library (PCL)  1.4.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
mls.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: mls.hpp 3385 2011-12-05 04:40:55Z rusu $
00037  *
00038  */
00039 
00040 #ifndef PCL_SURFACE_IMPL_MLS_H_
00041 #define PCL_SURFACE_IMPL_MLS_H_
00042 
00043 #include "pcl/surface/mls.h"
00044 #include <pcl/common/io.h>
00045 #include <pcl/common/centroid.h>
00046 #include <pcl/common/eigen.h>
00047 
00049 template <typename PointInT, typename NormalOutT> void
00050 pcl::MovingLeastSquares<PointInT, NormalOutT>::reconstruct (PointCloudIn &output)
00051 {
00052   // check if normals have to be computed/saved
00053   if (normals_)
00054   {
00055     // Copy the header
00056     normals_->header = input_->header;
00057     // Clear the fields in case the method exits before computation
00058     normals_->width = normals_->height = 0;
00059     normals_->points.clear ();
00060   }
00061 
00062   // Copy the header
00063   output.header = input_->header;
00064 
00065   if (search_radius_ <= 0 || sqr_gauss_param_ <= 0)
00066   {
00067     PCL_ERROR ("[pcl::%s::reconstruct] Invalid search radius (%f) or Gaussian parameter (%f)!\n", getClassName ().c_str (), search_radius_, sqr_gauss_param_);
00068     output.width = output.height = 0;
00069     output.points.clear ();
00070     return;
00071   }
00072 
00073   
00074   if (!initCompute ()) 
00075   {
00076     output.width = output.height = 0;
00077     output.points.clear ();
00078     return;
00079   }
00080 
00081   // Initialize the spatial locator
00082   if (!tree_)
00083   {
00084     KdTreePtr tree;
00085     if (input_->isOrganized ())
00086       tree.reset (new pcl::search::OrganizedNeighbor<PointInT> ());
00087     else
00088       tree.reset (new pcl::search::KdTree<PointInT> (false));
00089     setSearchMethod (tree);
00090   }
00091 
00092   // Send the surface dataset to the spatial locator
00093   tree_->setInputCloud (input_, indices_);
00094 
00095   // Use original point positions for fitting
00096   // \note no up/down/adapting-sampling or hole filling possible like this
00097   output.points.resize (indices_->size ());
00098   // Check if fake indices were used, otherwise the output loses its organized structure
00099   if (!fake_indices_)
00100     pcl::copyPointCloud (*input_, *indices_, output);
00101   else
00102     output = *input_;
00103 
00104   // Resize the output normal dataset
00105   if (normals_)
00106   {
00107     normals_->points.resize (output.points.size ());
00108     normals_->width    = output.width;
00109     normals_->height   = output.height;
00110     normals_->is_dense = output.is_dense;
00111   }
00112 
00113   // Perform the actual surface reconstruction
00114   performReconstruction (output);
00115 
00116   deinitCompute ();
00117 }
00118 
00120 template <typename PointInT, typename NormalOutT> void
00121 pcl::MovingLeastSquares<PointInT, NormalOutT>::computeMLSPointNormal (PointInT &pt,
00122                                                                       const PointCloudIn &input,
00123                                                                       const std::vector<int> &nn_indices,
00124                                                                       std::vector<float> &nn_sqr_dists,
00125                                                                       Eigen::Vector4f &model_coefficients)
00126 {
00127   // Compute the plane coefficients
00128   //pcl::computePointNormal<PointInT> (*input_, nn_indices, model_coefficients, curvature);
00129   EIGEN_ALIGN16 Eigen::Matrix3f covariance_matrix;
00130   Eigen::Vector4f xyz_centroid;
00131 
00132   // Estimate the XYZ centroid
00133   pcl::compute3DCentroid (input, nn_indices, xyz_centroid);
00134 
00135   // Compute the 3x3 covariance matrix
00136   pcl::computeCovarianceMatrix (input, nn_indices, xyz_centroid, covariance_matrix);
00137 
00138   // Get the plane normal
00139   EIGEN_ALIGN16 Eigen::Vector3f::Scalar eigen_value;
00140   EIGEN_ALIGN16 Eigen::Vector3f eigen_vector;
00141   pcl::eigen33 (covariance_matrix, eigen_value, eigen_vector);
00142   model_coefficients.head<3> () = eigen_vector;
00143   model_coefficients[3] = -1 * model_coefficients.dot (xyz_centroid);
00144 
00145   // Projected point
00146   Eigen::Vector3f point = pt.getVector3fMap ();
00147   float distance = point.dot (model_coefficients.head<3> ()) + model_coefficients[3];
00148   point -= distance * model_coefficients.head<3> ();
00149 
00150   float curvature = covariance_matrix.trace ();
00151   // Compute the curvature surface change
00152   if (curvature != 0)
00153     curvature = fabs (eigen_value / curvature);
00154 
00155   // Perform polynomial fit to update point and normal
00157   if (polynomial_fit_ && (int)nn_indices.size () >= nr_coeff_)
00158   {
00159     // Get a copy of the plane normal easy access
00160     Eigen::Vector3d plane_normal = model_coefficients.head<3> ().cast<double> ();
00161 
00162     // Update neighborhood, since point was projected, and computing relative
00163     // positions. Note updating only distances for the weights for speed
00164     std::vector<Eigen::Vector3d> de_meaned (nn_indices.size ());
00165     for (size_t ni = 0; ni < nn_indices.size (); ++ni)
00166     {
00167       de_meaned[ni][0] = input_->points[nn_indices[ni]].x - point[0];
00168       de_meaned[ni][1] = input_->points[nn_indices[ni]].y - point[1];
00169       de_meaned[ni][2] = input_->points[nn_indices[ni]].z - point[2];
00170       nn_sqr_dists[ni] = de_meaned[ni].dot (de_meaned[ni]);
00171     }
00172 
00173     // Allocate matrices and vectors to hold the data used for the polynomial fit
00174     Eigen::VectorXd weight_vec (nn_indices.size ());
00175     Eigen::MatrixXd P (nr_coeff_, nn_indices.size ());
00176     Eigen::VectorXd f_vec (nn_indices.size ());
00177     Eigen::VectorXd c_vec;
00178     Eigen::MatrixXd P_weight; // size will be (nr_coeff_, nn_indices.size ());
00179     Eigen::MatrixXd P_weight_Pt (nr_coeff_, nr_coeff_);
00180 
00181     // Get local coordinate system (Darboux frame)
00182     Eigen::Vector3d v = plane_normal.unitOrthogonal ();
00183     Eigen::Vector3d u = plane_normal.cross (v);
00184 
00185     // Go through neighbors, transform them in the local coordinate system,
00186     // save height and the evaluation of the polynome's terms
00187     double u_coord, v_coord, u_pow, v_pow;
00188     for (size_t ni = 0; ni < nn_indices.size (); ++ni)
00189     {
00190       // (re-)compute weights
00191       weight_vec (ni) = exp (-nn_sqr_dists[ni] / sqr_gauss_param_);
00192 
00193       // transforming coordinates
00194       u_coord = de_meaned[ni].dot (u);
00195       v_coord = de_meaned[ni].dot (v);
00196       f_vec (ni) = de_meaned[ni].dot (plane_normal);
00197 
00198       // compute the polynomial's terms at the current point
00199       int j = 0;
00200       u_pow = 1;
00201       for (int ui = 0; ui <= order_; ++ui)
00202       {
00203         v_pow = 1;
00204         for (int vi = 0; vi <= order_ - ui; ++vi)
00205         {
00206           P (j++, ni) = u_pow * v_pow;
00207           v_pow *= v_coord;
00208         }
00209         u_pow *= u_coord;
00210       }
00211     }
00212 
00213     // Computing coefficients
00214     P_weight = P * weight_vec.asDiagonal ();
00215     P_weight_Pt = P_weight * P.transpose ();
00216     c_vec = P_weight * f_vec;
00217     P_weight_Pt.llt ().solveInPlace (c_vec);
00218 
00219     // Projection onto MLS surface along Darboux normal to the height at (0,0)
00220     if (pcl_isfinite (c_vec[0]))
00221     {
00222       point += (c_vec[0] * plane_normal).cast<float> ();
00223 
00224       // Compute tangent vectors using the partial derivates evaluated at (0,0) which is c_vec[order_+1] and c_vec[1]
00225       if (normals_)
00226       {
00227         Eigen::Vector3d normal = c_vec[order_ + 1] * u + c_vec[1] * v - plane_normal;
00228         model_coefficients.head<3> () = normal.cast<float> ();
00229         model_coefficients.head<3> ().normalize ();
00230       }
00231     }
00232   }
00233 
00234   // Save the smoothed results
00235   pt.x = point[0];
00236   pt.y = point[1];
00237   pt.z = point[2];
00238 
00239   model_coefficients[3] = curvature;
00240 }
00241 
00243 template <typename PointInT, typename NormalOutT> void
00244 pcl::MovingLeastSquares<PointInT, NormalOutT>::performReconstruction (PointCloudIn &output)
00245 {
00246   // Compute the number of coefficients
00247   nr_coeff_ = (order_ + 1) * (order_ + 2) / 2;
00248 
00249   // Allocate enough space to hold the results of nearest neighbor searches
00250   // \note resize is irrelevant for a radiusSearch ().
00251   std::vector<int> nn_indices;
00252   std::vector<float> nn_sqr_dists;
00253   
00254   // For all points
00255   for (size_t cp = 0; cp < indices_->size (); ++cp)
00256   {
00257     // Get the initial estimates of point positions and their neighborhoods
00258     if (!searchForNeighbors ((*indices_)[cp], nn_indices, nn_sqr_dists))
00259     {
00260       if (normals_)
00261         normals_->points[cp].normal[0] = normals_->points[cp].normal[1] = normals_->points[cp].normal[2] = normals_->points[cp].curvature = std::numeric_limits<float>::quiet_NaN ();
00262       continue;
00263     }
00264 
00265     // Check the number of nearest neighbors for normal estimation (and later
00266     // for polynomial fit as well)
00267     if (nn_indices.size () < 3)
00268       continue;
00269 
00270     Eigen::Vector4f model_coefficients;
00271     // Get a plane approximating the local surface's tangent and project point onto it
00272     computeMLSPointNormal (output.points[cp], *input_, nn_indices, nn_sqr_dists,
00273                            model_coefficients); 
00274 
00275     // Save results to output cloud
00276     if (normals_)
00277     {
00278       normals_->points[cp].normal[0] = model_coefficients[0];
00279       normals_->points[cp].normal[1] = model_coefficients[1];
00280       normals_->points[cp].normal[2] = model_coefficients[2];
00281       normals_->points[cp].curvature = model_coefficients[3];
00282     }
00283   }
00284 }
00285 
00286 #define PCL_INSTANTIATE_MovingLeastSquares(T,OutT) template class PCL_EXPORTS pcl::MovingLeastSquares<T,OutT>;
00287 
00288 #endif    // PCL_SURFACE_IMPL_MLS_H_
00289 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines