Point Cloud Library (PCL)  1.11.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Modules Pages
sac_model_registration.hpp
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Point Cloud Library (PCL) - www.pointclouds.org
5  * Copyright (c) 2010-2011, Willow Garage, Inc.
6  * Copyright (c) 2012-, Open Perception, Inc.
7  *
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  *
14  * * Redistributions of source code must retain the above copyright
15  * notice, this list of conditions and the following disclaimer.
16  * * Redistributions in binary form must reproduce the above
17  * copyright notice, this list of conditions and the following
18  * disclaimer in the documentation and/or other materials provided
19  * with the distribution.
20  * * Neither the name of the copyright holder(s) nor the names of its
21  * contributors may be used to endorse or promote products derived
22  * from this software without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35  * POSSIBILITY OF SUCH DAMAGE.
36  *
37  * $Id$
38  *
39  */
40 
41 #ifndef PCL_SAMPLE_CONSENSUS_IMPL_SAC_MODEL_REGISTRATION_H_
42 #define PCL_SAMPLE_CONSENSUS_IMPL_SAC_MODEL_REGISTRATION_H_
43 
44 #include <pcl/sample_consensus/sac_model_registration.h>
45 #include <pcl/common/eigen.h>
46 #include <pcl/point_types.h>
47 
48 //////////////////////////////////////////////////////////////////////////
49 template <typename PointT> bool
51 {
52  if (samples.size () != sample_size_)
53  {
54  PCL_ERROR ("[pcl::SampleConsensusModelRegistration::isSampleGood] Wrong number of samples (is %lu, should be %lu)!\n", samples.size (), sample_size_);
55  return (false);
56  }
57  using namespace pcl::common;
58  using namespace pcl::traits;
59 
60  PointT p10 = input_->points[samples[1]] - input_->points[samples[0]];
61  PointT p20 = input_->points[samples[2]] - input_->points[samples[0]];
62  PointT p21 = input_->points[samples[2]] - input_->points[samples[1]];
63 
64  return ((p10.x * p10.x + p10.y * p10.y + p10.z * p10.z) > sample_dist_thresh_ &&
65  (p20.x * p20.x + p20.y * p20.y + p20.z * p20.z) > sample_dist_thresh_ &&
66  (p21.x * p21.x + p21.y * p21.y + p21.z * p21.z) > sample_dist_thresh_);
67 }
68 
69 //////////////////////////////////////////////////////////////////////////
70 template <typename PointT> bool
71 pcl::SampleConsensusModelRegistration<PointT>::computeModelCoefficients (const Indices &samples, Eigen::VectorXf &model_coefficients) const
72 {
73  if (!target_)
74  {
75  PCL_ERROR ("[pcl::SampleConsensusModelRegistration::computeModelCoefficients] No target dataset given!\n");
76  return (false);
77  }
78  // Need 3 samples
79  if (samples.size () != sample_size_)
80  {
81  return (false);
82  }
83 
84  Indices indices_tgt (3);
85  for (int i = 0; i < 3; ++i)
86  {
87  indices_tgt[i] = correspondences_.at (samples[i]);
88  }
89 
90  estimateRigidTransformationSVD (*input_, samples, *target_, indices_tgt, model_coefficients);
91  return (true);
92 }
93 
94 //////////////////////////////////////////////////////////////////////////
95 template <typename PointT> void
96 pcl::SampleConsensusModelRegistration<PointT>::getDistancesToModel (const Eigen::VectorXf &model_coefficients, std::vector<double> &distances) const
97 {
98  if (indices_->size () != indices_tgt_->size ())
99  {
100  PCL_ERROR ("[pcl::SampleConsensusModelRegistration::getDistancesToModel] Number of source indices (%lu) differs than number of target indices (%lu)!\n", indices_->size (), indices_tgt_->size ());
101  distances.clear ();
102  return;
103  }
104  if (!target_)
105  {
106  PCL_ERROR ("[pcl::SampleConsensusModelRegistration::getDistanceToModel] No target dataset given!\n");
107  return;
108  }
109  // Check if the model is valid given the user constraints
110  if (!isModelValid (model_coefficients))
111  {
112  distances.clear ();
113  return;
114  }
115  distances.resize (indices_->size ());
116 
117  // Get the 4x4 transformation
118  Eigen::Matrix4f transform;
119  transform.row (0).matrix () = model_coefficients.segment<4>(0);
120  transform.row (1).matrix () = model_coefficients.segment<4>(4);
121  transform.row (2).matrix () = model_coefficients.segment<4>(8);
122  transform.row (3).matrix () = model_coefficients.segment<4>(12);
123 
124  for (std::size_t i = 0; i < indices_->size (); ++i)
125  {
126  Eigen::Vector4f pt_src (input_->points[(*indices_)[i]].x,
127  input_->points[(*indices_)[i]].y,
128  input_->points[(*indices_)[i]].z, 1.0f);
129  Eigen::Vector4f pt_tgt (target_->points[(*indices_tgt_)[i]].x,
130  target_->points[(*indices_tgt_)[i]].y,
131  target_->points[(*indices_tgt_)[i]].z, 1.0f);
132 
133  Eigen::Vector4f p_tr (transform * pt_src);
134  // Calculate the distance from the transformed point to its correspondence
135  // need to compute the real norm here to keep MSAC and friends general
136  distances[i] = (p_tr - pt_tgt).norm ();
137  }
138 }
139 
140 //////////////////////////////////////////////////////////////////////////
141 template <typename PointT> void
142 pcl::SampleConsensusModelRegistration<PointT>::selectWithinDistance (const Eigen::VectorXf &model_coefficients, const double threshold, Indices &inliers)
143 {
144  if (indices_->size () != indices_tgt_->size ())
145  {
146  PCL_ERROR ("[pcl::SampleConsensusModelRegistration::selectWithinDistance] Number of source indices (%lu) differs than number of target indices (%lu)!\n", indices_->size (), indices_tgt_->size ());
147  inliers.clear ();
148  return;
149  }
150  if (!target_)
151  {
152  PCL_ERROR ("[pcl::SampleConsensusModelRegistration::selectWithinDistance] No target dataset given!\n");
153  return;
154  }
155 
156  double thresh = threshold * threshold;
157 
158  // Check if the model is valid given the user constraints
159  if (!isModelValid (model_coefficients))
160  {
161  inliers.clear ();
162  return;
163  }
164 
165  inliers.clear ();
166  error_sqr_dists_.clear ();
167  inliers.reserve (indices_->size ());
168  error_sqr_dists_.reserve (indices_->size ());
169 
170  Eigen::Matrix4f transform;
171  transform.row (0).matrix () = model_coefficients.segment<4>(0);
172  transform.row (1).matrix () = model_coefficients.segment<4>(4);
173  transform.row (2).matrix () = model_coefficients.segment<4>(8);
174  transform.row (3).matrix () = model_coefficients.segment<4>(12);
175 
176  for (std::size_t i = 0; i < indices_->size (); ++i)
177  {
178  Eigen::Vector4f pt_src (input_->points[(*indices_)[i]].x,
179  input_->points[(*indices_)[i]].y,
180  input_->points[(*indices_)[i]].z, 1);
181  Eigen::Vector4f pt_tgt (target_->points[(*indices_tgt_)[i]].x,
182  target_->points[(*indices_tgt_)[i]].y,
183  target_->points[(*indices_tgt_)[i]].z, 1);
184 
185  Eigen::Vector4f p_tr (transform * pt_src);
186 
187  float distance = (p_tr - pt_tgt).squaredNorm ();
188  // Calculate the distance from the transformed point to its correspondence
189  if (distance < thresh)
190  {
191  inliers.push_back ((*indices_)[i]);
192  error_sqr_dists_.push_back (static_cast<double> (distance));
193  }
194  }
195 }
196 
197 //////////////////////////////////////////////////////////////////////////
198 template <typename PointT> std::size_t
200  const Eigen::VectorXf &model_coefficients, const double threshold) const
201 {
202  if (indices_->size () != indices_tgt_->size ())
203  {
204  PCL_ERROR ("[pcl::SampleConsensusModelRegistration::countWithinDistance] Number of source indices (%lu) differs than number of target indices (%lu)!\n", indices_->size (), indices_tgt_->size ());
205  return (0);
206  }
207  if (!target_)
208  {
209  PCL_ERROR ("[pcl::SampleConsensusModelRegistration::countWithinDistance] No target dataset given!\n");
210  return (0);
211  }
212 
213  double thresh = threshold * threshold;
214 
215  // Check if the model is valid given the user constraints
216  if (!isModelValid (model_coefficients))
217  {
218  return (0);
219  }
220 
221  Eigen::Matrix4f transform;
222  transform.row (0).matrix () = model_coefficients.segment<4>(0);
223  transform.row (1).matrix () = model_coefficients.segment<4>(4);
224  transform.row (2).matrix () = model_coefficients.segment<4>(8);
225  transform.row (3).matrix () = model_coefficients.segment<4>(12);
226 
227  std::size_t nr_p = 0;
228  for (std::size_t i = 0; i < indices_->size (); ++i)
229  {
230  Eigen::Vector4f pt_src (input_->points[(*indices_)[i]].x,
231  input_->points[(*indices_)[i]].y,
232  input_->points[(*indices_)[i]].z, 1);
233  Eigen::Vector4f pt_tgt (target_->points[(*indices_tgt_)[i]].x,
234  target_->points[(*indices_tgt_)[i]].y,
235  target_->points[(*indices_tgt_)[i]].z, 1);
236 
237  Eigen::Vector4f p_tr (transform * pt_src);
238  // Calculate the distance from the transformed point to its correspondence
239  if ((p_tr - pt_tgt).squaredNorm () < thresh)
240  nr_p++;
241  }
242  return (nr_p);
243 }
244 
245 //////////////////////////////////////////////////////////////////////////
246 template <typename PointT> void
247 pcl::SampleConsensusModelRegistration<PointT>::optimizeModelCoefficients (const Indices &inliers, const Eigen::VectorXf &model_coefficients, Eigen::VectorXf &optimized_coefficients) const
248 {
249  if (indices_->size () != indices_tgt_->size ())
250  {
251  PCL_ERROR ("[pcl::SampleConsensusModelRegistration::optimizeModelCoefficients] Number of source indices (%lu) differs than number of target indices (%lu)!\n", indices_->size (), indices_tgt_->size ());
252  optimized_coefficients = model_coefficients;
253  return;
254  }
255 
256  // Check if the model is valid given the user constraints
257  if (!isModelValid (model_coefficients) || !target_)
258  {
259  optimized_coefficients = model_coefficients;
260  return;
261  }
262 
263  Indices indices_src (inliers.size ());
264  Indices indices_tgt (inliers.size ());
265  for (std::size_t i = 0; i < inliers.size (); ++i)
266  {
267  indices_src[i] = inliers[i];
268  indices_tgt[i] = correspondences_.at (indices_src[i]);
269  }
270 
271  estimateRigidTransformationSVD (*input_, indices_src, *target_, indices_tgt, optimized_coefficients);
272 }
273 
274 //////////////////////////////////////////////////////////////////////////
275 template <typename PointT> void
277  const pcl::PointCloud<PointT> &cloud_src,
278  const Indices &indices_src,
279  const pcl::PointCloud<PointT> &cloud_tgt,
280  const Indices &indices_tgt,
281  Eigen::VectorXf &transform) const
282 {
283  transform.resize (16);
284 
285  Eigen::Matrix<double, 3, Eigen::Dynamic> src (3, indices_src.size ());
286  Eigen::Matrix<double, 3, Eigen::Dynamic> tgt (3, indices_tgt.size ());
287 
288  for (std::size_t i = 0; i < indices_src.size (); ++i)
289  {
290  src (0, i) = cloud_src[indices_src[i]].x;
291  src (1, i) = cloud_src[indices_src[i]].y;
292  src (2, i) = cloud_src[indices_src[i]].z;
293 
294  tgt (0, i) = cloud_tgt[indices_tgt[i]].x;
295  tgt (1, i) = cloud_tgt[indices_tgt[i]].y;
296  tgt (2, i) = cloud_tgt[indices_tgt[i]].z;
297  }
298 
299  // Call Umeyama directly from Eigen
300  Eigen::Matrix4d transformation_matrix = pcl::umeyama (src, tgt, false);
301 
302  // Return the correct transformation
303  transform.segment<4> (0).matrix () = transformation_matrix.cast<float> ().row (0);
304  transform.segment<4> (4).matrix () = transformation_matrix.cast<float> ().row (1);
305  transform.segment<4> (8).matrix () = transformation_matrix.cast<float> ().row (2);
306  transform.segment<4> (12).matrix () = transformation_matrix.cast<float> ().row (3);
307 }
308 
309 #define PCL_INSTANTIATE_SampleConsensusModelRegistration(T) template class PCL_EXPORTS pcl::SampleConsensusModelRegistration<T>;
310 
311 #endif // PCL_SAMPLE_CONSENSUS_IMPL_SAC_MODEL_REGISTRATION_H_
312 
bool computeModelCoefficients(const Indices &samples, Eigen::VectorXf &model_coefficients) const override
Compute a 4x4 rigid transformation matrix from the samples given.
Eigen::internal::umeyama_transform_matrix_type< Derived, OtherDerived >::type umeyama(const Eigen::MatrixBase< Derived > &src, const Eigen::MatrixBase< OtherDerived > &dst, bool with_scaling=false)
Returns the transformation between two point sets.
Definition: eigen.hpp:660
void optimizeModelCoefficients(const Indices &inliers, const Eigen::VectorXf &model_coefficients, Eigen::VectorXf &optimized_coefficients) const override
Recompute the 4x4 transformation using the given inlier set.
void estimateRigidTransformationSVD(const pcl::PointCloud< PointT > &cloud_src, const Indices &indices_src, const pcl::PointCloud< PointT > &cloud_tgt, const Indices &indices_tgt, Eigen::VectorXf &transform) const
Estimate a rigid transformation between a source and a target point cloud using an SVD closed-form so...
PointCloud represents the base class in PCL for storing collections of 3D points. ...
void getDistancesToModel(const Eigen::VectorXf &model_coefficients, std::vector< double > &distances) const override
Compute all distances from the transformed points to their correspondences.
bool isSampleGood(const Indices &samples) const override
Check if a sample of indices results in a good sample of points indices.
void selectWithinDistance(const Eigen::VectorXf &model_coefficients, const double threshold, Indices &inliers) override
Select all the points which respect the given model coefficients as inliers.
A point structure representing Euclidean xyz coordinates, and the RGB color.
std::size_t countWithinDistance(const Eigen::VectorXf &model_coefficients, const double threshold) const override
Count all the points which respect the given model coefficients as inliers.