{"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":[{"sourceType":"competition","sourceId":99552,"databundleVersionId":13441085}],"dockerImageVersionId":31089,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport pydicom\nimport nibabel as nib\nimport ast\n\nimport os\nimport cv2\n\nimport SimpleITK as sitk\nfrom concurrent.futures import ThreadPoolExecutor\nfrom collections import Counter\nimport plotly.graph_objects as go","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-08-23T12:57:34.902022Z","iopub.execute_input":"2025-08-23T12:57:34.902318Z","iopub.status.idle":"2025-08-23T12:57:35.737406Z","shell.execute_reply.started":"2025-08-23T12:57:34.902292Z","shell.execute_reply":"2025-08-23T12:57:35.736353Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"labels = [\n    \"BG\",\n\"Other Posterior Circulation\",\n\"Basilar Tip\",\n\"R Posterior Communicating Artery\",\n\"L Posterior Communicating Artery\",\n\"R Infraclinoid Internal Carotid Artery\",\n\"L Infraclinoid Internal Carotid Artery\",\n\"R Supraclinoid Internal Carotid Artery\",\n\"L Supraclinoid Internal Carotid Artery\",\n\"R Middle Cerebral Artery\",\n\"L Middle Cerebral Artery\",\n\"R Anterior Cerebral Artery\",\n\"L Anterior Cerebral Artery\",\n\"Anterior Communicating Artery\"\n\n]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-23T12:57:35.738327Z","iopub.execute_input":"2025-08-23T12:57:35.738804Z","iopub.status.idle":"2025-08-23T12:57:35.744321Z","shell.execute_reply.started":"2025-08-23T12:57:35.73878Z","shell.execute_reply":"2025-08-23T12:57:35.743305Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"traindf = pd.read_csv(\"/kaggle/input/rsna-intracranial-aneurysm-detection/train.csv\")\nlabeldf = pd.read_csv(\"/kaggle/input/rsna-intracranial-aneurysm-detection/train_localizers.csv\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-23T12:58:00.544067Z","iopub.execute_input":"2025-08-23T12:58:00.544445Z","iopub.status.idle":"2025-08-23T12:58:00.585189Z","shell.execute_reply.started":"2025-08-23T12:58:00.544417Z","shell.execute_reply":"2025-08-23T12:58:00.58405Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\nuid = '1.2.826.0.1.3680043.8.498.10076056930521523789588901704956188485'\nniipath = f\"/kaggle/input/rsna-intracranial-aneurysm-detection/segmentations/{uid}_cowseg.nii\"\n\nlabel = nib.load(niipath)\nlabel.get_fdata().shape","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-23T12:58:02.167731Z","iopub.execute_input":"2025-08-23T12:58:02.168105Z","iopub.status.idle":"2025-08-23T12:58:02.503757Z","shell.execute_reply.started":"2025-08-23T12:58:02.168072Z","shell.execute_reply":"2025-08-23T12:58:02.502774Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"traindf[traindf[\"SeriesInstanceUID\"] == uid]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-23T12:58:02.847425Z","iopub.execute_input":"2025-08-23T12:58:02.847772Z","iopub.status.idle":"2025-08-23T12:58:02.865464Z","shell.execute_reply.started":"2025-08-23T12:58:02.847745Z","shell.execute_reply":"2025-08-23T12:58:02.864547Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def get_label_coords(uid):\n    \n    l = ast.literal_eval(labeldf[labeldf[\"SeriesInstanceUID\"] == uid].coordinates.iloc[0])\n    suid = labeldf[labeldf[\"SeriesInstanceUID\"] == uid].SOPInstanceUID.iloc[0]\n\n    ds = pydicom.dcmread(f\"/kaggle/input/rsna-intracranial-aneurysm-detection/series/{uid}/{suid}.dcm\")\n    \n    return int(l[\"x\"]),int(l[\"y\"]), int(ds.InstanceNumber)\n\n\ndef load_series2vol(series_path, series_id=None, spacing_tolerance=1e-3, resample=False, default_thickness=1.0, max_workers=20):\n    reader = sitk.ImageSeriesReader()\n\n    # Get all series IDs\n    series_ids = reader.GetGDCMSeriesIDs(series_path)\n    if not series_ids:\n        raise RuntimeError(f\"No DICOM series found in {series_path}\")\n\n    # Pick first if not specified\n    series_id = str(series_ids[0] if series_id is None else series_id)\n\n    # Get file names for the series\n    all_files = reader.GetGDCMSeriesFileNames(series_path, series_id)\n\n    # --- Parallel metadata read (fast size check) ---\n    def get_size(f):\n        ds = pydicom.dcmread(f, stop_before_pixels=True)\n        return (int(ds.Rows), int(ds.Columns)), f\n\n    with ThreadPoolExecutor(max_workers=max_workers) as ex:\n        sizes = list(ex.map(get_size, all_files))\n\n    # Pick the most common size\n    most_common_size = Counter(s[0] for s in sizes).most_common(1)[0][0]\n    files = [f for (sz, f) in sizes if sz == most_common_size]\n\n    # --- Now read the actual image series ---\n    reader.SetFileNames(files)\n    image = reader.Execute()\n\n    # --- Fix zero thickness ---\n    spacing = list(image.GetSpacing())\n    if spacing[2] == 0:\n        spacing[2] = default_thickness\n        image.SetSpacing(spacing)\n\n    # --- Optional resample ---\n    if resample and abs(spacing[2] - spacing[0]) > spacing_tolerance:\n        print(\"resampling....\")\n        new_spacing = [spacing[0], spacing[1], spacing[0]]\n        new_size = [\n            int(round(image.GetSize()[0] * spacing[0] / new_spacing[0])),\n            int(round(image.GetSize()[1] * spacing[1] / new_spacing[1])),\n            int(round(image.GetSize()[2] * spacing[2] / new_spacing[2]))\n        ]\n        resampler = sitk.ResampleImageFilter()\n        resampler.SetOutputSpacing(new_spacing)\n        resampler.SetSize(new_size)\n        resampler.SetOutputDirection(image.GetDirection())\n        resampler.SetOutputOrigin(image.GetOrigin())\n        resampler.SetInterpolator(sitk.sitkLinear)\n        image = resampler.Execute(image)\n\n    # Convert to numpy array\n    volume = sitk.GetArrayFromImage(image)\n    return volume\n\ndef view_nii_segmentation(uid, mip, file_path: str, flip=False):\n    \"\"\"\n    Loads and creates a static 2D view of a .nii segmentation.\n\n    Args:\n        uid: identifier (used for label coords).\n        file_path (str): Path to the .nii or .nii.gz file.\n        flip (bool): Whether to flip the Y-axis.\n    \"\"\"\n    nii_image = nib.load(file_path)\n    data = nii_image.get_fdata()\n\n    print(f\"Image dimensions: {data.shape}\")\n    unique_labels = np.unique(data)\n    print(f\"Found labels: {unique_labels}\")\n\n\n    # Plot the MIP as grayscale\n    plt.figure(figsize=(6, 6))\n    plt.imshow(mip, cmap=\"gray\")\n\n    # Overlay label markers\n    for label_value in unique_labels:\n        if label_value == 0:  # skip background\n            continue\n        x, y, z = np.where(data == label_value)\n        x = x[::5]\n        y = y[::5]\n        z = z[::5] \n        if flip: \n            y = data.shape[1] - y\n            \n        plt.scatter(x, y, s=1, label=f\"{labels[int(label_value)]}\", alpha=0.6)\n\n    # Overlay additional label coords\n    lx, ly, lz = get_label_coords(uid)\n\n    plt.scatter([lx], [ly], c=\"red\", s=20, label=\"Label Coord\", marker=\"x\")\n\n    plt.title(\"Segmentation MIP\")\n    plt.axis(\"off\")\n    plt.legend(loc=\"upper right\", fontsize=6)\n    plt.tight_layout()\n    plt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-23T12:58:04.133407Z","iopub.execute_input":"2025-08-23T12:58:04.134046Z","iopub.status.idle":"2025-08-23T12:58:04.150749Z","shell.execute_reply.started":"2025-08-23T12:58:04.134014Z","shell.execute_reply":"2025-08-23T12:58:04.149611Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\nvol = load_series2vol(f\"/kaggle/input/rsna-intracranial-aneurysm-detection/series/{uid}\", uid)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-23T12:58:06.13858Z","iopub.execute_input":"2025-08-23T12:58:06.138911Z","iopub.status.idle":"2025-08-23T12:58:41.608656Z","shell.execute_reply.started":"2025-08-23T12:58:06.138888Z","shell.execute_reply":"2025-08-23T12:58:41.604036Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"mip = vol.max(axis=0)\n\nplt.figure(figsize=(8,8))\nplt.imshow(mip, cmap=\"gray\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-23T12:58:41.617528Z","iopub.execute_input":"2025-08-23T12:58:41.61963Z","iopub.status.idle":"2025-08-23T12:58:42.356553Z","shell.execute_reply.started":"2025-08-23T12:58:41.619442Z","shell.execute_reply":"2025-08-23T12:58:42.355399Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"view_nii_segmentation(uid,mip,niipath)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-23T12:58:42.357576Z","iopub.execute_input":"2025-08-23T12:58:42.357886Z","iopub.status.idle":"2025-08-23T12:59:31.041196Z","shell.execute_reply.started":"2025-08-23T12:58:42.357859Z","shell.execute_reply":"2025-08-23T12:59:31.040156Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Segmentation and the MIP vessels doesn't overlap properly","metadata":{}},{"cell_type":"code","source":"view_nii_segmentation(uid,mip,niipath,flip=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-23T13:00:15.109316Z","iopub.execute_input":"2025-08-23T13:00:15.109667Z","iopub.status.idle":"2025-08-23T13:01:02.257015Z","shell.execute_reply.started":"2025-08-23T13:00:15.109642Z","shell.execute_reply":"2025-08-23T13:01:02.256049Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"But after fliping the segmentation in y-axis they begin to overlap!","metadata":{}}]}