自动摘要: 安装 pipinstallopen3d
几何学 本教程演示了点云的基本用法。 可视化点云 本教程的第一部分读取点云并将其可视化。 ``` importop ……..
安装
1 | pip install open3d |
几何学
本教程演示了点云的基本用法。
可视化点云
本教程的第一部分读取点云并将其可视化。
1 | import open3d as o3d |
输出结果:
1 | 加载一个ply点云,打印它,渲染它 |
它看起来像一个密集的表面,但它实际上是一个渲染为表面的点云。GUI 支持各种键盘功能。例如,’-‘ 键减小了点(表面)的大小。
open3d.ioread_point_cloud(filename,format=auto,remove_nan_points=False,remove_infinite_points=False,print_progress=False)函数功能:read_point_cloud从文件中读取点云。它尝试根据扩展名解码文件。有关支持的文件类型列表,请参阅文件 IO。参数:
- filename(str):文件路径;
- format(str,optional,default=auto):输入文件的格式。如果未指定或设置为auto,则从文件扩展名推断格式;
- remove_nan_points(bool,optional,default=False):如果为真,所有包含NaN的点都会从PointCloud中移除;
- remove_infinite_points(bool,optional,default=False):如果为真,则从PointCloud中删除所有包含无限值的点。
- print_progress(bool,optional,default=False):如果设置为True,则会在控制台中显示进度条。
返回值:open3d.geometry.PointCloud
draw_geometries(geometry_list,window_name=’Open3D’,width=1920,height=1080,left=50,top=50,point_show_normal=False,mesh_show_wireframe=False,mesh_show_back_face=False,lookat,up,front,zoom)函数功能:draw_geometries可视化点云。使用鼠标/触控板从不同的视点查看几何图形。参数:
- geometry_list(List[open3d.geometry.Geometry]):要可视化的几何图形列表;
- window_name(str,optional,default=’Open3D’):可视化窗口的显示主题;
- width(int,optional,default=1920):可视化窗口的宽度;
- height(int,optional,default=1080):可视化窗口的高度;
- left(int,optional,defalult=50):可视化窗口的左边距;
- top(int,optional,default=50):可视化窗口的上边距;
- point_show_normal(bool,optional,default=False):如果设置为True,则可视化点法线;
- mesh_show_wireframe(bool,optional,default=False):如果设置为True,则可视化网格线框;
- mesh_show_back_face(bool,optional,default=False):也可视化网格三角形的背面;
- lookat(numpy.ndarray[numpy.float64[3,1]]):相机的观察向量;
- up(numpy.ndarray[numpy.float64[3,1]]):相机的向上向量;
- front(numpy.ndarray[numpy.float64[3,1]]):相机的前向量。
- zoom(float):相机的变焦;
体素缩减采样
体素缩减采样使用规则的体素网格从输入点云创建均匀的缩减采样点云。它通常用作许多点云处理任务的预处理步骤。该算法分两步运行:
- 点被桶入体素中;
- 每个被占用的体素通过平均内部的所有点来生成一个点,即一个体素只表示一个点。输出结果:
1
2
3
4
5
6
7
8import open3d as o3d
print('以0.05的体素对点云进行下采样')
ply_point_cloud = o3d.data.PLYPointCloud()
pcd = o3d.io.read_point_cloud(ply_point_cloud.path)
downpcd = pcd.voxel_down_sample(voxel_size=0.05)
o3d.visualization.draw_geometries([downpcd],zoom=0.3412,front=[0.4257,-0.2125,-0.8795],
lookat=[2.6172,2.0475,1.532],up=[-0.0694,-0.9768,0.2024])1
以0.05的体素对点云进行下采样
顶点法向估计
点云的另一个基本操作是点正态估计。按下N可查看点法线。该键 “-,+” 可用于控制法向长度。
1 | import open3d as o3d |
输出结果:
1 | 重新计算下采样点云的法线 |
Open3d.geometry.PointCloud:estimate_normals(self,search_param=KDTreeSearchParamKNN with knn=30,fast_normal_computon=True)函数功能:estimate_normals计算每个点法向的函数,该函数查找相邻点并使用协方差分析计算相邻点的主轴。参数:
- search_param(open3d.geometry.KDTreeSearchParam,option,default=KDTreeSearchParamKNN with knn=30):用于邻域搜索的KDTree搜索参数。
- fast_normal_computation(bool,optional,default=True):如果为真,则正态估计使用非迭代方法从协方差矩阵中提取特征向量。这更快,但数值不稳定。
KDTreeSearchParamHybrid该函数采用类的实例作为参数。radius = 0.1和max_nn = 30这两个关键参数指定搜索半径和最大最近邻。它具有10cm的搜索半径,最多只能考虑30个邻居,以节省计算时间。 功能:KDTreeSearchParamHybrid混合KNN和半径搜索的KDTree搜索参数。
注意:协方差分析算法生成两个相反的方向作为正态候选项。在不知道几何图形的全局结构的情况下,两者都可能是正确的。这称为正常方向问题。Open3D 尝试将法线定向为与原始法线对齐(如果存在)。否则,Open3D 会进行随机猜测。进一步的方向函数,例如,如果方向是一个问题,则需要调用orient_normals_to_align_with_direction和orient_normals_towards_camera_location。
估计顶点法向
估计的法向量可以从 downpcd 的法向量中检索出来。
1 | import open3d as o3d |
输出结果:
1 | 打印第0个点的法向量 |
要查看其他变量,请使用help(downpcd)。可以使用np.asarray将法向量变换为 numpy 数组。
1 | import open3d as o3d |
输出结果:
1 | 打印前10点的法向量 |
裁剪点云
1 | import open3d as o3d |
输出结果:
1 | 加载一个多边形体积并使用它裁剪原始点云 |
class:open3d.data.DemoCropPointCloud介绍:DemoCropPointCloud的数据类包含点云和cropped.json(保存的选定多边形体积文件)。该数据集在Open3D中用于点云裁剪演示。init(self:open3d.cpu.pybind.data.DemoCropPointCloud,data_root:str=“”)->None属性:
- cropped_json_path:保存的选定多边形体积文件的路径;
- data_root:获取数据根目录。数据根在构建时设置或自动确定;
- download_dir:获取下载目录的绝对路径。即${data_root}/${download_prefix}/${prefix};
- extract_dir:获取提取目录的绝对路径。即${data_root}/${extract_prefix}/${prefix};
- point_cloud_path:示例点云的路径;
- prefix:获取数据集的前缀;
- read_selection_polygon_volume读取指定多边形选择区域的 json 文件,vol.crop_point_cloud(pcd)裁剪点云的函数, 过滤掉点,只剩下椅子了。
绘制点云
1 | import open3d as o3d |
输出结果:
1 | 给椅子上色 |
paint_uniform_color将所有点绘制为统一的颜色,颜色位于 RGB 空间 [0, 1] 范围内。
点云距离
Open3D 提供了compute_point_cloud_distance方法来计算从源点云到目标点云的距离,即它计算源点云中每个点到目标点云中最近点的距离。
open3d.geometry.PointCloudcompute_point_cloud_distance(self,target)函数功能:对于源点云中的每个点,计算到目标点云的距离。参数:
- target(open3d.geometry.PointCloud):目标点云
返回值:open3d.utility.DoubleVector
open3d.geometry.PointCloudselect_by_index(self,indices,invert=False)函数功能:从输入点云中选择点到输出点云中的功能参数:
- indices(List[int]):要选择的点的索引;
- invert(bool,optional,default=False):设置为True以反转索引的选择。
返回值:open3d.geometry.PointCloud
在下面的示例中,我们使用该函数来计算两个点云之间的差异。请注意,此方法也可用于计算两个点云之间的倒角距离。
1 | import open3d as o3d |
输出结果:
包围框
点云几何类型与 Open3D 中的所有其他几何类型一样具有包围框。目前,Open3D 实现了一个PointCloudAxisAlignedBoundingBox和一个OrientedBoundingBox,它也可以用来裁剪几何体。
1 | import open3d as o3d |
输出结果:
open3d.geometry.PointCloudget_axis_aligned_bounding_box(self)函数功能:返回几何的轴对齐边界框。参数:无返回值:open3d.geometry.AxisAlignedBoundingBox
open3d.geometry.PointCloudget_oriented_bounding_box(self:open3d.geometry.Geometry3D,robust:bool=False)->open3d::geometry::OrientedBoundingBox函数功能:返回几何体的定向边界框;基于凸包的PCA计算定向边界框。返回的边界框是最小边界框的近似值。参数:
- robust(bool):如果设置为True,则使用更健壮的方法,该方法适用于退化情况,但会在点坐标中引入噪声。
返回值:定向边界框。边界框的方向使得轴相对于主成分是有序的 open3d.geometry.OrientedBoundingBox。
凸包
点云的凸壳是包含所有点的最小凸集。Open3D 包含计算点云的凸壳的方法compute_convex_hull。实现基于Qhull。在下面的示例代码中,我们首先从网格中对点云进行采样,并计算以三角形网格形式返回的凸壳。然后,我们将凸起的船体可视化为红色LineSet。
1 | import open3d as o3d |
输出结果:
open3d.ioread_triangle_mesh(filename,enable_post_processing=False,print_progress=False)函数功能:从文件中读取三角形网格参数:
- filename(str):文件路径;
- enable_post_processing(bool,optional,default=False):
- print_progress(bool,optional,default=False):如果设置为True,则会在控制台中显示进度条。
返回值:open3d.geometry.TriangleMesh
open3d.geometry.TriangleMeshcompute_vertex_normals(self,normalized=True)函数功能:计算顶点法线的函数,通常在渲染之前调用参数:normalized(bool,optional,default=True)返回值:open3d.geometry.TriangleMesh
DBSCAN聚类
给定来自例如深度传感器的点云,我们希望将本地点云集群组合在一起。为此,我们可以使用聚类分析算法。Open3D 实现了 DBSCAN [Ester1996] ,这是一种基于密度的聚类算法。该算法在cluster_dbscan中实现并需要两个参数:eps定义到聚类中邻居的距离,并定义形成聚类所需的最小点数min_points。该函数返回labels,其中标签-1指示噪声。
class open3d.utility.VerbosityContextManager介绍:用于临时更改Open3D详细级别的上下文管理器;初始:init(self:open3d.utility.VerbosityContextManager,level:open3d.utility.VerbosityLevel)->None:创建具有给定VerbosityLevel的VerbosityContextManager;属性:无
class open3d.utility.VerbosityLevel介绍:详细级别的枚举类;方法:Debug=VerbosityLevel.Debug:3 Error=< VerbosityLevel.Error:0> Info=< VerbosityLevel.Info:2> Warning=VerbosityLevel.Warning:1属性:value
open3d.geometry.PointCloudcluster_dbscan(self,eps,min_points,print_progress=False)函数功能:根据算法返回点标签列表,-1表示噪声。参数:
- eps(float):用于查找相邻点的密度函数;
- min_points(int):形成聚类的最小点数;
- print_progress(bool,optional,default=False):如果为True,则进度会在控制台中可视化。
class open3d.utility.Vector3dVector介绍:将形状(n,3)的float64 numpy数组转换为Open3D格式。
1 | import open3d as o3d |
输出结果:
1 | [Open3D DEBUG] Precompute neighbors. |
注意:此算法预先计算所有点的 epsilon 半径内的所有邻居。如果所选的 epsilon 太大,这可能需要大量内存。
RANSAC平面分割
Open3D 还支持使用 RANSAC 分割来自点云的几何基元。要找到在点云中具有最大支撑的平面,我们可以使用segment_plane。该方法有三个参数:distance_threshold定义了点到估计平面的最大距离,这些距离内的点被认为是内点(inlier),ransac_n定义随机采样以估计平面的点数,以及num_iterations定义随机平面采样和验证的频率。然后,该函数返回(a,b,c,d)平面,以便对于平面上的每个点(x,y,z),我们都有ax+by+cz+d=0 。该函数进一步返回内点的索引列表。
open3d.geometry.PointCloudsegment_plane(self,distance_threshold,ransac_n,num_iterations,seed=None)函数功能:使用RANSAC算法在点云中分割平面参数:
- distance_threshold(float):一个点与平面模型的最大距离,仍然被认为是一个内点;
- ransac_n(int):每次迭代中被视为内点的初始点数;
- num_iterations(int):迭代次数;
- seed(Optional[int],optional,default=None):随机生成器中使用的种子值,设置为None以在每个函数调用中使用随机种子值。
返回值:Tuple[numpy.ndarray[numpy.float64[4,1]],List[int]]
1 | import open3d as o3d |
输出结果:
隐藏点删除
假设您希望从给定视点渲染点云,但背景中的点会泄漏到前景中,因为它们不会被其他点遮挡。为此,我们可以应用隐藏点删除算法。在Open3D中,[Katz2007]的方法实现了从给定视图近似点云的可见性,而无需表面重建或法线估计。
class open3d.data.ArmadilloMesh介绍:ArmadilloMesh 的数据类包含来自 Stanford 3D Scanning Repository 的 ArmadilloMesh.ply方法:init(self:open3d.data.ArmadilloMesh,data_root:str=“”)->None属性:
- data_root:获取数据根目录。数据根在构建时设置或自动确定;
- download_dir:获取下载路径的绝对路径;
- extract_dir:获取解压目录的绝对路径;
- path:ArmadilloMesh.ply文件的路径;
- prefix:获取数据集的前缀。
1 | import open3d as o3d |
输出结果:
1 | print('定义参数用于删除隐藏点') |
输出结果:
Mesh
https://blog.csdn.net/u014072827/article/details/112399050Open3D 具有一个称为TriangleMesh的 3D 三角形网格的数据结构。下面的代码显示了如何从ply文件中读取三角形网格并打印其顶点和三角形。
1 | import open3d as o3d |
输出结果:
1 | 测试网格在open3D |
TriangleMesh类具有一些数据字段,例如vertices和triangles。Open3D 通过numpy提供直接内存访问。
可视化3D网络
1 | import open3d as o3d |
输出结果:
1 | 尝试使用网格法线(存在:False) 和颜色(存在:False)去渲染网格 |
可以旋转和移动这个网格,但是由于它是纯灰色的所以看起来不是并不像一个3D图形。这是因为当前网格没有顶点或面的法线。因此,使用统一颜色着色而不是更复杂的Phong着色。
表面法线估计
使用曲面法线绘制网格。
1 | import open3d as o3d |
输出结果:
1 | 计算法线和渲染 |
它使用计算compute_vertex_normals和paint_uniform_color作为mesh的成员函数。
裁剪网格
通过numpy直接操作网格的triangle和triangle_normals数据域去除一半的曲面。
1 | import open3d as o3d |
输出结果:
渲染网格
paint_uniform_color给网格涂上统一的颜色。颜色位于 RGB 空间 [0, 1] 范围内。
1 | import open3d as o3d |
输出结果:
1 | 渲染网格 |
网格属性
三角形网格具有多个可以使用 Open3D 进行测试的属性。一个重要的属性是流形属性,可使用is_edge_manifold去测试网格是否为边缘流形(edge manifold),使用is_vertex_manifold去测试所有顶点是否为流形。如果每个边缘包括一个或两个三角形,则这个三角网格是边缘流形。函数 is _ edge _ Manifold 具有 bool 参数 allow _ boundary _ edge,该参数定义是否允许边界边缘。此外,如果顶点的星形边是边缘流形和边缘连接的话,则三角形网格是顶点流形。比如两个或者更多的面可能只有一个顶点连接而不是通过边。
另一个属性是自相交测试。如果在一个网格中存在与另一个网格相交的三角形,is_self_intersecting这个函数就会返回true。一个水密网格能够被定义成一个边缘流形,顶点流形和不自交的网格。在Open3D中通过is_watertight接口实现这种检测。
可以测试一个网格是否为可定向的,即三角形可以以所有法线指向外部的方式定向。这个通过is_orientable实现。
下面的示例代码测试了这些属性并且可视化。非流形边缘用红色表示,边界边缘用绿色标识,非流形顶点用绿色点,自交的三角形用粉色显示。其中需要open3d_example.py文件,代码如下:
1 | # ---------------------------------------------------------------------------- |
示例代码:
1 | import open3d as o3d |
输出结果:
1 | KnotMesh |
1 | Mobius |
1 | non-manifold edge |
1 | non-manifold vertex |
1 | open box |
1 | intersecting_boxes |
网格过滤
Open3d包含许多过滤网格的算法,下面将展示实现的滤波器来平滑噪声三角形网格。
平均过滤器
最简单的过滤器是均值滤波器。给定的顶点由相邻顶点的平均值N给出的。公式如下:
可以使用此过滤器对网格进行降噪,如下面的代码所。filter_smooth_simple函数的参数number_of_iterations用来定义应用于网格的滤波器的频率。
1 | import numpy as np |
输出结果:
1 | 添加噪声的网络 |
1 | 使用均值滤波器迭代1次 |
1 | 使用均值滤波器迭代5次 |
拉普拉斯算子(Laplacian)
另一个重要的网格过滤器是拉普拉斯算子,其定义如下:
其中λ是滤波器的强度,w_{n}是与相邻顶点的距离相关的归一化权重. 这个滤波器的接口是filter_smooth_laplacian,有两个参数: number_of_iterations 和 lambda。
1 | import open3d as o3d |
输出结果:
1 | 使用拉普拉斯滤波器迭代10次 |
1 | 使用拉普拉斯滤波器迭代50次 |
Taubin滤波器
均值滤波和Laplacian滤波有一个问题是他们会使三角网格收缩。[Taubin1995] 展示了使用两种不同λ参数的Laplacian滤波器来防止网格收缩。这个滤波器的实现接口是:filter_smooth_taubin。
1 | import open3d as o3d |
输出结果:
1 | 使用Taubin滤波迭代10次 |
1 | 使用Taubin滤波迭代100次 |
采样
Open3d包含了从三角网格中采样点云的功能。最简单的方法是使用sample_points_uniformly函数从三角网格的三维表面均匀采样。参数number_of_points表示从网格中采样的点云的点数。
1 | import open3d as o3d |
输出结果:
1 | import open3d as o3d |
输出结果:
均匀采样可得到表面上的点簇。泊松盘采样能使采样点均匀的分布。sample_points_poisson_disk实现了该功能。因此该算法从一个采样后的点云开始,移除点以满足采样标准。这个算法支持两个初始点云的选择方法:
- 默认通过参数init_factor:首先通过init_factor x number_of_points来从网格中均匀采样点云,之后进行消除。
- 可以直接提供一个点云数据给sample_points_poisson_disk函数,之后会进行点云的消除。输出结果:
1
2
3
4
5
6
7
8import open3d as o3d
mesh = o3d.geometry.TriangleMesh.create_sphere()
pcd = mesh.sample_points_poisson_disk(number_of_points=500,init_factor=5)
o3d.visualization.draw_geometries([pcd])
pcd = mesh.sample_points_uniformly(number_of_points=2500)
pcd = mesh.sample_points_poisson_disk(number_of_points=500,pcl=pcd)
o3d.visualization.draw_geometries([pcd])
1 | import open3d as o3d |
输出结果:
网格细分
网格细分就是把每个三角形划分为更小的三角形。最简单的方式就是,计算三角形每个边的中点,将其划分为四个较小的三角形。这个通过subdivide_midpoint函数实现。3D曲面和面积保持不变但是顶点和三角形的数量增加了。number_of_iterations参数定义了重复细分多少次。
1 | import open3d as o3d |
输出结果:
1 | 网格有8个顶点和12个三角形 |
1 | 再分之后有26个顶点和48个三角形 |
Open3d实现了基于[Loop1987]的附加细分方法。该方法基于四次样条曲线,该样条曲线除了在特殊顶点处生成连续的极限曲面外,其他地方都生成连续的极限曲面。这样可以得到更加平滑的拐角。
1 | import open3d as o3d |
输出结果:
1 | 网格有762个顶点和1520个三角形 |
1 | 再分之后有12162个顶点和24320个三角形 |
1 | import open3d as o3d |
输出结果:
1 | 网格有1440个顶点和2880个三角形 |
1 | 再分之后有23040个顶点和46080个三角形 |
网格简化
有时,我们希望用较少的三角形和顶点表示一个高分辨率网格,但低分辨率网格仍应接近高分辨率网格。为此,Open3D 实现了许多网格简化方法。
顶点聚类
顶点聚类的方法是将所有落入给定大小的体素的顶点聚集到单个顶点。函数接口为simplify_vertex_clustering,参数voxel_size设置体素网格大小。contraction定义如何聚集顶点。
1 | 输入网格有35947个顶点和69451个三角形 |
1 | 体素有0.004865593749999999个 |
1 | 体素有0.009731187499999999个 |
网格抽取
网格细分的另一种方式是逐步执行的网格抽取。我们选择一个使误差度量最小化的三角形并将其删除。重复此过程直到满足指定的三角形数量时停止。Open3D实现了simplify_quadric_decimation接口去最小化误差平方(到相邻平面的距离),参数target_number_of_triangles定义了抽取算法的停止条件。
1 | 输入网格有35947个顶点和69451个三角形 |
1 | 简化网格之后有1978个顶点和1700个三角形 |
连通分量
各种重建方法的结果。 Open3D实现了一个连接组件算法cluster_connected_triangles,该算法将每个三角形分配给一组连接的三角形。 它为每个三角形返回cluster_index中的簇索引,每个簇返回cluster_n_triangles中三角形的数目以及cluster_area中簇的表面积。下面的代码展示cluster_connected_triangles的应用和如何使用它来删除假(spurious)三角形。
1 | import open3d as o3d |
输出结果:
1 | 生成数据 |
1 | import open3d as o3d |
输出结果:
1 | cluster connected triangles |
1 | import open3d as o3d |
输出结果:
1 | 展示删除小簇的网格 |
1 | import open3d as o3d |
输出结果:
1 | 展示最大簇 |