当前位置: 首页 > 工具软件 > Open Diameter > 使用案例 >

open3D点云操作

白学
2023-12-01

open3D一些知识点和操作

首先贴上可以运行的完整代码(包括注释),如果有什么需要再了解的,可以继续看下去。

import open3d as o3d
import numpy as np
from matplotlib import pyplot as plt
"""点云可视化"""
print("Load a ply point cloud, print it, and render it")
pcd = o3d.io.read_point_cloud("./bunny.ply")#读取ply点云数据
#print(pcd)
#print(np.asarray(pcd.points))#将pcd数据转化为numpy数组
#o3d.visualization.draw_geometries([pcd])
"""体素下采样"""
#print("Downsample the point cloud with a voxel of 0.0")
#downpcd = pcd.voxel_down_sample(voxel_size=0.0001)#体素下采样,voxel_size越大,采的点越少
#o3d.visualization.draw_geometries([downpcd])
"""顶点法线估计"""
#print("Recompute the normal of the downsampled point cloud")
#pcd.estimate_normals(search_param=o3d.geometry.KDTreeSearchParamHybrid(radius=0.1, max_nn=30))
#o3d.visualization.draw_geometries([pcd])
"""裁剪点云"""
#print("Load a polygon volume and use it to crop the original point cloud")
#vol = o3d.visualization.read_selection_polygon_volume("../../TestData/Crop/cropped.json")#读取一个指定多边形区域的json文件。
#chair = vol.crop_point_cloud(pcd)#vol.crop_point_cloud(pcd)过滤掉点,只保留椅子部分。
#o3d.visualization.draw_geometries([chair])
"""点云上色"""
#print("Paint chair")
#pcd.paint_uniform_color([1, 0.706, 0])#paint_uniform_color给所有的点上一个统一的颜色,颜色是在RGB空间得[0,1]范围内得值。
#o3d.visualization.draw_geometries([pcd])
""""包围框"""
#aabb = pcd.get_axis_aligned_bounding_box()#返回一个轴对齐的几何体边界框
#aabb.color = (1,0,0)
#obb = pcd.get_oriented_bounding_box()#返回一个几何图形的定向包围盒
#obb.color = (0,1,0)
#o3d.visualization.draw_geometries([pcd, aabb, obb])
"""凸包"""
#hull, _ = pcd.compute_convex_hull()#计算凸包的方法:compute_convex_hull.这个接口的实现基于Qhull
#hull_ls = o3d.geometry.LineSet.create_from_triangle_mesh(hull)
#hull_ls.paint_uniform_color((1, 0, 0))
#o3d.visualization.draw_geometries([pcd, hull_ls])
"""DBSCAN 聚类 基于密度的聚类算法"""
#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[:, 0:3])#给点云赋予颜色,提取1,2,3列
#o3d.visualization.draw_geometries([pcd])
"""
        平面分割
destance_threshold定义了一个点到一个估计平面的最大距离,这些距离内的点被认为是内点(inlier)
ransac_n定义了使用随机抽样估计一个平面的点的个数
num_iterations定义了随机平面采样和验证的频率(迭代次数)

返回(a,b,c,d)作为一个平面,对于平面上每个点(x,y,z)我们有ax+by+cz+d=0。
这个函数还会返回内点索引的列表。
"""
#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])
"""隐点移除"""
#print("Convert mesh to a point cloud and estimate dimensions")
#diameter = np.linalg.norm(np.asarray(pcd.get_max_bound()) - np.asarray(pcd.get_min_bound()))
#o3d.visualization.draw_geometries([pcd])
#
#
#print("Define parameters used for hidden_point_removal")
#camera = [0, 0, diameter]
#radius = diameter * 100
#
#print("Get all points that are visible from given view point")
#_, pt_map = pcd.hidden_point_removal(camera, radius)
#
#print("Visualize result")
#pcd = pcd.select_by_index(pt_map)
#o3d.visualization.draw_geometries([pcd])
"""KDTree最近邻域搜索"""
print("Testing kdtree in open3d ...")
print("Load a point cloud and paint it gray.")
pcd.paint_uniform_color([0.5, 0.5, 0.5])#画成灰色
pcd_tree = o3d.geometry.KDTreeFlann(pcd)#构建一个KDTree类
print("Paint the 1500th point red.")
pcd.colors[1500] = [1, 0, 0]#把第1500个点画成红色
print("Find its neighbors with distance less than 0.2, paint green.")
[k, idx, _] = pcd_tree.search_radius_vector_3d(pcd.points[1500], 0.02)#参数1:锚点;参数2:搜索半径。获得所有的和锚点距离小于给定半径的点索引
#print(np.asarray(idx).shape)#idx为一维数组
np.asarray(pcd.colors)[idx[1:], :] = [0, 1, 0]#寻址,将这些点涂成绿色
print("Visualize the point cloud.")
o3d.visualization.draw_geometries([pcd])

PointCloud类:点云由点坐标、可选的点颜色和点法线组成。

定义的数据描述符:
colors
float64 array of shape (num_points, 3), range [0, 1] , use numpy.asarray() to access data: 点的三色
normals
float64 array of shape (num_points, 3), use numpy.asarray() to access data: 法线
points
float64 array of shape (num_points, 3), use numpy.asarray() to access data: 点坐标
函数方法:

normalize_normals(...)
     normalize_normals(self)
     将点法线归一化为长度1。
     Returns:
          None
paint_uniform_color(...)
	paint_uniform_color(self, color)
	给点云中的每个点赋予相同的颜色。
    Args:
       color (numpy.ndarray[float64[3, 1]]): RGB color for the PointCloud.
    Returns:
        None

Vector3dVector(pybind11_builtins.pybind11_object)类

将 float64 numpy 数组的“(n,3)”转换为 open3d 格式。

	# From numpy to Open3D
	pcd.points = open3d.utility.Vector3dVector(np_points)
	# From Open3D to numpy
	np_points = np.asarray(pcd.points)

支持的点云类型:

xyz	每一行包括 [x,y,z] 三个值,x,y,z 是三维坐标
xyzn	每一行包括 [x,y,z,nx,ny,nz] 六个值,其中nx,ny,nz 是法线
xyzrgb	每一行包括 [x,y,z,r,g,b] 六个值,这里r,g,b的范围在[0,1]浮动
pts	第一行是一个整数,表示点的个数。之后每一行包括 [x,y,z,i,r,g,b] 七个值,其中rgb的类型为uint8
ply	这个格式可以包含点云和网格数据
pcd	

可视化点云

print("Load a ply point cloud, print it, and render it")
pcd = o3d.io.read_point_cloud("../../TestData/fragment.ply")
print(pcd)
print(np.asarray(pcd.points))
o3d.visualization.draw_geometries([pcd], zoom=0.3412,
                                  front=[0.4257, -0.2125, -0.8795],
                                  lookat=[2.6172, 2.0475, 1.532],
                                  up=[-0.0694, -0.9768, 0.2024])

read_point_cloud 用来读取点云数据。他尝试通过文件扩展名来解码文件。
draw_geometries 可视化点云数据。使用鼠标可以查看不同视角的数据。

在GUI窗口按 h 键可以输出所有快捷键的列表。

体素降采样

体素降采样通过使用规则体素网格从输入点云创造一致化降采样点云。这通常在点云处理任务的预处理步骤,这个算法分为两步:

  1. 把点云装进体素网格
  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], zoom=0.3412,
                                 front=[0.4257, -0.2125, -0.8795],
                                 lookat=[2.6172, 2.0475, 1.532],
                                 up=[-0.0694, -0.9768, 0.2024])
voxel_down_sample(...)
    voxel_down_sample(self, voxel_size)
    用一个体素对输入点云下采样。法线和颜色会被均值化。
    Args:
        voxel_size (float): 下采样的体素尺寸
    Returns:
        open3d.cpu.pybind.geometry.PointCloud

o3d.geometry.KDTreeSearchParamHybrid(radius=0.1, max_nn=30)):混合 knn 和半径搜索的 kdtree 搜索参数。

两个参数:

  max_nn
      最大值,“ max _ nn”的邻域将被检查
  radius
      搜索半径

包围框

get_axis_aligned_bounding_box(...)
    get_axis_aligned_bounding_box(self)
    返回一个轴对齐的几何体边界框。
    Returns:
        open3d.geometry.AxisAlignedBoundingBox
        
get_oriented_bounding_box(...)
    get_oriented_bounding_box(self)
    返回一个几何图形的定向包围盒。
    Returns:
        open3d.geometry.OrientedBoundingBox

VerbosityContextManager类

class VerbosityContextManager(pybind11_builtins.pybind11_object)
 |  一个上下文管理器来暂时改变 open3d 的冗长级别
 |  Method resolution order:
 |      VerbosityContextManager
 |      pybind11_builtins.pybind11_object
 |      builtins.object
 |  Methods defined here:
 |  __enter__(...)
 |      __enter__(self: open3d.cpu.pybind.utility.VerbosityContextManager) -> None
 |      Enter the context manager
 |  __exit__(...)
 |      __exit__(self: open3d.cpu.pybind.utility.VerbosityContextManager, arg0: object, arg1: object, arg2: object) -> None
 |      Exit the context manager
 |  __init__(...)
 |      __init__(self: open3d.cpu.pybind.utility.VerbosityContextManager, level: open3d.cpu.pybind.utility.VerbosityLevel) -> None
 |      Create a VerbosityContextManager with a given VerbosityLevel

cluster_dbscan聚类算法百度百科

cluster_dbscan(...)
    cluster_dbscan(self, eps, min_points, print_progress=False)
    Cluster PointCloud using the DBSCAN algorithm  Ester et al., 'A Density-Based Algorithm for Discovering Clusters in Large Spatial Databases with Noise', 1996. Returns a list of point labels, -1 indicates noise according to the algorithm.
    参数:
        eps (float): 用于寻找邻近点的密度参数。
        min_points (int): 形成群集的最小点数。
        print_progress (bool, optional, default=False): 如果是True,进度会在控制台上显示出来。
    Returns:
        open3d.cpu.pybind.utility.IntVector

平面分割使用RANSAC从点云中分割几何基元

"""
        平面分割
destance_threshold定义了一个点到一个估计平面的最大距离,这些距离内的点被认为是内点(inlier)
ransac_n定义了使用随机抽样估计一个平面的点的个数
num_iterations定义了随机平面采样和验证的频率(迭代次数)

返回(a,b,c,d)作为一个平面,对于平面上每个点(x,y,z)我们有ax+by+cz+d=0。
这个函数还会返回内点索引的列表。
"""
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])

隐点移除hidden_point_removal(…)

hidden_point_removal(...)
    hidden_point_removal(self, camera_location, radius)
    移除点云中的隐藏点并返回剩余点的网格。 'Direct Visibility of Point Sets', 2007. 关于噪音点云半径选择的其他信息可以在 mehra 等人的文章中找到。 'Visibility of Noisy Point Cloud Data', 2010.
    参数:
        camera_location (numpy.ndarray[float64[3, 1]]): 所有在那个位置看不见的地点都会被移除
        radius (float): 球投影的半径
    Returns:
        Tuple[open3d.geometry.TriangleMesh, List[int]]

画线的区别

要画线的话,需要定义Lineset和创造一组点还有一组边。边是一对点的索引。下面的例子中创建了自定义的点和边(表示为线(lines))来创建一个立方体。颜色是可选的,在这个例子中每条边表示为红色。这个脚本可视化的下面的立方体。

print("Let's draw a cubic using o3d.geometry.LineSet.")
points = [
        [0, 0, 0],
        [1, 0, 0],
        [0, 1, 0],
        [1, 1, 0],
        [0, 0, 1],
        [1, 0, 1],
        [0, 1, 1],
        [1, 1, 1],
]
lines = [
        [0, 1],#这里就是指0点指向1点的一条线
        [0, 2],
        [1, 3],
        [2, 3],
        [4, 5],
        [4, 6],
        [5, 7],
        [6, 7],
        [0, 4],
        [1, 5],
        [2, 6],
        [3, 7],
]
colors = [[1, 0, 0] for i in range(len(lines))]
line_set = o3d.geometry.LineSet(
    points=o3d.utility.Vector3dVector(points),
    lines=o3d.utility.Vector2iVector(lines),#索引转化为open3d中的线的表示
)
line_set.colors = o3d.utility.Vector3dVector(colors)#线的颜色
o3d.visualization.draw_geometries([line_set])

Open3d使用FLANN构建KDTree以便进行快速最近邻检索

print("Testing kdtree in open3d ...")
print("Load a point cloud and paint it gray.")
pcd.paint_uniform_color([0.5, 0.5, 0.5])#画成灰色
pcd_tree = o3d.geometry.KDTreeFlann(pcd)#构建一个KDTree类
print("Paint the 1500th point red.")
pcd.colors[1500] = [1, 0, 0]#把第1500个点画成红色
print("Find its neighbors with distance less than 0.2, paint green.")
[k, idx, _] = pcd_tree.search_radius_vector_3d(pcd.points[1500], 0.02)#参数1:锚点;参数2:搜索半径。获得所有的和锚点距离小于给定半径的点索引
#print(np.asarray(idx).shape)#idx为一维数组
np.asarray(pcd.colors)[idx[1:], :] = [0, 1, 0]#寻址,将这些点涂成绿色
print("Visualize the point cloud.")
o3d.visualization.draw_geometries([pcd])
 类似资料: