msight-base 0.1.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3 @@
1
+ from .detection import *
2
+ from .road_user import *
3
+ from .trajectory import *
@@ -0,0 +1,36 @@
1
+ from enum import Enum
2
+
3
+
4
+ class BehaviorType(Enum):
5
+ """
6
+ Enum for different types of behaviors.
7
+ """
8
+ UNKNOWN = -1
9
+ CONSTANT = 0
10
+ ACCELERATE = 1
11
+ DECELERATE = 2
12
+ STOP = 3
13
+ LANE_KEEPING = 4
14
+ LANE_CHANGING = 5
15
+ LANE_DEPARTURE = 6
16
+ LEFT_TURN = 7
17
+ RIGHT_TURN = 8
18
+
19
+ # Additional behaviors
20
+ U_TURN = 9
21
+ YIELDING = 10
22
+ FOLLOWING = 11
23
+ OVERTAKING = 12
24
+ PARKING = 13
25
+ EMERGENCY_BRAKING = 14
26
+
27
+ def __str__(self):
28
+ return self.name.lower()
29
+
30
+ @classmethod
31
+ def from_name(cls, name: str):
32
+ try:
33
+ return cls[name.upper()]
34
+ except KeyError:
35
+ # Fall back to UNKNOWN
36
+ return cls.UNKNOWN
@@ -0,0 +1,42 @@
1
+ from typing import List, Optional
2
+ from .utils.cls import get_class_path, import_class_from_path
3
+
4
+ class DetectedObjectBase:
5
+ def __init__(self):
6
+ pass
7
+
8
+ def to_dict(self):
9
+ raise NotImplementedError("Subclasses should implement this!")
10
+
11
+ class DetectionResultBase:
12
+ def __init__(self, object_list: List[DetectedObjectBase], timestamp: int, sensor_type: Optional[str] = None):
13
+ self.object_list = object_list
14
+ self.timestamp = timestamp
15
+ self.sensor_type = sensor_type
16
+
17
+ def to_dict(self):
18
+ object_data_type = get_class_path(self.object_list[0].__class__) if len(self.object_list) > 0 else get_class_path(DetectedObjectBase)
19
+ return {
20
+ 'object_list': [obj.to_dict() for obj in self.object_list],
21
+ 'timestamp': self.timestamp,
22
+ 'sensor_type': self.sensor_type,
23
+ 'object_data_type': object_data_type,
24
+ }
25
+
26
+ @staticmethod
27
+ def from_dict(data: dict) -> 'DetectionResultBase':
28
+ object_data_type = data.get("object_data_type")
29
+ if object_data_type is None:
30
+ raise ValueError(f"Missing 'object_data_type' in data: {data}")
31
+
32
+ obj_cls = import_class_from_path(object_data_type)
33
+ if data['object_list'] is not None and len(data['object_list']) > 0:
34
+ object_list = [obj_cls.from_dict(obj_data) for obj_data in data['object_list']]
35
+ else:
36
+ object_list = []
37
+
38
+ return DetectionResultBase(
39
+ object_list=object_list,
40
+ timestamp=data['timestamp'],
41
+ sensor_type=data['sensor_type'],
42
+ )
msight_base/map.py ADDED
@@ -0,0 +1,213 @@
1
+ from enum import Enum
2
+ from typing import List
3
+ from commonroad.scenario.lanelet import LaneletType, LaneletNetwork
4
+ import matplotlib.pyplot as plt
5
+
6
+
7
+ class LaneShape(Enum):
8
+ """
9
+ Enum for different types of lane shape.
10
+ """
11
+ STRAIGHT = 'straight'
12
+ LEFT_TURN = 'left-turn'
13
+ RIGHT_TURN = 'right-turn'
14
+ U_TURN = 'u-turn'
15
+
16
+
17
+ class LaneSide(Enum):
18
+ """
19
+ Enum for different types of lane side.
20
+ """
21
+ LEFT = 1
22
+ RIGHT = -1
23
+ ONLANE = 0
24
+ UNKNOWN = 'unknown'
25
+
26
+ @classmethod
27
+ def from_name(cls, name: str):
28
+ try:
29
+ return cls[name.upper()]
30
+ except KeyError:
31
+ # Fall back to UNKNOWN
32
+ return cls.UNKNOWN
33
+
34
+
35
+ class MapInfo:
36
+ def __init__(self, lane_id, lane_point_idx, dis_to_lane_center, side: LaneSide, related_lane_id, related_route, nearest_next_lane_point_idx=None):
37
+ self.lane_id = lane_id
38
+ self.lane_point_idx = lane_point_idx
39
+ self.dis_to_lane_center = dis_to_lane_center
40
+ self.side = side
41
+ self.related_lane_id = related_lane_id
42
+ self.related_route = related_route
43
+ self.nearest_next_lane_point_idx = nearest_next_lane_point_idx
44
+
45
+ def __repr__(self):
46
+ return f"MapInfo(lane_id={self.lane_id}, lane_point_idx={self.lane_point_idx})"
47
+
48
+ def from_dict(cls, object_dict):
49
+ return cls(
50
+ lane_id=object_dict.get('lane_id', None),
51
+ lane_point_idx=object_dict.get('lane_point_idx', None),
52
+ dis_to_lane_center=object_dict.get('dis_to_lane_center', None),
53
+ side=LaneSide.from_name(object_dict.get('side', 'unknown')),
54
+ related_lane_id=object_dict.get('related_lane_id', None),
55
+ related_route=object_dict.get('related_route', None),
56
+ nearest_next_lane_point_idx=object_dict.get('nearest_next_lane_point_idx', None)
57
+ )
58
+
59
+ def to_dict(self):
60
+ return {
61
+ 'lane_id': self.lane_id,
62
+ 'lane_point_idx': self.lane_point_idx,
63
+ 'dis_to_lane_center': self.dis_to_lane_center,
64
+ 'side': self.side.value,
65
+ 'related_lane_id': self.related_lane_id,
66
+ 'related_route': self.related_route,
67
+ 'nearest_next_lane_point_idx': self.nearest_next_lane_point_idx
68
+ }
69
+
70
+
71
+ class MapObject:
72
+ def __init__(self, commonroadObj: LaneletNetwork, center_point, map_lanes, lane_heading, lane_shape: List[LaneShape], lane_seg_length, background_img, corner_coords):
73
+ self.center_point = center_point
74
+ self._map_lanes = map_lanes
75
+ self._lane_heading = lane_heading
76
+ self._lane_shape = lane_shape
77
+ self._lane_seg_length = lane_seg_length
78
+ self.background_img = background_img
79
+ self.corner_coords = corner_coords
80
+
81
+ if isinstance(commonroadObj, LaneletNetwork):
82
+ self.map_polylines_ids = [lanelet.lanelet_id for lanelet in commonroadObj.lanelets]
83
+ self._suc_edges = [lanelet.successor for lanelet in commonroadObj.lanelets]
84
+ self._pre_edges = [lanelet.predecessor for lanelet in commonroadObj.lanelets]
85
+ self._left_edges = [lanelet.adj_left for lanelet in commonroadObj.lanelets]
86
+ self._left_edge_directions = [lanelet.adj_left_same_direction for lanelet in commonroadObj.lanelets]
87
+ self._right_edges = [lanelet.adj_right for lanelet in commonroadObj.lanelets]
88
+ self._right_edge_directions = [lanelet.adj_right_same_direction for lanelet in commonroadObj.lanelets]
89
+ self.intersection_lane_id_list = [lanelet.lanelet_id for lanelet in commonroadObj.lanelets if LaneletType.INTERSECTION in lanelet.lanelet_type]
90
+ self.straight_lane_id_list = [lanelet.lanelet_id for lanelet in commonroadObj.lanelets if LaneletType.INTERSECTION not in lanelet.lanelet_type]
91
+ else:
92
+ self.map_polylines_ids = []
93
+ self._suc_edges = []
94
+ self._pre_edges = []
95
+ self._left_edges = []
96
+ self._left_edge_directions = []
97
+ self._right_edges = []
98
+ self._right_edge_directions = []
99
+ self.intersection_lane_id_list = []
100
+ self.straight_lane_id_list = []
101
+
102
+ def suc_edges(self, id=-1):
103
+ if id == -1:
104
+ return self._suc_edges
105
+ else:
106
+ if id not in self.map_polylines_ids:
107
+ raise ValueError(f"Lanelet id {id} not found in map_polylines_ids")
108
+ return self._suc_edges[self.map_polylines_ids.index(id)]
109
+
110
+ def pre_edges(self, id=-1):
111
+ if id == -1:
112
+ return self._pre_edges
113
+ else:
114
+ if id not in self.map_polylines_ids:
115
+ raise ValueError(f"Lanelet id {id} not found in map_polylines_ids")
116
+ return self._pre_edges[self.map_polylines_ids.index(id)]
117
+
118
+ def left_edges(self, id=-1):
119
+ if id == -1:
120
+ return self._left_edges
121
+ else:
122
+ if id not in self.map_polylines_ids:
123
+ raise ValueError(f"Lanelet id {id} not found in map_polylines_ids")
124
+ return self._left_edges[self.map_polylines_ids.index(id)]
125
+
126
+ def right_edges(self, id=-1):
127
+ if id == -1:
128
+ return self._right_edges
129
+ else:
130
+ if id not in self.map_polylines_ids:
131
+ raise ValueError(f"Lanelet id {id} not found in map_polylines_ids")
132
+ return self._right_edges[self.map_polylines_ids.index(id)]
133
+
134
+ def left_edge_directions(self, id=-1):
135
+ if id == -1:
136
+ return self._left_edge_directions
137
+ else:
138
+ if id not in self.map_polylines_ids:
139
+ raise ValueError(f"Lanelet id {id} not found in map_polylines_ids")
140
+ return self._left_edge_directions[self.map_polylines_ids.index(id)]
141
+
142
+ def right_edge_directions(self, id=-1):
143
+ if id == -1:
144
+ return self._right_edge_directions
145
+ else:
146
+ if id not in self.map_polylines_ids:
147
+ raise ValueError(f"Lanelet id {id} not found in map_polylines_ids")
148
+ return self._right_edge_directions[self.map_polylines_ids.index(id)]
149
+
150
+ def lane_shape(self, id=-1):
151
+ if id == -1:
152
+ return self._lane_shape
153
+ else:
154
+ if id not in self.map_polylines_ids:
155
+ raise ValueError(f"Lanelet id {id} not found in map_polylines_ids")
156
+ return self._lane_shape[self.map_polylines_ids.index(id)]
157
+
158
+ def map_lanes(self, id=-1, idx=-1):
159
+ if id == -1:
160
+ return self._map_lanes
161
+ else:
162
+ if id not in self.map_polylines_ids:
163
+ raise ValueError(f"Lanelet id {id} not found in map_polylines_ids")
164
+ if idx == -1:
165
+ return self._map_lanes[self.map_polylines_ids.index(id)]
166
+ else:
167
+ if idx >= len(self._map_lanes[self.map_polylines_ids.index(id)]):
168
+ raise ValueError(f"Index {idx} out of range for lane with id {id}")
169
+ return self._map_lanes[self.map_polylines_ids.index(id)][idx]
170
+
171
+ def lane_heading(self, id=-1, idx=-1):
172
+ if id == -1:
173
+ return self._lane_heading
174
+ else:
175
+ if id not in self.map_polylines_ids:
176
+ raise ValueError(f"Lanelet id {id} not found in map_polylines_ids")
177
+ if idx == -1:
178
+ return self._lane_heading[self.map_polylines_ids.index(id)]
179
+ else:
180
+ if idx >= len(self._lane_heading[self.map_polylines_ids.index(id)]):
181
+ raise ValueError(f"Index {idx} out of range for lane with id {id}")
182
+ return self._lane_heading[self.map_polylines_ids.index(id)][idx]
183
+
184
+ def lane_seg_length(self, id=-1, idx=-1):
185
+ if id == -1:
186
+ return self._lane_seg_length
187
+ else:
188
+ if id not in self.map_polylines_ids:
189
+ raise ValueError(f"Lanelet id {id} not found in map_polylines_ids")
190
+ if idx == -1:
191
+ return self._lane_seg_length[self.map_polylines_ids.index(id)]
192
+ else:
193
+ if idx >= len(self._lane_seg_length[self.map_polylines_ids.index(id)]):
194
+ raise ValueError(f"Index {idx} out of range for lane with id {id}")
195
+ return self._lane_seg_length[self.map_polylines_ids.index(id)][idx]
196
+
197
+ def to_dict(self):
198
+ return {
199
+ 'center_point': self.center_point,
200
+ 'map_lanes': self._map_lanes,
201
+ 'lane_heading': self._lane_heading,
202
+ 'map_polylines_ids': self.map_polylines_ids,
203
+ 'suc_edges': self._suc_edges,
204
+ 'pre_edges': self._pre_edges,
205
+ 'left_edges': self._left_edges,
206
+ 'left_edge_directions': self._left_edge_directions,
207
+ 'right_edges': self._right_edges,
208
+ 'right_edge_directions': self._right_edge_directions,
209
+ 'lane_shape': self._lane_shape,
210
+ 'intersection_lane_id_list': self.intersection_lane_id_list,
211
+ 'straight_lane_id_list': self.straight_lane_id_list,
212
+ 'corner_coords': self.corner_coords,
213
+ }
@@ -0,0 +1,182 @@
1
+ from enum import IntEnum
2
+ from msight_base.map import MapInfo
3
+ from msight_base.behavior import BehaviorType
4
+
5
+
6
+ class RoadUserPoint:
7
+ def __init__(self,
8
+ x=None,
9
+ y=None,
10
+ speed=None,
11
+ acceleration=None,
12
+ heading=None,
13
+ width=None,
14
+ length=None,
15
+ height=None,
16
+ poly_box=None,
17
+ category=None,
18
+ confidence=None,
19
+ turning_signal=None,
20
+ map_info=None,
21
+ timestamp=None,
22
+ frame_step=None,
23
+ traj_id=None,
24
+ sensor_data={},
25
+ behaviors=[],
26
+ conf_int_2sigma=None,
27
+ conf_int_vel_2sigma=None,
28
+ heading_confidence=None,
29
+ yaw_rate=None):
30
+ self._timestamp = timestamp
31
+ self._frame_step = frame_step
32
+ self.x = x
33
+ self.y = y
34
+ self.speed = speed
35
+ self.acceleration = acceleration
36
+ self.heading = heading
37
+ self.width = width
38
+ self.length = length
39
+ self.height = height
40
+ self.poly_box = poly_box
41
+ self.category = category
42
+ self.traj = None
43
+ self.frame = None
44
+ self.prev = None
45
+ self.next = None
46
+ self.sensor_data = sensor_data # sensor id to sensor data map
47
+ self.confidence = confidence
48
+ self.turning_signal = turning_signal
49
+ self.map_info = map_info
50
+ self.behaviors = behaviors
51
+ self.pred_trajectory = None
52
+ self.conf_int_2sigma = conf_int_2sigma
53
+ self.conf_int_vel_2sigma = conf_int_vel_2sigma
54
+ self.heading_confidence = heading_confidence
55
+ self.yaw_rate = yaw_rate
56
+
57
+ ## this is used to store the id when the object's trajectory is not yet created or assigned
58
+ self._traj_id = traj_id
59
+
60
+ ## this is also used to store the id when the object's trajectory is not yet created or assigned
61
+ ## for some use cases, we need a uuid instead of a trajectory id (that increments from 0)
62
+ self._traj_uuid = None
63
+
64
+ @property
65
+ def traj_id(self):
66
+ if self.traj is not None:
67
+ return self.traj.id
68
+ return self._traj_id
69
+
70
+ @traj_id.setter
71
+ def traj_id(self, value):
72
+ if self.traj is not None:
73
+ raise AttributeError("Cannot set traj_id directly when traj is assigned.")
74
+ self._traj_id = value
75
+
76
+ @property
77
+ def frame_step(self):
78
+ if self.frame is None:
79
+ return None
80
+ return self.frame.step
81
+
82
+ @frame_step.setter
83
+ def frame_step(self, value):
84
+ if self.frame is not None:
85
+ raise AttributeError("Cannot set frame_step directly when frame is assigned.")
86
+ self._frame_step = value
87
+
88
+ @property
89
+ def timestamp(self):
90
+ if self.frame is None:
91
+ return self._timestamp
92
+ return self.frame.timestamp
93
+
94
+ @timestamp.setter
95
+ def timestamp(self, value):
96
+ if self.frame is not None:
97
+ raise AttributeError("Cannot set timestamp directly when frame is assigned.")
98
+ self._timestamp = value
99
+
100
+ @staticmethod
101
+ def from_dict(object_dict):
102
+ return RoadUserPoint(
103
+ timestamp=object_dict.get('timestamp', None),
104
+ frame_step=object_dict.get('frame_step', None),
105
+ traj_id=object_dict.get('traj_id', None),
106
+ x=object_dict.get('x', None),
107
+ y=object_dict.get('y', None),
108
+ speed=object_dict.get('speed', None),
109
+ acceleration=object_dict.get('acceleration', None),
110
+ heading=object_dict.get('heading', None),
111
+ width=object_dict.get('width', None),
112
+ length=object_dict.get('length', None),
113
+ height=object_dict.get('height', None),
114
+ poly_box=object_dict.get('poly_box', None),
115
+ category=RoadUserCategory(int(object_dict['category'])) if object_dict.get('category') is not None else None,
116
+ confidence=object_dict.get('confidence', None),
117
+ turning_signal=object_dict.get('turning_signal', None),
118
+ map_info=MapInfo.from_dict(object_dict['map_info']) if object_dict.get('map_info') else None,
119
+ sensor_data=object_dict.get('sensor_data', {}),
120
+ behaviors=[BehaviorType[behavior] for behavior in object_dict.get('behaviors', [])],
121
+ conf_int_2sigma=object_dict.get('conf_int_2sigma', None),
122
+ conf_int_vel_2sigma=object_dict.get('conf_int_vel_2sigma', None),
123
+ heading_confidence=object_dict.get('heading_confidence', None),
124
+ yaw_rate=object_dict.get('yaw_rate', None)
125
+ )
126
+
127
+ def to_dict(self):
128
+ return {
129
+ 'traj_id': self.traj_id,
130
+ 'frame_step': self.frame_step,
131
+ 'timestamp': self.timestamp,
132
+ 'x': self.x,
133
+ 'y': self.y,
134
+ 'speed': self.speed,
135
+ 'acceleration': self.acceleration,
136
+ 'heading': self.heading,
137
+ 'width': self.width,
138
+ 'length': self.length,
139
+ 'height': self.height,
140
+ 'category': RoadUserCategory(int(self.category)) if self.category is not None else None,
141
+ 'confidence': self.confidence,
142
+ 'turning_signal': self.turning_signal,
143
+ 'poly_box': self.poly_box,
144
+ 'map_info': self.map_info.to_dict() if self.map_info else None,
145
+ 'behaviors': [str(behavior) for behavior in self.behaviors],
146
+ 'sensor_data': self.sensor_data,
147
+ 'conf_int_2sigma': self.conf_int_2sigma,
148
+ 'conf_int_vel_2sigma': self.conf_int_vel_2sigma,
149
+ 'heading_confidence': self.heading_confidence,
150
+ 'yaw_rate': self.yaw_rate,
151
+ }
152
+
153
+ def __repr__(self):
154
+ return f"RoadUserPoint(x={self.x}, y={self.y}, heading={self.heading}, width={self.width}, length={self.length}, category={self.category})"
155
+
156
+
157
+ class RoadUserCategory(IntEnum):
158
+ """
159
+ Enum for road user categories.
160
+ """
161
+ UNKNOWN = -1
162
+ SEDAN = 0
163
+ SUV = 1
164
+ TRUCK = 2
165
+ BUS = 3
166
+ PEDESTRIAN = 4
167
+ BICYCLE = 5
168
+ MOTORCYCLE = 6
169
+ TRAILER = 7
170
+ VAN = 8
171
+ PICKUP = 9
172
+
173
+ def __str__(self):
174
+ return self.name.lower()
175
+
176
+ @classmethod
177
+ def from_name(cls, name: str):
178
+ try:
179
+ return cls[name.upper()]
180
+ except KeyError:
181
+ # Fall back to UNKNOWN
182
+ return cls.UNKNOWN
@@ -0,0 +1,186 @@
1
+ import bisect
2
+ from .road_user import RoadUserPoint
3
+ from typing import List
4
+
5
+ class Container:
6
+ def __init__(self, id=None, objects = None):
7
+ self.id = id
8
+ if objects is None:
9
+ objects = []
10
+ self.objects = objects
11
+
12
+ def __len__(self):
13
+ return len(self.objects)
14
+
15
+ def __iter__(self):
16
+ return iter(self.objects)
17
+
18
+ def __getitem__(self, item):
19
+ return self.objects[item]
20
+
21
+
22
+ class Trajectory(Container):
23
+ def __init__(self, id=None):
24
+ self.steps = []
25
+ self.step_to_object_map = {}
26
+ super().__init__(id=id, objects=[])
27
+
28
+ def add_object(self, obj, step, insort=False):
29
+ if insort:
30
+ index = bisect.bisect_left(self.steps, step)
31
+ if index < len(self.steps) and self.steps[index] == step:
32
+ raise ValueError(f"Step {step} already exists")
33
+ self.steps.insert(index, step)
34
+ self.objects.insert(index, obj)
35
+ self.step_to_object_map[step] = obj
36
+ if index > 0:
37
+ self.objects[index - 1].next = obj
38
+ obj.prev = self.objects[index - 1]
39
+ if index < len(self.objects) - 1:
40
+ obj.next = self.objects[index + 1]
41
+ self.objects[index + 1].prev = obj
42
+ else:
43
+ if len(self.steps) > 0 and step < self.steps[-1]:
44
+ raise ValueError(f"Step {step} is less than the last step {self.steps[-1]}, if you want to insert in between use insort=True")
45
+ self.objects.append(obj)
46
+ self.step_to_object_map[step] = obj
47
+ self.steps.append(step)
48
+ if len(self.objects) > 1:
49
+ self.objects[-2].next = obj
50
+ obj.prev = self.objects[-2]
51
+ obj.traj = self
52
+
53
+ def get_object_at_step(self, step):
54
+ return self.step_to_object_map.get(step, None)
55
+
56
+ def remove_object(self, step):
57
+ if step not in self.steps:
58
+ return
59
+ # raise ValueError(f"Step {step} does not exist in the trajectory")
60
+ obj = self.get_object_at_step(step)
61
+ self.objects.remove(obj)
62
+ self.steps.remove(step)
63
+ del self.step_to_object_map[step]
64
+ obj.traj = None
65
+ next_obj = obj.next
66
+ prev_obj = obj.prev
67
+ if next_obj is not None:
68
+ next_obj.prev = prev_obj
69
+ if prev_obj is not None:
70
+ prev_obj.next = next_obj
71
+
72
+
73
+ class Frame(Container):
74
+ def __init__(self, step, timestamp=None):
75
+ self.step = step
76
+ self.timestamp = timestamp
77
+ self.traj_ids = set()
78
+ self.traj_id_to_obj_map = {}
79
+ super().__init__(None, objects=[])
80
+
81
+ def add_object(self, obj):
82
+ if obj.traj_id in self.traj_ids:
83
+ raise ValueError(f"Object with id {obj.traj_id} already exists in the frame")
84
+ self.objects.append(obj)
85
+ self.traj_id_to_obj_map[obj.traj_id] = obj
86
+ self.traj_ids.add(obj.traj_id)
87
+ obj.frame = self
88
+
89
+ def remove_object(self, obj):
90
+ if obj.traj_id not in self.traj_ids:
91
+ raise ValueError(f"Object with id {obj.traj_id} does not exist in the frame")
92
+ self.objects.remove(obj)
93
+ del self.traj_id_to_obj_map[obj.traj_id]
94
+ self.traj_ids.remove(obj.traj_id)
95
+ obj.frame = None
96
+
97
+
98
+ class TrajectoryManager:
99
+ def __init__(self, max_frames=None):
100
+ self.trajectories = []
101
+ self.traj_ids = set()
102
+ self.traj_id_to_traj_map = {}
103
+ self.frames = []
104
+ self.steps = []
105
+ self.timestamps = []
106
+ self.step_to_frame_map = {}
107
+ self.timestamp_to_frame_map = {}
108
+ self.max_frames = max_frames
109
+
110
+ @property
111
+ def last_step(self):
112
+ return self.steps[-1] if len(self.steps)>0 else -1
113
+
114
+ @property
115
+ def earliest_step(self):
116
+ return self.steps[0] if len(self.steps)>0 else -1
117
+
118
+ @property
119
+ def last_frame(self):
120
+ return self.frames[-1]
121
+
122
+ def delete_earliest_frame(self):
123
+ if not self.frames:
124
+ raise ValueError("No frames to delete")
125
+ step = self.frames[0].step
126
+ for obj in self.frames[0].objects:
127
+ # print(obj.traj, obj.traj_id)
128
+ if obj.traj is not None:
129
+ obj.traj.remove_object(step)
130
+ if self.frames[0].timestamp is not None:
131
+ del self.timestamp_to_frame_map[self.frames[0].timestamp]
132
+ self.timestamps.remove(self.frames[0].timestamp)
133
+ del self.step_to_frame_map[step]
134
+ self.steps.remove(step)
135
+
136
+ for traj in self.trajectories:
137
+ if len(traj.objects) == 0:
138
+ self.remove_traj(traj)
139
+ self.frames.pop(0)
140
+
141
+ def add_object(self, obj, traj_id, step, timestamp=None, insort=False):
142
+ if traj_id not in self.traj_ids:
143
+ traj = Trajectory(traj_id)
144
+ self.trajectories.append(traj)
145
+ self.traj_ids.add(traj_id)
146
+ self.traj_id_to_traj_map[traj_id] = traj
147
+ else:
148
+ traj = self.traj_id_to_traj_map[traj_id]
149
+
150
+ if step >= self.last_step + 1:
151
+ frame = Frame(step, timestamp)
152
+ self.frames.append(frame)
153
+ self.steps.append(step)
154
+ self.step_to_frame_map[step] = frame
155
+ if timestamp is not None:
156
+ self.timestamps.append(timestamp)
157
+ self.timestamp_to_frame_map[timestamp] = frame
158
+
159
+ elif step <= self.last_step and step >= self.earliest_step:
160
+ frame = self.step_to_frame_map[step]
161
+ else:
162
+ raise ValueError(f"Step {step} is not a valid step, valid steps are from 0 to {self.last_step+1}")
163
+
164
+ traj.add_object(obj, step, insort=insort)
165
+ frame.add_object(obj)
166
+ while self.max_frames is not None and len(self.frames) > self.max_frames:
167
+ # print(len(self.frames), self.max_frames)
168
+ self.delete_earliest_frame()
169
+
170
+ def add_list_as_new_frame(self, object_list: List[RoadUserPoint], timestamp=None):
171
+ # use this method to push a list of objects as the last frame, this is very useful when you have a list of objects that are already tracked with id assigned
172
+ step = self.last_step + 1
173
+ for obj in object_list:
174
+ if obj.traj_id is None:
175
+ raise ValueError("Object must have a traj_id to be added to a trajectory manager")
176
+ self.add_object(obj, obj.traj_id, step, timestamp=obj.timestamp)
177
+
178
+
179
+ def remove_traj(self, traj: Trajectory):
180
+ # print(f"Removing trajectory with id {traj.id}")
181
+ tid = traj.id
182
+ self.trajectories.remove(traj)
183
+ self.traj_ids.remove(tid)
184
+ del self.traj_id_to_traj_map[tid]
185
+ for obj in traj:
186
+ obj.frame.remove_object(obj)
File without changes
@@ -0,0 +1,9 @@
1
+ def get_class_path(cls):
2
+ module = cls.__module__
3
+ class_name = cls.__name__
4
+ return f"{module}.{class_name}"
5
+
6
+ def import_class_from_path(path: str):
7
+ module_path, class_name = path.rsplit('.', 1)
8
+ module = __import__(module_path, fromlist=[class_name])
9
+ return getattr(module, class_name)
@@ -0,0 +1,33 @@
1
+ from pathlib import Path
2
+ from msight_base import TrajectoryManager, RoadUserPoint
3
+ import json
4
+ from datetime import datetime
5
+ from tqdm import tqdm
6
+
7
+
8
+ def get_timestamp_from_filename(file_name: str) -> datetime:
9
+ # file name is like "2023-09-05 10-00-00-039784.json"
10
+ stem = file_name.split(".")[0]
11
+ return datetime.strptime(stem, "%Y-%m-%d %H-%M-%S-%f")
12
+
13
+
14
+ def read_msight_json_data(file_path: Path) -> TrajectoryManager:
15
+ tm = TrajectoryManager()
16
+ step = 0
17
+ for frame_file in tqdm(list(file_path.iterdir())):
18
+ if frame_file.suffix != ".json":
19
+ continue
20
+ timestamp = get_timestamp_from_filename(frame_file.stem)
21
+ with open(frame_file, "r") as f:
22
+ frame_data = json.load(f)
23
+ for obj_data in frame_data['fusion']:
24
+ obj = RoadUserPoint(
25
+ obj_data['lat'],
26
+ obj_data['lon'],
27
+ heading=obj_data['heading'],
28
+ width=obj_data['width'],
29
+ length=obj_data['length'],
30
+ )
31
+ tm.add_object(obj, obj_data['id'], step, timestamp=timestamp)
32
+ step += 1
33
+ return tm
@@ -0,0 +1 @@
1
+ from .visualizer import Visualizer
@@ -0,0 +1,118 @@
1
+ import numpy as np
2
+ import cv2
3
+ import json
4
+
5
+
6
+ class VideoWriter(object):
7
+
8
+ def __init__(self, name, out_size_w=960, out_size_h=720):
9
+
10
+ self.video_writer = cv2.VideoWriter(
11
+ name + '.mp4', cv2.VideoWriter_fourcc(*'MP4V'),
12
+ 10.0, (out_size_w, out_size_h))
13
+ self.video_writer_cat = cv2.VideoWriter(
14
+ name + '_cat.mp4', cv2.VideoWriter_fourcc(*'MP4V'),
15
+ 10.0, (out_size_h + out_size_w, out_size_h))
16
+
17
+ self.out_size_w = out_size_w
18
+ self.out_size_h = out_size_h
19
+
20
+ def save_frame(self, vis_det, vis_loc):
21
+
22
+ vis_det = cv2.resize(vis_det, (self.out_size_w, self.out_size_h))
23
+ vis_loc = cv2.resize(vis_loc, (self.out_size_h, self.out_size_h))
24
+
25
+ self.video_writer.write(vis_det[:, :, ::-1])
26
+
27
+ frame_cat = np.concatenate([vis_det, vis_loc], axis=1)
28
+ self.video_writer_cat.write(frame_cat[:, :, ::-1])
29
+
30
+ cv2.namedWindow('frame_cat', cv2.WINDOW_NORMAL)
31
+ cv2.imshow('frame_cat', frame_cat[:, :, ::-1])
32
+ cv2.waitKey(1)
33
+
34
+
35
+ ############ some helper functions ##############
36
+
37
+ class Struct:
38
+ def __init__(self, **entries):
39
+ self.__dict__.update(entries)
40
+
41
+
42
+ def parse_config(path_to_json=r'./config.json'):
43
+ with open(path_to_json) as f:
44
+ data = json.load(f)
45
+ return Struct(**data)
46
+
47
+
48
+
49
+ ################ BB draw on 2D image... ####################
50
+
51
+ def draw_bb_on_image(vehicle_list, img):
52
+
53
+ for i in range(len(vehicle_list)):
54
+ v = vehicle_list[i]
55
+ x_bottom_c, y_bottom_c = v.pixel_bottom_center.x, v.pixel_bottom_center.y
56
+ diagonal_length = v.diagonal_length_pixel
57
+
58
+ # draw box
59
+ pt1 = (int(x_bottom_c - diagonal_length / 2), int(y_bottom_c - diagonal_length / 2))
60
+ pt2 = (int(x_bottom_c + diagonal_length / 2), int(y_bottom_c + diagonal_length / 2))
61
+ cv2.rectangle(img, pt1=pt1, pt2=pt2, color=(255, 0, 0), thickness=1, lineType=cv2.LINE_AA)
62
+ box_tmp = img[pt1[1]:pt2[1], pt1[0]:pt2[0], :]
63
+ img[pt1[1]:pt2[1], pt1[0]:pt2[0], 1:] = (0.75 * box_tmp[:, :, 1:]).astype(np.uint8)
64
+
65
+ # draw bottom center
66
+ cv2.circle(img, (x_bottom_c, y_bottom_c), 2, (255, 0, 0), -1)
67
+ # text = 'id=%s' % v.id
68
+ # pt = (x_bottom_c, y_bottom_c - 5)
69
+ # cv2.putText(img, text=text, org=pt, fontFace=cv2.FONT_HERSHEY_SIMPLEX,
70
+ # fontScale=0.5, color=(255, 255, 0), thickness=1, lineType=cv2.LINE_AA)
71
+
72
+ return img
73
+
74
+
75
+ ################ BB (YOLOX) draw on 2D image... ####################
76
+ # Instead of draw the square, we directly draw the rect predicted by YOLOX
77
+
78
+ def draw_bb_on_image_yolox(vehicle_list, img):
79
+
80
+ for i in range(len(vehicle_list)):
81
+ v = vehicle_list[i]
82
+ x_bottom_c, y_bottom_c = v.pixel_bottom_center.x, v.pixel_bottom_center.y
83
+ x1, y1, x2, y2 = v.pixel_bbox
84
+
85
+ # draw box
86
+ pt1 = (int(x1), int(y1))
87
+ pt2 = (int(x2), int(y2))
88
+ cv2.rectangle(img, pt1=pt1, pt2=pt2, color=(255, 0, 0), thickness=1, lineType=cv2.LINE_AA)
89
+ box_tmp = img[pt1[1]:pt2[1], pt1[0]:pt2[0], :]
90
+ img[pt1[1]:pt2[1], pt1[0]:pt2[0], 1:] = (0.75 * box_tmp[:, :, 1:]).astype(np.uint8)
91
+
92
+ # draw bottom center
93
+ cv2.circle(img, (x_bottom_c, y_bottom_c), 2, (255, 0, 0), -1)
94
+ # text = 'id=%s' % v.id
95
+ # pt = (x_bottom_c, y_bottom_c - 5)
96
+ # cv2.putText(img, text=text, org=pt, fontFace=cv2.FONT_HERSHEY_SIMPLEX,
97
+ # fontScale=0.5, color=(255, 255, 0), thickness=1, lineType=cv2.LINE_AA)
98
+
99
+ return img
100
+
101
+ # map center lat/lon
102
+ # use the following for Ann Arbor Ellsworth Roundabout
103
+ LAT0, LON0 = 42.229392, -83.739012
104
+
105
+
106
+ def coord_normalization(lat, lon, center_lat=LAT0, center_lon=LON0):
107
+ "from lat/lon to local coordinate with unit meter"
108
+ lat_norm = (lat - center_lat) * 111000.
109
+ lon_norm = (lon - center_lon) * 111000. * np.cos(center_lat/180.*np.pi)
110
+ return lat_norm, lon_norm
111
+
112
+
113
+ def coord_unnormalization(lat_norm, lon_norm, center_lat=LAT0, center_lon=LON0):
114
+ "from local coordinate with unit meter to lat/lon"
115
+ lat = lat_norm / 111000. + center_lat
116
+ lon = lon_norm / 111000. / np.cos(center_lat/180.*np.pi) + center_lon
117
+ return lat, lon
118
+
@@ -0,0 +1,289 @@
1
+ import numpy as np
2
+ import cv2
3
+ import os
4
+ import json
5
+ import math
6
+ from msight_base import TrajectoryManager
7
+ from .utils import coord_normalization, coord_unnormalization
8
+
9
+
10
+ class Struct:
11
+ def __init__(self, **entries):
12
+ self.__dict__.update(entries)
13
+
14
+
15
+ def parse_config(path_to_json=r'./config.json'):
16
+ with open(path_to_json) as f:
17
+ data = json.load(f)
18
+ return Struct(**data)
19
+
20
+
21
+ class Visualizer:
22
+ """
23
+ Basemap for detection visualization. Show and map detection to base map layer.
24
+ Pixel image: vehicle bounding box, vehicle id
25
+ Map layer: location, heading, rect box, trajectory, predicted future...
26
+ """
27
+
28
+ def __init__(self, map_image_path, map_width=1024, map_height=1024, RGB=False):
29
+ self.h, self.w = map_height, map_width
30
+
31
+ self.f = parse_config(os.path.splitext(map_image_path)[0] + '.json')
32
+ self.transform_wd2px, self.transform_px2wd = self._create_coord_mapper()
33
+
34
+ basemap = cv2.imread(map_image_path, cv2.IMREAD_COLOR)
35
+ if not RGB:
36
+ basemap = cv2.cvtColor(basemap, cv2.COLOR_BGR2RGB)
37
+ self.basemap = cv2.resize(basemap, (map_width, map_height))
38
+ self.basemap = (self.basemap.astype(np.float64) * 0.3).astype(np.uint8)
39
+
40
+ np.random.seed(0)
41
+ self.color_table = np.random.randint(80, 255, (10, 3))
42
+ np.random.seed()
43
+
44
+ self.traj_manager = TrajectoryManager(max_frames=100)
45
+ self.traj_layer = np.zeros([self.h, self.w, 3], dtype=np.uint8)
46
+ self.traj_alpha = np.zeros([self.h, self.w, 3], dtype=np.float32)
47
+
48
+ if os.path.exists(r'./vehicle_category.json'):
49
+ self.label_list = parse_config(r'./vehicle_category.json')
50
+ else:
51
+ self.label_list = None
52
+
53
+ @staticmethod
54
+ def _draw_vehicle_as_point(vis, ptc, color):
55
+ # draw circle boundary
56
+ cv2.circle(vis, tuple(ptc), 10, color, -1)
57
+ # draw center location
58
+ cv2.circle(vis, tuple(ptc), 4, (255, 255, 0), -1)
59
+
60
+ @staticmethod
61
+ def _draw_vehicle_as_box(vis, pts, color):
62
+ # fill rectangle
63
+ cv2.fillPoly(vis, [np.array(pts)], color, lineType=cv2.LINE_AA)
64
+
65
+ @staticmethod
66
+ def _draw_vehicle_heading_as_arrow(vis, ptc, heading, color):
67
+ # draw heading
68
+ # convert degree to radian
69
+ heading = math.radians(heading-90)
70
+
71
+ line_length = 25
72
+ pt1 = (int(ptc[0]), int(ptc[1]))
73
+ pt2 = (int(ptc[0] + line_length*np.cos(heading)),
74
+ int(ptc[1] + line_length*np.sin(heading)))
75
+ cv2.arrowedLine(vis, pt1=pt1, pt2=pt2, color=color,
76
+ thickness=3, line_type=cv2.LINE_AA)
77
+
78
+ @staticmethod
79
+ def _draw_predicted_future(vis, pts, color):
80
+ # draw mean trajectory
81
+ for i in range(len(pts)-1):
82
+ pt1 = (int(pts[i][0]), int(pts[i][1]))
83
+ pt2 = (int(pts[i+1][0]), int(pts[i+1][1]))
84
+ cv2.line(vis, pt1=pt1, pt2=pt2, color=color,
85
+ thickness=1, lineType=cv2.LINE_AA)
86
+
87
+ @staticmethod
88
+ def _draw_trust_region(vis, pts, r, color):
89
+ # draw trust regions
90
+ # vis: image
91
+ # pts: points
92
+ # r: radius
93
+ # color: color
94
+ for i in range(len(pts)):
95
+ ptc = (int(pts[i][0]), int(pts[i][1]))
96
+ rx, ry = int(r[i][0]), int(r[i][1]) # trust region
97
+ cv2.ellipse(vis, center=ptc, axes=(rx, ry), angle=0, startAngle=0, endAngle=360,
98
+ color=color, thickness=1, lineType=cv2.LINE_AA)
99
+
100
+ @staticmethod
101
+ def _print_vehicle_info(vis, ptc, v, color):
102
+ # print latitude
103
+ pt = (ptc[0] + 15, ptc[1])
104
+ text = "%.6f" % v.x
105
+ cv2.putText(vis, text=text, org=pt, fontFace=cv2.FONT_HERSHEY_SIMPLEX,
106
+ fontScale=0.5, color=color, thickness=1, lineType=cv2.LINE_AA)
107
+ # print longitude
108
+ pt = (ptc[0] + 15, ptc[1] + 20)
109
+ text = "%.6f" % v.y
110
+ cv2.putText(vis, text=text, org=pt, fontFace=cv2.FONT_HERSHEY_SIMPLEX,
111
+ fontScale=0.5, color=color, thickness=1, lineType=cv2.LINE_AA)
112
+ # print id
113
+ if hasattr(v, 'traj_id') and v.traj_id is not None:
114
+ pt = (ptc[0] + 15, ptc[1] + 40)
115
+ text = f"id: {v.traj_id}"
116
+ cv2.putText(vis, text=text, org=pt, fontFace=cv2.FONT_HERSHEY_SIMPLEX,
117
+ fontScale=0.5, color=color, thickness=1, lineType=cv2.LINE_AA)
118
+ if v.heading is not None:
119
+ pt= (ptc[0] + 15, ptc[1] + 60)
120
+ text = f"heading: {v.heading:.2f} deg"
121
+ cv2.putText(vis, text=text, org=pt, fontFace=cv2.FONT_HERSHEY_SIMPLEX,
122
+ fontScale=0.5, color=color, thickness=1, lineType=cv2.LINE_AA)
123
+ # pt = (ptc[0] + 15, ptc[1] + 60)
124
+ # if hasattr(v, 'lane') and v.lane is not None:
125
+ # text = f"lane: {v.lane}"
126
+ # cv2.putText(vis, text=text, org=pt, fontFace=cv2.FONT_HERSHEY_SIMPLEX,
127
+ # fontScale=0.5, color=color, thickness=1, lineType=cv2.LINE_AA)
128
+ # # print category
129
+ # if v.category is not None:
130
+ # pt = (ptc[0] + 15, ptc[1] + 40)
131
+ # if label_list is not None:
132
+ # text = "%s" % label_list.id2label[str(v.category)]
133
+ # else:
134
+ # text = "Category: %d" % v.category
135
+ # cv2.putText(vis, text=text, org=pt, fontFace=cv2.FONT_HERSHEY_SIMPLEX,
136
+ # fontScale=0.5, color=color, thickness=1, lineType=cv2.LINE_AA)
137
+
138
+ def _create_coord_mapper(self):
139
+
140
+ # wd_tl, wd_tr, wd_bl, wd_br = self.f.tl.copy(), self.f.tr.copy(), self.f.bl.copy(), self.f.br.copy()
141
+ px_tl, px_tr, px_bl, px_br = [0, 0], [
142
+ self.w-1, 0], [0, self.h-1], [self.w-1, self.h-1]
143
+
144
+ # normalize to local coordination
145
+ wd_tl = coord_normalization(
146
+ self.f.tl[0], self.f.tl[1], self.f.tl[0], self.f.tl[1])
147
+ wd_tr = coord_normalization(
148
+ self.f.tr[0], self.f.tr[1], self.f.tl[0], self.f.tl[1])
149
+ wd_bl = coord_normalization(
150
+ self.f.bl[0], self.f.bl[1], self.f.tl[0], self.f.tl[1])
151
+ wd_br = coord_normalization(
152
+ self.f.br[0], self.f.br[1], self.f.tl[0], self.f.tl[1])
153
+
154
+ wd_points = np.array([wd_tl, wd_tr, wd_bl, wd_br], np.float32)
155
+ px_points = np.array([px_tl, px_tr, px_bl, px_br], np.float32)
156
+
157
+ transform_wd2px = cv2.getPerspectiveTransform(
158
+ src=wd_points, dst=px_points)
159
+ transform_px2wd = cv2.getPerspectiveTransform(
160
+ src=px_points, dst=wd_points)
161
+
162
+ return transform_wd2px, transform_px2wd
163
+
164
+ def _world2pxl(self, pt_world, output_int=True):
165
+
166
+ # normalize to local coordination
167
+ pt_world = np.array(pt_world).reshape([-1, 2])
168
+ lat, lon = pt_world[:, 0], pt_world[:, 1]
169
+ lat_norm, lon_norm = coord_normalization(
170
+ lat, lon, self.f.tl[0], self.f.tl[1])
171
+ pt_world = np.array([lat_norm, lon_norm]).T
172
+
173
+ pt_world = np.array(pt_world).reshape([-1, 1, 2]).astype(np.float32)
174
+ pt_pixel = cv2.perspectiveTransform(pt_world, self.transform_wd2px)
175
+ pt_pixel = np.squeeze(pt_pixel)
176
+
177
+ if output_int:
178
+ pt_pixel = pt_pixel.astype(np.int32)
179
+
180
+ return pt_pixel
181
+
182
+ def _pxl2world(self, pt_pixel):
183
+
184
+ pt_pixel = np.array(pt_pixel).reshape([-1, 1, 2]).astype(np.float32)
185
+ pt_world = cv2.perspectiveTransform(
186
+ pt_pixel, self.transform_px2wd).astype(np.float64)
187
+ pt_world = np.squeeze(pt_world)
188
+ pt_world = pt_world.reshape([-1, 2])
189
+
190
+ # unnormalize to world coordination
191
+ lat_norm, lon_norm = pt_world[:, 0], pt_world[:, 1]
192
+ lat, lon = coord_unnormalization(
193
+ lat_norm, lon_norm, self.f.tl[0], self.f.tl[1])
194
+ pt_world = np.array([lat, lon]).T
195
+
196
+ return pt_world
197
+
198
+ def draw_points(self, frame, show_heading=False):
199
+ # TODO: draw vehicle as box when show_heading is True
200
+ if len(frame) == 0:
201
+ return self.basemap
202
+
203
+ vis = np.copy(self.basemap)
204
+
205
+ for i in range(0, len(frame)):
206
+ v = frame[i]
207
+
208
+ if v.x is None or v.y is None:
209
+ continue
210
+
211
+ color = self.color_table[hash(v.traj_id) % 10].tolist()
212
+
213
+ ptc = self._world2pxl([v.x, v.y])
214
+
215
+ # box unavailiable, draw a circle instead
216
+ self._draw_vehicle_as_point(vis, ptc, color)
217
+
218
+ if show_heading:
219
+ self._draw_vehicle_heading_as_arrow(vis, ptc, v.heading, color)
220
+
221
+ # print vehicle info beside box
222
+ self._print_vehicle_info(vis, ptc, v, (255, 255, 0),)
223
+
224
+ return vis
225
+
226
+ def draw_trajectory(self, frame, linewidth=2):
227
+
228
+ # update trajectory manager
229
+ for v in frame:
230
+ self.traj_manager.add_object(v, v.traj_id, frame.step, timestamp=frame.timestamp)
231
+
232
+ # update alpha (fade out)
233
+ self.traj_alpha *= 0.95
234
+
235
+ # draw trajectory
236
+ for v in self.traj_manager.last_frame:
237
+ pt_map = self._world2pxl([v.x, v.y])
238
+ v_ = v.prev
239
+ if v_ is None:
240
+ # print('prev is None')
241
+ continue
242
+ pt_map_prev = self._world2pxl([v_.x, v_.y])
243
+
244
+ pt1 = (int(pt_map[0]), int(pt_map[1]))
245
+ pt2 = (int(pt_map_prev[0]), int(pt_map_prev[1]))
246
+
247
+ color = self.color_table[hash(v.traj_id) % 10].tolist()
248
+
249
+ cv2.line(self.traj_layer, pt1=pt1, pt2=pt2,
250
+ color=color, thickness=linewidth)
251
+ cv2.line(self.traj_alpha, pt1=pt1, pt2=pt2,
252
+ color=(0.8, 0.8, 0.8), thickness=linewidth)
253
+
254
+ return self.traj_layer, self.traj_alpha
255
+
256
+ @staticmethod
257
+ def layer_blending(base_layer, traj_layer, traj_alpha):
258
+ base_layer = base_layer.astype(np.float32)/255.
259
+ traj_layer = traj_layer.astype(np.float32)/255.
260
+ vis = base_layer*(1-traj_alpha) + traj_layer*traj_alpha
261
+ return vis
262
+
263
+ def draw_polygon(self, base_layer, polygon, color, thickness=2):
264
+ pts = self._world2pxl(polygon)
265
+ layer = cv2.polylines(
266
+ base_layer, [pts], isClosed=True, color=color, thickness=thickness)
267
+ return layer
268
+
269
+ def render(self, frame, with_traj=True, linewidth=2, show_heading=False):
270
+ base_layer = self.draw_points(
271
+ frame, show_heading=show_heading)
272
+
273
+ if with_traj:
274
+ traj_layer, traj_alpha = self.draw_trajectory(
275
+ frame, linewidth)
276
+ map_vis = self.layer_blending(base_layer, traj_layer, traj_alpha)
277
+ map_vis = (map_vis*255.).astype(np.uint8)
278
+ else:
279
+ map_vis = base_layer
280
+
281
+ return map_vis
282
+
283
+ def render_roaduser_points(self, list_of_points, show_heading=False):
284
+ ## this method is used to render a list of roaduser point, this is particularly useful when you have a list of points without knowing the id (so you can't generate frame)
285
+
286
+ base_layer = self.draw_points(
287
+ list_of_points, show_heading=show_heading)
288
+ return base_layer
289
+
@@ -0,0 +1,10 @@
1
+ Metadata-Version: 2.4
2
+ Name: msight_base
3
+ Version: 0.1.2
4
+ Summary: Object classes and base trajectory management for the MSight system
5
+ Author-email: Rusheng Zhang <zrs1990@gmail.com>
6
+ Requires-Python: >=3.6
7
+ Requires-Dist: numpy
8
+ Requires-Dist: opencv-python
9
+ Requires-Dist: tqdm
10
+ Requires-Dist: commonroad-io
@@ -0,0 +1,16 @@
1
+ msight_base/__init__.py,sha256=pkeaGsGHCbbH4o0qkSjFb7eAKl-nMNiorNwYBNgYWEY,77
2
+ msight_base/behavior.py,sha256=vEouWCXx1rjKnmRDgEFgDo8DPyoh_OZegNxXi42OH6s,732
3
+ msight_base/detection.py,sha256=v6GG4UuLOyZcwdRz2dWUX-O7AWCMwvsT-_mhWchS7Nw,1643
4
+ msight_base/map.py,sha256=YCM_oNYkmtmpeerlvbdreGsF0-mOOVHuzaO5TbF3-74,9251
5
+ msight_base/road_user.py,sha256=X0US7aaY1a5-gUVYLGT3HV_QHDNaKEewMygpAlPdUEQ,6651
6
+ msight_base/trajectory.py,sha256=eNq_dSrBVy4q7BVqqGnYVfyGc0zxLwNPMySn9DRgP-4,6894
7
+ msight_base/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ msight_base/utils/cls.py,sha256=ShJ3loBdzEN9m4dqexU-hWQ60nV_c879siw5fbPAXOY,315
9
+ msight_base/utils/data.py,sha256=ByvesNDSozRTCwQBAySrVLmavjgZH9UAwG2OfEnREx8,1194
10
+ msight_base/visualizer/__init__.py,sha256=IEWq4Rah8uNuhp9ay1lj3t8n40tY-ZDc3g3DKxZWv0I,36
11
+ msight_base/visualizer/utils.py,sha256=kd5OwLWELhGK5N-cCv0nDS-mHApPMcQ9erQMmAQzM-U,4297
12
+ msight_base/visualizer/visualizer.py,sha256=lBFIyfETqFaXCMK2NdLkg-4MGkVmrGSwtf6XFWLgDwM,11324
13
+ msight_base-0.1.2.dist-info/METADATA,sha256=GMAQnxBCpksvEUbSqLB6Ukcex1Dye9KYD3lNXm7MbLs,312
14
+ msight_base-0.1.2.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
15
+ msight_base-0.1.2.dist-info/top_level.txt,sha256=6I_xkTYR6LZXAjnAiTFNVItZhpdUpTRMj_TjvOs2Wig,12
16
+ msight_base-0.1.2.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.10.2)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ msight_base