使用层次聚类的有组织点云的快速平面提取(续)

这是老师很久之前给的一篇paper,LZ还是有拖延症,到现在才想起来要把这篇paper的一些自己的思考或者说一些理解记录下来,如果有兴趣的,小伙伴可以看下原文“Fast Plane Extraction in Organized Point Clouds Using Agglomerative Hierarchical Clustering”。

1.使用的数据

按照原文的翻译是有组织的点云,其实这还是对于这个算法来说有所偏颇的,在代码使用的时候只使用了点云部分的深度信息,并不包含rgb的信息,只是在使用kinect的时候,PCL库直接是以点云的形式把数据保存下来的。

何为organized point cloud,这个在之前学习PCL的时候就说过,如果点云是可以以2D对3D点云进行索引的话,这就算是organized point cloud,在实际代码中表现在定义点云大小的时候直接定义点云的height和width,一般就是480和640,如果是unorganized point cloud,一般point cloud 的height定义为1,width就是整个点云数目,把kinect采集到的数据定义成unorganized的话,height = 1, width = 307200,这是没办法通过2D进行索引的,相当于把整个点云拉成一条,在数据利用上缺失了点与点之间的空间信息,不利于有些点云的特征的处理。

2.参数设置的问题

文章中有很多人工设置的参数,不同的参数对于后续的平面提取肯定是有影响的,而且对于程序运行的精度也会有所影响。原文中提到了几个阈值的设定也是偏向于经验值或者参考其他文献设定的。当然相机内参是肯定要的。。。

这里写图片描述

3.算法总体

具体的步骤可以参考上图流程

输入:深度相机获得的深度图像

step1:初始化

对于输入的深度图像进行初始化,先分成10*10大小的方块(尺寸是人为设定,可自行修改),每一块就相当于是图模型的一个node(注意node包含不只一个点)。如果出现下面四种情况,要把该节点和对应的边删除掉:

节点的均方误差高于设定阈值

节点含有缺失的数据

节点包含的深度不连续

节点在两个平面的边界

step2:层次聚类

未完待续。。。

点云平面识别是PCL库中的一个常见应用,可以通过以下步骤实现: 1. 读入点云数据,可以使用PCL的PointCloud类来处理点云数据。 2. 估计点云的法向量,可以使用PCL中的NormalEstimation类来估计点云的法向量。 3. 对点云进行分割,将点云分割成不同的平面,可以使用PCL中的SACSegmentation类来进行分割。 4. 对每个平面进行聚类,将点云分成不同的聚类,可以使用PCL中的EuclideanClusterExtraction类进行聚类。 5. 可以将每个聚类绘制出来,以便可视化结果。 下面是一个简单的示例代码,展示如何使用PCL库识别点云平面: ``` #include <pcl/point_types.h> #include <pcl/features/normal_3d.h> #include <pcl/segmentation/sac_segmentation.h> #include <pcl/filters/extract_indices.h> #include <pcl/kdtree/kdtree.h> #include <pcl/segmentation/extract_clusters.h> int main () { // 加载点云数据 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>); pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered (new pcl::PointCloud<pcl::PointXYZ>); pcl::io::loadPCDFile<pcl::PointXYZ> ("table_scene_lms400.pcd", *cloud); // 估计法向量 pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne; pcl::PointCloud<pcl::Normal>::Ptr normals (new pcl::PointCloud<pcl::Normal>); pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ>); tree->setInputCloud (cloud); ne.setInputCloud (cloud); ne.setSearchMethod (tree); ne.setRadiusSearch (0.03); ne.compute (*normals); // 分割平面 pcl::SACSegmentation<pcl::PointXYZ> seg; pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients); pcl::PointIndices::Ptr inliers (new pcl::PointIndices); seg.setOptimizeCoefficients (true); seg.setModelType (pcl::SACMODEL_PLANE); seg.setMethodType (pcl::SAC_RANSAC); seg.setDistanceThreshold (0.01); seg.setInputCloud (cloud); seg.setInputNormals (normals); seg.segment (*inliers, *coefficients); // 提取平面点云 pcl::ExtractIndices<pcl::PointXYZ> extract; extract.setInputCloud (cloud); extract.setIndices (inliers); extract.filter (*cloud_filtered); // 聚类 pcl::search::KdTree<pcl::PointXYZ>::Ptr ec_tree (new pcl::search::KdTree<pcl::PointXYZ>); ec_tree->setInputCloud (cloud_filtered); std::vector<pcl::PointIndices> cluster_indices; pcl::EuclideanClusterExtraction<pcl::PointXYZ> ec; ec.setClusterTolerance (0.02); ec.setMinClusterSize (100); ec.setMaxClusterSize (25000); ec.setSearchMethod (ec_tree); ec.setInputCloud (cloud_filtered); ec.extract (cluster_indices); // 输出结果 std::cout << "Number of clusters: " << cluster_indices.size () << std::endl; for (std::vector<pcl::PointIndices>::const_iterator it = cluster_indices.begin (); it != cluster_indices.end (); ++it) { pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_cluster (new pcl::PointCloud<pcl::PointXYZ>); for (std::vector<int>::const_iterator pit = it->indices.begin (); pit != it->indices.end (); ++pit) cloud_cluster->push_back ((*cloud_filtered)[*pit]); std::cout << "Cluster size: " << cloud_cluster->size () << std::endl; } return (0); } ``` 这个示例代码首先加载点云数据,然后使用NormalEstimation类估计点云的法向量。接着,使用SACSegmentation类分割点云提取平面点云。最后,使用EuclideanClusterExtraction类对平面点云进行聚类,并输出聚类结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值