{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Introduction to DICOM & Voxels\n![image.png](https://www.andersondiagnostics.com/wp-content/uploads/2017/09/CT-Scanner.jpg)\n\n### What is a DICOM?\n**D**igital **I**maging and **Co**mmunications in **M**edicine (DICOM) - an international standard related to the exchange, storage and communication of digital medical images. Prior to this format, there was no standardized way to transfer medical scans. So loading up a single patient's study outside the hospital, in older formats took about 10-30 minutes for a single scan! \n\nWhile DICOM 16-bit images (with values ranging from -32768..32767), other 8-bit greyscale images store values 0 - 255. These value ranges in DICOM are useful, as they correlate with the [Hounsfield Scale](https://en.wikipedia.org/wiki/Hounsfield_scale). Each voxel can store a large amount of information.\n\nNB: If you want to get right to the code & image example, click [here](#example)\n"},{"metadata":{},"cell_type":"markdown","source":"### Table of Contents\n\n* [Workflow of a Radiologist](#workflow)\n* [Why subdural hematomas are tricky](#explanation)\n* [Using the Subdural Window](#revelation)\n* [Example of subdural in the dataset](#example)"},{"metadata":{},"cell_type":"markdown","source":"<a id=\"workflow\"></a>\n# Workflow of a Radiologist\n\nThis website shows a typical workflow, thought process and professional approach that a radiologists takes, when given a task to detect any abnormalities on a CT scan of the brain. [radiopedia.org](https://radiopaedia.org/articles/ct-head-an-approach?lang=gb) There are some details that I will skip over, as they are dealing with 3D scans in real life. In our dataset, for each patient ID we have only one slice (2D) of the brain to make our diagnosis from. \n\n> To be as good as a radiologist, you have to start thinking like one.\n\nThe issue that I want to highlight is how important windows are in a **radiologist's workflow**. I see most people are only using the brain matter window, which is able to pick up most abnormalities, I will show later that this might cause one to miss some diagnoses. This is one of the tricks where my professor used to catch me with during quizes. So keep your eyes open and take notes if you wish!\n\nThere are at least **5 windows** that a radiologist goes through for each scan!\n\n1. Brain Matter window : W:80 L:40\n2. Blood/subdural window: W:130-300 L:50-100\n3. Soft tissue window: W:350–400 L:20–60\n4. Bone window: W:2800 L:600\n5. Grey-white differentiation window: W:8 L:32 or W:40 L:40\n\n------------------------------------------------------------\n\nThink of a window as an instruction to the computer to highlight only voxels which filfill a specific value. \nL = window level or center\nW = window width or range\n\n*Example*:     \nBrain Matter window  \nL = 40   \nW = 80    \nVoxels displayed range from 0 to 80   \n(  Lower limit = 40 - (80/2), upper limit = 40 + (80/2)  )    \nVoxel values outside this range will be completely black or white.      \ncredits to @amelnozieres for the correct calculation.\n\nSo you begin to see here, if it is possible to store 64k different values in each voxel - then the brain matter window only reveals a tiny fraction of this information. Converting this information to a compressed format such as .png may cause some loss of information. Similar to how we may lose some precision by converting float64 to float16 dtype."},{"metadata":{},"cell_type":"markdown","source":"<a id=\"explanation\"></a>\n# Why subdural hematomas are tricky\n\nThese critters are tricky by nature. If you check their definition, they usually are right next to the skull, longish in shape and follows the curvature of the skull.\nHonestly, I need to do a double take to spot these nasties sometimes in the tiny screens of the emergency department.\n\nExhibit 1: Arrow marking subdural hemorrhage\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F3454874%2F340f0cfb56257ff428b9e70193017731%2Fsubdural_window.png?generation=1569863200163417&alt=media)\n\nExhibit 2: Right with subdural window\n![](http://www.learningradiology.com/images/neuroimages/subduralx2.jpg)\n"},{"metadata":{},"cell_type":"markdown","source":"<a id=\"example\"></a>\n\n# Example of subdural hematoma in dataset\n\nHere I will get straight into the code, and show you an example.\nCredits to [Marco](https://www.kaggle.com/marcovasquez/basic-eda-data-visualization), [Nanashi](https://www.kaggle.com/jesucristo/rsna-introduction-eda-models) & [Richard McKinley](https://www.kaggle.com/omission/eda-view-dicom-images-with-correct-windowing) for their inspiration and awesome coding. Please go and upvote their kernels if you haven't done so yet."},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"import numpy as np\nimport pandas as pd \nimport matplotlib.pyplot as plt\nimport pydicom\nimport os\n\nprint('Loaded in libraries!')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"TRAIN_IMG_PATH = \"../input/rsna-intracranial-hemorrhage-detection/stage_1_train_images/\"\nTEST_IMG_PATH = \"../input/rsna-intracranial-hemorrhage-detection/stage_1_test_images/\"\nBASE_PATH = '/kaggle/input/rsna-intracranial-hemorrhage-detection/'\nTRAIN_DIR = 'stage_1_train_images/'\nTEST_DIR = 'stage_1_test_images/'\n\ntrain = pd.read_csv(\"../input/rsna-intracranial-hemorrhage-detection/stage_1_train.csv\")\nsub = pd.read_csv(\"../input/rsna-intracranial-hemorrhage-detection/stage_1_sample_submission.csv\")\ntrain_images = os.listdir(\"../input/rsna-intracranial-hemorrhage-detection/stage_1_train_images/\")\ntest_images = os.listdir(\"../input/rsna-intracranial-hemorrhage-detection/stage_1_test_images/\")\n\ndef window_image(img, window_center,window_width, intercept, slope, rescale=True):\n\n    img = (img*slope +intercept)\n    img_min = window_center - window_width//2\n    img_max = window_center + window_width//2\n    img[img<img_min] = img_min\n    img[img>img_max] = img_max\n    \n    if rescale:\n        # Extra rescaling to 0-1, not in the original notebook\n        img = (img - img_min) / (img_max - img_min)\n    \n    return img\n    \ndef get_first_of_dicom_field_as_int(x):\n    #get x[0] as in int is x is a 'pydicom.multival.MultiValue', otherwise get int(x)\n    if type(x) == pydicom.multival.MultiValue:\n        return int(x[0])\n    else:\n        return int(x)\n\ndef get_windowing(data):\n    dicom_fields = [data[('0028','1050')].value, #window center\n                    data[('0028','1051')].value, #window width\n                    data[('0028','1052')].value, #intercept\n                    data[('0028','1053')].value] #slope\n    return [get_first_of_dicom_field_as_int(x) for x in dicom_fields]\n\n    \n    \ndef view_images(images, title = '', aug = None):\n    width = 5\n    height = 2\n    fig, axs = plt.subplots(height, width, figsize=(15,5))\n    \n    for im in range(0, height * width):\n        data = pydicom.read_file(os.path.join(TRAIN_IMG_PATH,'ID_'+images[im]+ '.dcm'))\n        image = data.pixel_array\n        window_center , window_width, intercept, slope = get_windowing(data)\n        image_windowed = window_image(image, window_center, window_width, intercept, slope)\n\n\n        i = im // width\n        j = im % width\n        axs[i,j].imshow(image_windowed, cmap=plt.cm.bone) \n        axs[i,j].axis('off')\n        \n    plt.suptitle(title)\n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"#split out information to type and patientID\n\ntrain['type'] = train['ID'].str.split(\"_\", n = 3, expand = True)[2]\ntrain['PatientID'] = train['ID'].str.split(\"_\", n = 3, expand = True)[1]\ntrain['filename'] = train['ID'].apply(lambda st: \"ID_\" + st.split('_')[1] + \".png\")\n\nsub['filename'] = sub['ID'].apply(lambda st: \"ID_\" + st.split('_')[1] + \".png\")\nsub['type'] = sub['ID'].apply(lambda st: st.split('_')[2])\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true,"_kg_hide-output":true},"cell_type":"code","source":"view_images(train[(train['type'] == 'epidural') & (train['Label'] == 1)][:10].PatientID.values, title = 'Images with epidural')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true,"_kg_hide-output":true},"cell_type":"code","source":"train[(train['type'] == 'subdural') & (train['Label'] == 1)][:10]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"###ID_6ef1c9a94 good subdural\n\ncase = os.path.join(TRAIN_IMG_PATH,'ID_9d9cc6b01.dcm')\n\ndata = pydicom.read_file(case)\n\n#print(data)\nwindow_center , window_width, intercept, slope = get_windowing(data)\nimg = pydicom.read_file(case).pixel_array\n\n#displaying the image\n\nfig, (ax1, ax2, ax3, ax4) = plt.subplots(4,1, sharex='col', figsize=(10,24), gridspec_kw={'hspace': 0.1, 'wspace': 0})\n\nax1.set_title('Default window')\nim1 = ax1.imshow(img,  cmap=plt.cm.bone)\n\nax2.set_title('Brain window')\nimg2 = window_image(img, 40, 80, intercept, slope)\nim2 = ax2.imshow(img2, cmap=plt.cm.bone)\n\nax3.set_title('Subdural window')\nimg3 = window_image(img, 80, 200, intercept, slope)\nim3 = ax3.imshow(img3, cmap=plt.cm.bone)\nax3.annotate('', xy=(150, 380), xytext=(120, 430),\n            arrowprops=dict(facecolor='red', shrink=0.05),\n            )\nax3.annotate('', xy=(220, 430), xytext=(190, 500),\n            arrowprops=dict(facecolor='red', shrink=0.05),\n            )\n\nax4.set_title('Bone window')\nimg4 = window_image(img, 600, 2800, intercept, slope)\nim4 = plt.imshow(img4, cmap=plt.cm.bone)\n\nfor ax in fig.axes:\n    ax.axis(\"off\")\n    \nplt.show()\nprint(case)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Conclusion\n\nI hope to have shown you how important it is to incorporate subdural windows if you are a data scientist who wants to be as good as a radiologist. The evidence is as above, it is for you to examine and do drop me questions if you have in the chat below.\n\nI hope that this has been of value to you on Kaggle. Perhaps this may be the final bit to tweak your model, or adds a boost to your LB score. \nThis is my medical knowledge that is passed down to you, this is a way for me to give back to this awesome community from which I have learnt so much Python and coding from. \nPlease upvote this kernel if you have found it helpful!"},{"metadata":{},"cell_type":"markdown","source":"Credits and References\n\nKuzmak, P. M., Dayhoff, R. E., Gavrilov, S., Cebelinski, G., Shovestul, M. L., & Casertano, A. (2012). Streamlining importation of outside prior DICOM studies into an imaging system. Journal of digital imaging, 25(1), 70–77. doi:10.1007/s10278-011-9406-x\n\nHeit, J. J., Iv, M., & Wintermark, M. (2017). Imaging of Intracranial Hemorrhage. Journal of stroke, 19(1), 11–27. doi:10.5853/jos.2016.00563\n\nDr Daniel J Bell and Dr Henry Knipe et al. Subdural window. Radiopedia.org\n\nhttps://www.kaggle.com/omission/eda-view-dicom-images-with-correct-windowing\n\nhttps://gist.github.com/lebedov/e81bd36f66ea1ab60a1ce890b07a6229"},{"metadata":{},"cell_type":"markdown","source":"A side note about bone windows: useful to detect any bone fractures, which increases the probability of any hemorrhage in the brain.\nI'm not sure how to code this into the algorithm, but I hope someone can enlighten me on this."}],"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":4,"nbformat_minor":1}