{"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":"gpu","dataSources":[{"sourceId":99552,"databundleVersionId":13747926,"sourceType":"competition"},{"sourceId":12885547,"sourceType":"datasetVersion","datasetId":8030314},{"sourceId":549965,"sourceType":"modelInstanceVersion","modelInstanceId":419249,"modelId":436908}],"dockerImageVersionId":31090,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import sys\nimport matplotlib.pyplot as plt \nsys.path.append('/kaggle/input/rsna-iad-vesselfm-codebase')\nimport torch\nimport torch.nn.functional as F\nimport numpy as np\nfrom tqdm import tqdm\nfrom monai.inferers import SlidingWindowInfererAdapt\nfrom skimage.morphology import remove_small_objects\nfrom skimage.exposure import equalize_hist\nfrom utils.data import generate_transforms\nfrom utils.io import determine_reader_writer\nimport os\nfrom monai.transforms import LoadImaged, Spacingd, LoadImage\nfrom monai.networks.nets import DynUNet\nimport SimpleITK as sitk\nimport yaml\nimport torch.nn as nn\nfrom scipy.ndimage import label\nfrom tqdm import  tqdm\nimport pydicom\nfrom concurrent.futures import ThreadPoolExecutor\nfrom collections import Counter\nimport pandas as pd\nfrom matplotlib.widgets import Slider\nimport ipywidgets as widgets\nfrom IPython.display import HTML\nfrom matplotlib.animation import FuncAnimation\nfrom monai.transforms import (\n    Compose,\n    EnsureChannelFirstd,\n    EnsureTyped,\n    Resized,\n    RandCropByLabelClassesd,\n    SpatialPadd,\n    ConcatItemsd,\n    ToTensord,\n    Lambdad,\n)\n\nfrom monai.transforms import MapTransform\nfrom skimage import morphology, filters","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-09-15T22:38:56.377586Z","iopub.execute_input":"2025-09-15T22:38:56.377877Z","iopub.status.idle":"2025-09-15T22:39:30.966766Z","shell.execute_reply.started":"2025-09-15T22:38:56.377849Z","shell.execute_reply":"2025-09-15T22:39:30.966121Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"yaml_path = '/kaggle/input/rsna-iad-vesselfm-codebase/configs/inference.yaml'\n\nwith open(yaml_path, 'r') as f:\n    config = yaml.safe_load(f)\n\n\nclass CFG:\n    ckpt_path = '/kaggle/input/rsna-iad-vesselfm-13-classes/pytorch/default/2/vesselfm_13_classes_dynunet-val_dice0.5047.ckpt'\n    model_structure = {\n        'in_channels': 1,\n        'out_channels': 14,\n        'spatial_dims': 3,\n        'strides': [[1, 1, 1], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2]] , # 5 levels\n        'kernel_size': [[3, 3, 3], [3, 3, 3], [3, 3, 3], [3, 3, 3], [3, 3, 3]],\n        'upsample_kernel_size': [[2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2]],\n        'filters': [32, 64, 128, 256, 320],\n        'res_block': True}\n    device = 'cuda:0'\n    thrd = 0.1\n\n    #sliding window\n    batch_size= 1\n    patch_size= [128, 128, 128]\n    overlap= 0.5\n    mode= \"constant\"\n    sigma_scale= 0.125\n    padding_mode= \"constant\"\n\n    #volume transform\n    transforms_config = config['transforms_config']\n    transforms_config.insert(1, {'Resize': {\n        'spatial_size': (128, 384, 384),\n        'mode': \"trilinear\"\n    }},)\n    \n    tta = config['tta']\n    post = config['post']\n    merging = config['merging']","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-15T22:39:30.968259Z","iopub.execute_input":"2025-09-15T22:39:30.968926Z","iopub.status.idle":"2025-09-15T22:39:30.984555Z","shell.execute_reply.started":"2025-09-15T22:39:30.968904Z","shell.execute_reply":"2025-09-15T22:39:30.983959Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def load_model(cfg):\n    ckpt = torch.load(cfg.ckpt_path, map_location=cfg.device, weights_only=False)['state_dict']\n    ckpt = {k.replace(\"model.\", \"\"): v for k, v in ckpt.items()}\n    model = DynUNet(**CFG.model_structure)\n    model.load_state_dict(ckpt)\n    model.eval()\n    return model.to(cfg.device)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-15T22:39:30.985273Z","iopub.execute_input":"2025-09-15T22:39:30.986011Z","iopub.status.idle":"2025-09-15T22:39:31.004727Z","shell.execute_reply.started":"2025-09-15T22:39:30.985984Z","shell.execute_reply":"2025-09-15T22:39:31.00395Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = pd.read_csv('/kaggle/input/rsna-intracranial-aneurysm-detection/train.csv')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-15T22:39:31.006458Z","iopub.execute_input":"2025-09-15T22:39:31.006958Z","iopub.status.idle":"2025-09-15T22:39:31.047897Z","shell.execute_reply.started":"2025-09-15T22:39:31.006938Z","shell.execute_reply":"2025-09-15T22:39:31.047298Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model = load_model(CFG)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-15T22:39:31.048685Z","iopub.execute_input":"2025-09-15T22:39:31.049021Z","iopub.status.idle":"2025-09-15T22:39:33.373245Z","shell.execute_reply.started":"2025-09-15T22:39:31.048989Z","shell.execute_reply":"2025-09-15T22:39:33.372607Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"reader = determine_reader_writer('nii')()\ntransforms = generate_transforms(CFG.transforms_config)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-15T22:55:20.395805Z","iopub.execute_input":"2025-09-15T22:55:20.396425Z","iopub.status.idle":"2025-09-15T22:55:20.40095Z","shell.execute_reply.started":"2025-09-15T22:55:20.396398Z","shell.execute_reply":"2025-09-15T22:55:20.400141Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"uid = '1.2.826.0.1.3680043.8.498.10035643165968342618460849823699311381'\ndata_path = '/kaggle/input/rsna-intracranial-aneurysm-detection'\nvol_path = f'{data_path}/segmentations/{uid}.nii'\nmask_path = f'{data_path}/segmentations/{uid}_cowseg.nii'\nvol = reader.read_images(vol_path)[0].astype(np.float32)\nmask = reader.read_images(mask_path)[0]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-15T22:55:36.953838Z","iopub.execute_input":"2025-09-15T22:55:36.954469Z","iopub.status.idle":"2025-09-15T22:55:38.286934Z","shell.execute_reply.started":"2025-09-15T22:55:36.954443Z","shell.execute_reply":"2025-09-15T22:55:38.286344Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sample = df[df.SeriesInstanceUID==uid]\nmodality = sample.Modality.values[0]\nsample","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-15T22:39:35.901615Z","iopub.execute_input":"2025-09-15T22:39:35.901838Z","iopub.status.idle":"2025-09-15T22:39:35.933977Z","shell.execute_reply.started":"2025-09-15T22:39:35.901821Z","shell.execute_reply":"2025-09-15T22:39:35.932932Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"modality","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-15T22:39:35.934831Z","iopub.execute_input":"2025-09-15T22:39:35.935087Z","iopub.status.idle":"2025-09-15T22:39:35.939794Z","shell.execute_reply.started":"2025-09-15T22:39:35.935067Z","shell.execute_reply":"2025-09-15T22:39:35.939043Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class ModalityIntensityScalingd(MapTransform):\n    \"\"\"\n    Modality-agnostic normalization:\n      - Robust z-score within 2–98 percentiles\n      - Then rescale to [0, 1]\n    \"\"\"\n    def __init__(self, keys=(\"Image\",)):\n        super().__init__(keys)\n\n    def __call__(self, data):\n        d = dict(data)\n        img = d[self.keys[0]]\n\n        # robust stats\n        p2, p98 = np.percentile(img, (2, 98))\n        mask = (img >= p2) & (img <= p98)\n        mean = np.mean(img[mask])\n        std = np.std(img[mask]) + 1e-6\n\n        img = (img - mean) / std\n        img = np.clip((img - img.min()) / (img.max() - img.min() + 1e-6), 0, 1)\n\n        d[self.keys[0]] = img.astype(np.float32)\n        return d\n\n\ndef _generate_transforms(vol_size, input_size, mode):\n    if mode == \"train\":\n        return Compose([\n            EnsureChannelFirstd(keys=[\"Image\", \"Mask\"], channel_dim=\"no_channel\"),\n            EnsureTyped(keys=[\"Image\", \"Mask\"]),\n            Resized(keys=[\"Image\", \"Mask\"], spatial_size=vol_size, mode=[\"trilinear\", \"nearest\"]),\n            RandCropByLabelClassesd(\n                keys=[\"Image\", \"Mask\"],\n                label_key=\"Mask\",\n                spatial_size=input_size,\n                num_classes=13,\n                ratios=[1] * 13,\n                num_samples=4,\n                image_key=\"Image\",\n                allow_smaller=True,\n            ),\n            ModalityIntensityScalingd(keys=[\"Image\"]),\n            SpatialPadd(keys=[\"Image\", \"Mask\"], spatial_size=input_size, mode=\"constant\", method=\"symmetric\"),\n            ConcatItemsd(keys=[\"Image\", \"Mask\"], name=[\"Image\", \"Mask\"], dim=0),\n            ToTensord(keys=[\"Image\", \"Mask\"]),\n        ])\n    elif mode == 'val':\n        return Compose([\n            EnsureChannelFirstd(keys=[\"Image\", \"Mask\"], channel_dim=\"no_channel\"),\n            EnsureTyped(keys=[\"Image\", \"Mask\"]),\n            Resized(keys=[\"Image\", \"Mask\"], spatial_size=vol_size, mode=[\"trilinear\", \"nearest\"]),\n            ModalityIntensityScalingd(keys=[\"Image\"]),\n            ToTensord(keys=[\"Image\", \"Mask\"]),\n        ])\n    else:\n        return Compose([\n            EnsureChannelFirstd(keys=[\"Image\"], channel_dim=\"no_channel\"),\n            EnsureTyped(keys=[\"Image\"]),\n            Resized(keys=[\"Image\"], spatial_size=vol_size, mode=[\"trilinear\"]),\n            ModalityIntensityScalingd(keys=[\"Image\"]),\n            ToTensord(keys=[\"Image\"]),\n        ])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-15T22:48:07.265502Z","iopub.execute_input":"2025-09-15T22:48:07.26579Z","iopub.status.idle":"2025-09-15T22:48:07.275773Z","shell.execute_reply.started":"2025-09-15T22:48:07.265768Z","shell.execute_reply":"2025-09-15T22:48:07.274997Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sliding_window_inferer = SlidingWindowInfererAdapt(\n            roi_size=CFG.patch_size, sw_batch_size=1, overlap=0.5,\n        )","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-15T22:39:35.961024Z","iopub.execute_input":"2025-09-15T22:39:35.961302Z","iopub.status.idle":"2025-09-15T22:39:35.978798Z","shell.execute_reply.started":"2025-09-15T22:39:35.961274Z","shell.execute_reply":"2025-09-15T22:39:35.977873Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"T = _generate_transforms((128, 384, 384), (128, 128, 128), 'val')\n_input = {'Image': vol, 'Mask': mask, 'modality': modality}","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-15T22:48:09.254809Z","iopub.execute_input":"2025-09-15T22:48:09.255129Z","iopub.status.idle":"2025-09-15T22:48:09.259843Z","shell.execute_reply.started":"2025-09-15T22:48:09.255106Z","shell.execute_reply":"2025-09-15T22:48:09.258871Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"o = T(_input)\n_vol, _mask = o['Image'].to(CFG.device), o['Mask']","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-15T22:39:35.996404Z","iopub.execute_input":"2025-09-15T22:39:35.996627Z","iopub.status.idle":"2025-09-15T22:39:37.821782Z","shell.execute_reply.started":"2025-09-15T22:39:35.99661Z","shell.execute_reply":"2025-09-15T22:39:37.820983Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"mip, _ = _vol[0].max(dim=0)\nmip = mip.cpu()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-15T22:39:37.822937Z","iopub.execute_input":"2025-09-15T22:39:37.823208Z","iopub.status.idle":"2025-09-15T22:39:37.871825Z","shell.execute_reply.started":"2025-09-15T22:39:37.823188Z","shell.execute_reply":"2025-09-15T22:39:37.870955Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"with torch.no_grad():\n    pred_logits = sliding_window_inferer(_vol[None], model)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-15T22:39:37.872659Z","iopub.execute_input":"2025-09-15T22:39:37.873029Z","iopub.status.idle":"2025-09-15T22:39:42.486603Z","shell.execute_reply.started":"2025-09-15T22:39:37.872996Z","shell.execute_reply":"2025-09-15T22:39:42.486009Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"pred_probs = pred_logits.softmax(dim=1)\npred_mask = pred_logits.argmax(dim=1)\nmask_mip, _ = pred_mask[0].max(dim=0)\nmask_mip = mask_mip.cpu()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-15T22:39:42.487324Z","iopub.execute_input":"2025-09-15T22:39:42.487531Z","iopub.status.idle":"2025-09-15T22:39:42.560062Z","shell.execute_reply.started":"2025-09-15T22:39:42.487513Z","shell.execute_reply":"2025-09-15T22:39:42.559406Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"np.unique(df.Modality.values)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-15T22:39:42.560742Z","iopub.execute_input":"2025-09-15T22:39:42.561013Z","iopub.status.idle":"2025-09-15T22:39:42.567744Z","shell.execute_reply.started":"2025-09-15T22:39:42.56099Z","shell.execute_reply":"2025-09-15T22:39:42.566937Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.imshow(_vol[0].max(dim=0)[0].cpu())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-15T22:39:42.568443Z","iopub.execute_input":"2025-09-15T22:39:42.568719Z","iopub.status.idle":"2025-09-15T22:39:42.871016Z","shell.execute_reply.started":"2025-09-15T22:39:42.568702Z","shell.execute_reply":"2025-09-15T22:39:42.870331Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"_mask_mip = _mask[0].max(dim=0)[0]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-15T22:39:42.871831Z","iopub.execute_input":"2025-09-15T22:39:42.872075Z","iopub.status.idle":"2025-09-15T22:39:42.902432Z","shell.execute_reply.started":"2025-09-15T22:39:42.872056Z","shell.execute_reply":"2025-09-15T22:39:42.901617Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"pred_mask.shape","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-15T22:39:42.903252Z","iopub.execute_input":"2025-09-15T22:39:42.903578Z","iopub.status.idle":"2025-09-15T22:39:42.908471Z","shell.execute_reply.started":"2025-09-15T22:39:42.903551Z","shell.execute_reply":"2025-09-15T22:39:42.907662Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def cca_remove(mask_preds, min_size = 1000, sigma = 0.5):\n    '''\n    mask_preds: (D, H, W)\n    '''\n    #to 2d mip\n    mip_2d = mask_preds.max(axis=0)\n    \n    # Remove small bright spots (choose an area threshold)\n    smoothed_mip = filters.gaussian(mip_2d, sigma=sigma)\n    cleaned_mip = morphology.remove_small_objects(smoothed_mip > 0, min_size=min_size)  \n    \n    # Morphological opening for noise removal\n    selem = morphology.disk(2)  \n    cleaned_mip = morphology.opening(cleaned_mip, selem)\n    \n    # Convert boolean mask back to vessel intensity (optional thresholding)\n    cleaned_mip = cleaned_mip.astype(np.uint8) * mip_2d.max()\n    \n    # Median filter smoothing\n    cleaned_mip_mask = filters.median(cleaned_mip, morphology.disk(1))\n\n    masked_vol = (cleaned_mip_mask[None]!=0) * mask_preds\n\n    new_mip_mask = masked_vol.max(axis=0)\n    \n    return masked_vol, new_mip_mask","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-15T22:39:42.90932Z","iopub.execute_input":"2025-09-15T22:39:42.909554Z","iopub.status.idle":"2025-09-15T22:39:42.924335Z","shell.execute_reply.started":"2025-09-15T22:39:42.909531Z","shell.execute_reply":"2025-09-15T22:39:42.923659Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"_, new_mask_mip = cca_remove(pred_mask[0].cpu().numpy())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-15T22:39:42.9251Z","iopub.execute_input":"2025-09-15T22:39:42.925337Z","iopub.status.idle":"2025-09-15T22:39:43.256781Z","shell.execute_reply.started":"2025-09-15T22:39:42.925315Z","shell.execute_reply":"2025-09-15T22:39:43.256017Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"fig, ax = plt.subplots(ncols=4, figsize = (16, 16))\nax[0].imshow(vol.max(axis=0))\nax[1].imshow(mask_mip)\nax[1].set_title('before process')\nax[2].imshow(new_mask_mip)\nax[2].set_title('after process')\nax[3].imshow(_mask_mip)\nax[3].set_title('ground truth')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-15T22:39:43.257625Z","iopub.execute_input":"2025-09-15T22:39:43.258603Z","iopub.status.idle":"2025-09-15T22:39:44.060821Z","shell.execute_reply.started":"2025-09-15T22:39:43.258575Z","shell.execute_reply":"2025-09-15T22:39:44.060027Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"mask_mip.unique()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-15T22:39:44.061663Z","iopub.execute_input":"2025-09-15T22:39:44.0619Z","iopub.status.idle":"2025-09-15T22:39:44.080805Z","shell.execute_reply.started":"2025-09-15T22:39:44.061871Z","shell.execute_reply":"2025-09-15T22:39:44.080244Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"np.unique(new_mask_mip)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-15T22:39:44.081473Z","iopub.execute_input":"2025-09-15T22:39:44.08167Z","iopub.status.idle":"2025-09-15T22:39:44.090947Z","shell.execute_reply.started":"2025-09-15T22:39:44.081656Z","shell.execute_reply":"2025-09-15T22:39:44.09014Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"n_classes = 13\ncols = 3\nrows = int(np.ceil(n_classes / cols))\n\nfig, ax = plt.subplots(nrows=rows, ncols=cols, figsize=(cols*4, rows*4))\n\n# Flatten the axes array for easy indexing\nax = ax.flatten()\n\nfor i in range(n_classes):\n    ax[i].imshow(new_mask_mip == i+1, cmap='gray')\n    ax[i].imshow(mip, alpha=0.5)\n    ax[i].set_title(f\"Class {i+1}\")\n    ax[i].axis('off')\n\n# Hide unused subplots (if n_classes is not a multiple of cols)\nfor j in range(n_classes, len(ax)):\n    ax[j].axis('off')\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-15T22:39:44.091845Z","iopub.execute_input":"2025-09-15T22:39:44.09213Z","iopub.status.idle":"2025-09-15T22:39:45.837018Z","shell.execute_reply.started":"2025-09-15T22:39:44.092108Z","shell.execute_reply":"2025-09-15T22:39:45.836033Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Adapt to pipeline","metadata":{}},{"cell_type":"code","source":"from pathlib import Path\nfrom typing import List, Tuple, Dict, Optional\nimport cv2","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-15T22:41:37.295375Z","iopub.execute_input":"2025-09-15T22:41:37.295665Z","iopub.status.idle":"2025-09-15T22:41:37.300079Z","shell.execute_reply.started":"2025-09-15T22:41:37.295645Z","shell.execute_reply":"2025-09-15T22:41:37.299036Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def load_dicom_series(series_dir: Path) -> Tuple[np.ndarray, np.ndarray]:\n    \"\"\"\n    Load a DICOM series into a 3D HU volume with affine matrix.\n\n    Args:\n        series_dir (Path): directory containing DICOM files\n\n    Returns:\n        volume (np.ndarray): 3D array (Z, Y, X) in HU\n        affine (np.ndarray): 4x4 voxel-to-world affine\n    \"\"\"\n    # Collect DICOMs\n    dcm_paths = [Path(series_dir) / f for f in os.listdir(series_dir) if f.lower().endswith(\".dcm\")]\n    if not dcm_paths:\n        raise FileNotFoundError(f\"No DICOM files found in {series_dir}\")\n    \n    slices = [pydicom.dcmread(str(p), force=True) for p in dcm_paths]\n\n    # Orientation & sorting\n    orientation = np.array(slices[0].ImageOrientationPatient).reshape(2, 3)\n    row_cos, col_cos = orientation\n    normal = np.cross(row_cos, col_cos)\n    slices.sort(key=lambda ds: np.dot(ds.ImagePositionPatient, normal))\n\n    # HU scaling\n    slope = float(getattr(slices[0], \"RescaleSlope\", 1.0))\n    intercept = float(getattr(slices[0], \"RescaleIntercept\", 0.0))\n    volume = np.stack([ds.pixel_array for ds in slices]).astype(np.float32)\n    volume = volume * slope + intercept\n\n    # Spacing\n    Δx, Δy = [float(x) for x in slices[0].PixelSpacing]\n    positions = [np.array(ds.ImagePositionPatient) for ds in slices]\n    slice_positions = [np.dot(p, normal) for p in positions]\n    Δz = float(np.mean(np.diff(slice_positions)))\n\n    # Affine\n    slice_cos = normal\n    origin = np.array(slices[0].ImagePositionPatient)\n    affine = np.eye(4)\n    affine[0:3, 0] = row_cos * Δx\n    affine[0:3, 1] = col_cos * Δy\n    affine[0:3, 2] = slice_cos * Δz\n    affine[0:3, 3] = origin\n\n    return volume","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-15T22:59:39.567005Z","iopub.execute_input":"2025-09-15T22:59:39.567275Z","iopub.status.idle":"2025-09-15T22:59:39.575488Z","shell.execute_reply.started":"2025-09-15T22:59:39.567251Z","shell.execute_reply":"2025-09-15T22:59:39.574519Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"MAX_WORKERS = 4","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-15T22:40:56.195346Z","iopub.execute_input":"2025-09-15T22:40:56.196171Z","iopub.status.idle":"2025-09-15T22:40:56.199787Z","shell.execute_reply.started":"2025-09-15T22:40:56.196134Z","shell.execute_reply":"2025-09-15T22:40:56.199078Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = pd.read_csv('/kaggle/input/rsna-intracranial-aneurysm-detection/train.csv')\ndf_loc = pd.read_csv('/kaggle/input/rsna-intracranial-aneurysm-detection/train_localizers.csv')\nseg_path = Path('/kaggle/input/rsna-intracranial-aneurysm-detection/segmentations')\nseries_path = Path('/kaggle/input/rsna-intracranial-aneurysm-detection/series')\nseg_uids = [name.split('.nii')[0] for name in os.listdir(seg_path) if 'cowseg' not in name]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-15T23:14:04.685481Z","iopub.execute_input":"2025-09-15T23:14:04.686247Z","iopub.status.idle":"2025-09-15T23:14:04.715674Z","shell.execute_reply.started":"2025-09-15T23:14:04.686221Z","shell.execute_reply":"2025-09-15T23:14:04.714922Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"uid = '1.2.826.0.1.3680043.8.498.10092666779602341135460882241562348436'\npath = series_path/uid\nmask_path = seg_path/f'{uid}_cowseg.nii'\nvol_path = seg_path/f'{uid}.nii'\ndf[df.SeriesInstanceUID\t== uid]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-15T23:14:26.955383Z","iopub.execute_input":"2025-09-15T23:14:26.955948Z","iopub.status.idle":"2025-09-15T23:14:26.968156Z","shell.execute_reply.started":"2025-09-15T23:14:26.955914Z","shell.execute_reply":"2025-09-15T23:14:26.967453Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"transforms = generate_transforms(CFG.transforms_config)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-15T23:14:28.293451Z","iopub.execute_input":"2025-09-15T23:14:28.293732Z","iopub.status.idle":"2025-09-15T23:14:28.297889Z","shell.execute_reply.started":"2025-09-15T23:14:28.293709Z","shell.execute_reply":"2025-09-15T23:14:28.297316Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"vol = load_dicom_series(path)\nvol = np.flip(vol, axis=1).copy()\nvol = np.flip(vol, axis=2).copy()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-15T23:14:28.441355Z","iopub.execute_input":"2025-09-15T23:14:28.442116Z","iopub.status.idle":"2025-09-15T23:14:33.597461Z","shell.execute_reply.started":"2025-09-15T23:14:28.442085Z","shell.execute_reply":"2025-09-15T23:14:33.596777Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"transform_test = _generate_transforms((128, 384, 384), (128, 128, 128), 'test')\n_input = {'Image': vol}","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-15T23:14:33.598674Z","iopub.execute_input":"2025-09-15T23:14:33.599363Z","iopub.status.idle":"2025-09-15T23:14:33.604258Z","shell.execute_reply.started":"2025-09-15T23:14:33.599339Z","shell.execute_reply":"2025-09-15T23:14:33.603637Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_data = transform_test(_input)\ntest_vol = test_data['Image'].to(CFG.device)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-15T23:14:33.605031Z","iopub.execute_input":"2025-09-15T23:14:33.605244Z","iopub.status.idle":"2025-09-15T23:14:35.299444Z","shell.execute_reply.started":"2025-09-15T23:14:33.605227Z","shell.execute_reply":"2025-09-15T23:14:35.298832Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"with torch.no_grad():\n    pred_logits = sliding_window_inferer(test_vol[None], model)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-15T23:14:35.300719Z","iopub.execute_input":"2025-09-15T23:14:35.301051Z","iopub.status.idle":"2025-09-15T23:14:38.705434Z","shell.execute_reply.started":"2025-09-15T23:14:35.301032Z","shell.execute_reply":"2025-09-15T23:14:38.704777Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_mip, _ = test_vol[0].max(dim=0)\ntest_mip = test_mip.cpu()\n\npred_probs = pred_logits.softmax(dim=1)\npred_mask = pred_logits.argmax(dim=1)\n\nmask_mip, _ = pred_mask[0].max(dim=0)\nmask_mip = mask_mip.cpu()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-15T23:14:38.706097Z","iopub.execute_input":"2025-09-15T23:14:38.706279Z","iopub.status.idle":"2025-09-15T23:14:39.647753Z","shell.execute_reply.started":"2025-09-15T23:14:38.706264Z","shell.execute_reply":"2025-09-15T23:14:39.647149Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"_, new_mask_mip = cca_remove(pred_mask[0].cpu().numpy())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-15T23:14:39.648439Z","iopub.execute_input":"2025-09-15T23:14:39.648639Z","iopub.status.idle":"2025-09-15T23:14:39.930605Z","shell.execute_reply.started":"2025-09-15T23:14:39.648622Z","shell.execute_reply":"2025-09-15T23:14:39.930013Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"fig, ax = plt.subplots(ncols=3, figsize = (16, 16))\nax[0].imshow(test_mip)\nax[1].imshow(mask_mip)\nax[1].set_title('before process')\nax[2].imshow(new_mask_mip)\nax[2].set_title('after process')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-15T23:14:39.931388Z","iopub.execute_input":"2025-09-15T23:14:39.93159Z","iopub.status.idle":"2025-09-15T23:14:40.552767Z","shell.execute_reply.started":"2025-09-15T23:14:39.931573Z","shell.execute_reply":"2025-09-15T23:14:40.551864Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}