shin0412 commited on
Commit
ecf4d58
·
1 Parent(s): 5d3daa9

feat(RCLane): add CARLA dataset

Browse files
Files changed (1) hide show
  1. dataset_carla.py +83 -0
dataset_carla.py ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ CARLA dataset for RCLane (BanVienCorp/dataset_laneatt_fullmap, LaneATT format).
3
+
4
+ Annotation is JSON-lines:
5
+ - first line: {"Ys": [72 y-anchors, 0..1065 step 15]}
6
+ - each record: {"lines": [[x per anchor, -2 = missing], ...],
7
+ "types": [...], "image": "TownXX/.../frame.jpg"}
8
+ Images are 1920x1080.
9
+
10
+ Lanes are read in the original 1920x1080 space; the base class resizes to 800x320
11
+ and runs `encode` to build the GT. RCLane generates its own GT, so no seg labels needed.
12
+ """
13
+
14
+ import os
15
+ import json
16
+
17
+ import cv2
18
+
19
+ from dataset import LaneEncodeDataset
20
+
21
+
22
+ class CarlaLaneDataset(LaneEncodeDataset):
23
+ _MISSING = -2
24
+
25
+ def __init__(self, label_json, data_root, img_size=(320, 800),
26
+ cache_dir=None, max_samples=None):
27
+ super().__init__(img_size, cache_dir)
28
+ self.data_root = data_root
29
+ with open(label_json) as f:
30
+ lines = f.read().splitlines()
31
+ self.Ys = json.loads(lines[0])["Ys"]
32
+ self.records = [r for r in (json.loads(ln) for ln in lines[1:])
33
+ if "image" in r and "lines" in r]
34
+ if max_samples is not None:
35
+ self.records = self.records[:max_samples]
36
+
37
+ def __len__(self):
38
+ return len(self.records)
39
+
40
+ def _load(self, idx):
41
+ rec = self.records[idx]
42
+ img_path = os.path.join(self.data_root, rec["image"])
43
+ img = cv2.imread(img_path)
44
+ if img is None:
45
+ raise FileNotFoundError(img_path)
46
+ oh, ow = img.shape[:2]
47
+ lanes = []
48
+ for lane in rec["lines"]:
49
+ pts = [(x, self.Ys[i]) for i, x in enumerate(lane) if x != self._MISSING]
50
+ if len(pts) >= 2:
51
+ lanes.append(pts)
52
+ return img, lanes, ow, oh, rec["image"]
53
+
54
+
55
+ # --------------------------------------------------------------------------- #
56
+ # smoke test -- builds a tiny FAKE CARLA sample (no real data needed) and
57
+ # verifies the loader parses annotations and produces GT tensors.
58
+ # --------------------------------------------------------------------------- #
59
+ if __name__ == "__main__":
60
+ import tempfile
61
+ import numpy as np
62
+
63
+ tmp = tempfile.mkdtemp(prefix="fake_carla_")
64
+ img_rel = "Town01/clear_noon/000000.jpg"
65
+ os.makedirs(os.path.join(tmp, os.path.dirname(img_rel)), exist_ok=True)
66
+ cv2.imwrite(os.path.join(tmp, img_rel), np.zeros((1080, 1920, 3), np.uint8))
67
+
68
+ ys = list(range(0, 1080, 15)) # 72 anchors, like the real data
69
+ lane1 = [700 + i * 6 for i in range(len(ys))] # x per anchor
70
+ lane2 = [1200 - i * 6 for i in range(len(ys))]
71
+ label = os.path.join(tmp, "label_train.json")
72
+ with open(label, "w") as f:
73
+ f.write(json.dumps({"Ys": ys}) + "\n")
74
+ f.write(json.dumps({"lines": [lane1, lane2], "types": [0, 0], "image": img_rel}) + "\n")
75
+
76
+ ds = CarlaLaneDataset(label_json=label, data_root=tmp, cache_dir=None)
77
+ print("dataset size:", len(ds))
78
+ x, tgt = ds[0]
79
+ print("image:", tuple(x.shape), "| seg fg pixels:", int((tgt["seg_map"] > 0).sum()))
80
+ for k, v in tgt.items():
81
+ assert tuple(v.shape)[-2:] == (320, 800), f"bad shape for {k}"
82
+ assert int((tgt["seg_map"] > 0).sum()) > 0, "no foreground -- parse/encode failed"
83
+ print("OK -- CARLA loader parses JSONL and produces GT.")