{"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":"<h1 style=\"font-family: Verdana; font-size: 28px; font-style: normal; font-weight: bold; text-decoration: none; text-transform: none; letter-spacing: 3px; background-color: #606c38; color: white;\"><center><br>RSNA: Cervical Spine Fracture EDA</center></h1>\n                                                      \n<center><img src = \"https://storage.googleapis.com/kaggle-competitions/kaggle/36363/logos/header.png?t=2022-07-22-15-19-11\" width = \"1000\" height = \"400\"/></center>   \n\n<h5 style=\"text-align: center; font-family: Verdana; font-size: 12px; font-style: normal; font-weight: bold; text-decoration: None; text-transform: none; letter-spacing: 1px; color: black; background-color: #ffffff;\">CREATED BY: NGHI HUYNH</h5>\n","metadata":{}},{"cell_type":"markdown","source":"<p id=\"toc\"></p>\n<h2 class=\"list-group-item list-group-item-action active\" data-toggle=\"list\" style=\"font-family: Verdana; font-size: 24px; font-style: normal; font-weight: bold; text-decoration: none; text-transform: none; letter-spacing: 3px; background-color: #606c38; color: white;\" role=\"tab\" aria-controls=\"home\"><center><br>CONTENTS</center></h2>\n\n<h3 style=\"text-indent: 10vw; font-family: Verdana; font-size: 16px; font-style: normal; font-weight: normal; text-decoration: none; text-transform: none; letter-spacing: 2px; color: black; background-color: #ffffff;\"><a href=\"#background\">0&nbsp;&nbsp;&nbsp;&nbsp;BACKGROUND</a></h3>\n\n---\n\n<h3 style=\"text-indent: 10vw; font-family: Verdana; font-size: 16px; font-style: normal; font-weight: normal; text-decoration: none; text-transform: none; letter-spacing: 2px; color: black; background-color: #ffffff;\"><a href=\"#metadata\">1&nbsp;&nbsp;&nbsp;&nbsp;METADATA ANALYSIS</a></h3>\n\n---\n\n<h3 style=\"text-indent: 10vw; font-family: Verdana; font-size: 16px; font-style: normal; font-weight: normal; text-decoration: none; text-transform: none; letter-spacing: 2px; color: black; background-color: #ffffff;\"><a href=\"#img\">2&nbsp;&nbsp;&nbsp;&nbsp;IMAGE ANALYSIS</a></h3>\n\n---\n\n<h3 style=\"text-indent: 10vw; font-family: Verdana; font-size: 16px; font-style: normal; font-weight: normal; text-decoration: none; text-transform: none; letter-spacing: 2px; color: black; background-color: #ffffff;\"><a href=\"#conclusion\">3&nbsp;&nbsp;&nbsp;&nbsp;CONCLUSION</a></h3>\n\n---","metadata":{}},{"cell_type":"markdown","source":"<a id=\"background\"></a>\n\n<h2 style=\"font-family: Verdana; font-size: 24px; font-style: normal; font-weight: bold; text-decoration: none; text-transform: none; letter-spacing: 3px; background-color: #606c38; color: white;\" id=\"background\"><left><br>&nbsp;0. BACKGROUND <a href=\"#toc\">&#10514;</a><br></left> </h2>\n\n# Cervical Fractures (Broken Neck)\n**What are cervical fractures?**\n**[Cervical fracture](https://en.wikipedia.org/wiki/Cervical_fracture)**, commonly called a **broken neck**, is a fracture of any of the **seven** cervical vertebrae (**C1-7**) in the neck (Figure 1). Abnormal movement of neck bones or pieces of bone can cause a spinal cord injury resulting in loss of sensation, paralysis, or usually instant death. \n\n<figure>\n    <center><img src=\"https://cdcssl.ibsrv.net/cimg/www.deardoctorchiro.smb/450x450_85/509/spinal-column-and-vertebrae-1x-514509.jpg\" /></center>\n    <center><figcaption> <b>Figure 1:</b> Cerical spine anatomy</figcaption></center>\n</figure>\n\n**How do you identify them?**\nFigure 2 demonstrates [normal CT](https://radiopaedia.org/images/49855516?case_id=69091) scan vs CT scan of [cervical fractures](https://www.swjpcc.com/imaging/2014/4/2/medical-image-of-the-week-cervical-fracture-and-dislocation.html). \n<figure>\n    <center><img src=\"https://drive.google.com/uc?id=1mkTepbNoKW4SMTHkp6jK6FfN01JH7oRP\" width=\"700\" height=\"700\" /></center>\n    <center><figcaption> <b>Figure 2</b>: <cite><a href=\"https://radiopaedia.org/images/49855516?case_id=69091\"></a> Left </cite>: Normal CT neck. <cite><a href=\"https://www.swjpcc.com/imaging/2014/4/2/medical-image-of-the-week-cervical-fracture-and-dislocation.html\"></a>Right</cite>: CT scan of the neck showing C5-C6 fracture and dislocation (arrow). </figcaption></center>\n</figure>\n\n\n## Goal: \n\nIdentify **fractures** in CT scans of the cervical spine (neck) at both the level of a ***single vertebrae*** and the ***entire patient***. \n\n### Data:\n\n* train.csv: \n    * `StudyInstanceUID`: study ID. One unique study ID for each patient scan\n    * `patient_overall`: Target column at the patient level\n    * `C[1-7]`: Target column at the vertebrae level\n    \n* test.csv:\n    * `row_id`\n    * `StudyInstanceUID`\n    * `prediction_type`:  which one of the eight target columns needs a prediction in this row\n    \n* [train/test]_images/[StudyInstanceUID]/[slice_number].dcm: image data. ~ 1500 scans in the hidden test set. Each image is in the *dicom file format*. Dcm files are < **1mm** slice thickness, **axial** orientation, and **bone kernel**. Some of the dcm files are JPEG compresses. \n\n* sample_submission.csv\n    * `row_id`: the row ID. \n    * `fractured`: the target column.\n    \n* train_bounding_boxes.csv\n    * Bounding boxes for a subset of the training set -> **Visualize bounding boxes**\n* segmentations: pixel level annotations for a subset of the training set. `nifti file format`. Segmentation labels have values of 1 to 7 for C1 to C7 (seven cervical vertebrae) and 8 to 19 for T1 to T12 (twelve thoracic vertebrae), and 0 for everything else. We focus on the **cervical spine**, all scans have C1 to C7 labels but not all thoracic labels.\n\n**Note**: NIFTI files: segmentation in the **sagittal** plane, DICOM files: **axial** plane. Need to use the NIFTI header information to determine the appropriate orientation such that the DICOM images and segmentation match. \n\n## Evaluation:\n\n* Evaluation: weighted multi-label logarithmic loss.\n* Each fracture sub-type is its own row for every exam. Expected to predict a probability for a fracture at each of the seven cervical vertebrae designated as C1, C2, C3, C4, C5, C6, and C7. Also `patient_overall`: indicates that a fracture of ANY kind described before exists in the examination. The any label is weighted more highly than specific fracture level sub-types.\n    * `fractured`: indicates the probability of whether a fracture exists at the specified level. For each image ID in the test set, you must predict a probability for each of the different possible sub-types and the patient overall. \n    \n```\nrow_id,fractured\n1_C1,0\n1_C2,0\n1_C3,0\n1_C4,0.6\n1_C5,0\n1_C6,0.9\n1_C7,0.01\n1_patient_overall,0.99\n2_C1,0\netc.\n```\n\n> ###  *Note*:\n> * Train images: DICOM, axial plane\n> * Segmentation: NIFTI, sagitial plane\n\n## [Understanding anatomical planes](https://geekymedics.com/anatomical-planes/#:~:text=The%20sagittal%20plane%20is%20a,a%20midsagittal%20or%20median%20plane.):\n\nThere are three commonly used anatomical planes: **Sagittal, Coronal, and Axial**\n\n* **Sagittal**: a **longitudinal** plane, dividing the body into **right and left** parts. (**Segmentation images**)\n* Coronal: a **longitudinal** plane, dividing the body into **anterior** (front) and **posterior** (back)\n* **Axial** (tranverse) : a **horizontal** plan dividing the body into **superior** (super) and **inferior** (lower) sections. (**Training images**)\n\n<center><img src=\"https://www.researchgate.net/profile/Ralph-Mobbs/publication/354819059/figure/fig2/AS:1075981859188738@1633545474992/Planar-coordinate-system-of-the-cervical-spine-including-sagittal-coronal-and.png\" width=\"500\" height=\"100\" class=\"center\"/></center>","metadata":{}},{"cell_type":"markdown","source":"**Metadata analysis:**\n* Group per patient vs group per vertebrate\n* Scatterplot\n\n**Image analysis:**\n* Visualize based on each vertebrate and reconstruct 3D images from it.\n* Visualize bounding boxes, segmentation\n","metadata":{}},{"cell_type":"markdown","source":"## Imports","metadata":{}},{"cell_type":"code","source":"! pip install python-gdcm\n! pip install pylibjpeg pylibjpeg-libjpeg pydicom","metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2022-08-30T04:04:26.276639Z","iopub.execute_input":"2022-08-30T04:04:26.277707Z","iopub.status.idle":"2022-08-30T04:04:52.514322Z","shell.execute_reply.started":"2022-08-30T04:04:26.277594Z","shell.execute_reply":"2022-08-30T04:04:52.513001Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\n%matplotlib inline\nfrom matplotlib import animation, rc; rc('animation', html='jshtml')\nfrom matplotlib.colors import ListedColormap, LinearSegmentedColormap\nimport matplotlib.patches as patches\nfrom IPython.display import display_html\nimport seaborn as sns\nimport re\nimport os\nimport cv2\nimport gc\nfrom glob import glob\nimport pydicom\nfrom pydicom.pixel_data_handlers.util import apply_voi_lut","metadata":{"execution":{"iopub.status.busy":"2022-08-30T04:04:52.516992Z","iopub.execute_input":"2022-08-30T04:04:52.517412Z","iopub.status.idle":"2022-08-30T04:04:53.597186Z","shell.execute_reply.started":"2022-08-30T04:04:52.517369Z","shell.execute_reply":"2022-08-30T04:04:53.595999Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Helper functions","metadata":{}},{"cell_type":"code","source":"#https://www.kaggle.com/code/andradaolteanu/rsna-fracture-detection-dicom-images-explore\ndef show_values_on_bars(axs, h_v=\"v\", space=0.4):\n    '''Plots the value at the end of the a seaborn barplot.\n    axs: the ax of the plot\n    h_v: weather or not the barplot is vertical/ horizontal'''\n    \n    def _show_on_single_plot(ax):\n        if h_v == \"v\":\n            for p in ax.patches:\n                _x = p.get_x() + p.get_width() / 2\n                _y = p.get_y() + p.get_height()\n                value = int(p.get_height())\n                ax.text(_x, _y, format(value, ','), ha=\"center\") \n        elif h_v == \"h\":\n            for p in ax.patches:\n                _x = p.get_x() + p.get_width() + float(space)\n                _y = p.get_y() + p.get_height()\n                value = int(p.get_width())\n                ax.text(_x, _y, format(value, ','), ha=\"left\")\n\n    if isinstance(axs, np.ndarray):\n        for idx, ax in np.ndenumerate(axs):\n            _show_on_single_plot(ax)\n    else:\n        _show_on_single_plot(axs)\n        \ndef get_csv_info(csv, name=\"Default\"):\n    '''Prints main information for the speciffied .csv file.'''\n    \n    print(clr.S+f\"=== {name} ===\"+clr.E)\n    print(clr.S+f\"Shape:\"+clr.E, csv.shape)\n    print(clr.S+f\"Missing Values:\"+clr.E, csv.isna().sum().sum(), \"total missing datapoints.\")\n    print(clr.S+\"Columns:\"+clr.E, list(csv.columns), \"\\n\")\n    \n    #csv.head().style.set_properties(**{'border': '1.3px solid black', 'background': '#ccd5ae',\n                          #'color': '#023047'})\n    display_html(csv.head().style.set_properties(**{'border': '1.3px solid black', 'background': '#ccd5ae',\n                          'color': '#023047'}))\n    #print(\"\\n\")","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-08-30T04:04:53.598955Z","iopub.execute_input":"2022-08-30T04:04:53.599842Z","iopub.status.idle":"2022-08-30T04:04:53.61297Z","shell.execute_reply.started":"2022-08-30T04:04:53.599804Z","shell.execute_reply":"2022-08-30T04:04:53.611772Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Custom colors\nclass clr:\n    S = '\\033[1m' + '\\033[32m'\n    E = '\\033[0m'\n    \nmy_colors = [\"#606c38\", \"#283618\", \n             \"#fefae0\", \"#dda15e\", \"#bc6c25\",\n             \"#ffb4a2\", \"#e5989b\", \"#f4a261\",\"#e76f51\", \"#fec89a\", \"#ccd5ae\"]\nCMAP1 = ListedColormap(my_colors)\n\nprint(clr.S+\"Notebook Color Schemes:\"+clr.E)\nsns.palplot(sns.color_palette(my_colors))\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-08-30T04:04:53.616444Z","iopub.execute_input":"2022-08-30T04:04:53.617153Z","iopub.status.idle":"2022-08-30T04:04:53.754188Z","shell.execute_reply.started":"2022-08-30T04:04:53.617104Z","shell.execute_reply":"2022-08-30T04:04:53.75264Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id=\"metadata\"></a>\n\n<h2 style=\"font-family: Verdana; font-size: 24px; font-style: normal; font-weight: bold; text-decoration: none; text-transform: none; letter-spacing: 3px; background-color: #606c38; color: white;\" id=\"metadata\"><left><br>&nbsp;1. METADATA ANALYSIS <a href=\"#toc\">&#10514;</a><br></left> </h2>\n\n> #### *This part is inspired by an amazing notebook: [RSNA Fracture Detection: DICOM & Images Explore](https://www.kaggle.com/code/andradaolteanu/rsna-fracture-detection-dicom-images-explore) by [Andrada Olteanu](https://www.kaggle.com/andradaolteanu). I love her visualizations and clear explanation with nice color theme. So, I want to learn by playing around with my color theme and re-organizing the plots a bit.*\n\n# Cervical Fracture Analysis\n\n* train.csv: \n    * `StudyInstanceUID`: study ID. One unique study ID for each patient scan\n    * `patient_overall`: Target column at the patient level, i.e. if any of the vertebrae are fractured.\n    * `C[1-7]`: Target column at the vertebrae level","metadata":{}},{"cell_type":"code","source":"train_df = pd.read_csv('../input/rsna-2022-cervical-spine-fracture-detection/train.csv')\ntrain_df[\"total_fractures\"] = train_df.iloc[:, 2:].sum(axis=1)\ndt = pd.melt(train_df, \n             id_vars=['StudyInstanceUID', 'patient_overall','total_fractures'],\n             var_name=\"Vertebra\",\n             value_name=\"Flag\")","metadata":{"execution":{"iopub.status.busy":"2022-08-30T04:04:53.756844Z","iopub.execute_input":"2022-08-30T04:04:53.757963Z","iopub.status.idle":"2022-08-30T04:04:53.813096Z","shell.execute_reply.started":"2022-08-30T04:04:53.7579Z","shell.execute_reply":"2022-08-30T04:04:53.811426Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"get_csv_info(train_df, name=\"Train\")","metadata":{"execution":{"iopub.status.busy":"2022-08-30T04:04:53.815801Z","iopub.execute_input":"2022-08-30T04:04:53.817027Z","iopub.status.idle":"2022-08-30T04:04:53.904898Z","shell.execute_reply.started":"2022-08-30T04:04:53.816956Z","shell.execute_reply":"2022-08-30T04:04:53.903708Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Questions: \n* **At the patient overall level:**\n1. What is the proportion of patients having cervical fractures out of total number of patients?\n\n* **At the vertebrae level:**\n2. What is the proportion of patients having more than 1 cervical fracture?\n3. What is the proportion of the most dangerous cervical fractures? => Most cervical spine fractures occur predominantly at 2 levels: one third of injuries occur at the level of C2, and one half of injuries occur at the level of C6 or C7. Most fatal cervical spine injuries occur in upper cervical levels, either at craniocervical junstion C1 or C2.","metadata":{}},{"cell_type":"markdown","source":"### Visualizations","metadata":{}},{"cell_type":"code","source":"fig1 = plt.figure(figsize=(50,40)) #constrained_layout=True,\naxd = fig1.subplot_mosaic(\n    \"\"\"\n    AB\n    CC\n    \"\"\"\n)\nfig1.suptitle('Cervical Fractures Analysis', \n             weight=\"bold\", size=60)\nfont = {'family' : 'normal',\n        'weight' : 'bold',\n        'size'   : 30}\n\nplt.rc('font', **font)\n\nsns.countplot(data=train_df, x=\"patient_overall\", ax=axd['A'], palette=[my_colors[0], my_colors[5]], alpha=0.6)\n\n\nshow_values_on_bars(axd['A'], h_v=\"v\", space=0.4)\naxd['A'].set_title(\"Patient Overall Fracture Flag [frequency]\", weight=\"bold\", size=40)\naxd['A'].set_xlabel(\"Fracture Flag\", size = 30, weight=\"bold\")\naxd['A'].set_ylabel(\"\")\naxd['A'].set_yticks([])\n\nsns.countplot(data=dt, x=\"Vertebra\", hue=\"Flag\", ax=axd['B'], palette=[my_colors[0], my_colors[5]], alpha=0.6)\nshow_values_on_bars(axd['B'], h_v=\"v\", space=0.4)\naxd['B'].set_title(\"Fracture Flag on Vertebra Type [frequency]\", weight=\"bold\", size=40)\naxd['B'].set_xlabel(\"Vertebra\", size = 30, weight=\"bold\")\naxd['B'].set_ylabel(\"\")\naxd['B'].set_yticks([])\n\nsns.countplot(data=train_df, x=\"total_fractures\", ax=axd['C'], palette=my_colors, alpha=0.6)\nshow_values_on_bars(axd['C'], h_v=\"v\", space=0.4)\naxd['C'].set_title(\"Number of Bones Fractured per Patient\", weight=\"bold\", size=40)\naxd['C'].set_xlabel(\"Total Bones Fractured\", size = 30, weight=\"bold\")\naxd['C'].set_ylabel(\"\")\naxd['C'].set_yticks([])\n\n# Line    \naxd['C'].axvline(x=1.5, linestyle = '--', color=my_colors[5], lw=8)\naxd['C'].text(x=1.6, y=650, s=f\"{round((35+64+239)/961*100,2)}% cases have 1+ bones fractured at the same time.\",\n         color=my_colors[8], size=40, weight=\"bold\")\n\n# font = {'family' : 'normal',\n#         'weight' : 'bold',\n#         'size'   : 30}\n\n# plt.rc('font', **font)\n\n#sns.despine(right=True, top=True, left=False) # remove the spines from the left and right by default\n\nfig1.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-08-30T04:04:53.907324Z","iopub.execute_input":"2022-08-30T04:04:53.907705Z","iopub.status.idle":"2022-08-30T04:04:55.394772Z","shell.execute_reply.started":"2022-08-30T04:04:53.90767Z","shell.execute_reply":"2022-08-30T04:04:55.393635Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Observations:\n* Classes are balanced between patients with and without fractures. Around **47.59%** patients have at least one cervical fracture.\n* **35.17%** cases have more than 1 cervical fracture at the same time. \n* **44.85%** cases are C1-2 fractures-one of the most fatal cervical spine injuries.","metadata":{}},{"cell_type":"markdown","source":"# Bounding boxes analysis\n\n* train_bounding_boxes.csv\n    * Bounding boxes for a subset of the training set -> **Visualize bounding boxes**\n    * Number of bboxes == numer of fractures\n","metadata":{}},{"cell_type":"code","source":"train_bbox_df = pd.read_csv('../input/rsna-2022-cervical-spine-fracture-detection/train_bounding_boxes.csv')\nget_csv_info(train_bbox_df, name=\"Train BBox\") # add extra argument as needed","metadata":{"execution":{"iopub.status.busy":"2022-08-30T04:04:55.396781Z","iopub.execute_input":"2022-08-30T04:04:55.397221Z","iopub.status.idle":"2022-08-30T04:04:55.43257Z","shell.execute_reply.started":"2022-08-30T04:04:55.39718Z","shell.execute_reply":"2022-08-30T04:04:55.431296Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Questions\n\n* What is the slice numbers distribution for each study instance?\n* What is the coordinate distribution of the bounding boxes?\n* What is the density distribution of height and width of the bounding boxes?","metadata":{}},{"cell_type":"markdown","source":"## Visualization","metadata":{}},{"cell_type":"code","source":"fig2 = plt.figure(figsize=(50, 30))\n\nfig2_axes = fig2.subplot_mosaic(\n    \"\"\"\n    AA\n    BC\n    \"\"\"\n)\n\nfig2.suptitle(\"Bounding Boxes Analysis\", \n             weight=\"bold\", size=60)\n\nhist = sns.histplot(x=train_bbox_df[\"StudyInstanceUID\"].value_counts().values, ax=fig2_axes['A'], color=my_colors[1], fill=True,\n             stat='density', discrete=False, element='bars', alpha=0.3, binwidth=2\n            )\nkde =sns.kdeplot(x=train_bbox_df[\"StudyInstanceUID\"].value_counts().values, ax=fig2_axes['A'], color=my_colors[8], linewidth=6)\n\nheights = [p.get_height() for p in hist.patches]\nfor p in hist.patches:\n    if  p.get_x() >= 80: # get x or y coordinate, set condition\n        p.set(color= my_colors[7], alpha=0.6)  # set color for patches sastifying the given condition\n        \nfig2_axes['A'].set_title(\"Number of Bounding Boxes per Study Instance\", weight=\"bold\", size=50)\nfig2_axes['A'].set_xlabel(\"Number of BBoxes / Study Instance\", size = 40)\nfig2_axes['A'].set_ylabel(ylabel=\"Density\",size=40, weight=\"bold\")\n\nslices = np.sum(train_bbox_df[\"StudyInstanceUID\"].value_counts().values >= 80)\nfig2_axes['A'].axvline(x=81, color=my_colors[1], lw=4,linestyle='--',label='axvline - full height')\nfig2_axes['A'].text(x=85, y=0.015, s=f\"There are {slices} slices having 80+ bboxes/study.\", \n         color=my_colors[0], size=40)\n\ncoordinate = sns.scatterplot(x=train_bbox_df.x.values, y=train_bbox_df.y.values,ax=fig2_axes['B'],color=my_colors[1], s=80, alpha=0.6)\ncoordinate.set_title(\"Coordinate Distribution\", size=50, weight=\"bold\")\ncoordinate.set_xlabel(\"x\", size=40, weight=\"bold\")\ncoordinate.set_ylabel(\"y\", size=40, weight=\"bold\")\n\nsize = sns.kdeplot(x=train_bbox_df.height.values, y=train_bbox_df.width.values, ax=fig2_axes['C'], color=my_colors[7], fill=True,shade=True, bw_adjust=1.5)\nsize.set_title(\"Bounding Box Density\", size=50, weight=\"bold\")\nsize.set_xlabel(\"height\", size=40, weight=\"bold\")\nsize.set_ylabel(\"width\", size=40, weight=\"bold\")\n\nfont = {'family' : 'normal',\n        'size'   : 30}\n\nplt.rc('font', **font)\n#plt.savefig('bbox_analysis.png')\n\nfig2.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-08-30T04:04:55.434173Z","iopub.execute_input":"2022-08-30T04:04:55.434534Z","iopub.status.idle":"2022-08-30T04:05:01.848504Z","shell.execute_reply.started":"2022-08-30T04:04:55.434501Z","shell.execute_reply":"2022-08-30T04:05:01.847322Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Observations\n\n* There are **12** slices having more than 80 bounding boxes per study\n* Majority of coordination lies between **xy = [150-250]**\n* A large proportion of bounding boxes is **small** (around *50x50*)\n\n","metadata":{}},{"cell_type":"markdown","source":"# Test\n\n* test.csv:\n    * `row_id`\n    * `StudyInstanceUID`\n    * `prediction_type`:  which one of the eight target columns needs a prediction in this row","metadata":{}},{"cell_type":"code","source":"test_df = pd.read_csv('../input/rsna-2022-cervical-spine-fracture-detection/test.csv')\nget_csv_info(test_df, name=\"Test\")","metadata":{"execution":{"iopub.status.busy":"2022-08-30T04:05:01.851559Z","iopub.execute_input":"2022-08-30T04:05:01.851953Z","iopub.status.idle":"2022-08-30T04:05:01.874841Z","shell.execute_reply.started":"2022-08-30T04:05:01.851917Z","shell.execute_reply":"2022-08-30T04:05:01.873644Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Sample submission\n\n* sample_submission.csv\n    * `row_id`: the row ID. \n    * `fractured`: the target column.","metadata":{}},{"cell_type":"code","source":"submission = pd.read_csv('../input/rsna-2022-cervical-spine-fracture-detection/sample_submission.csv')\nget_csv_info(submission, name=\"Submission\")","metadata":{"execution":{"iopub.status.busy":"2022-08-30T04:05:01.876822Z","iopub.execute_input":"2022-08-30T04:05:01.877645Z","iopub.status.idle":"2022-08-30T04:05:01.899318Z","shell.execute_reply.started":"2022-08-30T04:05:01.877594Z","shell.execute_reply":"2022-08-30T04:05:01.898117Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id=\"img\"></a>\n\n<h2 style=\"font-family: Verdana; font-size: 24px; font-style: normal; font-weight: bold; text-decoration: none; text-transform: none; letter-spacing: 3px; background-color: #606c38; color: white;\" id=\"img\"><left><br>&nbsp;2. IMAGE ANALYSIS <a href=\"#toc\">&#10514;</a><br></left> </h2>\n\n> #### *This part is inspired by this cool notebook: [RSNA-CT gifs](https://www.kaggle.com/code/samuelcortinhas/rsna-ct-gifs) by [Samuel Cortinhas](https://www.kaggle.com/samuelcortinhas). I modified the `create_animation` to also display the bounding boxes with color.*","metadata":{}},{"cell_type":"markdown","source":"# Helper functions","metadata":{}},{"cell_type":"code","source":"def highlight(rows):\n    df = lambda x: [f'background: {my_colors[10]}' if x.name in rows\n                        else '' for i in x]\n    return df","metadata":{"execution":{"iopub.status.busy":"2022-08-30T04:05:01.900979Z","iopub.execute_input":"2022-08-30T04:05:01.901906Z","iopub.status.idle":"2022-08-30T04:05:01.908463Z","shell.execute_reply.started":"2022-08-30T04:05:01.901851Z","shell.execute_reply":"2022-08-30T04:05:01.907505Z"},"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":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-08-30T04:05:01.909724Z","iopub.execute_input":"2022-08-30T04:05:01.91036Z","iopub.status.idle":"2022-08-30T04:05:01.921478Z","shell.execute_reply.started":"2022-08-30T04:05:01.910294Z","shell.execute_reply":"2022-08-30T04:05:01.920239Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def create_animation(patient_id, drc='train_images', save=False, fps=10):\n    # Get paths\n    BASE_PATH = \"../input/rsna-2022-cervical-spine-fracture-detection/train_images\"\n    bbox_df = train_bbox_df[train_bbox_df[\"StudyInstanceUID\"]==patient_id].reset_index(drop=True)\n    png_paths = [f\"{BASE_PATH}/{patient_id}/{slice_no}.dcm\" \n                 for slice_no in bbox_df[\"slice_number\"]]\n    \n    \n    # Get images\n    files = [pydicom.dcmread(path) for path in png_paths]\n    images = [apply_voi_lut(file.pixel_array, file) for file in files]\n    \n   \n    # Stack images\n    animation_arr = np.stack(images, axis=0)\n\n    del images#, images_small\n    gc.collect()\n    \n    # Initialise plot\n    fig, axs = plt.subplots(figsize=(10,10))  # if size is too big then gif gets truncated\n    \n    # Draw BBoxes for the first frame \n    x = bbox_df.iloc[0][\"x\"]\n    y = bbox_df.iloc[0][\"y\"]\n    \n    width = bbox_df.iloc[0][\"width\"]\n    height = bbox_df.iloc[0][\"height\"]\n\n    # add bounding box\n    rect = patches.Rectangle((x, y), width, height, fill=False, edgecolor=\"red\", linewidth=1.5)\n    axs.add_patch(rect)\n    \n    im = plt.imshow(animation_arr[0], cmap='gist_gray')\n    \n    plt.axis('off')\n    plt.title(f\"Patient ID: {patient_id}\", fontweight=\"bold\",size=20)\n    \n    # Load next frame, load next bounding box\n    def animate_func(i):\n        axs.patches.pop() # remove the last patch before drawing new one\n        x_i = bbox_df.iloc[i][\"x\"]\n        y_i = bbox_df.iloc[i][\"y\"]\n\n        width_i = bbox_df.iloc[i][\"width\"]\n        height_i = bbox_df.iloc[i][\"height\"]\n\n        # add bounding box\n        rect_i = patches.Rectangle((x_i, y_i), width_i, height_i, fill=False, edgecolor=\"red\", linewidth=1.5)\n        axs.add_patch(rect_i)\n        im.set_array(animation_arr[i])\n        return [im]\n    \n    plt.close()\n    \n    # Animation function\n    anim = animation.FuncAnimation(fig, animate_func, frames = animation_arr.shape[0], interval = 1000//fps)\n    \n    # Save\n    # if save:\n    #    os.makedirs(save_dir, exist_ok=True)\n    #    anim.save(os.path.join(save_dir, f\"patient_{patient_id}.gif\"), fps=10, writer='imagemagick')\n        \n    return anim","metadata":{"execution":{"iopub.status.busy":"2022-08-30T04:05:01.922863Z","iopub.execute_input":"2022-08-30T04:05:01.923195Z","iopub.status.idle":"2022-08-30T04:05:01.93888Z","shell.execute_reply.started":"2022-08-30T04:05:01.923167Z","shell.execute_reply":"2022-08-30T04:05:01.937422Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# CT Scan Animation","metadata":{}},{"cell_type":"code","source":"patient_ids = train_bbox_df[\"StudyInstanceUID\"].value_counts().to_frame().reset_index()\npatient_ids.columns = ['patient_id', 'number_slices']\npatient_ids.sort_values(by='number_slices',ascending=True)[90:95].style.apply(highlight([137,144]), axis=1)","metadata":{"execution":{"iopub.status.busy":"2022-08-30T04:05:01.940271Z","iopub.execute_input":"2022-08-30T04:05:01.941201Z","iopub.status.idle":"2022-08-30T04:05:01.965471Z","shell.execute_reply.started":"2022-08-30T04:05:01.941167Z","shell.execute_reply":"2022-08-30T04:05:01.964566Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"create_animation(patient_ids.patient_id[137], fps=1.5)","metadata":{"execution":{"iopub.status.busy":"2022-08-30T04:05:01.967073Z","iopub.execute_input":"2022-08-30T04:05:01.967417Z","iopub.status.idle":"2022-08-30T04:05:06.888375Z","shell.execute_reply.started":"2022-08-30T04:05:01.967382Z","shell.execute_reply":"2022-08-30T04:05:06.887412Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# some imgs cant be opened using pydicom due to due to compression\n# pydicom can only handle Pixel Data that hasn't been compressed, to be fixed later \ncreate_animation(patient_ids.patient_id[144], fps=1.5)","metadata":{"execution":{"iopub.status.busy":"2022-08-30T04:05:06.889661Z","iopub.execute_input":"2022-08-30T04:05:06.890185Z","iopub.status.idle":"2022-08-30T04:05:11.512739Z","shell.execute_reply.started":"2022-08-30T04:05:06.890152Z","shell.execute_reply":"2022-08-30T04:05:11.511323Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id=\"conclusion\"></a>\n\n<h2 style=\"font-family: Verdana; font-size: 24px; font-style: normal; font-weight: bold; text-decoration: none; text-transform: none; letter-spacing: 3px; background-color: #606c38; color: white;\" id=\"conclusion\"><left><br>&nbsp;3. CONCLUSION <a href=\"#toc\">&#10514;</a><br></left> </h2>\n\n### *Cervical Fracture Analysis*\n* Classes are balanced between patients with and without fractures. \n* **35.17%** cases have more than 1 cervical fracture at the same time. \n* C1-2 are the most fatal cervical spine injuries. It contributes to **44.85%** of total cases.\n\n### *Bounding Box Analysis*\n* There are **12** slices having more than 80 bounding boxes per study. We can consider those slices as outliers. \n* Majority of coordination lies between **xy = [150-250]**\n* A large proportion of bounding boxes is **small** (around *50x50*)\n\n### *Image Analysis*\n* Some images can't be opened due to **JPEG compression** mentioned by the host. We need to have different handlers for those images","metadata":{}},{"cell_type":"markdown","source":"# References\n\n* [RSNA Fracture Detection: DICOM & Images Explore](https://www.kaggle.com/code/andradaolteanu/rsna-fracture-detection-dicom-images-explore) by [Andrada Olteanu](https://www.kaggle.com/andradaolteanu)\n* [RSNA-CT gifs](https://www.kaggle.com/code/samuelcortinhas/rsna-ct-gifs) by [Samuel Cortinhas](https://www.kaggle.com/samuelcortinhas)\n* [RSNA EDA: DICOM, segmentaitons, bboxes, 3D plot](https://www.kaggle.com/code/leventelippenszky/rsna-eda-dicom-segmentations-bboxes-3d-plot/notebook) by [_lev_lipinski](https://www.kaggle.com/leventelippenszky)","metadata":{}},{"cell_type":"markdown","source":"<div class=\"list-group\" id=\"list-tab\" role=\"tablist\">\n<h3 class=\"list-group-item list-group-item-action active\" data-toggle=\"list\" style='background:#ffb4a2; border:0; color:black' role=\"tab\" aria-controls=\"home\"><center><br>If you find this notebook useful, do give me an upvote, it motivates me a lot.<br><br> This notebook is still a work in progress. Keep checking for further developments!😊</center></h3>","metadata":{}}]}