Spaces:
Configuration error
Configuration error
feat(RCLane): add CARLA dataset
Browse files- 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.")
|