Point Cloud Library (PCL)  1.6.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
gicp.hpp
Go to the documentation of this file.
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2010, 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: gicp.hpp 6152 2012-07-04 22:58:53Z rusu $
35  *
36  */
37 
38 #include <boost/unordered_map.hpp>
40 
42 template <typename PointSource, typename PointTarget>
43 template<typename PointT> void
45  const typename pcl::KdTree<PointT>::Ptr kdtree,
46  std::vector<Eigen::Matrix3d>& cloud_covariances)
47 {
48  if (k_correspondences_ > int (cloud->size ()))
49  {
50  PCL_ERROR ("[pcl::GeneralizedIterativeClosestPoint::computeCovariances] Number or points in cloud (%zu) is less than k_correspondences_ (%zu)!\n", cloud->size (), k_correspondences_);
51  return;
52  }
53 
54  Eigen::Vector3d mean;
55  std::vector<int> nn_indecies; nn_indecies.reserve (k_correspondences_);
56  std::vector<float> nn_dist_sq; nn_dist_sq.reserve (k_correspondences_);
57 
58  // We should never get there but who knows
59  if(cloud_covariances.size () < cloud->size ())
60  cloud_covariances.resize (cloud->size ());
61 
62  typename pcl::PointCloud<PointT>::const_iterator points_iterator = cloud->begin ();
63  std::vector<Eigen::Matrix3d>::iterator matrices_iterator = cloud_covariances.begin ();
64  for(;
65  points_iterator != cloud->end ();
66  ++points_iterator, ++matrices_iterator)
67  {
68  const PointT &query_point = *points_iterator;
69  Eigen::Matrix3d &cov = *matrices_iterator;
70  // Zero out the cov and mean
71  cov.setZero ();
72  mean.setZero ();
73 
74  // Search for the K nearest neighbours
75  kdtree->nearestKSearch(query_point, k_correspondences_, nn_indecies, nn_dist_sq);
76 
77  // Find the covariance matrix
78  for(int j = 0; j < k_correspondences_; j++) {
79  const PointT &pt = (*cloud)[nn_indecies[j]];
80 
81  mean[0] += pt.x;
82  mean[1] += pt.y;
83  mean[2] += pt.z;
84 
85  cov(0,0) += pt.x*pt.x;
86 
87  cov(1,0) += pt.y*pt.x;
88  cov(1,1) += pt.y*pt.y;
89 
90  cov(2,0) += pt.z*pt.x;
91  cov(2,1) += pt.z*pt.y;
92  cov(2,2) += pt.z*pt.z;
93  }
94 
95  mean /= static_cast<double> (k_correspondences_);
96  // Get the actual covariance
97  for (int k = 0; k < 3; k++)
98  for (int l = 0; l <= k; l++)
99  {
100  cov(k,l) /= static_cast<double> (k_correspondences_);
101  cov(k,l) -= mean[k]*mean[l];
102  cov(l,k) = cov(k,l);
103  }
104 
105  // Compute the SVD (covariance matrix is symmetric so U = V')
106  Eigen::JacobiSVD<Eigen::Matrix3d> svd(cov, Eigen::ComputeFullU);
107  cov.setZero ();
108  Eigen::Matrix3d U = svd.matrixU ();
109  // Reconstitute the covariance matrix with modified singular values using the column // vectors in V.
110  for(int k = 0; k < 3; k++) {
111  Eigen::Vector3d col = U.col(k);
112  double v = 1.; // biggest 2 singular values replaced by 1
113  if(k == 2) // smallest singular value replaced by gicp_epsilon
114  v = gicp_epsilon_;
115  cov+= v * col * col.transpose();
116  }
117  }
118 }
119 
121 template <typename PointSource, typename PointTarget> void
122 pcl::GeneralizedIterativeClosestPoint<PointSource, PointTarget>::computeRDerivative(const Vector6d &x, const Eigen::Matrix3d &R, Vector6d& g) const
123 {
124  Eigen::Matrix3d dR_dPhi;
125  Eigen::Matrix3d dR_dTheta;
126  Eigen::Matrix3d dR_dPsi;
127 
128  double phi = x[3], theta = x[4], psi = x[5];
129 
130  double cphi = cos(phi), sphi = sin(phi);
131  double ctheta = cos(theta), stheta = sin(theta);
132  double cpsi = cos(psi), spsi = sin(psi);
133 
134  dR_dPhi(0,0) = 0.;
135  dR_dPhi(1,0) = 0.;
136  dR_dPhi(2,0) = 0.;
137 
138  dR_dPhi(0,1) = sphi*spsi + cphi*cpsi*stheta;
139  dR_dPhi(1,1) = -cpsi*sphi + cphi*spsi*stheta;
140  dR_dPhi(2,1) = cphi*ctheta;
141 
142  dR_dPhi(0,2) = cphi*spsi - cpsi*sphi*stheta;
143  dR_dPhi(1,2) = -cphi*cpsi - sphi*spsi*stheta;
144  dR_dPhi(2,2) = -ctheta*sphi;
145 
146  dR_dTheta(0,0) = -cpsi*stheta;
147  dR_dTheta(1,0) = -spsi*stheta;
148  dR_dTheta(2,0) = -ctheta;
149 
150  dR_dTheta(0,1) = cpsi*ctheta*sphi;
151  dR_dTheta(1,1) = ctheta*sphi*spsi;
152  dR_dTheta(2,1) = -sphi*stheta;
153 
154  dR_dTheta(0,2) = cphi*cpsi*ctheta;
155  dR_dTheta(1,2) = cphi*ctheta*spsi;
156  dR_dTheta(2,2) = -cphi*stheta;
157 
158  dR_dPsi(0,0) = -ctheta*spsi;
159  dR_dPsi(1,0) = cpsi*ctheta;
160  dR_dPsi(2,0) = 0.;
161 
162  dR_dPsi(0,1) = -cphi*cpsi - sphi*spsi*stheta;
163  dR_dPsi(1,1) = -cphi*spsi + cpsi*sphi*stheta;
164  dR_dPsi(2,1) = 0.;
165 
166  dR_dPsi(0,2) = cpsi*sphi - cphi*spsi*stheta;
167  dR_dPsi(1,2) = sphi*spsi + cphi*cpsi*stheta;
168  dR_dPsi(2,2) = 0.;
169 
170  g[3] = matricesInnerProd(dR_dPhi, R);
171  g[4] = matricesInnerProd(dR_dTheta, R);
172  g[5] = matricesInnerProd(dR_dPsi, R);
173 }
174 
176 template <typename PointSource, typename PointTarget> void
178  const std::vector<int> &indices_src,
179  const PointCloudTarget &cloud_tgt,
180  const std::vector<int> &indices_tgt,
181  Eigen::Matrix4f &transformation_matrix)
182 {
183  if (indices_src.size () < 4) // need at least 4 samples
184  {
186  "[pcl::GeneralizedIterativeClosestPoint::estimateRigidTransformationBFGS] Need at least 4 points to estimate a transform! Source and target have " << indices_src.size () << " points!");
187  return;
188  }
189  // Set the initial solution
190  Vector6d x = Vector6d::Zero ();
191  x[0] = transformation_matrix (0,3);
192  x[1] = transformation_matrix (1,3);
193  x[2] = transformation_matrix (2,3);
194  x[3] = atan2 (transformation_matrix (2,1), transformation_matrix (2,2));
195  x[4] = asin (-transformation_matrix (2,0));
196  x[5] = atan2 (transformation_matrix (1,0), transformation_matrix (0,0));
197 
198  // Set temporary pointers
199  tmp_src_ = &cloud_src;
200  tmp_tgt_ = &cloud_tgt;
201  tmp_idx_src_ = &indices_src;
202  tmp_idx_tgt_ = &indices_tgt;
203 
204  // Optimize using forward-difference approximation LM
205  const double gradient_tol = 1e-2;
206  OptimizationFunctorWithIndices functor(this);
207  BFGS<OptimizationFunctorWithIndices> bfgs (functor);
208  bfgs.parameters.sigma = 0.01;
209  bfgs.parameters.rho = 0.01;
210  bfgs.parameters.tau1 = 9;
211  bfgs.parameters.tau2 = 0.05;
212  bfgs.parameters.tau3 = 0.5;
213  bfgs.parameters.order = 3;
214 
215  int inner_iterations_ = 0;
216  int result = bfgs.minimizeInit (x);
217  do
218  {
219  inner_iterations_++;
220  result = bfgs.minimizeOneStep (x);
221  if(result)
222  {
223  break;
224  }
225  result = bfgs.testGradient(gradient_tol);
226  } while(result == BFGSSpace::Running && inner_iterations_ < max_inner_iterations_);
227  if(result == BFGSSpace::NoProgress || result == BFGSSpace::Success || inner_iterations_ == max_inner_iterations_)
228  {
229  PCL_DEBUG ("[pcl::registration::TransformationEstimationBFGS::estimateRigidTransformation]");
230  PCL_DEBUG ("BFGS solver finished with exit code %i \n", result);
231  transformation_matrix.setIdentity();
232  applyState(transformation_matrix, x);
233  }
234  else
236  "[pcl::" << getClassName () << "::TransformationEstimationBFGS::estimateRigidTransformation] BFGS solver didn't converge!");
237 }
238 
240 template <typename PointSource, typename PointTarget> inline double
242 {
243  Eigen::Matrix4f transformation_matrix = gicp_->base_transformation_;
244  gicp_->applyState(transformation_matrix, x);
245  double f = 0;
246  int m = static_cast<int> (gicp_->tmp_idx_src_->size ());
247  for (int i = 0; i < m; ++i)
248  {
249  // The last coordinate, p_src[3] is guaranteed to be set to 1.0 in registration.hpp
250  Vector4fMapConst p_src = gicp_->tmp_src_->points[(*gicp_->tmp_idx_src_)[i]].getVector4fMap ();
251  // The last coordinate, p_tgt[3] is guaranteed to be set to 1.0 in registration.hpp
252  Vector4fMapConst p_tgt = gicp_->tmp_tgt_->points[(*gicp_->tmp_idx_tgt_)[i]].getVector4fMap ();
253  Eigen::Vector4f pp (transformation_matrix * p_src);
254  // Estimate the distance (cost function)
255  // The last coordiante is still guaranteed to be set to 1.0
256  Eigen::Vector3d res(pp[0] - p_tgt[0], pp[1] - p_tgt[1], pp[2] - p_tgt[2]);
257  Eigen::Vector3d temp (gicp_->mahalanobis((*gicp_->tmp_idx_src_)[i]) * res);
258  //increment= res'*temp/num_matches = temp'*M*temp/num_matches (we postpone 1/num_matches after the loop closes)
259  f+= double(res.transpose() * temp);
260  }
261  return f/m;
262 }
263 
265 template <typename PointSource, typename PointTarget> inline void
267 {
268  Eigen::Matrix4f transformation_matrix = gicp_->base_transformation_;
269  gicp_->applyState(transformation_matrix, x);
270  //Zero out g
271  g.setZero ();
272  //Eigen::Vector3d g_t = g.head<3> ();
273  Eigen::Matrix3d R = Eigen::Matrix3d::Zero ();
274  int m = static_cast<int> (gicp_->tmp_idx_src_->size ());
275  for (int i = 0; i < m; ++i)
276  {
277  // The last coordinate, p_src[3] is guaranteed to be set to 1.0 in registration.hpp
278  Vector4fMapConst p_src = gicp_->tmp_src_->points[(*gicp_->tmp_idx_src_)[i]].getVector4fMap ();
279  // The last coordinate, p_tgt[3] is guaranteed to be set to 1.0 in registration.hpp
280  Vector4fMapConst p_tgt = gicp_->tmp_tgt_->points[(*gicp_->tmp_idx_tgt_)[i]].getVector4fMap ();
281 
282  Eigen::Vector4f pp (transformation_matrix * p_src);
283  // The last coordiante is still guaranteed to be set to 1.0
284  Eigen::Vector3d res (pp[0] - p_tgt[0], pp[1] - p_tgt[1], pp[2] - p_tgt[2]);
285  // temp = M*res
286  Eigen::Vector3d temp (gicp_->mahalanobis ((*gicp_->tmp_idx_src_)[i]) * res);
287  // Increment translation gradient
288  // g.head<3> ()+= 2*M*res/num_matches (we postpone 2/num_matches after the loop closes)
289  g.head<3> ()+= temp;
290  // Increment rotation gradient
291  pp = gicp_->base_transformation_ * p_src;
292  Eigen::Vector3d p_src3 (pp[0], pp[1], pp[2]);
293  R+= p_src3 * temp.transpose();
294  }
295  g.head<3> ()*= 2.0/m;
296  R*= 2.0/m;
297  gicp_->computeRDerivative(x, R, g);
298 }
299 
301 template <typename PointSource, typename PointTarget> inline void
303 {
304  Eigen::Matrix4f transformation_matrix = gicp_->base_transformation_;
305  gicp_->applyState(transformation_matrix, x);
306  f = 0;
307  g.setZero ();
308  Eigen::Matrix3d R = Eigen::Matrix3d::Zero ();
309  const int m = static_cast<const int> (gicp_->tmp_idx_src_->size ());
310  for (int i = 0; i < m; ++i)
311  {
312  // The last coordinate, p_src[3] is guaranteed to be set to 1.0 in registration.hpp
313  Vector4fMapConst p_src = gicp_->tmp_src_->points[(*gicp_->tmp_idx_src_)[i]].getVector4fMap ();
314  // The last coordinate, p_tgt[3] is guaranteed to be set to 1.0 in registration.hpp
315  Vector4fMapConst p_tgt = gicp_->tmp_tgt_->points[(*gicp_->tmp_idx_tgt_)[i]].getVector4fMap ();
316  Eigen::Vector4f pp (transformation_matrix * p_src);
317  // The last coordiante is still guaranteed to be set to 1.0
318  Eigen::Vector3d res (pp[0] - p_tgt[0], pp[1] - p_tgt[1], pp[2] - p_tgt[2]);
319  // temp = M*res
320  Eigen::Vector3d temp (gicp_->mahalanobis((*gicp_->tmp_idx_src_)[i]) * res);
321  // Increment total error
322  f+= double(res.transpose() * temp);
323  // Increment translation gradient
324  // g.head<3> ()+= 2*M*res/num_matches (we postpone 2/num_matches after the loop closes)
325  g.head<3> ()+= temp;
326  pp = gicp_->base_transformation_ * p_src;
327  Eigen::Vector3d p_src3 (pp[0], pp[1], pp[2]);
328  // Increment rotation gradient
329  R+= p_src3 * temp.transpose();
330  }
331  f/= double(m);
332  g.head<3> ()*= double(2.0/m);
333  R*= 2.0/m;
334  gicp_->computeRDerivative(x, R, g);
335 }
336 
338 template <typename PointSource, typename PointTarget> inline void
339 pcl::GeneralizedIterativeClosestPoint<PointSource, PointTarget>::computeTransformation (PointCloudSource &output, const Eigen::Matrix4f& guess)
340 {
341  using namespace std;
342  // Difference between consecutive transforms
343  double delta = 0;
344  // Get the size of the target
345  const size_t N = indices_->size ();
346  // Set the mahalanobis matrices to identity
347  mahalanobis_.resize (N, Eigen::Matrix3d::Identity ());
348  // Compute target cloud covariance matrices
349  computeCovariances<PointTarget> (target_, tree_, target_covariances_);
350  // Compute input cloud covariance matrices
351  computeCovariances<PointSource> (input_, input_tree_, input_covariances_);
352 
353  base_transformation_ = guess;
354  nr_iterations_ = 0;
355  converged_ = false;
356  double dist_threshold = corr_dist_threshold_ * corr_dist_threshold_;
357  std::vector<int> nn_indices (1);
358  std::vector<float> nn_dists (1);
359 
360  while(!converged_)
361  {
362  size_t cnt = 0;
363  std::vector<int> source_indices (indices_->size ());
364  std::vector<int> target_indices (indices_->size ());
365 
366  // guess corresponds to base_t and transformation_ to t
367  Eigen::Matrix4d transform_R = Eigen::Matrix4d::Zero ();
368  for(size_t i = 0; i < 4; i++)
369  for(size_t j = 0; j < 4; j++)
370  for(size_t k = 0; k < 4; k++)
371  transform_R(i,j)+= double(transformation_(i,k)) * double(guess(k,j));
372 
373  Eigen::Matrix3d R = transform_R.topLeftCorner<3,3> ();
374 
375  for (size_t i = 0; i < N; i++)
376  {
377  PointSource query = output[i];
378  query.getVector4fMap () = guess * query.getVector4fMap ();
379  query.getVector4fMap () = transformation_ * query.getVector4fMap ();
380 
381  if (!searchForNeighbors (query, nn_indices, nn_dists))
382  {
383  PCL_ERROR ("[pcl::%s::computeTransformation] Unable to find a nearest neighbor in the target dataset for point %d in the source!\n", getClassName ().c_str (), (*indices_)[i]);
384  return;
385  }
386 
387  // Check if the distance to the nearest neighbor is smaller than the user imposed threshold
388  if (nn_dists[0] < dist_threshold)
389  {
390  Eigen::Matrix3d &C1 = input_covariances_[i];
391  Eigen::Matrix3d &C2 = target_covariances_[nn_indices[0]];
392  Eigen::Matrix3d &M = mahalanobis_[i];
393  // M = R*C1
394  M = R * C1;
395  // temp = M*R' + C2 = R*C1*R' + C2
396  Eigen::Matrix3d temp = M * R.transpose();
397  temp+= C2;
398  // M = temp^-1
399  M = temp.inverse ();
400  source_indices[cnt] = static_cast<int> (i);
401  target_indices[cnt] = nn_indices[0];
402  cnt++;
403  }
404  }
405  // Resize to the actual number of valid correspondences
406  source_indices.resize(cnt); target_indices.resize(cnt);
407  /* optimize transformation using the current assignment and Mahalanobis metrics*/
408  previous_transformation_ = transformation_;
409  //optimization right here
410  try
411  {
412  rigid_transformation_estimation_(output, source_indices, *target_, target_indices, transformation_);
413  /* compute the delta from this iteration */
414  delta = 0.;
415  for(int k = 0; k < 4; k++) {
416  for(int l = 0; l < 4; l++) {
417  double ratio = 1;
418  if(k < 3 && l < 3) // rotation part of the transform
419  ratio = 1./rotation_epsilon_;
420  else
421  ratio = 1./transformation_epsilon_;
422  double c_delta = ratio*fabs(previous_transformation_(k,l) - transformation_(k,l));
423  if(c_delta > delta)
424  delta = c_delta;
425  }
426  }
427  }
428  catch (PCLException &e)
429  {
430  PCL_DEBUG ("[pcl::%s::computeTransformation] Optimization issue %s\n", getClassName ().c_str (), e.what ());
431  break;
432  }
433  nr_iterations_++;
434  // Check for convergence
435  if (nr_iterations_ >= max_iterations_ || delta < 1)
436  {
437  converged_ = true;
438  previous_transformation_ = transformation_;
439  PCL_DEBUG ("[pcl::%s::computeTransformation] Convergence reached. Number of iterations: %d out of %d. Transformation difference: %f\n",
440  getClassName ().c_str (), nr_iterations_, max_iterations_, (transformation_ - previous_transformation_).array ().abs ().sum ());
441  }
442  else
443  PCL_DEBUG ("[pcl::%s::computeTransformation] Convergence failed\n", getClassName ().c_str ());
444  }
445  //for some reason the static equivalent methode raises an error
446  // final_transformation_.block<3,3> (0,0) = (transformation_.block<3,3> (0,0)) * (guess.block<3,3> (0,0));
447  // final_transformation_.block <3, 1> (0, 3) = transformation_.block <3, 1> (0, 3) + guess.rightCols<1>.block <3, 1> (0, 3);
448  final_transformation_.topLeftCorner (3,3) = previous_transformation_.topLeftCorner (3,3) * guess.topLeftCorner (3,3);
449  final_transformation_(0,3) = previous_transformation_(0,3) + guess(0,3);
450  final_transformation_(1,3) = previous_transformation_(1,3) + guess(1,3);
451  final_transformation_(2,3) = previous_transformation_(2,3) + guess(2,3);
452 }
453 
454 template <typename PointSource, typename PointTarget> void
455 pcl::GeneralizedIterativeClosestPoint<PointSource, PointTarget>::applyState(Eigen::Matrix4f &t, const Vector6d& x) const
456 {
457  // !!! CAUTION Stanford GICP uses the Z Y X euler angles convention
458  Eigen::Matrix3f R;
459  R = Eigen::AngleAxisf (static_cast<float> (x[5]), Eigen::Vector3f::UnitZ ())
460  * Eigen::AngleAxisf (static_cast<float> (x[4]), Eigen::Vector3f::UnitY ())
461  * Eigen::AngleAxisf (static_cast<float> (x[3]), Eigen::Vector3f::UnitX ());
462  t.topLeftCorner<3,3> () = R * t.topLeftCorner<3,3> ();
463  Eigen::Vector4f T (static_cast<float> (x[0]), static_cast<float> (x[1]), static_cast<float> (x[2]), 0.0f);
464  t.col (3) += T;
465 }
466