"""Build NTUH2022G4 labeled manifest: native T1c + tumor seg pairs from register_inv. Fast listing-only pass (no volume decoding); content validated during preprocessing. """ import os import sys sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) import re import json from src.common import ROOT, save_jsonl T1C_RE = re.compile(r"T1.*\+C") EXCL_RE = re.compile(r"MRA|FLAIR|TOF|T2|SWI|DWI", re.I) def main(limit=None): out = os.path.join(ROOT, "data", "manifests", "ntuh.jsonl") reg_inv = "/mnt/pve/SRS/NTUH2022G4/register_inv" rows = [] n_subj = 0 for s in sorted(os.listdir(reg_inv)): fp = os.path.join(reg_inv, s) if not os.path.isdir(fp): continue n_subj += 1 for c in os.listdir(fp): cp = os.path.join(fp, c) if not os.path.isdir(cp): continue fl = set(os.listdir(cp)) for f in sorted(fl): if not f.endswith(".nii.gz") or f.endswith((".seg.nii.gz", ".label.nii.gz")): continue if not T1C_RE.search(f) or EXCL_RE.search(f): continue seg = f[: -len(".nii.gz")] + ".seg.nii.gz" if seg not in fl: continue rows.append({"key": f"ntuh_{s}_{c}", "subject": s, "case": c, "date": c2date(c), "img": os.path.join(cp, f), "label": os.path.join(cp, seg), "source": "ntuh"}) if limit and n_subj >= limit: break save_jsonl(rows, out) print(f"subjects={n_subj} rows={len(rows)}") def c2date(c): m = re.match(r"case?(\d{4})\.(\d{2})\.(\d{2})\.", c) return f"{m.group(1)}-{m.group(2)}-{m.group(3)}" if m else c if __name__ == "__main__": main()