{"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":"### What is the competition?\n\nThis competition is about identifying and localizing COVID-19 abnormalities on chest radiographs. We need to categorize a given chest radiograph image into 4 different classes namely;\n\n* Negative for Pneumonia\n* Typical Appearance \n* Indeterminate Appearance\n* Atypical Appearance\n\nAlogn with that we need to predicta bounding box that describes the abnormalities. Hence this is a This is an object detection/localization and classification problem. The train and test images given in this competition are in DICOM format. \n\n### What is DICOM?\n\nDICOM® — [Digital Imaging and Communications in Medicine](https://www.dicomstandard.org) — is the ISO recognized international standard for medical images and related information. It defines the formats for medical images that can be exchanged with the data and quality necessary for clinical use.\n\n### What is Object Detection?\nA typical usage of convolutional neural network is to classify an image into respective classes. For example Dog vs Cat or Classifying the handwritten digits like the MNIST dataset. However, Object detection is about identifying where a particular object(s) is in the given image and to classify it. Object localization is to define a bounding box (the location) of the classified object within the image. An example is given below. \n\n![YOLO-Object-Detection](https://user-images.githubusercontent.com/48846576/119601441-cca11500-bdae-11eb-8711-8e0b2683dd19.png)\n <div align='center'>Source: You Only Look Once: Unified, Real-Time Object Detection <a href=\"https://pjreddie.com/darknet/yolo/\">https://pjreddie.com/darknet/yolo/</a></div>\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_kg_hide-input":false}},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\n\nimport plotly.graph_objects as go\nfrom plotly.offline import iplot, init_notebook_mode\ninit_notebook_mode(connected=True)\nimport seaborn as sns\nimport matplotlib.pyplot as plt\nfrom plotly.offline import iplot, init_notebook_mode\ninit_notebook_mode(connected=True)\nimport plotly_express as px\nimport plotly.graph_objects as go\nfrom plotly.subplots import make_subplots\nfrom plotly.offline import init_notebook_mode\nimport plotly.io as pio\nfrom plotly.subplots import make_subplots\n# setting default template to plotly_white for all visualizations\npio.templates.default = \"plotly_white\"\n%matplotlib inline\nimport gc\n\nfrom colorama import Fore, Back, Style\n\ny_ = Fore.YELLOW\nr_ = Fore.RED\ng_ = Fore.GREEN\nb_ = Fore.BLUE\nm_ = Fore.MAGENTA\nc_ = Fore.CYAN\nres = Style.RESET_ALL\n\nimport warnings\nwarnings.filterwarnings('ignore')","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-06-02T02:42:51.26475Z","iopub.execute_input":"2021-06-02T02:42:51.265252Z","iopub.status.idle":"2021-06-02T02:42:53.889762Z","shell.execute_reply.started":"2021-06-02T02:42:51.265168Z","shell.execute_reply":"2021-06-02T02:42:53.888972Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install python-gdcm","metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2021-06-02T02:42:53.892518Z","iopub.execute_input":"2021-06-02T02:42:53.89274Z","iopub.status.idle":"2021-06-02T02:43:02.817984Z","shell.execute_reply.started":"2021-06-02T02:42:53.892718Z","shell.execute_reply":"2021-06-02T02:43:02.817104Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style=\"background-color:#fdb913; font-size:120%;  font-family:sans-serif; text-align:center\"><b>Load and Explore Data</b></div>\n","metadata":{}},{"cell_type":"code","source":"PATH = '/kaggle/input/siim-covid19-detection/'\nsubmission = pd.read_csv('/kaggle/input/siim-covid19-detection/sample_submission.csv', index_col=None)\nimage_df = pd.read_csv('/kaggle/input/siim-covid19-detection/train_image_level.csv', index_col=None)\nstudy_df = pd.read_csv('/kaggle/input/siim-covid19-detection/train_study_level.csv', index_col=None)\npd.set_option('display.max_columns', None)  \npd.set_option('display.max_colwidth', None)\nprint(f\"{y_}Train image level csv shape : {image_df.shape}{res}\\n{g_}Train study level csv shape : {study_df.shape}{res}\")","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-06-02T02:43:02.819304Z","iopub.execute_input":"2021-06-02T02:43:02.819521Z","iopub.status.idle":"2021-06-02T02:43:02.888719Z","shell.execute_reply.started":"2021-06-02T02:43:02.819497Z","shell.execute_reply":"2021-06-02T02:43:02.888006Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nall_files = []\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        all_files.append(os.path.join(dirname, filename))","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-06-02T02:43:02.889921Z","iopub.execute_input":"2021-06-02T02:43:02.890275Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"study_df","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"image_df","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"study_grp = pd.melt(study_df, id_vars=list(study_df.columns)[:1], value_vars=list(study_df.columns)[1:],\n             var_name='label', value_name='value')\nstudy_grp = study_grp.loc[study_grp['value']!=0]\ncolors = {'Typical Appearance' : '#DCD427',\n'Negative for Pneumonia' : '#0092CC',\n'Indeterminate Appearance' : '#CC3333',\n#'Atypical Appearance' : '#779933',\n          'Atypical Appearance' : '#E6E6E6'\n         }\n\nstudy_grp = study_grp.groupby('label').sum().sort_values('value',ascending=False).reset_index()\nstudy_grp['color'] = study_grp['label'].apply(lambda x: colors[x])\nstudy_grp","metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def plot_study_label(df):\n    pio.templates.default = \"plotly_dark\"\n    fig = px.bar(df, x='label', y='value',\n             hover_data=['label', 'value'], color='label',\n             #labels={column: label},\n             color_discrete_map=colors,\n             text='value')\n    fig.update_layout(xaxis={'categoryorder':'array', 'categoryarray': df['label'],\n                             'title' : None, \n                             'showgrid':False},\n                      yaxis={'showgrid':False,\n                            'title' : 'Count'},\n                      showlegend=False,\n                     title = 'Study samples in train data')\n    fig.update_traces(textfont_size=16)\n    fig.show()\n","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_study_label(study_grp)","metadata":{"execution":{"iopub.status.idle":"2021-06-02T02:43:28.257013Z","shell.execute_reply.started":"2021-06-02T02:43:28.004817Z","shell.execute_reply":"2021-06-02T02:43:28.256033Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"study_grp['pct'] = round((study_grp['value'] / study_grp['value'].sum())*100,2)\n\nfig = go.Figure(data=[go.Pie(labels=study_grp['label'],\n                             values=study_grp['pct'],\n                             hole=.3,\n                             pull=[0.1, 0.1, 0.1, 0.1]\n                            )\n                     ]\n               )\nfig.update_traces(hoverinfo='label+percent', textinfo='percent', textfont_size=16,\n                  marker=dict(colors=study_grp['color'], line=dict(color='#000000', width=2))\n                 )\nfig.update_layout(title={'text': \"% of labels in training data\",\n        'y':0.9,\n        'x':0.45,\n        'xanchor': 'center',\n        'yanchor': 'top'})\nfig.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-06-02T02:43:28.257943Z","iopub.execute_input":"2021-06-02T02:43:28.258167Z","iopub.status.idle":"2021-06-02T02:43:28.307997Z","shell.execute_reply.started":"2021-06-02T02:43:28.258146Z","shell.execute_reply":"2021-06-02T02:43:28.306984Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style=\"background-color:#fdb913; font-size:120%;  font-family:sans-serif; text-align:center\"><b>DICOM Image</b></div>\n","metadata":{}},{"cell_type":"markdown","source":"### Overview \nDICOM - Digital Imaging and Communication in Medicine is a standard format for encoding and transmitting medical images. This format stores image metadata like patient information, image acquistion parameters, image size, pixel size, etc along with the actual image. The image metadata is stored in the DICOM header. The image pixel data may be compressed using various techniques like JPEG, lossless JPEG, run length encoding (RLE), etc. Let's load a sample image to look at its header (metadata) and the actual pixel_array.\n\n### Bit-Depth\n\nThe pixel range of an image format is determined by its bit-depth. The range is $ [0, 2^{bitdepth} -1] $. For example, an 8-bit image will have a range of $[0, 2^{8} -1] = [0, 255]$. Most of the common photographic formats such as JPEG, PNG, etc use 8 bits for storage and only have positive values. A JPEG image containing 3 channels (RGB) will have a bit-depth of 8 for each channel hence a total bit-depth of 24.\n\nHowever, medical images use a higher bit-depth since higher accuracy is needed. For example the sample image metadata shown below uses ((0028, 0100) Bits Allocated field) uses 16 bits. Hence the range of pixel values for a 16 bit image is $[0, 65535] $ for a total of $2^{16} = 65536$ values. \n","metadata":{}},{"cell_type":"code","source":"from pydicom import dcmread, read_file\nfrom pydicom.data import get_testdata_file\nfile_path = PATH+\"train/00086460a852/9e8302230c91/65761e66de9f.dcm\"\ndicom = read_file(file_path, stop_before_pixels=False)","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-06-02T02:43:28.309245Z","iopub.execute_input":"2021-06-02T02:43:28.309484Z","iopub.status.idle":"2021-06-02T02:43:28.976213Z","shell.execute_reply.started":"2021-06-02T02:43:28.309463Z","shell.execute_reply":"2021-06-02T02:43:28.975036Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"dicom","metadata":{"execution":{"iopub.status.busy":"2021-06-02T02:43:28.977363Z","iopub.execute_input":"2021-06-02T02:43:28.977567Z","iopub.status.idle":"2021-06-02T02:43:28.983906Z","shell.execute_reply.started":"2021-06-02T02:43:28.977546Z","shell.execute_reply":"2021-06-02T02:43:28.983475Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"img=dicom.pixel_array\ntype(img), img.shape","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-06-02T02:43:28.984857Z","iopub.execute_input":"2021-06-02T02:43:28.98511Z","iopub.status.idle":"2021-06-02T02:43:29.001671Z","shell.execute_reply.started":"2021-06-02T02:43:28.98509Z","shell.execute_reply":"2021-06-02T02:43:29.001051Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"box = image_df.loc[image_df['id']=='65761e66de9f_image'].reset_index(drop=True)\nfrom ast import literal_eval\n\nimport matplotlib.patches as patches\n# Create figure and axes\nfig, ax = plt.subplots(figsize=(10, 8))\nax.imshow(img, cmap=\"gray\")\n# Create a Rectangle patch\nrect1 = patches.Rectangle((720.65215, 636.51048), 332.19348, 648.12561, linewidth=1.5, edgecolor='r', facecolor='none')\nrect2 = patches.Rectangle((2044.77989, 847.90622), 329.87049, 576.11169, linewidth=1.5, edgecolor='r', facecolor='none')\n# Add the patch to the Axes\nax.add_patch(rect1)\nax.add_patch(rect2)\nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-06-02T02:43:29.002518Z","iopub.execute_input":"2021-06-02T02:43:29.002736Z","iopub.status.idle":"2021-06-02T02:43:29.697066Z","shell.execute_reply.started":"2021-06-02T02:43:29.002713Z","shell.execute_reply":"2021-06-02T02:43:29.696156Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Let's display sample images..","metadata":{}},{"cell_type":"markdown","source":"<div style=\"background-color:#fdb913; font-size:120%;  font-family:sans-serif; text-align:center\"><b>Display Samples</b></div>\n","metadata":{}},{"cell_type":"code","source":"from ast import literal_eval\ndef get_samples(num):\n    study_df_grp = pd.melt(study_df, id_vars=list(study_df.columns)[:1], value_vars=list(study_df.columns)[1:],\n             var_name='label', value_name='value')\n    study_df_grp = study_df_grp.loc[study_df_grp['value']!=0].reset_index(drop=True)\n    labels = list(study_df_grp['label'].unique())\n    study_samples = {}\n    for label in labels:\n        study_ids = study_df_grp.loc[study_df_grp['label'] == label].sample(num)['id'].tolist() #Get num sample rows from the datafame\n        samples = []\n        for study_id in study_ids:\n            image = {}\n            study_instance_id = study_id.split('_')[0]\n            image_id = image_df.loc[image_df['StudyInstanceUID']==study_instance_id]['id'].values[0].split('_')[0] #Get the image matching study id\n            file_name = [string for string in all_files if image_id in string]\n            image['study_id'] = study_instance_id\n            image['dicom_file'] = file_name[0]\n            #Get the bounding boxes\n            box = None\n            try:\n                box = literal_eval(image_df.loc[image_df['StudyInstanceUID']==study_instance_id]['boxes'].values[0])\n            except ValueError:\n                pass\n            image['boxes'] = box\n            samples.append(image)\n        study_samples[label] = samples\n    return study_samples\n\nsamples = get_samples(6)\n\ndef display_all_class_samples():\n    ''' Input : List of samples \n    '''\n    all_class_samples = []\n    for key in samples:\n        sample_dict = samples[key][0]\n        sample_dict['class'] = key\n        all_class_samples.append(sample_dict)\n    fig1, ax1 = plt.subplots(1,4, figsize=(18, 5), facecolor='w', edgecolor='b')\n    fig1.subplots_adjust(hspace =.3, wspace=0.3)\n    axs = ax1.ravel()\n    for item, ax in zip(all_class_samples, axs):\n        dicom = read_file(item['dicom_file'], stop_before_pixels=False)\n        img = dicom.pixel_array\n        ax.imshow(img, cmap=\"gray\")\n        if 'boxes' in item and item['boxes'] is not None:\n            for box in item['boxes']:             \n                rect = patches.Rectangle((box['x'], box['y']), box['width'], box['height'], linewidth=1.5, edgecolor='r', facecolor='none')\n                ax.add_patch(rect)\n        ax.set_title('{}'.format(item['class']),fontsize = 18)    \n    plt.tight_layout(pad=3.0)\n    plt.subplots_adjust(top=0.91)\n    plt.suptitle('Samples across all classes',fontsize = 20)\n    plt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-06-02T02:43:29.698113Z","iopub.execute_input":"2021-06-02T02:43:29.698351Z","iopub.status.idle":"2021-06-02T02:43:29.782045Z","shell.execute_reply.started":"2021-06-02T02:43:29.698324Z","shell.execute_reply":"2021-06-02T02:43:29.78103Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"display_all_class_samples()","metadata":{"execution":{"iopub.status.busy":"2021-06-02T02:43:29.78318Z","iopub.execute_input":"2021-06-02T02:43:29.783469Z","iopub.status.idle":"2021-06-02T02:43:35.926575Z","shell.execute_reply.started":"2021-06-02T02:43:29.783444Z","shell.execute_reply":"2021-06-02T02:43:35.925993Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def display_samples(samples, title, draw_boxes=False):\n    ''' Input : List of samples \n    '''\n    fig1, ax1 = plt.subplots(2,3, figsize=(18, 12), facecolor='w', edgecolor='b')\n    fig1.subplots_adjust(hspace =.3, wspace=0.3)\n    axs = ax1.ravel()\n    for item, ax in zip(samples, axs):\n        dicom = read_file(item['dicom_file'], stop_before_pixels=False)\n        img = dicom.pixel_array\n        ax.imshow(img, cmap=\"gray\")\n        if draw_boxes == True and item['boxes'] is not None:\n            for box in item['boxes']:             \n                rect = patches.Rectangle((box['x'], box['y']), box['width'], box['height'], linewidth=1.5, edgecolor='r', facecolor='none')\n                ax.add_patch(rect)\n        ax.set_title('Study : {}'.format(item['study_id']),fontsize = 18)\n        \n    plt.tight_layout(pad=3.0)\n    plt.subplots_adjust(top=0.91)\n    plt.suptitle(title,fontsize = 20)\n    plt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-06-02T02:43:35.927517Z","iopub.execute_input":"2021-06-02T02:43:35.927902Z","iopub.status.idle":"2021-06-02T02:43:35.935241Z","shell.execute_reply.started":"2021-06-02T02:43:35.927868Z","shell.execute_reply":"2021-06-02T02:43:35.934366Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style=\"background-color:#fdb913; font-size:120%;  font-family:sans-serif; text-align:center\"><b>Negative for Pneumonia</b></div>\n","metadata":{}},{"cell_type":"code","source":"display_samples(samples['Negative for Pneumonia'],'Negative for Pneumonia')","metadata":{"execution":{"iopub.status.busy":"2021-06-02T02:43:35.936388Z","iopub.execute_input":"2021-06-02T02:43:35.936721Z","iopub.status.idle":"2021-06-02T02:43:43.127104Z","shell.execute_reply.started":"2021-06-02T02:43:35.936634Z","shell.execute_reply":"2021-06-02T02:43:43.12604Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def display_histogram(samples, title):\n    ''' Input : List of samples \n    '''\n    fig1, ax1 = plt.subplots(2,3, figsize=(18, 12), facecolor='w', edgecolor='b')\n    fig1.subplots_adjust(hspace =.3, wspace=0.3)\n    axs = ax1.ravel()\n    for item, ax in zip(samples, axs):\n        dicom = read_file(item['dicom_file'], stop_before_pixels=False)\n        img = dicom.pixel_array\n        sub_plot = sns.histplot(img.flatten(), ax=ax)\n        ax.set_title('Study : {}'.format(item['study_id']),fontsize = 18)\n        \n    plt.tight_layout(pad=3.0)\n    plt.subplots_adjust(top=0.91)\n    plt.suptitle('Image Histogram - {}'.format(title),fontsize = 20)\n    plt.show()\n","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-06-02T02:43:43.128713Z","iopub.execute_input":"2021-06-02T02:43:43.129059Z","iopub.status.idle":"2021-06-02T02:43:43.137106Z","shell.execute_reply.started":"2021-06-02T02:43:43.129025Z","shell.execute_reply":"2021-06-02T02:43:43.135837Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"display_histogram(samples['Negative for Pneumonia'],'Negative for Pneumonia')","metadata":{"execution":{"iopub.status.busy":"2021-06-02T02:43:43.138641Z","iopub.execute_input":"2021-06-02T02:43:43.139014Z","iopub.status.idle":"2021-06-02T02:44:14.027616Z","shell.execute_reply.started":"2021-06-02T02:43:43.13898Z","shell.execute_reply":"2021-06-02T02:44:14.026854Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style=\"background-color:#fdb913; font-size:120%;  font-family:sans-serif; text-align:center\"><b>Typical Appearance</b></div>\n","metadata":{}},{"cell_type":"code","source":"display_samples(samples['Typical Appearance'],'Typical Appearance', draw_boxes=True)","metadata":{"execution":{"iopub.status.busy":"2021-06-02T02:44:14.028506Z","iopub.execute_input":"2021-06-02T02:44:14.028735Z","iopub.status.idle":"2021-06-02T02:44:23.594538Z","shell.execute_reply.started":"2021-06-02T02:44:14.02871Z","shell.execute_reply":"2021-06-02T02:44:23.593499Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"display_histogram(samples['Typical Appearance'],'Typical Appearance')","metadata":{"execution":{"iopub.status.busy":"2021-06-02T02:44:23.595673Z","iopub.execute_input":"2021-06-02T02:44:23.595915Z","iopub.status.idle":"2021-06-02T02:45:22.896431Z","shell.execute_reply.started":"2021-06-02T02:44:23.595891Z","shell.execute_reply":"2021-06-02T02:45:22.895495Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style=\"background-color:#fdb913; font-size:120%;  font-family:sans-serif; text-align:center\"><b>Indeterminate Appearance</b></div>\n","metadata":{}},{"cell_type":"code","source":"display_samples(samples['Indeterminate Appearance'],'Indeterminate Appearance', draw_boxes=True)","metadata":{"execution":{"iopub.status.busy":"2021-06-02T02:45:22.899526Z","iopub.execute_input":"2021-06-02T02:45:22.899732Z","iopub.status.idle":"2021-06-02T02:45:30.24766Z","shell.execute_reply.started":"2021-06-02T02:45:22.89971Z","shell.execute_reply":"2021-06-02T02:45:30.246819Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"display_histogram(samples['Indeterminate Appearance'],'Indeterminate Appearance')","metadata":{"execution":{"iopub.status.busy":"2021-06-02T02:45:30.2496Z","iopub.execute_input":"2021-06-02T02:45:30.249864Z","iopub.status.idle":"2021-06-02T02:46:03.505354Z","shell.execute_reply.started":"2021-06-02T02:45:30.249838Z","shell.execute_reply":"2021-06-02T02:46:03.504612Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style=\"background-color:#fdb913; font-size:120%;  font-family:sans-serif; text-align:center\"><b>Atypical Appearance</b></div>\n","metadata":{}},{"cell_type":"code","source":"display_samples(samples['Atypical Appearance'],'Atypical Appearance', draw_boxes=True)","metadata":{"execution":{"iopub.status.busy":"2021-06-02T02:46:03.506251Z","iopub.execute_input":"2021-06-02T02:46:03.506468Z","iopub.status.idle":"2021-06-02T02:46:10.604918Z","shell.execute_reply.started":"2021-06-02T02:46:03.506442Z","shell.execute_reply":"2021-06-02T02:46:10.604179Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"display_histogram(samples['Atypical Appearance'],'Atypical Appearance')","metadata":{"execution":{"iopub.status.busy":"2021-06-02T02:46:10.605735Z","iopub.execute_input":"2021-06-02T02:46:10.605965Z","iopub.status.idle":"2021-06-02T02:46:47.624651Z","shell.execute_reply.started":"2021-06-02T02:46:10.605925Z","shell.execute_reply":"2021-06-02T02:46:47.623875Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style=\"background-color:#fdb913; font-size:120%;  font-family:sans-serif; text-align:center\"><b>Extract Metadata from DICOM Files</b></div>\n","metadata":{}},{"cell_type":"code","source":"def get_files(file_format):\n    files=[]\n    train_files = []\n    for file in all_files:\n        if file_format in file:\n            files.append(file)\n    return files\ntrain_files = get_files('/train/')\ntest_files = get_files('/test/')","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-06-02T02:46:47.625829Z","iopub.execute_input":"2021-06-02T02:46:47.626138Z","iopub.status.idle":"2021-06-02T02:46:47.632365Z","shell.execute_reply.started":"2021-06-02T02:46:47.626108Z","shell.execute_reply":"2021-06-02T02:46:47.631229Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from pydicom.tag import Tag\nfrom tqdm import tqdm\npvt_creator1 = Tag(0x2001, 0x10) #Private Creator 1\npvt_creator2 = Tag(0x0903, 0x10) #Private Creator 1\n\ncolumns = [ 'StudyID',\n 'StudyInstanceUID',\n 'PatientSex', \n 'BitsAllocated',\n 'BitsStored',\n 'Columns',\n 'Rows',\n 'BodyPartExamined', \n 'HighBit', \n 'ImageType',\n 'ImagerPixelSpacing',\n 'InstanceNumber',\n 'Modality',\n 'PatientID',\n 'PatientName',\n 'AccessionNumber',\n 'DeidentificationMethod',\n #'DeidentificationMethodCodeSequence',\n 'PhotometricInterpretation',\n 'PixelRepresentation',\n 'SOPClassUID',\n 'SOPInstanceUID',\n 'SamplesPerPixel',\n 'SeriesInstanceUID',\n 'SeriesNumber',\n 'SpecificCharacterSet',\n 'StudyDate',\n 'StudyTime',\n 'PrivateCreator1',\n 'PrivateCreator2']\n\ndef extract_metadata(columns, files):\n    df = pd.DataFrame(columns=columns)\n    for num, file in tqdm(enumerate(files)):\n        row = {}\n        dicom_img = read_file(file, stop_before_pixels=True)\n        for col in columns:\n            if col not in ['PrivateCreator1', 'PrivateCreator2']:\n                row[col] = dicom_img[col].value\n        try:        \n            row['PrivateCreator1'] = dicom_img.get_item(pvt_creator1).value\n            row['PrivateCreator2'] = dicom_img.get_item(pvt_creator2).value    \n        except AttributeError:\n            pass\n        df = df.append(row,ignore_index=True)\n    return df","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-06-02T02:46:47.633565Z","iopub.execute_input":"2021-06-02T02:46:47.633863Z","iopub.status.idle":"2021-06-02T02:46:47.651609Z","shell.execute_reply.started":"2021-06-02T02:46:47.63383Z","shell.execute_reply":"2021-06-02T02:46:47.650781Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df = extract_metadata(columns, train_files)","metadata":{"execution":{"iopub.status.busy":"2021-06-02T02:46:47.652806Z","iopub.execute_input":"2021-06-02T02:46:47.653107Z","iopub.status.idle":"2021-06-02T02:50:07.315174Z","shell.execute_reply.started":"2021-06-02T02:46:47.653077Z","shell.execute_reply":"2021-06-02T02:50:07.314601Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_df = extract_metadata(columns, test_files)","metadata":{"execution":{"iopub.status.busy":"2021-06-02T02:50:07.316386Z","iopub.execute_input":"2021-06-02T02:50:07.316703Z","iopub.status.idle":"2021-06-02T02:50:42.911271Z","shell.execute_reply.started":"2021-06-02T02:50:07.316669Z","shell.execute_reply":"2021-06-02T02:50:42.910321Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df['Rows'] = train_df['Rows'].astype(int)\ntrain_df['Columns'] = train_df['Columns'].astype(int)\ntest_df['Rows'] = test_df['Rows'].astype(int)\ntest_df['Columns'] = test_df['Columns'].astype(int)\ntrain_df.to_csv('train_imgs_meta.csv', index=None)\ntest_df.to_csv('test_imgs_meta.csv', index=None)","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-06-02T02:50:42.912348Z","iopub.execute_input":"2021-06-02T02:50:42.912556Z","iopub.status.idle":"2021-06-02T02:50:43.084904Z","shell.execute_reply.started":"2021-06-02T02:50:42.912533Z","shell.execute_reply":"2021-06-02T02:50:43.08389Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Metadata of train images","metadata":{}},{"cell_type":"code","source":"train_df","metadata":{"execution":{"iopub.status.busy":"2021-06-02T02:50:43.086189Z","iopub.execute_input":"2021-06-02T02:50:43.086416Z","iopub.status.idle":"2021-06-02T02:50:43.139411Z","shell.execute_reply.started":"2021-06-02T02:50:43.086393Z","shell.execute_reply":"2021-06-02T02:50:43.138361Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df['PatientSex'].value_counts().reset_index()\\\n    .style.background_gradient(subset=['PatientSex'], cmap='winter_r')\\","metadata":{"execution":{"iopub.status.busy":"2021-06-02T02:50:43.140518Z","iopub.execute_input":"2021-06-02T02:50:43.140718Z","iopub.status.idle":"2021-06-02T02:50:43.19247Z","shell.execute_reply.started":"2021-06-02T02:50:43.140696Z","shell.execute_reply":"2021-06-02T02:50:43.191193Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df['BodyPartExamined'].value_counts().reset_index()\\\n    .style.background_gradient(subset=['BodyPartExamined'], cmap='nipy_spectral_r')\\","metadata":{"execution":{"iopub.status.busy":"2021-06-02T02:50:43.194154Z","iopub.execute_input":"2021-06-02T02:50:43.194434Z","iopub.status.idle":"2021-06-02T02:50:43.214758Z","shell.execute_reply.started":"2021-06-02T02:50:43.194406Z","shell.execute_reply":"2021-06-02T02:50:43.214064Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df['BitsStored'] = train_df['BitsStored'].astype(int)\ndef combine_image_size(row):\n    return str(row['Rows']) + ',' + str(row['Columns'])\ntrain_df['ImageSize'] = train_df.apply(lambda x: combine_image_size(x), axis=1)","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-06-02T02:50:43.217011Z","iopub.execute_input":"2021-06-02T02:50:43.217408Z","iopub.status.idle":"2021-06-02T02:50:43.322848Z","shell.execute_reply.started":"2021-06-02T02:50:43.217372Z","shell.execute_reply":"2021-06-02T02:50:43.321755Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig = go.Figure(go.Scattergl(\n    x=train_df['Rows'], y=train_df['Columns'],\n    name='Image Size',\n    mode='markers',  \n    marker=dict(\n        color='#0092CC',\n    )\n))\nfig.update_layout(xaxis={'title' : 'Rows', \n                             'showgrid':False},\n                      yaxis={'showgrid':False,\n                            'title' : 'Columns'},\n                      showlegend=False,\n                     title = 'Train - image size')\nfig.update_traces(textfont_size=16)\nfig.show()\n\n","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-06-02T02:50:43.324435Z","iopub.execute_input":"2021-06-02T02:50:43.324786Z","iopub.status.idle":"2021-06-02T02:50:43.381629Z","shell.execute_reply.started":"2021-06-02T02:50:43.32475Z","shell.execute_reply":"2021-06-02T02:50:43.380565Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Metadata of test images","metadata":{}},{"cell_type":"code","source":"test_df","metadata":{"execution":{"iopub.status.busy":"2021-06-02T02:50:43.382781Z","iopub.execute_input":"2021-06-02T02:50:43.383036Z","iopub.status.idle":"2021-06-02T02:50:43.428465Z","shell.execute_reply.started":"2021-06-02T02:50:43.383013Z","shell.execute_reply":"2021-06-02T02:50:43.427717Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_df['PatientSex'].value_counts().reset_index()\\\n    .style.background_gradient(subset=['PatientSex'], cmap='winter_r')\\","metadata":{"execution":{"iopub.status.busy":"2021-06-02T02:50:43.429661Z","iopub.execute_input":"2021-06-02T02:50:43.429888Z","iopub.status.idle":"2021-06-02T02:50:43.451986Z","shell.execute_reply.started":"2021-06-02T02:50:43.429864Z","shell.execute_reply":"2021-06-02T02:50:43.451242Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_df['BodyPartExamined'].value_counts().reset_index()\\\n    .style.background_gradient(subset=['BodyPartExamined'], cmap='magma_r')\\","metadata":{"_kg_hide-input":false,"execution":{"iopub.status.busy":"2021-06-02T02:50:43.452976Z","iopub.execute_input":"2021-06-02T02:50:43.453294Z","iopub.status.idle":"2021-06-02T02:50:43.470434Z","shell.execute_reply.started":"2021-06-02T02:50:43.453261Z","shell.execute_reply":"2021-06-02T02:50:43.469361Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig = go.Figure(go.Scattergl(\n    x=test_df['Rows'], y=test_df['Columns'],\n    name='Image Size',\n    mode='markers',  \n    marker=dict(\n        color='#DCD427',\n    )\n))\nfig.update_layout(xaxis={'title' : 'Rows', \n                             'showgrid':False},\n                      yaxis={'showgrid':False,\n                            'title' : 'Columns'},\n                      showlegend=False,\n                     title = 'Test - image size')\nfig.update_traces(textfont_size=16)\nfig.show()\n\n","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-06-02T02:50:43.471429Z","iopub.execute_input":"2021-06-02T02:50:43.471723Z","iopub.status.idle":"2021-06-02T02:50:43.501492Z","shell.execute_reply.started":"2021-06-02T02:50:43.471691Z","shell.execute_reply":"2021-06-02T02:50:43.499195Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df['ImageSize'] = train_df['Rows'] * train_df['Columns']\ntest_df['ImageSize'] = test_df['Rows'] * test_df['Columns']\n\nfig = go.Figure()\nfig.add_trace(go.Box(y=train_df['ImageSize'], \n                         name='Train', \n                         jitter=0.5,\n                         whiskerwidth=0.6,\n                         fillcolor='#0092CC',\n                         marker_size=5,\n                         line_width=1))\nfig.add_trace(go.Box(y=test_df['ImageSize'], \n                         name='Test', \n                         jitter=0.5,\n                         whiskerwidth=0.6,\n                         fillcolor='#DCD427',\n                         marker_size=5,\n                         line_width=1))\n\nfig.update_layout(xaxis={'title' : None,'showgrid' :False},\n                  yaxis=dict(title='Image Size (Pixels)',showgrid=False,zeroline=False),\n                 title = 'Image Size IQR')    \nfig.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-06-02T02:50:43.503325Z","iopub.execute_input":"2021-06-02T02:50:43.503644Z","iopub.status.idle":"2021-06-02T02:50:43.561464Z","shell.execute_reply.started":"2021-06-02T02:50:43.50361Z","shell.execute_reply":"2021-06-02T02:50:43.560909Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Image Modality\nDICOM file has an attribute called \"Modality\". This describes the technology used to capture the radiography images.\n* CR - Computed Radiography \n* DX - Digital Radiography \n\nQuick reference on these are [here](https://www.jpihealthcare.com/computed-radiography-cr-and-digital-radiography-dr-which-should-you-choose/)\n\nThe images given in this competitions have approximately equal distribution among these two techonologies. Digital Radiography has slightly more samples in both train and test images","metadata":{}},{"cell_type":"code","source":"modality_train = train_df['Modality'].value_counts().reset_index().rename(columns={'index':'Modality','Modality':'Count'})\nmodality_train['Type'] = 'Train'\nmodality_test = test_df['Modality'].value_counts().reset_index().rename(columns={'index':'Modality','Modality':'Count'})\nmodality_test['Type'] = 'Test'\nmodality_df = pd.concat([modality_train, modality_test]).reset_index(drop=True)\nmodality_map = {'DX' : 'Digital Radiography',\n'CR' : 'Computed Radiography'}\nmodality_df['Desc'] = modality_df['Modality'].apply(lambda x : modality_map[x])\nbar_colors = ['#FFA48E', '#4ACFAC']\nmodalities = list(modality_df.Desc.unique())\nfig = go.Figure()\nfor modality, color in zip(modalities, bar_colors):\n    df = modality_df.loc[modality_df['Desc'] == modality]\n    fig.add_trace(go.Bar(\n        x=df['Type'],\n        y=df['Count'],\n        name=modality,\n        marker_color = color,\n        #text = df['passenger_count_new'],\n        #texttemplate='%{text:.2s}', \n        textposition='auto',\n        marker_line_width=2.5, opacity=0.8,\n        marker_line_color = color        \n    ))\nfig.update_layout(barmode='stack',\n                  xaxis=dict(\n                                tickmode = 'array',\n                                 title=None,\n                                 showgrid=False,\n                                 zeroline=False,\n                            ),\n                      yaxis=dict(title='Count',\n                                 showgrid=False,\n                                 zeroline=False,\n                                ), \n                      title = dict(text = 'Modality of images',\n                                   xref = 'paper',\n                                  ),\n                      bargap=0.15, \n                    bargroupgap=0.1,\n                     )     \nfig.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-06-02T02:50:43.562353Z","iopub.execute_input":"2021-06-02T02:50:43.562648Z","iopub.status.idle":"2021-06-02T02:50:43.60438Z","shell.execute_reply.started":"2021-06-02T02:50:43.562618Z","shell.execute_reply":"2021-06-02T02:50:43.603316Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_modality_sample(df, modality):\n    studyinstance = df.loc[(df['Modality'] == modality) & (df['PatientSex'] == 'M')].sample(n=1)['StudyInstanceUID'].values[0]\n    return studyinstance\n    #files = [file for file in all_files if studyinstance in file]\n    #return files[0]\n\ndef get_modality_samples():\n    modality_samples = []\n    modality_samples.append(get_modality_sample(train_df,'CR'))\n    modality_samples.append(get_modality_sample(train_df,'DX'))\n    study_samples = []\n    for study_instance_id in modality_samples:\n        samples = []\n        image = {}\n        image_id = image_df.loc[image_df['StudyInstanceUID']==study_instance_id]['id'].values[0].split('_')[0] #Get the image matching study id\n        file_name = [string for string in all_files if image_id in string]\n        image['study_id'] = study_instance_id\n        image['dicom_file'] = file_name[0]\n        #Get the bounding boxes\n        box = None\n        try:\n            box = literal_eval(image_df.loc[image_df['StudyInstanceUID']==study_instance_id]['boxes'].values[0])\n        except ValueError:\n            pass\n        image['boxes'] = box\n        study_samples.append(image)\n        #study_samples[study_instance_id] = samples\n    return study_samples\n\ndef display_modality_samples(samples, title, draw_boxes=False):\n    ''' Input : List of samples \n    '''\n    fig1, ax1 = plt.subplots(1,2, figsize=(18, 12), facecolor='w', edgecolor='b')\n    fig1.subplots_adjust(hspace =.3, wspace=0.3)\n    axs = ax1.ravel()\n    for item, ax in zip(samples, axs):\n        dicom = read_file(item['dicom_file'], stop_before_pixels=False)\n        img = dicom.pixel_array\n        ax.imshow(img, cmap=\"gray\")\n        if draw_boxes == True and item['boxes'] is not None:\n            for box in item['boxes']:             \n                rect = patches.Rectangle((box['x'], box['y']), box['width'], box['height'], linewidth=1.5, edgecolor='r', facecolor='none')\n                ax.add_patch(rect)\n        ax.set_title('Study : {}'.format(item['study_id']),fontsize = 18)\n        \n    plt.tight_layout(pad=1.0)\n#    plt.subplots_adjust(top=0.99)\n    plt.suptitle(title,fontsize = 20)\n    plt.show()\n\ndisplay_modality_samples(get_modality_samples(), 'Computed Radiography vs Digital Radiography', True)","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-06-02T02:50:43.605471Z","iopub.execute_input":"2021-06-02T02:50:43.605715Z","iopub.status.idle":"2021-06-02T02:50:45.363822Z","shell.execute_reply.started":"2021-06-02T02:50:43.605689Z","shell.execute_reply":"2021-06-02T02:50:45.363009Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Photometric Interpretation\n\nIn DICOM, monochrome images are given a photometric interpretation of 'MONOCHROME1' (low values=bright, high values=dim) or 'MONOCHROME2' (low values=dark, high values=bright).","metadata":{}},{"cell_type":"code","source":"pi_train = train_df['PhotometricInterpretation'].value_counts().reset_index().rename(columns={'index':'PhotometricInterpretation','PhotometricInterpretation':'Count'})\npi_train['Type'] = 'Train'\npi_test = test_df['PhotometricInterpretation'].value_counts().reset_index().rename(columns={'index':'PhotometricInterpretation','PhotometricInterpretation':'Count'})\npi_test['Type'] = 'Test'\npi_df = pd.concat([pi_train, pi_test]).reset_index(drop=True)\nbar_colors = ['#FFA48E', '#4ACFAC']\npi_values = list(pi_df.PhotometricInterpretation.unique())\nfig = go.Figure()\nfor pi, color in zip(pi_values, bar_colors):\n    df = pi_df.loc[pi_df['PhotometricInterpretation'] == pi]\n    fig.add_trace(go.Bar(\n        x=df['Type'],\n        y=df['Count'],\n        name=pi,\n        marker_color = color,\n        #text = df['passenger_count_new'],\n        #texttemplate='%{text:.2s}', \n        textposition='auto',\n        marker_line_width=2.5, opacity=0.8,\n        marker_line_color = color        \n    ))\nfig.update_layout(barmode='stack',\n                  xaxis=dict(\n                                tickmode = 'array',\n                                 title=None,\n                                 showgrid=False,\n                                 zeroline=False,\n                            ),\n                      yaxis=dict(title='Count',\n                                 showgrid=False,\n                                 zeroline=False,\n                                ), \n                      title = dict(text = 'Photometric Interpretation of images',\n                                   xref = 'paper',\n                                  ),\n                      bargap=0.15, \n                    bargroupgap=0.1,\n                     )     \nfig.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-06-02T02:50:45.365132Z","iopub.execute_input":"2021-06-02T02:50:45.365434Z","iopub.status.idle":"2021-06-02T02:50:45.400589Z","shell.execute_reply.started":"2021-06-02T02:50:45.3654Z","shell.execute_reply":"2021-06-02T02:50:45.399884Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_photometricInterpretation_sample(df, modality):\n    studyinstance = df.loc[(df['PhotometricInterpretation'] == modality) & (df['PatientSex'] == 'M')].sample(n=1)['StudyInstanceUID'].values[0]\n    return studyinstance\n    #files = [file for file in all_files if studyinstance in file]\n    #return files[0]\n\ndef get_PhotometricInterpretation_samples():\n    modality_samples = []\n    modality_samples.append(get_photometricInterpretation_sample(train_df,'MONOCHROME2'))\n    modality_samples.append(get_photometricInterpretation_sample(train_df,'MONOCHROME1'))\n    study_samples = []\n    for study_instance_id in modality_samples:\n        samples = []\n        image = {}\n        image_id = image_df.loc[image_df['StudyInstanceUID']==study_instance_id]['id'].values[0].split('_')[0] #Get the image matching study id\n        file_name = [string for string in all_files if image_id in string]\n        image['study_id'] = study_instance_id\n        image['dicom_file'] = file_name[0]\n        #Get the bounding boxes\n        box = None\n        try:\n            box = literal_eval(image_df.loc[image_df['StudyInstanceUID']==study_instance_id]['boxes'].values[0])\n        except ValueError:\n            pass\n        image['boxes'] = box\n        study_samples.append(image)\n        #study_samples[study_instance_id] = samples\n    return study_samples\n\ndef display_photometricInterpretation_samples(samples, title, draw_boxes=False):\n    ''' Input : List of samples \n    '''\n    fig1, ax1 = plt.subplots(1,2, figsize=(18, 12), facecolor='w', edgecolor='b')\n    fig1.subplots_adjust(hspace =.3, wspace=0.3)\n    axs = ax1.ravel()\n    for item, ax in zip(samples, axs):\n        dicom = read_file(item['dicom_file'], stop_before_pixels=False)\n        img = dicom.pixel_array\n        ax.imshow(img, cmap=\"gray\")\n        if draw_boxes == True and item['boxes'] is not None:\n            for box in item['boxes']:             \n                rect = patches.Rectangle((box['x'], box['y']), box['width'], box['height'], linewidth=1.5, edgecolor='r', facecolor='none')\n                ax.add_patch(rect)\n        ax.set_title('Study : {}'.format(item['study_id']),fontsize = 18)\n        \n    plt.tight_layout(pad=1.0)\n#    plt.subplots_adjust(top=0.99)\n    plt.suptitle(title,fontsize = 20)\n    plt.show()\n\ndisplay_photometricInterpretation_samples(get_PhotometricInterpretation_samples(), 'MONOCHROME2 vs MONOCHROME1', True)","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-06-02T02:50:45.40167Z","iopub.execute_input":"2021-06-02T02:50:45.402116Z","iopub.status.idle":"2021-06-02T02:50:48.870536Z","shell.execute_reply.started":"2021-06-02T02:50:45.402083Z","shell.execute_reply":"2021-06-02T02:50:48.867128Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style=\"background-color:#fdb913; font-size:120%;  font-family:sans-serif; text-align:center\"><b>Explore bounding boxes in training data</b></div>\n","metadata":{}},{"cell_type":"code","source":"img_df = image_df.copy()\nfrom ast import literal_eval\n\ndef count_bb(x):\n    count=0\n    bb_lst = literal_eval(x)\n    for box in bb_lst:\n        count+=1\n    return count\n\ndef bb_size(x):\n    sizes= []\n    bb_lst = literal_eval(x)\n    for box in bb_lst:\n        w=box['width']\n        h=box['height']\n        sizes.append(w*h)\n    return sizes\n    \nimg_df['boxes'] = img_df['boxes'].fillna('[]')\nimg_df['bb_count'] = img_df['boxes'].apply(lambda x: count_bb(x))\nimg_df['bb_size'] = img_df['boxes'].apply(lambda x: bb_size(x))\n\nbbs_lst = []\nfor index, row in img_df.iterrows():\n    #lst = literal_eval(row['bb_size'])\n    bbs_lst.extend(row['bb_size'])","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-06-02T02:50:48.871847Z","iopub.execute_input":"2021-06-02T02:50:48.87212Z","iopub.status.idle":"2021-06-02T02:50:49.681459Z","shell.execute_reply.started":"2021-06-02T02:50:48.872093Z","shell.execute_reply":"2021-06-02T02:50:49.68087Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig1, ax1 = plt.subplots(1,1, figsize=(8, 6), facecolor='w', edgecolor='g')\nfig1.subplots_adjust(hspace =.3, wspace=0.3)\nsub_plot = sns.histplot(img_df['bb_count'], ax=ax1)\nax1.set_title('Number of bounding boxes in train images',fontsize = 18)\nax1.set_xlabel('Number of bounding boxes', fontsize=12)\nax1.set_ylabel('Count', fontsize=12)\nplt.tight_layout(pad=3.0)\nplt.subplots_adjust(top=0.91)\nplt.show()\n","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-06-02T02:50:49.682407Z","iopub.execute_input":"2021-06-02T02:50:49.682709Z","iopub.status.idle":"2021-06-02T02:50:49.901454Z","shell.execute_reply.started":"2021-06-02T02:50:49.682677Z","shell.execute_reply":"2021-06-02T02:50:49.900991Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig1, ax1 = plt.subplots(1,1, figsize=(8, 6), facecolor='w', edgecolor='g')\nfig1.subplots_adjust(hspace =.3, wspace=0.3)\nsub_plot = sns.histplot(bbs_lst,bins=100, ax=ax1)\nax1.set_title('Size of bounding boxes in train images',fontsize = 18)\nax1.set_xlabel('Size', fontsize=12)\nax1.ticklabel_format(style='plain')\n#start, end = ax1.get_xlim()\n#ax1.xaxis.set_ticks(np.arange(start, end, 500000))\nax1.set_ylabel('Count', fontsize=12)\nplt.tight_layout(pad=3.0)\nplt.subplots_adjust(top=0.91)\nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-06-02T02:50:49.902259Z","iopub.execute_input":"2021-06-02T02:50:49.902537Z","iopub.status.idle":"2021-06-02T02:50:50.216143Z","shell.execute_reply.started":"2021-06-02T02:50:49.902515Z","shell.execute_reply":"2021-06-02T02:50:50.21564Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"img_bb_df = pd.DataFrame(columns=['image_id','study_ins_id','bb_count', 'bb_size'])\n\nfor index, rec in img_df.iterrows():\n    row= {}\n    row['image_id'] = rec['id'].split('_')[0]\n    row['study_ins_id'] = rec['StudyInstanceUID']\n    row['bb_count'] = rec['bb_count']    \n    #bb_lst = literal_eval(rec['bb_size'])\n    for bb in rec['bb_size']:\n        row['bb_size'] = bb\n        img_bb_df = img_bb_df.append(row, ignore_index=True)\n","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-06-02T02:50:50.216931Z","iopub.execute_input":"2021-06-02T02:50:50.217235Z","iopub.status.idle":"2021-06-02T02:51:12.859623Z","shell.execute_reply.started":"2021-06-02T02:50:50.217213Z","shell.execute_reply":"2021-06-02T02:51:12.858443Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> Let's look at the distribution of bounding box sizes. The training images contain variable number of bounding boxes like 1, 2, 3, 4, 5 and 8. ","metadata":{}},{"cell_type":"code","source":"fig = go.Figure()\n#Sky Blue, Hyper Red, Sulphur Yellow, Green\nbb_colors = ['#0092CC','#FF3333','#DCD427','#779933']\n\nfor bb_count, color in zip([1,2,3,4], bb_colors):\n    df = img_bb_df.loc[img_bb_df['bb_count']==bb_count].reset_index(drop=True)\n    fig.add_trace(go.Box(y=df['bb_size'], \n                             name='BB count : {}'.format(bb_count), \n                             jitter=0.5,\n                             whiskerwidth=0.6,\n                             fillcolor=color,\n                             marker_size=5,\n                             line_width=1))\nfig.update_layout(xaxis={'title' : None,'showgrid' :False},\n                  yaxis=dict(title='Bounding Box Size (Pixels)',showgrid=False,zeroline=False),\n                 title = 'Train images - Bounding Box Size IQR')    \nfig.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-06-02T02:51:12.860753Z","iopub.execute_input":"2021-06-02T02:51:12.860978Z","iopub.status.idle":"2021-06-02T02:51:12.939531Z","shell.execute_reply.started":"2021-06-02T02:51:12.860935Z","shell.execute_reply":"2021-06-02T02:51:12.938834Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Add labels to the image_bb dataframe\nsg_df = pd.melt(study_df, id_vars=list(study_df.columns)[:1], value_vars=list(study_df.columns)[1:],\n             var_name='label', value_name='value')\nsg_df = sg_df.loc[sg_df['value']!=0]\nsg_df['study_id'] = sg_df['id'].apply(lambda x : str(x).split('_')[0])\nlbl_map = {'Negative for Pneumonia' : 'Negative',\n 'Typical Appearance' : 'Typical',\n 'Indeterminate Appearance' : 'Indeterminate', \n 'Atypical Appearance' : 'Atypical'}\nsg_df['lbl'] = sg_df['label'].apply(lambda x: lbl_map[x])\nslbl_map = dict(zip(sg_df.study_id, sg_df.lbl)) \nimg_bb_df['label'] = img_bb_df['study_ins_id'].apply(lambda x: slbl_map[x])\n#slbl_map","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2021-06-02T02:51:12.940517Z","iopub.execute_input":"2021-06-02T02:51:12.94086Z","iopub.status.idle":"2021-06-02T02:51:12.964275Z","shell.execute_reply.started":"2021-06-02T02:51:12.940837Z","shell.execute_reply":"2021-06-02T02:51:12.963424Z"},"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"large_bb = img_bb_df.sort_values('bb_size', ascending=False).head(20).reset_index(drop=True)\ndef find_file(img_id):\n    imgs = [file for file in all_files if img_id in file]\n    return imgs[0]\n\nlarge_bb['file'] = large_bb['image_id'].apply(lambda x : find_file(x))\nlarge_bb = large_bb[['image_id','study_ins_id','label','file']]\nlg_bb_dict = large_bb.set_index('image_id').T.to_dict('list')\n","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-06-02T02:51:12.965283Z","iopub.execute_input":"2021-06-02T02:51:12.965507Z","iopub.status.idle":"2021-06-02T02:51:12.993526Z","shell.execute_reply.started":"2021-06-02T02:51:12.965478Z","shell.execute_reply":"2021-06-02T02:51:12.99217Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import matplotlib.patheffects as path_effects\nCOLOR='white'\ndef show_image(img, figsize=None, ax=None, cmap=\"gray\"):\n    if not ax: \n        fig, ax = plt.subplots(figsize=figsize)\n    ax.imshow(img, cmap=cmap)\n    ax.get_xaxis().set_visible(False)\n    ax.get_yaxis().set_visible(False)\n\ndef draw_outline(o, lw):\n    o.set_path_effects([patheffects.Stroke(linewidth=lw, foreground='black'), patheffects.Normal()])\n\n    \ndef draw_text(ax, x,y, txt, fontsize=14):\n    text = ax.text(x,y, \n                   txt,\n                  verticalalignment = 'top',\n                  color=COLOR,\n                  fontsize=fontsize,\n                  weight='bold')\n\ndef draw_bb(ax, bb, label):\n    for b in bb:\n        patch = ax.add_patch(patches.Rectangle((b['x'],\n                                           b['y']),\n                                           b['width'],\n                                           b['height'],\n                        fill=False,\n                         edgecolor='red',\n                         lw=2))\n        #draw_text(ax, b['x'], b['y'], label)\n\n\ndef get_image(file):\n    dicom = read_file(file, stop_before_pixels=False)\n    return dicom.pixel_array\n\ndef get_bb(img_id):\n    bb = literal_eval(image_df.loc[image_df['id'] == \"{}_image\".format(img_id)]['boxes'].values[0])\n    return bb\n        \ndef show_bb(samples, title, rows=3, cols=4):\n    ''' Input : Dict of samples\n    '''\n    fig, axs = plt.subplots(rows, cols, figsize=(18, 12), facecolor='w', edgecolor='b')\n    #fig.subplots_adjust(hspace =.3, wspace=0.3)\n    for i, ax in enumerate(axs.ravel()):\n        img_id = list(samples.keys())[i]\n        data = list(samples.values())[i]\n        img = get_image(data[2])\n        bb = get_bb(img_id)\n        show_image(img, ax=ax)\n        draw_bb(ax, bb, data[1])\n        ax.set_title('{}, {}'.format(data[0],data[1]),fontsize = 14)\n\n    plt.tight_layout(pad=3.0)\n    plt.subplots_adjust(top=0.91)\n    plt.suptitle(title,fontsize = 20)\n    plt.show()\nshow_bb(lg_bb_dict, 'Large Bounding Boxes')","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-06-02T03:10:59.610295Z","iopub.execute_input":"2021-06-02T03:10:59.610583Z","iopub.status.idle":"2021-06-02T03:11:13.520338Z","shell.execute_reply.started":"2021-06-02T03:10:59.610559Z","shell.execute_reply":"2021-06-02T03:11:13.517586Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"small_bb = img_bb_df.sort_values('bb_size', ascending=True).head(20).reset_index(drop=True)\nsmall_bb['file'] = small_bb['image_id'].apply(lambda x : find_file(x))\nsmall_bb = small_bb[['image_id','study_ins_id','label','file']]\nsm_bb_dict = small_bb.set_index('image_id').T.to_dict('list')\nshow_bb(sm_bb_dict, 'Small Bounding Boxes')","metadata":{"execution":{"iopub.status.busy":"2021-06-02T03:04:35.929358Z","iopub.execute_input":"2021-06-02T03:04:35.929849Z","iopub.status.idle":"2021-06-02T03:04:41.358317Z","shell.execute_reply.started":"2021-06-02T03:04:35.929818Z","shell.execute_reply":"2021-06-02T03:04:41.357598Z"},"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> There are two images which are outliers. One has 5 bounding boxes with classification as 'Indeterminate Appearance' and the other one has 8 bounding boxes with classification as 'Typical Appearance'. So we are dealing with localization of upto and may be even more than 8 objects!","metadata":{}},{"cell_type":"code","source":"outlr_bb = img_bb_df.loc[img_bb_df['bb_count']>4]\n\noutlr_bb['file'] = outlr_bb['image_id'].apply(lambda x : find_file(x))\noutlr_bb = outlr_bb[['image_id','study_ins_id','label','file']]\nol_bb_dict = outlr_bb.set_index('image_id').T.to_dict('list')\n#show_bb(sm_bb_dict, 'Small Bounding Boxes')\nol_bb_dict\nshow_bb(ol_bb_dict, 'Outliers!', rows=1, cols=2)","metadata":{"execution":{"iopub.status.busy":"2021-06-02T03:11:14.598244Z","iopub.execute_input":"2021-06-02T03:11:14.598541Z","iopub.status.idle":"2021-06-02T03:11:16.648913Z","shell.execute_reply.started":"2021-06-02T03:11:14.598517Z","shell.execute_reply":"2021-06-02T03:11:16.647844Z"},"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Work in progress","metadata":{}},{"cell_type":"code","source":"","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}