3333import os
3434from typing import List , Dict
3535from collections import defaultdict
36+ from datetime import datetime
3637# ROS, CV
3738import rospy
3839import message_filters
4849from .pedestrian_detection_utils import *
4950from ..interface .gem import GEMInterface
5051from ..component import Component
51- from .AgentTracker import AgentTracker
52+ from .IdTracker import IdTracker
5253
5354
5455def box_to_fake_agent (box ):
@@ -110,6 +111,10 @@ def __init__(self, vehicle_interface : GEMInterface) -> None:
110111 self .tf_listener = tf .TransformListener ()
111112
112113 if self .debug : self .init_debug ()
114+
115+ self .prev_time = None # Time in seconds since last scan for basic velocity calculation
116+ self .current_time = None # Time in seconds of current scan for basic velocity calculation
117+ self .id_tracker = IdTracker ()
113118
114119 def init_debug (self ,) -> None :
115120 # Debug Publishers
@@ -144,7 +149,7 @@ def find_dims(self, clusters: List[List[np.ndarray]]) -> List[np.ndarray]:
144149 # Work towards own tracking class instead of simple YOLO track?
145150 # Fix division by time
146151 # ret: Dict[track_id: vel[x, y, z]]
147- def find_vels (self , track_ids : List [int ], obj_centers : List [np .ndarray ]) -> Dict [int , np .ndarray ]:
152+ def find_vels (self , track_ids : List [int ], obj_centers : List [np .ndarray ], obj_dims : List [ np . ndarray ] ) -> Dict [int , np .ndarray ]:
148153 # Object not seen -> velocity = None
149154 track_id_center_map = dict (zip (track_ids , obj_centers ))
150155 vels = defaultdict (lambda : np .array (())) # None is faster, np.array matches other find_ methods.
@@ -159,8 +164,7 @@ def find_vels(self, track_ids: List[int], obj_centers: List[np.ndarray]) -> Dict
159164 if prev_agent .pose .x and prev_agent .pose .y and prev_agent .pose .z and track_id_center_map [prev_agent .track_id ].shape == 3 :
160165 vels [prev_track_id ] = (track_id_center_map [prev_track_id ] - np .array ([prev_agent .pose .x , prev_agent .pose .y , prev_agent .pose .z ])) / (self .curr_time - self .prev_time )
161166 return vels
162-
163-
167+
164168 # TODO: Separate debug/viz class, bbox and 2d 3d points funcs
165169 def viz_object_states (self , cv_image , boxes , extracted_pts_all ):
166170 # Extract 3D pedestrians points in lidar frame
@@ -221,7 +225,7 @@ def viz_object_states(self, cv_image, boxes, extracted_pts_all):
221225
222226
223227 def update_object_states (self , track_result : List [Results ], extracted_pts_all : List [np .ndarray ]) -> None :
224- self .prev_agents = self .current_agents .copy ()
228+ # self.prev_agents = self.current_agents.copy()
225229 self .current_agents .clear ()
226230
227231 # Return if no track results available
@@ -263,27 +267,124 @@ def update_object_states(self, track_result: List[Results], extracted_pts_all: L
263267
264268 # TODO: CONVERT FROM VEHICLE FRAME TO START FRAME HERE
265269 # Then compare previous and current agents with the same id to calculate velocity
266- obj_vels = self .find_vels (track_ids , obj_centers )
267-
268- # Update Current AgentStates
269- for ind in range (num_objs ):
270- obj_center = (None , None , None ) if obj_centers [ind ].size == 0 else obj_centers [ind ]
271- obj_dim = (None , None , None ) if obj_dims [ind ].size == 0 else obj_dims [ind ]
272- self .current_agents [track_ids [ind ]] = (
273- AgentState (
274- track_id = track_ids [ind ],
275- pose = ObjectPose (t = 0 , x = obj_center [0 ], y = obj_center [1 ], z = obj_center [2 ] ,yaw = 0 ,pitch = 0 ,roll = 0 ,frame = ObjectFrameEnum .CURRENT ),
276- # (l, w, h)
277- # TODO: confirm (z -> l, x -> w, y -> h)
278- dimensions = (obj_dim [0 ], obj_dim [1 ], obj_dim [2 ]),
279- outline = None ,
280- type = AgentEnum .PEDESTRIAN ,
281- activity = AgentActivityEnum .MOVING ,
282- velocity = None if obj_vels [track_ids [ind ]].size == 0 else tuple (obj_vels [track_ids [ind ]]),
283- yaw_rate = 0
284- ))
270+ self .find_vels_and_ids (obj_centers , obj_dims )
271+ # obj_vels = self.find_vels(track_ids, obj_centers)
272+
273+ # # Update Current AgentStates
274+ # for ind in range(num_objs):
275+ # obj_center = (None, None, None) if obj_centers[ind].size == 0 else obj_centers[ind]
276+ # obj_dim = (None, None, None) if obj_dims[ind].size == 0 else obj_dims[ind]
277+ # self.current_agents[track_ids[ind]] = (
278+ # AgentState(
279+ # track_id = track_ids[ind],
280+ # pose=ObjectPose(t=0, x=obj_center[0], y=obj_center[1], z=obj_center[2] ,yaw=0,pitch=0,roll=0,frame=ObjectFrameEnum.CURRENT),
281+ # # (l, w, h)
282+ # # TODO: confirm (z -> l, x -> w, y -> h)
283+ # dimensions=(obj_dim[0], obj_dim[1], obj_dim[2]),
284+ # outline=None,
285+ # type=AgentEnum.PEDESTRIAN,
286+ # activity=AgentActivityEnum.MOVING,
287+ # velocity= None if obj_vels[track_ids[ind]].size == 0 else tuple(obj_vels[track_ids[ind]]),
288+ # yaw_rate=0
289+ # ))
290+
291+ def find_vels_and_ids (self , obj_centers : List [np .ndarray ], obj_dims : List [np .ndarray ]):
292+ new_prev_agents = {} # Stores current agents in START frame for next time through (since
293+ # planning wants us to send them agents in CURRENT frame)
294+ # Object not seen -> velocity = None
295+ vels = defaultdict (lambda : np .array (())) # None is faster, np.array matches other find_ methods.
296+
297+ # THIS ASSUMES EVERYTHING IS IN THE SAME FRAME WHICH WOULD WORK FOR STATIONARY CAR.
298+ # TODO: NEED TO STORE AND INCORPORATE TRANSFORMS SOMEHOW TO DEAL WITH MOVING CAR CASE
299+ assigned = False
300+ num_pairings = len (obj_centers )
301+ converted_centers = obj_centers # TODO: REPLACE WITH THIS: self.convert_vehicle_frame_to_start_frame(obj_centers)
302+
303+ # Loop through the indexes of the obj_center and obj_dim pairings
304+ for idx in range (num_pairings ):
305+ assigned = False
306+
307+ # Loop through previous agents backwards
308+ for prev_id , prev_state in reversed (self .prev_agents .items ()):
309+ # If an obj_center and obj_dim pair overlaps with a previous agent, assume that they're the same agent
310+ if self .agents_overlap (converted_centers [idx ], obj_dims [idx ], prev_state ):
311+ assigned = True
312+
313+ if self .prev_time == None :
314+ # This shouldn't ever be triggered
315+ vel = 0
316+ else :
317+ delta_t = self .curr_time - self .prev_time
318+ vel = (obj_centers [idx ] - np .array ([prev_state .pose .x , prev_state .pose .y , prev_state .pose .z ])) / delta_t .total_seconds ()
319+ print ("VELOCITY:" )
320+ print (vel )
321+
322+ self .current_agents [prev_id ] = (
323+ AgentState (
324+ track_id = prev_id ,
325+ pose = ObjectPose (t = 0 , x = obj_centers [idx ][0 ], y = obj_centers [idx ][1 ], z = obj_centers [idx ][2 ], yaw = 0 ,pitch = 0 ,roll = 0 ,frame = ObjectFrameEnum .CURRENT ),
326+ # (l, w, h)
327+ # TODO: confirm (z -> l, x -> w, y -> h)
328+ dimensions = (obj_dims [idx ][0 ], obj_dims [idx ][1 ], obj_dims [idx ][2 ]),
329+ outline = None ,
330+ type = AgentEnum .PEDESTRIAN ,
331+ activity = AgentActivityEnum .MOVING ,
332+ velocity = None if vel .size == 0 else tuple (vel ),
333+ yaw_rate = 0
334+ ))
335+ del self .prev_agents [prev_id ] # Remove previous agent from previous agents
336+ break
337+
338+ # If not assigned:
339+ if not assigned :
340+ # Set velocity to 0 and assign the new agent a new id with IdTracker
341+ id = self .id_tracker .get_new_id ()
342+ self .current_agents [id ] = (
343+ AgentState (
344+ track_id = id ,
345+ pose = ObjectPose (t = 0 , x = obj_centers [idx ][0 ], y = obj_centers [idx ][1 ], z = obj_centers [idx ][2 ] ,yaw = 0 ,pitch = 0 ,roll = 0 ,frame = ObjectFrameEnum .CURRENT ),
346+ # (l, w, h)
347+ # TODO: confirm (z -> l, x -> w, y -> h)
348+ dimensions = (obj_dims [idx ][0 ], obj_dims [idx ][1 ], obj_dims [idx ][2 ]),
349+ outline = None ,
350+ type = AgentEnum .PEDESTRIAN ,
351+ activity = AgentActivityEnum .MOVING ,
352+ velocity = None ,
353+ yaw_rate = 0
354+ ))
355+ self .prev_agents = new_prev_agents
356+
357+ # Calculates whether 2 agents overlap in START frame. True if they do, false if not
358+ def agents_overlap (obj_center : np .ndarray , obj_dim : np .ndarray , prev_agent : AgentState ) -> bool :
359+ # Calculate corners of obj_center and obj_dim pairing
360+ x1_min , x1_max = obj_center [0 ] - obj_dim [0 ] / 2.0 , obj_center [0 ] + obj_dim [0 ] / 2.0
361+ y1_min , y1_max = obj_center [1 ] - obj_dim [1 ] / 2.0 , obj_center [1 ] + obj_dim [1 ] / 2.0 # CENTER CALCULATION
362+ z1_min , z1_max = obj_center [2 ] - obj_dim [2 ] / 2.0 , obj_center [2 ] + obj_dim [2 ] / 2.0
363+
364+ # Calculate corners of AgentState
365+ # Beware: AgentState(PhysicalObject) builds bbox from
366+ # dims [-l/2,l/2] x [-w/2,w/2] x [0,h], not
367+ # [-l/2,l/2] x [-w/2,w/2] x [-h/2,h/2]
368+ # TODO: confirm (z -> l, x -> w, y -> h)
369+ x2_min , x2_max = prev_agent .pose .x - prev_agent .dimensions .width / 2.0 , prev_agent .pose .x + prev_agent .dimensions .width / 2.0
370+ y2_min , y2_max = prev_agent .pose .y , prev_agent .pose .y + prev_agent .dimensions .height # AGENT STATE CALCULATION
371+ z2_min , z2_max = prev_agent .pose .z - prev_agent .dimensions .length / 2.0 , prev_agent .pose .z + prev_agent .dimensions .length / 2.0
372+
373+ # True if they overlap, false if not
374+ return (
375+ ( (x1_min <= x2_min and x2_min <= x1_max ) or (x2_min <= x1_min and x1_min <= x2_max ) ) and
376+ ( (y1_min <= y2_min and y2_min <= y1_max ) or (y2_min <= y1_min and y1_min <= y2_max ) ) and
377+ ( (z1_min <= z2_min and z2_min <= z1_max ) or (z2_min <= z1_min and z1_min <= z2_max ) )
378+ )
379+
380+ def convert_vehicle_frame_to_start_frame (obj_centers : List [np .ndarray ]) -> List [np .ndarray ]:
381+ pass
285382
286383 def ouster_oak_callback (self , rgb_image_msg : Image , lidar_pc2_msg : PointCloud2 ):
384+ # Update times for basic velocity calculation
385+ self .prev_time = self .current_time
386+ self .current_time = datetime .now ()
387+
287388 # Convert to cv2 image and run detector
288389 cv_image = self .bridge .imgmsg_to_cv2 (rgb_image_msg , "bgr8" )
289390 track_result = self .detector .track (source = cv_image , classes = self .classes_to_detect , persist = True , conf = self .confidence )
0 commit comments