{"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":"![COVID-19](https://images.pexels.com/photos/3992933/pexels-photo-3992933.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500)","metadata":{}},{"cell_type":"markdown","source":"<div style=\"color:white; display:fill; border-radius:5px; background-color:#5642C5;font-size:200%;font-family:Verdana; letter-spacing:0.5px\"><p style=\"padding: 10px;color:white;\">Introduction</p></div>\n\n## This is a competition where we need to identify & localize COVID-19 abnormalities from the chest radiographs.\n## This is an object detection and classification problem.\n\n## Items to be classified (Performed on study level on training dataset, need to find the same for test dataset)\n1. Negative for Pneumonia\n2. Typical Appearance\n3. Indeterminate Appearance\n4. Atypical Appearance\n\nLet's get started !!!","metadata":{}},{"cell_type":"markdown","source":"<div style=\"font-size:30px\" class=\"alert alert-block alert-info\"> Cool Imports</div>","metadata":{}},{"cell_type":"code","source":"pip install pylibjpeg pylibjpeg-libjpeg pydicom\n","metadata":{"execution":{"iopub.status.busy":"2021-06-07T18:09:17.855183Z","iopub.execute_input":"2021-06-07T18:09:17.855728Z","iopub.status.idle":"2021-06-07T18:09:24.910471Z","shell.execute_reply.started":"2021-06-07T18:09:17.855673Z","shell.execute_reply":"2021-06-07T18:09:24.909230Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport os, glob, ast, cv2, sys\nfrom pathlib import Path\nimport seaborn as sns\nimport pylibjpeg\nimport matplotlib.pyplot as plt\nimport plotly.graph_objects as go\nimport plotly.express as px\nfrom plotly.subplots import make_subplots\nfrom collections import Counter\nimport pydicom\nfrom pydicom.pixel_data_handlers.util import apply_voi_lut\nfrom plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplot\nimport plotly as py\ninit_notebook_mode(connected=True)\n\nfrom colorama import Fore, Back, Style\ny_ = Fore.YELLOW\nr_ = Fore.RED\ng_ = Fore.GREEN\nb_ = Fore.BLUE\nm_ = Fore.MAGENTA\nsr_ = Style.RESET_ALL\nprint(f\"{y_}Folder Contents:{b_}\\n\")\n\ncount = 1\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    if count < 10:\n        for filename in filenames:\n            print(f\"{os.path.join(dirname, filename)}\");\n            count += 1\nprint(f\"{sr_}\")","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_kg_hide-input":false,"execution":{"iopub.status.busy":"2021-06-07T18:09:24.912842Z","iopub.execute_input":"2021-06-07T18:09:24.913366Z","iopub.status.idle":"2021-06-07T18:09:31.480926Z","shell.execute_reply.started":"2021-06-07T18:09:24.913289Z","shell.execute_reply":"2021-06-07T18:09:31.479708Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style=\"font-size:30px\" class=\"alert alert-block alert-info\"> Dataset Analytics</div>","metadata":{}},{"cell_type":"code","source":"files = glob.glob('/kaggle/input/siim-covid19-detection/*')\n\nprint(f\" {r_} Number of CSV Files : {b_}{len([file for file in files if file.endswith('.csv')])}{sr_}\")\n\ntraining_study_files = glob.glob('/kaggle/input/siim-covid19-detection/train/*')\nprint(f\" {r_} Number of Training Study Files : {b_}{len(training_study_files)}{sr_}\")\ntraining_series_files = glob.glob('/kaggle/input/siim-covid19-detection/train/*/*')\nprint(f\" {r_} Number of Training Series Files : {b_}{len(training_series_files)}{sr_}\")\ntraining_image_files = glob.glob('/kaggle/input/siim-covid19-detection/train/*/*/*.dcm')\nprint(f\" {r_} Number of Training Image (.dcm) Files : {b_}{len(training_image_files)} \\n\")\n\ntesting_study_files = glob.glob('/kaggle/input/siim-covid19-detection/test/*')\nprint(f\" {r_} Number of Testing Study Files : {b_}{len(testing_study_files)}{sr_}\")\ntesting_series_files = glob.glob('/kaggle/input/siim-covid19-detection/test/*/*')\nprint(f\" {r_} Number of Testing Series Files : {b_}{len(testing_series_files)}{sr_}\")\ntesting_image_files = glob.glob('/kaggle/input/siim-covid19-detection/test/*/*/*.dcm')\nprint(f\" {r_} Number of Testing Image (.dcm) Files : {b_}{len(testing_image_files)}{sr_}\")\n\n## Intuitively we can think study as number of patients (6064) and there can be multiple radiographs taken by any single patient. \n## Thus in total there is 6334 image(.dcm) files.","metadata":{"execution":{"iopub.status.busy":"2021-06-07T18:09:31.483849Z","iopub.execute_input":"2021-06-07T18:09:31.484502Z","iopub.status.idle":"2021-06-07T18:09:41.177940Z","shell.execute_reply.started":"2021-06-07T18:09:31.484456Z","shell.execute_reply":"2021-06-07T18:09:41.176693Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style=\"font-size:20px\" class=\"alert alert-block alert-info\"> Sneek peek at train_study_level.csv </div>\n\n## train_study_level.csv - The train study-level metadata, with one row for each study, including correct labels.","metadata":{}},{"cell_type":"code","source":"tsl_df = pd.read_csv('/kaggle/input/siim-covid19-detection/train_study_level.csv')\nprint(\"\\n\", tsl_df.info())\ntsl_df.head()","metadata":{"execution":{"iopub.status.busy":"2021-06-07T18:09:41.180133Z","iopub.execute_input":"2021-06-07T18:09:41.180779Z","iopub.status.idle":"2021-06-07T18:09:41.215476Z","shell.execute_reply.started":"2021-06-07T18:09:41.180737Z","shell.execute_reply":"2021-06-07T18:09:41.214505Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(f\"{r_}Unique Elements : \\n {b_}{np.unique(tsl_df[list(tsl_df.columns[1:])].values, axis=0)}{sr_}\")","metadata":{"execution":{"iopub.status.busy":"2021-06-07T18:09:41.216940Z","iopub.execute_input":"2021-06-07T18:09:41.217433Z","iopub.status.idle":"2021-06-07T18:09:41.238798Z","shell.execute_reply.started":"2021-06-07T18:09:41.217394Z","shell.execute_reply":"2021-06-07T18:09:41.237263Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style=\"font-size:30px\" class=\"alert alert-block alert-info\"> Class Distribution</div>","metadata":{}},{"cell_type":"code","source":"columns = tsl_df.columns[1:]\nx0 = [columns[0],columns[1],columns[2],columns[3]]\ny0 = [str(len(tsl_df[tsl_df[columns[0]] == 0])), str(len(tsl_df[tsl_df[columns[1]] == 0])), str(len(tsl_df[tsl_df[columns[2]] == 0])), str(len(tsl_df[tsl_df[columns[3]] == 0]))]\n\nx1 = [columns[0],columns[1],columns[2],columns[3]]\ny1 = [str(len(tsl_df[tsl_df[columns[0]] == 1])), str(len(tsl_df[tsl_df[columns[1]] == 1])), str(len(tsl_df[tsl_df[columns[2]] == 1])), str(len(tsl_df[tsl_df[columns[3]] == 1]))]\n\nfig = go.Figure()\nfig.add_trace(go.Histogram(histfunc=\"sum\", y=y0, x=x0, name=\"0\"))\nfig.add_trace(go.Histogram(histfunc=\"sum\", y=y1, x=x1, name=\"1\"))\n# fig.update_layout(barmode=\"overlay\",bargap=0.1)\npy.offline.iplot(fig)\n\n# Just as expected, there is slight skewness towards the samples of 0, than the samples of 1","metadata":{"execution":{"iopub.status.busy":"2021-06-07T18:09:41.240739Z","iopub.execute_input":"2021-06-07T18:09:41.241420Z","iopub.status.idle":"2021-06-07T18:09:42.155611Z","shell.execute_reply.started":"2021-06-07T18:09:41.241377Z","shell.execute_reply":"2021-06-07T18:09:42.154567Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style=\"font-size:20px\" class=\"alert alert-block alert-info\"> Sneek peek at train_image_level.csv </div>\n\n## train_image_level.csv - the train image-level metadata, with one row for each image, including both correct labels and any bounding boxes in a dictionary format. Some images in both test and train have multiple bounding boxes.","metadata":{}},{"cell_type":"code","source":"til_df = pd.read_csv('/kaggle/input/siim-covid19-detection/train_image_level.csv')\nprint(\"\\n\", til_df.info())\ntil_df.head()","metadata":{"execution":{"iopub.status.busy":"2021-06-07T18:09:42.157483Z","iopub.execute_input":"2021-06-07T18:09:42.157940Z","iopub.status.idle":"2021-06-07T18:09:42.225449Z","shell.execute_reply.started":"2021-06-07T18:09:42.157899Z","shell.execute_reply":"2021-06-07T18:09:42.224266Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style=\"font-size:30px\" class=\"alert alert-block alert-info\"> Bounding Box Distribution</div>","metadata":{}},{"cell_type":"markdown","source":"## Object Detection format (x,y,w,h)\n![coords](https://i.imgur.com/Ow9oPGx.png)","metadata":{}},{"cell_type":"code","source":"box_frequency = []\nfor index, row in til_df.iterrows():\n    if (isinstance(row.boxes, str)): ## To filter NaN\n        box_frequency.append(len(ast.literal_eval(row.boxes)))\n    else:\n        box_frequency.append(0)\n        \nfig = go.Figure(data=[go.Pie(labels=list(Counter(box_frequency).keys()), \n                             values=list(Counter(box_frequency).values()), \n                             textinfo='label+percent',\n                             insidetextorientation='radial',hole=.3)])\nfig.update_layout(title_text='BBOX Distribution - Pie')\npy.offline.iplot(fig)\n","metadata":{"execution":{"iopub.status.busy":"2021-06-07T18:09:42.226992Z","iopub.execute_input":"2021-06-07T18:09:42.227483Z","iopub.status.idle":"2021-06-07T18:09:43.308596Z","shell.execute_reply.started":"2021-06-07T18:09:42.227442Z","shell.execute_reply":"2021-06-07T18:09:43.307437Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig = go.Figure(go.Histogram(x=box_frequency, bingroup=1))\nfig.update_layout(barmode=\"overlay\",bargap=0.1,title_text='BBOX Distribution - Bar')\npy.offline.iplot(fig)","metadata":{"execution":{"iopub.status.busy":"2021-06-07T18:09:43.311870Z","iopub.execute_input":"2021-06-07T18:09:43.312152Z","iopub.status.idle":"2021-06-07T18:09:43.460625Z","shell.execute_reply.started":"2021-06-07T18:09:43.312124Z","shell.execute_reply":"2021-06-07T18:09:43.459363Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"count_of_none = np.count_nonzero(np.array(box_frequency) == 0 )\ncount_of_opacity = np.count_nonzero(np.array(box_frequency) != 0 )\n\nfig = go.Figure()\nfig.add_trace(go.Histogram(histfunc=\"sum\", x=['none','opacity'], y=[count_of_none,count_of_opacity]))\nfig.update_layout(title_text='Distribution of None Vs Opacity')\npy.offline.iplot(fig)","metadata":{"execution":{"iopub.status.busy":"2021-06-07T18:09:43.462469Z","iopub.execute_input":"2021-06-07T18:09:43.462884Z","iopub.status.idle":"2021-06-07T18:09:43.509427Z","shell.execute_reply.started":"2021-06-07T18:09:43.462849Z","shell.execute_reply":"2021-06-07T18:09:43.508356Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style=\"font-size:30px\" class=\"alert alert-block alert-info\"> Custom Functions</div>","metadata":{}},{"cell_type":"code","source":"## Functions\n\ndef get_image_id(path):\n    image_name = path.split('/')[-1].replace('.dcm', '_image')\n    return image_name\n\n\ndef create_study_id(path):\n    image_name = path.split('/')[-1].replace('.dcm', '_image')\n    return image_name\n\ndef dicom2array(path, voi_lut=True, fix_monochrome=True):\n    dicom = pydicom.read_file(path)\n    # VOI LUT (if available by DICOM device) is used to\n    # transform raw DICOM data to \"human-friendly\" view\n    if voi_lut:\n        data = apply_voi_lut(dicom.pixel_array, dicom)\n    else:\n        data = dicom.pixel_array\n    # depending on this value, X-ray may look inverted - fix that:\n    if fix_monochrome and dicom.PhotometricInterpretation == \"MONOCHROME1\":\n        data = np.amax(data) - data\n    data = data - np.min(data)\n    data = data / np.max(data)\n    data = (data * 255).astype(np.uint8)\n    data = cv2.cvtColor(data, cv2.COLOR_GRAY2RGB)\n\n    return data\n\ndef do_annotations(path, coords, color_codes):\n    temp_image = dicom2array(path)\n    for coord in coords:\n        cv2.rectangle(temp_image, (int(coord['x']), int(coord['y'])), (int(coord['x']+coord['width']), int(coord['y']+coord['height'])), color_codes, 15)\n    return temp_image\n\ndef make_subplots(display_image, display_image_w_annotation, title):\n    fig, ax = plt.subplots(3,2, sharex='col', figsize=(20,20), gridspec_kw={'hspace': 0, 'wspace': 0.1}) \n\n    ax[0, 0].imshow(cv2.resize(display_image[0], (1024, 1024)))\n    ax[0, 1].imshow(cv2.resize(display_image_w_annotation[0], (1024, 1024)))\n\n    ax[1, 0].imshow(cv2.resize(display_image[1], (1024, 1024)))\n    ax[1, 1].imshow(cv2.resize(display_image_w_annotation[1], (1024, 1024)))\n\n    ax[2, 0].imshow(cv2.resize(display_image[2], (1024, 1024)))\n    ax[2, 1].imshow(cv2.resize(display_image_w_annotation[2], (1024, 1024)))\n\n    plt.subplots_adjust(left=0.5)\n    plt.show()\n    \n    \n\ndef prepare_sample(training_images_df, col_number, samples, nan_flag = False):\n    df_subset = training_images_df[training_images_df.iloc[:, col_number] == 1].sample(frac=1)\n    \n    display_image, display_image_w_annotation  = [], []\n    title = str(training_images_df.columns[col_number])\n    color_codes = {}\n    color_codes[5] = (255, 0, 0)\n    color_codes[6] = (0, 0, 255)\n    color_codes[7] = (0, 255, 0)\n    \n    if nan_flag:\n        for idx, rows in df_subset.iterrows():\n            if (len(display_image) ==  samples) and (len(display_image_w_annotation) == samples):\n                return display_image, display_image_w_annotation, title, df_subset\n            else:\n                display_image.append(dicom2array(rows['training_images_path']))\n                display_image_w_annotation.append(dicom2array(rows['training_images_path']))\n    else:\n        for idx, rows in df_subset.iterrows():\n            if (len(display_image) ==  samples) and (len(display_image_w_annotation) == samples):\n                return display_image, display_image_w_annotation, title\n            else:\n                if isinstance(rows['boxes'], str):\n#                     print(rows['training_images_path'], rows['boxes'])\n                    display_image.append(dicom2array(rows['training_images_path']))\n                    display_image_w_annotation.append(do_annotations(rows['training_images_path'], ast.literal_eval(rows.boxes), color_codes[col_number]))","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-06-07T18:09:43.510840Z","iopub.execute_input":"2021-06-07T18:09:43.511429Z","iopub.status.idle":"2021-06-07T18:09:43.533373Z","shell.execute_reply.started":"2021-06-07T18:09:43.511393Z","shell.execute_reply":"2021-06-07T18:09:43.532362Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style=\"font-size:20px\" class=\"alert alert-block alert-info\"> Merging two dataframes into a single one based on the foreign key</div>","metadata":{}},{"cell_type":"code","source":"training_images_path = glob.glob('/kaggle/input/siim-covid19-detection/train/*/*/*.dcm')\ntraining_images_df = pd.DataFrame(training_images_path, columns =['training_images_path'])\n\ntraining_images_df['image_id'] = training_images_df.apply(lambda rows: get_image_id(rows['training_images_path']), axis=1)\ntraining_images_df = pd.merge(training_images_df, til_df, left_on='image_id', right_on='id', how='left').drop(['image_id','id'], axis=1)\ntraining_images_df.head()","metadata":{"execution":{"iopub.status.busy":"2021-06-07T18:09:43.535065Z","iopub.execute_input":"2021-06-07T18:09:43.535999Z","iopub.status.idle":"2021-06-07T18:09:49.262650Z","shell.execute_reply.started":"2021-06-07T18:09:43.535953Z","shell.execute_reply":"2021-06-07T18:09:49.261578Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"training_images_df['StudyInstance'] = training_images_df.apply(lambda rows: get_image_id(rows['StudyInstanceUID']) + \"_study\", axis=1)\ntraining_images_df = pd.merge(training_images_df, tsl_df, left_on='StudyInstance', right_on='id', how='left').drop(['StudyInstance','id'], axis=1)\ntraining_images_df.info()\ntraining_images_df.to_csv('/kaggle/working/training_images_df.csv', index=False)\ntraining_images_df.head()","metadata":{"execution":{"iopub.status.busy":"2021-06-07T18:09:49.265864Z","iopub.execute_input":"2021-06-07T18:09:49.266172Z","iopub.status.idle":"2021-06-07T18:09:49.448845Z","shell.execute_reply.started":"2021-06-07T18:09:49.266140Z","shell.execute_reply":"2021-06-07T18:09:49.447596Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style=\"font-size:30px\" class=\"alert alert-block alert-info\"> Image Analytics</div>","metadata":{}},{"cell_type":"markdown","source":"<div style=\"font-size:20px\" class=\"alert alert-block alert-warning\"> Samples based on the class --> Negative for Pneumonia</div>","metadata":{}},{"cell_type":"code","source":"display_image, display_image_w_annotation, title, df_subset = prepare_sample(training_images_df, col_number=4, samples = 3, nan_flag = True)\nmake_subplots(display_image, display_image_w_annotation, title)","metadata":{"execution":{"iopub.status.busy":"2021-06-07T18:09:49.450341Z","iopub.execute_input":"2021-06-07T18:09:49.450901Z","iopub.status.idle":"2021-06-07T18:09:52.769748Z","shell.execute_reply.started":"2021-06-07T18:09:49.450860Z","shell.execute_reply":"2021-06-07T18:09:52.768713Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style=\"font-size:20px\" class=\"alert alert-block alert-warning\"> Samples based on the class --> Typical Appearance</div>","metadata":{}},{"cell_type":"code","source":"display_image, display_image_w_annotation, title = prepare_sample(training_images_df, col_number=5, samples = 3)\nmake_subplots(display_image, display_image_w_annotation, title)","metadata":{"execution":{"iopub.status.busy":"2021-06-07T18:09:52.771185Z","iopub.execute_input":"2021-06-07T18:09:52.771663Z","iopub.status.idle":"2021-06-07T18:09:56.987115Z","shell.execute_reply.started":"2021-06-07T18:09:52.771622Z","shell.execute_reply":"2021-06-07T18:09:56.983779Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style=\"font-size:20px\" class=\"alert alert-block alert-warning\"> Samples based on the class --> Indeterminate Appearance</div>","metadata":{}},{"cell_type":"code","source":"display_image, display_image_w_annotation, title = prepare_sample(training_images_df, col_number=6, samples = 3)\nmake_subplots(display_image, display_image_w_annotation, title)","metadata":{"execution":{"iopub.status.busy":"2021-06-07T18:09:56.989162Z","iopub.execute_input":"2021-06-07T18:09:56.989596Z","iopub.status.idle":"2021-06-07T18:09:59.779110Z","shell.execute_reply.started":"2021-06-07T18:09:56.989551Z","shell.execute_reply":"2021-06-07T18:09:59.777382Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style=\"font-size:20px\" class=\"alert alert-block alert-warning\"> Samples based on the class --> Atypical Appearance</div>","metadata":{}},{"cell_type":"code","source":"display_image, display_image_w_annotation, title = prepare_sample(training_images_df, col_number=7, samples = 3)\nmake_subplots(display_image, display_image_w_annotation, title)","metadata":{"execution":{"iopub.status.busy":"2021-06-07T18:10:39.483870Z","iopub.execute_input":"2021-06-07T18:10:39.484377Z","iopub.status.idle":"2021-06-07T18:10:44.069526Z","shell.execute_reply.started":"2021-06-07T18:10:39.484322Z","shell.execute_reply":"2021-06-07T18:10:44.068443Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style=\"font-size:20px\" class=\"alert alert-block alert-danger\"> Work in Progress </div>","metadata":{}}]}