{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"## Background\n\nThe spine is made up of bones, muscles, tendons, nerves, and other tissues that reach from the base of the skull near the spinal cord (clivus) to the coccyx (tailbone). The vertebrae (back bones) of the spine include the **cervical spine (C1-C7)**, thoracic spine (T1-T12), lumbar spine (L1-L5), sacral spine (S1-S5), and the tailbone.([source](https://www.cancer.gov/publications/dictionaries/cancer-terms/def/vertebral-column)).\n\n<img align=center src=\"https://i.imgur.com/xDpCFsX.png\" width=350>\n\nThe **goal** of this competition is to identify fractures in CT scans of the cervical spine (neck) at both the level of a single vertebrae and the entire patient. The example below shows a minimally displaced C4 fracture in the axial (A), sagittal (B) and coronal (C) planes ([source](http://www.ajnr.org/content/early/2021/04/01/ajnr.A7094/tab-figures-data)).\n\n<img align=center src=\"https://i.imgur.com/8uusLFK.png\" width=800>","metadata":{}},{"cell_type":"markdown","source":"## Libraries","metadata":{}},{"cell_type":"code","source":"import os\nimport glob\nimport pydicom\nimport nibabel as nib\nimport pandas as pd\nimport numpy as np\nfrom pydicom.pixel_data_handlers.util import apply_voi_lut\nimport matplotlib.pyplot as plt\nimport matplotlib.patches as patches\nimport seaborn as sns","metadata":{"execution":{"iopub.status.busy":"2022-08-17T15:15:13.518312Z","iopub.execute_input":"2022-08-17T15:15:13.519178Z","iopub.status.idle":"2022-08-17T15:15:15.252649Z","shell.execute_reply.started":"2022-08-17T15:15:13.518912Z","shell.execute_reply":"2022-08-17T15:15:15.250741Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"DATA_DIR = \"../input/rsna-2022-cervical-spine-fracture-detection\"\nTRAIN_DIR = os.path.join(DATA_DIR, \"train_images\")\nSEGM_DIR = os.path.join(DATA_DIR, \"segmentations\")\n\ntrain_df = pd.read_csv(os.path.join(DATA_DIR, \"train.csv\"))\nprint(train_df.shape)\ntrain_df.head()","metadata":{"execution":{"iopub.status.busy":"2022-08-17T15:15:15.255529Z","iopub.execute_input":"2022-08-17T15:15:15.256166Z","iopub.status.idle":"2022-08-17T15:15:15.309635Z","shell.execute_reply.started":"2022-08-17T15:15:15.256112Z","shell.execute_reply":"2022-08-17T15:15:15.308142Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# source: https://www.kaggle.com/code/andradaolteanu/rsna-fracture-detection-dicom-images-explore\nsns.set_theme()\nfig, (ax1, ax2) = plt.subplots(1, 2, figsize=(24, 12))\nsns.countplot(x=\"patient_overall\", data=train_df, ax=ax1)\nax1.set_title(\"Fracture overall\")\n\ntrain_df_melt = pd.melt(train_df, id_vars=[\"StudyInstanceUID\", \"patient_overall\"], var_name=\"cervical_vertebrae\", value_name=\"fracture\")\nsns.countplot(x=\"cervical_vertebrae\", hue=\"fracture\", data=train_df_melt, ax=ax2)\nax2.set_title(\"Fracture of cervical vertebrae\");","metadata":{"execution":{"iopub.status.busy":"2022-08-17T15:15:15.311876Z","iopub.execute_input":"2022-08-17T15:15:15.31353Z","iopub.status.idle":"2022-08-17T15:15:15.923725Z","shell.execute_reply.started":"2022-08-17T15:15:15.313459Z","shell.execute_reply":"2022-08-17T15:15:15.922539Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Takeaways**:\n* data is balanced in terms of overall fractures\n* C7 was broken most often in the data\n* C3 was broken least often","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize=(16, 10))\nsns.countplot(x=train_df.iloc[:, 2:].sum(axis=1))\nplt.xlabel(\"number of fractures\")\nplt.title(\"Number of fractures per patient\");","metadata":{"execution":{"iopub.status.busy":"2022-08-17T15:15:15.927979Z","iopub.execute_input":"2022-08-17T15:15:15.929347Z","iopub.status.idle":"2022-08-17T15:15:16.233609Z","shell.execute_reply.started":"2022-08-17T15:15:15.929283Z","shell.execute_reply":"2022-08-17T15:15:16.231652Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Takeaways**:\n* among patients with a fracture, most of them have 1 or 2 cervical vertebrae fractured","metadata":{}},{"cell_type":"markdown","source":"## Patterns in multiple fractures","metadata":{}},{"cell_type":"code","source":"def get_fracture_indices(train_df, num_frac):\n    df = train_df[train_df.iloc[:, 2:].sum(axis=1) == num_frac].iloc[:, 2:]\n    # create a np array with the column indices\n    col_idx_tmp = np.tile(np.arange(df.shape[1]), df.shape[0])\n    col_idx = np.reshape(col_idx_tmp, df.shape)\n    # select column indices in each row that are nonzero, i.e. fractures\n    nonzero_col_idx = col_idx[df.to_numpy(dtype=bool)]\n    return nonzero_col_idx","metadata":{"execution":{"iopub.status.busy":"2022-08-17T15:15:16.236616Z","iopub.execute_input":"2022-08-17T15:15:16.237195Z","iopub.status.idle":"2022-08-17T15:15:16.247283Z","shell.execute_reply.started":"2022-08-17T15:15:16.237152Z","shell.execute_reply":"2022-08-17T15:15:16.245567Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# patients with two fractures\ntwo_frac_indices = get_fracture_indices(train_df, 2)\ndist_btw_fractures = np.diff(two_frac_indices.reshape(-1, 2), axis=1).flatten()\n\nplt.figure(figsize=(16, 10))\nsns.countplot(x=dist_btw_fractures)\nplt.xlabel(\"distance between fractured cervical vertebrae\")\nplt.title(\"Distance between fractured cervical vertebrae for patients with two fractures (e.g. C1 and C3 have distance 2)\");","metadata":{"execution":{"iopub.status.busy":"2022-08-17T15:15:16.249461Z","iopub.execute_input":"2022-08-17T15:15:16.252325Z","iopub.status.idle":"2022-08-17T15:15:16.5687Z","shell.execute_reply.started":"2022-08-17T15:15:16.252235Z","shell.execute_reply":"2022-08-17T15:15:16.567417Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Takeaways**:\n* for the vast majority of patients with 2 fractures, the 2 fractured cervical vertebrae are next to each other\n* this information might be useful for postprocessing","metadata":{}},{"cell_type":"code","source":"# patients with three fractures\nthree_frac_indices = get_fracture_indices(train_df, 3)\ndist_btw_subseq_frac = np.diff(three_frac_indices.reshape(-1, 3), axis=1).flatten()\npct_patients_w_subseq_frac = (dist_btw_subseq_frac.reshape(-1, 2).sum(axis=1) == 2).mean()\n\nplt.figure(figsize=(12, 8))\nplt.bar(x=[\"\\w subsequent fractures\", \"\\wo subsequent fractures\"], height=[pct_patients_w_subseq_frac, 1-pct_patients_w_subseq_frac], width=0.5)\nplt.ylabel(\"proportion of patients\")\nplt.title(\"Patients with 3 fractures\");","metadata":{"execution":{"iopub.status.busy":"2022-08-17T15:15:16.570917Z","iopub.execute_input":"2022-08-17T15:15:16.57138Z","iopub.status.idle":"2022-08-17T15:15:16.811925Z","shell.execute_reply.started":"2022-08-17T15:15:16.571342Z","shell.execute_reply":"2022-08-17T15:15:16.810591Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Takeaways**:\n* for around half of the patients with 3 fractures, the fractured cervical vertebrae are subsequent ones (e.g. C1, C2, C3)","metadata":{}},{"cell_type":"markdown","source":"## Dicom files\n### Example","metadata":{}},{"cell_type":"code","source":"example = \"../input/rsna-2022-cervical-spine-fracture-detection/train_images/1.2.826.0.1.3680043.10001/1.dcm\"\nexample_ds = pydicom.dcmread(example)\nexample_ds","metadata":{"execution":{"iopub.status.busy":"2022-08-17T15:15:16.813826Z","iopub.execute_input":"2022-08-17T15:15:16.814329Z","iopub.status.idle":"2022-08-17T15:15:16.841819Z","shell.execute_reply.started":"2022-08-17T15:15:16.81429Z","shell.execute_reply":"2022-08-17T15:15:16.840832Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# source: https://www.kaggle.com/code/allunia/rsna-csf-cervical-spine-fracture-eda/notebook\ndef rescale_img_to_hu(dcm_ds):\n    \"\"\"Rescales the image to Hounsfield unit.\n    \"\"\"\n    return dcm_ds.pixel_array * dcm_ds.RescaleSlope + dcm_ds.RescaleIntercept","metadata":{"execution":{"iopub.status.busy":"2022-08-17T15:15:16.843418Z","iopub.execute_input":"2022-08-17T15:15:16.844242Z","iopub.status.idle":"2022-08-17T15:15:16.850209Z","shell.execute_reply.started":"2022-08-17T15:15:16.844197Z","shell.execute_reply":"2022-08-17T15:15:16.84913Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# original image\nfig, axs = plt.subplots(2, 2, figsize=(24, 12))\naxs[0, 0].imshow(example_ds.pixel_array, cmap=\"bone\")\naxs[0, 0].axis(\"off\")\nsns.histplot(example_ds.pixel_array.flatten(), ax=axs[0, 1])\n\n# rescaled image\nrescaled_img = rescale_img_to_hu(example_ds)\naxs[1, 0].imshow(rescaled_img, cmap=\"bone\")\naxs[1, 0].axis(\"off\")\nsns.histplot(rescaled_img.flatten(), ax=axs[1, 1])","metadata":{"execution":{"iopub.status.busy":"2022-08-17T15:15:16.854137Z","iopub.execute_input":"2022-08-17T15:15:16.855017Z","iopub.status.idle":"2022-08-17T15:15:18.799322Z","shell.execute_reply.started":"2022-08-17T15:15:16.854969Z","shell.execute_reply":"2022-08-17T15:15:18.798076Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def show_slices_for_patient(patient_id, nrows, ncols):\n    patient_dir = os.path.join(TRAIN_DIR, patient_id)\n    num_slices = len(glob.glob(f\"{patient_dir}/*\"))\n    print(f\"Number of slices for patient: {num_slices}\")\n    fig, axs = plt.subplots(nrows, ncols, figsize=(24,15))\n    axs = axs.flatten()\n    for i in range(min(num_slices, nrows*ncols)):\n        # dicom filenames start from 1\n        ds = pydicom.dcmread(os.path.join(patient_dir, f\"{i+1}.dcm\"))\n        axs[i].imshow(rescale_img_to_hu(ds), cmap=\"bone\")\n        axs[i].axis(\"off\")","metadata":{"execution":{"iopub.status.busy":"2022-08-17T15:15:18.800543Z","iopub.execute_input":"2022-08-17T15:15:18.800984Z","iopub.status.idle":"2022-08-17T15:15:18.810006Z","shell.execute_reply.started":"2022-08-17T15:15:18.800948Z","shell.execute_reply":"2022-08-17T15:15:18.808682Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"show_slices_for_patient(\"1.2.826.0.1.3680043.10001\", 4, 6)","metadata":{"execution":{"iopub.status.busy":"2022-08-17T15:15:18.811507Z","iopub.execute_input":"2022-08-17T15:15:18.812322Z","iopub.status.idle":"2022-08-17T15:15:22.32756Z","shell.execute_reply.started":"2022-08-17T15:15:18.812272Z","shell.execute_reply":"2022-08-17T15:15:22.326197Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Number of slices per patient","metadata":{}},{"cell_type":"code","source":"def calc_num_slices_per_patient(train_df):\n    num_slices = []\n    for patient_id in train_df[\"StudyInstanceUID\"]:\n        slice_paths = glob.glob(f\"{TRAIN_DIR}/{patient_id}/*\")\n        num_slices.append(len(slice_paths))\n    train_df[\"num_slices\"] = num_slices\n    return train_df","metadata":{"execution":{"iopub.status.busy":"2022-08-17T15:15:22.329225Z","iopub.execute_input":"2022-08-17T15:15:22.330231Z","iopub.status.idle":"2022-08-17T15:15:22.337504Z","shell.execute_reply.started":"2022-08-17T15:15:22.330188Z","shell.execute_reply":"2022-08-17T15:15:22.335657Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df = calc_num_slices_per_patient(train_df)\ntrain_df.head()","metadata":{"execution":{"iopub.status.busy":"2022-08-17T15:15:22.339976Z","iopub.execute_input":"2022-08-17T15:15:22.340812Z","iopub.status.idle":"2022-08-17T15:18:52.930315Z","shell.execute_reply.started":"2022-08-17T15:15:22.340769Z","shell.execute_reply":"2022-08-17T15:18:52.928721Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(16, 10))\nsns.histplot(x=\"num_slices\", data=train_df)\nplt.title(\"Histogram of number of slices per patient\");","metadata":{"execution":{"iopub.status.busy":"2022-08-17T15:18:52.932268Z","iopub.execute_input":"2022-08-17T15:18:52.932689Z","iopub.status.idle":"2022-08-17T15:18:53.321509Z","shell.execute_reply.started":"2022-08-17T15:18:52.932654Z","shell.execute_reply":"2022-08-17T15:18:53.320187Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Segmentations","metadata":{}},{"cell_type":"code","source":"# nibabel docs: https://nipy.org/nibabel/nifti_images.html?highlight=nifti\nexample_path = \"../input/rsna-2022-cervical-spine-fracture-detection/segmentations/1.2.826.0.1.3680043.10921.nii\"\nexample_segm_mask = nib.load(example_path)\nprint(example_segm_mask.header)","metadata":{"execution":{"iopub.status.busy":"2022-08-17T15:18:53.323313Z","iopub.execute_input":"2022-08-17T15:18:53.323681Z","iopub.status.idle":"2022-08-17T15:18:53.347706Z","shell.execute_reply.started":"2022-08-17T15:18:53.323647Z","shell.execute_reply":"2022-08-17T15:18:53.346454Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df[train_df[\"StudyInstanceUID\"] == \"1.2.826.0.1.3680043.10921\"]","metadata":{"execution":{"iopub.status.busy":"2022-08-17T15:18:53.349341Z","iopub.execute_input":"2022-08-17T15:18:53.350574Z","iopub.status.idle":"2022-08-17T15:18:53.372034Z","shell.execute_reply.started":"2022-08-17T15:18:53.350529Z","shell.execute_reply":"2022-08-17T15:18:53.37038Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Nifti header field `dim` shows that patient \"1.2.826.0.1.3680043.10921\" has 339 slices.","metadata":{}},{"cell_type":"code","source":"def show_segm_for_patient(patient_id, nrows, ncols, step=1):\n    \"\"\"Shows slices with segmentation masks for the patient, skips slices that have empty segmentation masks.\"\"\"\n    num_slices = train_df.loc[train_df[\"StudyInstanceUID\"] == patient_id, \"num_slices\"].values[0]\n    print(f\"Number of slices for patient: {num_slices}\")\n    \n    print(f\"Fracture information for patient: \")\n    print(f\"{train_df[train_df['StudyInstanceUID'] == patient_id].iloc[:, 1:-1]}\")\n    patient_dir = os.path.join(TRAIN_DIR, patient_id)\n    \n    segm_path = os.path.join(SEGM_DIR, f\"{patient_id}.nii\")\n    # source: https://www.kaggle.com/code/kretes/segmentations-fracture-zoom-in\n    segm_mask = nib.load(segm_path).get_fdata()\n        \n    # flip in z axis\n    segm_mask = np.flip(segm_mask, axis=-1)\n    # rotate 90 degrees in xy\n    segm_mask = np.rot90(segm_mask, axes=(0, 1))\n        \n    fig, axs = plt.subplots(nrows, ncols, figsize=(24,15))\n    axs = axs.flatten()\n    \n    count = 0\n    idx = 0\n    while count < nrows*ncols:\n        if segm_mask[:, :, idx].max() > 0:\n            # dicom filenames start from 1\n            ds = pydicom.dcmread(os.path.join(patient_dir, f\"{idx+1}.dcm\"))\n            axs[count].imshow(rescale_img_to_hu(ds), cmap=\"bone\")\n            axs[count].axis(\"off\")\n            segm_im = axs[count].imshow(segm_mask[:, :, idx], alpha=0.4)\n            segm_max = segm_mask[:, :, idx].max()\n            \n            segm_labels = np.unique(segm_mask[:, :, idx][segm_mask[:, :, idx].nonzero()])\n            segm_colors = [segm_im.cmap(label/segm_max) for label in segm_labels]\n            ptch = [patches.Patch(color=segm_colors[i], label=f\"C{int(segm_labels[i])}\") for i in range(len(segm_labels))]\n            axs[count].legend(handles=ptch)\n            count += 1\n        idx += step","metadata":{"execution":{"iopub.status.busy":"2022-08-17T15:39:27.004239Z","iopub.execute_input":"2022-08-17T15:39:27.004717Z","iopub.status.idle":"2022-08-17T15:39:27.020109Z","shell.execute_reply.started":"2022-08-17T15:39:27.004683Z","shell.execute_reply":"2022-08-17T15:39:27.019108Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"show_segm_for_patient(\"1.2.826.0.1.3680043.10921\", nrows=4, ncols=6, step=8)","metadata":{"execution":{"iopub.status.busy":"2022-08-17T15:39:30.336018Z","iopub.execute_input":"2022-08-17T15:39:30.33727Z","iopub.status.idle":"2022-08-17T15:39:35.124676Z","shell.execute_reply.started":"2022-08-17T15:39:30.337214Z","shell.execute_reply":"2022-08-17T15:39:35.123026Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Takeaway**\n* in the axial plane, usually 1 or 2 cervical vertebrae are visible in a given slice","metadata":{}},{"cell_type":"markdown","source":"## Bounding boxes","metadata":{}},{"cell_type":"code","source":"bboxes_df = pd.read_csv(os.path.join(DATA_DIR, \"train_bounding_boxes.csv\"))\nprint(bboxes_df.shape)\nbboxes_df.head()","metadata":{"execution":{"iopub.status.busy":"2022-08-17T15:18:59.857128Z","iopub.execute_input":"2022-08-17T15:18:59.857676Z","iopub.status.idle":"2022-08-17T15:18:59.904484Z","shell.execute_reply.started":"2022-08-17T15:18:59.85764Z","shell.execute_reply":"2022-08-17T15:18:59.903405Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(f\"Number of patients with bounding boxes: {bboxes_df['StudyInstanceUID'].nunique()}\")","metadata":{"execution":{"iopub.status.busy":"2022-08-17T15:18:59.90636Z","iopub.execute_input":"2022-08-17T15:18:59.908105Z","iopub.status.idle":"2022-08-17T15:18:59.917286Z","shell.execute_reply.started":"2022-08-17T15:18:59.908043Z","shell.execute_reply":"2022-08-17T15:18:59.915926Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df_bbox = train_df[train_df[\"StudyInstanceUID\"].isin(bboxes_df[\"StudyInstanceUID\"])].drop(columns=\"num_slices\")\n\nsns.set_theme()\nfig, (ax1, ax2) = plt.subplots(1, 2, figsize=(24, 12))\nsns.countplot(x=\"patient_overall\", data=train_df_bbox, ax=ax1)\nax1.set_title(\"Fracture overall (patients with bounding boxes)\")\n\ntrain_df_bbox_melt = pd.melt(train_df_bbox, id_vars=[\"StudyInstanceUID\", \"patient_overall\"], var_name=\"cervical_vertebrae\", value_name=\"fracture\")\nsns.countplot(x=\"cervical_vertebrae\", hue=\"fracture\", data=train_df_bbox_melt, ax=ax2)\nax2.set_title(\"Fracture of cervical vertebrae (patients with bounding boxes)\");","metadata":{"execution":{"iopub.status.busy":"2022-08-17T15:18:59.918945Z","iopub.execute_input":"2022-08-17T15:18:59.920147Z","iopub.status.idle":"2022-08-17T15:19:00.405723Z","shell.execute_reply.started":"2022-08-17T15:18:59.920094Z","shell.execute_reply":"2022-08-17T15:19:00.404247Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def show_bboxes_for_patient(patient_id, nrows, ncols):\n    patient_dir = os.path.join(TRAIN_DIR, patient_id)\n    num_slices = len(glob.glob(f\"{patient_dir}/*\"))\n    print(f\"Number of slices for patient: {num_slices}\")\n    \n    bboxes_patient_df = bboxes_df[bboxes_df[\"StudyInstanceUID\"] == patient_id]\n    num_bboxes = bboxes_patient_df.shape[0]\n    print(f\"Number of bounding boxes for patient: {num_bboxes}\")\n    \n    print(f\"Fracture information for patient: \")\n    print(f\"{train_df[train_df['StudyInstanceUID'] == patient_id].iloc[:, 1:-1]}\")\n    \n    fig, axs = plt.subplots(nrows, ncols, figsize=(24,15))\n    axs = axs.flatten()\n    \n    for i in range(min(num_bboxes, nrows*ncols)):\n        slice_number = bboxes_patient_df.iloc[i][\"slice_number\"]\n        ds = pydicom.dcmread(os.path.join(patient_dir, f\"{slice_number}.dcm\"))\n        axs[i].imshow(rescale_img_to_hu(ds), cmap=\"bone\")\n        axs[i].axis(\"off\")\n        \n        x = bboxes_patient_df.iloc[i][\"x\"]\n        y = bboxes_patient_df.iloc[i][\"y\"]\n        width = bboxes_patient_df.iloc[i][\"width\"]\n        height = bboxes_patient_df.iloc[i][\"height\"]\n        rect = patches.Rectangle((x, y), width, height, fill=False, edgecolor=\"blue\", linewidth=1.5)\n        axs[i].add_patch(rect)","metadata":{"execution":{"iopub.status.busy":"2022-08-17T15:19:00.407491Z","iopub.execute_input":"2022-08-17T15:19:00.408697Z","iopub.status.idle":"2022-08-17T15:19:00.419907Z","shell.execute_reply.started":"2022-08-17T15:19:00.408653Z","shell.execute_reply":"2022-08-17T15:19:00.418622Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"show_bboxes_for_patient(\"1.2.826.0.1.3680043.10051\", 3, 5)","metadata":{"execution":{"iopub.status.busy":"2022-08-17T15:19:00.421492Z","iopub.execute_input":"2022-08-17T15:19:00.421857Z","iopub.status.idle":"2022-08-17T15:19:02.947421Z","shell.execute_reply.started":"2022-08-17T15:19:00.421824Z","shell.execute_reply":"2022-08-17T15:19:02.945536Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"show_bboxes_for_patient(\"1.2.826.0.1.3680043.19381\", 4, 5)","metadata":{"execution":{"iopub.status.busy":"2022-08-17T15:34:50.262562Z","iopub.execute_input":"2022-08-17T15:34:50.263175Z","iopub.status.idle":"2022-08-17T15:34:52.771748Z","shell.execute_reply.started":"2022-08-17T15:34:50.263134Z","shell.execute_reply":"2022-08-17T15:34:52.770164Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 3D plots ","metadata":{}},{"cell_type":"code","source":"def plot_3d_for_patient(patient_id):    \n    num_slices = train_df.loc[train_df[\"StudyInstanceUID\"] == patient_id, \"num_slices\"].values[0]\n    print(f\"Number of slices for patient: {num_slices}\")\n    print(f\"Fracture information for patient: \")\n    print(f\"{train_df[train_df['StudyInstanceUID'] == patient_id].iloc[:, 1:-1]}\")\n    patient_dir = os.path.join(TRAIN_DIR, patient_id)\n    \n    for i in range(num_slices):\n        # dicom filenames start from 1\n        ds = pydicom.dcmread(os.path.join(patient_dir, f\"{i+1}.dcm\"))\n        if i == 0:\n            pixel_spacing = ds.PixelSpacing\n            slice_thickness = ds.SliceThickness\n            axial_aspect = pixel_spacing[1] / pixel_spacing[0]\n            sagittal_aspect = pixel_spacing[1] / slice_thickness\n            coronal_aspect = slice_thickness / pixel_spacing[0]\n            img_shape = list(ds.pixel_array.shape)\n            img_shape.append(num_slices)\n            img3d = np.zeros(img_shape)\n        img2d = rescale_img_to_hu(ds)\n        img3d[:, :, i] = img2d\n        \n    fig, axs = plt.subplots(1, 3, figsize=(24,15))\n    \n    axs[0].imshow(img3d[:, :, img_shape[2]//2], cmap=\"bone\")\n    axs[0].set_aspect(axial_aspect)\n    axs[0].axis(\"off\")\n    axs[0].set_title(\"Axial\")\n\n    axs[1].imshow(img3d[:, img_shape[1]//2, :], cmap=\"bone\")\n    axs[1].set_aspect(sagittal_aspect)\n    axs[1].axis(\"off\")\n    axs[1].set_title(\"Sagittal\")\n\n    axs[2].imshow(img3d[img_shape[0]//2, :, :].T, cmap=\"bone\")\n    axs[2].set_aspect(coronal_aspect)\n    axs[2].axis(\"off\")\n    axs[2].set_title(\"Coronal\")","metadata":{"execution":{"iopub.status.busy":"2022-08-17T15:19:02.949659Z","iopub.execute_input":"2022-08-17T15:19:02.950654Z","iopub.status.idle":"2022-08-17T15:19:02.96641Z","shell.execute_reply.started":"2022-08-17T15:19:02.950609Z","shell.execute_reply":"2022-08-17T15:19:02.964454Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# pick a patient with many fractures\ntrain_df[\"num_fractures\"] = train_df[[\"C1\", \"C2\", \"C3\", \"C4\", \"C5\", \"C6\", \"C7\"]].sum(axis=1)\ntrain_df.sort_values(by=\"num_fractures\", ascending=False)","metadata":{"execution":{"iopub.status.busy":"2022-08-17T15:40:34.378953Z","iopub.execute_input":"2022-08-17T15:40:34.379583Z","iopub.status.idle":"2022-08-17T15:40:34.410425Z","shell.execute_reply.started":"2022-08-17T15:40:34.379546Z","shell.execute_reply":"2022-08-17T15:40:34.409401Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_3d_for_patient(\"1.2.826.0.1.3680043.19381\")","metadata":{"execution":{"iopub.status.busy":"2022-08-17T15:19:09.75147Z","iopub.execute_input":"2022-08-17T15:19:09.752117Z","iopub.status.idle":"2022-08-17T15:19:17.997555Z","shell.execute_reply.started":"2022-08-17T15:19:09.751949Z","shell.execute_reply":"2022-08-17T15:19:17.996094Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Takeaways**\n* all the cervical vertebrae is visible in the middle sagittal slice\n* it might be worthwhile to plot the CT scan in the sagittal plane","metadata":{}},{"cell_type":"markdown","source":"## Sagittal plane plots","metadata":{}},{"cell_type":"code","source":"def plot_slices_sagittal_patient(patient_id, nrows, ncols, step=1):    \n    num_slices = train_df.loc[train_df[\"StudyInstanceUID\"] == patient_id, \"num_slices\"].values[0]\n    print(f\"Number of slices for patient: {num_slices}\")\n    print(f\"Fracture information for patient: \")\n    print(f\"{train_df[train_df['StudyInstanceUID'] == patient_id].iloc[:, 1:-1]}\")\n    patient_dir = os.path.join(TRAIN_DIR, patient_id)\n    \n    for i in range(num_slices):\n        # dicom filenames start from 1\n        ds = pydicom.dcmread(os.path.join(patient_dir, f\"{i+1}.dcm\"))\n        if i == 0:\n            pixel_spacing = ds.PixelSpacing\n            slice_thickness = ds.SliceThickness\n            axial_aspect = pixel_spacing[1] / pixel_spacing[0]\n            sagittal_aspect = pixel_spacing[1] / slice_thickness\n            coronal_aspect = slice_thickness / pixel_spacing[0]\n            img_shape = list(ds.pixel_array.shape)\n            img_shape.append(num_slices)\n            img3d = np.zeros(img_shape)\n        img2d = rescale_img_to_hu(ds)\n        img3d[:, :, i] = img2d\n    \n    print(f\"Shape of 3D scan: {img3d.shape}\")\n    fig, axs = plt.subplots(nrows, ncols, figsize=(24,15))\n    axs = axs.flatten()\n    \n    count = 0\n    idx = 0\n    while count < nrows*ncols:\n        axs[count].imshow(img3d[:, idx, :], cmap=\"bone\")\n        axs[count].axis(\"off\")\n        axs[count].set_aspect(sagittal_aspect)\n        count += 1\n        idx += step","metadata":{"execution":{"iopub.status.busy":"2022-08-17T15:19:17.999452Z","iopub.execute_input":"2022-08-17T15:19:17.999911Z","iopub.status.idle":"2022-08-17T15:19:18.014458Z","shell.execute_reply.started":"2022-08-17T15:19:17.999864Z","shell.execute_reply":"2022-08-17T15:19:18.012457Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_slices_sagittal_patient(\"1.2.826.0.1.3680043.19381\", 3, 5, 30)","metadata":{"execution":{"iopub.status.busy":"2022-08-17T15:19:18.017089Z","iopub.execute_input":"2022-08-17T15:19:18.017744Z","iopub.status.idle":"2022-08-17T15:19:24.121175Z","shell.execute_reply.started":"2022-08-17T15:19:18.017704Z","shell.execute_reply":"2022-08-17T15:19:24.119754Z"},"trusted":true},"execution_count":null,"outputs":[]}]}