参考:https://www.cnblogs.com/li-yao7758258/p/6479255.html 具体解析
https://blog.csdn.net/weixin_34375054/article/details/85797616
https://www.cnblogs.com/wellp/p/12053048.html 其他方法
官网的代码,用的以及参考链接里代码都一样。用table点云,可能由于数据量太大,运行过慢,迟迟显示不出来,但是从生成的cloud_normal.pcd文件来看,是OK哒。
用rabbit点云,但打开生成的带法线pcd,显示的均为nan,可能是因为pcd中缺少一些信息。confusing。
这是教程带的点云和rabbit点云,好像用其他的点云就不太能算出来。
这个代码我稍微在原本的基础上添加了一点点,主要添加了保存生成的法线pcd,以及将生成的法线添加到原本的点云中。
#include <pcl/io/io.h>
#include <pcl/io/pcd_io.h>
#include <pcl/features/integral_image_normal.h>
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/point_types.h>
#include <pcl/features/normal_3d.h>
#include <pcl/visualization/pcl_visualizer.h>
int
main (int argc, char** argv)
{
//加载点云
//pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
//pcl::io::loadPCDFile ("table_scene_lms400.pcd", *cloud);
std::string filename = argv[1];
std::cout << "Reading " << filename << std::endl;
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
if (pcl::io::loadPCDFile<pcl::PointXYZ>(filename, *cloud) == -1) // load the file
{
PCL_ERROR("Couldn't read file");
return -1;
}
std::cout << "points: " << cloud->points.size() << std::endl;
//估计法线
pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;
ne.setInputCloud (cloud);
//创建一个空的kdtree对象,并把它传递给法线估计对象
//基于给出的输入数据集,kdtree将被建立
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ> ());
ne.setSearchMethod (tree);
//输出数据集
pcl::PointCloud<pcl::Normal>::Ptr cloud_normals (new pcl::PointCloud<pcl::Normal>);
//使用半径在查询点周围3厘米范围内的所有邻元素
ne.setRadiusSearch (0.03);
//计算特征值
ne.compute (*cloud_normals);
pcl::io::savePCDFileASCII("cloud_normals.pcd", *cloud_normals);
// cloud_normals->points.size ()应该与input cloud_downsampled->points.size ()有相同尺寸
std::cout << "Normal calculated successfully !" << std::endl;
//法线可视化
pcl::visualization::PCLVisualizer viewer("PCL Viewer");
viewer.setBackgroundColor (0.5, 0.2, 0.7);
viewer.addPointCloudNormals<pcl::PointXYZ,pcl::Normal>(cloud, cloud_normals);
std::cout << "cloud_with_normals display!" << std::endl;
//将法线添加到点云,(另一种显示方法)保存添加法线后的点云到pcd文件
pcl::PointCloud<pcl::PointNormal>::Ptr cloud_with_normals(new pcl::PointCloud<pcl::PointNormal>);
pcl::concatenateFields(*cloud, *cloud_normals, *cloud_with_normals);
pcl::io::savePCDFileASCII("cloud_with_normals.pcd", *cloud_with_normals);
//viewer.addPointCloudNormals<pcl::PointNormal>(cloud_with_normals, 50, 0.01, "normals");
std::cout << "cloud_with_normals saved!" << std::endl;
while (!viewer.wasStopped ())
{
viewer.spinOnce ();
}
return 0;
}
利用积分图进行法线估计,只能用于有序点云的估计。
#include <pcl/io/io.h>
#include <pcl/io/pcd_io.h>
#include <pcl/features/integral_image_normal.h>
#include <pcl/visualization/cloud_viewer.h>
int
main ()
{
//加载点云
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
pcl::io::loadPCDFile ("table_scene_mug_stereo_textured.pcd", *cloud);
/**
三种法线估计方法
COVARIANCE_MATRIX 模式从具体某个点的局部邻域的协方差矩阵创建9个积分,来计算这个点的法线
AVERAGE_3D_GRADIENT 模式创建6个积分图来计算水平方向和垂直方向的平滑后的三维梯度并使用两个梯度间的向量
积计算法线
AVERAGE_DEPTH——CHANGE 模式只创建了一个单一的积分图,从而平局深度变化计算法线
**/
//估计法线
pcl::PointCloud<pcl::Normal>::Ptr normals (new pcl::PointCloud<pcl::Normal>);
pcl::IntegralImageNormalEstimation<pcl::PointXYZ, pcl::Normal> ne;
ne.setNormalEstimationMethod (ne.AVERAGE_3D_GRADIENT);
ne.setMaxDepthChangeFactor(0.02f);
ne.setNormalSmoothingSize(10.0f);
ne.setInputCloud(cloud);
ne.compute(*normals);
//法线可视化
pcl::visualization::PCLVisualizer viewer("PCL Viewer");
viewer.setBackgroundColor (0.0, 0.0, 0.5);
viewer.addPointCloudNormals<pcl::PointXYZ,pcl::Normal>(cloud, normals);
while (!viewer.wasStopped ())
{
viewer.spinOnce ();
}
return 0;
}