PCL专栏目录及须知-优快云博客
1.原理
以表面法线为基准进行聚类:
即对点云中所有点云点的表面法线进行聚类,将每个聚类之后的表面法线所对应的中心点作为该邻域半径中的下采样的样本点,以实现抽稀的效果。
(1)计算点云中所有点云点的表面法线。
(2)建KD树。
(3)对每个点云点进行邻域搜索,邻域半径内搜索到的点云点获取其表面法线,进行聚类。
(4)将聚类得出的表面法线,取其所对应的的点云点作为该邻域半径内的特征点,保留。
(5)依次遍历所有点云点,得到抽稀后的结果点云。
如下图:
即对下图中的所有表面法线(蓝色的线)进行聚类,得到特征点;而不是对点云点进行聚类得到特征点。
2.使用场景
抽稀:本方法的优势在于,可以在抽稀的同时,保留点云法线这一重要的点云特征(按照表面法线聚类之后的值作为特征点进行抽稀,点数减少了,但其关键法线向量不会变)
3.注意事项
如果法向量生成错误,那么使用该代码时会报错(不像有些PCL使用法向量的方法,就算法向量生成错误,也只是跳过这个NAN点,不做计算,不会有报错)。因此要保证法向量生成正确。
4.关键函数
(1)这个值越小结果点云越稀疏,这个值越大结果点云越密集。
setRatio()
(2)设置随机数种子点;设置这个值可以让点云每次计算出的结果相同。
setSeed()
5.代码
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
#include <pcl/filters/sampling_surface_normal.h>
#include <boost/thread/thread.hpp>
#include <pcl/features/normal_3d_omp.h>
#include <pcl/filters/normal_space.h>
#include <pcl/visualization/pcl_visualizer.h>
int main()
{
/****************表面法线采样滤波********************/
pcl::PointCloud <pcl::PointNormal>::Ptr cloud(new pcl::PointCloud <pcl::PointNormal>());
pcl::PointCloud <pcl::PointNormal>::Ptr cloud_filtered(new pcl::PointCloud <pcl::PointNormal>());
for (double i = 0; i < 10; i += 0.1) // 创建二维平面点云
{
for (double j = 0; j < 10; j += 0.1)
{
pcl::PointNormal pt;
pt.x = i;
pt.y = j;
pt.z = 1;
cloud->points.push_back(pt);
}
}
cloud->width = 1;
cloud->height = uint32_t(cloud->points.size());
pcl::SamplingSurfaceNormal <pcl::PointNormal> filter;
filter.setInputCloud(cloud);
filter.setRatio(0.2f); // 设置每个网格中要采样点的比率,该值对结果影响较大;这个值越小结果点云越稀疏,这个值越大结果点云越密集
filter.setSeed(3); // 设置随机数种子点;设置该值之后,每次计算的的结果就一致了。
filter.filter(*cloud_filtered);
/****************展示********************/
boost::shared_ptr<pcl::visualization::PCLVisualizer> view_raw(new pcl::visualization::PCLVisualizer("raw"));
view_raw->addPointCloud<pcl::PointNormal>(cloud, "raw cloud");
view_raw->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "raw cloud");
boost::shared_ptr<pcl::visualization::PCLVisualizer> view_filtered(new pcl::visualization::PCLVisualizer("filter"));
view_filtered->addPointCloud<pcl::PointNormal>(cloud_filtered, "filtered cloud");
view_filtered->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "filtered cloud");
while (!view_raw->wasStopped())
{
view_raw->spinOnce(100);
boost::this_thread::sleep(boost::posix_time::microseconds(100000));
}
while (!view_filtered->wasStopped())
{
view_filtered->spinOnce(100);
boost::this_thread::sleep(boost::posix_time::microseconds(100000));
}
return 0;
}