找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

3504

积分

0

好友

463

主题
发表于 昨天 08:17 | 查看: 7| 回复: 0

在计算几何领域,凸包(Convex Hull) 是一个基础且重要的概念。给定二维或三维空间中的点集,凸包是能够包含所有点的最小凸多边形(2D)或凸多面体(3D)。PCL 提供了 pcl::ConvexHull 类,借助 Qhull 库实现凸包计算,广泛应用于碰撞检测、形状分析、物体识别等场景。

1. 凸包

凸包的核心思想是用最小的凸多边形/凸多面体包围所有输入点。所谓“凸”是指:对于集合内的任意两点,连接它们的线段完全位于集合内部。

2D与3D凸包对比图:左侧展示二维点集的凸多边形轮廓,右侧展示三维点集的凸多面体结构

凸包具有以下特点:

  • 最小包围性:凸包是包含所有点的最小凸集;
  • 顶点子集:凸包的顶点是原始点集的子集;
  • 唯一性:给定点集的凸包是唯一的;
  • 维度依赖:2D凸包是多边形,3D凸包是多面体。

2. ConvexHull

pcl::ConvexHull 类用于实现凸包计算能力,分析源码可知,算法执行步骤如下:

  • 维度判断:当维度为默认值0时,会根据输入点云的维度自动判断是2D(共面)还是3D;建议主动设置维度
  • 数据准备:将点云数据转换为Qhull所需的坐标数组;
  • Qhull计算:调用Qhull库计算凸包;
  • 结果提取:提取凸包顶点和面片信息;
  • 面积体积:若启用,计算凸包的面积和体积。

2.1 接口

主要接口为:

//计算凸包(仅输出顶点)
//@param points 凸包顶点点云
void reconstruct(PointCloud &points);

//计算凸包(输出顶点和面片)
//@param points 凸包顶点点云
//@param polygons 凸包面片集合。2D凸包仅1个面片(凸多边形),3D凸包为多个三角面片,
//                每个面片的vertices存储顶点索引,用于描述凸包表面的拓扑结构
void reconstruct(PointCloud &points, std::vector<pcl::Vertices> &polygons);

//设置是否计算面积和体积
//@param value true表示计算面积和体积,false表示不计算
//注意:启用此选项时,Qhull会输出信息到控制台
void setComputeAreaVolume(bool value);

//获取凸包总面积
//@return 凸包面积(2D为多边形面积,3D为表面积)
double getTotalArea() const;

//获取凸包总体积
//@return 凸包体积(仅3D有效,2D返回0)
double getTotalVolume() const;

//设置输入数据维度
//@param dimension 维度,2表示2D,3表示3D
//若不设置,将自动判断
//仅支持2/3,其他将会报错
void setDimension(int dimension);

//获取输入数据维度
//@return 维度(2或3)
int getDimension() const;

//获取凸包顶点在原始点云中的索引
//@param hull_point_indices 凸包顶点索引
void getHullPointIndices(pcl::PointIndices &hull_point_indices) const;

在应用 ConvexHull 时,需要注意以下事项:

  • 输入点云:必须包含至少3个点,否则计算结果无意义;
  • 维度设置:虽然该函数可以自动进行维度判断,但是仍旧建议手动设置维度,以避免自动判断错误;当前仅支持2D和3D凸包计算。
  • 计算开销:凸包计算时间与点云规模成正比,对大规模点云需谨慎使用。

2.2 对比记忆

为了更清晰地理解 ConvexHull 的特点,将2D凸包与3D凸包进行全面对比:

对比维度 OpenCV凸包 2D凸包 3D凸包
输出形状 凸多边形 凸多边形 凸多面体
面片数量 1个(单个多边形) 1个(单个多边形) 多个(三角面片)
面积含义 轮廓面积 多边形面积 表面积
体积含义 不支持 0 实际体积
投影需求 不需要 需要(投影到XY/YZ/XZ平面) 不需要
输入类型 轮廓点(vector) 点云(PointCloud) 点云(PointCloud)
输出类型 顶点索引 点云+面片索引 点云+面片索引
底层算法 Sklansky算法 Qhull Qhull
应用场景 图像处理、轮廓分析、手势识别 平面轮廓提取 物体包围盒、碰撞检测

3. 代码示例

为了更直观地展示 ConvexHull 的使用方法,整理示例代码如下:

3.1 基本示例:3D凸包计算

#include <pcl/surface/convex_hull.h>
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>

int main(){
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in(new pcl::PointCloud<pcl::PointXYZ>);
    pcl::io::loadPCDFile("input.pcd", *cloud_in);

    pcl::ConvexHull<pcl::PointXYZ> chull;
    chull.setInputCloud(cloud_in);
    chull.setDimension(3);

    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_hull(new pcl::PointCloud<pcl::PointXYZ>);
    std::vector<pcl::Vertices> polygons;
    chull.reconstruct(*cloud_hull, polygons);

    std::cout << "Convex hull has " << cloud_hull->size() << " points" << std::endl;
    std::cout << "Convex hull has " << polygons.size() << " polygons" << std::endl;

    pcl::io::savePCDFile("hull.pcd", *cloud_hull);

    return 0;
}

3.2 进阶示例:计算凸包面积和体积

#include <pcl/surface/convex_hull.h>
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>

int main(){
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in(new pcl::PointCloud<pcl::PointXYZ>);
    pcl::io::loadPCDFile("input.pcd", *cloud_in);

    pcl::ConvexHull<pcl::PointXYZ> chull;
    chull.setInputCloud(cloud_in);
    chull.setDimension(3);
    chull.setComputeAreaVolume(true);

    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_hull(new pcl::PointCloud<pcl::PointXYZ>);
    chull.reconstruct(*cloud_hull);

    std::cout << "Convex hull area: " << chull.getTotalArea() << std::endl;
    std::cout << "Convex hull volume: " << chull.getTotalVolume() << std::endl;

    pcl::io::savePCDFile("hull.pcd", *cloud_hull);

    return 0;
}

3.3 高级示例:输出PolygonMesh格式

#include <pcl/surface/convex_hull.h>
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/io/vtk_io.h>

int main(){
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in(new pcl::PointCloud<pcl::PointXYZ>);
    pcl::io::loadPCDFile("input.pcd", *cloud_in);

    pcl::ConvexHull<pcl::PointXYZ> chull;
    chull.setInputCloud(cloud_in);
    chull.setDimension(3);

    pcl::PolygonMesh mesh;
    chull.reconstruct(mesh);

    std::cout << "Mesh has " << mesh.cloud.width * mesh.cloud.height << " points" << std::endl;
    std::cout << "Mesh has " << mesh.polygons.size() << " polygons" << std::endl;

    pcl::io::saveVTKFile("convex_hull.vtk", mesh);

    return 0;
}

4. 总结

本文重点介绍了 pcl::ConvexHull 类的核心原理、主要参数及使用方法。作为一种基础的计算几何算法,凸包在算法设计中占有重要地位。通过对比分析,展示了2D和3D凸包计算的区别,并提供了详细的C++代码示例,希望能帮助你在3D点云处理项目中更有效地应用该功能,实现精确的碰撞检测或物体识别。




上一篇:月薪8元的AI员工如何搭建?基于OpenClaw部署与大模型选择攻略
下一篇:BCPL语言详解:C语言诞生前,系统编程的基石与设计思想
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-2-25 09:10 , Processed in 0.591374 second(s), 43 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表