python 欧式聚类

本文介绍了使用Open3D库在Python中实现的欧式聚类算法,通过KDTreeFlann对点云进行近邻搜索,对给定的点云数据进行快速聚类,生成具有特定大小限制的簇,并可视化聚类结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

欧式聚类

import open3d as o3d
import numpy as np



def euclidean_cluster(cloud, tolerance, min_cluster_size, max_cluster_size):
    """
    欧式聚类
    :param cloud:输入点云
    :param tolerance: 设置近邻搜索的搜索半径(也即两个不同聚类团点之间的最小欧氏距离)
    :param min_cluster_size:设置一个聚类需要的最少的点数目
    :param max_cluster_size:设置一个聚类需要的最大点数目
    :return:聚类个数
    """

    kdtree = o3d.geometry.KDTreeFlann(cloud)  # 对点云建立kd树索引

    num_points = len(cloud.points)
    processed = [-1] * num_points  # 定义所需变量
    clusters = []  # 初始化聚类
    # 遍历各点
    for idx in range(num_points):
        if processed[idx] == 1:  # 如果该点已经处理则跳过
            continue
        seed_queue = []  # 定义一个种子队列
        sq_idx = 0
        seed_queue.append(idx)  # 加入一个种子点
        processed[idx] = 1

        while sq_idx < len(seed_queue):

            k, nn_indices, _ = kdtree.search_radius_vector_3d(cloud.points[seed_queue[sq_idx]], tolerance)

            if k == 1:  # k=1表示该种子点没有近邻点
                sq_idx += 1
                continue
            for j in range(k):

                if nn_indices[j] == num_points or processed[nn_indices[j]] == 1:
                    continue  # 种子点的近邻点中如果已经处理就跳出此次循环继续
                seed_queue.append(nn_indices[j])
                processed[nn_indices[j]] = 1

            sq_idx += 1

        if max_cluster_size > len(seed_queue) > min_cluster_size:
            clusters.append(seed_queue)

    return clusters



if __name__ == '__main__':
    # --------------------------加载点云数据------------------------------
    pcd = o3d.io.read_point_cloud("test.pcd")
    print(pcd)
    # --------------------------快速欧式聚类------------------------------
    fec = euclidean_cluster(pcd, tolerance=0.05, min_cluster_size=100, max_cluster_size=500000)
    # -------------------------聚类结果分类保存---------------------------
    segment = []  # 存储分割结果的容器
    print(len(fec))
    for i in range(len(fec)):
        print(i)
        ind = fec[i]
        clusters_cloud = pcd.select_by_index(ind)
        r_color = np.random.uniform(0, 1, (1, 3))  # 直线点云随机赋色
        clusters_cloud.paint_uniform_color([r_color[:, 0], r_color[:, 1], r_color[:, 2]])
        segment.append(clusters_cloud)
        file_name = "聚类\\cluster_" + str(i + 1) + ".pcd"
        o3d.io.write_point_cloud(file_name, clusters_cloud)
    # ----------------------------结果可视化------------------------------
    o3d.visualization.draw_geometries(segment, window_name="欧式聚类",
                                      width=1024, height=768,
                                      left=50, top=50,
                                      mesh_show_back_face=False)


结果:

在这里插入图片描述

快速欧式聚类

import open3d as o3d
import numpy as np


def fast_euclidean_cluster(cloud, tolerance, max_n, min_cluster_size, max_cluster_size):

    num_points = len(cloud.points)
    labels = [0] * num_points  # initalize all point label as 0
    segLab = 1  # Segment label
    kdtree = o3d.geometry.KDTreeFlann(cloud)  # 建立kd-tree索引
    for idx in range(num_points):
        if labels[idx] == 0:  # if Pi.lable =0
            # Pnn = FindNeighbor(pi,dth)
            k, nn_indices, _ = kdtree.search_hybrid_vector_3d(cloud.points[idx], tolerance, max_n)
            minSegLab = segLab

            for j in nn_indices:
                # if Nonzero(Pnn.lab)
                if (labels[j] > 0) and (labels[j] < minSegLab):
                    minSegLab = labels[j]  # minSegLab = min(N0nzero(Pnn.lab),SegLab)
            for j in nn_indices:  # foreach pj in Pnn do
                tempLab = labels[j]
                if tempLab > minSegLab:  # if pj.lab > minSeglab then
                    for k in range(num_points):  # foreach pk.lab in P do
                        if labels[k] == tempLab:  # if pk.lab = Pj.lab then
                            labels[k] = minSegLab  # pk.lab = minSegLab

                labels[j] = minSegLab  # 将所有邻近点分类

            segLab += 1
    # 根据分类结果对点云附加分类标签
    labMap = [[0] * 2 for _ in range(num_points)]
    for iv in range(num_points):
        labMap[iv][0] = iv
        labMap[iv][1] = labels[iv]
    labMap = sorted(labMap, key=lambda x: x[1])
    # 根据分类标签对点云进行分类
    index = 0
    allClusters = []
    for iv in range(num_points):
        seed_queue = []  # 定义一个种子队列
        if labMap[iv][1] != labMap[index][1]:
            for j in range(index, iv):
                seed_queue.append(labMap[j][0])
            index = iv
            if max_cluster_size > len(seed_queue) > min_cluster_size:
                allClusters.append(seed_queue)

    return allClusters


if __name__ == '__main__':
    # --------------------------加载点云数据------------------------------
    pcd = o3d.io.read_point_cloud("test.pcd")
    print(pcd)
    # --------------------------快速欧式聚类------------------------------
    fec = fast_euclidean_cluster(pcd, tolerance=0.08, max_n=1000, min_cluster_size=10, max_cluster_size=50000)
    # -------------------------聚类结果分类保存---------------------------
    segment = []  # 存储分割结果的容器
    print(len(fec))
    for i in range(len(fec)):
        print(i)
        ind = fec[i]
        clusters_cloud = pcd.select_by_index(ind)
        r_color = np.random.uniform(0, 1, (1, 3))  # 直线点云随机赋色
        clusters_cloud.paint_uniform_color([r_color[:, 0], r_color[:, 1], r_color[:, 2]])
        segment.append(clusters_cloud)
        file_name = "聚类\\cluster_" + str(i + 1) + ".pcd"
        o3d.io.write_point_cloud(file_name, clusters_cloud)
    # ----------------------------结果可视化------------------------------
    o3d.visualization.draw_geometries(segment, window_name="快速欧式聚类",
                                      width=1024, height=768,
                                      left=50, top=50,
                                      mesh_show_back_face=False)

结果
在这里插入图片描述
为何少了一条??????????

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

躺躺11

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值