de99 commited on
Commit
53f2c76
·
verified ·
1 Parent(s): 90e657e

Upload datasets_v1.py

Browse files
Files changed (1) hide show
  1. datasets_v1.py +364 -0
datasets_v1.py ADDED
@@ -0,0 +1,364 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Meta Platforms, Inc. and affiliates.
2
+ # All rights reserved.
3
+
4
+ # This source code is licensed under the license found in the
5
+ # LICENSE file in the root directory of this source tree.
6
+ # --------------------------------------------------------
7
+ # References:
8
+ # NoMaD, GNM, ViNT: https://github.com/robodhruv/visualnav-transformer
9
+ # --------------------------------------------------------
10
+ import cv2
11
+ import numpy as np
12
+ import torch
13
+ import os
14
+ from PIL import Image
15
+ from typing import Tuple
16
+ import yaml
17
+ import pickle
18
+ import tqdm
19
+ from torch.utils.data import Dataset
20
+ from misc import angle_difference, get_data_path, get_delta_np, normalize_data, to_local_coords
21
+ from project_functions import reproject_depth_to_other_pose_2seq, project_to_2d_image_2seq, resize_image_half
22
+
23
+ class BaseDataset(Dataset):
24
+ def __init__(
25
+ self,
26
+ data_folder: str,
27
+ data_split_folder: str,
28
+ dataset_name: str,
29
+ image_size: Tuple[int, int],
30
+ min_dist_cat: int,
31
+ max_dist_cat: int,
32
+ len_traj_pred: int,
33
+ traj_stride: int,
34
+ context_size: int,
35
+ transform: object,
36
+ traj_names: str,
37
+ normalize: bool = True,
38
+ predefined_index: list = None,
39
+ goals_per_obs: int = 1,
40
+ ):
41
+ self.data_folder = data_folder
42
+ self.data_split_folder = data_split_folder
43
+ self.dataset_name = dataset_name
44
+ self.goals_per_obs = goals_per_obs
45
+
46
+
47
+ traj_names_file = os.path.join(data_split_folder, traj_names)
48
+ with open(traj_names_file, "r") as f:
49
+ file_lines = f.read()
50
+ self.traj_names = file_lines.split("\n")
51
+ if "" in self.traj_names:
52
+ self.traj_names.remove("")
53
+
54
+ self.image_size = image_size
55
+ self.distance_categories = list(range(min_dist_cat, max_dist_cat + 1))
56
+ self.min_dist_cat = self.distance_categories[0]
57
+ self.max_dist_cat = self.distance_categories[-1]
58
+ self.len_traj_pred = len_traj_pred
59
+ self.traj_stride = traj_stride
60
+
61
+ self.context_size = context_size
62
+ self.normalize = normalize
63
+
64
+ # load data/data_config.yaml
65
+ with open("config/data_config.yaml", "r") as f:
66
+ all_data_config = yaml.safe_load(f)
67
+
68
+ dataset_names = list(all_data_config.keys())
69
+ dataset_names.sort()
70
+ # use this index to retrieve the dataset name from the data_config.yaml
71
+ self.data_config = all_data_config[self.dataset_name]
72
+ self.transform = transform
73
+ self._load_index(predefined_index)
74
+ self.ACTION_STATS = {}
75
+ for key in all_data_config['action_stats']:
76
+ self.ACTION_STATS[key] = np.expand_dims(all_data_config['action_stats'][key], axis=0)
77
+
78
+ def _load_index(self, predefined_index) -> None:
79
+ """
80
+ Generates a list of tuples of (obs_traj_name, goal_traj_name, obs_time, goal_time) for each observation in the dataset
81
+ """
82
+ if predefined_index:
83
+ print(f"****** Using a predefined evaluation index... {predefined_index}******")
84
+ with open(predefined_index, "rb") as f:
85
+ self.index_to_data = pickle.load(f)
86
+ return
87
+ else:
88
+ print("****** Evaluating from NON PREDEFINED index... ******")
89
+ index_to_data_path = os.path.join(
90
+ self.data_split_folder,
91
+ f"dataset_dist_{self.min_dist_cat}_to_{self.max_dist_cat}_n{self.context_size}_len_traj_pred_{self.len_traj_pred}.pkl",
92
+ )
93
+
94
+ self.index_to_data, self.goals_index = self._build_index()
95
+ with open(index_to_data_path, "wb") as f:
96
+ pickle.dump((self.index_to_data, self.goals_index), f)
97
+
98
+ def _build_index(self, use_tqdm: bool = False):
99
+ """
100
+ Build an index consisting of tuples (trajectory name, time, max goal distance)
101
+ """
102
+ samples_index = []
103
+ goals_index = []
104
+
105
+ for traj_name in tqdm.tqdm(self.traj_names, disable=not use_tqdm, dynamic_ncols=True):
106
+ traj_data = self._get_trajectory(traj_name)
107
+ traj_len = len(traj_data["position"])
108
+ for goal_time in range(0, traj_len):
109
+ goals_index.append((traj_name, goal_time))
110
+
111
+ begin_time = self.context_size - 1
112
+ end_time = traj_len - self.len_traj_pred
113
+ for curr_time in range(begin_time, end_time, self.traj_stride):
114
+ max_goal_distance = min(self.max_dist_cat, traj_len - curr_time - 1)
115
+ min_goal_distance = max(self.min_dist_cat, -curr_time)
116
+ samples_index.append((traj_name, curr_time, min_goal_distance, max_goal_distance))
117
+
118
+ return samples_index, goals_index
119
+
120
+ def _get_trajectory(self, trajectory_name):
121
+ with open(os.path.join(self.data_folder, trajectory_name, "traj_data.pkl"), "rb") as f:
122
+ traj_data = pickle.load(f)
123
+ for k,v in traj_data.items():
124
+ traj_data[k] = v.astype('float')
125
+ return traj_data
126
+
127
+ def __len__(self) -> int:
128
+ return len(self.index_to_data)
129
+
130
+ def _compute_projected_image(self, traj_data, curr_time, goal_time, rgb_img):
131
+ start_index = curr_time
132
+ end_index = curr_time + self.len_traj_pred + 1
133
+ pose_src = traj_data["pose"][start_index:end_index][-1]
134
+ pose_dst = traj_data["pose"][goal_time]
135
+ depth_map = traj_data["depth"][start_index:end_index][-1]
136
+ K = traj_data["K"]
137
+
138
+ projected_images = self.generate_augmented_image(K=K, depth_map=depth_map, rgb_img=rgb_img, pose_src=pose_src, pose_dst=pose_dst)
139
+ return projected_images
140
+
141
+ def generate_augmented_image(self, K, depth_map, rgb_img, pose_src, pose_dst) -> np.ndarray:
142
+ """
143
+ 基于深度图 + pose 生成从另一个相机视角观察到的图像。
144
+ """
145
+ image_size = depth_map.shape # (H, W)
146
+ if rgb_img.shape[:2] != image_size:
147
+ rgb_img = resize_image_half(rgb_img)
148
+ points_3d, colors = reproject_depth_to_other_pose_2seq(K, depth_map, rgb_img, pose_src, pose_dst)
149
+ images = project_to_2d_image_2seq(K, points_3d, colors, image_size) # (H, W, 3, goal_time)
150
+ return images
151
+
152
+ def _compute_actions(self, traj_data, curr_time, goal_time, rgb_img):
153
+ start_index = curr_time
154
+ end_index = curr_time + self.len_traj_pred + 1
155
+ yaw = traj_data["yaw"][start_index:end_index]
156
+ positions = traj_data["position"][start_index:end_index]
157
+ goal_pos = traj_data["position"][goal_time]
158
+ goal_yaw = traj_data["yaw"][goal_time]
159
+
160
+ if len(yaw.shape) == 2:
161
+ yaw = yaw.squeeze(1)
162
+
163
+ if yaw.shape != (self.len_traj_pred + 1,):
164
+ raise ValueError("is used?")
165
+ # const_len = self.len_traj_pred + 1 - yaw.shape[0]
166
+ # yaw = np.concatenate([yaw, np.repeat(yaw[-1], const_len)])
167
+ # positions = np.concatenate([positions, np.repeat(positions[-1][None], const_len, axis=0)], axis=0)
168
+
169
+ waypoints_pos = to_local_coords(positions, positions[0], yaw[0])
170
+ waypoints_yaw = angle_difference(yaw[0], yaw)
171
+ actions = np.concatenate([waypoints_pos, waypoints_yaw.reshape(-1, 1)], axis=-1)
172
+ actions = actions[1:]
173
+
174
+ goal_pos = to_local_coords(goal_pos, positions[0], yaw[0])
175
+ goal_yaw = angle_difference(yaw[0], goal_yaw)
176
+
177
+ if self.normalize:
178
+ actions[:, :2] /= self.data_config["metric_waypoint_spacing"]
179
+ goal_pos[:, :2] /= self.data_config["metric_waypoint_spacing"]
180
+
181
+ goal_pos = np.concatenate([goal_pos, goal_yaw.reshape(-1, 1)], axis=-1)
182
+
183
+ projected_images = self._compute_projected_image(traj_data, curr_time, goal_time, rgb_img)
184
+ return actions, goal_pos, projected_images
185
+
186
+ class TrainingDataset(BaseDataset):
187
+ def __init__(
188
+ self,
189
+ data_folder: str,
190
+ data_split_folder: str,
191
+ dataset_name: str,
192
+ image_size: Tuple[int, int],
193
+ min_dist_cat: int,
194
+ max_dist_cat: int,
195
+ len_traj_pred: int,
196
+ traj_stride: int,
197
+ context_size: int,
198
+ transform: object,
199
+ traj_names: str = 'traj_names.txt',
200
+ normalize: bool = True,
201
+ predefined_index: list = None,
202
+ goals_per_obs: int = 1,
203
+ ):
204
+ super().__init__(data_folder, data_split_folder, dataset_name, image_size, min_dist_cat, max_dist_cat,
205
+ len_traj_pred, traj_stride, context_size, transform, traj_names, normalize, predefined_index, goals_per_obs)
206
+
207
+
208
+ def __getitem__(self, i: int) -> Tuple[torch.Tensor]:
209
+ try:
210
+ f_curr, curr_time, min_goal_dist, max_goal_dist = self.index_to_data[i]
211
+ goal_offset = np.random.randint(min_goal_dist, max_goal_dist + 1, size=(self.goals_per_obs))
212
+ goal_time = (curr_time + goal_offset).astype('int')
213
+ rel_time = (goal_offset).astype('float')/(128.) # TODO: refactor, currently a fixed const
214
+
215
+ context_times = list(range(curr_time - self.context_size + 1, curr_time + 1))
216
+ context = [(f_curr, t) for t in context_times] + [(f_curr, t) for t in goal_time]
217
+
218
+ obs_image = torch.stack([self.transform(Image.open(get_data_path(self.data_folder, f, t))) for f, t in context])
219
+
220
+ # Load other trajectory data
221
+ curr_traj_data = self._get_trajectory(f_curr)
222
+
223
+ # aug
224
+ f_img, t_img = context[-1] # curr_time img
225
+ rgb_img = cv2.imread(get_data_path(self.data_folder, f_img, t_img))
226
+ rgb_img = cv2.cvtColor(rgb_img, cv2.COLOR_BGR2RGB)
227
+
228
+ # Compute actions
229
+ _, goal_pos, projected_images = self._compute_actions(curr_traj_data, curr_time, goal_time, rgb_img)
230
+ goal_pos[:, :2] = normalize_data(goal_pos[:, :2], self.ACTION_STATS)
231
+
232
+ projected_tensor_list = [self.transform(Image.fromarray(img)) for img in projected_images]
233
+ projected_tensor = torch.stack(projected_tensor_list, dim=0)
234
+
235
+ return (
236
+ torch.as_tensor(obs_image, dtype=torch.float32),
237
+ torch.as_tensor(goal_pos, dtype=torch.float32),
238
+ torch.as_tensor(rel_time, dtype=torch.float32),
239
+ torch.as_tensor(projected_tensor, dtype=torch.float32),
240
+ )
241
+ except Exception as e:
242
+ print(f"Exception in {self.dataset_name}", e)
243
+ raise Exception(e)
244
+
245
+ class EvalDataset(BaseDataset):
246
+ def __init__(
247
+ self,
248
+ data_folder: str,
249
+ data_split_folder: str,
250
+ dataset_name: str,
251
+ image_size: Tuple[int, int],
252
+ min_dist_cat: int,
253
+ max_dist_cat: int,
254
+ len_traj_pred: int,
255
+ traj_stride: int,
256
+ context_size: int,
257
+ transform: object,
258
+ traj_names: str,
259
+ normalize: bool = True,
260
+ predefined_index: list = None,
261
+ goals_per_obs: int = 1,
262
+ ):
263
+ super().__init__(data_folder, data_split_folder, dataset_name, image_size, min_dist_cat, max_dist_cat,
264
+ len_traj_pred, traj_stride, context_size, transform, traj_names, normalize, predefined_index, goals_per_obs)
265
+
266
+ def __getitem__(self, i: int) -> Tuple[torch.Tensor]:
267
+ try:
268
+ f_curr, curr_time, _, _ = self.index_to_data[i]
269
+ context_times = list(range(curr_time - self.context_size + 1, curr_time + 1))
270
+ pred_times = list(range(curr_time + 1, curr_time + self.len_traj_pred + 1))
271
+
272
+ context = [(f_curr, t) for t in context_times]
273
+ pred = [(f_curr, t) for t in pred_times]
274
+
275
+ obs_image = torch.stack([self.transform(Image.open(get_data_path(self.data_folder, f, t))) for f, t in context])
276
+ pred_image = torch.stack([self.transform(Image.open(get_data_path(self.data_folder, f, t))) for f, t in pred])
277
+
278
+ curr_traj_data = self._get_trajectory(f_curr)
279
+
280
+ # Compute last rgb image
281
+ f_img, t_img = context[-1] # curr_time img
282
+ rgb_img = cv2.imread(get_data_path(self.data_folder, f_img, t_img))
283
+ rgb_img = cv2.cvtColor(rgb_img, cv2.COLOR_BGR2RGB)
284
+ # Compute actions
285
+ actions, _, projected_images = self._compute_actions(curr_traj_data, curr_time, np.array([curr_time+1]), rgb_img) # last argument is dummy goal
286
+ actions[:, :2] = normalize_data(actions[:, :2], self.ACTION_STATS)
287
+ delta = get_delta_np(actions)
288
+ # Compute projected tensor
289
+ projected_tensor_list = [self.transform(Image.fromarray(img)) for img in projected_images]
290
+ projected_tensor = torch.stack(projected_tensor_list, dim=0)
291
+ return (
292
+ torch.tensor([i], dtype=torch.float32), # for logging purposes
293
+ torch.as_tensor(obs_image, dtype=torch.float32),
294
+ torch.as_tensor(pred_image, dtype=torch.float32),
295
+ torch.as_tensor(delta, dtype=torch.float32),
296
+ torch.as_tensor(projected_tensor, dtype=torch.float32),
297
+ )
298
+ except Exception as e:
299
+ print(f"Exception in {self.dataset_name}", e)
300
+ raise Exception(e)
301
+
302
+ class TrajectoryEvalDataset(BaseDataset):
303
+ def __init__(
304
+ self,
305
+ data_folder: str,
306
+ data_split_folder: str,
307
+ dataset_name: str,
308
+ image_size: Tuple[int, int],
309
+ min_dist_cat: int,
310
+ max_dist_cat: int,
311
+ len_traj_pred: int,
312
+ traj_stride: int,
313
+ context_size: int,
314
+ transform: object,
315
+ traj_names: str,
316
+ normalize: bool = True,
317
+ predefined_index: list = None,
318
+ goals_per_obs: int = 1,
319
+ ):
320
+ super().__init__(data_folder, data_split_folder, dataset_name, image_size, min_dist_cat, max_dist_cat,
321
+ len_traj_pred, traj_stride, context_size, transform, traj_names, normalize, predefined_index, goals_per_obs)
322
+
323
+
324
+ def _sample_goal(self, trajectory_name, curr_time, min_goal_dist, max_goal_dist):
325
+ """
326
+ Sample a goal from the future in the same trajectory.
327
+ Returns: (trajectory_name, goal_time, goal_is_negative)
328
+ """
329
+ goal_offset = np.random.randint(min_goal_dist, max_goal_dist + 1)
330
+ goal_time = curr_time + int(goal_offset)
331
+ return trajectory_name, goal_time, False
332
+
333
+ def __getitem__(self, i: int) -> Tuple[torch.Tensor]:
334
+ try:
335
+ f_curr, curr_time, min_goal_dist, max_goal_dist = self.index_to_data[i]
336
+ f_goal, goal_time, _ = self._sample_goal(f_curr, curr_time, min_goal_dist, max_goal_dist)
337
+
338
+ context_times = list(range(curr_time - self.context_size + 1, curr_time + 1))
339
+ context = [(f_curr, t) for t in context_times]
340
+
341
+ obs_image = torch.stack([self.transform(Image.open(get_data_path(self.data_folder, f, t))) for f, t in context])
342
+ goal_image = self.transform(Image.open(get_data_path(self.data_folder, f_goal, goal_time))).unsqueeze(0)
343
+ curr_traj_data = self._get_trajectory(f_curr)
344
+ # Compute actions, goal_pos, projected images
345
+ f_img, t_img = context[-1] # curr_time img
346
+ rgb_img = cv2.imread(get_data_path(self.data_folder, f_img, t_img))
347
+ rgb_img = cv2.cvtColor(rgb_img, cv2.COLOR_BGR2RGB)
348
+
349
+ actions, goal_pos, projected_images = self._compute_actions(curr_traj_data, curr_time, np.array([goal_time]), rgb_img)
350
+
351
+ projected_tensor_list = [self.transform(Image.fromarray(img)) for img in projected_images]
352
+ projected_tensor = torch.stack(projected_tensor_list, dim=0)
353
+
354
+ return (
355
+ torch.tensor([i], dtype=torch.float32), # for logging purposes
356
+ torch.as_tensor(obs_image, dtype=torch.float32),
357
+ torch.as_tensor(goal_image, dtype=torch.float32),
358
+ torch.as_tensor(actions, dtype=torch.float32),
359
+ torch.as_tensor(goal_pos, dtype=torch.float32),
360
+ torch.as_tensor(projected_tensor, dtype=torch.float32),
361
+ )
362
+ except Exception as e:
363
+ print(f"Exception in {self.dataset_name}", e)
364
+ raise Exception(e)