Point Cloud Library (PCL)  1.6.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
sac_model_plane.hpp
Go to the documentation of this file.
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2009, Willow Garage, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of Willow Garage, Inc. nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * $Id: sac_model_plane.hpp 6144 2012-07-04 22:06:28Z rusu $
35  *
36  */
37 
38 #ifndef PCL_SAMPLE_CONSENSUS_IMPL_SAC_MODEL_PLANE_H_
39 #define PCL_SAMPLE_CONSENSUS_IMPL_SAC_MODEL_PLANE_H_
40 
42 #include <pcl/common/centroid.h>
43 #include <pcl/common/eigen.h>
44 #include <pcl/common/concatenate.h>
45 
47 template <typename PointT> bool
48 pcl::SampleConsensusModelPlane<PointT>::isSampleGood (const std::vector<int> &samples) const
49 {
50  // Need an extra check in case the sample selection is empty
51  if (samples.empty ())
52  return (false);
53  // Get the values at the two points
54  pcl::Array4fMapConst p0 = input_->points[samples[0]].getArray4fMap ();
55  pcl::Array4fMapConst p1 = input_->points[samples[1]].getArray4fMap ();
56  pcl::Array4fMapConst p2 = input_->points[samples[2]].getArray4fMap ();
57 
58  Eigen::Array4f dy1dy2 = (p1-p0) / (p2-p0);
59 
60  return ( (dy1dy2[0] != dy1dy2[1]) || (dy1dy2[2] != dy1dy2[1]) );
61 }
62 
64 template <typename PointT> bool
66  const std::vector<int> &samples, Eigen::VectorXf &model_coefficients)
67 {
68  // Need 3 samples
69  if (samples.size () != 3)
70  {
71  PCL_ERROR ("[pcl::SampleConsensusModelPlane::computeModelCoefficients] Invalid set of samples given (%zu)!\n", samples.size ());
72  return (false);
73  }
74 
75  pcl::Array4fMapConst p0 = input_->points[samples[0]].getArray4fMap ();
76  pcl::Array4fMapConst p1 = input_->points[samples[1]].getArray4fMap ();
77  pcl::Array4fMapConst p2 = input_->points[samples[2]].getArray4fMap ();
78 
79  // Compute the segment values (in 3d) between p1 and p0
80  Eigen::Array4f p1p0 = p1 - p0;
81  // Compute the segment values (in 3d) between p2 and p0
82  Eigen::Array4f p2p0 = p2 - p0;
83 
84  // Avoid some crashes by checking for collinearity here
85  Eigen::Array4f dy1dy2 = p1p0 / p2p0;
86  if ( (dy1dy2[0] == dy1dy2[1]) && (dy1dy2[2] == dy1dy2[1]) ) // Check for collinearity
87  return (false);
88 
89  // Compute the plane coefficients from the 3 given points in a straightforward manner
90  // calculate the plane normal n = (p2-p1) x (p3-p1) = cross (p2-p1, p3-p1)
91  model_coefficients.resize (4);
92  model_coefficients[0] = p1p0[1] * p2p0[2] - p1p0[2] * p2p0[1];
93  model_coefficients[1] = p1p0[2] * p2p0[0] - p1p0[0] * p2p0[2];
94  model_coefficients[2] = p1p0[0] * p2p0[1] - p1p0[1] * p2p0[0];
95  model_coefficients[3] = 0;
96 
97  // Normalize
98  model_coefficients.normalize ();
99 
100  // ... + d = 0
101  model_coefficients[3] = -1 * (model_coefficients.template head<4>().dot (p0.matrix ()));
102 
103  return (true);
104 }
105 
107 template <typename PointT> void
109  const Eigen::VectorXf &model_coefficients, std::vector<double> &distances)
110 {
111  // Needs a valid set of model coefficients
112  if (model_coefficients.size () != 4)
113  {
114  PCL_ERROR ("[pcl::SampleConsensusModelPlane::getDistancesToModel] Invalid number of model coefficients given (%zu)!\n", model_coefficients.size ());
115  return;
116  }
117 
118  distances.resize (indices_->size ());
119 
120  // Iterate through the 3d points and calculate the distances from them to the plane
121  for (size_t i = 0; i < indices_->size (); ++i)
122  {
123  // Calculate the distance from the point to the plane normal as the dot product
124  // D = (P-A).N/|N|
125  /*distances[i] = fabs (model_coefficients[0] * input_->points[(*indices_)[i]].x +
126  model_coefficients[1] * input_->points[(*indices_)[i]].y +
127  model_coefficients[2] * input_->points[(*indices_)[i]].z +
128  model_coefficients[3]);*/
129  Eigen::Vector4f pt (input_->points[(*indices_)[i]].x,
130  input_->points[(*indices_)[i]].y,
131  input_->points[(*indices_)[i]].z,
132  1);
133  distances[i] = fabs (model_coefficients.dot (pt));
134  }
135 }
136 
138 template <typename PointT> void
140  const Eigen::VectorXf &model_coefficients, const double threshold, std::vector<int> &inliers)
141 {
142  // Needs a valid set of model coefficients
143  if (model_coefficients.size () != 4)
144  {
145  PCL_ERROR ("[pcl::SampleConsensusModelPlane::selectWithinDistance] Invalid number of model coefficients given (%zu)!\n", model_coefficients.size ());
146  return;
147  }
148 
149  int nr_p = 0;
150  inliers.resize (indices_->size ());
151 
152  // Iterate through the 3d points and calculate the distances from them to the plane
153  for (size_t i = 0; i < indices_->size (); ++i)
154  {
155  // Calculate the distance from the point to the plane normal as the dot product
156  // D = (P-A).N/|N|
157  Eigen::Vector4f pt (input_->points[(*indices_)[i]].x,
158  input_->points[(*indices_)[i]].y,
159  input_->points[(*indices_)[i]].z,
160  1);
161  if (fabs (model_coefficients.dot (pt)) < threshold)
162  {
163  // Returns the indices of the points whose distances are smaller than the threshold
164  inliers[nr_p] = (*indices_)[i];
165  nr_p++;
166  }
167  }
168  inliers.resize (nr_p);
169 }
170 
172 template <typename PointT> int
174  const Eigen::VectorXf &model_coefficients, const double threshold)
175 {
176  // Needs a valid set of model coefficients
177  if (model_coefficients.size () != 4)
178  {
179  PCL_ERROR ("[pcl::SampleConsensusModelPlane::countWithinDistance] Invalid number of model coefficients given (%zu)!\n", model_coefficients.size ());
180  return (0);
181  }
182 
183  int nr_p = 0;
184 
185  // Iterate through the 3d points and calculate the distances from them to the plane
186  for (size_t i = 0; i < indices_->size (); ++i)
187  {
188  // Calculate the distance from the point to the plane normal as the dot product
189  // D = (P-A).N/|N|
190  Eigen::Vector4f pt (input_->points[(*indices_)[i]].x,
191  input_->points[(*indices_)[i]].y,
192  input_->points[(*indices_)[i]].z,
193  1);
194  if (fabs (model_coefficients.dot (pt)) < threshold)
195  nr_p++;
196  }
197  return (nr_p);
198 }
199 
201 template <typename PointT> void
203  const std::vector<int> &inliers, const Eigen::VectorXf &model_coefficients, Eigen::VectorXf &optimized_coefficients)
204 {
205  // Needs a valid set of model coefficients
206  if (model_coefficients.size () != 4)
207  {
208  PCL_ERROR ("[pcl::SampleConsensusModelPlane::optimizeModelCoefficients] Invalid number of model coefficients given (%zu)!\n", model_coefficients.size ());
209  optimized_coefficients = model_coefficients;
210  return;
211  }
212 
213  // Need at least 3 points to estimate a plane
214  if (inliers.size () < 4)
215  {
216  PCL_ERROR ("[pcl::SampleConsensusModelPlane::optimizeModelCoefficients] Not enough inliers found to support a model (%zu)! Returning the same coefficients.\n", inliers.size ());
217  optimized_coefficients = model_coefficients;
218  return;
219  }
220 
221  Eigen::Vector4f plane_parameters;
222 
223  // Use Least-Squares to fit the plane through all the given sample points and find out its coefficients
224  EIGEN_ALIGN16 Eigen::Matrix3f covariance_matrix;
225  Eigen::Vector4f xyz_centroid;
226 
227  computeMeanAndCovarianceMatrix (*input_, inliers, covariance_matrix, xyz_centroid);
228 
229  // Compute the model coefficients
230  EIGEN_ALIGN16 Eigen::Vector3f::Scalar eigen_value;
231  EIGEN_ALIGN16 Eigen::Vector3f eigen_vector;
232  pcl::eigen33 (covariance_matrix, eigen_value, eigen_vector);
233 
234  // Hessian form (D = nc . p_plane (centroid here) + p)
235  optimized_coefficients.resize (4);
236  optimized_coefficients[0] = eigen_vector [0];
237  optimized_coefficients[1] = eigen_vector [1];
238  optimized_coefficients[2] = eigen_vector [2];
239  optimized_coefficients[3] = 0;
240  optimized_coefficients[3] = -1 * optimized_coefficients.dot (xyz_centroid);
241 }
242 
244 template <typename PointT> void
246  const std::vector<int> &inliers, const Eigen::VectorXf &model_coefficients, PointCloud &projected_points, bool copy_data_fields)
247 {
248  // Needs a valid set of model coefficients
249  if (model_coefficients.size () != 4)
250  {
251  PCL_ERROR ("[pcl::SampleConsensusModelPlane::projectPoints] Invalid number of model coefficients given (%zu)!\n", model_coefficients.size ());
252  return;
253  }
254 
255  projected_points.header = input_->header;
256  projected_points.is_dense = input_->is_dense;
257 
258  Eigen::Vector4f mc (model_coefficients[0], model_coefficients[1], model_coefficients[2], 0);
259 
260  // normalize the vector perpendicular to the plane...
261  mc.normalize ();
262  // ... and store the resulting normal as a local copy of the model coefficients
263  Eigen::Vector4f tmp_mc = model_coefficients;
264  tmp_mc[0] = mc[0];
265  tmp_mc[1] = mc[1];
266  tmp_mc[2] = mc[2];
267 
268  // Copy all the data fields from the input cloud to the projected one?
269  if (copy_data_fields)
270  {
271  // Allocate enough space and copy the basics
272  projected_points.points.resize (input_->points.size ());
273  projected_points.width = input_->width;
274  projected_points.height = input_->height;
275 
276  typedef typename pcl::traits::fieldList<PointT>::type FieldList;
277  // Iterate over each point
278  for (size_t i = 0; i < input_->points.size (); ++i)
279  // Iterate over each dimension
280  pcl::for_each_type <FieldList> (NdConcatenateFunctor <PointT, PointT> (input_->points[i], projected_points.points[i]));
281 
282  // Iterate through the 3d points and calculate the distances from them to the plane
283  for (size_t i = 0; i < inliers.size (); ++i)
284  {
285  // Calculate the distance from the point to the plane
286  Eigen::Vector4f p (input_->points[inliers[i]].x,
287  input_->points[inliers[i]].y,
288  input_->points[inliers[i]].z,
289  1);
290  // use normalized coefficients to calculate the scalar projection
291  float distance_to_plane = tmp_mc.dot (p);
292 
293  pcl::Vector4fMap pp = projected_points.points[inliers[i]].getVector4fMap ();
294  pp = p - mc * distance_to_plane; // mc[3] = 0, therefore the 3rd coordinate is safe
295  }
296  }
297  else
298  {
299  // Allocate enough space and copy the basics
300  projected_points.points.resize (inliers.size ());
301  projected_points.width = static_cast<uint32_t> (inliers.size ());
302  projected_points.height = 1;
303 
304  typedef typename pcl::traits::fieldList<PointT>::type FieldList;
305  // Iterate over each point
306  for (size_t i = 0; i < inliers.size (); ++i)
307  // Iterate over each dimension
308  pcl::for_each_type <FieldList> (NdConcatenateFunctor <PointT, PointT> (input_->points[inliers[i]], projected_points.points[i]));
309 
310  // Iterate through the 3d points and calculate the distances from them to the plane
311  for (size_t i = 0; i < inliers.size (); ++i)
312  {
313  // Calculate the distance from the point to the plane
314  Eigen::Vector4f p (input_->points[inliers[i]].x,
315  input_->points[inliers[i]].y,
316  input_->points[inliers[i]].z,
317  1);
318  // use normalized coefficients to calculate the scalar projection
319  float distance_to_plane = tmp_mc.dot (p);
320 
321  pcl::Vector4fMap pp = projected_points.points[i].getVector4fMap ();
322  pp = p - mc * distance_to_plane; // mc[3] = 0, therefore the 3rd coordinate is safe
323  }
324  }
325 }
326 
328 template <typename PointT> bool
330  const std::set<int> &indices, const Eigen::VectorXf &model_coefficients, const double threshold)
331 {
332  // Needs a valid set of model coefficients
333  if (model_coefficients.size () != 4)
334  {
335  PCL_ERROR ("[pcl::SampleConsensusModelPlane::doSamplesVerifyModel] Invalid number of model coefficients given (%zu)!\n", model_coefficients.size ());
336  return (false);
337  }
338 
339  for (std::set<int>::const_iterator it = indices.begin (); it != indices.end (); ++it)
340  {
341  Eigen::Vector4f pt (input_->points[*it].x,
342  input_->points[*it].y,
343  input_->points[*it].z,
344  1);
345  if (fabs (model_coefficients.dot (pt)) > threshold)
346  return (false);
347  }
348 
349  return (true);
350 }
351 
352 #define PCL_INSTANTIATE_SampleConsensusModelPlane(T) template class PCL_EXPORTS pcl::SampleConsensusModelPlane<T>;
353 
354 #endif // PCL_SAMPLE_CONSENSUS_IMPL_SAC_MODEL_PLANE_H_
355