Spaces:
Sleeping
Sleeping
Dheepak Karan
Align the demo with what actually ships, and pull model code from the main repo
c8f05dd Download data/scripts/dataset.py from dheepakkaran/multi-camera-bev: direct link, hf CLI and curl.
- Browser
- Download file 10 kB
-
https://huggingface.co/spaces/dheepakkaran/multi-camera-bev/resolve/main/data/scripts/dataset.py
- Command line
-
hf download hf://spaces/dheepakkaran/multi-camera-bev/data/scripts/dataset.py
-
curl -L -o dataset.py https://huggingface.co/spaces/dheepakkaran/multi-camera-bev/resolve/main/data/scripts/dataset.py
10 kB
| # ============================================================ | |
| # dataset.py | |
| # ============================================================ | |
| # | |
| # ETHUKU CREATE PANNINOM? | |
| # ━━━━━━━━━━━━━━━━━━━━━━ | |
| # PyTorch DataLoader-ku puriyara madhiri oru Dataset class venum. | |
| # Rendu velai pannuthu: | |
| # 1. Input taiyaar: 6 camera images + K + E (sample_loader use) | |
| # 2. TARGET taiyaar: ground-truth boxes -> BEV map format | |
| # (heatmap, offset, size, rot...) -> loss compare panna | |
| # | |
| # MUNADI FILE ODA CONNECTION: | |
| # ━━━━━━━━━━━━━━━━━━━━━━━━━━ | |
| # sample_loader.load_sample() -> input side | |
| # constants.py -> grid size, classes | |
| # training/train.py ithai DataLoader-la wrap pannum. | |
| # | |
| # INNER OPERATIONS: | |
| # ━━━━━━━━━━━━━━━━ | |
| # nuScenes boxes (LIDAR frame) -> ego frame -> BEV grid cell (200x200) | |
| # -> antha cell-la gaussian blob varaiyurom (heatmap) | |
| # -> regression values (offset, z, size, yaw, velocity) store pannurom. | |
| # | |
| # INPUT / OUTPUT: | |
| # ━━━━━━━━━━━━━━ | |
| # __getitem__(i) -> dict with images/intrinsics/extrinsics + targets | |
| # | |
| # EPADI USE AAGUM: | |
| # ━━━━━━━━━━━━━━━ | |
| # Model "intha cell-la car iruku" nu predict pannum. | |
| # Namma target "aama/illa" nu solli, difference = loss. | |
| # | |
| # ============================================================ | |
| import numpy as np | |
| import torch | |
| from torch.utils.data import Dataset | |
| from .constants import ( | |
| BEV_H, BEV_W, BEV_RESOLUTION, X_RANGE, Y_RANGE, | |
| N_CLASSES, NUSCENES_NAME_MAP, CLASS_TO_IDX, | |
| VAL_SCENES, DATA_ROOT, VERSION, | |
| ) | |
| from .sample_loader import load_sample | |
| def draw_gaussian(heatmap: np.ndarray, cx: int, cy: int, radius: int) -> None: | |
| """ | |
| Heatmap-la oru cell suthi "mellisaana veliccham" (gaussian) varaiyurathu. | |
| Yaen point mattum illa, blob? | |
| Object center exactly oru cell-la nikkathu - konjam adjacent cell-um | |
| "kittathatta correct" thaan. So neighbours-ku konjam score kudukirom. | |
| Ithu illaina training romba kastam (200x200 = 40000 cell-la 1 mattum | |
| correct-nu solli model-ai therikka mudiyathu). | |
| Args: | |
| heatmap: [H, W] array, in-place modify aagum | |
| cx, cy : center cell (column, row) | |
| radius : blob size in cells | |
| """ | |
| diameter = 2 * radius + 1 | |
| sigma = diameter / 6.0 # standard CenterNet choice | |
| # Chinna gaussian patch create pannurom | |
| y, x = np.ogrid[-radius:radius + 1, -radius:radius + 1] | |
| g = np.exp(-(x * x + y * y) / (2 * sigma * sigma)) # center=1.0, edge~0 | |
| g[g < np.finfo(g.dtype).eps * g.max()] = 0 | |
| H, W = heatmap.shape | |
| # Grid edge-la object irundha patch veliya poidum -> clip pannurom | |
| left, right = min(cx, radius), min(W - cx, radius + 1) | |
| top, bottom = min(cy, radius), min(H - cy, radius + 1) | |
| if right <= 0 or bottom <= 0 or left < 0 or top < 0: | |
| return | |
| masked_hm = heatmap[cy - top:cy + bottom, cx - left:cx + right] | |
| masked_g = g[radius - top:radius + bottom, radius - left:radius + right] | |
| # maximum: rendu object overlap aana, periya value-ai vachikirom | |
| np.maximum(masked_hm, masked_g, out=masked_hm) | |
| class NuScenesBEVDataset(Dataset): | |
| """ | |
| nuScenes mini -> BEV detection dataset. | |
| Args: | |
| data_root: "data/nuscenes-mini" | |
| split: "train" or "val" | |
| nusc: already-loaded NuScenes object (optional, reuse panna) | |
| """ | |
| def __init__(self, data_root: str = DATA_ROOT, split: str = "train", nusc=None): | |
| from nuscenes.nuscenes import NuScenes | |
| self.data_root = data_root | |
| self.split = split | |
| # NuScenes DB load pannurathu ~10 sec edukkum, so oru thadava mattum | |
| self.nusc = nusc if nusc is not None else NuScenes( | |
| version=VERSION, dataroot=data_root, verbose=False | |
| ) | |
| # Scene level-la split pannurom (sample level illa). | |
| # Yaen? Ore scene-la adjacent frames kittathatta same photo. | |
| # Train-la oru frame, val-la adjacent frame irundha = cheating. | |
| self.sample_tokens = [] | |
| for scene in self.nusc.scene: | |
| is_val = scene["name"] in VAL_SCENES | |
| if (split == "val") != is_val: | |
| continue | |
| token = scene["first_sample_token"] | |
| while token: | |
| self.sample_tokens.append(token) | |
| token = self.nusc.get("sample", token)["next"] | |
| def __len__(self) -> int: | |
| return len(self.sample_tokens) | |
| def _boxes_in_ego(self, sample_token: str) -> list: | |
| """ | |
| Antha sample-oda ellaa annotation box-aiyum EGO CAR frame-la thara. | |
| Yaen ego frame? Namma camera extrinsics-um camera->ego thaan. | |
| Rendum ore frame-la irundha thaan match aagum. | |
| Returns: | |
| list of dict: {cls, x, y, z, w, l, h, yaw, vx, vy} | |
| x = pinnadi(-)/munnadi(+) metres, y = valathu(-)/idathu(+) metres | |
| """ | |
| from pyquaternion import Quaternion | |
| sample = self.nusc.get("sample", sample_token) | |
| # LIDAR_TOP sample_data -> ego pose reference-ku use pannurom | |
| lidar_token = sample["data"]["LIDAR_TOP"] | |
| sd = self.nusc.get("sample_data", lidar_token) | |
| ego_pose = self.nusc.get("ego_pose", sd["ego_pose_token"]) | |
| ego_t = np.array(ego_pose["translation"]) | |
| ego_R_inv = Quaternion(ego_pose["rotation"]).inverse | |
| boxes = [] | |
| for ann_token in sample["anns"]: | |
| ann = self.nusc.get("sample_annotation", ann_token) | |
| name = NUSCENES_NAME_MAP.get(ann["category_name"]) | |
| if name is None: # namma 10 class-la illa -> skip | |
| continue | |
| # Global (world) coords -> ego coords | |
| center = np.array(ann["translation"]) - ego_t | |
| center = ego_R_inv.rotate(center) | |
| rot = ego_R_inv * Quaternion(ann["rotation"]) | |
| yaw = rot.yaw_pitch_roll[0] # top-down la yaw mattum thevai | |
| w, l, h = ann["size"] # nuScenes order: width,length,height | |
| vel = self.nusc.box_velocity(ann_token) # global m/s, nan varalam | |
| if np.any(np.isnan(vel)): | |
| vx, vy = 0.0, 0.0 | |
| else: | |
| v_ego = ego_R_inv.rotate(vel) | |
| vx, vy = float(v_ego[0]), float(v_ego[1]) | |
| boxes.append({ | |
| "cls": CLASS_TO_IDX[name], | |
| "x": float(center[0]), "y": float(center[1]), "z": float(center[2]), | |
| "w": float(w), "l": float(l), "h": float(h), | |
| "yaw": float(yaw), "vx": vx, "vy": vy, | |
| }) | |
| return boxes | |
| def _build_targets(self, boxes: list) -> dict: | |
| """ | |
| Box list -> BEV target maps (model output-oda same shape). | |
| Returns dict of tensors: | |
| heatmap [10,200,200] 0..1, center-la 1.0 | |
| mask [1,200,200] 1 = inga object center iruku | |
| offset [2,200,200] cell-uku ulla exact position (0..1) | |
| height [1,200,200] z metres | |
| size [3,200,200] log(w), log(l), log(h) | |
| rot [2,200,200] sin(yaw), cos(yaw) | |
| vel [2,200,200] vx, vy | |
| """ | |
| heatmap = np.zeros((N_CLASSES, BEV_H, BEV_W), dtype=np.float32) | |
| mask = np.zeros((1, BEV_H, BEV_W), dtype=np.float32) | |
| offset = np.zeros((2, BEV_H, BEV_W), dtype=np.float32) | |
| height = np.zeros((1, BEV_H, BEV_W), dtype=np.float32) | |
| size = np.zeros((3, BEV_H, BEV_W), dtype=np.float32) | |
| rot = np.zeros((2, BEV_H, BEV_W), dtype=np.float32) | |
| vel = np.zeros((2, BEV_H, BEV_W), dtype=np.float32) | |
| for b in boxes: | |
| # metres -> grid cell (float) | |
| # Example: x = 0m -> (0 - (-50))/0.5 = 100 = grid center | |
| # x = 10m (10m munnadi) -> (10+50)/0.5 = 120 | |
| fx = (b["x"] - X_RANGE[0]) / BEV_RESOLUTION | |
| fy = (b["y"] - Y_RANGE[0]) / BEV_RESOLUTION | |
| cx, cy = int(fx), int(fy) | |
| if not (0 <= cx < BEV_W and 0 <= cy < BEV_H): | |
| continue # 100x100m veliya -> skip | |
| # Object evlo periyathu-nu paathu blob size decide | |
| radius = max(2, int(min(b["w"], b["l"]) / BEV_RESOLUTION / 2)) | |
| draw_gaussian(heatmap[b["cls"]], cx, cy, radius) | |
| mask[0, cy, cx] = 1.0 | |
| # int-la potta appuram missing aana decimal part. | |
| # Ithu illaina 0.5m varai error (cell size). | |
| offset[0, cy, cx] = fx - cx | |
| offset[1, cy, cx] = fy - cy | |
| height[0, cy, cx] = b["z"] | |
| # log yaen? size 0.5m to 20m varai varum. log potta range | |
| # chinnathaagum -> network kathukka easy. | |
| size[0, cy, cx] = np.log(max(b["w"], 0.1)) | |
| size[1, cy, cx] = np.log(max(b["l"], 0.1)) | |
| size[2, cy, cx] = np.log(max(b["h"], 0.1)) | |
| # yaw-ai neradiya predict panna problem: 0 degree = 360 degree | |
| # aana number-la romba different. sin/cos-la athu solve aagum. | |
| rot[0, cy, cx] = np.sin(b["yaw"]) | |
| rot[1, cy, cx] = np.cos(b["yaw"]) | |
| vel[0, cy, cx] = b["vx"] | |
| vel[1, cy, cx] = b["vy"] | |
| return { | |
| "heatmap": torch.from_numpy(heatmap), | |
| "mask": torch.from_numpy(mask), | |
| "offset": torch.from_numpy(offset), | |
| "height": torch.from_numpy(height), | |
| "size": torch.from_numpy(size), | |
| "rot": torch.from_numpy(rot), | |
| "vel": torch.from_numpy(vel), | |
| } | |
| def __getitem__(self, idx: int) -> dict: | |
| token = self.sample_tokens[idx] | |
| sample = load_sample(self.nusc, token, self.data_root) # inputs | |
| targets = self._build_targets(self._boxes_in_ego(token)) # labels | |
| return { | |
| "images": sample["images"], # [6,3,224,400] | |
| "intrinsics": sample["intrinsics"], # [6,3,3] | |
| "extrinsics": sample["extrinsics"], # [6,4,4] | |
| "targets": targets, | |
| } | |