三维点云中常用的表面重建算法

表面重建算法起源于计算机视觉和计算几何学领域。早期的研究集中在从二维图像中提取三维信息。然而,随着三维扫描技术的进步,越来越多的研究转向了如何从点云数据中重建表面。三维点云表面重建技术的发展,始于20世纪90年代,主要推动力是激光扫描和结构光扫描的广泛应用。

Result of 3D reconstruction with inputs from drone video footage. Figure from Neuralangelo paper (Li et.al. 2023),IEEE Conference on Computer Vision and Pattern Recognition (CVPR), 2023
凸包Convex Hull

ConvexHull3D:https://mathworld.wolfram.com/ConvexHull.html

在了解点云表面重建算法前,我们需要知道什么是凸包。凸包是包含所有点的最小凸多边形或多面体,而表面重建则是从点云数据中重建出原始物体的表面。并且凸包是包覆这群点的所有外壳当中,表面积和体积最小的一个外壳,而最小的外壳一定是凸的。虽然凸包是最简单的表面重建形式,适用于点云分布在物体外表面的情况,但对于复杂几何形状需要更复杂的表面重建算法,如Delaunay三角剖分、Poisson表面重建等。这些方法能够处理具有凹陷或洞的物体,通过插值和拟合技术生成满足一定平滑性和几何特征的表面。

凸包(Convex Hull)背后的主要思想来自凸多边形的定义。提醒一下,凸多边形是所有内角都小于 180° 的多边形。通过这个定义,我们发现每个正多边形都是凸的。如果一个角度大于 180°,则该多边形被认为是凹的。凸包使用与凸多边形应用于点集相同的原理。例如,凸包是包含集合中所有点的最小凸多边形。

凸包的目的之一是修剪平面上的特定区域。它主用于计算机图形学、几何和导航。Jarvis March是查找凸包的最流行和最简单的算法之一。它的简单的原理是探索一个集合中的 n 个点并返回围绕该集合的点的列表,这些点具有凸包的属性。这种方法在较好的情况下需要 O(nm) 的时间复杂度,其中 n 是探索的点数,m 是形成凸包形状的点数。在最坏的情况下,即 n = m,时间复杂度变为 O(n^2)。对于大数据集来说,这很容易变得非常大。要使用 Gift Warping 算法计算一组点的凸包,我们从已知位于凸包中的最左边的点 (对于 i = 0)开始。然后,我们选择另一个点 ,例如所有剩余的点都在点 和 之间绘制的线的右侧,然后我们循环重复,直到到达第一个点 。

Jarvis March:https://alphasldiallo.github.io/convex-hull-delaunay-triangulation-and-alpha-shapes/

常用的表面重建方法

表面重建算法的数学原理通常涉及几何和拓扑学。以下是常用的表面重建方法:

Alpha形状构建

给定一组任意分布的数据点,有许多方法可以将它们组织成三角形网格。但并非所有可能的三角形网格都能很好地表示点之间的空间关系。右边的图像是 Delaunay 三角剖分的示例。除了美观之外,Delaunay 还具有许多有利的特性,这些特性由 Boris Delaunay 于 1934 年和其他研究人员证明。https://gwlucastrig.github.io/TinfourDocs/DelaunayIntro/index.html

通过Delaunay三角剖分,我们可以找到一组点的Alpha形状。具体实现方法如下:

  1. 计算点集的Delaunay三角剖分。

  2. 删除至少有一条边的长度超过的所有三角形。

  3. 保留剩余的三角形作为Alpha形状的一部分。

Alpha Shapes算法基于Delaunay三角剖分,它通过一个参数来控制形状的细节程度。

若足够小则包含点对的圆不会包含其他点则是一个边

这种强大的方法用于概括包含一组点的边界多边形。下图中作者根据收集的运动轨迹生成了楼层平面图。如下图所示,与凸包不同,alpha 形状可以更精确地找到一组点的准确轮廓。该算法主要用于计算几何,尤其是在处理 3D 形状时。

用凸包和 alpha 形状构建平面图的图示

import open3d as o3d
from copy import deepcopy

if __name__ == '__main__':
    file_path = 'rabbit.pcd'
    pcd = o3d.io.read_point_cloud(file_path)
    pcd = pcd.uniform_down_sample(50)  # 每50个点采样一次
    pcd.paint_uniform_color([0.5, 0.5, 0.5])  # 指定显示为灰色
    print(pcd)

    pcd1 = deepcopy(pcd)
    pcd1.translate((20, 0, 0))  # 整体进行x轴方向平移20
    mesh1 = o3d.geometry.TriangleMesh.create_from_point_cloud_alpha_shape(pcd1, alpha=2)
    mesh1.paint_uniform_color([1.0, 0.6667, 0.0039])  # 指定颜色
    print(mesh1)

    o3d.visualization.draw_geometries([pcd, mesh1],  # 点云列表
                                      window_name="Alpha Shape 重建",
                                      point_show_normal=False,
                                      width=800,  # 窗口宽度
                                      height=600,
                                      mesh_show_wireframe=True,
                                      mesh_show_back_face=True,
                                      )  # 窗口高度
Ball Pivoting滚球算法

Ball Pivoting算法通过在点云上滚动一个球来构建表面。该算法依赖于球的半径,在滚动过程中连接球接触的点。

球半径确定了表面的细节和连接

import open3d as o3d
from copy import deepcopy

if __name__ == '__main__':
    file_path = 'rabbit.pcd'
    pcd = o3d.io.read_point_cloud(file_path)
    pcd = pcd.uniform_down_sample(50)  # 每50个点采样一次
    pcd.paint_uniform_color([0.5, 0.5, 0.5])  # 指定显示为灰色
    print(pcd)

    pcd2 = deepcopy(pcd)
    pcd2.translate((-20, 0, 0))  # 整体进行x轴方向平移-20
    radius = 0.01  # 搜索半径
    max_nn = 10  # 邻域内用于估算法线的最大点数
    pcd2.estimate_normals(search_param=o3d.geometry.KDTreeSearchParamHybrid(radius, max_nn))
    radii = [1, 2]  # 半径列表
    mesh2 = o3d.geometry.TriangleMesh.create_from_point_cloud_ball_pivoting(pcd2, o3d.utility.DoubleVector(radii))
    mesh2.paint_uniform_color([0, 0, 1])

    o3d.visualization.draw_geometries([pcd, mesh2],  # 点云列表
                                      window_name="Ball Pivoting 重建",
                                      point_show_normal=False,
                                      width=800,  # 窗口宽度
                                      height=600,
                                      mesh_show_wireframe=True,
                                      mesh_show_back_face=True,
                                      )  # 窗口高度
Poisson Surface Reconstruction

Poisson Surface Reconstruction算法通过解Poisson方程,从点云中重建表面。它将点云视为一个连续的标量场,利用梯度场的散度来重建表面。

其中, 是向量场, 是散度。

import open3d as o3d
import numpy as np
from copy import deepcopy

if __name__ == '__main__':
    file_path = 'rabbit.pcd'
    pcd = o3d.io.read_point_cloud(file_path)
    pcd = pcd.uniform_down_sample(50)  # 每50个点采样一次
    pcd.paint_uniform_color([0.5, 0.5, 0.5])  # 指定显示为灰色
    print(pcd)

    pcd3 = deepcopy(pcd)
    pcd3.translate((0, 20, 0))  # 整体进行y轴方向平移20
    radius = 0.01  # 搜索半径
    max_nn = 10  # 邻域内用于估算法线的最大点数
    pcd3.estimate_normals(search_param=o3d.geometry.KDTreeSearchParamHybrid(radius, max_nn))
    mesh3, densities = o3d.geometry.TriangleMesh.create_from_point_cloud_poisson(pcd3, depth=9)
    vertices_to_remove = densities < np.quantile(densities, 0.35)
    mesh3.remove_vertices_by_mask(vertices_to_remove)
    mesh3.paint_uniform_color([1, 0, 0])

    o3d.visualization.draw_geometries([pcd, mesh3],  # 点云列表
                                      window_name="Poisson 重建",
                                      point_show_normal=False,
                                      width=800,  # 窗口宽度
                                      height=600,
                                      mesh_show_wireframe=True,
                                      mesh_show_back_face=True,
                                      )  # 窗口高度
Voxel Grid

Voxel Grid方法通过将点云划分为规则的三维网格(体素),并在每个体素中估计表面法线和曲率来重建表面。

体素尺寸决定了重建的分辨率

import open3d as o3d
from copy import deepcopy

if __name__ == '__main__':
    file_path = 'rabbit.pcd'
    pcd = o3d.io.read_point_cloud(file_path)
    pcd = pcd.uniform_down_sample(50)  # 每50个点采样一次
    pcd.paint_uniform_color([0.5, 0.5, 0.5])  # 指定显示为灰色
    print(pcd)

    pcd4 = deepcopy(pcd)
    pcd4.translate((0, -20, 0))  # 整体进行y轴方向平移-20
    pcd4.paint_uniform_color([0, 1, 1])
    mesh4 = o3d.geometry.VoxelGrid.create_from_point_cloud(pcd4, voxel_size=1)

    o3d.visualization.draw_geometries([pcd, mesh4],  # 点云列表
                                      window_name="Voxel Grid 重建",
                                      point_show_normal=False,
                                      width=800,  # 窗口宽度
                                      height=600,
                                      mesh_show_wireframe=True,
                                      mesh_show_back_face=True,
                                      )  # 窗口高度

上述代码使用Alpha Shapes、Ball Pivoting、Poisson Surface Reconstruction和Voxel Grid等方法重建了点云的表面。

应用领域和场景

三维点云表面重建算法广泛应用于多个领域:

  1. 文物保护:用于数字化和重建文物表面,方便研究和展示。

  2. 医疗影像:在CT和MRI图像中重建人体器官的三维模型,辅助诊断和手术规划。

  3. 机器人导航:帮助机器人理解环境的三维结构,实现自主导航。

  4. 计算机动画:在电影和游戏中创建逼真的三维模型和场景。

三维点云表面重建算法在多个领域有广泛的应用和重要性。了解这些算法的原理和应用场景,不仅能帮助我们更好地使用这些技术,还能激发我们在更多领域的创新和探索。

以上内容总结自网络,如有帮助欢迎关注与转发,我们下次再见!

相关推荐
肥猪猪爸23 分钟前
使用卡尔曼滤波器估计pybullet中的机器人位置
数据结构·人工智能·python·算法·机器人·卡尔曼滤波·pybullet
readmancynn35 分钟前
二分基本实现
数据结构·算法
萝卜兽编程38 分钟前
优先级队列
c++·算法
盼海1 小时前
排序算法(四)--快速排序
数据结构·算法·排序算法
一直学习永不止步1 小时前
LeetCode题练习与总结:最长回文串--409
java·数据结构·算法·leetcode·字符串·贪心·哈希表
Rstln2 小时前
【DP】个人练习-Leetcode-2019. The Score of Students Solving Math Expression
算法·leetcode·职场和发展
芜湖_2 小时前
【山大909算法题】2014-T1
算法·c·单链表
珹洺2 小时前
C语言数据结构——详细讲解 双链表
c语言·开发语言·网络·数据结构·c++·算法·leetcode
几窗花鸢2 小时前
力扣面试经典 150(下)
数据结构·c++·算法·leetcode
.Cnn2 小时前
用邻接矩阵实现图的深度优先遍历
c语言·数据结构·算法·深度优先·图论