gicp_omp_impl.hpp 22 KB

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