{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.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":71549,"databundleVersionId":8561470,"sourceType":"competition"},{"sourceId":183752660,"sourceType":"kernelVersion"}],"dockerImageVersionId":30732,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"\nimport numpy as np \nimport pandas as pd\nimport os\nimport pydicom\nfrom tqdm import tqdm\nimport matplotlib.pyplot as plt\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2024-06-16T10:28:19.438864Z","iopub.execute_input":"2024-06-16T10:28:19.439259Z","iopub.status.idle":"2024-06-16T10:28:20.042464Z","shell.execute_reply.started":"2024-06-16T10:28:19.439229Z","shell.execute_reply":"2024-06-16T10:28:20.041088Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Build DataFrame","metadata":{}},{"cell_type":"code","source":"def build_dicom_meta_df(train_root):\n    study_ids = os.listdir(train_root)\n    study_ids.sort(key=lambda i: int(os.path.splitext(os.path.basename(i))[0]))\n    counter = 0\n    meta_dict = dict()\n    for study_id in tqdm(study_ids):\n        study_root = os.path.join(train_root, study_id)\n        series_ids = os.listdir(study_root)\n        series_ids.sort(key=lambda i: int(os.path.splitext(os.path.basename(i))[0]))\n        for series_id in series_ids:\n            series_root = os.path.join(study_root, series_id)\n            fn_list = os.listdir(series_root)\n            fn_list.sort(key=lambda i: int(os.path.splitext(os.path.basename(i))[0]))\n            for fn in fn_list:\n                path = os.path.join(series_root, fn)\n                dicom = pydicom.dcmread(path)\n                elem_list = [dicom[elem.tag] for elem in dicom.elements() if elem.VR != 'OB'] # exclude pixel_array\n                keys = ['study_id', 'series_id', 'fn']\n                values = [study_id, series_id, fn]\n                for elem in elem_list:\n                    if isinstance(elem.value, pydicom.multival.MultiValue):\n                        for i, v in enumerate(elem.value):\n                            keys.append(f'{elem.keyword}_{i}')\n                            values.append(v)\n                    else:\n                        keys.append(elem.keyword)\n                        values.append(elem.value)\n        \n                # update meta_dict\n                for k, v in zip(keys, values):\n                    if k in meta_dict:\n                        meta_dict[k].append(v)\n                    else:\n                        meta_dict[k] = counter * [None]\n                        meta_dict[k].append(v)\n                counter += 1\n                \n    # pad to same length\n    for k, v in meta_dict.items():\n        if len(v) < counter:\n            meta_dict[k] = v + (counter - len(v)) * [None]\n            \n    meta_df = pd.DataFrame.from_dict(meta_dict)\n    return meta_df\n\nmeta_df = build_dicom_meta_df('/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification/train_images')\n\nmeta_df.to_csv('dicom_meta.csv', index=False)\n","metadata":{"execution":{"iopub.status.busy":"2024-06-16T10:28:20.262914Z","iopub.execute_input":"2024-06-16T10:28:20.263422Z","iopub.status.idle":"2024-06-16T10:49:10.467715Z","shell.execute_reply.started":"2024-06-16T10:28:20.263390Z","shell.execute_reply":"2024-06-16T10:49:10.466453Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"meta_df","metadata":{"execution":{"iopub.status.busy":"2024-06-16T10:56:55.938269Z","iopub.execute_input":"2024-06-16T10:56:55.938712Z","iopub.status.idle":"2024-06-16T10:56:56.280103Z","shell.execute_reply.started":"2024-06-16T10:56:55.938676Z","shell.execute_reply":"2024-06-16T10:56:56.278879Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(15, 15))\n\nplt.subplot(3, 2, 1)\nplt.title('Rows')\nmeta_df['Rows'].hist()\n\nplt.subplot(3, 2, 2)\nplt.title('Rows')\nmeta_df['Columns'].hist()\n\nplt.subplot(3, 2, 3)\nplt.title('Slice Thickness')\nmeta_df['SliceThickness'].hist()\n\nplt.subplot(3, 2, 4)\nplt.title('Spacing Between Slices')\nmeta_df['SpacingBetweenSlices'].hist()\n\nplt.subplot(3, 2, 5)\nplt.title('Slice Location')\nmeta_df['SliceLocation'].hist()","metadata":{"execution":{"iopub.status.busy":"2024-06-16T09:39:23.669805Z","iopub.execute_input":"2024-06-16T09:39:23.670315Z","iopub.status.idle":"2024-06-16T09:39:25.396224Z","shell.execute_reply.started":"2024-06-16T09:39:23.670257Z","shell.execute_reply":"2024-06-16T09:39:25.394596Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"meta_df.drop(['study_id', 'series_id', 'fn', 'StudyInstanceUID', 'SeriesInstanceUID', 'PatientID'], axis=1).hist(figsize=(20, 20));","metadata":{"execution":{"iopub.status.busy":"2024-06-16T09:39:25.400194Z","iopub.execute_input":"2024-06-16T09:39:25.400751Z","iopub.status.idle":"2024-06-16T09:39:32.301795Z","shell.execute_reply.started":"2024-06-16T09:39:25.400703Z","shell.execute_reply":"2024-06-16T09:39:32.300471Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Spacing Between Slices\n`SpacingBetweenSlices == (ImagePositionPatient[1] - ImagePositionPatient[0]).square().sum().sqrt()`","metadata":{}},{"cell_type":"code","source":"temp_df = meta_df[['ImagePositionPatient_0', 'ImagePositionPatient_1', 'ImagePositionPatient_2', 'SpacingBetweenSlices']]\ni = 0\nx1, y1, z1, d1 = temp_df.iloc[i]\nx2, y2, z2, d2 = temp_df.iloc[i+1]\n\n((x1 - x2) ** 2 + (y1 - y2)**2 + (z1 - z2) ** 2) ** 0.5, d1, d2","metadata":{"execution":{"iopub.status.busy":"2024-06-16T09:39:32.303477Z","iopub.execute_input":"2024-06-16T09:39:32.303866Z","iopub.status.idle":"2024-06-16T09:39:32.317810Z","shell.execute_reply.started":"2024-06-16T09:39:32.303833Z","shell.execute_reply":"2024-06-16T09:39:32.316310Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# series Thickness","metadata":{}},{"cell_type":"code","source":"train_series_descriptions = pd.read_csv('/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification/train_series_descriptions.csv')\nseries_description_dict = {str(row['series_id']):row['series_description'] for _, row in train_series_descriptions.iterrows()}","metadata":{"execution":{"iopub.status.busy":"2024-06-16T10:56:19.185730Z","iopub.execute_input":"2024-06-16T10:56:19.186605Z","iopub.status.idle":"2024-06-16T10:56:19.567109Z","shell.execute_reply.started":"2024-06-16T10:56:19.186555Z","shell.execute_reply":"2024-06-16T10:56:19.565591Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\nthickness = dict()\n\nfor _, row in tqdm(meta_df.iterrows(), total=len(meta_df)):\n    records = thickness.get(row['series_id'], [])\n    thickness[row['series_id']] = records\n    coord = row[['ImagePositionPatient_0', 'ImagePositionPatient_1', 'ImagePositionPatient_2']].to_numpy()\n    records.append(coord)\n\nfor k, records in thickness.items():\n    thickness[k] = np.stack(records, axis=0)\n    # compute thickness\n    thickness[k] = np.sum(np.sum(np.diff(thickness[k], axis=0)**2, axis=1) ** 0.5)\n\nsagittal_t2_thickness = [thickness[k] for k in thickness.keys() if series_description_dict[k] == 'Sagittal T2/STIR']\nsagittal_t1_thickness = [thickness[k] for k in thickness.keys() if series_description_dict[k] == 'Sagittal T1']\naxial_t2_thickness = [thickness[k] for k in thickness.keys() if series_description_dict[k] == 'Axial T2']","metadata":{"execution":{"iopub.status.busy":"2024-06-16T10:56:23.807585Z","iopub.execute_input":"2024-06-16T10:56:23.808528Z","iopub.status.idle":"2024-06-16T10:56:23.825178Z","shell.execute_reply.started":"2024-06-16T10:56:23.808490Z","shell.execute_reply":"2024-06-16T10:56:23.823902Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(10, 2))\nplt.subplot(1, 3, 1)\nplt.hist(sagittal_t2_thickness, bins=20);\nplt.title('Sagittal T2/STIR')\nplt.grid(True)\n\nplt.subplot(1, 3, 2)\nplt.hist(sagittal_t1_thickness, bins=20);\nplt.title('Sagittal T1')\nplt.grid(True)\n\nplt.subplot(1, 3, 3)\nplt.hist(axial_t2_thickness, bins=20);\nplt.title('Axial T2')\nplt.grid(True)","metadata":{"execution":{"iopub.status.busy":"2024-06-16T10:56:25.888920Z","iopub.execute_input":"2024-06-16T10:56:25.890242Z","iopub.status.idle":"2024-06-16T10:56:26.619618Z","shell.execute_reply.started":"2024-06-16T10:56:25.890195Z","shell.execute_reply":"2024-06-16T10:56:26.618394Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}