0. 简介
之前作者专门为点云匹配写了几篇博客,但是我们发现最近几年有更多的新方法已经在不断地被使用。
同时之前有些内容也没有很好的概括,所以这里我们将作为一篇进阶文章来介绍这些方法的使用。
1. 地面点去除
处了使用一些复杂的方法(fec)或是一些简单的方法(根据高度来滤除)以外,还可以使用ransac的方法完成平面拟合
#include #include #include #include #include void removepointsunderground(const pcl::pointcloud& cloud_in, pcl::pointcloud& cloud_out){ // 对输入点云进行降采样 pcl::pointcloud::ptr cloud_downsampled(new pcl::pointcloud); pcl::voxelgrid voxel_grid; voxel_grid.setinputcloud(cloud_in.makeshared()); voxel_grid.setleafsize(0.1f, 0.1f, 0.1f); // 设置体素格大小 voxel_grid.filter(*cloud_downsampled); // 创建一个滤波器对象,用于提取地面平面 pcl::pointcloud::ptr cloud_filtered(new pcl::pointcloud); pcl::passthrough pass_through; pass_through.setinputcloud(cloud_downsampled); pass_through.setfilterfieldname(z); // 对z轴进行滤波 pass_through.setfilterlimits(-1.5, 0.5); // 设置滤波范围,过滤掉z轴在-1.5到0.5之间的点 pass_through.filter(*cloud_filtered); // 创建一个分割对象,用于提取地面平面 pcl::modelcoefficients::ptr coefficients(new pcl::modelcoefficients); pcl::pointindices::ptr inliers(new pcl::pointindices); pcl::sacsegmentation segmentation; segmentation.setinputcloud(cloud_filtered); segmentation.setmodeltype(pcl::sacmodel_plane); segmentation.setmethodtype(pcl::sac_ransac); segmentation.setdistancethreshold(0.1); // 设置距离阈值,点到平面的距离小于该阈值的点将被认为是地面点 segmentation.segment(*inliers, *coefficients); // 创建一个提取对象,用于提取地面点 pcl::pointcloud::ptr cloud_ground(new pcl::pointcloud); pcl::extractindices extract; extract.setinputcloud(cloud_filtered); extract.setindices(inliers); extract.setnegative(false); // 提取地面点,即保留inliers对应的点 extract.filter(*cloud_ground); // 创建一个提取对象,用于提取非地面点 pcl::pointcloud::ptr cloud_non_ground(new pcl::pointcloud); extract.setnegative(true); // 提取非地面点,即去除inliers对应的点 extract.filter(*cloud_non_ground); // 将结果保存到输出点云中 cloud_out = *cloud_non_ground;}
2. pca主成分判别
除了去除点云以外,还可以通过主成分判别来判断我们分割的是否是地面。其中eigenvectors()函数得到的矩阵中的三个列向量分别对应于数据的主成分轴。
这些主成分轴是按照数据方差的降序排列的,即第一个列向量对应的是数据的第一主成分轴,第二个列向量对应的是数据的第二主成分轴,第三个列向量对应的是数据的第三主成分轴。对于pca的特征值和特征向量可以从这里理解:
https://blog.csdn.net/lazysnake666/article/details/122404671
#include #include #include #include bool estimateplane(const pcl::pointcloud& cloud){ // 将输入点云数据转换为pcl点云格式 for (const auto& point : cloud) { pcl::pointxyz pclpoint; pclpoint.x = point.x(); pclpoint.y = point.y(); pclpoint.z = point.z(); cloud->push_back(pclpoint); } // 创建pca对象 pcl::pca pca; pca.setinputcloud(cloud); // 计算主成分 eigen::vector3f eigenvalues = pca.geteigenvalues(); eigen::matrix3f eigenvectors = pca.geteigenvectors(); // 获取地面法向量,因为最小的就是第三列,所以最后一列是地面(0,0,1),如果是墙面那就(x,1-x,0) eigen::vector3f groundnormal = eigenvectors.col(2);#eigen_vector.block(0, 2)//最小成分的主成分向量,对应的是地面的法线,因为地面xy都存在比较大的主成分 // 如果是其他的比如灯杆这种,一般的就会是fabs(eigen_vector.block(0, 0).dot(eigen::unitz()))的形式,也就是最大主成分,沿着最大主成分方向 bool is_ground = (fabs(groundnormal.dot( eigen::unitz())) > 0.98) && (eigenvalues(2) 10 * eigen_values(1) return is_ground;}
3. gicp配准
gicp配准这块在之前的博客经典论文阅读之-gicp(icp大一统)中已经详细讲过了,下面就是一个示例代码
意法半导体推出针对智能工业应用的高集成度、高灵活性的同步整流DC/DC转换器
Datalogic得利捷将携新品Memor 11系列移动终端亮相2023中国零售业博览会
自动驾驶浪潮袭来,汽车产业链面临重新洗牌
预训练语言模型设计的理论化认识
基于SOGI滤波器的单相锁频环仿真案例
点云滤波与匹配进阶干货收藏
东芝开始提供业内首批符合UFS 2.0的嵌入式NAND闪存模块的样品出货
Linux初始的RAM磁盘(initrd)的概述
新能源汽车的种类众多,他们的区别是什么
有驾无车人群正在扩大,互联网租车习惯正在养成
下游新能源汽车市场复苏带动上游锂盐市场需求增长
Haylou Smart Watch智能手表在小米有品商城开启众筹 首发价99.9元
开放、包容的MM32合作共赢平台——2019灵动MM32协作大会成功举办
温度容限监测系统
传感器市场稳步增长 20家国内企业抢食“大蛋糕”
华为的胜利,本质上美式制度和管理的胜利
Spring事务的传播行为与回滚机制
永续合约系统开发,场外OTC交易系统源码开发费用
Maxim推出完全集成的PMIC
产生EMI问题的2个原因