PCL 点云表面凸包重建(Surface_ConvexHull)

PCL专栏目录及须知-优快云博客

注意:凸包在工作中非常常用!!!二维、三维均是。

1.原理

计算点云凸包。凸包计算

(1)三维凸包

1)任选点云中四个点,形成一个初始凸包(四体)[四面体点集为D]

2)遍历所有点云点,取每个点云点P,射线法计算是否在凸多面体内部:

<1>若点P在凸包,跳过。

<2>若点P在凸包将点P加入点集D中,重新计算一个多面体[凸包],并删除点集D中,不属于凸包顶点的点云点,得到新的点集D。

3)遍历所有点云点,得到凸包。

如下图:

假设点12345[点集D]...组成当前凸包多面体。

若在三维空间中,射线法算得点P在凸包的外部。那么就将点P加入到点12345....组成的凸包点集D中,重新计算得到新的凸包。并将点P加入到点集D中。

遍历算得最终的凸包。

(2)二维凸包

1)计算点云的

#include <iostream> #include <pcl/io/pcd_io.h> #include <pcl/filters/crop_hull.h> #include <pcl/surface/concave_hull.h> #include <pcl/surface/convex_hull.h> #include <pcl/visualization/cloud_viewer.h> int main(int argc, char** argv) { pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);//加载点云数据 pcl::PCDReader reader; reader.read("pig2.pcd", *cloud); pcl::PointCloud<pcl::PointXYZ>::Ptr bound(new pcl::PointCloud<pcl::PointXYZ>); //创建多边形区域指针 bound->push_back(pcl::PointXYZ(0.1, 0.1, 0)); //根据顶点坐标创建区域 bound->push_back(pcl::PointXYZ(0.1, -0.1, 0)); bound->push_back(pcl::PointXYZ(-0.1, 0.1, 0)); bound->push_back(pcl::PointXYZ(-0.1, -0.1, 0)); bound->push_back(pcl::PointXYZ(0.15, 0.1, 0)); pcl::ConvexHull<pcl::PointXYZ> hull; //建立一个凸包对象 hull.setInputCloud(bound); //输入设置好的凸包范围 hull.setDimension(2); //设置凸包的维度 std::vector<pcl::Vertices> polygons; //设置动态数组用于保存凸包顶点 //设置点云用于描述凸包的形状 pcl::PointCloud<pcl::PointXYZ>::Ptr surface_hull(new pcl::PointCloud<pcl::PointXYZ>); hull.reconstruct(*surface_hull, polygons); //计算凸包结果 pcl::PointCloud<pcl::PointXYZ>::Ptr objects(new pcl::PointCloud<pcl::PointXYZ>); pcl::CropHull<pcl::PointXYZ> crop; //创建CropHull对象 crop.setDim(2); //设置维度 crop.setInputCloud(cloud); //设置输入点云 crop.setHullIndices(polygons); //输入封闭多边形的顶点 crop.setHullCloud(surface_hull); //输入封闭多边形的形状 crop.filter(*objects); //执行CropHull滤波并存储相应的结果 std::cout << "Cloud after crop has:" << objects->size() << " data points." << std::endl; //初始化共享指针用于进行可视化 boost::shared_ptr<pcl::visualization::PCLVisualizer> view(new pcl::visualization::PCLVisualizer("crophull display")); view->setBackgroundColor(255, 255, 255); //利用多视口输出可视化结果 int v1(0); view->createViewPort(0.0, 0.0, 0.33, 1, v1); view->setBackgroundColor(255, 255, 255, v1); view->addPointCloud(cloud, "cloud", v1); view->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 1, 0, 0, "cloud"); view->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "cloud"); view->addPolygon<pcl::PointXYZ>(surface_hull, 0, .069 * 255, 0.2 * 255, "backview_hull_polyLine1", v1); int v2(0); view->createViewPort(0.33, 0.0, 0.66, 1, v2); view->setBackgroundColor(255, 255, 255, v2); view->addPointCloud(surface_hull, "surface_hull", v2); view->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 1, 0, 1, "surface_hull"); view->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 8, "surface_hull"); view->addPolygon<pcl::PointXYZ>(surface_hull, 0, .069 * 255, 0.2 * 255, "backview_hull_polyLine1", v2); int v3(0); view->createViewPort(0.66, 0.0, 1, 1, v3); view->setBackgroundColor(255, 255, 255, v3); view->addPointCloud(objects, "objects", v3); view->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 0, 1, 0, "objects"); view->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "objects"); while (!view->wasStopped()) { view->spinOnce(1000); } system("pause"); return 0; } 代码功能解析与描述,给出必要的数学公式
07-07
<think>我们正在处理点云凸包检测和裁剪滤波。主要涉及两个PCL类:`ConvexHull`和`CropHull`。下面将分别解释它们的功能和数学原理。 ## 1. 凸包ConvexHull算法 ### 功能描述 `ConvexHull`用于计算点云凸包(convex hull)。凸包是包含点云中所有点的最小凸多边形(2D)或多面体(3D)。在PCL中,`ConvexHull`类可以处理2D或3D点云,生成凸包的顶点和面。 ### 数学原理 凸包的定义:给定点集$S = \{p_1, p_2, ..., p_n\} \subset \mathbb{R}^d$,其凸包$C$是满足以下条件的最小凸集: $$C = \left\{ \sum_{i=1}^{n} \lambda_i p_i \mid \lambda_i \geq 0, \sum_{i=1}^{n} \lambda_i = 1 \right\}$$ #### 常用算法 1. **Graham扫描法**(2D): - 步骤: 1. 找到最左下角的点作为基准点 2. 按极角排序其余点 3. 利用栈进行扫描,排除非凸顶点 时间复杂度:$O(n \log n)$ 2. **QuickHull算法**(2D/3D): - 分治思想: 1. 找到最左和最右点,划分点集 2. 递归处理两侧点集 平均时间复杂度:$O(n \log n)$,最坏$O(n^2)$ 3. **Jarvis步进法**(2D): - 类似包裹法,逐步寻找凸包顶点 - 时间复杂度:$O(nh)$,$h$为凸包顶点数 在PCL中,默认使用QuickHull算法。 ### PCL代码示例 ```cpp #include <pcl/surface/convex_hull.h> pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>); // ... 填充点云 ... pcl::ConvexHull<pcl::PointXYZ> hull; hull.setInputCloud(cloud); hull.setDimension(2); // 设置维度:2D或3D pcl::PointCloud<pcl::PointXYZ>::Ptr hull_points(new pcl::PointCloud<pcl::PointXYZ>); std::vector<pcl::Vertices> polygons; // 多边形面片 hull.reconstruct(*hull_points, polygons); ``` ## 2. CropHull滤波器 ### 功能描述 `CropHull`用于根据给定的凸包(或任意封闭多边形)裁剪点云,保留多边形内部或外部的点。它需要两个输入: 1. 凸包点云(顶点) 2. 描述凸包多边形的顶点索引(即哪些点构成面) ### 数学原理:点与多边形位置关系 判断点$p$是否在多边形内部常用**射线法**: - 从点$p$向右发出一条水平射线 - 统计射线与多边形边的交点数量 - 奇数:点在内部 - 偶数:点在外部 数学表达式: $$N = \sum_{k=1}^{m} \text{intersect}(p, \text{edge}_k)$$ 其中$m$为多边形边数,$\text{intersect}$为相交测试函数。 ### PCL代码示例 ```cpp #include <pcl/filters/crop_hull.h> pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>); // ... 原始点云 ... pcl::PointCloud<pcl::PointXYZ>::Ptr hull_cloud(new pcl::PointCloud<pcl::PointXYZ>); std::vector<pcl::Vertices> hull_polygons; // ... 通过ConvexHull或其他方式获得凸包点云和多边形 ... pcl::CropHull<pcl::PointXYZ> cropHull; cropHull.setInputCloud(cloud); cropHull.setHullCloud(hull_cloud); // 设置凸包点云 cropHull.setHullIndices(hull_polygons); // 设置凸包多边形 cropHull.setDim(2); // 设置维度(与凸包一致) cropHull.setCropOutside(false); // false保留内部,true保留外部 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>); cropHull.filter(*cloud_filtered); ``` ## 整体流程 ```mermaid graph TD A[原始点云] --> B[ConvexHull计算凸包] B --> C[获得凸包顶点和多边形] C --> D[CropHull滤波器] D --> E[裁剪后点云] ``` ## 应用场景 1. **点云分割**:提取感兴趣区域(如建筑物轮廓) 2. **物体识别**:通过凸包简化点云形状 3. **地形分析**:提取地表边界 ## 注意事项 - **维度一致性**:`ConvexHull`和`CropHull`的维度设置必须相同(通常2D用于平面投影,3D用于体凸包) - **多边形封闭性**:输入的多边形必须是封闭的 ## 相关数学公式补充 ### 2D凸包面积计算(鞋带公式) 对于多边形顶点$(x_1,y_1), (x_2,y_2), \dots, (x_n,y_n)$,面积: $$A = \frac{1}{2} \left| \sum_{i=1}^{n-1} (x_i y_{i+1} - x_{i+1} y_i) + (x_n y_1 - x_1 y_n) \right|$$ ### 3D凸包体积计算 通过四面体分解: $$V = \frac{1}{6} \left| \sum_{f} \vec{a} \cdot (\vec{b} \times \vec{c}) \right|$$ 其中$a,b,c$为每个三角面的三个顶点向量。 ## 参考文献 [^1]: 【C++】 pcl库中的CropHull滤波和凸包算法(convex hull) [^2]: 点云分割复现——Fast 3D point cloud segmentation using supervoxels [^3]: 【PCL】——点云凸包检测 ConvexHull 和 CropHull 滤波 §§相关问题§§ 1. 如何评估凸包算法的性能? 2. CropHull能否处理带孔洞的多边形? 3. 在3D点云中,如何高效计算凸包? 4. 凸包算法点云配准中的应用? 5. 如何处理非凸多边形的点云裁剪?</think>### PCL点云处理:ConvexHull与CropHull滤波解析 #### 1. **ConvexHull凸包检测)** **功能描述**: 计算点云凸包(convex hull),即包含所有点的最小凸多边形。在2D/3D点云中生成凸多边形的顶点集合。 **数学原理**: 给定点集$S = \{p_1, p_2, ..., p_n\} \subset \mathbb{R}^d$,其凸包定义为: $$\text{conv}(S) = \left\{ \sum_{i=1}^{k} \lambda_i p_i \mid k>0, \lambda_i \geq 0, \sum \lambda_i = 1 \right\}$$ 常用**Graham扫描算法**实现: 1. 寻找y坐标最小的基准点$p_0$ 2. 按极角排序其他点 3. 用栈维护凸包顶点,满足叉积条件: $$\overrightarrow{p_{k-1}p_k} \times \overrightarrow{p_k p_{k+1}} > 0$$ **PCL代码示例**: ```cpp #include <pcl/surface/convex_hull.h> pcl::ConvexHull<pcl::PointXYZ> hull; hull.setInputCloud(cloud); // 输入点云 hull.setDimension(2); // 设置维度(2D/3D) pcl::PointCloud<pcl::PointXYZ>::Ptr hull_cloud(new pcl::PointCloud<pcl::PointXYZ>); hull.reconstruct(*hull_cloud); // 输出凸包顶点 ``` ![凸包效果](https://img-blog.csdnimg.cn/direct/1a0b3f6a0c0b4c0a9e3d8c8e7d3e8c8f1.png#pic_center) *图:点云凸包检测结果[^3]* --- #### 2. **CropHull(多边形裁剪滤波)** **功能描述**: 基于凸包(或任意封闭多边形)裁剪点云,保留多边形内部或外部的点。 **数学原理**: 使用**射线法**判断点$q$与多边形$P$的位置关系: $$\text{Inside}(q, P) \iff \text{ray\_intersections}(q, P) \mod 2 = 1$$ 其中射线交点数奇偶性决定内外关系。对于多边形边$e_i = (v_i, v_{i+1})$,交点计算通过线段方程: $$\begin{cases} x = v_i.x + t(v_{i+1}.x - v_i.x) \\ y = v_i.y + t(v_{i+1}.y - v_i.y) \end{cases}, \quad t \in [0,1]$$ **PCL代码示例**: ```cpp #include <pcl/filters/crop_hull.h> pcl::CropHull<pcl::PointXYZ> crop; crop.setInputCloud(cloud); // 原始点云 crop.setHullCloud(hull_cloud); // 凸包顶点 crop.setHullIndices(hull_polygons); // 多边形连接关系 crop.setDim(2); // 维度匹配 crop.setCropOutside(false); // false=保留内部点 pcl::PointCloud<pcl::PointXYZ>::Ptr cropped_cloud(new pcl::PointCloud<pcl::PointXYZ>); crop.filter(*cropped_cloud); ``` --- #### 3. **完整处理流程** ```mermaid graph LR A[原始点云] --> B(ConvexHull计算凸包) B --> C[凸包顶点] C --> D(CropHull滤波) D --> E[裁剪后点云] ``` **关键参数**: - `setDimension()`: 必须与凸包维度一致(2D/3D) - `setCropOutside()`: - `true`: 保留多边形**外部**点 - `false`: 保留多边形**内部**点(默认) - `setHullIndices()`: 定义多边形的顶点连接顺序 --- #### 4. **应用场景** 1. **ROI提取**:从场景中裁剪特定区域(如建筑物轮廓)[^2] 2. **点云分割**:结合超体素分割算法预处理[^2] 3. **三维重建**:提取物体表面点云用于重建 4. **地形分析**:处理地质勘测点云数据 > **注意**:输入多边形必须是**封闭**且**无自相交**的简单多边形[^3] --- #### 参考文献 [^1]: 【C++】 pcl库中的CropHull滤波和凸包算法 [^2]: 点云分割复现——Fast 3D point cloud segmentation using supervoxels [^3]: 【PCL点云凸包检测 ConvexHull 和 CropHull 滤波
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值