点云边缘提取及可视化

点云素材:bunny.txt

#include <pcl/features/normal_3d.h>
#include <pcl/features/boundary.h>
#include <pcl/visualization/pcl_visualizer.h>

void CreateCloudFromTxt(const std::string& file_path,
                        pcl::PointCloud<pcl::PointXYZ>::Ptr cloud) {
    std::ifstream fin(file_path.c_str());
    std::string line;
    pcl::PointXYZ point;
    while (getline(fin, line)) {
        std::stringstream ss(line);
        ss >> point.x;
        ss >> point.y;
        ss >> point.z;
        cloud->push_back(point);
    }
    fin.close();
}

void EstimateNormal(const pcl::PointCloud<pcl::PointXYZ>::Ptr cloud,
                    pcl::PointCloud<pcl::Normal>::Ptr normals) {
  pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> normal_est;
  normal_est.setInputCloud(cloud);
  // normal_est.setRadiusSearch(0.05); // 设置为分辨率的10倍时效果较好,邻域半径太小,噪声较大,估计的法线容易出错,而太大则估计速度较慢
  normal_est.setKSearch(10); // 点云法向计算时,需要搜索的近邻点数目
  pcl::search::KdTree<pcl::PointXYZ>::Ptr kdtree(new pcl::search::KdTree<pcl::PointXYZ>);
  normal_est.setSearchMethod(kdtree); // 建立kdtree来进行近邻点集搜索
  normal_est.compute(*normals);
}

void EstimateBoundary(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud,
                      pcl::PointCloud<pcl::Normal>::Ptr normals,
                      pcl::PointCloud<pcl::Boundary>& boundaries) {
  pcl::BoundaryEstimation<pcl::PointXYZ, pcl::Normal, pcl::Boundary> boundary_est;
  boundary_est.setInputCloud(cloud);
  boundary_est.setInputNormals(normals); // 边界估计依赖于法线
  boundary_est.setKSearch(10); // 一般这里的数值越高,最终边界识别的精度越好
  // boundary_est.setRadiusSearch(0.1); // 设置为分辨率的10倍时效果较好,太小则内部的很多点就都当成边界点了
  boundary_est.setAngleThreshold(M_PI / 2); // 边界估计时的角度阈值,默认值为PI/2,可根据需要进行更改。
  pcl::search::KdTree<pcl::PointXYZ>::Ptr kdtree(new pcl::search::KdTree<pcl::PointXYZ>);
  boundary_est.setSearchMethod(kdtree);
  boundary_est.compute(boundaries);
}

void visualization(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud,
                   pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_boundary) {
  boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("Boundaries"));
 
  // 添加需要显示的点云数据
  viewer->addPointCloud<pcl::PointXYZ>(cloud, "bunny");

  pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> single_color(cloud, 255, 0, 0);
  viewer->addPointCloud<pcl::PointXYZ>(cloud_boundary, single_color, "boundaries");
  viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "boundaries");
 
  while (!viewer->wasStopped()) {
    viewer->spinOnce(100);
    boost::this_thread::sleep(boost::posix_time::microseconds(100000));
  }
}

int main(int argc, char**argv) {
  // 加载点云模型
  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
  CreateCloudFromTxt("/tmp/bunny.txt", cloud);
 
  // 计算法线
  pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>);
  EstimateNormal(cloud, normals);

  // 提取边缘
  pcl::PointCloud<pcl::Boundary> boundaries;
  EstimateBoundary(cloud, normals, boundaries);

  // 输出边界点的个数
  std::cout << "cloud size: " <<cloud->points.size() << std::endl;
  std::cout << "boundaries size: " <<boundaries.points.size() << std::endl;

  // 存储边界点云数据
  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_boundary(new pcl::PointCloud<pcl::PointXYZ>);
  for(size_t i = 0; i < cloud->points.size(); ++i) { 
    if(boundaries[i].boundary_point > 0) { 
      cloud_boundary->push_back(cloud->points[i]);
    }
  }

  // 可视化点云边缘
  visualization(cloud, cloud_boundary);
  
  return 0;
}

输出:

cloud size: 397
boundaries size: 397

可视化结果:

猜你喜欢

转载自blog.csdn.net/A_L_A_N/article/details/108059153
今日推荐