{"cells":[{"metadata":{},"cell_type":"markdown","source":"<center><img src=\"data:image/png;base64,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\" width=\"300px\">\n</center>"},{"metadata":{},"cell_type":"markdown","source":"<font color=\"red\" size=5><center>RSNA-STR Pulmonary Embolism Detection</center></font>"},{"metadata":{},"cell_type":"markdown","source":"# Introduction \n\nIn this notebook I will dwell about DICOM files and CT Scans. Also we will visualize the tabular data using seaborn and matplotlib. We will even extract the important metadata that can be used as input to models.\n\nThe metadata will be provided as CSV. \nTo access the CSV please click this [LINK](https://www.kaggle.com/nitindatta/pulmonary-embolism-ct-data)\n\n### **What is Pulmonary Embolism?**\n* Pulmonary embolism (PE) is a blockage of an artery in the lungs by a substance that has moved from elsewhere in the body through the bloodstream (embolism). \n* Symptoms of a PE may include shortness of breath, chest pain particularly upon breathing in, and coughing up blood. \n* Most times, a pulmonary embolism is caused by blood clots that travel from the legs, or rarely, other parts of the body (deep vein thrombosis or DVT).\n\nWatch the video below to get some insights about it..\n\n<font color=\"red\" size=3>Please upvote this kernel if you like it. It motivates me to produce more quality content :)</font>"},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"from IPython.display import HTML\nHTML('<center><iframe width=\"700\" height=\"400\" src=\"https://www.youtube.com/embed/Sm7GX5vNQ0k?rel=0&amp;controls=0&amp;showinfo=0\" frameborder=\"0\" allowfullscreen></iframe></center>')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<a class=\"anchor\" id=\"toc\"></a>\n<div style=\"background: #f9f9f9 none repeat scroll 0 0;border: 1px solid #aaa;display: table;font-size: 95%;margin-bottom: 1em;padding: 20px;width: 600px;\">\n<h1>Contents</h1>\n<ul style=\"font-weight: 700;text-align: left;list-style: outside none none !important;\">\n<li style=\"list-style: outside none none !important;font-size:17px\"><a href=\"#1.1\">1 Data Preparation</a></li>\n      <ul style=\"font-weight: 700;text-align: left;list-style: outside none none !important;\">\n            <li style=\"list-style: outside none none !important;\"><a href=\"#1.1\">1.1 Importing Dependencies</a></li>\n            <li style=\"list-style: outside none none !important;\"><a href=\"#1.2\">1.2 Reading our CSV files 📁</a></li>\n            <li style=\"list-style: outside none none !important;\"><a href=\"#1.3\">1.3 Data Fields📊</a></li>\n            <li style=\"list-style: outside none none !important;\"><a href=\"#1.4\">1.4 Insights about our data</a></li>\n            <li style=\"list-style: outside none none !important;\"><a href=\"#1.5\">1.5 Any Missing Values (❔)(❔)(❔)</a></li>\n      </ul>\n<li style=\"list-style: outside none none !important;font-size:17px\"><a href=\"#2.1\">2 Diving into CT Scans</a></li>\n      <ul style=\"font-weight: 700;text-align: left;list-style: outside none none !important;\">\n            <li style=\"list-style: outside none none !important;\"><a href=\"#2.1\">2.1 Loading the scans ■■■■■■■■■■■□□□</a></li>\n            <li style=\"list-style: outside none none !important;\"><a href=\"#2.2\">2.2 Understanding more about Hounsfield Units</a></li>\n            <li style=\"list-style: outside none none !important;\"><a href=\"#2.3\">2.3 Utility Functions</a></li>\n           <li style=\"list-style: outside none none !important;\"><a href=\"#2.4\">2.4 Sorting our slices and GIF creation</a></li>\n           <li style=\"list-style: outside none none !important;\"><a href=\"#2.5\">2.5 3D Reconstruction using slices</a></li>\n            <li style=\"list-style: outside none none !important;\"><a href=\"#2.6\">2.6 Extracting DICOM data</a></li>\n      </ul>\n    \n<li style=\"list-style: outside none none !important;font-size:17px\"><a href=\"#3.1\">3 Light EDA</a></li>\n<li style=\"list-style: outside none none !important;font-size:17px\"><a href=\"#4\">4 Acknowledgements</a></li>\n      <ul style=\"font-weight: 700;text-align: left;list-style: outside none none !important;\">    \n\n</ul>\n</div>"},{"metadata":{},"cell_type":"markdown","source":"# Data Preparation\n## Importing dependencies\n<a class=\"anchor\" id=\"1.1\"></a>\n<a href=\"#toc\" class=\"btn btn-primary btn-sm\" role=\"button\" aria-pressed=\"true\" style=\"color:white\" data-toggle=\"popover\" title=\"go to Colors\">Go To Table of Contents</a>"},{"metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"trusted":true},"cell_type":"code","source":"!conda install -c conda-forge gdcm -y","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":false,"trusted":true},"cell_type":"code","source":"import numpy as np \nimport pandas as pd \nimport matplotlib.pyplot as plt\nimport seaborn as sns\n%matplotlib inline\nfrom IPython.display import HTML\n\nsns.set_style('darkgrid')\nimport pydicom\nimport scipy.ndimage\nimport gdcm\nimport imageio\nfrom IPython import display\n\n\nfrom skimage import measure \nfrom mpl_toolkits.mplot3d.art3d import Poly3DCollection\nfrom skimage.morphology import disk, opening, closing\nfrom tqdm import tqdm\n\nfrom plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplot\nimport plotly.figure_factory as ff\nfrom plotly.graph_objs import *\ninit_notebook_mode(connected=True) \nfrom PIL import Image\n\nimport warnings\nwarnings.filterwarnings(\"ignore\", category=DeprecationWarning)\nwarnings.filterwarnings(\"ignore\", category=UserWarning)\nwarnings.filterwarnings(\"ignore\", category=FutureWarning)\n\nfrom os import listdir, mkdir","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"basepath = \"../input/rsna-str-pulmonary-embolism-detection/\"\nlistdir(basepath)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":" ## Reading our CSV files 📁\n <a class=\"anchor\" id=\"1.2\"></a>\n<a href=\"#toc\" class=\"btn btn-primary btn-sm\" role=\"button\" aria-pressed=\"true\" style=\"color:white\" data-toggle=\"popover\" title=\"go to Colors\">Go To Table of Contents</a>"},{"metadata":{"trusted":true},"cell_type":"code","source":"train = pd.read_csv(basepath + \"train.csv\")\ntest = pd.read_csv(basepath + \"test.csv\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Data fields 📊\n<a class=\"anchor\" id=\"1.3\"></a>\n<a href=\"#toc\" class=\"btn btn-primary btn-sm\" role=\"button\" aria-pressed=\"true\" style=\"color:white\" data-toggle=\"popover\" title=\"go to Colors\">Go To Table of Contents</a>\n\nNOTE: You can find this on the competition page but still I am presenting it here\n\n* `StudyInstanceUID` - unique ID for each study (exam) in the data.\n* `SeriesInstanceUID` - unique ID for each series within the study.\n* `SOPInstanceUID` - unique ID for each image within the study (and data).\n* `pe_present_on_image` - image-level, notes whether any form of PE is present on the image.\n* `negative_exam_for_pe` - exam-level, whether there are any images in the study that have PE present.\n* `qa_motion` - informational, indicates whether radiologists noted an issue with motion in the study.\n* `qa_contrast` - informational, indicates whether radiologists noted an issue with contrast in the study.\n* `flow_artifact` - informational\n* `rv_lv_ratio_gte_1` - exam-level, indicates whether the RV/LV ratio present in the study is >= 1\n* `rv_lv_ratio_lt_1` - exam-level, indicates whether the RV/LV ratio present in the study is < 1\n* `leftsided_pe` - exam-level, indicates that there is PE present on the left side of the images in the study\n* `chronic_p`e - exam-level, indicates that the PE in the study is chronic\n* `true_filling_defect_not_pe` - informational, indicates a defect that is NOT PE\n* `rightsided_pe` - exam-level, indicates that there is PE present on the right side of the images in the study\n* `acute_and_chronic_pe` - exam-level, indicates that the PE present in the study is both acute AND chronic\n* `central_pe` - exam-level, indicates that there is PE present in the center of the images in the study\n* `indeterminate` -exam-level, indicates that while the study is not negative for PE, an ultimate set of exam-level labels could not be created, due to QA issues\n\n## Insights about our data\n<a class=\"anchor\" id=\"1.4\"></a>\n<a href=\"#toc\" class=\"btn btn-primary btn-sm\" role=\"button\" aria-pressed=\"true\" style=\"color:white\" data-toggle=\"popover\" title=\"go to Colors\">Go To Table of Contents</a>\n\nFew sanity checks about data such astype of each column, memory occupied etc."},{"metadata":{"trusted":true},"cell_type":"code","source":"train.shape, test.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"train.head().T","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":false},"cell_type":"code","source":"train.info()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":false},"cell_type":"code","source":"test.info()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"📌 We are dealing with approximately 240 MB of tabular data"},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"print(\"Number of unique Study instances are\", train['StudyInstanceUID'].nunique())\nprint(\"Number of unique Series instances are\", train['SeriesInstanceUID'].nunique())","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"📌 As both Study and Series are the same number we can infer that there is only one series for each study.\n\n\n## Any Missing Values (❔)(❔)(❔)\n\n<a class=\"anchor\" id=\"1.5\"></a>\n<a href=\"#toc\" class=\"btn btn-primary btn-sm\" role=\"button\" aria-pressed=\"true\" style=\"color:white\" data-toggle=\"popover\" title=\"go to Colors\">Go To Table of Contents</a>\n\nNow we will see if there are any null values or not"},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"print('Null values in train data:',train.isnull().sum().sum())\nprint('Null values in test data:',test.isnull().sum().sum())","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"📌 No missing values and clean data\n\n# Diving into CT-scans\n\n## Loading the scans ■■■■■■■■■■■□□□\n<a class=\"anchor\" id=\"2.1\"></a>\n<a href=\"#toc\" class=\"btn btn-primary btn-sm\" role=\"button\" aria-pressed=\"true\" style=\"color:white\" data-toggle=\"popover\" title=\"go to Colors\">Go To Table of Contents</a>"},{"metadata":{"trusted":true},"cell_type":"code","source":"def load_scans(dcm_path):\n    files = listdir(dcm_path)\n    f = [pydicom.dcmread(dcm_path + \"/\" + str(file)) for file in files]\n    return f","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"example = basepath + \"train/\" + train.StudyInstanceUID.values[0] +'/'+ train.SeriesInstanceUID.values[0]\nfile_names = listdir(example)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"scans = load_scans(example)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Let us take a look at an example of dicom data"},{"metadata":{"trusted":true},"cell_type":"code","source":"scans[0]","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Few details about CT Scans: \n\n* CT-scan captures information about the radiodensity of an object or tissue exposed to x-rays.A transversal slice of a scan is reconstructed after taking measurements from several different directions.\n* We use something called as  **Hounsfield Units** which is defined as *Relative quantitative measurement of radio density used by radiologists in the interpretation of computed tomography (CT) images*\n* The CT-scans are already in the HU format\n* ct-scanner yields roughly 4000 grey values that can't be captured by our eyes. So we perform something called as windowing.\n* Water has HU 0 and Air -1000\n\nIf you dont know all these details do not worry please watch the below video to understand more about CT windows, HU etc.\n\n📌 For the main content jump to the 7th minute"},{"metadata":{},"cell_type":"markdown","source":"## Understanding more about Hounsfield Units\n<a class=\"anchor\" id=\"2.2\"></a>\n<a href=\"#toc\" class=\"btn btn-primary btn-sm\" role=\"button\" aria-pressed=\"true\" style=\"color:white\" data-toggle=\"popover\" title=\"go to Colors\">Go To Table of Contents</a>\n"},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"from IPython.display import HTML\nHTML('<center><iframe width=\"700\" height=\"400\" src=\"https://www.youtube.com/embed/KZld-5W99cI?rel=0&amp;controls=0&amp;showinfo=0\" frameborder=\"0\" allowfullscreen></iframe></center>')","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(12,6))\nfor n in range(10):\n    image = scans[n].pixel_array.flatten()\n    rescaled_image = image * scans[n].RescaleSlope + scans[n].RescaleIntercept\n    sns.distplot(image.flatten());\nplt.title(\"HU unit distributions for 10 examples\");","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"📌 In the above graph we have plotted pixel distributions of 5 examples. \n\nNext we will look at pixel array distribution along with the CT scan Image"},{"metadata":{},"cell_type":"markdown","source":"## Utility Functions\n<a class=\"anchor\" id=\"2.3\"></a>\n<a href=\"#toc\" class=\"btn btn-primary btn-sm\" role=\"button\" aria-pressed=\"true\" style=\"color:white\" data-toggle=\"popover\" title=\"go to Colors\">Go To Table of Contents</a>\n"},{"metadata":{"trusted":true,"_kg_hide-input":false},"cell_type":"code","source":"def load_slice(path):\n    slices = [pydicom.read_file(path + '/' + s) for s in listdir(path)]\n    slices.sort(key = lambda x: float(x.ImagePositionPatient[2]))\n    try:\n        slice_thickness = np.abs(slices[0].ImagePositionPatient[2] - slices[1].ImagePositionPatient[2])\n    except:\n        slice_thickness = np.abs(slices[0].SliceLocation - slices[1].SliceLocation)\n        \n    for s in slices:\n        s.SliceThickness = slice_thickness\n        \n    return slices\n\ndef transform_to_hu(slices):\n    images = np.stack([file.pixel_array for file in slices])\n    images = images.astype(np.int16)\n\n    # convert ouside pixel-values to air:\n    # I'm using <= -1000 to be sure that other defaults are captured as well\n    images[images <= -1000] = 0\n    \n    # convert to HU\n    for n in range(len(slices)):\n        \n        intercept = slices[n].RescaleIntercept\n        slope = slices[n].RescaleSlope\n        \n        if slope != 1:\n            images[n] = slope * images[n].astype(np.float64)\n            images[n] = images[n].astype(np.int16)\n            \n        images[n] += np.int16(intercept)\n    \n    return np.array(images, dtype=np.int16)\n\ndef resample(image, scan, new_spacing=[1,1,1]):\n    spacing = np.array([float(scans_0[0].SliceThickness), \n                        float(scans_0[0].PixelSpacing[0]), \n                        float(scans_0[0].PixelSpacing[0])])\n\n\n    resize_factor = spacing / new_spacing\n    new_real_shape = image.shape * resize_factor\n    new_shape = np.round(new_real_shape)\n    real_resize_factor = new_shape / image.shape\n    new_spacing = spacing / real_resize_factor\n    \n    image = scipy.ndimage.interpolation.zoom(image, real_resize_factor)\n    \n    return image, new_spacing\n\ndef make_mesh(image, threshold=-300, step_size=1):\n    p = image.transpose(2,1,0)\n    verts, faces, norm, val = measure.marching_cubes_lewiner(p, threshold, step_size=step_size, allow_degenerate=True)\n    return verts, faces\n\n\ndef plt_3d(verts, faces):\n    print(\"Drawing\")\n    x,y,z = zip(*verts) \n    fig = plt.figure(figsize=(10, 10))\n    ax = fig.add_subplot(111, projection='3d')\n\n    # Fancy indexing: `verts[faces]` to generate a collection of triangles\n    mesh = Poly3DCollection(verts[faces], linewidths=0.05, alpha=1)\n    face_color = [1, 1, 0.9]\n    mesh.set_facecolor(face_color)\n    ax.add_collection3d(mesh)\n\n    ax.set_xlim(0, max(x))\n    ax.set_ylim(0, max(y))\n    ax.set_zlim(0, max(z))\n#     ax.set_axis_bgcolor((0.7, 0.7, 0.7))\n    ax.set_facecolor((0.7,0.7,0.7))\n    plt.show()\n","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"sns.set_style('white')\nhu_scans = transform_to_hu(scans)\n\nfig, ax = plt.subplots(1,2,figsize=(15,4))\n\n\nax[0].set_title(\"CT-scan in HU\")\nax[0].imshow(hu_scans[0], cmap=\"plasma\")\nax[1].set_title(\"HU values distribution\");\nsns.distplot(hu_scans[0].flatten(), ax=ax[1],color='red', kde_kws=dict(lw=2, ls=\"--\",color='blue'));\nax[1].grid(False)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"📌 From the graph we can infer that most of the area is filled with air as air has HU around -1000 and the next highest is water: HU around 0\n\n## Sorting our slices and GIF creation\n<a class=\"anchor\" id=\"2.4\"></a>\n<a href=\"#toc\" class=\"btn btn-primary btn-sm\" role=\"button\" aria-pressed=\"true\" style=\"color:white\" data-toggle=\"popover\" title=\"go to Colors\">Go To Table of Contents</a>\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"first_patient = load_slice('../input/rsna-str-pulmonary-embolism-detection/train/0003b3d648eb/d2b2960c2bbf')\nfirst_patient_pixels = transform_to_hu(first_patient)\n\ndef sample_stack(stack, rows=6, cols=6, start_with=10, show_every=5):\n    fig,ax = plt.subplots(rows,cols,figsize=[18,20])\n    for i in range(rows*cols):\n        ind = start_with + i*show_every\n        ax[int(i/rows),int(i % rows)].set_title(f'slice {ind}')\n        ax[int(i/rows),int(i % rows)].imshow(stack[ind],cmap='bone')\n        ax[int(i/rows),int(i % rows)].axis('off')\n    plt.show()\n\nsample_stack(first_patient_pixels)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"We are arranging the slices in order and skipping 5 slices at a time to look at wider variety of slices"},{"metadata":{"trusted":true},"cell_type":"code","source":"imageio.mimsave(\"/tmp/gif.gif\", first_patient_pixels, duration=0.1)\ndisplay.Image(filename=\"/tmp/gif.gif\", format='png')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## 3D Reconstruction using slices\n<a class=\"anchor\" id=\"2.5\"></a>\n<a href=\"#toc\" class=\"btn btn-primary btn-sm\" role=\"button\" aria-pressed=\"true\" style=\"color:white\" data-toggle=\"popover\" title=\"go to Colors\">Go To Table of Contents</a>\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"first_patient_scan = '../input/rsna-str-pulmonary-embolism-detection/train/0003b3d648eb/d2b2960c2bbf'\nscans_0 = load_scans(first_patient_scan)\nimgs_after_resamp, spacing = resample(first_patient_pixels, scans_0, [1,1,1])\nv, f = make_mesh(imgs_after_resamp, threshold = 350)\nplt_3d(v, f)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"im_path = []\ntrain_path = '../input/rsna-str-pulmonary-embolism-detection/train/'\nfor i in listdir(train_path): \n    for j in listdir(train_path + i):\n        x = i+'/'+j\n        im_path.append(x)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Extracting DICOM data\n<a class=\"anchor\" id=\"2.6\"></a>\n<a href=\"#toc\" class=\"btn btn-primary btn-sm\" role=\"button\" aria-pressed=\"true\" style=\"color:white\" data-toggle=\"popover\" title=\"go to Colors\">Go To Table of Contents</a>"},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"def get_window_value(feature):\n    if type(feature) == pydicom.multival.MultiValue:\n        return np.int(feature[0])\n    else:\n        return np.int(feature)\n\npixelspacing_r = []\npixelspacing_c = []\nslice_thicknesses = []\nids = []\nid_pth = []\nrow_values = []\ncolumn_values = []\nwindow_widths = []\nwindow_levels = []\nmodality = []\nkvp = []\ntable_height = []\nx_ray_tube = []\nexp = []\npos = []\ntilt = []\nbits = []\nrescale_inter = []\nrescale_slope = []\nphotometric_interpretation = []\nconvolution_kernel = [] \n\n\nfor i in im_path:\n    ids.append(i.split('/')[0]+'_'+i.split('/')[1])\n    example_dcm = listdir(train_path  + i + \"/\")[0]\n    id_pth.append(train_path + i)\n    dataset = pydicom.dcmread(train_path + i + \"/\" + example_dcm)\n    \n    window_widths.append(get_window_value(dataset.WindowWidth))\n    window_levels.append(get_window_value(dataset.WindowCenter))\n    \n    spacing = dataset.PixelSpacing\n    slice_thicknesses.append(dataset.SliceThickness)\n    \n    row_values.append(dataset.Rows)\n    column_values.append(dataset.Columns)\n    pixelspacing_r.append(spacing[0])\n    pixelspacing_c.append(spacing[1])\n    \n    modality.append(dataset.Modality)\n    kvp.append(dataset.KVP)\n    table_height.append(dataset.TableHeight)\n    x_ray_tube.append(dataset.XRayTubeCurrent)\n    exp.append(dataset.Exposure)\n    pos.append(dataset.PatientPosition)\n    tilt.append(dataset.GantryDetectorTilt)\n    bits.append(dataset.BitsAllocated)\n    rescale_inter.append(dataset.RescaleIntercept)\n    rescale_slope.append(dataset.RescaleSlope)\n    photometric_interpretation.append(dataset.PhotometricInterpretation)\n    convolution_kernel.append(dataset.ConvolutionKernel)\n    \nscan_properties = pd.DataFrame(data=ids, columns=[\"ID\"])\nscan_properties.loc[:, \"rows\"] = row_values\nscan_properties.loc[:, \"columns\"] = column_values\nscan_properties.loc[:, \"area\"] = scan_properties[\"rows\"] * scan_properties[\"columns\"]\nscan_properties.loc[:, \"pixelspacing_r\"] = pixelspacing_r\nscan_properties.loc[:, \"pixelspacing_c\"] = pixelspacing_c\nscan_properties.loc[:, \"pixelspacing_area\"] = scan_properties.pixelspacing_r * scan_properties.pixelspacing_c\nscan_properties.loc[:, \"slice_thickness\"] = slice_thicknesses\nscan_properties.loc[:, \"id_pth\"] = id_pth\nscan_properties.loc[:, \"window_width\"] = window_widths\nscan_properties.loc[:, \"window_level\"] = window_levels\nscan_properties.loc[:, \"modality\"] = modality\nscan_properties.loc[:, \"kvp\"] = kvp\nscan_properties.loc[:, \"table_height\"] = table_height\nscan_properties.loc[:, \"x_ray_tube_current\"] = x_ray_tube\nscan_properties.loc[:, \"exposure\"] = exp \nscan_properties.loc[:,\"patient_position\"] = pos\nscan_properties.loc[:,\"detector_tilt\"] = tilt\nscan_properties.loc[:,\"bits_allocated\"] = bits\nscan_properties.loc[:,\"rescale_intercept\"] = rescale_inter\nscan_properties.loc[:, \"rescale_slope\"] = rescale_slope\nscan_properties.loc[:, \"photometric_interpretation\"] = photometric_interpretation\nscan_properties.loc[:, \"convolution_kernel\"] = convolution_kernel\n\nscan_properties.head().T","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Pixelspacing\n* The pixelspacing attribute you can find in the dicom files is an important one. It tells us how much physical distance is covered by one pixel. You can see that there are only 2 values that describe the x- and y-direction in the plane of a transversal slice.\n* For one patient this pixelspacing is usually the same for all slices.\n* But between patients the pixelspacing can differ due to personal or institutional preferences of doctors and the clinic and it also depends on the scanner type. Consequently if you compare two images in the size of the lungs it does not automatically mean that the bigger one is really larger in the physical size of the organ!"},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"sns.set_style('darkgrid')\nfig, ax = plt.subplots(1,2,figsize=(20,5))\nsns.distplot(pixelspacing_r, ax=ax[0], color='green', kde_kws=dict(lw=3, ls=\"--\",color='red'))\nax[0].set_title(\"Pixel spacing distribution \\n in row direction \")\nax[0].set_ylabel(\"Counts in train\")\nax[0].set_xlabel(\"mm\")\nsns.distplot(pixelspacing_c, ax=ax[1], color=\"Blue\",kde_kws=dict(lw=3, ls=\"--\",color='red'))\nax[1].set_title(\"Pixel spacing distribution \\n in column direction\");\nax[1].set_ylabel(\"Counts in train\");\nax[1].set_xlabel(\"mm\");","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"We can see that the values really vary a lot from patient to patient! As they are given in mm and ct-scans usually cover 512 row and column values\n\n### Physical area & slice volume covered by a single ct-scan\n\nNow, we know some important quantities to compute the physical distance covered by a ct-scan!"},{"metadata":{"trusted":true},"cell_type":"code","source":"scan_properties[\"r_distance\"] = scan_properties.pixelspacing_r * scan_properties.rows\nscan_properties[\"c_distance\"] = scan_properties.pixelspacing_c * scan_properties[\"columns\"]\nscan_properties[\"area_cm2\"] = 0.1* scan_properties[\"r_distance\"] * 0.1*scan_properties[\"c_distance\"]\nscan_properties[\"slice_volume_cm3\"] = 0.1*scan_properties.slice_thickness * scan_properties.area_cm2","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"fig, ax = plt.subplots(1,2,figsize=(20,5))\nsns.distplot(scan_properties.area_cm2, ax=ax[0], color=\"Limegreen\",kde_kws=dict(lw=3, ls=\"--\",color='red'))\nsns.distplot(scan_properties.slice_volume_cm3, ax=ax[1], color=\"Mediumseagreen\",kde_kws=dict(lw=3, ls=\"--\",color='red'))\nax[0].set_title(\"CT-slice area in $cm^{2}$\")\nax[1].set_title(\"CT-slice volume in $cm^{3}$\")\nax[0].set_xlabel(\"$cm^{2}$\")\nax[1].set_xlabel(\"$cm^{3}$\");","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"scan_properties.head(3).T","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"scan_properties.describe().T","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"scan_properties.dtypes","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"scan_properties.to_csv('Pulmonary_Embolism_CT_scans_data.csv',index=False)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Light EDA\n<a class=\"anchor\" id=\"3.1\"></a>\n<a href=\"#toc\" class=\"btn btn-primary btn-sm\" role=\"button\" aria-pressed=\"true\" style=\"color:white\" data-toggle=\"popover\" title=\"go to Colors\">Go To Table of Contents</a>\n"},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"scan_cols = scan_properties.copy()\nscan_cols.drop(['rows','columns','area','detector_tilt','bits_allocated','rescale_slope'],axis=1,inplace=True)\n\ncorr = scan_cols.corr()\nmask = np.zeros_like(corr)\nmask[np.triu_indices_from(mask)] = True\nwith sns.axes_style(\"white\"):\n    f, ax = plt.subplots(figsize=(12, 12))\n    ax = sns.heatmap(corr,mask=mask,square=True,linewidths=.8,cmap=\"viridis\",annot=True)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"We can see an unusual heatmap this is because:\n\n📌 Most of our values are dervied which makes some features highly correlated"},{"metadata":{"trusted":true},"cell_type":"code","source":"y_cols = ['pixelspacing_r','pixelspacing_c','pixelspacing_area']\nx_cols = 'slice_volume_cm3'\n\nplt.figure(figsize=(18,6))\nfor i in range(len(y_cols)):\n    plt.subplot(1, 3, i+1)\n    sns.scatterplot(x=x_cols,y=y_cols[i],data=scan_cols,hue='slice_thickness',size='slice_thickness')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"📌 Slice_thickness is directly proportional to the volume"},{"metadata":{"trusted":true},"cell_type":"code","source":"cols = train.copy()\ncols.drop(['StudyInstanceUID','SeriesInstanceUID','SOPInstanceUID'],axis=1,inplace=True)\ncolumns = cols.columns","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"fig, ax = plt.subplots(7,2,figsize=(16,28))\nfor i,col in enumerate(columns): \n    plt.subplot(7,2,i+1)\n    sns.countplot(cols[col],palette='hot')   ","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"corr = cols.corr()\nmask = np.zeros_like(corr)\nmask[np.triu_indices_from(mask)] = True\nwith sns.axes_style(\"white\"):\n    f, ax = plt.subplots(figsize=(12, 12))\n    ax = sns.heatmap(corr,mask=mask,square=True,linewidths=.8,cmap=\"summer\",annot=True)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Acknowledgements\n<a class=\"anchor\" id=\"4\"></a>\n\n1. [Excellent work of Laura Fink](https://www.kaggle.com/allunia/pulmonary-fibrosis-dicom-preprocessing)\n2. [Insights used by prk007](https://www.kaggle.com/prk007/insights-from-tabular-and-image-data)\n3. [3D reconstruction by Md. Redwan Karim Sony](https://www.kaggle.com/redwankarimsony/rsna-str-3d-stacking-3d-plot-segmentation/comments)\n\n\n<a href=\"#toc\" class=\"btn btn-primary btn-sm\" role=\"button\" aria-pressed=\"true\" style=\"color:white\" data-toggle=\"popover\" title=\"go to Colors\">Back to Table of Contents</a>"},{"metadata":{},"cell_type":"markdown","source":"<font color=\"chocolate\" size=+2.5><b>My Other Kernels</b></font>\n\nClick on the button to view kernel...\n\n\n<a href=\"https://www.kaggle.com/nitindatta/fifa-in-depth-analysis-with-linear-regression\" class=\"btn btn-success\" style=\"color:white;\">FIFA In-Depth Analysis</a><br><br>\n\n<a href=\"https://www.kaggle.com/nitindatta/ensemble-learning-part-1\" class=\"btn btn-success\" style=\"color:white;\">Ensemble Learning Part 1</a><br><br>\n\n<a href=\"https://www.kaggle.com/nitindatta/ensemble-learning-part-2\" class=\"btn btn-success\" style=\"color:white;\">Ensemble Learning Part 2</a><br><br>\n\n<a href=\"https://www.kaggle.com/nitindatta/students-performance-in-exams-eda-in-depth\" class=\"btn btn-success\" style=\"color:white;\">Students performance in Exams- EDA in depth 📊📈</a><br><br>\n\n<a href=\"https://www.kaggle.com/nitindatta/pulmonary-embolism-dicom-preprocessing-eda\" class=\"btn btn-success\" style=\"color:white;\">🩺Pulmonary Embolism Dicom preprocessing & EDA🩺</a><br><br>\n\n<a href=\"https://www.kaggle.com/nitindatta/first-kaggle-submission\" class=\"btn btn-success\" style=\"color:white;\">Titanic: Machine Learning from Disaster</a><br><br>\n\n<a href=\"https://www.kaggle.com/nitindatta/graduate-admission-chances\" class=\"btn btn-success\" style=\"color:white;\">📖 Graduate Admission Chances 📕 📔</a><br><br>\n\n<a href=\"https://www.kaggle.com/nitindatta/flower-classification-augmentations-eda\" class=\"btn btn-success\" style=\"color:white;\">Flower_Classification+Augmentations+EDA</a><br><br>\n\n<a href=\"https://www.kaggle.com/nitindatta/storytelling-with-gwd-pre-print-data\" class=\"btn btn-success\" style=\"color:white;\">Storytelling with GWD pre_print data</a><br><br>\n\n\n### If these kernels impress you,give them an <font size=\"+2\" color=\"red\"><b>Upvote</b></font>.<br>\n\n<a href=\"#toc\" class=\"btn btn-primary\" role=\"button\" aria-pressed=\"true\" style=\"color:white\" data-toggle=\"popover\" title=\"go to Colors\">Go to TOP</a>"},{"metadata":{},"cell_type":"markdown","source":"<font color=\"red\" size=5><center>🚧WORK UNDER PROGRESS🚧</center></font>"}],"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":4}