PCL 点云骨架提取和节点分类:叶尖、内部节点、交叉节点
#include
int main() { // 输入文件路径 std::string input_file = "D:\DIANYUNWENJIANJIA\kruskal_ply.ply";
// 加载点云数据
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
if (pcl::io::loadPLYFile(input_file, *cloud) == -1) {
std::cerr << "Failed to load input file!" << std::endl;
return -1;
}
// 手动计算法线
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);
// 设置计算法线的K值
int k = 10;
// 遍历每个点,计算其法线
for (size_t i = 0; i < cloud->size(); i++) {
pcl::Normal normal;
std::vector<int> k_indices(k);
std::vector<float> k_distances(k);
tree->nearestKSearch(cloud->points[i], k, k_indices, k_distances);
// 计算协方差矩阵
Eigen::Matrix3f covariance_matrix;
Eigen::Vector4f centroid;
pcl::computeMeanAndCovarianceMatrix(*cloud, k_indices, covariance_matrix, centroid);
// 使用特征值分解计算法线
Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f> eigen_solver(covariance_matrix, Eigen::ComputeEigenvectors);
Eigen::Vector3f normal_vector = eigen_solver.eigenvectors().col(0);
normal.normal_x = normal_vector[0];
normal.normal_y = normal_vector[1];
normal.normal_z = normal_vector[2];
normals->push_back(normal);
}
// 阈值α
float alpha = 3.0;
// 骨架修减和节点分类
pcl::PointCloud<pcl::PointXYZ>::Ptr skeleton(new pcl::PointCloud<pcl::PointXYZ>);
std::vector<int> labels(cloud->size(), -1);
for (size_t i = 0; i < cloud->size(); i++) {
int neighbor_count = 0;
std::vector<int> k_indices(5);
std::vector<float> k_distances(5);
tree->nearestKSearch(cloud->points[i], 5, k_indices, k_distances);
for (int j = 0; j < k_indices.size(); j++) {
int neighbor_index = k_indices[j];
if (cloud->points[i].y < cloud->points[neighbor_index].y) {
neighbor_count++;
}
}
if (neighbor_count < alpha) {
labels[i] = 3; // 丢弃的分支
}
else if (neighbor_count == 1) {
labels[i] = 0; // 叶尖
}
else if (neighbor_count == 2) {
labels[i] = 1; // 内部节点
}
else if (neighbor_count >= 3) {
labels[i] = 2; // 结点
skeleton->push_back(cloud->points[i]);
}
}
// 保存输出点云数据
std::string output_file = "D:\\DIANYUNWENJIANJIA\\gujiaxiujianhejiedianfenlei_ply.ply";
pcl::PointCloud<pcl::PointXYZRGB> colored_cloud;
colored_cloud.width = cloud->size();
colored_cloud.height = 1;
colored_cloud.is_dense = false;
colored_cloud.points.resize(colored_cloud.width * colored_cloud.height);
for (size_t i = 0; i < colored_cloud.points.size(); i++) {
colored_cloud.points[i].x = cloud->points[i].x;
colored_cloud.points[i].y = cloud->points[i].y;
colored_cloud.points[i].z = cloud->points[i].z;
if (labels[i] == 0) {
colored_cloud.points[i].r = 255;
colored_cloud.points[i].g = 0;
colored_cloud.points[i].b = 0;
}
else if (labels[i] == 1) {
colored_cloud.points[i].r = 255;
colored_cloud.points[i].g = 255;
colored_cloud.points[i].b = 255;
}
else if (labels[i] == 2) {
colored_cloud.points[i].r = 0;
colored_cloud.points[i].g = 255;
colored_cloud.points[i].b = 0;
}
else if (labels[i] == 3) {
colored_cloud.points[i].r = 0;
colored_cloud.points[i].g = 0;
colored_cloud.points[i].b = 255;
}
}
pcl::io::savePLYFile(output_file, colored_cloud);
// 可视化点云数据
pcl::visualization::PCLVisualizer viewer("Point Cloud Viewer");
viewer.setBackgroundColor(0, 0, 0);
viewer.addPointCloud<pcl::PointXYZRGB>(colored_cloud.makeShared(), "colored_cloud");
viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "colored_cloud");
viewer.spin();
// 输出信息
std::cout << "骨架修减和节点分类已完成,结果保存在文件:" << output_file << std::endl;
return 0;
原文地址: http://www.cveoy.top/t/topic/pFqh 著作权归作者所有。请勿转载和采集!