1+ import argparse
2+ import matplotlib .pyplot as plt
3+ import numpy as np
4+ import pandas as pd
5+ import seaborn as sns
6+ from tqdm import tqdm
7+ from pathlib import Path
8+ from scipy import interpolate
9+ from datasets .utils import constants as ds_constants , parsing as ds_parsing
10+
11+
12+
13+ def avg_vel (ds_name , timestamps , joints_gt ):
14+
15+ assert 1 <= joints_gt .shape [2 ] <= 3 , 'coordinates must be either 2D or 3D'
16+ # iterate on each joint
17+ data = np .zeros ((len (timestamps ), len (ds_constants .HPECoreSkeleton .KEYPOINTS_MAP ) * 2 ))
18+ keys = []
19+ for joint_key , joint_ind in ds_constants .HPECoreSkeleton .KEYPOINTS_MAP .items ():
20+ data [:,joint_ind * 2 ] = joints_gt [:, joint_ind , 0 ]
21+ data [:,joint_ind * 2 + 1 ] = joints_gt [:, joint_ind , 1 ]
22+ keys .append (joint_key + ' x' )
23+ keys .append (joint_key + ' y' )
24+
25+ df = pd .DataFrame (abs (data ), columns = keys )
26+ # print(df.describe())
27+ avg75 = np .mean (df .describe ().loc ['75%' ])
28+ # print("\n75% = " + str(avg75), flush=True)
29+ avgMax = np .mean (df .describe ().loc ['max' ])
30+ # print("Max = " + str(avgMax), flush=True)
31+ avgMean = np .mean (df .describe ().loc ['mean' ])
32+ # print("Mean = " + str(avgMean), flush=True)
33+ avgStd = np .mean (df .describe ().loc ['std' ])
34+ # print("Std = " + str(avgStd), flush=True)
35+
36+ if (avgMax >= 250 and avgMean >= 57 ):
37+ print ("FAST" )
38+ elif (avgMax < 100 and avgMean < 18 ):
39+ print ("SLOW" )
40+
41+ return avg75 , avgMax , avgMean , avgStd
42+
43+
44+ def main (args ):
45+
46+ plt .close ('all' )
47+
48+ # output_folder_path = Path(args.output_folder)
49+ # output_folder_path = output_folder_path.resolve()
50+ # output_folder_path.mkdir(parents=True, exist_ok=True)
51+ results = dict ()
52+ results ['datasets' ] = dict ()
53+ results ['global' ] = dict ()
54+ list75 = []
55+ listMax = []
56+ listMean = []
57+ listStd = []
58+
59+ # import GT from yarp
60+ datasets_path = Path (args .datasets_path )
61+ yarp_file_paths = list (datasets_path .glob ('**/data.log' ))
62+
63+ for yarp_path in tqdm (yarp_file_paths , desc = "Progress: " ):
64+ # for yarp_path in track(yarp_file_paths):
65+
66+ if 'skeleton' not in yarp_path .parent .name :
67+ continue
68+ dataset_name = yarp_path .parent .parent .name
69+ print ('\x1b [1;33;20m' + "Procesing " + str (dataset_name ) + '\x1b [0m' )
70+ data = ds_parsing .import_yarp_skeleton_data (yarp_path )
71+ ts_gt = np .concatenate (([.0 ], data ['ts' ], [data ['ts' ][- 1 ] + 1 ]))
72+
73+ # interpolate ground truth joints so that they can be compared with the high frequency predictions
74+ for k_map in ds_constants .HPECoreSkeleton .KEYPOINTS_MAP .items ():
75+ x_interpolation = interpolate .interp1d (ts_gt , np .concatenate (([data [k_map [0 ]][0 , 0 ]], data [k_map [0 ]][:, 0 ], [data [k_map [0 ]][- 1 , 0 ]])))
76+ y_interpolation = interpolate .interp1d (ts_gt , np .concatenate (([data [k_map [0 ]][0 , 1 ]], data [k_map [0 ]][:, 1 ], [data [k_map [0 ]][- 1 , 1 ]])))
77+ data [k_map [0 ]] = dict ()
78+ data [k_map [0 ]]['x' ] = x_interpolation
79+ data [k_map [0 ]]['y' ] = y_interpolation
80+ skeletons_gt = np .zeros ((len (ts_gt ), len (ds_constants .HPECoreSkeleton .KEYPOINTS_MAP ), 2 ))
81+ for k_map in ds_constants .HPECoreSkeleton .KEYPOINTS_MAP .items ():
82+ skeletons_gt [:, k_map [1 ], 0 ] = data [k_map [0 ]]['x' ](ts_gt )
83+ skeletons_gt [:, k_map [1 ], 1 ] = data [k_map [0 ]]['y' ](ts_gt )
84+
85+ # resample GT at 1 KHz
86+ fHz = 1000
87+ tGT1K = np .arange (ts_gt [0 ], ts_gt [- 1 ], 1 / fHz )
88+ skeletons_gt1K = np .zeros ((len (tGT1K ), len (ds_constants .HPECoreSkeleton .KEYPOINTS_MAP ), 2 ))
89+ for k_map in ds_constants .HPECoreSkeleton .KEYPOINTS_MAP .items ():
90+ skeletons_gt1K [:, k_map [1 ], 0 ] = data [k_map [0 ]]['x' ](tGT1K )
91+ skeletons_gt1K [:, k_map [1 ], 1 ] = data [k_map [0 ]]['y' ](tGT1K )
92+ # differenciate GT poses
93+ vel_gt1K_noF = np .gradient (skeletons_gt1K , axis = 0 )* fHz
94+ # filter velocity
95+ from scipy .signal import savgol_filter
96+ vel_gt1K = savgol_filter (vel_gt1K_noF , 901 , 3 , axis = 0 )
97+
98+ # calculate statistics for each dataset
99+ value75 , valueMax , valueMean , valueStd = avg_vel (str (dataset_name ), tGT1K , vel_gt1K )
100+ # add to global list
101+ list75 .append (value75 )
102+ listMax .append (valueMax )
103+ listMean .append (valueMean )
104+ listStd .append (valueStd )
105+
106+ dataList = list (zip (list75 , listMax , listMean , listStd ))
107+ df = pd .DataFrame (dataList , columns = ['75%' , 'Max' , 'Mean' , 'Std' ])
108+ # print(df.describe())
109+
110+ # define clusters for mean velocity
111+ df ['mean_group' ] = pd .cut (df ['Mean' ], bins = range (5 , 71 , 13 ))
112+ # define clusters for max velocity
113+ df ['max_group' ] = pd .cut (df ['Max' ], bins = range (50 , 301 , 50 ))
114+
115+ # plots
116+ my_dpi = 96
117+ fig1 = plt .figure (figsize = (2048 / my_dpi , 900 / my_dpi ), dpi = my_dpi )
118+ ax1 = sns .boxplot (x = "mean_group" , y = "Mean" , data = df )
119+ ax1 .set_xlabel ("Speed [px/s]" , fontsize = 24 )
120+ ax1 .set_ylabel ("Speed [px/s]" , fontsize = 24 )
121+ fig1 .suptitle ('Mean velocity distribution' , fontsize = 32 , y = 0.92 )
122+ plt .xticks (fontsize = 22 , rotation = 0 )
123+
124+ fig2 = plt .figure (figsize = (2048 / my_dpi , 900 / my_dpi ), dpi = my_dpi )
125+ ax2 = sns .boxplot (x = "max_group" , y = "Max" , data = df )
126+ ax2 .set_xlabel ("Speed [px/s]" , fontsize = 24 )
127+ ax2 .set_ylabel ("Speed [px/s]" , fontsize = 24 )
128+ fig2 .suptitle ('Max velocity distribution' , fontsize = 32 , y = 0.92 )
129+ plt .xticks (fontsize = 22 , rotation = 0 )
130+
131+ # print statistics
132+ print (df )
133+ print ("Mean values range:" )
134+ print ("[" , np .min (df ['Mean' ]), ", " , np .max (df ['Mean' ]), "]" )
135+ print ("Max values range:" )
136+ print ("[" , np .min (df ['Max' ]), ", " , np .max (df ['Max' ]), "]" )
137+
138+ plt .show ()
139+
140+
141+
142+ if __name__ == '__main__' :
143+ parser = argparse .ArgumentParser (description = '...' )
144+ parser .add_argument ('-d' , '--datasets_path' , help = 'Path to the folders containing data saved in Yarp format' , required = True )
145+ parser .add_argument ('-o' , '--output_folder' , help = 'Path to the folder where velocity study results will be saved' , required = False )
146+
147+ args , unknown = parser .parse_known_args ()
148+ if (unknown ):
149+ print ('\x1b [1;31;20m' + 'Unknown argument/s: ' + ' ' .join (unknown ) + '\x1b [0m' )
150+
151+ main (args )
0 commit comments