{"cells":[{"cell_type":"markdown","metadata":{},"source":"# Pack labelled RSNA knee subset\n\nCopies study folders listed in `SELECTED_STUDY_IDS` from competition\n`train_series/` into kernel output as `train_images/`. Run via `make download-data` locally.","id":"intro"},{"cell_type":"code","metadata":{},"source":"import json\nimport shutil\nfrom pathlib import Path\n\nWORKING = Path(\"/kaggle/working\")\nIMAGES_OUT = WORKING / \"train_images\"\nIMAGES_OUT.mkdir(parents=True, exist_ok=True)\n\n\ndef find_competition_root() -> Path:\n    input_root = Path(\"/kaggle/input\")\n    if not input_root.exists():\n        raise FileNotFoundError(\"/kaggle/input does not exist\")\n\n    matches: list[Path] = []\n    for candidate in input_root.rglob(\"train.csv\"):\n        matches.append(candidate.parent)\n    for name in (\"train_series\", \"train_images\"):\n        for candidate in input_root.rglob(name):\n            if candidate.is_dir():\n                matches.append(candidate.parent)\n\n    if not matches:\n        mounted = [p.name for p in input_root.iterdir()]\n        raise FileNotFoundError(\n            \"Could not find competition train.csv or train_series under /kaggle/input. \"\n            f\"Mounted: {mounted}\"\n        )\n    return sorted(set(matches), key=lambda p: len(str(p)))[0]\n\n\nSELECTED_STUDY_IDS = [\"1.2.826.0.1.3680043.8.498.10095687747295410396510538520594649149\", \"1.2.826.0.1.3680043.8.498.10170898615867673028696505248839028269\", \"1.2.826.0.1.3680043.8.498.10306159113324811538703788080836752052\", \"1.2.826.0.1.3680043.8.498.11287937729196958426538087439102017580\", \"1.2.826.0.1.3680043.8.498.11382021393803389951964005983002209238\", \"1.2.826.0.1.3680043.8.498.11548045715264151632153040089882701935\", \"1.2.826.0.1.3680043.8.498.11557620559191469069130827959098335840\", \"1.2.826.0.1.3680043.8.498.11771393824519892797114773408583976756\", \"1.2.826.0.1.3680043.8.498.11851412923016044948101698015974810604\", \"1.2.826.0.1.3680043.8.498.11915937982684988073644209606907169581\"]\n\n\ndef load_selected_ids() -> list[str]:\n    if SELECTED_STUDY_IDS:\n        return [str(uid) for uid in SELECTED_STUDY_IDS]\n    for path in (\n        WORKING / \"selected_studies.json\",\n        Path(\"selected_studies.json\"),\n    ):\n        if path.exists():\n            payload = json.loads(path.read_text(encoding=\"utf-8\"))\n            return [str(uid) for uid in payload[\"study_instance_uids\"]]\n    raise FileNotFoundError(\"No SELECTED_STUDY_IDS or selected_studies.json found\")\n\n\nCOMP_ROOT = find_competition_root()\nselected = load_selected_ids()\nsrc_root = COMP_ROOT / \"train_series\"\nif not src_root.exists():\n    src_root = COMP_ROOT / \"train_images\"\n\nmanifest = {\n    \"competition\": \"rsna-knee-abnormality-detection\",\n    \"competition_root\": str(COMP_ROOT),\n    \"source_root\": str(src_root),\n    \"n_requested\": len(selected),\n    \"study_instance_uids\": selected,\n    \"studies\": [],\n    \"missing\": [],\n}\n\nfor uid in selected:\n    src = src_root / uid\n    dst = IMAGES_OUT / uid\n    if not src.exists():\n        manifest[\"missing\"].append(uid)\n        continue\n    if dst.exists():\n        shutil.rmtree(dst)\n    shutil.copytree(src, dst)\n    n_dcm = len(list(dst.rglob(\"*.dcm\")))\n    manifest[\"studies\"].append({\"StudyInstanceUID\": uid, \"dcm_files\": n_dcm})\n\nmanifest_path = WORKING / \"subset_manifest.json\"\nmanifest_path.write_text(json.dumps(manifest, indent=2), encoding=\"utf-8\")\nprint(json.dumps(manifest, indent=2))\n\nif manifest[\"missing\"]:\n    raise RuntimeError(f\"Missing {len(manifest['missing'])} study folders under {src_root}\")\nif not manifest[\"studies\"]:\n    raise RuntimeError(\"No study folders copied to kernel output\")","execution_count":null,"outputs":[],"id":"pack-subset"}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.10.0"}},"nbformat":4,"nbformat_minor":5}