Source code for feature_extractor.CarLidarFeatureExtractor

import math
from src.Roadway.roadway import Roadway
from src.Record.record import SceneRecord
from src.Record.frame import Frame
from src.Vec import VecE2, VecSE2
from feature_extractor.collision_detection import ConvexPolygon, to_oriented_bounding_box_2, get_collision_time


[docs]class LidarSensor: def __init__(self, nbeams: int, max_range: float = 100.0, angle_offset: float = 0.0, angle_spread: float = 2*math.pi): ''' a single lidar detector ''' if nbeams > 1: start = angle_offset - angle_spread/2 stop = angle_offset + angle_spread/2 length = nbeams+1 interval = (stop - start)/(length - 1) angles = [start+interval*i for i in range(1, length)] else: angles = [] nbeams = 0 ranges = [None for i in range(nbeams)] range_rates = [None for i in range(nbeams)] self.angles = angles self.ranges = ranges self.range_rates = range_rates self.max_range = max_range self.poly = ConvexPolygon(4) @property def nbeams(self): return len(self.angles)
[docs]class CarLidarFeatureExtractor: def __init__(self, carlidar_nbeams: int = 20, extract_carlidar_rangerate: bool = True, carlidar_max_range: float = 50.0): ''' LIDAR Range and Range Rate 20 artificial LIDAR beams output in regular polar intervals, providing the relative position and velocity of intercepted objects. ''' self.carlidar = LidarSensor(carlidar_nbeams, max_range=carlidar_max_range, angle_offset=0.) self.num_features = self.carlidar.nbeams * (1 + extract_carlidar_rangerate) self.features = [0 for i in range(self.num_features)] self.extract_carlidar_rangerate = extract_carlidar_rangerate def __len__(self): return self.num_features
[docs] def pull_features(self, rec: SceneRecord, roadway: Roadway, veh_idx: int, models: {}, pastframe: int = 0): scene = rec[pastframe] nbeams_carlidar = self.carlidar.nbeams idx = 0 if nbeams_carlidar > 0: self.carlidar = observe(self.carlidar, scene, roadway, veh_idx) stop = len(self.carlidar.ranges) + idx self.features[idx:stop] = self.carlidar.ranges idx += nbeams_carlidar if self.extract_carlidar_rangerate: stop = len(self.carlidar.range_rates) + idx self.features[idx:stop] = self.carlidar.range_rates return self.features
[docs] def feature_names(self): fs = [] for i in range(self.carlidar.nbeams): fs.append("lidar_{}".format(i)) if self.extract_carlidar_rangerate: for i in range(self.carlidar.nbeams): fs.append("rangerate_lidar_{}".format(i)) return fs
[docs] def feature_info(self): info = dict() for name in self.feature_names(): if "rangerate" in name: info[name] = {"high": 30., "low": -30.} else: info[name] = {"high": self.carlidar.max_range, "low": 0.} return info
[docs]def observe(lidar: LidarSensor, scene: Frame, roadway: Roadway, vehicle_index: int): state_ego = scene[vehicle_index].state egoid = scene[vehicle_index].id ego_vel = VecE2.polar(state_ego.v, state_ego.posG.theta) in_range_ids = set() for i in range(scene.n): veh = scene[i] if veh.id != egoid: a = state_ego.posG - veh.state.posG distance = VecE2.norm(VecE2.VecE2(a.x, a.y)) # account for the length and width of the vehicle by considering # the worst case where their maximum radius is aligned distance = distance - math.hypot(veh.definition.length_ / 2., veh.definition.width_ / 2.) if distance < lidar.max_range: in_range_ids.add(veh.id) # compute range and range_rate for each angle for (i, angle) in enumerate(lidar.angles): ray_angle = state_ego.posG.theta + angle ray_vec = VecE2.polar(1.0, ray_angle) ray = VecSE2.VecSE2(state_ego.posG.x, state_ego.posG.y, ray_angle) range_ = lidar.max_range range_rate = 0.0 for j in range(scene.n): veh = scene[j] # only consider the set of potentially in range vehicles if veh.id in in_range_ids: lidar.poly.set(to_oriented_bounding_box_2(lidar.poly, veh)) range2 = get_collision_time(ray, lidar.poly, 1.0) # TODO: continue finish here if range2 and range2 < range_: range_ = range2 relative_speed = VecE2.polar(veh.state.v, veh.state.posG.theta) - ego_vel range_rate = VecE2.proj_(relative_speed, ray_vec) lidar.ranges[i] = range_ lidar.range_rates[i] = range_rate return lidar