ICP算法进行点云配准

一、算法原理

1.配准

给定两个来自不同坐标系的三维数据点集,找到两个点集空间的变换关系,使得两个点集能统一到同一坐标系统中,即配准过程。

2.ICP(Iterative Closest Point,迭代最近邻点)

ICP本质上是基于最小二乘法的最优配准方法,精度高,不需要提取特征点;但是需要在icp使用之前两点云已经完成粗配准,否则容易陷入局部最优。该算法重复进行选择对应关系点对,计算最优刚体变换这一过程,直到满足正确配准的收敛精度要求。ICP是一个广泛使用的配准算法,主要目的就是找到旋转和平移参数,将两个不同坐标系下的点云,以其中一个点云坐标系为全局坐标系,另一个点云经过旋转和平移后两组点云重合部分完全重叠。算法只适用于刚体配准;算法不适用于部分重叠点云的配准。
算法的输入:参考点云和目标点云,停止迭代的标准。
算法的输出:旋转和平移矩阵,即转换矩阵。

ICP算法原理
假设点云{Q}为目标点云(参考点云),{P}为源点云(待配准的点云), p i ( i ∈ 1 , 2 , . . . N ), q i 是{E}中与 pi距离最近的点。​
我们需要计算从{P }到{Q }的RT变换矩阵,即旋转矩阵R和平移矩阵T。如果变换参数是准确的,那么点云{P }中的每一个点 p i ,经过变换后应该与点云{Q}中的点 q i 完全重合,即: qi = R pi + T 。但由于有噪声的存在,不可能所有点都完全重合,所以我们定义目标函数:

使目标函数最小的R,T即为所求变换参数。F其实就是参考点云{Q } 与 已经进行R,T矩阵空间变换的{P’} 之间的平均距离。
计算方法:首先,对{P}中的每个点 pi ,寻找其在{Q}中的最近点 qi (利用kd树最近邻查找算法可实现),组成一一对应的点对。计算两组点云的质心,分别记为 u p , u q :

对两组点云进行去质心,得到:

构建矩阵H:

对H矩阵进行SVD分解:

(SVD(奇异值分解)是一种常用的矩阵重要特征计算工具,我们只是借助它计算RT矩阵,在此暂不必深究),得到R与T:

得到R,T矩阵以后,用其对待配准空间进行空间变换得到新的点集,并代入目标函数:

若如果新的变换点集与参考点集满足两点集的平均距离小于某一给定阈值,则停止迭代计算,否则新的变换点集作为新的{P_i }继续迭代,直到达到目标函数的要求。

总结ICP算法:
(1)计算{P}中的每一个点在{Q}点集中的对应近点;
(2)求得使上述对应点对平均距离最小的刚体变换,求得平移参数和旋转参数;
(3)对{P}使用上一步求得的平移和旋转矩阵进行空间变换,得到新的变换点集{P’};
(4)如果新的变换点集与参考点集满足两点集的平均距离小于某一给定阈值,或者迭代次数达到设定的最大值,则停止迭代计算,否则新的变换点集作为新的{P}继续迭代,直到达到目标函数的要求。

可能存在的问题
(1)算法收敛于局部最小误差。
(2)噪声或异常数据可能导致算法无法收敛或错误。
(3)在进行ICP算法第一步要确定一个迭代初值,选取的初值将对最后配准结果产生重要的影响,如果初值选择不合适,算法可能就会限入局部最优,使得迭代不能收敛到正确的配准结果。
二、源代码(PCL1.1.1+Visual Studio 2019)

#include <pcl/registration/ia_ransac.h>//点云的ransac算法头文件
#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
#include <pcl/io/pcd_io.h>//pcd输入输出头文件
#include <pcl/registration/icp.h>//点云icp算法头文件
#include <pcl/visualization/pcl_visualizer.h>//点云可视化头文件
#include <time.h>
#include <boost/thread.hpp>
typedef pcl::PointXYZ PointT; //重定义pcl::PointXYZ为PointT
typedef pcl::PointCloud<PointT> PointCloud; //重定义pcl::PointCloud<PointT>为PointCloud

//点云可视化
void visualize_pcd(PointCloud::Ptr pcd_src,
    PointCloud::Ptr pcd_tgt,
    PointCloud::Ptr pcd_final)
{
    pcl::visualization::PCLVisualizer viewer("registration Viewer");
    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> src_h(pcd_src, 0, 255, 0);
    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> tgt_h(pcd_tgt, 255, 0, 0);
    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> final_h(pcd_final, 0, 0, 255);
    viewer.addPointCloud(pcd_src, src_h, "source cloud");    //source绿色
    viewer.addPointCloud(pcd_tgt, tgt_h, "tgt cloud");     //target红色
    //viewer.addPointCloud (pcd_final, final_h, "final cloud");  //final蓝色

    while (!viewer.wasStopped())
    {
        viewer.spinOnce(100);
        boost::this_thread::sleep(boost::posix_time::microseconds(100000));
    }
}

int main(int argc, char** argv)
{
    //加载点云文件
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_src_o(new pcl::PointCloud<pcl::PointXYZ>);//原点云,待配准
    pcl::io::loadPCDFile("scan11.pcd", *cloud_src_o);
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_tgt_o(new pcl::PointCloud<pcl::PointXYZ>);//目标点云
    pcl::io::loadPCDFile("scan22.pcd", *cloud_tgt_o);
    clock_t start = clock();

    //icp配准
    pcl::PointCloud<pcl::PointXYZ>::Ptr icp_result(new pcl::PointCloud<pcl::PointXYZ>);
    pcl::IterativeClosestPoint<pcl::PointXYZ, pcl::PointXYZ> icp;

    // 最大迭代次数
    icp.setMaximumIterations(50);
    // 两次变化矩阵之间的差值
    icp.setTransformationEpsilon(1e-10);
    // 均方误差
    icp.setEuclideanFitnessEpsilon(0.01);

    icp.setInputSource(cloud_src_o);//录入source点云
    icp.setInputTarget(cloud_tgt_o);//录入target点云
    pcl::PointCloud<pcl::PointXYZ> final_cloud;
    icp.align(final_cloud);//最终配准结果
    clock_t end = clock();
    cout << "total time: " << (double)(end - start) / (double)CLOCKS_PER_SEC << " s" << endl;//输出配准所用时间
    std::cout << "ICP has converged:" << icp.hasConverged() << " score: " << icp.getFitnessScore() << std::endl;
    Eigen::Matrix4f icp_trans;
    icp_trans = icp.getFinalTransformation();
    std::cout << endl << "R,T=" << icp_trans << endl;//输出R、T
    //使用创建的变换对未过滤的输入点云进行变换
    pcl::transformPointCloud(*cloud_src_o, *icp_result, icp_trans);

    visualize_pcd(cloud_src_o, cloud_tgt_o, icp_result);
    return (0);
}

二、运行结果及分析

用来配准的两组点云数据下载:点这里

配准数据1:

room_scan1.pcd
在这里插入图片描述
room_scan2.pcd
在这里插入图片描述
配准结果:
在这里插入图片描述

配准数据2:

bunny1.pcd
在这里插入图片描述
bunny2.pcd:
在这里插入图片描述
配准结果:
在这里插入图片描述

  • 14
    点赞
  • 114
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
基于改进ICP点云配准算法是一种用于匹配两个或多个点云之间的方法。传统的ICP(Iterative Closest Point)算法点云配准中被广泛应用,但其在面临一些挑战时表现不佳。因此,为了改进ICP算法的性能,各种改进方法被提出。 改进ICP算法的主要思想是使其更加稳健和高效。其中一种改进方法是引入局部特征描述符,例如法线向量和颜色信息,以提高配准的准确性。通过在初始匹配阶段使用这些特征,可以更好地区分点云中的不同结构。在迭代匹配过程中,可以使用这些特征来寻找最佳对应点。此外,使用这些特征还可以提高算法对非刚体变形的适应能力,例如弯曲的物体。 另一种改进ICP算法的方法是引入采样技术,例如随机采样一致(RANSAC)。RANSAC可以用来过滤掉异常点,有助于减小噪声对匹配过程的影响。通过采取随机样本并计算与之最匹配的点对,可以筛选出最佳的匹配结果。 此外,基于改进ICP算法配准还可以利用全局优化策略来提高配准的精度和鲁棒性。这包括使用经典的优化算法,如最小二乘法或非线性优化算法,以优化初始变换矩阵。通过在全局空间中搜索最佳的变换参数,可以避免局部最优解,并提高配准的准确性。 综上所述,基于改进ICP点云配准算法通过引入局部特征描述符、采样技术和全局优化策略,可以提高匹配结果的准确性、稳定性和效率。这些改进使得算法能够更好地应对点云配准中的挑战,同时也为其他应用领域提供了更广阔的应用前景。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值