|
Point Cloud Library (PCL)
1.4.0
|
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
1.7.6.1