|
Point Cloud Library (PCL)
1.6.0
|
00001 /* 00002 * Software License Agreement (BSD License) 00003 * 00004 * Copyright (c) 2009, Willow Garage, Inc. 00005 * All rights reserved. 00006 * 00007 * Redistribution and use in source and binary forms, with or without 00008 * modification, are permitted provided that the following conditions 00009 * are met: 00010 * 00011 * * Redistributions of source code must retain the above copyright 00012 * notice, this list of conditions and the following disclaimer. 00013 * * Redistributions in binary form must reproduce the above 00014 * copyright notice, this list of conditions and the following 00015 * disclaimer in the documentation and/or other materials provided 00016 * with the distribution. 00017 * * Neither the name of Willow Garage, Inc. nor the names of its 00018 * contributors may be used to endorse or promote products derived 00019 * from this software without specific prior written permission. 00020 * 00021 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00022 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00023 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 00024 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 00025 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 00026 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 00027 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00028 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 00029 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00030 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 00031 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00032 * POSSIBILITY OF SUCH DAMAGE. 00033 * 00034 * $Id: sac_model_plane.hpp 6144 2012-07-04 22:06:28Z rusu $ 00035 * 00036 */ 00037 00038 #ifndef PCL_SAMPLE_CONSENSUS_IMPL_SAC_MODEL_PLANE_H_ 00039 #define PCL_SAMPLE_CONSENSUS_IMPL_SAC_MODEL_PLANE_H_ 00040 00041 #include <pcl/sample_consensus/sac_model_plane.h> 00042 #include <pcl/common/centroid.h> 00043 #include <pcl/common/eigen.h> 00044 #include <pcl/common/concatenate.h> 00045 00047 template <typename PointT> bool 00048 pcl::SampleConsensusModelPlane<PointT>::isSampleGood (const std::vector<int> &samples) const 00049 { 00050 // Need an extra check in case the sample selection is empty 00051 if (samples.empty ()) 00052 return (false); 00053 // Get the values at the two points 00054 pcl::Array4fMapConst p0 = input_->points[samples[0]].getArray4fMap (); 00055 pcl::Array4fMapConst p1 = input_->points[samples[1]].getArray4fMap (); 00056 pcl::Array4fMapConst p2 = input_->points[samples[2]].getArray4fMap (); 00057 00058 Eigen::Array4f dy1dy2 = (p1-p0) / (p2-p0); 00059 00060 return ( (dy1dy2[0] != dy1dy2[1]) || (dy1dy2[2] != dy1dy2[1]) ); 00061 } 00062 00064 template <typename PointT> bool 00065 pcl::SampleConsensusModelPlane<PointT>::computeModelCoefficients ( 00066 const std::vector<int> &samples, Eigen::VectorXf &model_coefficients) 00067 { 00068 // Need 3 samples 00069 if (samples.size () != 3) 00070 { 00071 PCL_ERROR ("[pcl::SampleConsensusModelPlane::computeModelCoefficients] Invalid set of samples given (%zu)!\n", samples.size ()); 00072 return (false); 00073 } 00074 00075 pcl::Array4fMapConst p0 = input_->points[samples[0]].getArray4fMap (); 00076 pcl::Array4fMapConst p1 = input_->points[samples[1]].getArray4fMap (); 00077 pcl::Array4fMapConst p2 = input_->points[samples[2]].getArray4fMap (); 00078 00079 // Compute the segment values (in 3d) between p1 and p0 00080 Eigen::Array4f p1p0 = p1 - p0; 00081 // Compute the segment values (in 3d) between p2 and p0 00082 Eigen::Array4f p2p0 = p2 - p0; 00083 00084 // Avoid some crashes by checking for collinearity here 00085 Eigen::Array4f dy1dy2 = p1p0 / p2p0; 00086 if ( (dy1dy2[0] == dy1dy2[1]) && (dy1dy2[2] == dy1dy2[1]) ) // Check for collinearity 00087 return (false); 00088 00089 // Compute the plane coefficients from the 3 given points in a straightforward manner 00090 // calculate the plane normal n = (p2-p1) x (p3-p1) = cross (p2-p1, p3-p1) 00091 model_coefficients.resize (4); 00092 model_coefficients[0] = p1p0[1] * p2p0[2] - p1p0[2] * p2p0[1]; 00093 model_coefficients[1] = p1p0[2] * p2p0[0] - p1p0[0] * p2p0[2]; 00094 model_coefficients[2] = p1p0[0] * p2p0[1] - p1p0[1] * p2p0[0]; 00095 model_coefficients[3] = 0; 00096 00097 // Normalize 00098 model_coefficients.normalize (); 00099 00100 // ... + d = 0 00101 model_coefficients[3] = -1 * (model_coefficients.template head<4>().dot (p0.matrix ())); 00102 00103 return (true); 00104 } 00105 00107 template <typename PointT> void 00108 pcl::SampleConsensusModelPlane<PointT>::getDistancesToModel ( 00109 const Eigen::VectorXf &model_coefficients, std::vector<double> &distances) 00110 { 00111 // Needs a valid set of model coefficients 00112 if (model_coefficients.size () != 4) 00113 { 00114 PCL_ERROR ("[pcl::SampleConsensusModelPlane::getDistancesToModel] Invalid number of model coefficients given (%zu)!\n", model_coefficients.size ()); 00115 return; 00116 } 00117 00118 distances.resize (indices_->size ()); 00119 00120 // Iterate through the 3d points and calculate the distances from them to the plane 00121 for (size_t i = 0; i < indices_->size (); ++i) 00122 { 00123 // Calculate the distance from the point to the plane normal as the dot product 00124 // D = (P-A).N/|N| 00125 /*distances[i] = fabs (model_coefficients[0] * input_->points[(*indices_)[i]].x + 00126 model_coefficients[1] * input_->points[(*indices_)[i]].y + 00127 model_coefficients[2] * input_->points[(*indices_)[i]].z + 00128 model_coefficients[3]);*/ 00129 Eigen::Vector4f pt (input_->points[(*indices_)[i]].x, 00130 input_->points[(*indices_)[i]].y, 00131 input_->points[(*indices_)[i]].z, 00132 1); 00133 distances[i] = fabs (model_coefficients.dot (pt)); 00134 } 00135 } 00136 00138 template <typename PointT> void 00139 pcl::SampleConsensusModelPlane<PointT>::selectWithinDistance ( 00140 const Eigen::VectorXf &model_coefficients, const double threshold, std::vector<int> &inliers) 00141 { 00142 // Needs a valid set of model coefficients 00143 if (model_coefficients.size () != 4) 00144 { 00145 PCL_ERROR ("[pcl::SampleConsensusModelPlane::selectWithinDistance] Invalid number of model coefficients given (%zu)!\n", model_coefficients.size ()); 00146 return; 00147 } 00148 00149 int nr_p = 0; 00150 inliers.resize (indices_->size ()); 00151 00152 // Iterate through the 3d points and calculate the distances from them to the plane 00153 for (size_t i = 0; i < indices_->size (); ++i) 00154 { 00155 // Calculate the distance from the point to the plane normal as the dot product 00156 // D = (P-A).N/|N| 00157 Eigen::Vector4f pt (input_->points[(*indices_)[i]].x, 00158 input_->points[(*indices_)[i]].y, 00159 input_->points[(*indices_)[i]].z, 00160 1); 00161 if (fabs (model_coefficients.dot (pt)) < threshold) 00162 { 00163 // Returns the indices of the points whose distances are smaller than the threshold 00164 inliers[nr_p] = (*indices_)[i]; 00165 nr_p++; 00166 } 00167 } 00168 inliers.resize (nr_p); 00169 } 00170 00172 template <typename PointT> int 00173 pcl::SampleConsensusModelPlane<PointT>::countWithinDistance ( 00174 const Eigen::VectorXf &model_coefficients, const double threshold) 00175 { 00176 // Needs a valid set of model coefficients 00177 if (model_coefficients.size () != 4) 00178 { 00179 PCL_ERROR ("[pcl::SampleConsensusModelPlane::countWithinDistance] Invalid number of model coefficients given (%zu)!\n", model_coefficients.size ()); 00180 return (0); 00181 } 00182 00183 int nr_p = 0; 00184 00185 // Iterate through the 3d points and calculate the distances from them to the plane 00186 for (size_t i = 0; i < indices_->size (); ++i) 00187 { 00188 // Calculate the distance from the point to the plane normal as the dot product 00189 // D = (P-A).N/|N| 00190 Eigen::Vector4f pt (input_->points[(*indices_)[i]].x, 00191 input_->points[(*indices_)[i]].y, 00192 input_->points[(*indices_)[i]].z, 00193 1); 00194 if (fabs (model_coefficients.dot (pt)) < threshold) 00195 nr_p++; 00196 } 00197 return (nr_p); 00198 } 00199 00201 template <typename PointT> void 00202 pcl::SampleConsensusModelPlane<PointT>::optimizeModelCoefficients ( 00203 const std::vector<int> &inliers, const Eigen::VectorXf &model_coefficients, Eigen::VectorXf &optimized_coefficients) 00204 { 00205 // Needs a valid set of model coefficients 00206 if (model_coefficients.size () != 4) 00207 { 00208 PCL_ERROR ("[pcl::SampleConsensusModelPlane::optimizeModelCoefficients] Invalid number of model coefficients given (%zu)!\n", model_coefficients.size ()); 00209 optimized_coefficients = model_coefficients; 00210 return; 00211 } 00212 00213 // Need at least 3 points to estimate a plane 00214 if (inliers.size () < 4) 00215 { 00216 PCL_ERROR ("[pcl::SampleConsensusModelPlane::optimizeModelCoefficients] Not enough inliers found to support a model (%zu)! Returning the same coefficients.\n", inliers.size ()); 00217 optimized_coefficients = model_coefficients; 00218 return; 00219 } 00220 00221 Eigen::Vector4f plane_parameters; 00222 00223 // Use Least-Squares to fit the plane through all the given sample points and find out its coefficients 00224 EIGEN_ALIGN16 Eigen::Matrix3f covariance_matrix; 00225 Eigen::Vector4f xyz_centroid; 00226 00227 computeMeanAndCovarianceMatrix (*input_, inliers, covariance_matrix, xyz_centroid); 00228 00229 // Compute the model coefficients 00230 EIGEN_ALIGN16 Eigen::Vector3f::Scalar eigen_value; 00231 EIGEN_ALIGN16 Eigen::Vector3f eigen_vector; 00232 pcl::eigen33 (covariance_matrix, eigen_value, eigen_vector); 00233 00234 // Hessian form (D = nc . p_plane (centroid here) + p) 00235 optimized_coefficients.resize (4); 00236 optimized_coefficients[0] = eigen_vector [0]; 00237 optimized_coefficients[1] = eigen_vector [1]; 00238 optimized_coefficients[2] = eigen_vector [2]; 00239 optimized_coefficients[3] = 0; 00240 optimized_coefficients[3] = -1 * optimized_coefficients.dot (xyz_centroid); 00241 } 00242 00244 template <typename PointT> void 00245 pcl::SampleConsensusModelPlane<PointT>::projectPoints ( 00246 const std::vector<int> &inliers, const Eigen::VectorXf &model_coefficients, PointCloud &projected_points, bool copy_data_fields) 00247 { 00248 // Needs a valid set of model coefficients 00249 if (model_coefficients.size () != 4) 00250 { 00251 PCL_ERROR ("[pcl::SampleConsensusModelPlane::projectPoints] Invalid number of model coefficients given (%zu)!\n", model_coefficients.size ()); 00252 return; 00253 } 00254 00255 projected_points.header = input_->header; 00256 projected_points.is_dense = input_->is_dense; 00257 00258 Eigen::Vector4f mc (model_coefficients[0], model_coefficients[1], model_coefficients[2], 0); 00259 00260 // normalize the vector perpendicular to the plane... 00261 mc.normalize (); 00262 // ... and store the resulting normal as a local copy of the model coefficients 00263 Eigen::Vector4f tmp_mc = model_coefficients; 00264 tmp_mc[0] = mc[0]; 00265 tmp_mc[1] = mc[1]; 00266 tmp_mc[2] = mc[2]; 00267 00268 // Copy all the data fields from the input cloud to the projected one? 00269 if (copy_data_fields) 00270 { 00271 // Allocate enough space and copy the basics 00272 projected_points.points.resize (input_->points.size ()); 00273 projected_points.width = input_->width; 00274 projected_points.height = input_->height; 00275 00276 typedef typename pcl::traits::fieldList<PointT>::type FieldList; 00277 // Iterate over each point 00278 for (size_t i = 0; i < input_->points.size (); ++i) 00279 // Iterate over each dimension 00280 pcl::for_each_type <FieldList> (NdConcatenateFunctor <PointT, PointT> (input_->points[i], projected_points.points[i])); 00281 00282 // Iterate through the 3d points and calculate the distances from them to the plane 00283 for (size_t i = 0; i < inliers.size (); ++i) 00284 { 00285 // Calculate the distance from the point to the plane 00286 Eigen::Vector4f p (input_->points[inliers[i]].x, 00287 input_->points[inliers[i]].y, 00288 input_->points[inliers[i]].z, 00289 1); 00290 // use normalized coefficients to calculate the scalar projection 00291 float distance_to_plane = tmp_mc.dot (p); 00292 00293 pcl::Vector4fMap pp = projected_points.points[inliers[i]].getVector4fMap (); 00294 pp = p - mc * distance_to_plane; // mc[3] = 0, therefore the 3rd coordinate is safe 00295 } 00296 } 00297 else 00298 { 00299 // Allocate enough space and copy the basics 00300 projected_points.points.resize (inliers.size ()); 00301 projected_points.width = static_cast<uint32_t> (inliers.size ()); 00302 projected_points.height = 1; 00303 00304 typedef typename pcl::traits::fieldList<PointT>::type FieldList; 00305 // Iterate over each point 00306 for (size_t i = 0; i < inliers.size (); ++i) 00307 // Iterate over each dimension 00308 pcl::for_each_type <FieldList> (NdConcatenateFunctor <PointT, PointT> (input_->points[inliers[i]], projected_points.points[i])); 00309 00310 // Iterate through the 3d points and calculate the distances from them to the plane 00311 for (size_t i = 0; i < inliers.size (); ++i) 00312 { 00313 // Calculate the distance from the point to the plane 00314 Eigen::Vector4f p (input_->points[inliers[i]].x, 00315 input_->points[inliers[i]].y, 00316 input_->points[inliers[i]].z, 00317 1); 00318 // use normalized coefficients to calculate the scalar projection 00319 float distance_to_plane = tmp_mc.dot (p); 00320 00321 pcl::Vector4fMap pp = projected_points.points[i].getVector4fMap (); 00322 pp = p - mc * distance_to_plane; // mc[3] = 0, therefore the 3rd coordinate is safe 00323 } 00324 } 00325 } 00326 00328 template <typename PointT> bool 00329 pcl::SampleConsensusModelPlane<PointT>::doSamplesVerifyModel ( 00330 const std::set<int> &indices, const Eigen::VectorXf &model_coefficients, const double threshold) 00331 { 00332 // Needs a valid set of model coefficients 00333 if (model_coefficients.size () != 4) 00334 { 00335 PCL_ERROR ("[pcl::SampleConsensusModelPlane::doSamplesVerifyModel] Invalid number of model coefficients given (%zu)!\n", model_coefficients.size ()); 00336 return (false); 00337 } 00338 00339 for (std::set<int>::const_iterator it = indices.begin (); it != indices.end (); ++it) 00340 { 00341 Eigen::Vector4f pt (input_->points[*it].x, 00342 input_->points[*it].y, 00343 input_->points[*it].z, 00344 1); 00345 if (fabs (model_coefficients.dot (pt)) > threshold) 00346 return (false); 00347 } 00348 00349 return (true); 00350 } 00351 00352 #define PCL_INSTANTIATE_SampleConsensusModelPlane(T) template class PCL_EXPORTS pcl::SampleConsensusModelPlane<T>; 00353 00354 #endif // PCL_SAMPLE_CONSENSUS_IMPL_SAC_MODEL_PLANE_H_ 00355
1.7.6.1