-
Notifications
You must be signed in to change notification settings - Fork 10
Vehicle to Start Frame Gen #125
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -47,9 +47,10 @@ | |
| # GEMStack | ||
| from ...state import AllState,VehicleState,ObjectPose,ObjectFrameEnum,AgentState,AgentEnum,AgentActivityEnum,ObjectFrameEnum | ||
| from .pedestrian_detection_utils import * | ||
| from ..interface.gem import GEMInterface | ||
| from ..interface.gem import GEMInterface, GNSSReading | ||
| from ..component import Component | ||
| from .IdTracker import IdTracker | ||
| from scipy.spatial.transform import Rotation as R | ||
|
|
||
| def box_to_fake_agent(box): | ||
| """Creates a fake agent state from an (x,y,w,h) bounding box. | ||
|
|
@@ -80,6 +81,7 @@ def __init__(self, vehicle_interface : GEMInterface) -> None: | |
| # track_id: AgentState | ||
| self.prev_agents = dict() | ||
| self.current_agents = dict() | ||
| self.current_agent_obj_dims = dict() | ||
| # TODO Implement time | ||
| self.confidence = 0.7 | ||
| self.classes_to_detect = 0 | ||
|
|
@@ -98,11 +100,23 @@ def __init__(self, vehicle_interface : GEMInterface) -> None: | |
| [-0.02289521, 0.00333035, 0.9997323]]) | ||
| self.t_lidar_to_vehicle = np.array([[0.0], [0.0], [0.35]]) | ||
|
|
||
| # Subscribers and sychronizers | ||
| self.rgb_rosbag = message_filters.Subscriber('/oak/rgb/image_raw', Image) | ||
| self.top_lidar_rosbag = message_filters.Subscriber('/ouster/points', PointCloud2) | ||
| self.sync = message_filters.ApproximateTimeSynchronizer([self.rgb_rosbag, self.top_lidar_rosbag], queue_size=10, slop=0.1) | ||
| self.sync.registerCallback(self.ouster_oak_callback) | ||
| # To calculate vehicle to start frame data | ||
| self.t_start_to_world = None | ||
| self.t_vehicle_to_world = None | ||
| self.t_vehicle_to_start = None | ||
|
|
||
| # Rospy Subscribers and sychronizers | ||
| # self.rgb_rosbag = message_filters.Subscriber('/oak/rgb/image_raw', Image) | ||
| # self.top_lidar_rosbag = message_filters.Subscriber('/ouster/points', PointCloud2) | ||
| # self.sync = message_filters.ApproximateTimeSynchronizer([self.rgb_rosbag, self.top_lidar_rosbag], queue_size=10, slop=0.1) | ||
| # self.sync.registerCallback(self.ouster_oak_callback) | ||
|
|
||
| # GEMStack Subscribers and sychronizers | ||
| # LIDAR Camera fusion | ||
| self.vehicle_interface.subscribe_sensor('sensor_fusion_Lidar_Camera_GNSS',self.ouster_oak_callback) | ||
|
|
||
| # LIDAR Camera GNSS fusion | ||
| # self.vehicle_interface.subscribe_sensor('sensor_fusion_Lidar_Camera_GNSS',self.ouster_oak_callback) | ||
|
|
||
| # TF listener to get transformation from LiDAR to Camera | ||
| self.tf_listener = tf.TransformListener() | ||
|
|
@@ -115,14 +129,8 @@ def __init__(self, vehicle_interface : GEMInterface) -> None: | |
|
|
||
| # Update function variables | ||
| self.t_start = datetime.now() # Estimated start frame time | ||
| # self.start_pose_abs = None | ||
| # self.start_pose_abs = ObjectPose( | ||
| # frame=ObjectFrameEnum.GLOBAL, | ||
| # t=0, | ||
| # x=0, | ||
| # y=0, | ||
| # z=0 | ||
| # ) | ||
| self.start_pose_abs = None # Get this from GNSS (GLOBAL frame) | ||
| self.current_vehicle_state = None # Current vehicle state from GNSS in GLOBAL frame | ||
|
|
||
| def init_debug(self,) -> None: | ||
| # Debug Publishers | ||
|
|
@@ -132,10 +140,23 @@ def init_debug(self,) -> None: | |
| self.pub_image = rospy.Publisher("/camera/image_detection", Image, queue_size=1) | ||
|
|
||
| def update(self, vehicle : VehicleState) -> Dict[str,AgentState]: | ||
| # if self.start_pose_abs is None: | ||
| # self.start_pose_abs = vehicle.pose # Store first pose which is start frame | ||
| # self.start_pose_abs.to_frame(frame=ObjectFrameEnum.GLOBAL, current_pose=) | ||
| # self.current_vehicle_pose_sf = vehicle.pose # Vehicle pose in start frame | ||
|
|
||
| # Convert to start state. | ||
| # self.current_vehicle_state | data from GNSS of vehicle pose in GLOBAL Frame | ||
| # self.start_pose_abs | data from GNSS of the first vehicle pose in GLOBAL Frame | ||
| vehicle.pose.to_frame(ObjectFrameEnum.START,self.current_vehicle_state.pose,self.start_pose_abs) | ||
|
|
||
| # To be checked with Lucas | ||
| # self.prev_agents = self.current_agents.copy() | ||
| self.current_agents.clear() | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This little bit here is good. I'll modify find_vels_and_ids to accept start frame data instead of current frame data |
||
|
|
||
| # Converting to start frame | ||
| obj_centers = vehicle.pose.apply(self.current_agent_obj_dims["pose"]) | ||
| obj_dims = vehicle.pose.apply(self.current_agent_obj_dims["dims"]) | ||
|
|
||
| # Creating agent state and trackinig ids | ||
| self.find_vels_and_ids(obj_centers, obj_dims) | ||
|
|
||
| return self.current_agents | ||
|
|
||
| # TODO: Improve Algo Knn, ransac, etc. | ||
|
|
@@ -154,29 +175,6 @@ def find_dims(self, clusters: List[List[np.ndarray]]) -> List[np.ndarray]: | |
| clusters = [np.array(clust) for clust in clusters] | ||
| dims = [np.array(()) if clust.size == 0 else np.max(clust, axis= 0) - np.min(clust, axis= 0) for clust in clusters] | ||
| return dims | ||
|
|
||
| # TODO: Slower but cleaner to input self.current_agents dict | ||
| # TODO: Moving Average across last N iterations pos/vel? Less spurious vals | ||
| # TODO Akul: Fix velocity calculation to calculate in ObjectFrameEnum.START | ||
| # Work towards own tracking class instead of simple YOLO track? | ||
| # Fix 1: division by time | ||
| # Fix 2: Put centers and dims in start frame for velocity calc + final agentstate in update_object_states | ||
| # ret: Dict[track_id: vel[x, y, z]] | ||
| # def find_vels(self, track_ids: List[int], obj_centers: List[np.ndarray], obj_dims: List[np.ndarray]) -> Dict[int, np.ndarray]: | ||
| # # Object not seen -> velocity = None | ||
| # track_id_center_map = dict(zip(track_ids, obj_centers)) | ||
| # vels = defaultdict(lambda: np.array(())) # None is faster, np.array matches other find_ methods. | ||
|
|
||
| # for prev_track_id, prev_agent in self.prev_agents.items(): | ||
| # if prev_track_id in track_ids: | ||
| # # TODO: Add prev_agents to memory to avoid None velocity | ||
| # # We should only be missing prev pose on first sight of track_id Agent. | ||
| # # print("shape 1: ", track_id_center_map[prev_agent.track_id]) | ||
| # # print("shape 2: ", np.array([prev_agent.pose.x, prev_agent.pose.y, prev_agent.pose.z])) | ||
| # # prev can be 3 separate Nones, current is just empty array... make this symmetrical | ||
| # 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: | ||
| # 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) | ||
| # return vels | ||
|
|
||
| # TODO: Separate debug/viz class, bbox and 2d 3d points funcs | ||
| def viz_object_states(self, cv_image, boxes, extracted_pts_all): | ||
|
|
@@ -238,9 +236,9 @@ def viz_object_states(self, cv_image, boxes, extracted_pts_all): | |
|
|
||
|
|
||
| def update_object_states(self, track_result: List[Results], extracted_pts_all: List[np.ndarray]) -> None: | ||
| # self.prev_agents = self.current_agents.copy() | ||
| self.current_agents.clear() | ||
|
|
||
|
|
||
| self.current_agent_obj_dims.clear() | ||
| # Return if no track results available | ||
| if track_result[0].boxes.id == None: | ||
| return | ||
|
|
@@ -264,25 +262,25 @@ def update_object_states(self, track_result: List[Results], extracted_pts_all: L | |
| obj_centers = self.find_centers(pedestrians_3d_pts) # Centers are calculated in lidar frame here | ||
| obj_dims = self.find_dims(pedestrians_3d_pts) | ||
|
|
||
| # If in vehicle frame, transform centers from top_lidar frame to vehicle frame | ||
| # Need to transform the center point one by one since matrix op can't deal with empty points | ||
| if self.vehicle_frame: | ||
| obj_centers_vehicle = [] | ||
| for obj_center in obj_centers: | ||
| if len(obj_center) > 0: | ||
| obj_center = np.array([obj_center]) | ||
| obj_center_vehicle = transform_lidar_points(obj_center, self.R_lidar_to_vehicle, self.t_lidar_to_vehicle)[0] | ||
| obj_centers_vehicle.append(obj_center_vehicle) | ||
| else: | ||
| obj_centers_vehicle.append(np.array(())) | ||
| obj_centers = obj_centers_vehicle | ||
| # Pose is stored in vehicle frame and converted to start frame in the update function | ||
| obj_centers_vehicle = [] | ||
| for obj_center in obj_centers: | ||
| if len(obj_center) > 0: | ||
| obj_center = np.array([obj_center]) | ||
| obj_center_vehicle = transform_lidar_points(obj_center, self.R_lidar_to_vehicle, self.t_lidar_to_vehicle)[0] | ||
| obj_centers_vehicle.append(obj_center_vehicle) | ||
| else: | ||
| obj_centers_vehicle.append(np.array(())) | ||
| obj_centers = obj_centers_vehicle | ||
|
|
||
| self.current_agent_obj_dims["pose"] = obj_center | ||
| self.current_agent_obj_dims["dims"] = obj_dims | ||
|
|
||
| self.find_vels_and_ids(obj_centers, obj_dims) | ||
|
|
||
| # TODO: Refactor to make more efficient | ||
| # TODO: Moving Average across last N iterations pos/vel? Less spurious vals | ||
| # TODO Fix velocity calculation to calculate in ObjectFrameEnum.START | ||
| def find_vels_and_ids(self, obj_centers: List[np.ndarray], obj_dims: List[np.ndarray]): | ||
|
|
||
| # Gate to check whether dims and centers are empty (will happen if no pedestrians are scanned): | ||
| for idx in range(len(obj_dims) -1, -1, -1): | ||
| if (obj_centers[idx].size == 0) or (obj_dims[0].size == 0): | ||
|
|
@@ -421,36 +419,87 @@ def create_agent_states_in_start_frame(self, obj_centers: List[np.ndarray], obj_ | |
| ) | ||
|
|
||
| # Convert agent to start frame and add to agents list: | ||
| agents.append( | ||
| state | ||
| # state.to_frame( | ||
| # frame=ObjectFrameEnum.START, | ||
| # current_pose=self.current_vehicle_pose_sf, | ||
| # # current_pose=ObjectPose( | ||
| # # frame=ObjectFrameEnum.CURRENT, | ||
| # # t=(self.curr_time - self.t_start).total_seconds(), | ||
| # # x=state.pose.x, | ||
| # # y=state.pose.y, | ||
| # # z=state.pose.z | ||
| # # ), | ||
| # start_pose_abs=self.start_pose_abs | ||
| # ) | ||
| ) | ||
| agents.append(state) | ||
|
|
||
| # Return the agent states converted to start frame: | ||
| return agents | ||
|
|
||
|
|
||
| # TODO : Generate Transformation matrix from vehicle to start | ||
| # Just keeping this here incase we need it, at this moment this function will not be used. | ||
| # def generate_vehicle_start_frame(self) -> np.ndarray: | ||
| # ''' | ||
| # Creates T matrix for WORLD to START Frame and T matrix for WORLD to VEHICLE Frame | ||
| # Return T VEHICLE to START | ||
| # ''' | ||
|
|
||
| # # T World to Start | ||
| # start_x, start_y, start_z = self.current_vehicle_state.pose.x, self.current_vehicle_state.pose.y, self.current_vehicle_state.pose.z | ||
| # start_yaw, start_roll, start_pitch = self.current_vehicle_state.pose.yaw, self.current_vehicle_state.pose.pitch, self.current_vehicle_state.pose.roll | ||
| # rotation_world_start = R.from_euler('xyz',[start_roll, start_pitch,start_yaw],degrees=False).as_matrix() | ||
| # self.t_start_to_world = np.eye(4) | ||
| # self.t_start_to_world[:3,:3] = rotation_world_start | ||
| # self.t_start_to_world[:3,3] = [start_x, start_y, start_z] | ||
|
|
||
|
|
||
| # # Converting vehicle_state from START to CURRENT | ||
| # self.current_vehicle_state.to_frame(frame=ObjectFrameEnum.CURRENT, current_pose=self.current_vehicle_state.pose, start_pose_abs=self.start_pose_abs) | ||
|
|
||
| # # T World to Vehicle | ||
| # vehicle_x, vehicle_y, vehicle_z = self.current_vehicle_state.pose.x, self.current_vehicle_state.pose.y, self.current_vehicle_state.pose.z | ||
| # vehicle_yaw, vehicle_roll, vehicle_pitch = self.current_vehicle_state.pose.yaw, self.current_vehicle_state.pose.pitch, self.current_vehicle_state.pose.roll | ||
| # rotation_world_vehicle = R.from_euler('xyz',[vehicle_roll, vehicle_pitch, vehicle_yaw],degrees=False).as_matrix() | ||
| # self.t_vehicle_to_world = np.eye(4) | ||
| # self.t_vehicle_to_world[:3,:3] = rotation_world_vehicle | ||
| # self.t_vehicle_to_world[:3,3] = [vehicle_x, vehicle_y, vehicle_z] | ||
|
|
||
| # return np.linalg.inv(self.t_start_to_world @ np.linalg.inv(self.t_vehicle_to_world)) | ||
|
|
||
|
|
||
| # TODO: Slower but cleaner to input self.current_agents dict | ||
| # TODO: Moving Average across last N iterations pos/vel? Less spurious vals | ||
| # TODO Akul: Fix velocity calculation to calculate in ObjectFrameEnum.START | ||
| # Work towards own tracking class instead of simple YOLO track? | ||
| # Fix 1: division by time | ||
| # Fix 2: Put centers and dims in start frame for velocity calc + final agentstate in update_object_states | ||
| # ret: Dict[track_id: vel[x, y, z]] | ||
| # def find_vels(self, track_ids: List[int], obj_centers: List[np.ndarray], obj_dims: List[np.ndarray]) -> Dict[int, np.ndarray]: | ||
| # # Object not seen -> velocity = None | ||
| # track_id_center_map = dict(zip(track_ids, obj_centers)) | ||
| # vels = defaultdict(lambda: np.array(())) # None is faster, np.array matches other find_ methods. | ||
|
|
||
| # for prev_track_id, prev_agent in self.prev_agents.items(): | ||
| # if prev_track_id in track_ids: | ||
| # # TODO: Add prev_agents to memory to avoid None velocity | ||
| # # We should only be missing prev pose on first sight of track_id Agent. | ||
| # # print("shape 1: ", track_id_center_map[prev_agent.track_id]) | ||
| # # print("shape 2: ", np.array([prev_agent.pose.x, prev_agent.pose.y, prev_agent.pose.z])) | ||
| # # prev can be 3 separate Nones, current is just empty array... make this symmetrical | ||
| # 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: | ||
| # 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) | ||
| # return vels | ||
|
|
||
| def ouster_oak_callback(self, rgb_image_msg: Image, lidar_pc2_msg: PointCloud2): | ||
| def ouster_oak_callback(self, cv_image: cv2.Mat, lidar_points: np.ndarray, vehicle_state: GNSSReading): | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should rename the variable vehicle_state here because it's confusing. VehicleState is the name of a class so if I were reading the code and working with it I'd assume this is an object of that class. |
||
| # Update times for basic velocity calculation | ||
| self.prev_time = self.curr_time | ||
| self.curr_time = datetime.now() | ||
|
|
||
| # Getting start pose in GLOBAL Frame | ||
| if self.start_pose_abs == None and vehicle_state.status == 'ok': | ||
| self.start_pose_abs = vehicle_state.pose | ||
|
|
||
| # Update current vehicle state and convert to START Frame | ||
| if (vehicle_state.status == 'ok'): | ||
nvikramraj marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| self.current_vehicle_state = vehicle_state | ||
| else: | ||
| raise Exception('Unable to get current pose of vehicle, lost GPS') | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I love it that you used an exception here. I think there are a lot of places where we should be using them to check for edge cases. This might be a confusing exception for the other teams though. It may potentially be a better idea to log this, print it to the console, and throw out the currently scanned in pedestrians because we can't calculate their positions relative to start frame. This might be a good question to ask your roommate what he thinks? |
||
|
|
||
| # Convert to cv2 image and run detector | ||
| cv_image = self.bridge.imgmsg_to_cv2(rgb_image_msg, "bgr8") | ||
| # cv_image = self.bridge.imgmsg_to_cv2(rgb_image_msg, "bgr8") | ||
nvikramraj marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| track_result = self.detector.track(source=cv_image, classes=self.classes_to_detect, persist=True, conf=self.confidence) | ||
|
|
||
| # Convert 1D PointCloud2 data to x, y, z coords | ||
| lidar_points = convert_pointcloud2_to_xyz(lidar_pc2_msg) | ||
| # lidar_points = convert_pointcloud2_to_xyz(lidar_pc2_msg) | ||
nvikramraj marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| # print("len lidar_points", len(lidar_points)) | ||
|
|
||
| # Downsample xyz point clouds | ||
|
|
@@ -495,6 +544,7 @@ def ouster_oak_callback(self, rgb_image_msg: Image, lidar_pc2_msg: PointCloud2): | |
| extracted_pts_all.append(extracted_pts) | ||
| else: extracted_pts_all.append(np.array(())) | ||
|
|
||
| # Generate Transformation matrix for vehicle to start | ||
| self.update_object_states(track_result, extracted_pts_all) | ||
| if self.debug: self.viz_object_states(cv_image, boxes, extracted_pts_all) | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,4 +10,5 @@ dacite | |
|
|
||
| # Perception | ||
| ultralytics | ||
| lap==0.5.12 | ||
| lap==0.5.12 | ||
| open3d | ||
Uh oh!
There was an error while loading. Please reload this page.