目录
一、概述
1.1原理
1.2实现步骤
1.3应用场景
二、代码实现
2.1关键函数
2.1.1 pcl::NormalEstimationOMP
2.1.2 pcl::NormalRefinement
2.1.3 visualizePointCloud
2.2完整代码
三、实现效果
PCL点云算法汇总及实战案例汇总的目录地址链接:
PCL点云算法与项目实战案例汇总(长期更新)
一、概述
法向量精细化处理不仅可以提高法向量的估计精度,还可以用于后续的点云处理和特征提取任务。通过对比初始法向量与精细化法向量的可视化效果,可以直观地看到处理的提升。
1.1原理
法向量估计基于最近邻点的协方差矩阵,通过计算法线的方向来描述点云表面的局部几何形状。为了进一步优化法向量结果,法向量精细化使用加权平均法调整法线方向,使其更平滑并更加贴合表面结构。法向量计算公式为:
1.2实现步骤
- 加载点云数据:从PCD文件中加载点云。
- 法向量计算:通过最近邻搜索为每个点计算法向量。
- 法向量精细化:对初始法向量进行平滑处理。
- 可视化:封装可视化函数,显示原始法向量与精细化后的法向量对比。
1.3应用场景
- 3D重建:提升法向量精度,增强3D模型的重建效果。
- 曲面光滑处理:通过精细化法向量来实现曲面平滑。
- 特征提取:在法向量基础上进行更精确的几何特征提取。
二、代码实现
2.1关键函数
2.1.1 pcl::NormalEstimationOMP
并行加速法向量估计函数,利用OpenMP进行并行计算。
pcl::NormalEstimationOMP<pcl::PointXYZ, pcl::Normal> ne;
ne.computePointNormal(*cloud, k_indices[i],normal.normal_x, normal.normal_y, normal.normal_z, normal.curvature);
2.1.2 pcl::NormalRefinement
法向量精细化处理函数,迭代调整法向量。
pcl::NormalRefinement<pcl::Normal> nr(k_indices, k_sqr_distances);
nr.setMaxIterations(50); // 设置最大迭代次数
nr.setConvergenceThreshold(0.1); // 设置收敛阈值
nr.filter(*normals_refined); // 进行法线精细化处理
2.1.3 visualizePointCloud
封装可视化函数,显示原始点云、法向量及精细化后的法向量。
void visualizePointCloud(pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud,pcl::PointCloud<pcl::Normal>::Ptr& normals,pcl::PointCloud<pcl::Normal>::Ptr& normals_refined)
{boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("Normal viewer"));int v1(0), v2(1);viewer->setWindowName("法向量精细化处理");viewer->createViewPort(0, 0.0, 0.5, 1.0, v1);viewer->createViewPort(0.5, 0.0, 1.0, 1.0, v2);viewer->setBackgroundColor(1.0, 1.0, 1.0, v1);viewer->setBackgroundColor(0.98, 0.98, 0.98, v2);pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> single_color(cloud, 0, 225, 0);viewer->addCoordinateSystem(0.1);viewer->addPointCloud<pcl::PointXYZ>(cloud, single_color, "sample cloud", v1);viewer->addPointCloudNormals<pcl::PointXYZ, pcl::Normal>(cloud, normals, 20, 0.02, "normals", v1);viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "sample cloud", v1);viewer->addPointCloud<pcl::PointXYZ>(cloud, single_color, "cloud", v2);viewer->addPointCloudNormals<pcl::PointXYZ, pcl::Normal>(cloud, normals_refined, 20, 0.02, "normals_refined", v2);viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "cloud", v2);while (!viewer->wasStopped()){viewer->spinOnce(100);boost::this_thread::sleep(boost::posix_time::microseconds(100000));}
}
2.2完整代码
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/kdtree/kdtree_flann.h>
#include <pcl/features/normal_3d_omp.h> // 使用OMP并行计算法向量
#include <pcl/filters/normal_refinement.h> // 法向量精细化处理
#include <pcl/visualization/pcl_visualizer.h>
#include <boost/thread/thread.hpp>// 封装的可视化函数
void visualizePointCloud(pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud,pcl::PointCloud<pcl::Normal>::Ptr& normals,pcl::PointCloud<pcl::Normal>::Ptr& normals_refined)
{boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("Normal viewer"));int v1(0), v2(1);viewer->setWindowName("法向量精细化处理");viewer->createViewPort(0, 0.0, 0.5, 1.0, v1);viewer->createViewPort(0.5, 0.0, 1.0, 1.0, v2);viewer->setBackgroundColor(0.0, 0.0, 0.0, v1);viewer->setBackgroundColor(0.08, 0.08, 0.08, v2);pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> single_color(cloud, 0, 225, 0);viewer->addCoordinateSystem(0.1);viewer->addPointCloud<pcl::PointXYZ>(cloud, single_color, "sample cloud", v1);viewer->addPointCloudNormals<pcl::PointXYZ, pcl::Normal>(cloud, normals, 20, 0.02, "normals", v1);viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "sample cloud", v1);viewer->addPointCloud<pcl::PointXYZ>(cloud, single_color, "cloud", v2);viewer->addPointCloudNormals<pcl::PointXYZ, pcl::Normal>(cloud, normals_refined, 20, 0.02, "normals_refined", v2);viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "cloud", v2);while (!viewer->wasStopped()){viewer->spinOnce(100);boost::this_thread::sleep(boost::posix_time::microseconds(100000));}
}int main()
{// ------------------------------加载点云数据---------------------------------pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);if (pcl::io::loadPCDFile<pcl::PointXYZ>("bunny.pcd", *cloud) == -1){PCL_ERROR("Could not read file\n");return -1;}const int k = 50; // K近邻点的个数std::vector<pcl::Indices> k_indices; // 近邻点的索引std::vector<std::vector<float>> k_sqr_distances; // 到近邻点的距离// ----------------------------构建邻域点索引---------------------------------pcl::search::KdTree<pcl::PointXYZ> search; // 初始化KD树的search方法search.setInputCloud(cloud); // 输入点云search.nearestKSearch(*cloud, pcl::Indices(), k, k_indices, k_sqr_distances); // 获取点云数据中每个点的K近邻// ------------------------------计算法线-------------------------------------pcl::NormalEstimationOMP<pcl::PointXYZ, pcl::Normal> ne;pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>);for (size_t i = 0; i < cloud->size(); ++i){pcl::Normal normal;ne.computePointNormal(*cloud, k_indices[i],normal.normal_x, normal.normal_y, normal.normal_z, normal.curvature);// 法线方向朝向视点pcl::flipNormalTowardsViewpoint((*cloud)[i], (*cloud).sensor_origin_[0], (*cloud).sensor_origin_[1], (*cloud).sensor_origin_[2],normal.normal_x, normal.normal_y, normal.normal_z);normals->push_back(normal);}// ------------------------------法线精细化处理------------------------------------pcl::PointCloud<pcl::Normal>::Ptr normals_refined(new pcl::PointCloud<pcl::Normal>);pcl::NormalRefinement<pcl::Normal> nr(k_indices, k_sqr_distances); // 法线精细化处理nr.setInputCloud(normals); // 添加法向量nr.setMaxIterations(500); // 最大迭代次数nr.setConvergenceThreshold(0.01);// 收敛阈值nr.filter(*normals_refined); // 进行法线精细化处理// 调用可视化函数visualizePointCloud(cloud, normals, normals_refined);return 0;
}