PCL 欧式聚类提取点云并保存结果:代码分析及问题解决
#include <iostream> #include <pcl/io/ply_io.h> #include <pcl/io/pcd_io.h> #include <pcl/point_types.h> #include <pcl/kdtree/kdtree.h> #include <pcl/segmentation/extract_clusters.h> #include <pcl/visualization/pcl_visualizer.h> #include <boost/thread/thread.hpp> #include <pcl/segmentation/extract_clusters.h> #include <pcl/features/moment_of_inertia_estimation.h> #include <pcl/features/normal_3d.h> #include <pcl/features/boundary.h> "vtkAutoInit.h"
VTK_MODULE_INIT(vtkRenderingOpenGL); // VTK was built with vtkRenderingOpenGL2 typedef pcl::PointXYZRGB PointT; typedef pcl::PointCloud<PointT> PointCloud;
using namespace std; using namespace pcl; using PointT = pcl::PointXYZRGB;
int main(int argc, char** argv) { // -------------------------------------------加载点云--------------------------------------------- pcl::PointCloud<PointT>::Ptr cloud(new pcl::PointCloud<PointT>); if (pcl::io::loadPLYFile <PointT>("D:\DIANYUNWENJIANJIA\qiepianfenge_ply.ply", *cloud) == -1) { PCL_ERROR("Cloud reading failed."); return (-1); } cout << "检测到点云个数" << cloud->size() << endl; // -------------------------------------------欧式聚类-------------------------------------------- pcl::search::KdTree<PointT>::Ptr tree(new pcl::search::KdTree<PointT>); tree->setInputCloud(cloud); vector<pcl::PointIndices> cluster_indices; // 创建聚类索引的容器 pcl::EuclideanClusterExtraction<PointT> ec;// 欧式聚类对象 ec.setClusterTolerance(0.01); // 设置近邻搜索的搜索半径(也即两个不同聚类团点之间的最小欧氏距离) ec.setMinClusterSize(5); // 设置一个聚类需要的最少的点数目为4 ec.setMaxClusterSize(800); // 设置一个聚类需要的最大点数目为1000 ec.setSearchMethod(tree); // 设置点云的搜索机制 ec.setInputCloud(cloud); // 设置输入点云
ec.extract(cluster_indices); // 从点云中提取聚类,并将点云索引保存在cluster_indices中
//计算点云质心
pcl::PointCloud<PointT>::Ptr cluster_centroids(new pcl::PointCloud<PointT>);
for (std::vector<pcl::PointIndices>::const_iterator it = cluster_indices.begin(); it != cluster_indices.end(); ++it)
{
PointT centroid(0, 0, 0);
for (std::vector<int>::const_iterator pit = it->indices.begin(); pit != it->indices.end(); ++pit)
{
centroid.x += cloud->points[*pit].x;
centroid.y += cloud->points[*pit].y;
centroid.z += cloud->points[*pit].z;
}
centroid.x /= it->indices.size();
centroid.y /= it->indices.size();
centroid.z /= it->indices.size();
cluster_centroids->points.push_back(centroid);
}
cluster_centroids->width = cluster_centroids->points.size();
cluster_centroids->height = 1;
cluster_centroids->is_dense = true;
// Save the centroids point cloud to a PLY file
pcl::io::savePLYFile("D:\DIANYUNWENJIANJIA\newOUSHIJULEI_ply.ply", *cluster_centroids);
//------------------------------------保存聚类结果并可视化---------------------------------------
boost::shared_ptr<pcl::visualization::PCLVisualizer>viewer(new pcl::visualization::PCLVisualizer("planar segment"));
viewer->setBackgroundColor(0, 0, 0);
viewer->setWindowName("欧式聚类");
int begin = 0; //定义一个计数器,用来给保存的文件命名,从1开始
for (auto it = cluster_indices.begin(); it != cluster_indices.end(); ++it) //遍历每一个聚类,
{
pcl::PointCloud<PointT>::Ptr cloud_cluster(new pcl::PointCloud<PointT>); //创建一个新的点云指针用来存储每一个聚类
for (auto pit = it->indices.begin(); pit != it->indices.end(); pit++) //遍历当前聚类中的所有点的索引
{
cloud_cluster->push_back(cloud->points[*pit]); //通过尾加法将点加入到cloud——cluster新点云中
}
cout << "size" << begin + 1 << : << cloud_cluster->size() << endl;
// 检查cloud_cluster的大小,如果为空,则输出提示信息
if (cloud_cluster->size() == 0)
{
std::cout << "聚类后的点云数据为空,请检查聚类参数设置。" << std::endl;
continue; // 跳过当前循环,继续处理下一个聚类
}
Eigen::Vector4f centroid; //创建一个四维向量容器
pcl::compute3DCentroid(*cloud_cluster, centroid);
std::stringstream sa;
sa << "cluster_" << begin;
pcl::PointXYZ center_point(centroid(0), centroid(1), centroid(2)); //确定质心点
//viewer->addSphere(pcl::PointXYZ(centroid[0], centroid[1], centroid[2]), 0.0023, 1.0, 0.0, 0.0, sa.str());//可视化质心点
//std::cout << "Cluster " << begin + 1 << " Centroid: (" << centroid[0] << ", " << centroid[1] << ", " << centroid[2] << ")" << std::endl;
std::stringstream ss; //定义一个字符串流,用于生成保存的ply文件名
ss << "Euclidean_cluster_" << begin + 1 << ".ply"; //设置文件的名字
pcl::io::savePLYFile(ss.str(), *cloud_cluster); //将当前聚类保存为ply文件
cout << ss.str() << "保存完毕!!!" << endl;
begin++; //计数器+1用于给下一个文件命名
// 可视化相关的代码
uint8_t R = rand() % (256) + 0;
uint8_t G = rand() % (256) + 0;
uint8_t B = rand() % (256) + 0;
string str;
ss << str;
pcl::visualization::PointCloudColorHandlerCustom<PointT> color(cloud_cluster, R, G, B);
viewer->addPointCloud<PointT>(cloud_cluster, color, str);
viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, str);
}
while (!viewer->wasStopped())
{
viewer->spinOnce(100);
boost::this_thread::sleep(boost::posix_time::microseconds(100000));
}
return (0);
}
这段代码的可视化都是正确的,但是保存的点云文件,在其他代码里面打开是空的,该如何解决,使用cloudcompare也打不开,我想检查点云数据为空:在保存之前,请确保聚类后的点云数据cloud_cluster是非空的。你可以使用cloud_cluster->size()来检查点云的大小。如何操作内容:在保存之前,确保聚类后的点云数据cloud_cluster是非空的,可以使用cloud_cluster->size()来检查点云的大小。如果点云数据为空,可能是聚类参数设置不合适导致的。可以尝试调整聚类的参数,如聚类的距离阈值、最小和最大聚类点数等,以确保正确地提取到聚类。
另外,还可以使用调试打印语句输出相关变量的值,以帮助定位问题。例如,在保存之前可以输出cloud_cluster的大小,以确认其是否为空。可以添加以下代码进行调试:
cout << "cloud_cluster size: " << cloud_cluster->size() << endl;
如果cloud_cluster的大小为0,说明在聚类过程中可能存在问题,需要进一步调整聚类参数或检查数据是否正确。
原文地址: https://www.cveoy.top/t/topic/pLzJ 著作权归作者所有。请勿转载和采集!