Point Cloud Library (PCL)  1.6.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
sac_model_stick.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 2328 2011-08-31 08:11:00Z rusu $
35  *
36  */
37 
38 #ifndef PCL_SAMPLE_CONSENSUS_IMPL_SAC_MODEL_STICK_H_
39 #define PCL_SAMPLE_CONSENSUS_IMPL_SAC_MODEL_STICK_H_
40 
42 #include <pcl/common/centroid.h>
43 #include <pcl/common/concatenate.h>
44 
46 template <typename PointT> bool
47 pcl::SampleConsensusModelStick<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 (false);
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::SampleConsensusModelStick::computeModelCoefficients] Invalid set of samples given (%zu)!\n", samples.size ());
69  return (false);
70  }
71 
72  model_coefficients.resize (7);
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;
78  model_coefficients[4] = input_->points[samples[1]].y;
79  model_coefficients[5] = input_->points[samples[1]].z;
80 
81 // model_coefficients[3] = input_->points[samples[1]].x - model_coefficients[0];
82 // model_coefficients[4] = input_->points[samples[1]].y - model_coefficients[1];
83 // model_coefficients[5] = input_->points[samples[1]].z - model_coefficients[2];
84 
85 // model_coefficients.template segment<3> (3).normalize ();
86  // We don't care about model_coefficients[6] which is the width (radius) of the stick
87 
88  return (true);
89 }
90 
92 template <typename PointT> void
94  const Eigen::VectorXf &model_coefficients, std::vector<double> &distances)
95 {
96  // Needs a valid set of model coefficients
97  if (!isModelValid (model_coefficients))
98  return;
99 
100  float sqr_threshold = static_cast<float> (radius_max_ * radius_max_);
101  distances.resize (indices_->size ());
102 
103  // Obtain the line point and direction
104  Eigen::Vector4f line_pt (model_coefficients[0], model_coefficients[1], model_coefficients[2], 0);
105  Eigen::Vector4f line_dir (model_coefficients[3], model_coefficients[4], model_coefficients[5], 0);
106  line_dir.normalize ();
107 
108  // Iterate through the 3d points and calculate the distances from them to the line
109  for (size_t i = 0; i < indices_->size (); ++i)
110  {
111  // Calculate the distance from the point to the line
112  // D = ||(P2-P1) x (P1-P0)|| / ||P2-P1|| = norm (cross (p2-p1, p2-p0)) / norm(p2-p1)
113  float sqr_distance = (line_pt - input_->points[(*indices_)[i]].getVector4fMap ()).cross3 (line_dir).squaredNorm ();
114 
115  if (sqr_distance < sqr_threshold)
116  // Need to estimate sqrt here to keep MSAC and friends general
117  distances[i] = sqrt (sqr_distance);
118  else
119  // Penalize outliers by doubling the distance
120  distances[i] = 2 * sqrt (sqr_distance);
121  }
122 }
123 
125 template <typename PointT> void
127  const Eigen::VectorXf &model_coefficients, const double threshold, std::vector<int> &inliers)
128 {
129  // Needs a valid set of model coefficients
130  if (!isModelValid (model_coefficients))
131  return;
132 
133  float sqr_threshold = static_cast<float> (threshold * threshold);
134 
135  int nr_p = 0;
136  inliers.resize (indices_->size ());
137 
138  // Obtain the line point and direction
139  Eigen::Vector4f line_pt1 (model_coefficients[0], model_coefficients[1], model_coefficients[2], 0);
140  Eigen::Vector4f line_pt2 (model_coefficients[3], model_coefficients[4], model_coefficients[5], 0);
141  Eigen::Vector4f line_dir = line_pt2 - line_pt1;
142  //Eigen::Vector4f line_dir (model_coefficients[3], model_coefficients[4], model_coefficients[5], 0);
143  //Eigen::Vector4f line_dir (model_coefficients[3] - model_coefficients[0], model_coefficients[4] - model_coefficients[1], model_coefficients[5] - model_coefficients[2], 0);
144  line_dir.normalize ();
145  //float norm = line_dir.squaredNorm ();
146 
147  // Iterate through the 3d points and calculate the distances from them to the line
148  for (size_t i = 0; i < indices_->size (); ++i)
149  {
150  // Calculate the distance from the point to the line
151  // D = ||(P2-P1) x (P1-P0)|| / ||P2-P1|| = norm (cross (p2-p1, p2-p0)) / norm(p2-p1)
152  Eigen::Vector4f dir = input_->points[(*indices_)[i]].getVector4fMap () - line_pt1;
153  //float u = dir.dot (line_dir);
154 
155  // If the point falls outside of the segment, ignore it
156  //if (u < 0.0f || u > 1.0f)
157  // continue;
158 
159  float sqr_distance = dir.cross3 (line_dir).squaredNorm ();
160  if (sqr_distance < sqr_threshold)
161  // Returns the indices of the points whose squared distances are smaller than the threshold
162  inliers[nr_p++] = (*indices_)[i];
163  }
164  inliers.resize (nr_p);
165 }
166 
168 template <typename PointT> int
170  const Eigen::VectorXf &model_coefficients, const double threshold)
171 {
172  // Needs a valid set of model coefficients
173  if (!isModelValid (model_coefficients))
174  return (0);
175 
176  float sqr_threshold = static_cast<float> (threshold * threshold);
177 
178  int nr_i = 0, nr_o = 0;
179 
180  // Obtain the line point and direction
181  Eigen::Vector4f line_pt1 (model_coefficients[0], model_coefficients[1], model_coefficients[2], 0);
182  Eigen::Vector4f line_pt2 (model_coefficients[3], model_coefficients[4], model_coefficients[5], 0);
183  Eigen::Vector4f line_dir = line_pt2 - line_pt1;
184  line_dir.normalize ();
185 
186  //Eigen::Vector4f line_dir (model_coefficients[3] - model_coefficients[0], model_coefficients[4] - model_coefficients[1], model_coefficients[5] - model_coefficients[2], 0);
187  //Eigen::Vector4f line_dir (model_coefficients[3], model_coefficients[4], model_coefficients[5], 0);
188 
189  // Iterate through the 3d points and calculate the distances from them to the line
190  for (size_t i = 0; i < indices_->size (); ++i)
191  {
192  // Calculate the distance from the point to the line
193  // D = ||(P2-P1) x (P1-P0)|| / ||P2-P1|| = norm (cross (p2-p1, p2-p0)) / norm(p2-p1)
194  Eigen::Vector4f dir = input_->points[(*indices_)[i]].getVector4fMap () - line_pt1;
195  //float u = dir.dot (line_dir);
196 
197  // If the point falls outside of the segment, ignore it
198  //if (u < 0.0f || u > 1.0f)
199  // continue;
200 
201  float sqr_distance = dir.cross3 (line_dir).squaredNorm ();
202  // Use a larger threshold (4 times the radius) to get more points in
203  if (sqr_distance < sqr_threshold)
204  nr_i++;
205  else if (sqr_distance < 4 * sqr_threshold)
206  nr_o++;
207  }
208 
209  return (nr_i - nr_o < 0 ? 0 : nr_i - nr_o);
210 }
211 
213 template <typename PointT> void
215  const std::vector<int> &inliers, const Eigen::VectorXf &model_coefficients, Eigen::VectorXf &optimized_coefficients)
216 {
217  // Needs a valid set of model coefficients
218  if (!isModelValid (model_coefficients))
219  {
220  optimized_coefficients = model_coefficients;
221  return;
222  }
223 
224  // Need at least 2 points to estimate a line
225  if (inliers.size () <= 2)
226  {
227  PCL_ERROR ("[pcl::SampleConsensusModelStick::optimizeModelCoefficients] Not enough inliers found to support a model (%zu)! Returning the same coefficients.\n", inliers.size ());
228  optimized_coefficients = model_coefficients;
229  return;
230  }
231 
232  optimized_coefficients.resize (7);
233 
234  // Compute the 3x3 covariance matrix
235  Eigen::Vector4f centroid;
236  Eigen::Matrix3f covariance_matrix;
237 
238  computeMeanAndCovarianceMatrix (*input_, inliers, covariance_matrix, centroid);
239 
240  optimized_coefficients[0] = centroid[0];
241  optimized_coefficients[1] = centroid[1];
242  optimized_coefficients[2] = centroid[2];
243 
244  // Extract the eigenvalues and eigenvectors
245  Eigen::Vector3f eigen_values;
246  Eigen::Vector3f eigen_vector;
247  pcl::eigen33 (covariance_matrix, eigen_values);
248  pcl::computeCorrespondingEigenVector (covariance_matrix, eigen_values [2], eigen_vector);
249 
250  optimized_coefficients.template segment<3> (3) = eigen_vector;
251 }
252 
254 template <typename PointT> void
256  const std::vector<int> &inliers, const Eigen::VectorXf &model_coefficients, PointCloud &projected_points, bool copy_data_fields)
257 {
258  // Needs a valid model coefficients
259  if (!isModelValid (model_coefficients))
260  return;
261 
262  // Obtain the line point and direction
263  Eigen::Vector4f line_pt (model_coefficients[0], model_coefficients[1], model_coefficients[2], 0);
264  Eigen::Vector4f line_dir (model_coefficients[3], model_coefficients[4], model_coefficients[5], 0);
265 
266  projected_points.header = input_->header;
267  projected_points.is_dense = input_->is_dense;
268 
269  // Copy all the data fields from the input cloud to the projected one?
270  if (copy_data_fields)
271  {
272  // Allocate enough space and copy the basics
273  projected_points.points.resize (input_->points.size ());
274  projected_points.width = input_->width;
275  projected_points.height = input_->height;
276 
277  typedef typename pcl::traits::fieldList<PointT>::type FieldList;
278  // Iterate over each point
279  for (size_t i = 0; i < projected_points.points.size (); ++i)
280  // Iterate over each dimension
281  pcl::for_each_type <FieldList> (NdConcatenateFunctor <PointT, PointT> (input_->points[i], projected_points.points[i]));
282 
283  // Iterate through the 3d points and calculate the distances from them to the line
284  for (size_t i = 0; i < inliers.size (); ++i)
285  {
286  Eigen::Vector4f pt (input_->points[inliers[i]].x, input_->points[inliers[i]].y, input_->points[inliers[i]].z, 0);
287  // double k = (DOT_PROD_3D (points[i], p21) - dotA_B) / dotB_B;
288  float k = (pt.dot (line_dir) - line_pt.dot (line_dir)) / line_dir.dot (line_dir);
289 
290  Eigen::Vector4f pp = line_pt + k * line_dir;
291  // Calculate the projection of the point on the line (pointProj = A + k * B)
292  projected_points.points[inliers[i]].x = pp[0];
293  projected_points.points[inliers[i]].y = pp[1];
294  projected_points.points[inliers[i]].z = pp[2];
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 line
311  for (size_t i = 0; i < inliers.size (); ++i)
312  {
313  Eigen::Vector4f pt (input_->points[inliers[i]].x, input_->points[inliers[i]].y, input_->points[inliers[i]].z, 0);
314  // double k = (DOT_PROD_3D (points[i], p21) - dotA_B) / dotB_B;
315  float k = (pt.dot (line_dir) - line_pt.dot (line_dir)) / line_dir.dot (line_dir);
316 
317  Eigen::Vector4f pp = line_pt + k * line_dir;
318  // Calculate the projection of the point on the line (pointProj = A + k * B)
319  projected_points.points[i].x = pp[0];
320  projected_points.points[i].y = pp[1];
321  projected_points.points[i].z = pp[2];
322  }
323  }
324 }
325 
327 template <typename PointT> bool
329  const std::set<int> &indices, const Eigen::VectorXf &model_coefficients, const double threshold)
330 {
331  // Needs a valid set of model coefficients
332  if (!isModelValid (model_coefficients))
333  return (false);
334 
335  // Obtain the line point and direction
336  Eigen::Vector4f line_pt (model_coefficients[0], model_coefficients[1], model_coefficients[2], 0);
337  Eigen::Vector4f line_dir (model_coefficients[3] - model_coefficients[0], model_coefficients[4] - model_coefficients[1], model_coefficients[5] - model_coefficients[2], 0);
338  //Eigen::Vector4f line_dir (model_coefficients[3], model_coefficients[4], model_coefficients[5], 0);
339  line_dir.normalize ();
340 
341  float sqr_threshold = static_cast<float> (threshold * threshold);
342  // Iterate through the 3d points and calculate the distances from them to the line
343  for (std::set<int>::const_iterator it = indices.begin (); it != indices.end (); ++it)
344  {
345  // Calculate the distance from the point to the line
346  // D = ||(P2-P1) x (P1-P0)|| / ||P2-P1|| = norm (cross (p2-p1, p2-p0)) / norm(p2-p1)
347  if ((line_pt - input_->points[*it].getVector4fMap ()).cross3 (line_dir).squaredNorm () > sqr_threshold)
348  return (false);
349  }
350 
351  return (true);
352 }
353 
354 #define PCL_INSTANTIATE_SampleConsensusModelStick(T) template class PCL_EXPORTS pcl::SampleConsensusModelStick<T>;
355 
356 #endif // PCL_SAMPLE_CONSENSUS_IMPL_SAC_MODEL_STICK_H_
357