3.Open3D教程——点云数据操作

点云数据

本教程阐述了基本的点云用法。

随需要的文件链接

1. 显示点云

import open3d as o3d
import numpy as np

print("Load a ply point cloud, print it, and render it")
pcd = o3d.io.read_point_cloud("fragment.ply")
print(pcd)
print(np.asarray(pcd.points))
o3d.visualization.draw_geometries([pcd])

read_point_cloud: 该方法用于读取点云,它会根据扩展名对文件进行解码。所支持的文件类型

draw_geometries: 查看点云,可以通过移动鼠标来从不同的角度点云。

它看起来像一个密集的曲面,但实际上是一个渲染为曲面的点云。GUI支持各种键盘功能。例如,-键减小点(曲面)的大小。

注:按H键为GUI打印出键盘指令的完整列表。有关可视化GUI的更多信息,请参阅可视化和自定义可视化。

2. 体素下采样

体素下采样使用常规体素栅格从输入点云创建均匀下采样点云。它通常用作许多点云处理任务的预处理步骤。该算法分两步操作:

  • 将点固定为体素。
  • 每个被占用的体素通过平均内部的所有点来生成正好一个点。
print("Downsample the point cloud with a voxel of 0.05")
downpcd = pcd.voxel_down_sample(voxel_size=0.05)
o3d.visualization.draw_geometries([downpcd])

对体素为0.05的点云进行下采样。

3. 顶点正态估计

点云的另一个基本操作是点正态估计。按N键查看点法线。键-和+可用于控制法线的长度。

print("Recompute the normal of the downsampled point cloud")
downpcd.estimate_normals(
    search_param=o3d.geometry.KDTreeSearchParamHybrid(radius=0.1, max_nn=30))
o3d.visualization.draw_geometries([downpcd],
                                  point_show_normal=True)

estimate_normals: 计算每个点的法线。该函数查找相邻点并使用协方差分析计算相邻点的主轴。该方法的两个关键参数radius=0.1和max_nn=30指定搜索半径和最大最近邻。它的搜索半径为10cm,最多只考虑30个邻居,节省了计算时间。

4. 访问估计顶点法线

可以从downpcdnormals变量中检索估计的法向量。

print("Print a normal vector of the 0th point")
print(downpcd.normals[0])

可以通过np.asaray将法向量转换为numpy数组。

print("Print the normal vectors of the first 10 points")
print(np.asarray(downpcd.normals)[:10, :])

5. 裁剪点云

加载多边形体积并使用它裁剪原始点云

print("Load a polygon volume and use it to crop the original point cloud")
vol = o3d.visualization.read_selection_polygon_volume(
    "cropped.json")
chair = vol.crop_point_cloud(pcd)
o3d.visualization.draw_geometries([chair])

read_selection_polygon_volume: 读取指定多边形选择区域的json文件。

vol.crop_point_cloud(pcd): 过滤出点。只剩下椅子了。

6. 绘制点云

print("Paint chair")
chair.paint_uniform_color([1, 0.706, 0])
o3d.visualization.draw_geometries([chair])

paint_uniform_color: 将所有点绘制为统一的颜色。颜色在RGB空间,[0,1]范围内。

7. 点云距离

Open3D提供了方法compute_point_cloud_distance来计算源文件和目标文件间的距离,它为源点云中的每个点计算到目标点云中最近点的距离。在下面的示例中,我们使用函数来计算两点云之间的差异。请注意,此方法也可用于计算两点云之间的倒角距离。

import open3d as o3d
import numpy as np

# Load data
pcd = o3d.io.read_point_cloud("test_data/fragment.ply")
vol = o3d.visualization.read_selection_polygon_volume(
    "test_data/Crop/cropped.json")
chair = vol.crop_point_cloud(pcd)

dists = pcd.compute_point_cloud_distance(chair)
dists = np.asarray(dists)
ind = np.where(dists > 0.01)[0]
pcd_without_chair = pcd.select_by_index(ind)
o3d.visualization.draw_geometries([pcd_without_chair])

8. 边界体积

点云几何体类型与Open3D中的所有其他几何体类型一样具有边界体积。当前,Open3D实现了一个AxisAlignedBoundingBox和一个OrientedBoundingBox,也可用于裁剪几何体。

aabb = chair.get_axis_aligned_bounding_box()
aabb.color = (1, 0, 0)
obb = chair.get_oriented_bounding_box()
obb.color = (0, 1, 0)
o3d.visualization.draw_geometries([chair, aabb, obb])

9. 密度的聚类算法簇

给定一个来自深度传感器的点云,我们希望将本地点云簇分组在一起。为此,我们可以使用聚类算法。Open3D实现了DBSCAN,这是一种基于密度的聚类算法。该算法在cluster_dbscan中实现,需要两个参数:eps定义到簇内邻居的距离,min_points定义形成簇所需的最小点数。函数返回labels,其中labelmin_points表示noise。

import open3d as o3d
import numpy as np
import matplotlib.pyplot as plt

pcd = o3d.io.read_point_cloud("test_data/fragment.ply")

with o3d.utility.VerbosityContextManager(
        o3d.utility.VerbosityLevel.Debug) as cm:
    labels = np.array(
        pcd.cluster_dbscan(eps=0.02, min_points=10, print_progress=True))

max_label = labels.max()
print(f"point cloud has {max_label + 1} clusters")
colors = plt.get_cmap("tab20")(labels / (max_label if max_label > 0 else 1))
colors[labels < 0] = 0
pcd.colors = o3d.utility.Vector3dVector(colors[:, :3])
o3d.visualization.draw_geometries([pcd])

10. 平面分割

Open3D还支持使用RANSAC从点云分割几何原语。要在点云中找到支撑度最大的平面,可以使用segment_plane.该。法有三个参数:distance_threshold定义了一个点到被认为是内联的估计平面的最大距离,ransac_n定义了随机采样以估计平面的点的数量,num_iterations定义了随机平面的采样和验证频率。然后函数将平面返回为(a,b,c,d),这样平面上的每个点(x,y,z)的ax+by+cz+d=0。函数还返回内部点的索引列表。

import open3d as o3d
import numpy as np
import matplotlib.pyplot as plt

pcd = o3d.io.read_point_cloud("test_data/fragment.pcd")
plane_model, inliers = pcd.segment_plane(distance_threshold=0.01,
                                         ransac_n=3,
                                         num_iterations=1000)
[a, b, c, d] = plane_model
print(f"Plane equation: {a:.2f}x + {b:.2f}y + {c:.2f}z + {d:.2f} = 0")

inlier_cloud = pcd.select_by_index(inliers)
inlier_cloud.paint_uniform_color([1.0, 0, 0])
outlier_cloud = pcd.select_by_index(inliers, invert=True)
o3d.visualization.draw_geometries([inlier_cloud, outlier_cloud])

版权声明:本文为weixin_40511249原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。