PCL专栏目录及须知
凹包计算多用在二维上,三维使用较少。
1.凹包计算
alpha-shape算法:
对任意的点云P,用一个半径为α的圆在点集P外滚动,当α足够大时,这个圆就不会滚到点集内部,其滚动的痕迹就是点集P的边界线。
(1)将点云投影到平面,得到二维点集P。
(2)定义一个圆(即滚球),圆半径为alpha。
(3)从点集P中任取种子点pi,计算pi同点集P内各点间的距离,并将所有与点pi间距离小于滚球直径alpha * 2的点加入点集Q(初始边界点)。
(4)从点集Q内任取种子点qi,生成同时过点pi及qi的,半径为alpha的两个外接圆Cpi,Cqi。
(5)判断两个外接圆Cpi,Cqi,若其中任意一个外接圆内,不存在点集P中的其他点(即pi及qi处在一个滚球内),那么连接pi及qi,作为凹包的其中一条边。
(6)对点集Q中所有点,依次进行(4)(5)步骤,直到所有点被处理。
(7)对点集P中所有点,依次进行(3)-(6)步骤,直到所有点被处理。
(8)得到所有连接的线条,组合成为凹包。
2.使用场景
凹包使用较少。使用多为凸包。
3.关键函数
(1)凹包设置凹包是2d的还是3d的
surface_3d.setDimension(3);
(2)滚球法的半径,值越小,生成的凹包越细分
surface_3d.setAlpha(0.5);
4.完整代码
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/surface/concave_hull.h>
#include <boost/thread/thread.hpp>
#include <pcl/visualization/pcl_visualizer.h>
int main()
{
/****************计算点云凹包********************/
// 原始点云
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in_3d(new pcl::PointCloud<pcl::PointXYZ>);
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in_2d(new pcl::PointCloud<pcl::PointXYZ>);
pcl::io::loadPCDFile("D:/code/csdn/data/rabbit.pcd", *cloud_in_3d); // 加载原始点云数据
pcl::io::loadPCDFile("D:/code/csdn/data/plane.pcd", *cloud_in_2d); // 加载原始点云数据
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_out_3d(new pcl::PointCloud<pcl::PointXYZ>); // 结果点云
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_out_2d(new pcl::PointCloud<pcl::PointXYZ>); // 结果点云
// 计算凹包(3d)
pcl::ConcaveHull<pcl::PointXYZ> surface_3d; // 3d凹包
surface_3d.setInputCloud(cloud_in_3d);
surface_3d.setDimension(3); // 凹包设置凹包是2d的还是3d的
surface_3d.setAlpha(0.5); // 值越小,生成的凹包越细分
std::vector<pcl::Vertices> polygons_3d; // 保存凹包顶点
surface_3d.reconstruct(*cloud_out_3d, polygons_3d); // 计算凹包
// 计算凹包(2d)
pcl::ConcaveHull<pcl::PointXYZ> surface_2d; // 2d凹包
surface_2d.setInputCloud(cloud_in_2d);
surface_2d.setDimension(2); // 凹包设置凹包是2d的还是3d的
surface_2d.setAlpha(true); // 值越小,生成的凹包越细分
std::vector<pcl::Vertices> polygons_2d; // 保存凹包顶点
surface_2d.reconstruct(*cloud_out_2d, polygons_2d); // 计算凹包
/****************展示********************/
// 3d
// 模型
boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer_3d(new pcl::visualization::PCLVisualizer("surface_3d"));
viewer_3d->setBackgroundColor(0, 0, 0);
viewer_3d->addPointCloud<pcl::PointXYZ>(cloud_in_3d, "cloud_3d");
viewer_3d->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "cloud_3d");
// 3d凹包
viewer_3d->addPolygonMesh<pcl::PointXYZ>(cloud_out_3d, polygons_3d, "polygons_3d");
viewer_3d->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 1, 0, 0, "polygons_3d");
viewer_3d->setRepresentationToWireframeForAllActors();
// 2d
// 模型
boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer_2d(new pcl::visualization::PCLVisualizer("surface_2d"));
viewer_2d->setBackgroundColor(0, 0, 0);
viewer_2d->addPointCloud<pcl::PointXYZ>(cloud_in_2d, "cloud_2d");
viewer_2d->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "cloud_2d");
// 2d凹包
viewer_2d->addPolygonMesh<pcl::PointXYZ>(cloud_out_2d, polygons_2d, "polygons_2d");
viewer_2d->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 1, 0, 0, "polygons_2d");
viewer_2d->setRepresentationToWireframeForAllActors();
while (!viewer_2d->wasStopped() || !viewer_3d->wasStopped())
{
viewer_2d->spinOnce(1000);
viewer_3d->spinOnce(1000);
boost::this_thread::sleep(boost::posix_time::microseconds(1000));
}
return 0;
}
5.结果展示
三维凹包
二维凹包