Spaces:
Runtime error
Runtime error
| """Pull full IXI2D training pool (~25k healthy slices) into dataset_v8. | |
| Phase 1 of the v9c data-expansion plan. Adds IXI2D's full training | |
| split as no_tumor slices in dataset_v8/train/{images,masks}/. | |
| EXCLUDES the 100 slices already used as held-out OOD test set | |
| (samples/ood/healthy_ixi2d/) by filename, so there is zero leakage | |
| between training pool and OOD evaluation. | |
| Source: iamkzntsv/IXI2D (HuggingFace, 28,275 slices from 600 IXI healthy | |
| subjects, skull-stripped + fsaverage-registered, MIT). | |
| """ | |
| from __future__ import annotations | |
| import os | |
| import sys | |
| import time | |
| import zipfile | |
| from pathlib import Path | |
| import cv2 | |
| import numpy as np | |
| ROOT = Path(__file__).resolve().parent.parent | |
| DATASET = ROOT / 'dataset_v8' | |
| OOD_HELDOUT_DIR = ROOT / 'samples' / 'ood' / 'healthy_ixi2d' | |
| def _held_out_basenames() -> set[str]: | |
| """Return the IXI2D base filenames already in the OOD test cohort — | |
| we strip the 'ixi2d_XXXX_' prefix and use the original IXI2D basename.""" | |
| out = set() | |
| if not OOD_HELDOUT_DIR.exists(): | |
| return out | |
| for p in OOD_HELDOUT_DIR.glob('*.jpg'): | |
| # Names look like 'ixi2d_0000_18927.jpg'; the IXI2D source name | |
| # is the trailing portion after the second underscore. | |
| parts = p.stem.split('_') | |
| if len(parts) >= 3: | |
| out.add(parts[-1]) # e.g. '18927' | |
| return out | |
| def main(): | |
| cached_zip = ROOT / 'samples' / 'ood' / '_zip_tmp_ixi' / 'data' / 'train.zip' | |
| cached_zip.parent.mkdir(parents=True, exist_ok=True) | |
| if not cached_zip.exists() or cached_zip.stat().st_size < 10_000_000: | |
| print('[1/3] downloading iamkzntsv/IXI2D train.zip ...') | |
| from huggingface_hub import hf_hub_download | |
| downloaded = hf_hub_download( | |
| repo_id='iamkzntsv/IXI2D', filename='data/train.zip', | |
| repo_type='dataset', local_dir=str(cached_zip.parent.parent), | |
| ) | |
| cached_zip = Path(downloaded) | |
| print(f' zip ready: {cached_zip} ({cached_zip.stat().st_size/1e6:.1f} MB)') | |
| held_out = _held_out_basenames() | |
| print(f'[2/3] excluding {len(held_out)} slices that are already in ' | |
| f'samples/ood/healthy_ixi2d/ (OOD test set)') | |
| # Ensure target directories | |
| for split in ('train', 'val'): | |
| (DATASET / split / 'images').mkdir(parents=True, exist_ok=True) | |
| (DATASET / split / 'masks').mkdir(parents=True, exist_ok=True) | |
| # Extract all .jpeg files (excluding __MACOSX). Assign to train by | |
| # default; route every 10th to val to keep IXI proportionally in val. | |
| added_train = added_val = skipped = 0 | |
| t0 = time.perf_counter() | |
| with zipfile.ZipFile(cached_zip) as zf: | |
| valid = sorted(n for n in zf.namelist() | |
| if n.lower().endswith(('.png', '.jpg', '.jpeg')) | |
| and not n.startswith('__MACOSX/')) | |
| print(f' {len(valid)} IXI2D images in zip') | |
| for i, nm in enumerate(valid): | |
| base = os.path.basename(nm) | |
| stem = base.rsplit('.', 1)[0] | |
| if stem in held_out: | |
| skipped += 1 | |
| continue | |
| split = 'val' if i % 10 == 0 else 'train' | |
| out_name = f'ixi2d_train_{stem}.png' | |
| img_path = DATASET / split / 'images' / out_name | |
| mask_path = DATASET / split / 'masks' / out_name | |
| if img_path.exists() and mask_path.exists(): | |
| # idempotent | |
| continue | |
| data = zf.read(nm) | |
| # Decode -> re-encode as PNG; create all-zero mask of same size | |
| arr = cv2.imdecode(np.frombuffer(data, np.uint8), cv2.IMREAD_COLOR) | |
| if arr is None: | |
| continue | |
| cv2.imwrite(str(img_path), arr) | |
| cv2.imwrite(str(mask_path), | |
| np.zeros(arr.shape[:2], dtype=np.uint8)) | |
| if split == 'train': | |
| added_train += 1 | |
| else: | |
| added_val += 1 | |
| elapsed = time.perf_counter() - t0 | |
| print(f'[3/3] added {added_train} to train / {added_val} to val ' | |
| f'(skipped {skipped} OOD held-outs) in {elapsed:.0f}s') | |
| # Final tally | |
| print('\nNew dataset_v8 healthy-source coverage:') | |
| for split in ('train', 'val'): | |
| img_dir = DATASET / split / 'images' | |
| ixi = sum(1 for p in img_dir.glob('ixi2d_*.png')) | |
| oneuro = sum(1 for p in img_dir.glob('oneuro_*.png')) | |
| kaggle = sum(1 for p in img_dir.glob('neg_kaggle*.png')) | |
| total = sum(1 for _ in img_dir.glob('*.png')) | |
| print(f' {split:5s} total={total:5d} ' | |
| f'kaggle_neg={kaggle:5d} ' | |
| f'openneuro={oneuro:5d} ixi2d={ixi:5d}') | |
| if __name__ == '__main__': | |
| main() | |