赞
踩
话不多说,直接上代码
#include <pcl/registration/icp.h> #include <pcl/point_types.h> pc_xyz::Ptr result = boost::make_shared<pc_xyz>(); pcl::IterativeClosestPoint<pcl::PointXYZ, pcl::PointXYZ> icp; icp.setMaxCorrespondenceDistance(max_correspondence_dist_);// 设置corr_dist_threshold_ icp.setMaximumIterations(max_iterations_); //设置max_iterations_ icp.setTransformationEpsilon(1e-6); //设置transformation_epsilon_ icp.setEuclideanFitnessEpsilon(1e-2); // 设置euclidean_fitness_epsilon_ icp.setInputSource(local_map_xyz);//设置input_ ,source_cloud_updated_ = true; icp.setInputTarget(global_map_xyz);//设置target_, target_cloud_updated_ = true; if (do_ransac_outlier_rejection_) { icp.setRANSACOutlierRejectionThreshold(ransac_outlier_rejection_threshold_); icp.setRANSACIterations(ransac_iterations_); } icp.align(*result);//主要匹配函数 is_converged = icp.hasConverged(); fitness = icp.getFitnessScore(); correction = icp.getFinalTransformation();
第1小节中的
icp.align(*result);//主要匹配函数
对应的为pcl/registtation/impl/registation.hpp中的
template <typename PointSource, typename PointTarget, typename Scalar> inline void
pcl::Registration<PointSource, PointTarget, Scalar>::align (PointCloudSource &output)
{
align (output, Matrix4::Identity ());
}
其调用pcl::Registration<PointSource, PointTarget, Scalar>::align (PointCloudSource &output, const Matrix4& guess) 函数。
ICP的核心内容也就是该函数,接下来我们对其进行详细解释:
template <typename PointSource, typename PointTarget, typename Scalar> inline void pcl::Registration<PointSource, PointTarget, Scalar>::align (PointCloudSource &output, const Matrix4& guess) { if (!initCompute ()) //初始化kd树,及点云索引 return; // Resize the output dataset if (output.points.size () != indices_->size ()) output.points.resize (indices_->size ()); // Copy the header output.header = input_->header; // Check if the output will be computed for all points or only a subset if (indices_->size () != input_->points.size ()) { output.width = static_cast<uint32_t> (indices_->size ()); output.height = 1; } else { output.width = static_cast<uint32_t> (input_->width); output.height = input_->height; } output.is_dense = input_->is_dense; // Copy the point data to output for (size_t i = 0; i < indices_->size (); ++i) output.points[i] = input_->points[(*indices_)[i]];//将原始点云复制到output中 // Set the internal point representation of choice unless otherwise noted if (point_representation_ && !force_no_recompute_) tree_->setPointRepresentation (point_representation_); // Perform the actual transformation computation converged_ = false; final_transformation_ = transformation_ = previous_transformation_ = Matrix4::Identity (); // Right before we estimate the transformation, we set all the point.data[3] values to 1 to aid the rigid // transformation for (size_t i = 0; i < indices_->size (); ++i) output.points[i].data[3] = 1.0; computeTransformation (output, guess);//求解旋转矩阵,动态绑定到pcl::IterativeClosestPoint::computeTransformation() deinitCompute ();// return (true); 直接返回true }
initCompute用于初始化kd树,及点云索引
template <typename PointSource, typename PointTarget, typename Scalar> bool Registration<PointSource, PointTarget, Scalar>::initCompute() { if (!target_) { PCL_ERROR("[pcl::registration::%s::compute] No input target dataset was given!\n", getClassName().c_str()); return (false); } // Only update target kd-tree if a new target cloud was set if (target_cloud_updated_ && !force_no_recompute_) {//force_no_recompute_默认初始化为false,因此第一次运行时,进入该if判断 tree_->setInputCloud(target_);//用目标点云初始化kd树 target_cloud_updated_ = false; } // Update the correspondence estimation if (correspondence_estimation_) { correspondence_estimation_->setSearchMethodTarget(tree_, force_no_recompute_);//初始化correspondence_estimation_,包括 tree_ = tree; force_no_recompute_ = force_no_recompute; target_cloud_updated_ = true; correspondence_estimation_->setSearchMethodSource(tree_reciprocal_, force_no_recompute_reciprocal_); } // Note: we /cannot/ update the search method on all correspondence rejectors, because // we know nothing about them. If they should be cached, they must be cached // individually. return (PCLBase<PointSource>::initCompute());//初始化与input_的size对应的indices_ }
enum ConvergenceState
{
CONVERGENCE_CRITERIA_NOT_CONVERGED,//默认值,converged_ = false;
CONVERGENCE_CRITERIA_ITERATIONS,//迭代结果为达到迭代次数,此时若设置failure_after_max_iter_ = true,就会导致converged_ = false;默认状态是failure_after_max_iter_ = false,因此该情况下超过迭代次数会判断converged_ = true
CONVERGENCE_CRITERIA_TRANSFORM,//平移距离的平方和满足transformation_epsilon_要求,则判断CONVERGENCE_CRITERIA_TRANSFORM, converged_ = true
CONVERGENCE_CRITERIA_ABS_MSE,//两次迭代的绝对距离差满足收敛要求,converged_ = true
CONVERGENCE_CRITERIA_REL_MSE,//两次迭代的相对距离差满足收敛要求,converged_ = true
CONVERGENCE_CRITERIA_NO_CORRESPONDENCES//迭代结果为对应点对太少,converged_ = false;
};
pcl::IterativeClosestPoint::computeTransformation() 位于pcl/registration/impl/icp.hpp文件中:
template <typename PointSource, typename PointTarget, typename Scalar> void IterativeClosestPoint<PointSource, PointTarget, Scalar>::computeTransformation( PointCloudSource& output, const Matrix4& guess) { // Point cloud containing the correspondences of each point in <input, indices> PointCloudSourcePtr input_transformed(new PointCloudSource); nr_iterations_ = 0; converged_ = false; // Initialise final transformation to the guessed one final_transformation_ = guess; // If the guessed transformation is non identity if (guess != Matrix4::Identity()) { input_transformed->resize(input_->size()); // Apply guessed transformation prior to search for neighbours transformCloud(*input_, *input_transformed, guess); } else *input_transformed = *input_; transformation_ = Matrix4::Identity(); // Make blobs if necessary determineRequiredBlobData();// 未指定correspondence_rejectors_ 以及点云都没有法向量的话,need_source_blob_以及need_target_blob_ 都是false,即不要求处理“二进制长对象(blob)” PCLPointCloud2::Ptr target_blob(new PCLPointCloud2); if (need_target_blob_) pcl::toPCLPointCloud2(*target_, *target_blob); // Pass in the default target for the Correspondence Estimation/Rejection code correspondence_estimation_->setInputTarget(target_); //设置CorrespondenceEstimationBase中的target_ ,target_cloud_updated_ = true; if (correspondence_estimation_->requiresTargetNormals()) correspondence_estimation_->setTargetNormals(target_blob); // Correspondence Rejectors need a binary blob for (std::size_t i = 0; i < correspondence_rejectors_.size(); ++i) { registration::CorrespondenceRejector::Ptr& rej = correspondence_rejectors_[i]; if (rej->requiresTargetPoints()) rej->setTargetPoints(target_blob); if (rej->requiresTargetNormals() && target_has_normals_) rej->setTargetNormals(target_blob); } convergence_criteria_->setMaximumIterations(max_iterations_);//设置DefaultConvergenceCriteria 中的max_iterations_ convergence_criteria_->setRelativeMSE(euclidean_fitness_epsilon_);//设置DefaultConvergenceCriteria 中的mse_threshold_relative_ convergence_criteria_->setTranslationThreshold(transformation_epsilon_);//设置DefaultConvergenceCriteria 中的translation_threshold_ if (transformation_rotation_epsilon_ > 0) convergence_criteria_->setRotationThreshold(transformation_rotation_epsilon_); else convergence_criteria_->setRotationThreshold(1.0 - transformation_epsilon_);//设置DefaultConvergenceCriteria 中的rotation_threshold_ // Repeat until convergence //以下进入icp迭代解算 do { // Get blob data if needed PCLPointCloud2::Ptr input_transformed_blob; if (need_source_blob_) { input_transformed_blob.reset(new PCLPointCloud2); toPCLPointCloud2(*input_transformed, *input_transformed_blob); } // Save the previously estimated transformation previous_transformation_ = transformation_; // Set the source each iteration, to ensure the dirty flag is updated correspondence_estimation_->setInputSource(input_transformed); if (correspondence_estimation_->requiresSourceNormals()) correspondence_estimation_->setSourceNormals(input_transformed_blob); // Estimate correspondences if (use_reciprocal_correspondence_) correspondence_estimation_->determineReciprocalCorrespondences( *correspondences_, corr_dist_threshold_); else correspondence_estimation_->determineCorrespondences(*correspondences_, corr_dist_threshold_);//基于kd树最近邻查找最近点。 // if (correspondence_rejectors_.empty ()) CorrespondencesPtr temp_correspondences(new Correspondences(*correspondences_)); for (std::size_t i = 0; i < correspondence_rejectors_.size(); ++i) { registration::CorrespondenceRejector::Ptr& rej = correspondence_rejectors_[i]; PCL_DEBUG("Applying a correspondence rejector method: %s.\n", rej->getClassName().c_str()); if (rej->requiresSourcePoints()) rej->setSourcePoints(input_transformed_blob); if (rej->requiresSourceNormals() && source_has_normals_) rej->setSourceNormals(input_transformed_blob); rej->setInputCorrespondences(temp_correspondences); rej->getCorrespondences(*correspondences_); // Modify input for the next iteration if (i < correspondence_rejectors_.size() - 1) *temp_correspondences = *correspondences_; } std::size_t cnt = correspondences_->size(); // Check whether we have enough correspondences if (static_cast<int>(cnt) < min_number_correspondences_) { PCL_ERROR("[pcl::%s::computeTransformation] Not enough correspondences found. " "Relax your threshold parameters.\n", getClassName().c_str()); convergence_criteria_->setConvergenceState( pcl::registration::DefaultConvergenceCriteria< Scalar>::CONVERGENCE_CRITERIA_NO_CORRESPONDENCES); converged_ = false; break;//若对应点对数太少,则直接终止icp,收敛状态为false } // Estimate the transform transformation_estimation_->estimateRigidTransformation( *input_transformed, *target_, *correspondences_, transformation_);//进行svd位姿解算 // Transform the data transformCloud(*input_transformed, *input_transformed, transformation_); // Obtain the final transformation final_transformation_ = transformation_ * final_transformation_;//叠加位姿估算结果 ++nr_iterations_; // Update the vizualization of icp convergence // if (update_visualizer_ != 0) // update_visualizer_(output, source_indices_good, *target_, target_indices_good ); converged_ = static_cast<bool>((*convergence_criteria_));//这里显式类型转换调用了pcl::registration::ConvergenceCriteria中对bool的重载,该重载中调用了pcl::registration::DefaultConvergenceCriteria<Scalar>::hasConverged()函数 } while (convergence_criteria_->getConvergenceState() == pcl::registration::DefaultConvergenceCriteria< Scalar>::CONVERGENCE_CRITERIA_NOT_CONVERGED); // Transform the input cloud using the final transformation PCL_DEBUG("Transformation " "is:\n\t%5f\t%5f\t%5f\t%5f\n\t%5f\t%5f\t%5f\t%5f\n\t%5f\t%5f\t%5f\t%5f\n\t%" "5f\t%5f\t%5f\t%5f\n", final_transformation_(0, 0), final_transformation_(0, 1), final_transformation_(0, 2), final_transformation_(0, 3), final_transformation_(1, 0), final_transformation_(1, 1), final_transformation_(1, 2), final_transformation_(1, 3), final_transformation_(2, 0), final_transformation_(2, 1), final_transformation_(2, 2), final_transformation_(2, 3), final_transformation_(3, 0), final_transformation_(3, 1), final_transformation_(3, 2), final_transformation_(3, 3));//打印最终的变换矩阵 // Copy all the values output = *input_; // Transform the XYZ + normals transformCloud(*input_, output, final_transformation_);//进行坐标转换获取最终结果output }
template <typename Scalar> bool pcl::registration::DefaultConvergenceCriteria<Scalar>::hasConverged () { convergence_state_ = CONVERGENCE_CRITERIA_NOT_CONVERGED; PCL_DEBUG ("[pcl::DefaultConvergenceCriteria::hasConverged] Iteration %d out of %d.\n", iterations_, max_iterations_); // 1. Number of iterations has reached the maximum user imposed number of iterations if (iterations_ >= max_iterations_) { if (failure_after_max_iter_) return (false); else { convergence_state_ = CONVERGENCE_CRITERIA_ITERATIONS; return (true); } return (failure_after_max_iter_ ? false : true); } // 2. The epsilon (difference) between the previous transformation and the current estimated transformation double cos_angle = 0.5 * (transformation_.coeff (0, 0) + transformation_.coeff (1, 1) + transformation_.coeff (2, 2) - 1);//罗德里格斯公式 double translation_sqr = transformation_.coeff (0, 3) * transformation_.coeff (0, 3) + transformation_.coeff (1, 3) * transformation_.coeff (1, 3) + transformation_.coeff (2, 3) * transformation_.coeff (2, 3);//平移二范数 PCL_DEBUG ("[pcl::DefaultConvergenceCriteria::hasConverged] Current transformation gave %f rotation (cosine) and %f translation.\n", cos_angle, translation_sqr); if (cos_angle >= rotation_threshold_ && translation_sqr <= translation_threshold_)//平移距离的二范数满足要求则判断CONVERGENCE_CRITERIA_TRANSFORM { if (iterations_similar_transforms_ < max_iterations_similar_transforms_) { // Increment the number of transforms that the thresholds are allowed to be similar ++iterations_similar_transforms_; return (false); } else { iterations_similar_transforms_ = 0; convergence_state_ = CONVERGENCE_CRITERIA_TRANSFORM; return (true); } } correspondences_cur_mse_ = calculateMSE (correspondences_);//计算平均距离,单位为m PCL_DEBUG ("[pcl::DefaultConvergenceCriteria::hasConverged] Previous / Current MSE for correspondences distances is: %f / %f.\n", correspondences_prev_mse_, correspondences_cur_mse_); // 3. The relative sum of Euclidean squared errors is smaller than a user defined threshold // Absolute if (fabs (correspondences_cur_mse_ - correspondences_prev_mse_) < mse_threshold_absolute_)//两次迭代的绝对距离差满足收敛要求 { if (iterations_similar_transforms_ < max_iterations_similar_transforms_) { // Increment the number of transforms that the thresholds are allowed to be similar ++iterations_similar_transforms_; return (false); } else { iterations_similar_transforms_ = 0; convergence_state_ = CONVERGENCE_CRITERIA_ABS_MSE; return (true); } } // Relative if (fabs (correspondences_cur_mse_ - correspondences_prev_mse_) / correspondences_prev_mse_ < mse_threshold_relative_)//两次迭代的相对距离差满足收敛要求 { if (iterations_similar_transforms_ < max_iterations_similar_transforms_) { // Increment the number of transforms that the thresholds are allowed to be similar ++iterations_similar_transforms_; return (false); } else { iterations_similar_transforms_ = 0; convergence_state_ = CONVERGENCE_CRITERIA_REL_MSE; return (true); } } correspondences_prev_mse_ = correspondences_cur_mse_; return (false); }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。