{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":99552,"databundleVersionId":13851420,"sourceType":"competition"}],"dockerImageVersionId":31153,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# **00 - Set Up**","metadata":{}},{"cell_type":"code","source":"%pip install celluloid --q\n%pip install torchio --q","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-05T10:22:49.152172Z","iopub.execute_input":"2025-11-05T10:22:49.158455Z","iopub.status.idle":"2025-11-05T10:22:57.580977Z","shell.execute_reply.started":"2025-11-05T10:22:49.158365Z","shell.execute_reply":"2025-11-05T10:22:57.579416Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"%matplotlib notebook\n\nfrom tqdm.notebook import tqdm\nfrom pathlib import Path\nimport pandas as pd\nimport numpy as np\nimport warnings\nwarnings.filterwarnings('ignore')\n\nimport nibabel as nib\nimport pydicom\n\nimport torch\nimport torchio as tio \nfrom sklearn.model_selection import train_test_split\nfrom torch.utils.data import Dataset\nfrom torch.utils.data import DataLoader\n\nfrom celluloid import Camera\nfrom IPython.display import HTML\n\nimport matplotlib.pyplot as plt\n%matplotlib inline","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-05T10:22:57.583695Z","iopub.execute_input":"2025-11-05T10:22:57.584105Z","iopub.status.idle":"2025-11-05T10:22:57.615092Z","shell.execute_reply.started":"2025-11-05T10:22:57.584075Z","shell.execute_reply":"2025-11-05T10:22:57.614089Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"labels = pd.read_csv(\"/kaggle/input/rsna-intracranial-aneurysm-detection/train.csv\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-05T10:22:57.616383Z","iopub.execute_input":"2025-11-05T10:22:57.616757Z","iopub.status.idle":"2025-11-05T10:22:57.693925Z","shell.execute_reply.started":"2025-11-05T10:22:57.616735Z","shell.execute_reply":"2025-11-05T10:22:57.693102Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"root_path = Path(\"/kaggle/input/rsna-intracranial-aneurysm-detection/series/\")\npatient_dirs = sorted([p for p in root_path.iterdir() if p.is_dir()])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-05T10:22:57.695394Z","iopub.execute_input":"2025-11-05T10:22:57.695725Z","iopub.status.idle":"2025-11-05T10:23:00.250481Z","shell.execute_reply.started":"2025-11-05T10:22:57.695693Z","shell.execute_reply":"2025-11-05T10:23:00.249447Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"patient_dirs[0]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-05T10:23:00.253247Z","iopub.execute_input":"2025-11-05T10:23:00.253523Z","iopub.status.idle":"2025-11-05T10:23:00.26122Z","shell.execute_reply.started":"2025-11-05T10:23:00.2535Z","shell.execute_reply":"2025-11-05T10:23:00.260402Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def get_aneurysm_present_for_patient(patient_dir: Path, labels_df: pd.DataFrame):\n    \"\"\"\n    Given a patient directory Path (SeriesInstanceUID) and the labels DataFrame,\n    return the Aneurysm Present value (0 or 1).\n    \"\"\"\n    # Extract SeriesInstanceUID from folder name\n    series_uid = patient_dir.name\n    \n    # Filter DataFrame\n    result = labels_df.loc[labels_df[\"SeriesInstanceUID\"] == series_uid, \"Aneurysm Present\"]\n    \n    if not result.empty:\n        return int(result.values[0])\n    else:\n        # UID not found\n        return None\n        \n\ndef get_modality_for_patient(patient_dir: Path, labels_df: pd.DataFrame):\n    \"\"\"\n    Given a patient directory Path (SeriesInstanceUID) and the labels DataFrame,\n    return the Modality value (e.g., 'CT', 'MR', etc.).\n    \"\"\"\n    # Extract SeriesInstanceUID from folder name\n    series_uid = patient_dir.name\n    \n    # Filter DataFrame\n    result = labels_df.loc[labels_df[\"SeriesInstanceUID\"] == series_uid, \"Modality\"]\n    \n    if not result.empty:\n        return result.values[0]\n    else:\n        # UID not found\n        return None","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-05T10:23:00.262215Z","iopub.execute_input":"2025-11-05T10:23:00.262507Z","iopub.status.idle":"2025-11-05T10:23:00.279176Z","shell.execute_reply.started":"2025-11-05T10:23:00.262479Z","shell.execute_reply":"2025-11-05T10:23:00.278081Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for i in range(5):\n    status = get_aneurysm_present_for_patient(patient_dirs[i], labels)\n    print(status)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-05T10:23:00.280293Z","iopub.execute_input":"2025-11-05T10:23:00.280555Z","iopub.status.idle":"2025-11-05T10:23:00.314163Z","shell.execute_reply.started":"2025-11-05T10:23:00.280536Z","shell.execute_reply":"2025-11-05T10:23:00.313008Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **01 - DataSet**","metadata":{}},{"cell_type":"markdown","source":"## **transforms**","metadata":{}},{"cell_type":"code","source":"def crop_from_slice(tensor):\n    return tensor[..., :30]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-05T10:23:00.31549Z","iopub.execute_input":"2025-11-05T10:23:00.315877Z","iopub.status.idle":"2025-11-05T10:23:00.332339Z","shell.execute_reply.started":"2025-11-05T10:23:00.315848Z","shell.execute_reply":"2025-11-05T10:23:00.33138Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"process = tio.Compose([\n    tio.ToCanonical(),\n    tio.Resample((1, 1, 1)),\n    tio.RescaleIntensity((-1, 1)),\n    tio.Lambda(crop_from_slice),\n    tio.CropOrPad((500, 500, 200)),    \n])\n\naugmentation = tio.RandomAffine(scales=(0.9, 1.1), degrees=(-10, 10))\n\ntrain_transform = tio.Compose([process, augmentation])\nval_transform = tio.Compose([process])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-05T10:23:00.333663Z","iopub.execute_input":"2025-11-05T10:23:00.334607Z","iopub.status.idle":"2025-11-05T10:23:00.352984Z","shell.execute_reply.started":"2025-11-05T10:23:00.334575Z","shell.execute_reply":"2025-11-05T10:23:00.352026Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## **subject dataset**","metadata":{}},{"cell_type":"code","source":"class AneurysmSubjectDataset(Dataset):\n    \"\"\"\n    Loads full 3D volumes (stacked 2D slices) per patient, along with\n    the aneurysm label and modality information.\n\n    Args:\n        patient_dirs (list[Path]): list of SeriesInstanceUID directories\n        labels_df (pd.DataFrame): dataframe with labels\n        train (bool): whether to use train split or validation split\n        test_size (float): fraction of data to use as validation\n        transform: optional transform function (applied to 3D volume)\n        random_state (int): random seed for train/validation split\n    \"\"\"\n    def __init__(self, patient_dirs, labels_df, train=True, test_size=0.2, transform=None, random_state=42):\n        self.labels_df = labels_df\n        self.transform = transform\n\n        # Split into train and validation sets\n        train_dirs, val_dirs = train_test_split(\n            patient_dirs, test_size=test_size, random_state=random_state, shuffle=True\n        )\n        self.patient_dirs = train_dirs if train else val_dirs\n\n    def __len__(self):\n        return len(self.patient_dirs)\n\n    def __getitem__(self, idx):\n        patient_dir = self.patient_dirs[idx]\n\n        # --- Load DICOM slices ---\n        dicom_files = list(patient_dir.glob(\"*.dcm\"))\n        dicoms = [pydicom.dcmread(f) for f in dicom_files]\n        dicoms.sort(key=lambda dcm: int(dcm.InstanceNumber))\n\n        slices = [dcm.pixel_array for dcm in dicoms]\n\n        # Stack into 3D volume: [H, W, D]\n        volume = np.stack(slices, axis=-1)  # [H, W, D]\n        volume = torch.from_numpy(volume).unsqueeze(0).float()  # [1, H, W, D]\n    \n        if self.transform:\n            import torchio as tio\n            subject = tio.Subject(image=tio.ScalarImage(tensor=volume))\n            subject = self.transform(subject)\n            volume = subject.image.data  # Extract transformed tensor\n\n        # --- Labels and Metadata ---\n        label = get_aneurysm_present_for_patient(patient_dir, self.labels_df)\n        modality = get_modality_for_patient(patient_dir, self.labels_df)\n\n        label = torch.tensor(label, dtype=torch.long)\n        modality = str(modality)  # keep as string, not tensor\n\n        return {\n            \"image\": volume,\n            \"label\": label,\n            \"modality\": modality,\n        }","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-05T10:23:00.354303Z","iopub.execute_input":"2025-11-05T10:23:00.35467Z","iopub.status.idle":"2025-11-05T10:23:00.372085Z","shell.execute_reply.started":"2025-11-05T10:23:00.354639Z","shell.execute_reply":"2025-11-05T10:23:00.371242Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_dataset = AneurysmSubjectDataset(\n    patient_dirs=patient_dirs,\n    labels_df=labels,\n    train=True,\n    test_size=0.5,\n    transform=None  \n)\n\nval_dataset = AneurysmSubjectDataset(\n    patient_dirs=patient_dirs,\n    labels_df=labels,\n    train=False,\n    test_size=0.5,\n    transform=None \n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-05T10:27:23.406515Z","iopub.execute_input":"2025-11-05T10:27:23.406864Z","iopub.status.idle":"2025-11-05T10:27:23.416343Z","shell.execute_reply.started":"2025-11-05T10:27:23.406841Z","shell.execute_reply":"2025-11-05T10:27:23.415341Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sample = train_dataset[1]\nimg = sample[\"image\"]\nlabel = sample[\"label\"]\nmodal = sample[\"modality\"]\n\nprint(\"Modality:\", modal)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-05T10:27:23.739599Z","iopub.execute_input":"2025-11-05T10:27:23.739941Z","iopub.status.idle":"2025-11-05T10:27:50.724623Z","shell.execute_reply.started":"2025-11-05T10:27:23.739915Z","shell.execute_reply":"2025-11-05T10:27:50.723744Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for i in range(5):\n    sample = train_dataset[i]\n    img = sample[\"image\"]\n    label = sample[\"label\"]\n    modal = sample[\"modality\"]\n\n    print(\"ImgShape:\", img.shape)\n    print(\"AneurysmPresent:\", label)\n    print(\"Modality:\", modal)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-05T10:27:50.725946Z","iopub.execute_input":"2025-11-05T10:27:50.726946Z","iopub.status.idle":"2025-11-05T10:28:19.849844Z","shell.execute_reply.started":"2025-11-05T10:27:50.726913Z","shell.execute_reply":"2025-11-05T10:28:19.848735Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(len(train_dataset), len(val_dataset))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-05T10:28:19.851139Z","iopub.execute_input":"2025-11-05T10:28:19.851973Z","iopub.status.idle":"2025-11-05T10:28:19.856901Z","shell.execute_reply.started":"2025-11-05T10:28:19.85194Z","shell.execute_reply":"2025-11-05T10:28:19.855825Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## **visualize**","metadata":{}},{"cell_type":"code","source":"fig = plt.figure()\ncamera = Camera(fig)\n\nsample = train_dataset[1]\nimg = sample[\"image\"]\nlabel = sample[\"label\"]\nmodal = sample[\"modality\"]\n\nprint(\"ImgShape:\", img.shape)\nprint(\"AneurysmPresent:\", label)\nprint(\"Modality:\", modal)\n\nfor i in range(img.shape[3]): \n    plt.imshow(img[0, :, :, i], cmap=\"bone\")\n    camera.snap();\n\nanimation = camera.animate(interval=50);\nHTML(animation.to_html5_video())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-05T10:33:54.759812Z","iopub.execute_input":"2025-11-05T10:33:54.760177Z","iopub.status.idle":"2025-11-05T10:35:41.375288Z","shell.execute_reply.started":"2025-11-05T10:33:54.760154Z","shell.execute_reply":"2025-11-05T10:35:41.374377Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}