Open3D 点云欧式聚类算法

时间:2024-07-14 09:42:45

目录

一、概述

1.1基本原理

1.2应用场景

二、代码实现

三、实现效果

3.1原始点云

3.2聚类后点云


前期试读,后续会将博客加入该专栏,欢迎订阅
Open3D与点云深度学习的应用_白葵新的博客-****博客

一、概述

1.1基本原理

        欧式聚类算法是一种基于点与点之间的欧氏距离来将点云数据分成多个簇的聚类方法。其主要目标是识别出数据中的密集区域,并将这些密集区域作为独立的簇。以下是欧式聚类算法的详细原理:

  1. 初始化:将所有点标记为未访问状态。
  2. 寻找邻居:对于每个未访问的点,从该点开始,找到在其欧氏距离范围内的所有邻居点(包括该点本身)。这个范围由参数 eps(邻域半径)定义。
  3. 形成聚类:如果邻居点的数量大于或等于一个指定的阈值 min_points,则将这些点标记为一个新簇,并继续检查这些邻居点的邻居,直到所有点都被访问并归类。
  4. 继续搜索:对于剩余的未访问点,重复步骤 2 和 3,直到所有点都被访问和归类。
  5. 处理噪声点:如果一个点的邻居数量少于 min_points,则该点被标记为噪声点。

1.2应用场景

  1. 点云分割:在三维点云数据中,欧式聚类可以用于分割不同的物体或结构。例如,在建筑物扫描数据中分割不同的房间或在自动驾驶中分割不同的道路和车辆。
  2. 目标检测:在自动驾驶或机器人视觉中,欧式聚类可以用于从点云数据中检测和分离目标物体,如车辆、行人和障碍物。
  3. 噪声过滤:欧式聚类可以用于识别并过滤掉孤立点或小簇,将其识别为噪声,增强数据的质量。

二、代码实现

import open3d as o3d
import numpy as np
import matplotlib.pyplot as plt
from sklearn.neighbors import NearestNeighbors



def euclidean_clustering(points, eps, min_points):
    """
    基于欧式距离的点云聚类算法实现。

    参数:
    points (ndarray): 点云数据的坐标数组。
    eps (float): 邻域半径,定义了搜索邻近点的范围。
    min_points (int): 形成一个簇的最小点数,如果邻域内的点数小于这个值,则该点被认为是噪声。

    返回:
    labels (ndarray): 聚类标签数组,每个点对应一个标签,-1 表示未分类的点,-2 表示噪声点。
    """

    # 使用 NearestNeighbors 查找邻近点
    nbrs = NearestNeighbors(radius=eps).fit(points)
    # 初始化标签数组,所有点初始标签为 -1 表示未分类
    labels = np.full(points.shape[0], -1)
    # 初始化聚类ID
    cluster_id = 0

    for i in range(points.shape[0]):
        # 跳过已经分类的点
        if labels[i] != -1:
            continue

        # 寻找点 i 的邻居
        neighbors = nbrs.radius_neighbors([points[i]], return_distance=False)[0]

        # 如果邻居点数小于最小点数阈值,将该点标记为噪声
        if len(neighbors) < min_points:
            labels[i] = -2
            continue

        # 将邻居点标记为同一簇
        labels[neighbors] = cluster_id
        # 使用列表模拟队列,将邻居点添加到队列中以扩展聚类
        neighbors_queue = list(neighbors)

        while neighbors_queue:
            # 取出队列中的第一个点
            current_point = neighbors_queue.pop(0)
            # 寻找当前点的邻居
            current_neighbors = nbrs.radius_neighbors([points[current_point]], return_distance=False)[0]

            # 如果邻居点数大于或等于最小点数阈值,继续扩展簇
            if len(current_neighbors) >= min_points:
                for neighbor in current_neighbors:
                    if labels[neighbor] in [-1, -2]:  # 仅处理未访问的点或噪声点
                        labels[neighbor] = cluster_id
                        neighbors_queue.append(neighbor)

        # 增加聚类ID
        cluster_id += 1

    return labels


# 读取点云数据
pcd = o3d.io.read_point_cloud("3dballs.pcd")

# 将点云数据转换为 NumPy 数组
points = np.asarray(pcd.points)

# 设置欧式聚类的参数
eps = 0.2  # 邻域半径,定义了搜索邻近点的范围
min_points = 10  # 形成一个簇的最小点数,如果邻域内的点数小于这个值,则该点被认为是噪声

# 执行欧式聚类
labels = euclidean_clustering(points, eps, min_points)

# 获取聚类数
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])

三、实现效果

3.1原始点云

3.2聚类后点云