目录
一、概述
1.1原理
1.2实现步骤
1.3应用场景
二、代码实现
2.1关键函数
2.1.1 perform_standard_icp 函数
2.1.2 perform_trimmed_icp 函数
2.1.3 visualize_registration 函数
2.2完整代码
PCL点云算法汇总及实战案例汇总的目录地址链接:
PCL点云算法与项目实战案例汇总(长期更新)
一、概述
Trimmed ICP算法是一种改进的点云配准算法,用于减少噪声点和异常值对配准精度的影响。它通过选择一定比例的内点参与配准,避免由于噪声或遮挡导致的误差传播。这种方法在处理具有部分重叠和大量噪声的点云数据时具有显著优势。
1.1原理
Trimmed ICP算法的核心思想是在每次迭代中只选择一部分最匹配的点对进行配准,通常通过设置内点的比例来控制匹配点的选择。该算法在配准时能够更好地处理局部噪声和不完全重叠的问题。
Trimmed ICP算法与标准ICP的不同之处在于:
- 配准点对选择:Trimmed ICP只选择源点云中最匹配的点对进行迭代,而不是使用所有点对,从而减少噪声点的干扰。
- 能量优化:在每次迭代中,Trimmed ICP只考虑一定比例的最小能量点对进行优化,从而更加鲁棒地处理部分匹配和噪声问题。
1.2实现步骤
- 加载点云数据:读取源点云和目标点云。
- 标准ICP配准:使用标准ICP进行初步配准,获得初始位姿估计。
- Trimmed ICP配准:在初始位姿基础上,使用Trimmed ICP进行精配准,通过设置内点比例进行优化。
- 可视化配准结果:输出和可视化配准前后点云的结果,并打印变换矩阵。
1.3应用场景
- 存在大量噪声的点云配准:Trimmed ICP能够有效剔除噪声点,适用于工业场景中的噪声数据处理。
- 部分重叠点云:当源点云和目标点云存在部分重叠时,Trimmed ICP通过选择部分匹配的点对进行配准,从而减少误差。
- 3D扫描、SLAM等需要精确配准的场景:Trimmed ICP能在带有噪声和部分重叠的点云中提供更高的配准精度。
二、代码实现
2.1关键函数
2.1.1 perform_standard_icp 函数
用于执行标准的ICP配准,获得初始的刚体变换矩阵:
// 执行标准ICP配准,获取初始位姿估计
void perform_standard_icp(pcl::PointCloud<pcl::PointXYZ>::Ptr& source_cloud, pcl::PointCloud<pcl::PointXYZ>::Ptr& target_cloud,
pcl::PointCloud<pcl::PointXYZ>::Ptr& icp_cloud, Eigen::Matrix4d& transformation_matrix, int iterations)
{
pcl::IterativeClosestPoint<pcl::PointXYZ, pcl::PointXYZ> icp;
icp.setMaximumIterations(iterations); // 设置最大迭代次数
icp.setMaxCorrespondenceDistance(15); // 设置最大对应点距离
icp.setTransformationEpsilon(1e-10); // 设置精度
icp.setEuclideanFitnessEpsilon(0.01); // 设置收敛条件
icp.setInputSource(source_cloud); // 设置源点云
icp.setInputTarget(target_cloud); // 设置目标点云
icp.align(*icp_cloud); // 执行ICP配准
if (icp.hasConverged())
{
std::cout << "\nICP has converged, score is " << icp.getFitnessScore() << std::endl;
transformation_matrix = icp.getFinalTransformation().cast<double>(); // 获取变换矩阵
print4x4Matrix(transformation_matrix); // 打印变换矩阵
}
else
{
PCL_ERROR("\nICP has not converged.\n");
exit(-1);
}
}
2.1.2 perform_trimmed_icp 函数
该函数执行Trimmed ICP配准,通过剔除噪声点进行更精细的配准:
// 执行Trimmed ICP配准,剔除噪声点进行精配准
void perform_trimmed_icp(pcl::PointCloud<pcl::PointXYZ>::Ptr& source_cloud, pcl::PointCloud<pcl::PointXYZ>::Ptr& target_cloud,
pcl::PointCloud<pcl::PointXYZ>::Ptr& icp_cloud, Eigen::Matrix4d& transformation_matrix)
{
pcl::recognition::TrimmedICP<pcl::PointXYZ, double> Tricp;
Tricp.init(target_cloud); // 初始化目标点云
float sigma = 0.96; // 设置内点比例
int Np = source_cloud->size(); // 源点云点数量
int Npo = Np * sigma; // 参与配准的点对数量
Tricp.setNewToOldEnergyRatio(sigma); // 设置内点能量比例
Tricp.align(*icp_cloud, Npo, transformation_matrix); // 执行Trimmed ICP配准
std::cout << "Trimmed ICP finished. Transformation matrix: \n";
print4x4Matrix(transformation_matrix); // 打印变换矩阵
}
2.1.3 visualize_registration 函数
该函数用于可视化配准前后的点云:
// 可视化配准前后的点云
void visualize_registration(pcl::PointCloud<pcl::PointXYZ>::Ptr& source, pcl::PointCloud<pcl::PointXYZ>::Ptr& target,
pcl::PointCloud<pcl::PointXYZ>::Ptr& result)
{
boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("配准结果"));
int v1, v2;
viewer->createViewPort(0, 0.0, 0.5, 1.0, v1); // 左侧视图
viewer->createViewPort(0.5, 0.0, 1.0, 1.0, v2); // 右侧视图
// 添加点云到视图中
pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> src_h(source, 0, 255, 0); // 源点云绿色
pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> tgt_h(target, 255, 0, 0); // 目标点云红色
pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> result_h(result, 0, 0, 255); // 配准后点云蓝色
viewer->addPointCloud(source, src_h, "source cloud", v1); // 左侧显示源点云
viewer->addPointCloud(target, tgt_h, "target cloud", v1); // 左侧显示目标点云
viewer->addPointCloud(result, result_h, "result cloud", v2); // 右侧显示配准后点云
while (!viewer->wasStopped())
{
viewer->spinOnce(100);
boost::this_thread::sleep(boost::posix_time::microseconds(10000));
}
}
2.2完整代码
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/registration/icp.h>
#include <pcl/console/time.h>
#include <pcl/recognition/ransac_based/trimmed_icp.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <Eigen/Dense>
#include "Trimmed.h" // 自定义的工具函数头文件
using namespace std;
// 执行标准ICP配准
void perform_standard_icp(pcl::PointCloud<pcl::PointXYZ>::Ptr& source_cloud,
pcl::PointCloud<pcl::PointXYZ>::Ptr& target_cloud,
pcl::PointCloud<pcl::PointXYZ>::Ptr& icp_cloud,
Eigen::Matrix4d& transformation_matrix, int iterations)
{
pcl::IterativeClosestPoint<pcl::PointXYZ, pcl::PointXYZ> icp;
icp.setMaximumIterations(iterations); // 设置最大迭代次数
icp.setMaxCorrespondenceDistance(15); // 设置最大对应点距离
icp.setTransformationEpsilon(1e-10); // 设置精度
icp.setEuclideanFitnessEpsilon(0.01); // 设置收敛条件
icp.setInputSource(source_cloud); // 设置源点云
icp.setInputTarget(target_cloud); // 设置目标点云
icp.align(*icp_cloud); // 执行ICP配准
if (icp.hasConverged())
{
std::cout << "\nICP has converged, score is " << icp.getFitnessScore() << std::endl;
transformation_matrix = icp.getFinalTransformation().cast<double>(); // 获取变换矩阵
print4x4Matrix(transformation_matrix); // 打印变换矩阵
}
else
{
PCL_ERROR("\nICP has not converged.\n");
exit(-1);
}
}
// 执行Trimmed ICP配准
void perform_trimmed_icp(pcl::PointCloud<pcl::PointXYZ>::Ptr& source_cloud,
pcl::PointCloud<pcl::PointXYZ>::Ptr& target_cloud,
pcl::PointCloud<pcl::PointXYZ>::Ptr& icp_cloud,
Eigen::Matrix4d& transformation_matrix)
{
pcl::recognition::TrimmedICP<pcl::PointXYZ, double> Tricp;
Tricp.init(target_cloud); // 初始化目标点云
float sigma = 0.96; // 设置内点比例
int Np = source_cloud->size(); // 源点云点数量
int Npo = Np * sigma; // 参与配准的点对数量
Tricp.setNewToOldEnergyRatio(sigma); // 设置内点能量比例
Tricp.align(*icp_cloud, Npo, transformation_matrix); // 执行Trimmed ICP配准
std::cout << "Trimmed ICP finished. Transformation matrix: \n";
print4x4Matrix(transformation_matrix); // 打印变换矩阵
}
// 可视化配准前后的点云
void visualize_registration(pcl::PointCloud<pcl::PointXYZ>::Ptr& source,
pcl::PointCloud<pcl::PointXYZ>::Ptr& target,
pcl::PointCloud<pcl::PointXYZ>::Ptr& result)
{
boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("配准结果"));
int v1, v2;
viewer->createViewPort(0, 0.0, 0.5, 1.0, v1); // 左侧视图
viewer->createViewPort(0.5, 0.0, 1.0, 1.0, v2); // 右侧视图
// 添加点云到视图中
pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> src_h(source, 0, 255, 0); // 源点云绿色
pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> tgt_h(target, 255, 0, 0); // 目标点云红色
pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> result_h(result, 0, 0, 255); // 配准后点云蓝色
viewer->addPointCloud(source, src_h, "source cloud", v1); // 左侧显示源点云
viewer->addPointCloud(target, tgt_h, "target cloud", v1); // 左侧显示目标点云
viewer->addPointCloud(result, result_h, "result cloud", v2); // 右侧显示配准后点云
while (!viewer->wasStopped())
{
viewer->spinOnce(100);
boost::this_thread::sleep(boost::posix_time::microseconds(10000));
}
}
int main(int argc, char* argv[])
{
pcl::PointCloud<pcl::PointXYZ>::Ptr source_cloud(new pcl::PointCloud<pcl::PointXYZ>);
pcl::PointCloud<pcl::PointXYZ>::Ptr target_cloud(new pcl::PointCloud<pcl::PointXYZ>);
pcl::PointCloud<pcl::PointXYZ>::Ptr icp_cloud(new pcl::PointCloud<pcl::PointXYZ>);
int iterations = 35;
pcl::console::TicToc time;
time.tic();
pcl::io::loadPCDFile("1.pcd", *source_cloud); // 加载源点云
pcl::io::loadPCDFile("2.pcd", *target_cloud); // 加载目标点云
Eigen::Matrix4d transformation_matrix = Eigen::Matrix4d::Identity(); // 变换矩阵
// 标准ICP实现
perform_standard_icp(source_cloud, target_cloud, icp_cloud, transformation_matrix, iterations);
// Trimmed ICP实现
perform_trimmed_icp(source_cloud, target_cloud, icp_cloud, transformation_matrix);
// 可视化
visualize_registration(source_cloud, target_cloud, icp_cloud);
return 0;
}