67 lines
No EOL
2.7 KiB
Python
67 lines
No EOL
2.7 KiB
Python
"""Build NTUH2022G4 labeled manifest: brain native T1c + tumor seg pairs from register_inv.
|
||
|
||
Rules:
|
||
- series name must contain T1 and +C
|
||
- exclude MRA/FLAIR/TOF/T2/SWI/DWI, _ROI1/_ROI re-exports, and spinal levels (e.g. T4-T8, T11-L3)
|
||
- dedupe per (subject, case, acquisition timestamp): prefer _MPR_Tra, else lowest series number
|
||
"""
|
||
import os
|
||
import sys
|
||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||
import re
|
||
from collections import defaultdict
|
||
from src.common import ROOT, DATA, save_jsonl, path
|
||
|
||
T1C_RE = re.compile(r"T1.*\+C|\+C.*T1")
|
||
EXCL_RE = re.compile(r"MRA|FLAIR|TOF|T2|SWI|DWI|_ROI|ROI1", re.I)
|
||
SPINE_RE = re.compile(r"[TLC]\s?\d+\s?[-–]\s?[TLC]\s?\d+|[TLC]\d{2}", re.I)
|
||
|
||
|
||
def main(limit=None):
|
||
out = os.path.join(DATA, "manifests", "ntuh.jsonl")
|
||
reg_inv = path("ntuh_register_inv")
|
||
cands = {} # (subj, case, ts) -> list of (pref, ser, fname)
|
||
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) or SPINE_RE.search(f):
|
||
continue
|
||
if f[: -len(".nii.gz")] + ".seg.nii.gz" not in fl:
|
||
continue
|
||
mt = re.search(r"_(\d{14})_(\d+)\.nii\.gz$", f)
|
||
ts = mt.group(1) if mt else f
|
||
ser = int(mt.group(2)) if mt else 9999
|
||
pref = 0 if "MPR_Tra" in f else 1
|
||
cands.setdefault((s, c, ts), []).append((pref, ser, f))
|
||
if limit and n_subj >= limit:
|
||
break
|
||
rows = []
|
||
for (s, c, ts), lst in sorted(cands.items()):
|
||
lst.sort(key=lambda x: (x[0], x[1]))
|
||
f = lst[0][2]
|
||
rows.append({"key": f"ntuh_{s}_{c}_{ts}", "subject": s, "case": c,
|
||
"date": c2date(c), "img": os.path.join(reg_inv, s, c, f),
|
||
"label": os.path.join(reg_inv, s, c, f[: -len(".nii.gz")] + ".seg.nii.gz"),
|
||
"source": "ntuh", "dedup": len(lst)})
|
||
save_jsonl(rows, out)
|
||
print(f"subjects={n_subj} rows={len(rows)} (deduped {sum(r['dedup'] for r in 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() |