66
77py-motmetrics at:
88https://github.com/cheind/py-motmetrics
9+
10+ Notes by Michael Hoss:
11+ For Python 3.10, we need to update the version of py-motmetrics to 1.4.0.
12+ Then, to keep this code working, we need to change back the types of OId HId to object because they are
13+ strings in nuscenes-devkit, whereas motmetrics changed these types to float from 1.1.3 to 1.4.0.
914"""
1015from collections import OrderedDict
1116from itertools import count
1217
13- import motmetrics
1418import numpy as np
1519import pandas as pd
20+ from motmetrics import MOTAccumulator
1621
22+ _INDEX_FIELDS = ['FrameId' , 'Event' ]
1723
18- class MOTAccumulatorCustom (motmetrics .mot .MOTAccumulator ):
24+ class MOTAccumulatorCustom (MOTAccumulator ):
25+ """This custom class was created by nuscenes-devkit to use a faster implementation of
26+ `new_event_dataframe_with_data` under compatibility with motmetrics<=1.1.3.
27+ Now that we use motmetrics==1.4.0, we need to use this custom implementation to use
28+ objects instead of strings for OId and HId.
29+ """
1930 def __init__ (self ):
2031 super ().__init__ ()
2132
2233 @staticmethod
2334 def new_event_dataframe_with_data (indices , events ):
24- """
25- Create a new DataFrame filled with data.
26- This version overwrites the original in MOTAccumulator achieves about 2x speedups.
35+ """Create a new DataFrame filled with data.
2736
2837 Params
2938 ------
30- indices: list
31- list of tuples (frameid, eventid)
32- events: list
33- list of events where each event is a list containing
34- 'Type', 'OId', HId', 'D'
39+ indices: dict
40+ dict of lists with fields 'FrameId' and 'Event'
41+ events: dict
42+ dict of lists with fields 'Type', 'OId', 'HId', 'D'
3543 """
36- idx = pd .MultiIndex .from_tuples (indices , names = ['FrameId' , 'Event' ])
37- df = pd .DataFrame (events , index = idx , columns = ['Type' , 'OId' , 'HId' , 'D' ])
44+
45+ if len (events ) == 0 :
46+ return MOTAccumulatorCustom .new_event_dataframe ()
47+
48+ raw_type = pd .Categorical (
49+ events ['Type' ],
50+ categories = ['RAW' , 'FP' , 'MISS' , 'SWITCH' , 'MATCH' , 'TRANSFER' , 'ASCEND' , 'MIGRATE' ],
51+ ordered = False )
52+ series = [
53+ pd .Series (raw_type , name = 'Type' ),
54+ pd .Series (events ['OId' ], dtype = object , name = 'OId' ), # OId is string in nuscenes-devkit
55+ pd .Series (events ['HId' ], dtype = object , name = 'HId' ), # HId is string in nuscenes-devkit
56+ pd .Series (events ['D' ], dtype = float , name = 'D' )
57+ ]
58+
59+ idx = pd .MultiIndex .from_arrays (
60+ [indices [field ] for field in _INDEX_FIELDS ],
61+ names = _INDEX_FIELDS )
62+ df = pd .concat (series , axis = 1 )
63+ df .index = idx
3864 return df
3965
4066 @staticmethod
4167 def new_event_dataframe ():
42- """ Create a new DataFrame for event tracking. """
68+ """Create a new DataFrame for event tracking."""
4369 idx = pd .MultiIndex (levels = [[], []], codes = [[], []], names = ['FrameId' , 'Event' ])
44- cats = pd .Categorical ([], categories = ['RAW' , 'FP' , 'MISS' , 'SWITCH' , 'MATCH' ])
70+ cats = pd .Categorical ([], categories = ['RAW' , 'FP' , 'MISS' , 'SWITCH' , 'MATCH' , 'TRANSFER' , 'ASCEND' , 'MIGRATE' ])
4571 df = pd .DataFrame (
4672 OrderedDict ([
47- ('Type' , pd .Series (cats )), # Type of event. One of FP (false positive), MISS, SWITCH, MATCH
48- ('OId' , pd .Series (dtype = object )),
49- # Object ID or -1 if FP. Using float as missing values will be converted to NaN anyways.
50- ('HId' , pd .Series (dtype = object )),
51- # Hypothesis ID or NaN if MISS. Using float as missing values will be converted to NaN anyways.
52- ('D' , pd .Series (dtype = float )), # Distance or NaN when FP or MISS
73+ ('Type' , pd .Series (cats )), # Type of event. One of FP (false positive), MISS, SWITCH, MATCH
74+ ('OId' , pd .Series (dtype = object )), # Object ID or -1 if FP. Using float as missing values will be converted to NaN anyways.
75+ ('HId' , pd .Series (dtype = object )), # Hypothesis ID or NaN if MISS. Using float as missing values will be converted to NaN anyways.
76+ ('D' , pd .Series (dtype = float )), # Distance or NaN when FP or MISS
5377 ]),
5478 index = idx
5579 )
@@ -63,8 +87,7 @@ def events(self):
6387 return self .cached_events_df
6488
6589 @staticmethod
66- def merge_event_dataframes (dfs , update_frame_indices = True , update_oids = True , update_hids = True ,
67- return_mappings = False ):
90+ def merge_event_dataframes (dfs , update_frame_indices = True , update_oids = True , update_hids = True , return_mappings = False ):
6891 """Merge dataframes.
6992
7093 Params
@@ -104,24 +127,29 @@ def merge_event_dataframes(dfs, update_frame_indices=True, update_oids=True, upd
104127
105128 # Update index
106129 if update_frame_indices :
107- next_frame_id = max ( r . index . get_level_values ( 0 ). max () + 1 ,
108- r .index .get_level_values (0 ).unique ().shape [0 ])
130+ # pylint: disable=cell-var-from-loop
131+ next_frame_id = max ( r . index . get_level_values ( 0 ). max () + 1 , r .index .get_level_values (0 ).unique ().shape [0 ])
109132 if np .isnan (next_frame_id ):
110133 next_frame_id = 0
111- copy .index = copy .index .map (lambda x : (x [0 ] + next_frame_id , x [1 ]))
134+ if not copy .index .empty :
135+ copy .index = copy .index .map (lambda x : (x [0 ] + next_frame_id , x [1 ]))
112136 infos ['frame_offset' ] = next_frame_id
113137
114138 # Update object / hypothesis ids
115139 if update_oids :
140+ # pylint: disable=cell-var-from-loop
116141 oid_map = dict ([oid , str (next (new_oid ))] for oid in copy ['OId' ].dropna ().unique ())
117142 copy ['OId' ] = copy ['OId' ].map (lambda x : oid_map [x ], na_action = 'ignore' )
118143 infos ['oid_map' ] = oid_map
119144
120145 if update_hids :
146+ # pylint: disable=cell-var-from-loop
121147 hid_map = dict ([hid , str (next (new_hid ))] for hid in copy ['HId' ].dropna ().unique ())
122148 copy ['HId' ] = copy ['HId' ].map (lambda x : hid_map [x ], na_action = 'ignore' )
123149 infos ['hid_map' ] = hid_map
124150
151+ # Avoid pandas warning. But is this legit/do we need such a column later on again?
152+ # copy = copy.dropna(axis=1, how='all')
125153 r = pd .concat ((r , copy ))
126154 mapping_infos .append (infos )
127155
0 commit comments