上一篇:http://www.cnblogs.com/yhlx125/p/4924283.html截图了一些ICP算法进行点云匹配的类图。

但是将对应点剔除这块和ICP算法的关系还是没有理解。

RANSAC算法可以实现点云剔除,但是ICP算法通过稳健性的算法实现匹配,似乎不进行对应点剔除。是不是把全局的点云匹配方法和局部点云匹配方法搞混了?

ICP算法可以通过三种方式处理噪声、部分重叠的问题:剔除、权重、Trimmed方法和稳健估计方法。下面分析一下PCL中关于ICP算法的实现。

首先是IterativeClosestPoint模板类继承自Registration模板类。

查看icp.h中的定义:

template <typename PointSource, typename PointTarget, typename Scalar = float>
class IterativeClosestPoint : public Registration<PointSource, PointTarget, Scalar>

查看registration.h中的定义:

 template <typename PointSource, typename PointTarget, typename Scalar = float>
class Registration : public PCLBase<PointSource>

同样的IterativeClosestPointNonLinear 继承自IterativeClosestPoint,查看icp_nl.h

template <typename PointSource, typename PointTarget, typename Scalar = float> class IterativeClosestPointNonLinear : public IterativeClosestPoint<PointSource, PointTarget, Scalar>

区别在于ICP算法的求解方式不同,非线性求解采用的是LM算法:http://www.cnblogs.com/yhlx125/p/4955337.html

下面重点说明IterativeClosestPoint模板类。匹配的关键方法Align在Registration中实现。

 template <typename PointSource, typename PointTarget, typename Scalar> inline void
pcl::Registration<PointSource, PointTarget, Scalar>::align (PointCloudSource &output, const Matrix4& guess)
{
if (!initCompute ())
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 = ;
}
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 = ; i < indices_->size (); ++i)
output.points[i] = input_->points[(*indices_)[i]]; // 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 = ; i < indices_->size (); ++i)
output.points[i].data[] = 1.0; computeTransformation (output, guess);

deinitCompute ();
}

重点关注computeTransformation虚方法。显然IterativeClosestPoint重载了基类这个方法。

virtual void computeTransformation (PointCloudSource &output, const Matrix4& guess) = ;

代码如下:

 template <typename PointSource, typename PointTarget, typename Scalar> void
pcl::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_ = ;
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 ();
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_);
if (correspondence_estimation_->requiresTargetNormals ())
correspondence_estimation_->setTargetNormals (target_blob);
// Correspondence Rejectors need a binary blob
for (size_t i = ; 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_);
convergence_criteria_->setRelativeMSE (euclidean_fitness_epsilon_);
convergence_criteria_->setTranslationThreshold (transformation_epsilon_);
convergence_criteria_->setRotationThreshold (1.0 - transformation_epsilon_); // Repeat until convergence
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_);

//if (correspondence_rejectors_.empty ())
CorrespondencesPtr temp_correspondences (new Correspondences (*correspondences_));
for (size_t i = ; 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 () - )
*temp_correspondences = *correspondences_;
} 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;
} // Estimate the transform
transformation_estimation_->estimateRigidTransformation (*input_transformed, *target_, *correspondences_, transformation_);

// Tranform 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_));
}
while (!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_ (, ), final_transformation_ (, ), final_transformation_ (, ), final_transformation_ (, ),
final_transformation_ (, ), final_transformation_ (, ), final_transformation_ (, ), final_transformation_ (, ),
final_transformation_ (, ), final_transformation_ (, ), final_transformation_ (, ), final_transformation_ (, ),
final_transformation_ (, ), final_transformation_ (, ), final_transformation_ (, ), final_transformation_ (, )); // Copy all the values
output = *input_;
// Transform the XYZ + normals
transformCloud (*input_, output, final_transformation_);
}

该方法的主体是一个do-while循环。这里要说三个内容:correspondence_estimation_ 、correspondence_rejectors_ 和 convergence_criteria_ 。

三个变量的作用分别是查找最近点,剔除错误的对应点,收敛准则。因为是do-while循环,因此收敛准则的作用是跳出循环。

transformation_estimation_是求解ICP的具体算法:

transformation_estimation_->estimateRigidTransformation (*input_transformed, *target_, *correspondences_, transformation_);

查看类图可以知道包括SVD奇异值分解算法,查看transformation_estimation_svd.hpp中的TransformationEstimationSVD类的estimateRigidTransformation 方法:

template <typename PointSource, typename PointTarget, typename Scalar> inline void
pcl::registration::TransformationEstimationSVD<PointSource, PointTarget, Scalar>::estimateRigidTransformation (
ConstCloudIterator<PointSource>& source_it,
ConstCloudIterator<PointTarget>& target_it,
Matrix4 &transformation_matrix) const

其中通过调用下面的代码实现了SVD求解,具体方法内部实现时通过Eigen3实现的。需要具体查看,可以借鉴。

transformation_matrix = pcl::umeyama (cloud_src, cloud_tgt, false);

[PCL]5 ICP算法进行点云匹配的更多相关文章

  1. PCL点云库:ICP算法

    ICP(Iterative Closest Point迭代最近点)算法是一种点集对点集配准方法.在VTK.PCL.MRPT.MeshLab等C++库或软件中都有实现,可以参见维基百科中的ICP Alg ...

  2. 点云匹配和ICP算法概述

    Iterative Closest Point (ICP) [1][2][3] is an algorithm employed to minimize the difference between ...

  3. ICP 算法

    ICP 算法是一种点云到点云的配准方法. 在SLAM中通过空间点云的配准(可以通过相机或者3D激光雷达获取点云数据),可以估计相机运动(机器人运动,旋转矩阵R与平移向量t),累积配准,并不断回环检测, ...

  4. 三维点集拟合:平面拟合、RANSAC、ICP算法

    ACM算法分类:http://www.kuqin.com/algorithm/20080229/4071.html 一: 拟合一个平面:使用SVD分解,代码里面去找吧 空间平面方程的一般表达式为: A ...

  5. ICP算法(Iterative Closest Point迭代最近点算法)

    标签: 图像匹配ICP算法机器视觉 2015-12-01 21:09 2217人阅读 评论(0) 收藏 举报 分类: Computer Vision(27) 版权声明:本文为博主原创文章,未经博主允许 ...

  6. ICP算法使用遇到的问题

    这几天在学习数据关联的方法,本来想使用ICP算法进行距离测距数据的配准,但是用的过程中出现问题,配的不准,而且偏差更大了. 红色的和黄色的2维激光点进行ICP配准,但将变换矩阵和黄色进行乘之后偏差更大 ...

  7. icp算法基本思想

    Icp基本思想参考资料:http://www.cnblogs.com/jian-li/articles/4945676.html ,包括点-点,点-面的各种icp变种 Icp算法就是两个点云X.Y之间 ...

  8. PCL采样一致性算法

    在计算机视觉领域广泛的使用各种不同的采样一致性参数估计算法用于排除错误的样本,样本不同对应的应用不同,例如剔除错误的配准点对,分割出处在模型上的点集,PCL中以随机采样一致性算法(RANSAC)为核心 ...

  9. ICP算法(迭代最近点)

    参考博客:http://www.cnblogs.com/21207-iHome/p/6034462.html 最近在做点云匹配,需要用c++实现ICP算法,下面是简单理解,期待高手指正. ICP算法能 ...

随机推荐

  1. JAVA WEB 的JSP(9*9乘法表+*型金字塔)

    运行环境及工具: (Tomcat7) + (JAVA JDK)+ (Eclipse for J2EE) 输出9*9乘法表 代码片段的练习 增加一些简单的JS功能 <%@ page import= ...

  2. ASP.NET MVC4系列验证机制、伙伴类共享源数据信息(数据注解和验证)

    一,mvc前后台验证 自定义属性标签MyRegularExpression using System; using System.Collections.Generic; using System.C ...

  3. discuz全局数组变量 后台各项设置 完整版

    $_G 保存了 Discuz! 中所有的预处理数据 缓存能够很好的提高程序的性能,一些配置数据没必要每次都查询数据库,只要在修改了的时候更新下缓存即可. Discuz! 中所有的缓存保存在 $_G[c ...

  4. Android基础知识

    一.四大组件 Activity(活动).Service(服务).BroadcastReceiver(广播器).Content Provider(内容提供器) 二.五大布局 LinearLayout(线 ...

  5. C3P0连接池问题,APPARENT DEADLOCK!!! Creating emergency..... [问题点数:20分,结帖人lovekong]

    采用c3p0连接池,每次调试程序,第一次访问时(Tomcat服务器重启后再访问)都会出现以下错误,然后连接库需要很长时间,最终是可以连上的,之后再访问就没问题了,请高手们会诊一下,希望能帮小弟解决此问 ...

  6. JiaThis WordPress分享插件安装全攻略

    WordPress 是一个功能非常强大的博客系统,插件众多,易于扩充功能.安装和使用都非常方便.目前 WordPress 已经成为主流的 Blog 搭建平台.按照下面的方法,只需简单几步,就可轻松地将 ...

  7. 页面静态化3 --- 使用PHP页面缓存机制来完成页面静态化(下)操作一个案例(新闻管理系统)

    案例需求: 使用PHP缓存机制完成新闻管理系统的页面静态化数据库表 ecs_article (新闻表)因为新闻这些信息,并不是对实时性要求高,本身这个新闻比较稳定,内容也比较固定,所以我们考虑: 当第 ...

  8. textView截取字符串-医生工作台1期

    textfield截取字符串 ios7 会崩溃 解: 之前的写法是这样的 正确的写法:   先判断markedTextRange是否为nil,   markedTextRange这个属性是啥意思呢 表 ...

  9. SQL优化(zhuan)

    转自:http://www.jfox.info/SQL-you-hua 数据库的优化问题 一.问题的提出 在应用系统开发初期,由于开发数据库数据比较少,对于查询SQL语句,复杂视图的的编写等体会不出S ...

  10. CentOS 6.5 源码安装MySQL5.6.26

    1:下载安装cmake (mysql5.5以后是通过cmake来编译的) 2:创建mysql的安装目录及数据库存放目录 #mkdir /usr/mysql                 //安装my ...