目录
前期试读,后续会将博客加入该专栏,欢迎订阅
Open3D与点云深度学习的应用_白葵新的博客-CSDN博客
一、DBSCAN基本原理
DBSCAN(Density-Based Spatial Clustering of Applications with Noise)是一种基于密度的聚类算法,能够识别任意形状的聚类,并处理噪声数据。
其工作原理如下:
1.核心点(Core Point):
- 对于数据集中的每个点,如果在其 ε 邻域内包含至少 minPts 个点,则该点被标记为核心点。
2.密度直达(Density Reachable):
- 如果点 q 在点 p 的 ε 邻域内,并且 p 是一个核心点,则称 q 是从 p 密度直达的。
3.密度可达(Density Connected):
- 如果存在一个点链 p1, p2, ..., pn,其中 p1 = p 且 pn = q,并且对于每对相邻点 pi 和 pi+1,pi 是从 pi+1 密度直达的,则称 q 是从 p 密度可达的。
4.聚类形成:
- 从任意一个核心点开始,递归地寻找所有密度可达的点,直到不再找到新的核心点为止,这样就形成了一个聚类。
- 对于所有未标记的点,重复上述过程,直到所有点都被标记。
5.噪声点:
- 所有不属于任何聚类的点都被标记为噪声点
二、代码实现
2.1关键函数
在 Open3D 的源码中,cluster_dbscan 函数是通过 C++ 实现并绑定到 Python 接口的。以下是其 Python 接口的大致实现方式:
def cluster_dbscan(self, eps, min_points, print_progress=False):
"""
Function to perform DBSCAN clustering on a point cloud.
"""
if not isinstance(self, o3d.geometry.PointCloud):
raise TypeError("Input must be an open3d.geometry.PointCloud")
if not (isinstance(eps, float) or isinstance(eps, int)):
raise TypeError("eps must be a float or int")
if not isinstance(min_points, int):
raise TypeError("min_points must be an int")
if not isinstance(print_progress, bool):
raise TypeError("print_progress must be a bool")
# Call the C++ backend function
return _pybind_clustering_dbscan(self, float(eps), int(min_points), bool(print_progress))
参数解释:
eps(float):
- 定义了两个点之间的最大距离(邻域半径),用于判断它们是否属于同一个簇。
- 值越小,要求邻近点距离越近,可能会生成更多小的簇。
min_points(int):
- 定义了形成一个簇所需的最小点数。
- 值越大,要求每个簇中必须包含更多的点,可能会生成较少的簇,同时将更多的点标记为噪声。
print_progress(bool):
- 决定是否在控制台输出聚类进度。
- 如果设置为 True,在聚类过程中会输出进度信息,便于观察算法的执行过程。
2.2完整代码
import open3d as o3d
import numpy as np
import matplotlib.pyplot as plt
# 读取点云
pcd = o3d.io.read_point_cloud("3dballs.pcd")
# 可视化结果-原始点云
o3d.visualization.draw_geometries([pcd])
# 设置 DBSCAN 聚类的参数
eps = 0.2 # 邻域半径
min_points = 10 # 最小点数
# 执行 DBSCAN 聚类
with o3d.utility.VerbosityContextManager(o3d.utility.VerbosityLevel.Debug) as cm:
labels = np.array(pcd.cluster_dbscan(eps=eps, min_points=min_points, 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])