open3d

文章目录

  • open3d
    • 1. 点云读写
    • 2. 点云可视化
      • 2.1 可视化单个点云
      • 2.2 可视化多个点云
      • 2.3 可视化属性
    • 3. k-d tree 与 Octree
      • 3.1 k-d tree
      • 3.2 Octree
    • 4. 滤波
      • 4.1 体素下采样
      • 4.2 统计滤波
      • 4.3 半径滤波
    • 5. 特征提取
      • 5.1 法线估计
    • 6.分割
      • 6.1 DBSCAN聚类分割
      • 6.2 RANSAC平面分割
      • 6.3 隐藏点剔除
    • 7. 曲面重建
      • 7.1 Alpha shapes
      • 7.2 Ball pivoting
      • 7.3 Poisson surface reconstruction
    • 8. 空间转换
      • 8.1 Translate 平移
      • 8.2 Rotation 旋转
      • 8.3 Scale 缩放
      • 8.4 General transformation (平移+旋转)
    • 9. 配准
    • 10. 常用算法
      • 10.1 计算点云距离
      • 10.2 最小包围盒
      • 10.3 计算凸包
      • 10.4 点云体素化
      • 10.5 计算点云质心
      • 10.6 根据索引提取点云
      • 10.7 点云赋色

open3d

1. 点云读写

import open3d as o3d
import numpy as np

pcd = o3d.io.read_point_cloud("test.pcd")
print(pcd) # 输出点云个数
print(np.asarray(pcd.points)) # 输出点的三维坐标
o3d.io.write_point_cloud("write.pcd", pcd, True) # 默认false,保存为Binarty;True 保存为ASICC形式
print(pcd)
  • 与PCL相比open3d通过扩展名判断文件类型,也可以指定文件类型
pcd = o3d.io.read_point_cloud("../../test_data/my_points.txt", format='xyz')

2. 点云可视化

2.1 可视化单个点云

import open3d as o3d
import numpy as np

pcd = o3d.io.read_point_cloud("test.pcd")
print(pcd)

o3d.visualization.draw_geometries([pcd])
  • 通过键盘上的 +、-,实时调整点的大小

2.2 可视化多个点云

o3d.visualization.draw_geometries([pcd1, pcd2, ... ,pcdn])
import open3d as o3d
import numpy as np

pcd1 = o3d.io.read_point_cloud("bunny.pcd")
print(pcd1)

pcd2 = o3d.io.read_point_cloud("bunny0.pcd")
print(pcd2)

o3d.visualization.draw_geometries([pcd1, pcd2])

2.3 可视化属性

  • 窗口大小边距 法线网格设置
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)
参数 含义
geometry_list 要可视化的几何体列表
window_name (str, optional, default=‘Open3D’),可视化窗口的显示标题
width (int, optional, default=1920),可视化窗口的宽度
height (int, optional, default=1080),可视化窗口的高度
left (int, optional, default=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),可视化网格三角形的背面
  • 增加相机视角
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)
参数 含义
lookat (numpy.ndarray[float64[3, 1]]),相机的注视向量
up (numpy.ndarray[float64[3, 1]]),相机的上方向向量
front (numpy.ndarray[float64[3, 1]]),相机的前矢量
zoom (float),相机的缩放倍数
  • 法线估计
# 法线估计
radius = 0.01   # 搜索半径
max_nn = 30     # 邻域内用于估算法线的最大点数
pcd.estimate_normals(search_param=o3d.geometry.KDTreeSearchParamHybrid(radius, max_nn))     # 执行法线估计

3. k-d tree 与 Octree

3.1 k-d tree

pcd_tree = o3d.geometry.KDTreeFlann(pcd)  # 建立KDTree
pcd_tree.search_knn_vector_3d(search_Pt, k)  # K近邻搜索
pcd_tree.search_radius_vector_3d(search_Pt, radius)  # 半径R近邻搜索
pcd_tree.search_hybrid_vector_3d(search_pt, radius, max_nn)  # 混合邻域搜索,返回半径radius内不超过max_nn个近邻点

返回值为 [K邻域内点数/R半径内点数/混合邻域内点数 , 点的索引, ]

  • 为点云点赋色
# 将点云设置为灰色
pcd.paint_uniform_color([0.5, 0.5, 0.5])
# 跳过查询点本身为点云赋色
np.asarray(pcd.colors)[idx_radius[1:], :] = [1, 0, 0]

3.2 Octree

  • Open3D具有几何体类型的八叉树,可用于创建、搜索和遍历具有用户指定的最大树深度的八叉树max_depth
  • 从根节点到“最大深度”(depth max_depth)处的相应叶节点的路径,将每个点插入到树中。随着树深度的增加,内部(最终是叶子)节点表示三维空间的较小分区
octree = o3d.geometry.Octree(max_depth=4)
octree.convert_from_point_cloud(pcd, size_expand=0.01)
o3d.visualization.draw_geometries([octree])
  • 从体素栅格中构建Octree
voxel_grid = o3d.geometry.VoxelGrid.create_from_point_cloud(pcd, voxel_size=0.2)
o3d.visualization.draw_geometries([voxel_grid])

octree = o3d.geometry.Octree(max_depth=4)
octree.create_from_voxel_grid(voxel_grid)
o3d.visualization.draw_geometries([octree])

4. 滤波

4.1 体素下采样

  • 将点云进行进行体素划分
  • 对所有非空体素,取体素内点云的质心作为该体素的点的位置
voxel_size = 0.5
downpcd = pcd.voxel_down_sample(voxel_size)

4.2 统计滤波

  • statistical_outlier_removal 滤除离群点
    • num_neighbors,指定为了计算给定点的平均距离,需要考虑多少个邻居。即K邻域的点数
    • std_ratio,允许根据点云平均距离的标准偏差设置阈值水平。该数值越低,滤除的点数就越多
num_neighbors = 20 # K邻域点的个数
std_ratio = 2.0 # 标准差乘数
# 执行统计滤波,返回滤波后的点云sor_pcd和对应的索引ind
sor_pcd, ind = pcd.remove_statistical_outlier(num_neighbors, std_ratio)
sor_pcd.paint_uniform_color([0, 0, 1])
# 提取噪声点云
sor_noise_pcd = pcd.select_by_index(ind,invert = True)
sor_noise_pcd.paint_uniform_color([1, 0, 0])

4.3 半径滤波

  • radius_outlier_removal 移除给定球体中几乎没有邻居的点
    • num_points,邻域球内的最少点数,低于该值的点为噪声点
    • radius ,邻域半径的大小
num_points = 20  # 邻域球内的最少点数,低于该值的点为噪声点
radius = 0.05    # 邻域半径大小
# 执行半径滤波,返回滤波后的点云sor_pcd和对应的索引ind
sor_pcd, ind = pcd.remove_radius_outlier(num_points, radius)
sor_pcd.paint_uniform_color([0, 0, 1])
# 提取噪声点云
sor_noise_pcd = pcd.select_by_index(ind,invert = True)
sor_noise_pcd.paint_uniform_color([1, 0, 0])

5. 特征提取

5.1 法线估计

radius = 0.01   # 搜索半径
max_nn = 30     # 邻域内用于估算法线的最大点数
pcd.estimate_normals(search_param=o3d.geometry.KDTreeSearchParamHybrid(radius, max_nn))     # 执行法线估计
o3d.visualization.draw_geometries([pcd], point_show_normal=True)

6.分割

6.1 DBSCAN聚类分割

eps = 0.5           # 同一聚类中最大点间距
min_points = 50     # 有效聚类的最小点数
with o3d.utility.VerbosityContextManager(o3d.utility.VerbosityLevel.Debug) as cm:
    labels = np.array(pcd.cluster_dbscan(eps, min_points, print_progress=True))
max_label = labels.max()    # 获取聚类标签的最大值 [-1,0,1,2,...,max_label],label = -1 为噪声,因此总聚类个数为 max_label + 1
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  # labels = -1 的簇为噪声,以黑色显示
pcd.colors = o3d.utility.Vector3dVector(colors[:, :3])
o3d.visualization.draw_geometries([pcd])

6.2 RANSAC平面分割

distance_threshold = 0.2    # 内点到平面模型的最大距离
ransac_n = 3                # 用于拟合平面的采样点数
num_iterations = 1000       # 最大迭代次数

# 返回模型系数plane_model和内点索引inliers,并赋值
plane_model, inliers = pcd.segment_plane(distance_threshold, ransac_n, num_iterations)

# 输出平面方程
[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([0, 0, 1.0])

# 平面外点点云
outlier_cloud = pcd.select_by_index(inliers, invert=True)
outlier_cloud.paint_uniform_color([1.0, 0, 0])

6.3 隐藏点剔除

diameter = np.linalg.norm(np.asarray(pcd.get_max_bound()) - np.asarray(pcd.get_min_bound()))
camera = [0, 0, diameter]       # 视点位置
radius = diameter * 100         # 噪声点云半径,The radius of the sperical projection
_, pt_map = pcd.hidden_point_removal(camera, radius)    # 获取视点位置能看到的所有点的索引 pt_map

7. 曲面重建

7.1 Alpha shapes

alpha = 0.03
print(f"alpha={alpha:.3f}")
mesh = o3d.geometry.TriangleMesh.create_from_point_cloud_alpha_shape(pcd, alpha)
mesh.compute_vertex_normals()
o3d.visualization.draw_geometries([mesh], mesh_show_back_face=True)

7.2 Ball pivoting

# ---------------------- 定义点云体素化函数 ----------------------
def get_mesh(_relative_path):
    mesh = o3d.io.read_triangle_mesh(_relative_path)
    mesh.compute_vertex_normals()
    return mesh
# =============================================================

# ------------------------- Ball pivoting --------------------------
print("->Ball pivoting...")
_relative_path = "bunny.ply"    # 设置相对路径
N = 2000                        # 将点划分为N个体素
pcd = get_mesh(_relative_path).sample_points_poisson_disk(N)
o3d.visualization.draw_geometries([pcd])

radii = [0.005, 0.01, 0.02, 0.04]
rec_mesh = o3d.geometry.TriangleMesh.create_from_point_cloud_ball_pivoting(pcd, o3d.utility.DoubleVector(radii))
o3d.visualization.draw_geometries([pcd, rec_mesh])
# ==============================================================

7.3 Poisson surface reconstruction

  • create_from_point_cloud_poisson

  • depth 定义了用于曲面重建的八叉树的深度,表示生成的三角形网格的分辨率。depth值越高,网格的细节就越多。

  • 直接读取

print('run Poisson surface reconstruction')
radius = 0.001   # 搜索半径
max_nn = 30         # 邻域内用于估算法线的最大点数
pcd.estimate_normals(search_param=o3d.geometry.KDTreeSearchParamHybrid(radius, max_nn))     # 执行法线估计

with o3d.utility.VerbosityContextManager(o3d.utility.VerbosityLevel.Debug) as cm:
    mesh, densities = o3d.geometry.TriangleMesh.create_from_point_cloud_poisson(pcd, depth=12)
print(mesh)
o3d.visualization.draw_geometries([mesh])
  • mesh方法
import open3d as o3d
import numpy as np

# -------------------------- 定义点云体素化函数 ---------------------------
def get_mesh(_relative_path):
    mesh = o3d.io.read_triangle_mesh(_relative_path)
    mesh.compute_vertex_normals()
    return mesh
# =====================================================================

# -------------------- Poisson surface reconstruction ------------------
# 加载点云
print("->Poisson surface reconstruction...")
_relative_path = "bunny.ply"    # 设置相对路径
N = 5000                        # 将点划分为N个体素
pcd = get_mesh(_relative_path).sample_points_poisson_disk(N)
pcd.normals = o3d.utility.Vector3dVector(np.zeros((1, 3)))  # 使现有法线无效

# 法线估计
pcd.estimate_normals()
o3d.visualization.draw_geometries([pcd], point_show_normal=True)
pcd.orient_normals_consistent_tangent_plane(100)
o3d.visualization.draw_geometries([pcd], point_show_normal=True)

# 泊松重建
print('run Poisson surface reconstruction')
with o3d.utility.VerbosityContextManager(
        o3d.utility.VerbosityLevel.Debug) as cm:
    mesh, densities = o3d.geometry.TriangleMesh.create_from_point_cloud_poisson(
        pcd, depth=9)
print(mesh)
o3d.visualization.draw_geometries([mesh])
# =====================================================================

8. 空间转换

8.1 Translate 平移

# true实现点云平移,false点云质心平移到第一个参数指定的位置
pcd.translate((tx,ty,tz),relative=True)

8.2 Rotation 旋转

pcd.rotate(R)     # 不指定旋转中心 绕质心旋转
pcd.rotate(R,center=(x,y,z)) # 指定旋转中心

8.3 Scale 缩放

pcd_scale.rotate(2,center=pcd.get_center())  # 缩放前后质心一致
pcd_scale.rotate(2,center=(x,y,z))   # 缩放后质心为(x,y,z)

8.4 General transformation (平移+旋转)

  • 4×4变换矩阵,前3行3列为旋转矩阵,第4列前3行为平移向量
T = np.eye(4)
T[ :3, :3] = pcd.get_rotation_matrix_from_xyz((np.pi/6,np.pi/4,0)) # 旋转矩阵
T[0,3] = 5.0 # 平移向量的dx
T[1,3] = 3.0 # 平移向量的dy
pcd_T.transform(T)
pcd_T.paint_uniform_color([0,0,1])

9. 配准

10. 常用算法

10.1 计算点云距离

  • 源点云中的每个点计算到目标点云中最近点的距离
dists = pcd1.compute_point_cloud_distance(pcd2)
dists = np.asarray(dists)

10.2 最小包围盒

# 轴向最小包围盒 AABB盒
aabb = pcd.get_axis_aligned_bounding_box()
# 最小包围盒 obb盒
obb = pcd.get_oriented_bounding_box()

10.3 计算凸包

hull, _ = pcd.compute_convex_hull()
hull_ls = o3d.geometry.LineSet.create_from_triangle_mesh(hull)

10.4 点云体素化

voxel_grid = o3d.geometry.VoxelGrid.create_from_point_cloud(pcd, voxel_size=0.005)

10.5 计算点云质心

pcd.get_center()

10.6 根据索引提取点云

inlier_pcd = pcd.select_by_index(self, indices, invert=False)
outlier_pcd = pcd.select_by_index(idx, invert=True)     # 对索引取反

10.7 点云赋色

# 将点云进行单一颜色赋值 RGB范围[0,1]
pcd.paint_uniform_color([1,0.706,0])

你可能感兴趣的:(点云,python)