472 lines
No EOL
20 KiB
Python
472 lines
No EOL
20 KiB
Python
import sys
|
|
import os
|
|
import numpy as np
|
|
import pandas as pd
|
|
import dill
|
|
import argparse
|
|
from tqdm import tqdm
|
|
from pyquaternion import Quaternion
|
|
from kalman_filter import NonlinearKinematicBicycle
|
|
from sklearn.model_selection import train_test_split
|
|
|
|
nu_path = './devkit/python-sdk/'
|
|
sys.path.append(nu_path)
|
|
sys.path.append("../../trajectron")
|
|
from nuscenes.nuscenes import NuScenes
|
|
from nuscenes.map_expansion.map_api import NuScenesMap
|
|
from nuscenes.utils.splits import create_splits_scenes
|
|
from environment import Environment, Scene, Node, GeometricMap, derivative_of
|
|
|
|
scene_blacklist = [499, 515, 517]
|
|
|
|
FREQUENCY = 2
|
|
dt = 1 / FREQUENCY
|
|
data_columns_vehicle = pd.MultiIndex.from_product([['position', 'velocity', 'acceleration', 'heading'], ['x', 'y']])
|
|
data_columns_vehicle = data_columns_vehicle.append(pd.MultiIndex.from_tuples([('heading', '°'), ('heading', 'd°')]))
|
|
data_columns_vehicle = data_columns_vehicle.append(pd.MultiIndex.from_product([['velocity', 'acceleration'], ['norm']]))
|
|
|
|
data_columns_pedestrian = pd.MultiIndex.from_product([['position', 'velocity', 'acceleration'], ['x', 'y']])
|
|
|
|
curv_0_2 = 0
|
|
curv_0_1 = 0
|
|
total = 0
|
|
|
|
standardization = {
|
|
'PEDESTRIAN': {
|
|
'position': {
|
|
'x': {'mean': 0, 'std': 1},
|
|
'y': {'mean': 0, 'std': 1}
|
|
},
|
|
'velocity': {
|
|
'x': {'mean': 0, 'std': 2},
|
|
'y': {'mean': 0, 'std': 2}
|
|
},
|
|
'acceleration': {
|
|
'x': {'mean': 0, 'std': 1},
|
|
'y': {'mean': 0, 'std': 1}
|
|
}
|
|
},
|
|
'VEHICLE': {
|
|
'position': {
|
|
'x': {'mean': 0, 'std': 80},
|
|
'y': {'mean': 0, 'std': 80}
|
|
},
|
|
'velocity': {
|
|
'x': {'mean': 0, 'std': 15},
|
|
'y': {'mean': 0, 'std': 15},
|
|
'norm': {'mean': 0, 'std': 15}
|
|
},
|
|
'acceleration': {
|
|
'x': {'mean': 0, 'std': 4},
|
|
'y': {'mean': 0, 'std': 4},
|
|
'norm': {'mean': 0, 'std': 4}
|
|
},
|
|
'heading': {
|
|
'x': {'mean': 0, 'std': 1},
|
|
'y': {'mean': 0, 'std': 1},
|
|
'°': {'mean': 0, 'std': np.pi},
|
|
'd°': {'mean': 0, 'std': 1}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
def augment_scene(scene, angle):
|
|
def rotate_pc(pc, alpha):
|
|
M = np.array([[np.cos(alpha), -np.sin(alpha)],
|
|
[np.sin(alpha), np.cos(alpha)]])
|
|
return M @ pc
|
|
|
|
data_columns_vehicle = pd.MultiIndex.from_product([['position', 'velocity', 'acceleration', 'heading'], ['x', 'y']])
|
|
data_columns_vehicle = data_columns_vehicle.append(pd.MultiIndex.from_tuples([('heading', '°'), ('heading', 'd°')]))
|
|
data_columns_vehicle = data_columns_vehicle.append(pd.MultiIndex.from_product([['velocity', 'acceleration'], ['norm']]))
|
|
|
|
data_columns_pedestrian = pd.MultiIndex.from_product([['position', 'velocity', 'acceleration'], ['x', 'y']])
|
|
|
|
scene_aug = Scene(timesteps=scene.timesteps, dt=scene.dt, name=scene.name, non_aug_scene=scene)
|
|
|
|
alpha = angle * np.pi / 180
|
|
|
|
for node in scene.nodes:
|
|
if node.type == 'PEDESTRIAN':
|
|
x = node.data.position.x.copy()
|
|
y = node.data.position.y.copy()
|
|
|
|
x, y = rotate_pc(np.array([x, y]), alpha)
|
|
|
|
vx = derivative_of(x, scene.dt)
|
|
vy = derivative_of(y, scene.dt)
|
|
ax = derivative_of(vx, scene.dt)
|
|
ay = derivative_of(vy, scene.dt)
|
|
|
|
data_dict = {('position', 'x'): x,
|
|
('position', 'y'): y,
|
|
('velocity', 'x'): vx,
|
|
('velocity', 'y'): vy,
|
|
('acceleration', 'x'): ax,
|
|
('acceleration', 'y'): ay}
|
|
|
|
node_data = pd.DataFrame(data_dict, columns=data_columns_pedestrian)
|
|
|
|
node = Node(node_type=node.type, node_id=node.id, data=node_data, first_timestep=node.first_timestep)
|
|
elif node.type == 'VEHICLE':
|
|
x = node.data.position.x.copy()
|
|
y = node.data.position.y.copy()
|
|
|
|
heading = getattr(node.data.heading, '°').copy()
|
|
heading += alpha
|
|
heading = (heading + np.pi) % (2.0 * np.pi) - np.pi
|
|
|
|
x, y = rotate_pc(np.array([x, y]), alpha)
|
|
|
|
vx = derivative_of(x, scene.dt)
|
|
vy = derivative_of(y, scene.dt)
|
|
ax = derivative_of(vx, scene.dt)
|
|
ay = derivative_of(vy, scene.dt)
|
|
|
|
v = np.stack((vx, vy), axis=-1)
|
|
v_norm = np.linalg.norm(np.stack((vx, vy), axis=-1), axis=-1, keepdims=True)
|
|
heading_v = np.divide(v, v_norm, out=np.zeros_like(v), where=(v_norm > 1.))
|
|
heading_x = heading_v[:, 0]
|
|
heading_y = heading_v[:, 1]
|
|
|
|
data_dict = {('position', 'x'): x,
|
|
('position', 'y'): y,
|
|
('velocity', 'x'): vx,
|
|
('velocity', 'y'): vy,
|
|
('velocity', 'norm'): np.linalg.norm(np.stack((vx, vy), axis=-1), axis=-1),
|
|
('acceleration', 'x'): ax,
|
|
('acceleration', 'y'): ay,
|
|
('acceleration', 'norm'): np.linalg.norm(np.stack((ax, ay), axis=-1), axis=-1),
|
|
('heading', 'x'): heading_x,
|
|
('heading', 'y'): heading_y,
|
|
('heading', '°'): heading,
|
|
('heading', 'd°'): derivative_of(heading, dt, radian=True)}
|
|
|
|
node_data = pd.DataFrame(data_dict, columns=data_columns_vehicle)
|
|
|
|
node = Node(node_type=node.type, node_id=node.id, data=node_data, first_timestep=node.first_timestep,
|
|
non_aug_node=node)
|
|
|
|
scene_aug.nodes.append(node)
|
|
return scene_aug
|
|
|
|
|
|
def augment(scene):
|
|
scene_aug = np.random.choice(scene.augmented)
|
|
scene_aug.temporal_scene_graph = scene.temporal_scene_graph
|
|
scene_aug.map = scene.map
|
|
return scene_aug
|
|
|
|
|
|
def trajectory_curvature(t):
|
|
path_distance = np.linalg.norm(t[-1] - t[0])
|
|
|
|
lengths = np.sqrt(np.sum(np.diff(t, axis=0) ** 2, axis=1)) # Length between points
|
|
path_length = np.sum(lengths)
|
|
if np.isclose(path_distance, 0.):
|
|
return 0, 0, 0
|
|
return (path_length / path_distance) - 1, path_length, path_distance
|
|
|
|
|
|
def process_scene(ns_scene, env, nusc, data_path):
|
|
scene_id = int(ns_scene['name'].replace('scene-', ''))
|
|
data = pd.DataFrame(columns=['frame_id',
|
|
'type',
|
|
'node_id',
|
|
'robot',
|
|
'x', 'y', 'z',
|
|
'length',
|
|
'width',
|
|
'height',
|
|
'heading'])
|
|
|
|
sample_token = ns_scene['first_sample_token']
|
|
sample = nusc.get('sample', sample_token)
|
|
frame_id = 0
|
|
while sample['next']:
|
|
annotation_tokens = sample['anns']
|
|
for annotation_token in annotation_tokens:
|
|
annotation = nusc.get('sample_annotation', annotation_token)
|
|
category = annotation['category_name']
|
|
if len(annotation['attribute_tokens']):
|
|
attribute = nusc.get('attribute', annotation['attribute_tokens'][0])['name']
|
|
else:
|
|
continue
|
|
|
|
if 'pedestrian' in category and not 'stroller' in category and not 'wheelchair' in category:
|
|
our_category = env.NodeType.PEDESTRIAN
|
|
elif 'vehicle' in category and 'bicycle' not in category and 'motorcycle' not in category and 'parked' not in attribute:
|
|
our_category = env.NodeType.VEHICLE
|
|
else:
|
|
continue
|
|
|
|
data_point = pd.Series({'frame_id': frame_id,
|
|
'type': our_category,
|
|
'node_id': annotation['instance_token'],
|
|
'robot': False,
|
|
'x': annotation['translation'][0],
|
|
'y': annotation['translation'][1],
|
|
'z': annotation['translation'][2],
|
|
'length': annotation['size'][0],
|
|
'width': annotation['size'][1],
|
|
'height': annotation['size'][2],
|
|
'heading': Quaternion(annotation['rotation']).yaw_pitch_roll[0]})
|
|
data = data.append(data_point, ignore_index=True)
|
|
|
|
# Ego Vehicle
|
|
our_category = env.NodeType.VEHICLE
|
|
sample_data = nusc.get('sample_data', sample['data']['CAM_FRONT'])
|
|
annotation = nusc.get('ego_pose', sample_data['ego_pose_token'])
|
|
data_point = pd.Series({'frame_id': frame_id,
|
|
'type': our_category,
|
|
'node_id': 'ego',
|
|
'robot': True,
|
|
'x': annotation['translation'][0],
|
|
'y': annotation['translation'][1],
|
|
'z': annotation['translation'][2],
|
|
'length': 4,
|
|
'width': 1.7,
|
|
'height': 1.5,
|
|
'heading': Quaternion(annotation['rotation']).yaw_pitch_roll[0],
|
|
'orientation': None})
|
|
data = data.append(data_point, ignore_index=True)
|
|
|
|
sample = nusc.get('sample', sample['next'])
|
|
frame_id += 1
|
|
|
|
if len(data.index) == 0:
|
|
return None
|
|
|
|
data.sort_values('frame_id', inplace=True)
|
|
max_timesteps = data['frame_id'].max()
|
|
|
|
x_min = np.round(data['x'].min() - 50)
|
|
x_max = np.round(data['x'].max() + 50)
|
|
y_min = np.round(data['y'].min() - 50)
|
|
y_max = np.round(data['y'].max() + 50)
|
|
|
|
data['x'] = data['x'] - x_min
|
|
data['y'] = data['y'] - y_min
|
|
|
|
scene = Scene(timesteps=max_timesteps + 1, dt=dt, name=str(scene_id), aug_func=augment)
|
|
|
|
# Generate Maps
|
|
map_name = nusc.get('log', ns_scene['log_token'])['location']
|
|
nusc_map = NuScenesMap(dataroot=data_path, map_name=map_name)
|
|
|
|
type_map = dict()
|
|
x_size = x_max - x_min
|
|
y_size = y_max - y_min
|
|
patch_box = (x_min + 0.5 * (x_max - x_min), y_min + 0.5 * (y_max - y_min), y_size, x_size)
|
|
patch_angle = 0 # Default orientation where North is up
|
|
canvas_size = (np.round(3 * y_size).astype(int), np.round(3 * x_size).astype(int))
|
|
homography = np.array([[3., 0., 0.], [0., 3., 0.], [0., 0., 3.]])
|
|
layer_names = ['lane', 'road_segment', 'drivable_area', 'road_divider', 'lane_divider', 'stop_line',
|
|
'ped_crossing', 'stop_line', 'ped_crossing', 'walkway']
|
|
map_mask = (nusc_map.get_map_mask(patch_box, patch_angle, layer_names, canvas_size) * 255.0).astype(
|
|
np.uint8)
|
|
map_mask = np.swapaxes(map_mask, 1, 2) # x axis comes first
|
|
# PEDESTRIANS
|
|
map_mask_pedestrian = np.stack((map_mask[9], map_mask[8], np.max(map_mask[:3], axis=0)), axis=0)
|
|
type_map['PEDESTRIAN'] = GeometricMap(data=map_mask_pedestrian, homography=homography, description=', '.join(layer_names))
|
|
# VEHICLES
|
|
map_mask_vehicle = np.stack((np.max(map_mask[:3], axis=0), map_mask[3], map_mask[4]), axis=0)
|
|
type_map['VEHICLE'] = GeometricMap(data=map_mask_vehicle, homography=homography, description=', '.join(layer_names))
|
|
|
|
map_mask_plot = np.stack(((np.max(map_mask[:3], axis=0) - (map_mask[3] + 0.5 * map_mask[4]).clip(
|
|
max=255)).clip(min=0).astype(np.uint8), map_mask[8], map_mask[9]), axis=0)
|
|
type_map['VISUALIZATION'] = GeometricMap(data=map_mask_plot, homography=homography, description=', '.join(layer_names))
|
|
|
|
scene.map = type_map
|
|
del map_mask
|
|
del map_mask_pedestrian
|
|
del map_mask_vehicle
|
|
del map_mask_plot
|
|
|
|
for node_id in pd.unique(data['node_id']):
|
|
node_frequency_multiplier = 1
|
|
node_df = data[data['node_id'] == node_id]
|
|
|
|
if node_df['x'].shape[0] < 2:
|
|
continue
|
|
|
|
if not np.all(np.diff(node_df['frame_id']) == 1):
|
|
# print('Occlusion')
|
|
continue # TODO Make better
|
|
|
|
node_values = node_df[['x', 'y']].values
|
|
x = node_values[:, 0]
|
|
y = node_values[:, 1]
|
|
heading = node_df['heading'].values
|
|
if node_df.iloc[0]['type'] == env.NodeType.VEHICLE and not node_id == 'ego':
|
|
# Kalman filter Agent
|
|
vx = derivative_of(x, scene.dt)
|
|
vy = derivative_of(y, scene.dt)
|
|
velocity = np.linalg.norm(np.stack((vx, vy), axis=-1), axis=-1)
|
|
|
|
filter_veh = NonlinearKinematicBicycle(dt=scene.dt, sMeasurement=1.0)
|
|
P_matrix = None
|
|
for i in range(len(x)):
|
|
if i == 0: # initalize KF
|
|
# initial P_matrix
|
|
P_matrix = np.identity(4)
|
|
elif i < len(x):
|
|
# assign new est values
|
|
x[i] = x_vec_est_new[0][0]
|
|
y[i] = x_vec_est_new[1][0]
|
|
heading[i] = x_vec_est_new[2][0]
|
|
velocity[i] = x_vec_est_new[3][0]
|
|
|
|
if i < len(x) - 1: # no action on last data
|
|
# filtering
|
|
x_vec_est = np.array([[x[i]],
|
|
[y[i]],
|
|
[heading[i]],
|
|
[velocity[i]]])
|
|
z_new = np.array([[x[i + 1]],
|
|
[y[i + 1]],
|
|
[heading[i + 1]],
|
|
[velocity[i + 1]]])
|
|
x_vec_est_new, P_matrix_new = filter_veh.predict_and_update(
|
|
x_vec_est=x_vec_est,
|
|
u_vec=np.array([[0.], [0.]]),
|
|
P_matrix=P_matrix,
|
|
z_new=z_new
|
|
)
|
|
P_matrix = P_matrix_new
|
|
|
|
curvature, pl, _ = trajectory_curvature(np.stack((x, y), axis=-1))
|
|
if pl < 1.0: # vehicle is "not" moving
|
|
x = x[0].repeat(max_timesteps + 1)
|
|
y = y[0].repeat(max_timesteps + 1)
|
|
heading = heading[0].repeat(max_timesteps + 1)
|
|
global total
|
|
global curv_0_2
|
|
global curv_0_1
|
|
total += 1
|
|
if pl > 1.0:
|
|
if curvature > .2:
|
|
curv_0_2 += 1
|
|
node_frequency_multiplier = 3*int(np.floor(total/curv_0_2))
|
|
elif curvature > .1:
|
|
curv_0_1 += 1
|
|
node_frequency_multiplier = 3*int(np.floor(total/curv_0_1))
|
|
|
|
vx = derivative_of(x, scene.dt)
|
|
vy = derivative_of(y, scene.dt)
|
|
ax = derivative_of(vx, scene.dt)
|
|
ay = derivative_of(vy, scene.dt)
|
|
|
|
if node_df.iloc[0]['type'] == env.NodeType.VEHICLE:
|
|
v = np.stack((vx, vy), axis=-1)
|
|
v_norm = np.linalg.norm(np.stack((vx, vy), axis=-1), axis=-1, keepdims=True)
|
|
heading_v = np.divide(v, v_norm, out=np.zeros_like(v), where=(v_norm > 1.))
|
|
heading_x = heading_v[:, 0]
|
|
heading_y = heading_v[:, 1]
|
|
|
|
data_dict = {('position', 'x'): x,
|
|
('position', 'y'): y,
|
|
('velocity', 'x'): vx,
|
|
('velocity', 'y'): vy,
|
|
('velocity', 'norm'): np.linalg.norm(np.stack((vx, vy), axis=-1), axis=-1),
|
|
('acceleration', 'x'): ax,
|
|
('acceleration', 'y'): ay,
|
|
('acceleration', 'norm'): np.linalg.norm(np.stack((ax, ay), axis=-1), axis=-1),
|
|
('heading', 'x'): heading_x,
|
|
('heading', 'y'): heading_y,
|
|
('heading', '°'): heading,
|
|
('heading', 'd°'): derivative_of(heading, dt, radian=True)}
|
|
node_data = pd.DataFrame(data_dict, columns=data_columns_vehicle)
|
|
else:
|
|
data_dict = {('position', 'x'): x,
|
|
('position', 'y'): y,
|
|
('velocity', 'x'): vx,
|
|
('velocity', 'y'): vy,
|
|
('acceleration', 'x'): ax,
|
|
('acceleration', 'y'): ay}
|
|
node_data = pd.DataFrame(data_dict, columns=data_columns_pedestrian)
|
|
|
|
node = Node(node_type=node_df.iloc[0]['type'], node_id=node_id, data=node_data, frequency_multiplier=node_frequency_multiplier)
|
|
node.first_timestep = node_df['frame_id'].iloc[0]
|
|
if node_df.iloc[0]['robot'] == True:
|
|
node.is_robot = True
|
|
scene.robot = node
|
|
|
|
scene.nodes.append(node)
|
|
|
|
return scene
|
|
|
|
|
|
def process_data(data_path, version, output_path, val_split):
|
|
nusc = NuScenes(version=version, dataroot=data_path, verbose=True)
|
|
splits = create_splits_scenes()
|
|
train_scenes, val_scenes = train_test_split(splits['train' if 'mini' not in version else 'mini_train'], test_size=val_split)
|
|
train_scene_names = splits['train' if 'mini' not in version else 'mini_train']
|
|
val_scene_names = []#val_scenes
|
|
test_scene_names = splits['val' if 'mini' not in version else 'mini_val']
|
|
|
|
ns_scene_names = dict()
|
|
ns_scene_names['train'] = train_scene_names
|
|
ns_scene_names['val'] = val_scene_names
|
|
ns_scene_names['test'] = test_scene_names
|
|
|
|
for data_class in ['train', 'val', 'test']:
|
|
env = Environment(node_type_list=['VEHICLE', 'PEDESTRIAN'], standardization=standardization)
|
|
attention_radius = dict()
|
|
attention_radius[(env.NodeType.PEDESTRIAN, env.NodeType.PEDESTRIAN)] = 10.0
|
|
attention_radius[(env.NodeType.PEDESTRIAN, env.NodeType.VEHICLE)] = 20.0
|
|
attention_radius[(env.NodeType.VEHICLE, env.NodeType.PEDESTRIAN)] = 20.0
|
|
attention_radius[(env.NodeType.VEHICLE, env.NodeType.VEHICLE)] = 30.0
|
|
|
|
env.attention_radius = attention_radius
|
|
env.robot_type = env.NodeType.VEHICLE
|
|
scenes = []
|
|
|
|
for ns_scene_name in tqdm(ns_scene_names[data_class]):
|
|
ns_scene = nusc.get('scene', nusc.field2token('scene', 'name', ns_scene_name)[0])
|
|
scene_id = int(ns_scene['name'].replace('scene-', ''))
|
|
if scene_id in scene_blacklist: # Some scenes have bad localization
|
|
continue
|
|
|
|
scene = process_scene(ns_scene, env, nusc, data_path)
|
|
if scene is not None:
|
|
if data_class == 'train':
|
|
scene.augmented = list()
|
|
angles = np.arange(0, 360, 15)
|
|
for angle in angles:
|
|
scene.augmented.append(augment_scene(scene, angle))
|
|
scenes.append(scene)
|
|
|
|
print(f'Processed {len(scenes):.2f} scenes')
|
|
|
|
env.scenes = scenes
|
|
|
|
if len(scenes) > 0:
|
|
mini_string = ''
|
|
if 'mini' in version:
|
|
mini_string = '_mini'
|
|
data_dict_path = os.path.join(output_path, 'nuScenes_' + data_class + mini_string + '_full.pkl')
|
|
with open(data_dict_path, 'wb') as f:
|
|
dill.dump(env, f, protocol=dill.HIGHEST_PROTOCOL)
|
|
print('Saved Environment!')
|
|
|
|
global total
|
|
global curv_0_2
|
|
global curv_0_1
|
|
print(f"Total Nodes: {total}")
|
|
print(f"Curvature > 0.1 Nodes: {curv_0_1}")
|
|
print(f"Curvature > 0.2 Nodes: {curv_0_2}")
|
|
total = 0
|
|
curv_0_1 = 0
|
|
curv_0_2 = 0
|
|
|
|
|
|
if __name__ == '__main__':
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument('--data', type=str, required=True)
|
|
parser.add_argument('--version', type=str, required=True)
|
|
parser.add_argument('--output_path', type=str, required=True)
|
|
parser.add_argument('--val_split', type=int, default=0.15)
|
|
args = parser.parse_args()
|
|
process_data(args.data, args.version, args.output_path, args.val_split) |