#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/search/kdtree.h>
#include <pcl/features/normal_3d.h>
#include <boost/thread.hpp> // For threading support
int main(int argc, char** argv)
{
// 创建点云对象指针
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>);
// 加载点云文件
if (pcl::io::loadPCDFile<pcl::PointXYZ>("D:/py code/3.pcd", *cloud) != 0)
{
return -1;
}
// 创建法线估计对象
pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> normalEstimation;
normalEstimation.setInputCloud(cloud);
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>);
normalEstimation.setSearchMethod(tree);
normalEstimation.setKSearch(20);
normalEstimation.compute(*normals);
// 创建可视化对象
pcl::visualization::PCLVisualizer viewer("Cloud Viewer");
// 设置背景为黑色
viewer.setBackgroundColor(0, 0, 0);
// 添加点云
viewer.addPointCloud<pcl::PointXYZ>(cloud, "sample cloud");
//对于封闭的、已知的几何体,设置视点是确保法线方向一致的一个有效方法。在PCL中,可以使用NormalEstimation
的setViewPoint
方法设置视点,默认视点是在坐标原点(0,0,0),对于许多情况可能不适用。对于斯坦福兔子模型,应该设置视点在模型外部的某个位置
// 假设模型位于原点附近,可以将视点设置在Z轴的某个正值,设置包围盒中心例如(0, 0, 10) 确定法线向内还是向外
normalEstimation.setViewPoint(0.16, 0.16, 0.12);
// 输出法线数量
std::cout << "Number of normals calculated: " << normals->size() << std::endl;
//尽管设置视点通常足以确保法线的正确方向,但有时还需要对每个法线向量进行检查和调整。可以编写一个函数,检查每个法线与从模型中心指向该点的向量之间的点积。如果点积为负,则表明法线指向内部,需要反转。
Eigen::Vector4f centroid;
pcl::compute3DCentroid(*cloud, centroid);
for (size_t i = 0; i < normals->size(); ++i) {
Eigen::Vector3f point(cloud->points[i].x, cloud->points[i].y, cloud->points[i].z);
Eigen::Vector3f normal(normals->points[i].normal_x, normals->points[i].normal_y, normals->points[i].normal_z);
Eigen::Vector3f toPoint = point - centroid.head<3>();
// 检查法线方向
if (normal.dot(toPoint) < 0) {
normals->points[i].normal_x *= -1;
normals->points[i].normal_y *= -1;
normals->points[i].normal_z *= -1;
}
}
// 添加法线显示
viewer.addPointCloudNormals<pcl::PointXYZ, pcl::Normal>(cloud, normals, 50, 0.02, "normals");//参数 50
和 0.02
分别代表每50个点显示一个法线,每个法线的长度是0.02(这些参数可以根据需要调整以获得更好的视觉效果)
viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 0.0, 1.0, 0.0, "normals");
// 设置点云颜色为青色
viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "sample cloud");
viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 0, 1.0, 1.0, "sample cloud");
// 开启用户界面循环
while (!viewer.wasStopped())
{
viewer.spinOnce(100);
boost::this_thread::sleep(boost::posix_time::microseconds(100000));
}
return 0;
}
//结果如图