Point Cloud Library (PCL)  1.6.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
sac_model_line.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_line.hpp 6144 2012-07-04 22:06:28Z rusu $
35  *
36  */
37 
38 #ifndef PCL_SAMPLE_CONSENSUS_IMPL_SAC_MODEL_LINE_H_
39 #define PCL_SAMPLE_CONSENSUS_IMPL_SAC_MODEL_LINE_H_
40 
42 #include <pcl/common/centroid.h>
43 #include <pcl/common/concatenate.h>
44 
46 template <typename PointT> bool
47 pcl::SampleConsensusModelLine<PointT>::isSampleGood (const std::vector<int> &samples) const
48 {
49  if (
50  (input_->points[samples[0]].x != input_->points[samples[1]].x)
51  &&
52  (input_->points[samples[0]].y != input_->points[samples[1]].y)
53  &&
54  (input_->points[samples[0]].z != input_->points[samples[1]].z))
55  return (true);
56 
57  return (true);
58 }
59 
61 template <typename PointT> bool
63  const std::vector<int> &samples, Eigen::VectorXf &model_coefficients)
64 {
65  // Need 2 samples
66  if (samples.size () != 2)
67  {
68  PCL_ERROR ("[pcl::SampleConsensusModelLine::computeModelCoefficients] Invalid set of samples given (%zu)!\n", samples.size ());
69  return (false);
70  }
71 
72  model_coefficients.resize (6);
73  model_coefficients[0] = input_->points[samples[0]].x;
74  model_coefficients[1] = input_->points[samples[0]].y;
75  model_coefficients[2] = input_->points[samples[0]].z;
76 
77  model_coefficients[3] = input_->points[samples[1]].x - model_coefficients[0];
78  model_coefficients[4] = input_->points[samples[1]].y - model_coefficients[1];
79  model_coefficients[5] = input_->points[samples[1]].z - model_coefficients[2];
80 
81  model_coefficients.template tail<3> ().normalize ();
82  return (true);
83 }
84 
86 template <typename PointT> void
88  const Eigen::VectorXf &model_coefficients, std::vector<double> &distances)
89 {
90  // Needs a valid set of model coefficients
91  if (!isModelValid (model_coefficients))
92  return;
93 
94  distances.resize (indices_->size ());
95 
96  // Obtain the line point and direction
97  Eigen::Vector4f line_pt (model_coefficients[0], model_coefficients[1], model_coefficients[2], 0);
98  Eigen::Vector4f line_dir (model_coefficients[3], model_coefficients[4], model_coefficients[5], 0);
99  line_dir.normalize ();
100 
101  // Iterate through the 3d points and calculate the distances from them to the line
102  for (size_t i = 0; i < indices_->size (); ++i)
103  {
104  // Calculate the distance from the point to the line
105  // D = ||(P2-P1) x (P1-P0)|| / ||P2-P1|| = norm (cross (p2-p1, p2-p0)) / norm(p2-p1)
106  // Need to estimate sqrt here to keep MSAC and friends general
107  distances[i] = sqrt ((line_pt - input_->points[(*indices_)[i]].getVector4fMap ()).cross3 (line_dir).squaredNorm ());
108  }
109 }
110 
112 template <typename PointT> void
114  const Eigen::VectorXf &model_coefficients, const double threshold, std::vector<int> &inliers)
115 {
116  // Needs a valid set of model coefficients
117  if (!isModelValid (model_coefficients))
118  return;
119 
120  double sqr_threshold = threshold * threshold;
121 
122  int nr_p = 0;
123  inliers.resize (indices_->size ());
124 
125  // Obtain the line point and direction
126  Eigen::Vector4f line_pt (model_coefficients[0], model_coefficients[1], model_coefficients[2], 0);
127  Eigen::Vector4f line_dir (model_coefficients[3], model_coefficients[4], model_coefficients[5], 0);
128  line_dir.normalize ();
129 
130  // Iterate through the 3d points and calculate the distances from them to the line
131  for (size_t i = 0; i < indices_->size (); ++i)
132  {
133  // Calculate the distance from the point to the line
134  // D = ||(P2-P1) x (P1-P0)|| / ||P2-P1|| = norm (cross (p2-p1, p2-p0)) / norm(p2-p1)
135  double sqr_distance = (line_pt - input_->points[(*indices_)[i]].getVector4fMap ()).cross3 (line_dir).squaredNorm ();
136 
137  if (sqr_distance < sqr_threshold)
138  {
139  // Returns the indices of the points whose squared distances are smaller than the threshold
140  inliers[nr_p] = (*indices_)[i];
141  nr_p++;
142  }
143  }
144  inliers.resize (nr_p);
145 }
146 
148 template <typename PointT> int
150  const Eigen::VectorXf &model_coefficients, const double threshold)
151 {
152  // Needs a valid set of model coefficients
153  if (!isModelValid (model_coefficients))
154  return (0);
155 
156  double sqr_threshold = threshold * threshold;
157 
158  int nr_p = 0;
159 
160  // Obtain the line point and direction
161  Eigen::Vector4f line_pt (model_coefficients[0], model_coefficients[1], model_coefficients[2], 0);
162  Eigen::Vector4f line_dir (model_coefficients[3], model_coefficients[4], model_coefficients[5], 0);
163  line_dir.normalize ();
164 
165  // Iterate through the 3d points and calculate the distances from them to the line
166  for (size_t i = 0; i < indices_->size (); ++i)
167  {
168  // Calculate the distance from the point to the line
169  // D = ||(P2-P1) x (P1-P0)|| / ||P2-P1|| = norm (cross (p2-p1, p2-p0)) / norm(p2-p1)
170  double sqr_distance = (line_pt - input_->points[(*indices_)[i]].getVector4fMap ()).cross3 (line_dir).squaredNorm ();
171 
172  if (sqr_distance < sqr_threshold)
173  nr_p++;
174  }
175  return (nr_p);
176 }
177 
179 template <typename PointT> void
181  const std::vector<int> &inliers, const Eigen::VectorXf &model_coefficients, Eigen::VectorXf &optimized_coefficients)
182 {
183  // Needs a valid set of model coefficients
184  if (!isModelValid (model_coefficients))
185  {
186  optimized_coefficients = model_coefficients;
187  return;
188  }
189 
190  // Need at least 2 points to estimate a line
191  if (inliers.size () <= 2)
192  {
193  PCL_ERROR ("[pcl::SampleConsensusModelLine::optimizeModelCoefficients] Not enough inliers found to support a model (%zu)! Returning the same coefficients.\n", inliers.size ());
194  optimized_coefficients = model_coefficients;
195  return;
196  }
197 
198  optimized_coefficients.resize (6);
199 
200  // Compute the 3x3 covariance matrix
201  Eigen::Vector4f centroid;
202  compute3DCentroid (*input_, inliers, centroid);
203  Eigen::Matrix3f covariance_matrix;
204  computeCovarianceMatrix (*input_, inliers, centroid, covariance_matrix);
205  optimized_coefficients[0] = centroid[0];
206  optimized_coefficients[1] = centroid[1];
207  optimized_coefficients[2] = centroid[2];
208 
209  // Extract the eigenvalues and eigenvectors
210  EIGEN_ALIGN16 Eigen::Vector3f eigen_values;
211  EIGEN_ALIGN16 Eigen::Vector3f eigen_vector;
212  pcl::eigen33 (covariance_matrix, eigen_values);
213  pcl::computeCorrespondingEigenVector (covariance_matrix, eigen_values [2], eigen_vector);
214  //pcl::eigen33 (covariance_matrix, eigen_vectors, eigen_values);
215 
216  optimized_coefficients.template tail<3> () = eigen_vector;
217 }
218 
220 template <typename PointT> void
222  const std::vector<int> &inliers, const Eigen::VectorXf &model_coefficients, PointCloud &projected_points, bool copy_data_fields)
223 {
224  // Needs a valid model coefficients
225  if (!isModelValid (model_coefficients))
226  return;
227 
228  // Obtain the line point and direction
229  Eigen::Vector4f line_pt (model_coefficients[0], model_coefficients[1], model_coefficients[2], 0);
230  Eigen::Vector4f line_dir (model_coefficients[3], model_coefficients[4], model_coefficients[5], 0);
231 
232  projected_points.header = input_->header;
233  projected_points.is_dense = input_->is_dense;
234 
235  // Copy all the data fields from the input cloud to the projected one?
236  if (copy_data_fields)
237  {
238  // Allocate enough space and copy the basics
239  projected_points.points.resize (input_->points.size ());
240  projected_points.width = input_->width;
241  projected_points.height = input_->height;
242 
243  typedef typename pcl::traits::fieldList<PointT>::type FieldList;
244  // Iterate over each point
245  for (size_t i = 0; i < projected_points.points.size (); ++i)
246  // Iterate over each dimension
247  pcl::for_each_type <FieldList> (NdConcatenateFunctor <PointT, PointT> (input_->points[i], projected_points.points[i]));
248 
249  // Iterate through the 3d points and calculate the distances from them to the line
250  for (size_t i = 0; i < inliers.size (); ++i)
251  {
252  Eigen::Vector4f pt (input_->points[inliers[i]].x, input_->points[inliers[i]].y, input_->points[inliers[i]].z, 0);
253  // double k = (DOT_PROD_3D (points[i], p21) - dotA_B) / dotB_B;
254  float k = (pt.dot (line_dir) - line_pt.dot (line_dir)) / line_dir.dot (line_dir);
255 
256  Eigen::Vector4f pp = line_pt + k * line_dir;
257  // Calculate the projection of the point on the line (pointProj = A + k * B)
258  projected_points.points[inliers[i]].x = pp[0];
259  projected_points.points[inliers[i]].y = pp[1];
260  projected_points.points[inliers[i]].z = pp[2];
261  }
262  }
263  else
264  {
265  // Allocate enough space and copy the basics
266  projected_points.points.resize (inliers.size ());
267  projected_points.width = static_cast<uint32_t> (inliers.size ());
268  projected_points.height = 1;
269 
270  typedef typename pcl::traits::fieldList<PointT>::type FieldList;
271  // Iterate over each point
272  for (size_t i = 0; i < inliers.size (); ++i)
273  // Iterate over each dimension
274  pcl::for_each_type <FieldList> (NdConcatenateFunctor <PointT, PointT> (input_->points[inliers[i]], projected_points.points[i]));
275 
276  // Iterate through the 3d points and calculate the distances from them to the line
277  for (size_t i = 0; i < inliers.size (); ++i)
278  {
279  Eigen::Vector4f pt (input_->points[inliers[i]].x, input_->points[inliers[i]].y, input_->points[inliers[i]].z, 0);
280  // double k = (DOT_PROD_3D (points[i], p21) - dotA_B) / dotB_B;
281  float k = (pt.dot (line_dir) - line_pt.dot (line_dir)) / line_dir.dot (line_dir);
282 
283  Eigen::Vector4f pp = line_pt + k * line_dir;
284  // Calculate the projection of the point on the line (pointProj = A + k * B)
285  projected_points.points[i].x = pp[0];
286  projected_points.points[i].y = pp[1];
287  projected_points.points[i].z = pp[2];
288  }
289  }
290 }
291 
293 template <typename PointT> bool
295  const std::set<int> &indices, const Eigen::VectorXf &model_coefficients, const double threshold)
296 {
297  // Needs a valid set of model coefficients
298  if (!isModelValid (model_coefficients))
299  return (false);
300 
301  // Obtain the line point and direction
302  Eigen::Vector4f line_pt (model_coefficients[0], model_coefficients[1], model_coefficients[2], 0);
303  Eigen::Vector4f line_dir (model_coefficients[3], model_coefficients[4], model_coefficients[5], 0);
304  line_dir.normalize ();
305 
306  double sqr_threshold = threshold * threshold;
307  // Iterate through the 3d points and calculate the distances from them to the line
308  for (std::set<int>::const_iterator it = indices.begin (); it != indices.end (); ++it)
309  {
310  // Calculate the distance from the point to the line
311  // D = ||(P2-P1) x (P1-P0)|| / ||P2-P1|| = norm (cross (p2-p1, p2-p0)) / norm(p2-p1)
312  if ((line_pt - input_->points[*it].getVector4fMap ()).cross3 (line_dir).squaredNorm () > sqr_threshold)
313  return (false);
314  }
315 
316  return (true);
317 }
318 
319 #define PCL_INSTANTIATE_SampleConsensusModelLine(T) template class PCL_EXPORTS pcl::SampleConsensusModelLine<T>;
320 
321 #endif // PCL_SAMPLE_CONSENSUS_IMPL_SAC_MODEL_LINE_H_
322