{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.12","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":71549,"databundleVersionId":8561470}],"dockerImageVersionId":31286,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        os.path.join(dirname, filename)\n\nprint(\"Dataset loading complete .\")\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-03-21T09:15:55.475764Z","iopub.execute_input":"2026-03-21T09:15:55.476186Z","iopub.status.idle":"2026-03-21T09:20:05.550811Z","shell.execute_reply.started":"2026-03-21T09:15:55.476149Z","shell.execute_reply":"2026-03-21T09:20:05.549783Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 1. Preprocessing","metadata":{}},{"cell_type":"code","source":"## Preprocessing Libraries Import\nimport pydicom\nimport cv2\nfrom tqdm import tqdm\n\nprint(\"Preprocessing Libraries Imported\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-21T09:20:05.552803Z","iopub.execute_input":"2026-03-21T09:20:05.553411Z","iopub.status.idle":"2026-03-21T09:20:06.592093Z","shell.execute_reply.started":"2026-03-21T09:20:05.553378Z","shell.execute_reply":"2026-03-21T09:20:06.590967Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"## Directories And Paths Setup\nROOT_DIR = \"/kaggle/input/competitions/rsna-2024-lumbar-spine-degenerative-classification\"\nDICOM_DIR = f\"{ROOT_DIR}/train_images\"\nOUTPUT_ROOT = \"/kaggle/working/final_processed_data\"\n\nprint(\"Done ...\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-21T09:20:06.593348Z","iopub.execute_input":"2026-03-21T09:20:06.593744Z","iopub.status.idle":"2026-03-21T09:20:06.599705Z","shell.execute_reply.started":"2026-03-21T09:20:06.593714Z","shell.execute_reply":"2026-03-21T09:20:06.598769Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"## Subfolders according to Severity (4 Categories)\nseverity_folders = [\n    'Normal_Mild', \n    'Moderate', \n    'Severe', \n    'Inconclusive'\n]\n\n## Subfolders according to Classes (5 Classes)\nclass_folders = [\n    'Left_Neural_Foraminal',\n    'Right_Neural_Foraminal',\n    'Left_Subarticular', \n    'Right_Subarticular',\n    'Left_Spinal_Canal',\n    'Right_Spinal_Canal'\n]\n\nprint(\"Done ...\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-21T09:20:06.601069Z","iopub.execute_input":"2026-03-21T09:20:06.601322Z","iopub.status.idle":"2026-03-21T09:20:06.626969Z","shell.execute_reply.started":"2026-03-21T09:20:06.601299Z","shell.execute_reply":"2026-03-21T09:20:06.625881Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"## Make Directories Accordingly\nfor folder in severity_folders:\n    os.makedirs(os.path.join(OUTPUT_ROOT, \"Severity\", folder), exist_ok=True)\n    \nfor folder in class_folders:\n    os.makedirs(os.path.join(OUTPUT_ROOT, \"By_Class\", folder), exist_ok=True)\n\nprint(\"Success ...\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-21T09:20:06.629746Z","iopub.execute_input":"2026-03-21T09:20:06.630112Z","iopub.status.idle":"2026-03-21T09:20:06.649593Z","shell.execute_reply.started":"2026-03-21T09:20:06.630085Z","shell.execute_reply":"2026-03-21T09:20:06.648438Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"## Loading Training Set Metadata\ndf_train = pd.read_csv(f\"{ROOT_DIR}/train.csv\")\ndf_coords = pd.read_csv(f\"{ROOT_DIR}/train_label_coordinates.csv\")\n\nprint(\"Metadata Loaded ...\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-21T09:20:06.650952Z","iopub.execute_input":"2026-03-21T09:20:06.651493Z","iopub.status.idle":"2026-03-21T09:20:06.932360Z","shell.execute_reply.started":"2026-03-21T09:20:06.651419Z","shell.execute_reply":"2026-03-21T09:20:06.931262Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"## Conversion from DICOM to PNG\ndef dicom_to_png(path):\n    try:\n        ds = pydicom.dcmread(path)\n        img = ds.pixel_array.astype(float)\n        # Rescale intercept and slope if present in DICOM metadata\n        if hasattr(ds, 'RescaleSlope') and hasattr(ds, 'RescaleIntercept'):\n            img = img * ds.RescaleSlope + ds.RescaleIntercept\n        \n        # Standard Min-Max Normalization to 8-bit\n        img = (img - np.min(img)) / (np.max(img) - np.min(img) + 1e-7)\n        img = (img * 255).astype(np.uint8)\n        return cv2.resize(img, (256, 256))\n    except:\n        return None\n\nprint(\"Conversion complete .\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-21T09:20:06.933606Z","iopub.execute_input":"2026-03-21T09:20:06.933961Z","iopub.status.idle":"2026-03-21T09:20:06.942010Z","shell.execute_reply.started":"2026-03-21T09:20:06.933922Z","shell.execute_reply":"2026-03-21T09:20:06.940803Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"## Preprocessing\ndef process_trainset(limit=5000):\n    print(\"Converting DICOMs and generating separate CSVs...\")\n    \n    # Lists to hold data for each CSV\n    severity_data = []\n    class_data = []\n\n    # Iterate through the coordinates dataframe\n    for _, row in tqdm(df_coords.iterrows(), total=min(len(df_coords), limit)):\n        study_id = str(row['study_id'])\n        series_id = str(row['series_id'])\n        instance_num = str(row['instance_number'])\n        condition = row['condition']\n        level = row['level']\n        \n        src_path = os.path.join(DICOM_DIR, study_id, series_id, f\"{instance_num}.dcm\")\n        \n        if os.path.exists(src_path):\n            img = dicom_to_png(src_path)\n            if img is None: continue\n            \n            # 1. Severity Logic & Data Collection\n            col_name = f\"{condition.lower().replace(' ', '_')}_{level.lower().replace('/', '_')}\".replace('neural_foraminal', 'neural_foraminal_narrowing')\n            try:\n                raw_severity = df_train.loc[df_train['study_id'] == int(study_id), col_name].values[0]\n                severity = raw_severity.replace(\"/\", \"_\") if isinstance(raw_severity, str) else \"Inconclusive\"\n            except:\n                severity = \"Inconclusive\"\n            \n            # 2. Class Logic & Data Collection\n            dest_class = condition.replace(' Stenosis', '').replace(' Narrowing', '').replace(' ', '_')\n            if \"Spinal_Canal\" in dest_class:\n                side = \"Left_\" if row['x'] < (img.shape[1] / 2) else \"Right_\"\n                dest_class = side + dest_class\n\n            file_name = f\"{study_id}_{series_id}_{instance_num}.png\"\n            \n            # Save the PNGs physically\n            cv2.imwrite(os.path.join(OUTPUT_ROOT, \"Severity\", severity, file_name), img)\n            cv2.imwrite(os.path.join(OUTPUT_ROOT, \"By_Class\", dest_class, file_name), img)\n\n            # --- Store in separate lists ---\n            severity_data.append({\n                'file_path': f\"Severity/{severity}/{file_name}\",\n                'label': severity,\n                'study_id': study_id\n            })\n            \n            class_data.append({\n                'file_path': f\"By_Class/{dest_class}/{file_name}\",\n                'label': dest_class,\n                'study_id': study_id,\n                'condition': condition\n            })\n\n    # Save CSV 1: Severity\n    pd.DataFrame(severity_data).to_csv(os.path.join(OUTPUT_ROOT, \"severity_labels.csv\"), index=False)\n    \n    # Save CSV 2: Clinical Classes\n    pd.DataFrame(class_data).to_csv(os.path.join(OUTPUT_ROOT, \"class_labels.csv\"), index=False)\n    \n    print(\"\\nCSV generation complete:\")\n    print(f\"- {OUTPUT_ROOT}/severity_labels.csv\")\n    print(f\"- {OUTPUT_ROOT}/class_labels.csv\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-21T09:20:06.943782Z","iopub.execute_input":"2026-03-21T09:20:06.944158Z","iopub.status.idle":"2026-03-21T09:20:06.961799Z","shell.execute_reply.started":"2026-03-21T09:20:06.944118Z","shell.execute_reply":"2026-03-21T09:20:06.960580Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def process_trainset_full():\n    print(\"Starting full conversion...\")\n    # Using len(df_coords) ensures we iterate through every single labeled image\n    process_trainset(limit=len(df_coords)) ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-21T09:20:06.963115Z","iopub.execute_input":"2026-03-21T09:20:06.963612Z","iopub.status.idle":"2026-03-21T09:20:06.984746Z","shell.execute_reply.started":"2026-03-21T09:20:06.963583Z","shell.execute_reply":"2026-03-21T09:20:06.983425Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"process_trainset_full()\nprint(\"Complete .\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-21T09:20:06.986351Z","iopub.execute_input":"2026-03-21T09:20:06.986722Z","iopub.status.idle":"2026-03-21T09:38:07.947702Z","shell.execute_reply.started":"2026-03-21T09:20:06.986685Z","shell.execute_reply":"2026-03-21T09:38:07.945996Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 2. Zipping ","metadata":{}},{"cell_type":"code","source":"import zipfile\nimport shutil\n\nprint(\"All images processed. Creating final ZIP archive...\")\n\ndef zip_and_cleanup(source_dir, zip_filename):\n    with zipfile.ZipFile(zip_filename, 'w', zipfile.ZIP_DEFLATED) as zipf:\n        for root, dirs, files in os.walk(source_dir):\n            for file in files:\n                file_path = os.path.join(root, file)\n                # Add file to zip\n                zipf.write(file_path, os.path.relpath(file_path, source_dir))\n                # DELETE the original file immediately to free up Disk Space\n                os.remove(file_path)\n    \n    # Remove the empty folder structure\n    shutil.rmtree(source_dir)\n\n# Compression and Cleanup\nzip_and_cleanup('/kaggle/working/final_processed_data', '/kaggle/working/rsna_full_output.zip')\n\nprint(\"SUCCESS: The complete dataset is ready in 'rsna_full_output.zip'!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-21T09:38:07.950387Z","iopub.execute_input":"2026-03-21T09:38:07.951125Z","iopub.status.idle":"2026-03-21T09:40:08.423037Z","shell.execute_reply.started":"2026-03-21T09:38:07.951082Z","shell.execute_reply":"2026-03-21T09:40:08.421722Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Download the ZIP file\nfrom IPython.display import FileLink\nFileLink(r'rsna_full_output.zip')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-21T09:40:28.674006Z","iopub.execute_input":"2026-03-21T09:40:28.675012Z","iopub.status.idle":"2026-03-21T09:40:28.680974Z","shell.execute_reply.started":"2026-03-21T09:40:28.674977Z","shell.execute_reply":"2026-03-21T09:40:28.680184Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}