接着上一节点云1
本节数据地址:链接:https://pan.baidu.com/s/1O4s8tFOvExhuKMl2OCv4Kg
提取码:82u1
先上代码
import open3d as o3d
pcd=o3d.io.read_point_cloud("./test_data/Crop/fragment.ply")
val=o3d.visualization.read_selection_polygon_volume("./test_data/Crop/cropped.json")
chair=val.crop_point_cloud(pcd)
o3d.visualization.draw_geometries([chair],
zoom=0.7,
front=[0.5439, -0.2333, -0.8060],
lookat=[2.4615, 2.1331, 1.338],
up=[-0.1781, -0.9708, 0.1608])
o3d.visualization.read_selection_polygon_volume函数能够根据读入的文件初始化一个o3d.visualization.SelectionPolygonVolume(),这个对象用于裁剪点云。该对象的crop_point_cloud方法用于裁剪点云,输入即是需要裁剪的点云。
import open3d as o3d
pcd=o3d.io.read_point_cloud("../test_data/Crop/fragment.ply")
vol=o3d.visualization.read_selection_polygon_volume("../test_data/Crop/cropped.json")
chair=vol.crop_point_cloud(pcd)
aadd=chair.get_axis_aligned_bounding_box()
aadd.color=(1,0,0)
obb=chair.get_oriented_bounding_box()
obb.color=(0,1,0)
o3d.visualization.draw_geometries([chair,aadd,obb],
zoom=0.7,
front=[0.5439, -0.2333, -0.8060],
lookat=[2.4615, 2.1331, 1.338],
up=[-0.1781, -0.9708, 0.1608]
)
这里我们先将点云中的椅子裁剪下来,然后计算椅子的两种边界框。点云对象的get_axis_aligned_bounding_box方法计算点云的最小轴对齐边界框。get_oriented_bounding_box方法返回几何图形的定向边界框。这两个方法均返回o3d.geometry.AxisAlignedBoundingBox对象,用于记录边界框的对象。
点云的凸壳是包含所有点的最小凸集,Open3D 包含计算点云的凸壳的方法。该实现基于Qhull。
import open3d as o3d
pcl = o3d.io.read_triangle_mesh("./test_data/bun_zipper.ply")
o3d.visualization.draw_geometries([pcl],window_name="mesh",width=810,height=520)
pcl=pcl.sample_points_poisson_disk(number_of_points=2000)
o3d.visualization.draw_geometries([pcl],window_name="pointcloud",width=810,height=520)
#创建凸包,返回的是凸包顶点
hull, _ = pcl.compute_convex_hull()
#给凸包顶点连线
hull_ls = o3d.geometry.LineSet.create_from_triangle_mesh(hull)
hull_ls.paint_uniform_color((1, 0, 0))
o3d.visualization.draw_geometries([pcl, hull_ls])
代码解析:o3d.io.read_triangle_mesh用于读取三角网格数据。然后我们可视化一下三角网格数据。使用三角网格对象的sample_points_poisson_disk方法将三角网格采样成点云,输入参数就是采样后点云的点数。再用点云对象的compute_convex_hull方法计算点云的凸包。然后使用o3d.geometry.LineSet.create_from_triangle_mesh函数从凸包创建线集。最后将线集渲染成红色的。
给定来自例如深度传感器的点云,我们希望将点云集群组合在一起。为此,我们可以使用聚类算法。Open3D实现了DBSCAN,这是一种基于密度的聚类算法。
代码如下:
import open3d as o3d
import numpy as np
import matplotlib.pyplot as plt
pcd=o3d.io.read_point_cloud("./test_data/fragment.ply")
o3d.visualization.draw_geometries([pcd],window_name="before cluster",width=810,height=520,
zoom=0.455,
front=[-0.4999, -0.1659, -0.8499],
lookat=[2.1813, 2.0619, 2.0999],
up=[0.1204, -0.9852, 0.1215])
with o3d.utility.VerbosityContextManager(o3d.utility.VerbosityLevel.Debug) as cm:
label=np.array(pcd.cluster_dbscan(eps=0.02,min_points=10,print_progress=True))
#聚类数
max_label=label.max()
print(f"point cloud has {max_label + 1} clusters")
colors=plt.get_cmap("tab20")(label/(max_label if max_label>0 else 1))
colors[label<0]=0
pcd.colors=o3d.utility.Vector3dVector(colors[:,:3])
o3d.visualization.draw_geometries([pcd],window_name="after cluster",width=810,height=520,
zoom=0.455,
front=[-0.4999, -0.1659, -0.8499],
lookat=[2.1813, 2.0619, 2.0999],
up=[0.1204, -0.9852, 0.1215]
)
代码解析:
其中o3d.utility.VerbosityContextManager对象是open3d的上下文管理器。点云对象的cluster_dbscan方法实现了DBSCAN 聚类。
cluster_dbscan方法的参数:
eps:用于查找属于一个聚类的密度参数
min_points:形成一个聚类的最小点数。
然后获取聚类数,利用plt.get_cmap给每个聚类渲染不同的颜色。
我们使用RANSAC 对点云中的几何基元进行分割,找出点云中的最大支持平面。
代码如下:
import open3d as o3d
pcd=o3d.io.read_point_cloud("./test_data/fragment.pcd")
o3d.visualization.draw_geometries([pcd],window_name="初始点云",
width=810,height=520,
zoom=0.8,
front=[-0.4999, -0.1659, -0.8499],
lookat=[2.1813, 2.0619, 2.0999],
up=[0.1204, -0.9852, 0.1215])
#平面估计,返回估计出的平面参数和点云平面的索引
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])
o3d.visualization.draw_geometries([inlier_cloud],window_name="inlier_cloud",
width=810,height=520,
zoom=0.8,
front=[-0.4999, -0.1659, -0.8499],
lookat=[2.1813, 2.0619, 2.0999],
up=[0.1204, -0.9852, 0.1215])
#平面以外的点
outlier_cloud=pcd.select_by_index(inliers,invert=True)
o3d.visualization.draw_geometries([outlier_cloud],window_name="outlier_cloud",
width=810,height=520,
zoom=0.8,
front=[-0.4999, -0.1659, -0.8499],
lookat=[2.1813, 2.0619, 2.0999],
up=[0.1204, -0.9852, 0.1215])
o3d.visualization.draw_geometries([inlier_cloud,outlier_cloud],window_name="after",
width=810,height=520,
zoom=0.8,
front=[-0.4999, -0.1659, -0.8499],
lookat=[2.1813, 2.0619, 2.0999],
up=[0.1204, -0.9852, 0.1215]
)
代码解析:
点云对象的segment_plane方法使用RANSAC算法在点云中分割平面。
参数如下:
distance_threshold:点云与平面的小于这个距离,这个点被视为平面的内点
ransac_n: 每次迭代中要考虑内联的初始点的数量
num_iterations:迭代数
seed:随机生成器中使用的种子值
这个函数返回的是一个元组,第一个元素是平面的参数,第二个元素是点云最大支撑面的点索引组成的列表。
然后我们使用点云对象的select_by_index方法将最大支撑平面部分的点云拿出来。这个方法的第一个参数就是点云索引,第二个参数invert为True的时候是反向索引,索引出输入的点云索引以外的点。
我们将最大支撑平面渲染成红色。
简单来说就是从一个视点观察点云,移除看不到的点
代码如下:
import open3d as o3d
import numpy as np
#三角网格的方式加载点云
pcd=o3d.io.read_triangle_mesh("./test_data/Armadillo.ply")
#估计三角网格的法线
pcd.compute_vertex_normals()
#将三角网格采样成点云
pcd=pcd.sample_points_poisson_disk(5000)
#计算范数,几何最大边界和最小边界
diameter=np.linalg.norm(np.asarray(pcd.get_max_bound())-np.asarray(pcd.get_min_bound()))
o3d.visualization.draw_geometries([pcd],window_name="初始点云",
width=810,height=520,
zoom=0.8,
front=[-0.4999, -0.1659, -0.8499],
lookat=[2.1813, 2.0619, 2.0999],
up=[0.1204, -0.9852, 0.1215])
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")
_,ptmap=pcd.hidden_point_removal(camera,radius)
pcd=pcd.select_by_index(ptmap)
o3d.visualization.draw_geometries([pcd],window_name="after",
width=810,height=520,
zoom=0.8,
front=[-0.4999, -0.1659, -0.8499],
lookat=[2.1813, 2.0619, 2.0999],
up=[0.1204, -0.9852, 0.1215])
代码解析:
三角网格对象的compute_vertex_normals方法用于估计三角网格的顶点法线。
点云对象的hidden_point_removal方法实现了隐藏点移除
参数如下:
camera_location:就是视点
radius:投影半径
这个函数返回的也是一个元组,元组的第二个元素就是从给定视点能看见的所有点的索引,然后我们将能看见的点云索引出来。