PCL 4PCS点云粗配准(Registration_FPCS)

4PCS用于点云粗配准,ICP用于粗配准之后的精配准。

本文算法原理参考于:3D点云配准算法-4PCS(4点全等集配准算法)

1.4PCS算法原理

核心思想:使用四个近似共面点来描述两个三维点云之间的刚性变换关系,因此由称”四点匹配算法“。即不停迭代计算源点云Q的四点集Qa,与目标点云P中与Qa重叠度最高的四点集Pb,二者之间的最优变换矩阵T,得到粗配准的变换矩阵。

如下图:

1.点云四点集的确定

(1)选择三个共面点

1)在源点云中随机选择三个点,要求这三点所构成的三角形面积尽量的大(三点确定一个平面,向量叉积可以计算面积),但是三点间的距离不能超过一定的阈值上限,该上限由两片点云的给定重叠率 f 确定。

2)因为三点之间距离越大,配准的鲁棒性越高;但距离过大,三点均在两点云的重叠区域之外了,配准效果又不好。因此需要在满足上限的基础之上,尽可能保证大的三级形面积。

3)若没有给定点云重叠率f,则可以进行f=1.0,0.75,0.5...重叠率递减测试,选择最优变换。

(2)选择第四个共面点

1)确定三点后,遍历源点云中所有的点,对每一个点进行计算验证选择最优的第四点。

2)第四点需要与其他三点组成的平面尽可能的共面(即不强制要求四点共面,但第四点到其他三点平面的距离尽可能小),并且第四点与其他三点的距离也要满足距离阈值范围(不能太近不能太远)。

2.4PCS计算

计算其四点构成的两线段交点的变换不变比,根据不变比在目标点云中遍历搜索对应的满足该约束所有四点集,得到的四点集,即近似全等四点集。

具体流程:

(1)选取源点云四点集

1)在源点云P中,使用上述的四点集的选择方法随机选择一个四点集B={b1,b2,b3,b4},其中(b1,b2)确定线段1,(b3,b4)确定线段2。

2)计算不变量d1=|b1-b2|,d2=|b3-b4|(约束1),不变比r1=|b1-e| / |b1-b2|,r2=|b3-e| / |b3-b4|(约束2)。注意因为四点不一定共面,两条线段也不一定相交,所以可以使用连接两个线段的最近点的中心点作为“交点”。

(2)遍历目标点云点对,筛选得到目标点云中的点对集合。

1)在目标点云Q中,遍历所有的点对,筛选满足约束1(允许有一定的误差)的点对集合R1,R2。其表示为:

计算R1 ={ (pi, pj) | pi, pj ∈ Q) },使|| pi - pj ||∈ [ d1- δ,d1+δ ].

计算R2 ={ (pi, pj) | pi, pj ∈ Q) },使|| pi - pj ||∈ [ d2- δ,d2+δ ].

(3)构建映射

1)遍历点对集合R1中的所有点对元素r1_i = {(q_i,q_j)},计算其线段上满足不变比r1的目标交点e1_i

2)所有计算结果e存入搜索树ANN Tree(近似最邻近搜索树,最常见的是K-D Tree算法),并构建相应的映射Map(e1_i) = r1_i = (q_i,q_j) 

(4)求解近似全等四点集

1)遍历点对集合R2中的所有点对元素r2_i = (q_i,q_j),计算其线段上满足不变比r2的目标交点e2_i,并构建相应的映射Map(e2_i) = r2_i

2)遍历所有的e2_i点,在之前构建的ANN Tree中搜索可接受误差范围内的重合点e1_i,若可找到则说明能在Q中找到一个对应的近似全等四点集U_i = \{Map(e1_i),Map(e2_i)\}。最终求得所有的近似全等四点集U = \{U_0,U_1,...\}

(5)得到本次迭代最优变换矩阵T

1)遍历所有的近似全等四点集U_i \in U,对每一个U_i通过最小二乘法计算其与B的对应变换矩阵T_i

2)使用该变换矩阵对源点云P进行变换得到P',统计P'与Q中的最大公共点集(LCP),记max(LCP)的变换矩阵为本次迭代的最优变换矩阵T并保留。

(6)不断迭代这个过程,记录最优的变换。迭代结束后得到的变换矩阵即为最优变换矩阵。

2.关键函数

(1)设置源和目标之间的近似重叠度

registration.setApproxOverlap(0.5)

(2)设置常数因子delta,用于对内部计算的参数进行加权

registration.setDelta(0.01)

(3)设置验证配准效果时要使用的采样点数量

registration.setNumberOfSamples(100)

3.完整代码

#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/registration/ia_fpcs.h>
#include <boost/thread/thread.hpp>
#include <pcl/visualization/pcl_visualizer.h>

int main()
{
	/****************FPCS配准********************/
	pcl::PointCloud<pcl::PointXYZ>::Ptr source(new pcl::PointCloud<pcl::PointXYZ>);			// 源点云
	pcl::PointCloud<pcl::PointXYZ>::Ptr target(new pcl::PointCloud<pcl::PointXYZ>);			// 目标点云
	pcl::io::loadPCDFile("D:/code/csdn/data/B30.pcd", *source);
	pcl::io::loadPCDFile("D:/code/csdn/data/B31.pcd", *target);
	pcl::PointCloud<pcl::PointXYZ>::Ptr result(new pcl::PointCloud<pcl::PointXYZ>);			// 目标点云转换后的结果

	// FPCS配准
	pcl::registration::FPCSInitialAlignment<pcl::PointXYZ, pcl::PointXYZ> registration;
	registration.setInputSource(source);				// 源点云
	registration.setInputTarget(target);				// 目标点云
	registration.setApproxOverlap(0.5);					// 设置源和目标之间的近似重叠度。
	registration.setDelta(0.01);						// 设置常数因子delta,用于对内部计算的参数进行加权
	registration.setNumberOfSamples(100);				// 设置验证配准效果时要使用的采样点数量
	registration.align(*result);

	/****************展示********************/
	boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("FPCS"));
	pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ>target_color(target, 255, 0, 0);		// 目标点云
	viewer->addPointCloud<pcl::PointXYZ>(target, target_color, "target cloud");
	pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ>result_color(result, 0, 255, 0);		// 配准结果点云
	viewer->addPointCloud<pcl::PointXYZ>(result, result_color, "result cloud");

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

	return (0);
}

4.结果展示

  • 11
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
点云ICP配准是一种常用的点云配准方法,可以将两组点云进行精确的对齐。在PCL中,ICP配准算法可以通过pcl::IterativeClosestPoint类实现。 以下是一个简单的点云ICP配准示例: ```c++ #include <pcl/point_types.h> #include <pcl/io/pcd_io.h> #include <pcl/registration/icp.h> int main(int argc, char** argv) { // 加载原始点云和目标点云 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in (new pcl::PointCloud<pcl::PointXYZ>); pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_out (new pcl::PointCloud<pcl::PointXYZ>); pcl::io::loadPCDFile<pcl::PointXYZ> ("input_cloud.pcd", *cloud_in); pcl::io::loadPCDFile<pcl::PointXYZ> ("target_cloud.pcd", *cloud_out); // 创建ICP对象 pcl::IterativeClosestPoint<pcl::PointXYZ, pcl::PointXYZ> icp; icp.setInputSource(cloud_in); icp.setInputTarget(cloud_out); // 设置ICP参数 icp.setMaxCorrespondenceDistance(0.05); icp.setMaximumIterations(50); icp.setTransformationEpsilon(1e-8); icp.setEuclideanFitnessEpsilon(1); // 执行ICP配准 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_aligned (new pcl::PointCloud<pcl::PointXYZ>); icp.align(*cloud_aligned); // 输出配准结果 std::cout << "ICP has converged:" << icp.hasConverged() << " score: " << icp.getFitnessScore() << std::endl; std::cout << icp.getFinalTransformation() << std::endl; // 保存配准后的点云 pcl::io::savePCDFile<pcl::PointXYZ>("output_cloud.pcd", *cloud_aligned); return 0; } ``` 在代码中,我们首先加载了原始点云和目标点云,然后创建了一个pcl::IterativeClosestPoint对象,并将原始点云和目标点云设置为输入源和目标。 接着,我们设置了ICP的参数,例如最大对应距离、最大迭代次数、变换阈值等等。 最后,我们调用icp.align()函数执行ICP配准,将配准后的点云保存到硬盘中。 需要注意的是,ICP算法只能对初始姿态比较接近的两组点云进行配准。如果两组点云初始姿态差距较大,需要使用其他方法(例如全局配准)进行预处理,以便ICP算法可以更快地收敛到最优解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值