DBSCAN聚类算法,是基于密度的聚类算法。该算法需要两个参数。
labels = np.array(pcd.cluster_dbscan(eps=0.02, min_points=10, print_progress=True))
入参:
- eps: 定义到聚类邻居的距离
- min_points: 定义形成聚类所需的最小点数。
出参:
- 该函数返回一个标签,其中标签-1表示噪音。
该算法定义以选中的点开始蔓延,邻居点距离<=0.02米,最小有10个点就可以构成一个簇;适用于原始点云分隔的比较开的,有明显界限的点云。
原始点云被分成了10个聚簇,每个聚簇不同的颜色,只有3个聚簇的点数比较巨大,明显一些。另外右边角落有一块比较小的片段。
点云聚类后分类别提取及可视化效果图如下:
控制台输出:
PointCloud with 196133 points.
[Open3D DEBUG] Precompute neighbors.
[Open3D DEBUG] Done Precompute neighbors.
[Open3D DEBUG] Compute Clusters
Precompute neighbors.[========================================] 100%
[Open3D DEBUG] Done Compute Clusters: 10
point cloud has 10 clusters
[0 0 0 ... 2 2 2] 196133
min: -1 max: 9
(array([ 23, 24, 25, ..., 196130, 196131, 196132], dtype=int64),) type: <class 'tuple'> size: 190176
PointCloud with 5957 points.
zero_index: (array([ 0, 1, 2, ..., 38888, 38889, 39501], dtype=int64),) size: 5957
label: -1 点云数: 109
label: 0 点云数: 5957
label: 1 点云数: 25136
label: 2 点云数: 150429
label: 3 点云数: 11
label: 4 点云数: 24
label: 5 点云数: 14352
label: 6 点云数: 65
label: 7 点云数: 12
label: 8 点云数: 10
label: 9 点云数: 28
#
# 该算法需要两个参数。
# -eps: 定义到聚类邻居的距离
# -min_points: 定义形成聚类所需的最小点数。
# 该函数返回一个标签,其中标签-1表示噪音。>
import open3d as o3d
import matplotlib.pyplot as plt
import numpy as np
path = "./fragment.ply"
print(path)
pcd = o3d.io.read_point_cloud(path)
print(pcd)
# 定义以选中的点开始蔓延,邻居点距离0.02米的,最小有10个点,可以构成一个簇;适用于点云分隔的比较开的,一块一块的点云。
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], "o3d dbscanclusting origin", width=400, height=400)
print(labels, len(labels))
min = labels.min()
max = labels.max()
# print('min: ', min, " max: ", max)
# 打印聚类非0的点云下标,点云数
print(np.nonzero(labels), ' type: ', type(np.nonzero(labels)), ' size: ', len(np.array(np.nonzero(labels)[0])))
zero_index = np.where(labels == 0) # 提取分类为0的聚类点云下标
zero_pcd = pcd.select_by_index(np.array(zero_index)[0]) # 根据下标提取点云点
print(zero_pcd)
print('zero_index: ', zero_index, " size: ", len(np.array(zero_index)[0]))
for label in range(min, max+1):
label_index = np.where(labels == label) # 提取分类为label的聚类点云下标
label_pcd = pcd.select_by_index(np.array(label_index)[0]) # 根据下标提取点云点
print('label: ', str(label), '点云数:', len(label_pcd.points))
# 可视化
o3d.visualization.draw_geometries([label_pcd], "o3d dbscanclusting " + str(label) + " results", width=400,
height=400)
# 分别按分类写入文件
o3d.io.write_point_cloud("./" + str(label) + ".pcd", label_pcd)
http://www.open3d.org/docs/release/tutorial/Basic/pointcloud.html#Access-estimated-vertex-normal