点云法线计算及可视化

点云素材:bunny.txt

#include <pcl/features/normal_3d.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); // 对于每一个点都用半径为5cm的近邻搜索方式
  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 visualization(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud,
                   pcl::PointCloud<pcl::Normal>::Ptr normals) {
  boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("Normals"));
  viewer->setBackgroundColor(0, 0, 0);
 
  //按照z值进行渲染点的颜色
	pcl::visualization::PointCloudColorHandlerGenericField<pcl::PointXYZ> fildColor(cloud, "x");
  // 添加需要显示的点云数据
  viewer->addPointCloud<pcl::PointXYZ>(cloud, fildColor, "bunny cloud");
  // viewer->addPointCloud<pcl::PointXYZ>(cloud, "bunny cloud");
 
  // 设置点显示大小
  viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "bunny cloud");
 
  // 添加需要显示的点云法向。cloud为原始点云模型,normal为法向信息,1表示需要显示法向的点云间隔,即每1个点显示一次法向,0.003表示法向长度。
  // viewer->addPointCloudNormals<pcl::PointXYZ, pcl::Normal>(cloud, normals, 1, 0.003, "normals");
 
  // Concatenate the XYZ and normal fields* 将点云数据与法向信息拼接
  pcl::PointCloud<pcl::PointNormal>::Ptr cloud_with_normals(new pcl::PointCloud<pcl::PointNormal>); // pcl::PointNormal, pcl::PointXYZINormal, pcl::PointXYZRGBNormal
  pcl::concatenateFields(*cloud, *normals, *cloud_with_normals);
  viewer->addPointCloudNormals<pcl::PointNormal>(cloud_with_normals, 1, 0.003, "normals");
 
  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);
  std::cout << "cloud size: " << cloud->size() << std::endl;
  std::cout << "normals size: " << normals->size() << std::endl;
 
  for (size_t i = 0; i < 5 && i < normals->size(); ++i) {
    std::cout << "[" << normals->points.at(i).normal_x << ", " // 法线各轴分量
                     << normals->points.at(i).normal_y << ", "
                     << normals->points.at(i).normal_z << ", "
                     << normals->points.at(i).curvature << "]" << std::endl; // 曲率
  }
 
  // 可视化点云及其法线
  visualization(cloud, normals);
 
  return 0;
}

输出:

 

可视化结果:

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
利用最小二乘拟合进行点云法线计算的步骤如下: 1. 数据预处理:首先,对点云数据进行预处理,包括滤波、去噪和下采样等操作。这有助于减少噪声和冗余信息的影响,提高法线计算的准确性。 2. 邻域搜索:对于每个点,确定其邻域内的点集。可以使用k最近邻搜索或半径搜索等方法来确定邻域。选择适当的邻域大小对法线计算非常重要。 3. 平面拟合:对于每个点,使用邻域中的点来拟合一个平面。可以采用最小二乘拟合方法来找到最优的平面参数。 - 计算平均值:计算邻域中所有点的坐标平均值作为平面的中心点。 - 构建协方差矩阵:计算邻域中所有点的协方差矩阵。 - 特征值分解:对协方差矩阵进行特征值分解,得到特征值和对应的特征向量。 - 选择最小特征值:选择特征值最小的特征向量作为法线方向。 4. 法线方向一致性:在估计法线后,可以通过检查邻域中估计的法线方向与当前点的法线方向的一致性来进行进一步的校正和调整。 5. 法线平滑:在某些情况下,对估计得到的法线进行平滑处理可以提高其准确性。这可以通过对邻域中的法线进行加权平均等方法来实现。 6. 可视化或应用:最后,可以将计算得到的法线用于可视化、形状分析、特征提取等任务中。 需要注意的是,最小二乘拟合方法是一种简单而常用的点云法线计算方法。具体的步骤和算法选择可能因应用场景和需求而有所不同。此外,点云数据质量、噪声水平和邻域选择等因素也会对法线计算结果产生影响,因此在实际应用中可能需要进行调试和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值