{"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":"nvidiaTeslaT4","dataSources":[{"sourceId":99552,"databundleVersionId":13851420,"sourceType":"competition"}],"dockerImageVersionId":31089,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!pip install -q --upgrade ultralytics","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-10-05T17:29:23.48524Z","iopub.execute_input":"2025-10-05T17:29:23.485488Z","iopub.status.idle":"2025-10-05T17:30:46.671799Z","shell.execute_reply.started":"2025-10-05T17:29:23.485469Z","shell.execute_reply":"2025-10-05T17:30:46.670967Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from ultralytics import YOLO\nYOLO('yolov8n.pt')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-05T17:31:48.830557Z","iopub.execute_input":"2025-10-05T17:31:48.831202Z","iopub.status.idle":"2025-10-05T17:31:52.28421Z","shell.execute_reply.started":"2025-10-05T17:31:48.831169Z","shell.execute_reply":"2025-10-05T17:31:52.283544Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport numpy as np\nimport cv2\nimport pydicom\nimport nibabel as nib\nimport SimpleITK as sitk\nfrom tqdm import tqdm\n\nseries_dir = \"/kaggle/input/rsna-intracranial-aneurysm-detection/series\"\nmask_dir = \"/kaggle/input/rsna-intracranial-aneurysm-detection/segmentations\"\nout_img_dir = \"/kaggle/working/dataset/images/train\"\nout_lbl_dir = \"/kaggle/working/dataset/labels/train\"\n\nos.makedirs(out_img_dir, exist_ok=True)\nos.makedirs(out_lbl_dir, exist_ok=True)\n\ndef load_dicom_sitk(series_path):\n    reader = sitk.ImageSeriesReader()\n    dicom_names = reader.GetGDCMSeriesFileNames(series_path)\n    reader.SetFileNames(dicom_names)\n    image = reader.Execute()\n    array = sitk.GetArrayFromImage(image)  # z, y, x\n    return image, array\n\ndef get_mip(volume):\n    mip = np.max(volume, axis=0)\n    mip = cv2.normalize(mip, None, 0, 255, cv2.NORM_MINMAX)\n    return mip.astype(np.uint8)\n\ndef mask_to_yolo(mask, out_w, out_h):\n    contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)\n    labels = []\n    for cnt in contours:\n        x, y, w, h = cv2.boundingRect(cnt)\n        x_c, y_c = (x + w/2) / out_w, (y + h/2) / out_h\n        w_n, h_n = w / out_w, h / out_h\n        labels.append(f\"0 {x_c:.6f} {y_c:.6f} {w_n:.6f} {h_n:.6f}\\n\")\n    return labels\n\nfor series_id in tqdm(os.listdir(series_dir)):\n    series_path = os.path.join(series_dir, series_id)\n    mask_path = os.path.join(mask_dir, f\"{series_id}.nii\")\n    if not os.path.exists(mask_path):\n        continue\n\n    try:\n        # Load DICOM stack\n        image_itk, volume = load_dicom_sitk(series_path)\n        spacing = image_itk.GetSpacing()\n        direction = image_itk.GetDirection()\n        origin = image_itk.GetOrigin()\n\n        # Load mask and resample to image space\n        mask_itk = sitk.ReadImage(mask_path)\n        mask_resampled = sitk.Resample(mask_itk, image_itk, sitk.Transform(), sitk.sitkNearestNeighbor)\n        mask_volume = sitk.GetArrayFromImage(mask_resampled)\n\n        # Compute MIP of image and mask\n        img_mip = get_mip(volume)\n        mask_mip = (np.max(mask_volume, axis=0) > 0).astype(np.uint8)\n\n        if np.sum(mask_mip) == 0:\n            continue  # skip empty masks\n\n        # Save image\n        cv2.imwrite(f\"{out_img_dir}/{series_id}.png\", img_mip)\n\n        # Save labels\n        labels = mask_to_yolo(mask_mip, img_mip.shape[1], img_mip.shape[0])\n        if labels:\n            with open(f\"{out_lbl_dir}/{series_id}.txt\", \"w\") as f:\n                f.writelines(labels)\n    except Exception as e:\n        print(\"Error with\", series_id, \":\", e)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-05T18:25:20.61659Z","iopub.execute_input":"2025-10-05T18:25:20.616906Z","iopub.status.idle":"2025-10-05T18:56:30.893271Z","shell.execute_reply.started":"2025-10-05T18:25:20.616883Z","shell.execute_reply":"2025-10-05T18:56:30.892423Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import glob\nimgs = glob.glob(\"/kaggle/working/dataset/images/train/*.png\")\nlbls = glob.glob(\"/kaggle/working/dataset/labels/train/*.txt\")\nprint(f\"Images: {len(imgs)}, Labels: {len(lbls)}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-05T18:56:54.68072Z","iopub.execute_input":"2025-10-05T18:56:54.680998Z","iopub.status.idle":"2025-10-05T18:56:54.686566Z","shell.execute_reply.started":"2025-10-05T18:56:54.680977Z","shell.execute_reply":"2025-10-05T18:56:54.686052Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os, random, shutil\nfrom glob import glob\n\n# Source folders\nimg_dir = \"/kaggle/working/dataset/images/train\"\nlbl_dir = \"/kaggle/working/dataset/labels/train\"\n\n# Output structure\nbase_dir = \"/kaggle/working/dataset\"\nos.makedirs(f\"{base_dir}/images/val\", exist_ok=True)\nos.makedirs(f\"{base_dir}/labels/val\", exist_ok=True)\n\nimages = glob(f\"{img_dir}/*.png\")\nrandom.shuffle(images)\nsplit = int(0.8 * len(images))\ntrain_imgs, val_imgs = images[:split], images[split:]\n\nfor subset, subset_imgs in [(\"train\", train_imgs), (\"val\", val_imgs)]:\n    for img_path in subset_imgs:\n        fname = os.path.basename(img_path)\n        lbl_path = os.path.join(lbl_dir, fname.replace(\".png\", \".txt\"))\n        shutil.move(img_path, f\"{base_dir}/images/{subset}/{fname}\")\n        shutil.move(lbl_path, f\"{base_dir}/labels/{subset}/{fname.replace('.png', '.txt')}\")\n\nprint(\"Split complete ✅\")\nprint(f\"Train: {len(train_imgs)} | Val: {len(val_imgs)}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-05T19:16:56.62075Z","iopub.execute_input":"2025-10-05T19:16:56.621048Z","iopub.status.idle":"2025-10-05T19:16:56.661594Z","shell.execute_reply.started":"2025-10-05T19:16:56.621001Z","shell.execute_reply":"2025-10-05T19:16:56.661041Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"yaml_text = \"\"\"\ntrain: /kaggle/working/dataset/images/train\nval: /kaggle/working/dataset/images/val\n\nnc: 1\nnames: ['aneurysm']\n\"\"\"\nwith open(\"/kaggle/working/data.yaml\", \"w\") as f:\n    f.write(yaml_text)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-05T19:17:07.701216Z","iopub.execute_input":"2025-10-05T19:17:07.701477Z","iopub.status.idle":"2025-10-05T19:17:07.705678Z","shell.execute_reply.started":"2025-10-05T19:17:07.701458Z","shell.execute_reply":"2025-10-05T19:17:07.70494Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import cv2, matplotlib.pyplot as plt, glob, random\n\nsample = random.choice(glob.glob(\"/kaggle/working/dataset/images/train/*.png\"))\nimg = cv2.imread(sample)\nh, w = img.shape[:2]\n\nwith open(sample.replace(\"images\", \"labels\").replace(\".png\", \".txt\")) as f:\n    for line in f:\n        _, xc, yc, bw, bh = map(float, line.split())\n        x1 = int((xc - bw/2) * w)\n        y1 = int((yc - bh/2) * h)\n        x2 = int((xc + bw/2) * w)\n        y2 = int((yc + bh/2) * h)\n        cv2.rectangle(img, (x1, y1), (x2, y2), (0,255,0), 2)\n\nplt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))\nplt.title(\"YOLOv8 Training Example\")\nplt.axis('off')\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-05T19:17:13.945534Z","iopub.execute_input":"2025-10-05T19:17:13.946039Z","iopub.status.idle":"2025-10-05T19:17:14.223481Z","shell.execute_reply.started":"2025-10-05T19:17:13.945984Z","shell.execute_reply":"2025-10-05T19:17:14.222722Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from ultralytics import YOLO\n\nmodel = YOLO('yolov8n.pt')  # small model for quick test; use yolov8s.pt later\nmodel.train(\n    data='/kaggle/working/data.yaml',\n    epochs=50,\n    imgsz=640,\n    batch=8,\n    name='rsna_yolo_v1'\n)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-05T19:21:20.585933Z","iopub.execute_input":"2025-10-05T19:21:20.586671Z","iopub.status.idle":"2025-10-05T19:23:36.615768Z","shell.execute_reply.started":"2025-10-05T19:21:20.586648Z","shell.execute_reply":"2025-10-05T19:23:36.614823Z"}},"outputs":[],"execution_count":null}]}