PCL MC移动立方体重建(HOPPE)(Surface_MarchingCubesHoppe)

PCL专栏目录及须知

移动立方体重建是一种体素级的重建方法,即通过

判断原始点云表面(等值面)与每个体素块顶点的相对位置,

查表计算得到与原始点云表面相交的各体素边及三角面片信息

线性插值修正交点,逼近等值面,

组合形成三角网格

主要应用于医学领域的可视化场景,例如CT扫描和MRI扫描的3D重建等。

1.Marching Squares(MC移动立方体重建的2D引入)

先以2D的该算法思想举例引入:

(1)待分割对象如下:

(2)对待分割对象二维栅格化。

(3)记录栅格化顶点相对位置信息,即哪些顶点在对象内部(红色),哪些在对象外部(蓝色)。

(4)计算多边形都穿过哪些栅格线。并以一内部对象(红色)及一外部对象(蓝色)的连线的中间位置(1/2处)作为记录值(紫色顶点)。

(5)排序并连接紫色点,得到原始表面的近似值(紫色线)。

(6)精确计算紫色点位置。即计算表面与存在紫色点的各边的详细交点,得到准确表面。

2.Marching cubes(MC移动立方体3D重建)

(1)体素化点云。得到由许多个小立方体组成的体素网格。

等值面的引入

指三维空间中具有相同数值的点构成的表面。即下文代码中iso_level的值。

(2)判断每个小体素块的各个顶点是否在原始点云内部(顶点只有内外两种可能性)。

比较等值面的值(iso_level)与小立方体8个顶点的数据值:

1)在原始点云表面内部:顶点数据值 高于或等于 等值面的值(iso_level)。

2)在原始点云表面外部:顶点数据值 低于 等值面的值(iso_level)。

(3)整理每个体素块的基本构型状态。

每个体素块由八个顶点组成,1个顶点内外一种状态,8个顶点则有2^8 = 256种状态。根据旋转、映射不变等特性,将体素256种状态归纳为一下15种基本构型:

(4)根据顶点状态设置“边查找表”及“三角形查找表”。

边查找表:edgeTable查找表。例如,0x80c=1000 0000 1100,意味着体素单元的边11、3、2和等值面相交。

三角形查找表:triTable。用于生成对应三角面片的组成情况。

(5)遍历计算每个体素块与原始点云相交的状态。

1)通过边查找表判断等值面和体素单元哪一条边相交

以如下情况为例:

<1>假如某体素块,仅下方的顶点3的值小于等值面值,其他顶点上的值都大于等值面值,即顶点3标记为1、其他顶点标记为0。

<2>用进制表示该体素块的体素顶点状态,二进制的0000 1000或者十进制的8。

<3>查找“边查找表”,即edgeTable[8] =0x80c=1000 0000 1100,得到体素单元的边11、3、2和等值面相交。

2)通过triTable表生成对应三角面片的组成情况

仍以上方情况为例:

triTable查找表得到triTable[8] = {3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}。即该顶点状态可以生成三角面,该三角面的3个顶点为边3、11、2等值面相交的交点。

(7)线性插值计算各交点的位置。

已知各条可与原始点云相交的体素块的边,通过线性插值,计算每个交点在该体素边的位置。

(8)遍历所有体素块,得到最终结果。

3.Hoppe法改进

在点云表面重建中,无法像3D医学图像那样直接获取Cube顶点的数据值,Hoppe等人使用Cube顶点到点云的有符号距离(signed distance function)来表示该数据值。 

(1)iso_level一般设置为0。

(2)计算Cube顶点到点云的有符号距离。

首先找到距离Cube顶点最近的数据点n,然后计算Cube顶点到表面在点n处的切平面的距离。实际是计算Cube顶点到点n的向量与切平面法向量的点乘,计算结果保留符号。

(3)使用MC方法确定三角面。 

4.使用场景

三维点云重建

5.关键函数

(1)等值面的值iso_level

segmentation->setIsoLevel(0.0f);

(2)移动立方体网格分辨率

segmentation->setGridResolution(50, 50, 50);

(3)定义在点云的边框和网格限制之间的网格内应该保留多少自由空间,不影响网格的分辨率,只是相应地改变体素大小。

segmentation->setPercentageExtendGrid(0.0f);

6.完整代码

#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/io/ply_io.h>
#include <pcl/point_types.h>
#include <pcl/kdtree/kdtree_flann.h>
#include <pcl/features/normal_3d.h>
#include <pcl/surface/marching_cubes_HOPPE.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <boost/thread/thread.hpp>

int main()
{
	/****************HOPPE移动立方体重建********************/
	pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGB>);				// 源点云
	pcl::io::loadPCDFile("D:/code/csdn/data/bunny2.pcd", *cloud);

	// 计算法线
	pcl::NormalEstimation<pcl::PointXYZRGB, pcl::Normal> n;
	pcl::search::KdTree<pcl::PointXYZRGB>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZRGB>);
	n.setInputCloud(cloud);
	n.setSearchMethod(tree);
	n.setKSearch(20);                                                                                   // k邻域搜索范围
	pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>);
	n.compute(*normals);

	pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr cloudNormals(new pcl::PointCloud<pcl::PointXYZRGBNormal>);         // 连接点云及法向量
	pcl::concatenateFields(*cloud, *normals, *cloudNormals);

	// HOPPE移动立方体重建
	pcl::MarchingCubes<pcl::PointXYZRGBNormal>::Ptr segmentation(new pcl::MarchingCubesHoppe<pcl::PointXYZRGBNormal>);
	pcl::search::KdTree<pcl::PointXYZRGBNormal>::Ptr tree2(new pcl::search::KdTree<pcl::PointXYZRGBNormal>);
	tree2->setInputCloud(cloudNormals);
	segmentation->setInputCloud(cloudNormals);
	segmentation->setIsoLevel(0.0f);													// 等值面的iso_level
	segmentation->setGridResolution(50, 50, 50);										// 移动立方体网格分辨率
	segmentation->setPercentageExtendGrid(0.0f);										// 定义在点云的边框和网格限制之间的网格内应该保留多少自由空间,不影响网格的分辨率,只是相应地改变体素大小。
	pcl::PolygonMesh triangles;                                                         // 存储最终三角化的网格模型
	segmentation->reconstruct(triangles);

	pcl::io::savePLYFile("D:/code/csdn/data/bunny5.ply", triangles);

	/****************展示********************/
	boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("GridProjection"));
	viewer->addPointCloud(cloud, "cloud");
	boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer0(new pcl::visualization::PCLVisualizer("GridProjection0"));
	viewer0->setBackgroundColor(255, 255, 255);
	viewer0->addPolygonMesh(triangles, "triangles");
	viewer0->setRepresentationToWireframeForAllActors();          // 网格模型以线框图模式显示

	while (!viewer->wasStopped() || !viewer0->wasStopped())
	{
		viewer->spinOnce(100);
		viewer0->spinOnce(100);
		boost::this_thread::sleep(boost::posix_time::microseconds(100000));
	}

	return (0);
}

7.结果展示

原始点云

重建后的网格信息

PCL(点云库)是一个开源的点云库,可以用于处理和分析三维点云数据。而曲面重建是指利用点云数据生成连续曲面模型的过程。而移动立方体是一种常用的方法,在曲面重建中被广泛应用。 移动立方体方法在曲面重建中的基本思想是将点云数据划分为许多小的立方体单元,并通过在每个立方体单元内的点云数据进行插值和拟合来生成平滑的曲面。具体步骤如下: 1. 网格化:首先将点云数据进行网格化,将整个点云空间划分为一系列的立方体单元。可以根据需要调整立方体单元的大小。 2. 法线估计:对于每个立方体单元,需要估计其中点云数据的法向量。常用的方法是通过最近邻点进行法线估计。 3. 邻域搜索:对于每个立方体单元,需要找到其邻域内的点云数据,用于插值和拟合。 4. 曲面重建:根据邻域内的点云数据进行插值和拟合,生成平滑的曲面。常用的方法是使用多项式拟合或基于样条函数的插值方法。 5. 后处理:对于生成的曲面模型,可以进行后处理操作,如去噪、平滑和曲面优化等,以进一步改善曲面的质量。 移动立方体方法在曲面重建中的优点是简单且易于实现,适用于处理大规模的点云数据。然而,由于其是一种局部方法,可能会导致曲面之间的不连续性。此外,对于包含较复杂几何信息的点云数据,移动立方体方法可能无法很好地重建出精确的曲面模型。因此,在实际应用中,可以根据具体需求选择适合的曲面重建方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值