在我们获得点云数据后,为了能够进行表面重建或者是进行物体的位姿确定,我们都需要确定物体表面的发现方向。
PCL中有现成的计算物体法线的类NormalEstimation,这个类做了以下3件事
1.得到p的最近邻
2.计算p的表面法线n
3.检查法线的朝向,然后拨乱反正。
默认的视角是(0,0,0)
计算一个点的法线
computePointNormal (const pcl::PointCloud<PointInT> &cloud, const std::vector<int> &indices, Eigen::Vector4f &plane_parameters, float &curvature);
前面两个参数很好理解,plane_parameters包含了4个参数,前面三个是法线的(nx,ny,nz)坐标,加上一个 nc .p_plane (centroid here) + p的坐标,然后最后一个参数是曲率。
#include <iostream>
#include <pcl/visualization/cloud_viewer.h>
#include<pcl/io/pcd_io.h>
#include<pcl/point_types.h>
#include <pcl/conversions.h>
#include <pcl/features/normal_3d.h>
#include <boost/thread/thread.hpp>
#include <pcl/common/common_headers.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/console/parse.h>
#include <pcl/filters/statistical_outlier_removal.h>
int main()
{
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_old(new pcl::PointCloud<pcl::PointXYZ>);
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_downsampled(new pcl::PointCloud<pcl::PointXYZ>);
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
pcl::io::loadPCDFile("test_pcd.pcd", *cloud_old);
//Use a voxelSampler to downsample
pcl::VoxelGrid<pcl::PointXYZ> voxelSampler;
voxelSampler.setInputCloud(cloud_old);
voxelSampler.setLeafSize(0.01f, 0.01f, 0.01f);
voxelSampler.filter(*cloud_downsampled);
//Use a filter to reduce noise
pcl::StatisticalOutlierRemoval<pcl::PointXYZ> statFilter;
statFilter.setInputCloud(cloud_downsampled);
statFilter.setMeanK(10);
statFilter.setStddevMulThresh(0.2);
statFilter.filter(*cloud);
// Create the normal estimation class, and pass the input dataset to it
pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;
ne.setInputCloud(cloud);
// Create an empty kdtree representation, and pass it to the normal estimation object.
// Its content will be filled inside the object, based on the given input dataset (as no other search surface is given).
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());
ne.setSearchMethod(tree);
// Output datasets
pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>);
// Use all neighbors in a sphere of radius 1cm
ne.setRadiusSearch(0.01);
// Compute the features
ne.compute(*normals);
boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("3D Viewer"));
viewer->setBackgroundColor(0, 0, 0);
viewer->addPointCloud<pcl::PointXYZ>(cloud, "sample cloud");
viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "sample cloud");
viewer->addPointCloudNormals<pcl::PointXYZ, pcl::Normal>(cloud, normals, 10, 0.2, "normals");
viewer->addCoordinateSystem(1.0);
viewer->initCameraParameters();
while (!viewer->wasStopped())
{
viewer->spinOnce(100);
boost::this_thread::sleep(boost::posix_time::microseconds(100000));
}
return 0;
}
但是第一次运行时出现了这样的问题,no ovverride found for vtkactor,解决这个问题其实很简单,首先加上#include <vtkAutoInit.h>
然后在mian的第一行加上VTK_MODULE_INIT(vtkRenderingOpenGL); 就没有问题了。