3维点集的聚类(python)

问题描述 投票:0回答:1

我从显示球轨迹的电影中提取了一组点。 每个点的坐标 (x,y) 对应于从电影中提取的图像中球的位置,以及对应于时间帧的 z 坐标。 下面的最终表示是在同一个 3D 图形中渲染的逐帧提取的所有点的总和。

这是一张没有“时间”数据的图片: 这是相机的角度。

问题是我还捕获了背景中玩家的一些运动(但由于它是平面图像,因此坐标没有提供玩家位于背景中的信息),甚至捕获了背景中另一个场地上的一些其他球后退 ! 但是当你从所有这些点的 3 维角度观察时,你仍然可以非常清楚地识别出主球的轨迹是什么,以及噪音是什么(球员的移动、后面比赛场地中的另一个球等)。 ..)

我希望能够对这些(x,y,时间戳)点进行聚类以消除噪音。 但到目前为止我使用的工具没有给出任何结果:meanshift、DBSCAN 不起作用。自组织映射或 Kohonen 网络都不是。 无论我改变什么参数,结果都不满意。

你知道为什么我的做法没有达到预期的结果吗?有没有更合适的方法来聚类 3D 数据?

这是我从电影中提取的一组数据:

http://arbalette.hopto.org/images/forums/shoot_prise_8_objets_detectes.json

图片已发

是第 2 次拍摄,但您有 10 次拍摄。 每个检测到的物体(球和噪声)都在“objects”对象中,X,Y 是坐标,frameNb 是时间(我图片中的 z 轴)

我尝试过的(例如使用 DBSCAN)如下:

with open("objets_detectes.json") as json_file:
    objets = json.load(json_file)

for shoot in objets:
    positions_spatiales = []    
    for objet in objets[shoot]["objets"]:
        point = [objets[shoot]["objets"][objet]["x"], objets[shoot]["objets"][objet]["y"], objets[shoot]["objets"][objet]["frameNb"]]
        positions_spatiales.append(point)

    positions_spatiales = np.array(positions_spatiales)
    #DBSCAN
    dbscan = DBSCAN(eps=30, min_samples=10)
    clusters = dbscan.fit_predict(positions_spatiales)
    unique_clusters = np.unique(clusters)

然后,我用 matplotlib 绘制它以查看每次拍摄的结果以及失败......

    fig = plt.figure()
    plt.title('Tir ' + str(shoot) + ', relation position/temps - analyse du bruit et clustering des points')
    ax = fig.add_subplot(111, projection='3d')
    color_indice = 0
    for cluster in unique_clusters:
        x = []
        y = []
        z = []
        cluster_points = positions_spatiales[clusters == cluster]
        for point in cluster_points:
            x.append(point[0])
            y.append(point[1])
            z.append(point[2])

     ax.scatter(x, y, z, c=[replace_by_unique_color_by_cluster], label='Cluster ' + str(cluster), marker='o')

     ax.set_xlabel('X')
     ax.set_ylabel('Y')
     ax.set_zlabel('temps')
     plt.show(block=True)

您可以在这里看到,绘制了具有以下参数的 3 个不同结果:我们可以清楚地看到主球的轨迹未被识别(1 个颜色 = 1 个已识别的簇)。

    dbscan = DBSCAN(eps=30, min_samples=10)

eps = 30:

    dbscan = DBSCAN(eps=70, min_samples=10)

eps = 70:

    dbscan = DBSCAN(eps=120, min_samples=10)

eps = 120:

python neural-network data-science cluster-analysis
1个回答
0
投票

到目前为止,我有以下答案,不是很好,但它暗示需要调整

eps
和点数才能获得最佳值:

读取数据和包:

import json
import pandas as pd
from sklearn.cluster import DBSCAN
from sklearn.preprocessing import StandardScaler
%matplotlib notebook
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import time

with open("shoot_prise_8_objets_detectes.json") as json_file:
    objets = json.load(json_file)

shoots = []
positions_spatiales = []
x = []
y = []
area = []
frameNumber = []
for shoot in objets:
    for objet in objets[shoot]["objets"]:
        x.append(objets[shoot]["objets"][objet]["x"])
        y.append(objets[shoot]["objets"][objet]["y"])
        area.append(objets[shoot]["objets"][objet]["area"])
        frameNumber.append(objets[shoot]["objets"][objet]["frameNb"])
        shoots.append(shoot)
        
df = pd.DataFrame(columns = ["shoots", "x", "y", "frame number"])
df["shoots"] = shoots
df["x"] = x
df["y"] = y
df["area"] = area
df["frame number"] = frameNumber

机器学习部分:

for shoot in df["shoots"].unique():
    #print("processing shoot "+str(shoot)+"...")
    subDf = df[df["shoots"] == shoot]
    #print(subDf) # printing
    dataForClustering = subDf[["x","y","frame number"]] # get data for clustering
    scaler = StandardScaler() # scale
    scaledDataForClustering = scaler.fit_transform(dataForClustering) # get scaled data
    #print("_____________________________________________") # niceness
    #print(scaledDataForClustering) # print to check
    # adjust as necessary...
    eps = 1
    min_samples = 3
    dbscan = DBSCAN(eps=eps, min_samples=min_samples)
    #print("_____________________________________________")
    clusters = dbscan.fit_predict(scaledDataForClustering) # predict clusters
    clusters_shifted = clusters + 1 # dshit for np.bincount
    cluster_counts = np.bincount(clusters_shifted) # get count of clusters
    most_common_cluster = np.argmax(cluster_counts) # find the cluster with the highest count
    clusters[clusters != most_common_cluster - 1] = -1 # assign all but non most frequent cluster as -1
    clusters[clusters == most_common_cluster - 1] = 1 # assign most frequent cluster as 1
    # till the end is for plotting...
    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')
    for cluster in np.unique(clusters):
        if cluster == -1:
            label = "noise"
        else:
            label = "ball"
        clusterPoints = subDf[clusters == cluster]
        ax.scatter(clusterPoints['x'], clusterPoints['y'], clusterPoints['frame number'], label=f'Cluster {label}')
    ax.set_xlabel('X')
    ax.set_ylabel('Y')
    ax.set_zlabel('Frame Number')
    ax.set_title('Shoot number: '+str(shoot))
    ax.legend()
    fig.canvas.draw()
    plt.savefig("soccer/shoot"+str(shoot)+".png", dpi = 330)
    time.sleep(0.1)

简单来说,我将最常见的簇指定为信号(非噪声),将其他所有簇指定为噪声。午餐后我会改进..这是迄今为止的结果(对于第一次拍摄,所有拍摄看起来都很相似):

© www.soinside.com 2019 - 2024. All rights reserved.