当前位置:   article > 正文

open3d-点云及其操作_open3d.cpu.pybind.geometry.pointcloud

open3d.cpu.pybind.geometry.pointcloud

open3d提供了一个专门用于点云的数据结构 PointCloud

  1. class PointCloud(Geometry3D):
  2. color # 颜色
  3. normals # 法向量
  4. points # 点云
  5. def __init__(self, *args, **kwargs):
  6. """
  7. __init__(*args, **kwargs)
  8. Overloaded function.
  9. 1. __init__(self: open3d.cpu.pybind.geometry.PointCloud) -> None
  10. Default constructor
  11. 2. __init__(self: open3d.cpu.pybind.geometry.PointCloud, arg0: open3d.cpu.pybind.geometry.PointCloud) -> None
  12. Copy constructor
  13. 3. __init__(self: open3d.cpu.pybind.geometry.PointCloud, points: open3d.cpu.pybind.utility.Vector3dVector) -> None
  14. Create a PointCloud from points
  15. """
  16. # dbscan聚类
  17. def cluster_dbscan(self, eps, min_points, print_progress=False):
  18. # 计算凸包
  19. def compute_convex_hull(self):
  20. # 计算马氏距离。 返回每个点的马氏距离
  21. def compute_mahalanobis_distance(self):
  22. # 计算均值与协方差矩阵
  23. def compute_mean_and_covariance(self):
  24. # 计算点云每个点到其最近点的距离
  25. def compute_nearest_neighbor_distance(self):
  26. # 计算当前点云每个点到目标点云的最近距离
  27. def compute_point_cloud_distance(self, target):
  28. def create_from_depth_image(self, depth, intrinsic, extrinsic, *args, **kwargs):
  29. def create_from_rgbd_image(self, image, intrinsic, extrinsic, *args, **kwargs):
  30. # 裁剪。 输入一个aabb框或obb框
  31. def crop(self, *args, **kwargs):
  32. # 计算顶点法向量
  33. def estimate_normals(self, search_param=None, *args, **kwargs):
  34. # 是否有color
  35. def has_colors(self):
  36. # 是否有法向量
  37. def has_normals(self):
  38. # 是否有点云点
  39. def has_points(self):
  40. # 隐藏点去除。
  41. def hidden_point_removal(self, camera_location, radius):
  42. # 归一化法向量。 法向量长度为1
  43. def normalize_normals(self):
  44. # 法向量方向一致
  45. def orient_normals_consistent_tangent_plane(self, k):
  46. # 法向量方向一致。 指定相机位置
  47. def orient_normals_towards_camera_location(self, camera_location=None, *args, **kwargs):
  48. # 法向量方向一致。 指定参考方向
  49. def orient_normals_to_align_with_direction(self, orientation_reference=None, *args, **kwargs):
  50. # 上色。 颜色rgb,范围0~1
  51. def paint_uniform_color(self, color):
  52. # 随机下采样。 指定下采样率
  53. def random_down_sample(self, sampling_ratio):
  54. # 删除non 和 inf 值的点
  55. def remove_non_finite_points(self, remove_nan=True, remove_infinite=True):
  56. # 删除指定半径内少于指定点数的点
  57. def remove_radius_outlier(self, nb_points, radius):
  58. # 删除相邻点中距离大于平均距离的点
  59. def remove_statistical_outlier(self, nb_neighbors, std_ratio):
  60. # 平面分割
  61. def segment_plane(self, distance_threshold, ransac_n, num_iterations):
  62. # 按照下标筛选点云
  63. def select_by_index(self, indices, invert=False):
  64. # 下采样。 每隔多少个点取一个
  65. def uniform_down_sample(self, every_k_points):
  66. # 体素下采样。 指定体素尺寸
  67. def voxel_down_sample(self, voxel_size):
  68. # 体素下采样并记录原数据。 指定体素尺寸
  69. def voxel_down_sample_and_trace(self, voxel_size, min_bound, max_bound, approximate_class=False):
  1. import numpy as np
  2. import open3d as o3d
  3. from open3d.web_visualizer import draw
  4. from open3d.visualization import draw_geometries
  1. pcd = o3d.io.read_point_cloud('datas/fragment.ply')
  2. draw(pcd)

1.体素下采样

open3d.geometry.PointCloud 提供了 voxel_down_sample(self, voxel_size) 方法,来进行体素下采样操作。

  1. def voxel_down_sample(self, voxel_size):
  2. """
  3. voxel_down_sample(self, voxel_size)
  4. 对输入点云进行体素下采样,如果法线和颜色存在,则法线和颜色取均值。
  5. Args:
  6. voxel_size (float): 体素尺寸
  7. Returns:
  8. open3d.geometry.PointCloud
  9. """
  1. downsample = pcd.voxel_down_sample(voxel_size=0.05)
  2. draw(downsample)

2. 顶点法向量估计

open3d.geometry.PointCloud 提供了 estimate_normals(self, voxel_size) 方法,来计算顶点法向量。

  1. def estimate_normals(self, search_param=None, *args, **kwargs):
  2. """
  3. estimate_normals(self, search_param=KDTreeSearchParamKNN with knn = 30, fast_normal_computation=True)
  4. Args:
  5. search_param (open3d.geometry.KDTreeSearchParam, optional): 用于领域搜索的KDTree搜索参数。 默认值为:KDTreeSearchParamKNN with knn = 30
  6. fast_normal_computation (bool, optional, default=True): 如果为true,通过协方差矩阵计算特征向量,速度更快,但数值不稳定。如果为False,则使用迭代方式。
  7. Returns:
  8. None 无返回值,法向量直接存储于 PointCloud.normals
  9. """

search_param 参数有:

  • class KDTreeSearchParamHybrid(KDTreeSearchParam):
    def init(self, radius, max_nn): # 搜索半径、最大近邻点数
  • class KDTreeSearchParamKNN(KDTreeSearchParam):
    def init(self, knn=30): # 近邻点数
  • class KDTreeSearchParamRadius(KDTreeSearchParam):
    def init(self, radius): # 搜索半径
  1. downsample.estimate_normals(search_param=o3d.geometry.KDTreeSearchParamHybrid(radius=0.1, max_nn=30))
  2. # 此处使用 draw_geometries绘制点云以及法线。
  3. draw_geometries([downsample], point_show_normal=True)

3. 裁剪点云

裁剪点云,首先需要确定裁剪区域

通过o3d.visualization.read_selection_polygon_volume()函数,读取一个多边形区域。

然后通过多边形裁剪点云。

  1. def read_selection_polygon_volume(filename):
  2. """
  3. read_selection_polygon_volume(filename)
  4. Function to read SelectionPolygonVolume from file
  5. Args:
  6. filename (str): The file path.
  7. Returns:
  8. open3d.visualization.SelectionPolygonVolume
  9. """
  10. pass

open3d.visualization.SelectionPolygonVolume 含有两个方法:

  • crop_point_cloud(input)
  • crop_triangle_mesh(input)
  1. # 读取多边形
  2. vol = o3d.visualization.read_selection_polygon_volume('datas/cropped.json')
  3. chair = vol.crop_point_cloud(pcd)
  4. draw(chair)

4. 点云上色

open3d.geometry.PointCloud 提供了 paint_uniform_color(self, color)方法,来为点云进行上色。

  1. def paint_uniform_color(self, color):
  2. """
  3. paint_uniform_color(self, color)
  4. Assigns each point in the PointCloud the same color.
  5. Args:
  6. color (numpy.ndarray[float64[3, 1]]):RGB颜色,值在0~1范围内
  7. Returns:
  8. open3d.geometry.PointCloud
  9. """
  10. pass
  1. chair.paint_uniform_color([1,0,0]) # 红色
  2. draw(chair)

5. 点云距离与筛选

open3d.geometry.PointCloud 提供了 compute_point_cloud_distance(self, target)方法,计算当前点云中每个点到目标点云中点的最近距离。

  1. def compute_point_cloud_distance(self, target):
  2. """
  3. Args:
  4. target (open3d.geometry.PointCloud): 目标点云
  5. Returns:
  6. open3d.utility.DoubleVector
  7. """

open3d.geometry.PointCloud 提供了 select_by_index(self, indices, invert=False)方法,通过下标来筛选点云。

  1. def select_by_index(self, indices, invert=False):
  2. """
  3. select_by_index(self, indices, invert=False)
  4. Args:
  5. indices (List[int]): 下标
  6. invert (bool, optional, default=False): 反选
  7. Returns:
  8. open3d.geometry.PointCloud
  9. """
  1. dists = pcd.compute_point_cloud_distance(chair) # 计算整体点云中,每个点到椅子点云中最近点的距离。
  2. dists = np.array(dists)
  3. ind = np.where(dists > 0.01)[0] # 获取距离大于0.01的点的下标
  4. pcd_without_chair = pcd.select_by_index(ind) # 通过下标筛选点云中点
  5. draw(pcd_without_chair)

6. 边界框

o3d.geometry.Geometry3D 提供了 get_axis_aligned_bounding_box() 方法,来获取aabb包围盒(轴对齐包围盒)

  1. def get_axis_aligned_bounding_box(self):
  2. """
  3. get_axis_aligned_bounding_box(self)
  4. Returns:
  5. open3d.geometry.AxisAlignedBoundingBox
  6. """

o3d.geometry.Geometry3D 提供了 get_oriented_bounding_box() 方法,来获取obb包围盒(有向包围盒)

  1. def get_oriented_bounding_box(self):
  2. """
  3. Returns:
  4. open3d.geometry.OrientedBoundingBox
  5. """
  1. aabb = chair.get_axis_aligned_bounding_box()
  2. print(aabb)
  3. draw([chair, aabb])

  1. obb = chair.get_oriented_bounding_box()
  2. print(obb)
  3. draw([chair, obb])

7.凸包

o3d.geometry.Geometry3D 提供了 compute_convex_hull() 方法,来获取点云的凸包。

  1. def compute_convex_hull(self):
  2. """
  3. Returns:
  4. Tuple[open3d.geometry.TriangleMesh, List[int]] 返回两个值,第一个以三角形网格返回凸包,第二个返回凸包的顶点下标。
  5. """
  1. hull, ind = chair.compute_convex_hull()
  2. hull.paint_uniform_color([1,0,0])
  3. draw([hull, chair])

  1. chair.paint_uniform_color([0.5,0.5,0.5])
  2. points = chair.select_by_index(ind) # 红色点为凸包顶点
  3. points.paint_uniform_color([1,0,0])
  4. draw([chair, points])

8. dbscan聚类

open3d.geometry.PointCloud 提供了 cluster_dbscan(self, eps, min_points, print_progress=False) 方法,实现dbscan密度聚类。

  1. def cluster_dbscan(self, eps, min_points, print_progress=False):
  2. """
  3. cluster_dbscan(self, eps, min_points, print_progress=False)
  4. Args:
  5. eps (float):密度
  6. min_points (int): 形成簇的最小点数
  7. print_progress (bool, optional, default=False):
  8. Returns:
  9. open3d.utility.IntVector label值,int
  10. """
  1. from matplotlib import pyplot as plt
  2. labels = pcd.cluster_dbscan(eps=0.02, min_points=10, print_progress=True)
  3. labels = np.asarray(labels)
  4. max_label = labels.max()
  5. colors = plt.get_cmap("tab20")(labels / (max_label if max_label > 0 else 1))
  6. colors[labels < 0] = 0
  7. pcd.colors = o3d.utility.Vector3dVector(colors[:, :3])
  8. draw(pcd)

9. 平面分割

open3d.geometry.PointCloud 提供了 **segment_plane(self, distance_threshold, ransac_n, num_iterations)** 方法,通过RANSAC从点云中分割平面。
  1. def segment_plane(self, distance_threshold, ransac_n, num_iterations):
  2. """
  3. Args:
  4. distance_threshold (float): 点到面的最大距离
  5. ransac_n (int): 随机采样估计平面的点数
  6. num_iterations (int): 迭代次数
  7. Returns:
  8. Tuple[numpy.ndarray[float64[4, 1]], List[int]]
  9. """
  1. pcd = o3d.io.read_point_cloud('datas/fragment.ply')
  2. plane_model, ind = pcd.segment_plane(distance_threshold=0.01, ransac_n=3, num_iterations=1000)
  3. plane = pcd.select_by_index(ind)
  4. plane.paint_uniform_color([1,0,0])
  5. without_plane = pcd.select_by_index(ind, True)
  6. draw([plane, without_plane])

10. 隐藏点去除

open3d.geometry.PointCloud 提供了 hidden_point_removal(self, camera_location, radius) 方法。

  1. def hidden_point_removal(self, camera_location, radius):
  2. """
  3. Args:
  4. camera_location (numpy.ndarray[float64[3, 1]]): All points not visible from that location will be reomved
  5. radius (float): The radius of the sperical projection
  6. Returns:
  7. Tuple[open3d.geometry.TriangleMesh, List[int]]
  8. """
  1. diameter = np.linalg.norm(np.asarray(pcd.get_max_bound()) - np.asarray(pcd.get_min_bound()))
  2. camera = [0, 0, diameter]
  3. radius = diameter * 100
  4. _, pt_map = pcd.hidden_point_removal(camera, radius)
  5. pcd = pcd.select_by_index(pt_map)
  6. draw(pcd)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/95601
推荐阅读
  

闽ICP备14008679号