38 #include <boost/unordered_map.hpp>
42 template <
typename Po
intSource,
typename Po
intTarget>
43 template<
typename Po
intT>
void
46 std::vector<Eigen::Matrix3d>& cloud_covariances)
48 if (k_correspondences_ >
int (cloud->
size ()))
50 PCL_ERROR (
"[pcl::GeneralizedIterativeClosestPoint::computeCovariances] Number or points in cloud (%zu) is less than k_correspondences_ (%zu)!\n", cloud->
size (), k_correspondences_);
55 std::vector<int> nn_indecies; nn_indecies.reserve (k_correspondences_);
56 std::vector<float> nn_dist_sq; nn_dist_sq.reserve (k_correspondences_);
59 if(cloud_covariances.size () < cloud->
size ())
60 cloud_covariances.resize (cloud->
size ());
63 std::vector<Eigen::Matrix3d>::iterator matrices_iterator = cloud_covariances.begin ();
65 points_iterator != cloud->
end ();
66 ++points_iterator, ++matrices_iterator)
68 const PointT &query_point = *points_iterator;
69 Eigen::Matrix3d &cov = *matrices_iterator;
75 kdtree->
nearestKSearch(query_point, k_correspondences_, nn_indecies, nn_dist_sq);
78 for(
int j = 0; j < k_correspondences_; j++) {
79 const PointT &pt = (*cloud)[nn_indecies[j]];
85 cov(0,0) += pt.x*pt.x;
87 cov(1,0) += pt.y*pt.x;
88 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;
95 mean /=
static_cast<double> (k_correspondences_);
97 for (
int k = 0; k < 3; k++)
98 for (
int l = 0; l <= k; l++)
100 cov(k,l) /=
static_cast<double> (k_correspondences_);
101 cov(k,l) -= mean[k]*mean[l];
106 Eigen::JacobiSVD<Eigen::Matrix3d> svd(cov, Eigen::ComputeFullU);
108 Eigen::Matrix3d U = svd.matrixU ();
110 for(
int k = 0; k < 3; k++) {
111 Eigen::Vector3d col = U.col(k);
115 cov+= v * col * col.transpose();
121 template <
typename Po
intSource,
typename Po
intTarget>
void
124 Eigen::Matrix3d dR_dPhi;
125 Eigen::Matrix3d dR_dTheta;
126 Eigen::Matrix3d dR_dPsi;
128 double phi = x[3], theta = x[4], psi = x[5];
130 double cphi = cos(phi), sphi = sin(phi);
131 double ctheta = cos(theta), stheta = sin(theta);
132 double cpsi = cos(psi), spsi = sin(psi);
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;
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;
146 dR_dTheta(0,0) = -cpsi*stheta;
147 dR_dTheta(1,0) = -spsi*stheta;
148 dR_dTheta(2,0) = -ctheta;
150 dR_dTheta(0,1) = cpsi*ctheta*sphi;
151 dR_dTheta(1,1) = ctheta*sphi*spsi;
152 dR_dTheta(2,1) = -sphi*stheta;
154 dR_dTheta(0,2) = cphi*cpsi*ctheta;
155 dR_dTheta(1,2) = cphi*ctheta*spsi;
156 dR_dTheta(2,2) = -cphi*stheta;
158 dR_dPsi(0,0) = -ctheta*spsi;
159 dR_dPsi(1,0) = cpsi*ctheta;
162 dR_dPsi(0,1) = -cphi*cpsi - sphi*spsi*stheta;
163 dR_dPsi(1,1) = -cphi*spsi + cpsi*sphi*stheta;
166 dR_dPsi(0,2) = cpsi*sphi - cphi*spsi*stheta;
167 dR_dPsi(1,2) = sphi*spsi + cphi*cpsi*stheta;
170 g[3] = matricesInnerProd(dR_dPhi, R);
171 g[4] = matricesInnerProd(dR_dTheta, R);
172 g[5] = matricesInnerProd(dR_dPsi, R);
176 template <
typename Po
intSource,
typename Po
intTarget>
void
178 const std::vector<int> &indices_src,
180 const std::vector<int> &indices_tgt,
181 Eigen::Matrix4f &transformation_matrix)
183 if (indices_src.size () < 4)
186 "[pcl::GeneralizedIterativeClosestPoint::estimateRigidTransformationBFGS] Need at least 4 points to estimate a transform! Source and target have " << indices_src.size () <<
" points!");
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));
199 tmp_src_ = &cloud_src;
200 tmp_tgt_ = &cloud_tgt;
201 tmp_idx_src_ = &indices_src;
202 tmp_idx_tgt_ = &indices_tgt;
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;
215 int inner_iterations_ = 0;
216 int result = bfgs.minimizeInit (x);
220 result = bfgs.minimizeOneStep (x);
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_)
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);
236 "[pcl::" << getClassName () <<
"::TransformationEstimationBFGS::estimateRigidTransformation] BFGS solver didn't converge!");
240 template <
typename Po
intSource,
typename Po
intTarget>
inline double
243 Eigen::Matrix4f transformation_matrix = gicp_->base_transformation_;
244 gicp_->applyState(transformation_matrix, x);
246 int m =
static_cast<int> (gicp_->tmp_idx_src_->size ());
247 for (
int i = 0; i < m; ++i)
250 Vector4fMapConst p_src = gicp_->tmp_src_->points[(*gicp_->tmp_idx_src_)[i]].getVector4fMap ();
252 Vector4fMapConst p_tgt = gicp_->tmp_tgt_->points[(*gicp_->tmp_idx_tgt_)[i]].getVector4fMap ();
253 Eigen::Vector4f pp (transformation_matrix * p_src);
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);
259 f+= double(res.transpose() * temp);
265 template <
typename Po
intSource,
typename Po
intTarget>
inline void
268 Eigen::Matrix4f transformation_matrix = gicp_->base_transformation_;
269 gicp_->applyState(transformation_matrix, x);
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)
278 Vector4fMapConst p_src = gicp_->tmp_src_->points[(*gicp_->tmp_idx_src_)[i]].getVector4fMap ();
280 Vector4fMapConst p_tgt = gicp_->tmp_tgt_->points[(*gicp_->tmp_idx_tgt_)[i]].getVector4fMap ();
282 Eigen::Vector4f pp (transformation_matrix * p_src);
284 Eigen::Vector3d res (pp[0] - p_tgt[0], pp[1] - p_tgt[1], pp[2] - p_tgt[2]);
286 Eigen::Vector3d temp (gicp_->mahalanobis ((*gicp_->tmp_idx_src_)[i]) * res);
291 pp = gicp_->base_transformation_ * p_src;
292 Eigen::Vector3d p_src3 (pp[0], pp[1], pp[2]);
293 R+= p_src3 * temp.transpose();
295 g.head<3> ()*= 2.0/m;
297 gicp_->computeRDerivative(x, R, g);
301 template <
typename Po
intSource,
typename Po
intTarget>
inline void
304 Eigen::Matrix4f transformation_matrix = gicp_->base_transformation_;
305 gicp_->applyState(transformation_matrix, x);
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)
313 Vector4fMapConst p_src = gicp_->tmp_src_->points[(*gicp_->tmp_idx_src_)[i]].getVector4fMap ();
315 Vector4fMapConst p_tgt = gicp_->tmp_tgt_->points[(*gicp_->tmp_idx_tgt_)[i]].getVector4fMap ();
316 Eigen::Vector4f pp (transformation_matrix * p_src);
318 Eigen::Vector3d res (pp[0] - p_tgt[0], pp[1] - p_tgt[1], pp[2] - p_tgt[2]);
320 Eigen::Vector3d temp (gicp_->mahalanobis((*gicp_->tmp_idx_src_)[i]) * res);
322 f+= double(res.transpose() * temp);
326 pp = gicp_->base_transformation_ * p_src;
327 Eigen::Vector3d p_src3 (pp[0], pp[1], pp[2]);
329 R+= p_src3 * temp.transpose();
332 g.head<3> ()*=
double(2.0/m);
334 gicp_->computeRDerivative(x, R, g);
338 template <
typename Po
intSource,
typename Po
intTarget>
inline void
345 const size_t N = indices_->size ();
347 mahalanobis_.resize (N, Eigen::Matrix3d::Identity ());
349 computeCovariances<PointTarget> (target_, tree_, target_covariances_);
351 computeCovariances<PointSource> (input_, input_tree_, input_covariances_);
353 base_transformation_ = guess;
356 double dist_threshold = corr_dist_threshold_ * corr_dist_threshold_;
357 std::vector<int> nn_indices (1);
358 std::vector<float> nn_dists (1);
363 std::vector<int> source_indices (indices_->size ());
364 std::vector<int> target_indices (indices_->size ());
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));
373 Eigen::Matrix3d R = transform_R.topLeftCorner<3,3> ();
375 for (
size_t i = 0; i < N; i++)
377 PointSource query = output[i];
378 query.getVector4fMap () = guess * query.getVector4fMap ();
379 query.getVector4fMap () = transformation_ * query.getVector4fMap ();
381 if (!searchForNeighbors (query, nn_indices, nn_dists))
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]);
388 if (nn_dists[0] < dist_threshold)
390 Eigen::Matrix3d &C1 = input_covariances_[i];
391 Eigen::Matrix3d &C2 = target_covariances_[nn_indices[0]];
392 Eigen::Matrix3d &M = mahalanobis_[i];
396 Eigen::Matrix3d temp = M * R.transpose();
400 source_indices[cnt] =
static_cast<int> (i);
401 target_indices[cnt] = nn_indices[0];
406 source_indices.resize(cnt); target_indices.resize(cnt);
408 previous_transformation_ = transformation_;
412 rigid_transformation_estimation_(output, source_indices, *target_, target_indices, transformation_);
415 for(
int k = 0; k < 4; k++) {
416 for(
int l = 0; l < 4; l++) {
419 ratio = 1./rotation_epsilon_;
421 ratio = 1./transformation_epsilon_;
422 double c_delta = ratio*fabs(previous_transformation_(k,l) - transformation_(k,l));
428 catch (PCLException &e)
430 PCL_DEBUG (
"[pcl::%s::computeTransformation] Optimization issue %s\n", getClassName ().c_str (), e.what ());
435 if (nr_iterations_ >= max_iterations_ || delta < 1)
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 ());
443 PCL_DEBUG (
"[pcl::%s::computeTransformation] Convergence failed\n", getClassName ().c_str ());
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);
454 template <
typename Po
intSource,
typename Po
intTarget>
void
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);