python实现无监督聚类后的匈牙利匹配

admin2024-07-01  17

描述

之前文章介绍过DBSCAN,使用C++实现过该算法。现在针对某个项目,利用python实现DBSCAN和Kmeans算法。
项目简介:利用某传感器可以采集场景中的点云,每一帧都可以采集数量不等的点(x,y,z)。想要利用DBSCAN和Kmeans对点云进行无监督式的聚类,并利用匈牙利匹配对不同帧的点云簇进行匹配,从而实现跟踪效果。
项目备注:这是别人拜托我来写的,我花了一点点时间。从我的角度,这种方法解决该项目,简直是胡扯。。。不过,项目和人不靠谱,并不影响代码的有效性,权当一种消遣。

数据格式

点云数据用csv格式文件存储,格式如下:
第1行 Frame # | X | Y | Z
第2行 1 -0.4 1.04 0.11
第100行 1 15.4 7.45 0.16
第101行 2 89.3 4.78 3.65
第114行 2 34.4 6.04 0.56
………
这里不贴出数据,有关数据部分的代码,可以调整为你自己所需的格式

DBSCAN算法代码

  • 实现功能:对点云进行DBSCAN聚类,并得到每一次聚类的点云簇的个数

加载所需的库

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import DBSCAN  
from sklearn.preprocessing import StandardScaler

从数据中不断按帧数来读取数据,从frame_start读,最多不能超过frame_end,直到读取点的数量达到num_threshold后停止。可以理解为,自适应地读取一定数量的点云,从而使得点云总数拓充到一个可以聚类的程度。

def adaption_frame(data, frame_start, frame_end, num_threshold=1000): 
    data_x = []
    data_y = []
    data_z = []
    for i in range(frame_start, frame_end):
        target_frame = i  # 替换为你想要读取的Frame值

        # 筛选出指定Frame值的点云数据
        table_data = data[data['Frame #'] == target_frame]

        x_arr = table_data['X'].values
        data_x = np.concatenate((data_x, x_arr), axis=0)

        y_arr = table_data['Y'].values
        data_y = np.concatenate((data_y, y_arr), axis=0)  

        z_arr = table_data['Z'].values
        data_z = np.concatenate((data_z, z_arr), axis=0)  

        if data_x.shape[0] > num_threshold:
            break

    return data_x, data_y, data_z

利用坐标值,简单的对点云进行去噪

def valid_data(data_x, data_y, data_z):
    # 创建一个布尔数组,检查每个元素是否在 -2 到 2 之间 
    # 使用 & 操作符来确保 A、B、C 的对应元素都满足条件 
    condition = (data_x >= -5) & (data_x <= 5) & (data_y>= -5) & (data_y <= 5) & (data_z >= -5) & (data_z <= 5)  

    # 使用布尔数组来索引 A、B、C,过滤出满足条件的元素 
    data_x_valid = data_x[condition]  
    data_y_valid = data_y[condition]  
    data_z_valid = data_z[condition]  

    # 输出新的数组大小 
# print("x valid shape:", data_x_valid.shape) 
# print("y valid shape:", data_y_valid.shape) 
# print("z valid shape:", data_z_valid.shape)

    return data_x_valid, data_y_valid, data_z_valid

用于点云的绘图

def draw_data_origin(data_x, data_y, data_z):
    # 创建3D绘图
    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')

    # 绘制点云
    ax.scatter(data_x, data_y, data_z, s=0.1)  # s控制点的大小

    # 设置轴标签
    ax.set_xlabel('X')
    ax.set_ylabel('Y')
    ax.set_zlabel('Z')
    ax.set_title(f'Point Cloud at Frame {1}')

    # 显示图形
    plt.show()

DBSCAN代码

def dbscan(data_x, data_y, data_z):
    # 将 X, Y, Z 合并成一个二维数组 
    data_input = np.column_stack((data_x, data_y, data_z))  

    # 标准化数据(对于许多聚类算法来说,标准化是一个好习惯) 
    scaler = StandardScaler()  
    data_scaled = scaler.fit_transform(data_input)  

    # 初始化 DBSCAN,这里 eps 和 min_samples 是两个重要的参数,需要根据数据特性进行调整 
    # eps 是邻域的半径大小,min_samples 是成为核心对象所需的最小邻居数 
    dbscan = DBSCAN(eps=0.3, min_samples=5)  

    # 进行聚类 
    labels = dbscan.fit_predict(data_scaled)  

    # 计算不同标签的数量,即点簇的个数 
    num_clusters = len(set(labels)) - (1 if -1 in labels else 0)  

    return num_clusters, labels,

对每一次的聚类结果,按照点数大小降序排列。例如:某次聚类结果分为了3类,label为2的点云簇点云数为100,label为2的点云簇点云数为30,label为3的点云簇点云数为50。结果就是对他们进行降序排列。

def order_cluster(clusters_num, labels):    
    unique_labels, inverse_indices = np.unique(labels, return_inverse=True)  
    print(unique_labels.shape)
    print(inverse_indices.shape)
    # 使用 numpy.bincount 统计每个标签出现的次数 

    counts = np.bincount(inverse_indices) 

    # 按照出现次数降序排列 
    sorted_indices = np.argsort(counts)[::-1]  # 获取降序排列的索引 
    sorted_labels = unique_labels[sorted_indices]  # 根据索引重新排列标签 
    sorted_counts = counts[sorted_indices]  # 根据索引重新排列计数 

    # 打印结果 
    for label, count in zip(sorted_labels, sorted_counts):  
        print(f"类别 {label}: {count} 次")

    A = []
    for i in range(unique_labels.shape[0]):
        # 首先找到个数最多的标签 
        most_common_label = sorted_labels[i]  
        # 然后找到这个标签在原始 labels 数组中的位置 
        positions_most_common = np.where(labels == most_common_label)[0]  

        A.append(positions_most_common)

    return A

第一次的聚类结果,需要进行特殊的处理。认为点云数量超过human_size,才可以成为一个有效簇。用这种方式得到第一次聚类结果,存在多少个有效簇,并返回最小簇的点云数

def getFirstJudge(clusters_num, labels_order, human_size):
    num = 0
    for i in range(clusters_num):
        size = labels_order[i].shape[0]
        if size > human_size:
            num = num + 1
            points_num_min = size
    return num, points_num_min

每一次的聚类结果进行处理。如果这一次的聚类结果,有某一次的点云簇点云数大于上一次的最小点数,认为簇的个数可以增加;否则更新最新的最小簇代表的点云个数。

def adaption_cluster(clusters_num, labels_order, num_last, points_num_min, human_size):
    print("上一帧个数:" + str(num_last)+ " 最小的点簇:"+str(points_num_min))
    for i in range(clusters_num):
        shape = labels_order[i].shape
        if i <= num_last-1:
            if labels_order[i].shape[0] < human_size:
                num_last = i + 1
                break
            else:
                points_num_min = labels_order[i].shape
        else:
            if labels_order[i].shape[0] > human_size:
                num_last = num_last + 1
                points_num_min = labels_order[i].shape
            else:
                break;
    return num_last, points_num_min

主函数的实现流程:
1.读取数据
2.积累一定帧数的点云,随后聚类
3.对每一次的聚类结果,进行处理

点击python实现无监督聚类后的匈牙利匹配 - 古月居 (guyuehome.com)可查看全文

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明原文出处。如若内容造成侵权/违法违规/事实不符,请联系SD编程学习网:675289112@qq.com进行投诉反馈,一经查实,立即删除!