{"cells":[{"metadata":{},"cell_type":"markdown","source":"\n<h1 style=\"font-size: 24px; text-align: center;\">Understanding Chest X-ray abnormalities </h1>\n<h1 style=\"font-family: Lucida Sans Typewriter; font-size: 16px; text-align: center;\"> Author- Sourabh Chauhan</h1>\n\n# Contents of the notebook\n\n <a href=\"#1-Introduction\"> 1. Introduction</a> \n \n <a href=\"#2-Imports\"> 2. Importing libraries</a> \n \n <a href=\"#3-Reading data\"> 3. Reading data </a>\n \n <a href=\"#4-Rad ID vs Class ID\"> 4. Rad id vs Class id skewness </a> \n\n <a href=\"#5-Conclusions from radiologists data skews\"> 5. Conclusions from radiologist skews</a> \n\n\n <a href=\"#6-Visualizing X-ray images \"> 7. Visualizing X-ray images</a> \n\n<a href=\"#7-Merging boxes\"> 7. Merging boxes</a> \n\n <a href=\"# 6-No findings treatment\"> 8. No findings treatment</a> \n\n\n"},{"metadata":{},"cell_type":"markdown","source":"# 1-Introduction\nThis Notebook is part of the [VinBigData Chest X-ray Abnormalities Detection](http://https://www.kaggle.com/c/vinbigdata-chest-xray-abnormalities-detection) competition. If you find it useful, feel free to upvote. \n\n\n<h1 style=\"font-family: Verdana; font-size: 24px; text-align: left;\">Problem Statement </h1>\nIn this competition, you’ll automatically localize and classify 14 types of thoracic abnormalities from chest radiographs. You'll work with a dataset consisting of 18,000 scans that have been annotated by experienced radiologists. You can train your model with 15,000 independently-labeled images and will be evaluated on a test set of 3,000 images. These annotations were collected via VinBigData's web-based platform, VinLab. Details on building the dataset can be found in our recent paper “VinDr-CXR: An open dataset of chest X-rays with radiologist's annotations”.\n\n\n___\n\n<h3 style=\"font-family: Verdana; font-size: 20px; text-align: left;\"> Minor details </h3>\n\n___\n\n * Images are blindly annotated with bounding boxes of 14 classes by 3 radiologists from a pool of 17, encoded with Rad IDs from R1 to R17.\n \n * The task is to automatically correctly predict boxes around abnormalities and classify them for the test images. Unlike the labels of the training set, those of the test set were already a consensus of 5 radiologists per image.\n \n \n ___\n\n<h3 style=\"font-family: Verdana; font-size: 20px; text-align: left;\"> Description of the data </h3>\n\n___\n \n* Format - DICOM (Digital Imaging and Communications in Medicine)\n* Number of images in Training set - 15000\n* Number of images in test set - 3000\n* Number of classes - 14\n* Number of radiologists - 17\n\n\n ****Metric for results****\n\n* The test set contains 3000 images. The public score will be calculated on approx. 10% of the test set and will be visible to you during the competition. Final rankings will be determined on the remaining 90% i.e. private LB\n\n\n\n ___\n\n<h3 style=\"font-family: Verdana; font-size: 20px; text-align: left;\"> Pitfalls and intial questions</h3>\n \n ___   \n    \n    \n[Ref1:- Following the welcome from host](http://https://www.kaggle.com/c/vinbigdata-chest-xray-abnormalities-detection/discussion/207741)\n* Section 7.C. In general, repositories like detectron2, mmdet, torchvision, timm, efficientdet with pre-trained ImageNet/COCO/OpenImages models and datasets like Chexpert, MIMIC, PadChest are allowed\n    \n    \n* Number of bounding boxes each image???? (multiple boxes were linked to same disease )\n\n    * You need to think of creative ways to combine our provided bounding boxes in the train data set before conducting any experiment. 5 detections of a single object is counted as 1 correct detection and 4 false detections – it is the responsibility of the participant’s system to filter multiple detections from its output.\n    \n    * \"For the test set, 5 radiologists involved into a two-stage labeling process. During the first stage, each image was independently annotated by 3 radiologists. In the second stage, 2 other radiologists, who have a higher level of experience, reviewed the annotations of the 3 previous annotators and communicated with each other in order to decide the final labels. The disagreements among initial annotators were carefully discussed and resolved by the 2 reviewers. Finally, the consensus of their opinions will serve as reference ground-truth.\"\n\n\n\n[Ref2 :- Evaluation metric ](https://www.kaggle.com/c/vinbigdata-chest-xray-abnormalities-detection/discussion/212287)\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"## Convert DCM to png, reference :- https://www.kaggle.com/onealbao/dicom-to-jpeg-conversion-kernel\n# Convert to PNG via PIL \n# https://github.com/python-pillow/Pillow\n#Learning DICOM format --> may be for later","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# 2-Imports"},{"metadata":{"trusted":true},"cell_type":"code","source":"from matplotlib import pyplot as plt\nimport glob\nimport pydicom ### to conver dicom to png images\nfrom pydicom.pixel_data_handlers.util import apply_voi_lut ### don't know why???\nimport cv2 ## OpenCV package\nfrom skimage import exposure ###  some preprocess like equalize histogram.\n\n### imports for the bbox section\nfrom PIL import Image\nfrom sklearn import preprocessing\nimport random\nfrom random import randint\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# 3-Reading data"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"_kg_hide-output":true},"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\n'''\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n'''\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"## Columns \nprimary_dir = '/kaggle/input/vinbigdata-chest-xray-abnormalities-detection/'\nsample_sub = pd.read_csv(primary_dir +'sample_submission.csv')\ntrain_csv = pd.read_csv(primary_dir +'train.csv')\ntest_csv = pd.read_csv(primary_dir +'train.csv')\n\nprint (train_csv.columns)\nprint (test_csv.columns)\n\nprint (sample_sub.columns)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print ('Total number of rows in traning images are :-', len((train_csv['image_id']))) \nprint ('Unique training images :- ', len(set(train_csv['image_id'])))\nprint ('Number of total radiologists:- ', len(set(train_csv['rad_id'])))\nprint ('Number of total classes of diagnosis', len(set(train_csv['class_name'])))\nprint (set(train_csv['class_name']))\nfig,ax = plt.subplots(1,2, figsize = (15, 6))\nax[0].hist(train_csv['rad_id'])\nax[1].hist(train_csv['class_id'])\n### \nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"markdown","source":"# 4-Rad ID vs Class ID"},{"metadata":{"trusted":true},"cell_type":"code","source":"## lets try to understand how each of the radiologist is trying to characterize the X-rays \n\n\ndf_test = train_csv.groupby(by = ['rad_id', 'class_id']).count()\ndisplay(df_test)\ncond = train_csv['class_id'] !=14\ntrain_csv[cond].class_id.hist(by=train_csv[cond].rad_id, sharey = False, sharex=True, density=1)\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"> ### That means Radiologist 1,2, 3, 4,5,6,7 are reporting only class_id=14 in their results which is ... 'no findings' in the X ray image. What to do about it \n* Should we just remove those radiologists from the sample??? \n    * Not a good idea to remove because may be these radiologists got only the images with features in their images.\n    ---- Let us take a deeper look at those images -----> "},{"metadata":{"trusted":true},"cell_type":"code","source":"# Reference --- https://www.kaggle.com/leftyork/visual-in-depth-eda-vinbigdata-competition-data\nimport plotly.express as px\nimport plotly\nimport plotly.express as px\nimport seaborn as sns\nimport plotly.graph_objects as go\n\n# PRESETS\nFIG_FONT = dict(family=\"Helvetica, Arial\", size=14, color=\"#7f7f7f\")\nLABEL_COLORS = [px.colors.label_rgb(px.colors.convert_to_RGB_255(x)) for x in sns.color_palette(\"coolwarm\", 15)]\n#LABEL_COLORS_WOUT_NO_FINDING = LABEL_COLORS[:8]+LABEL_COLORS[9:]\n\n'''\nfig = px.histogram(train_csv_good, x=\"rad_id\", color=\"rad_id\",opacity=0.85,\n                   labels={\"rad_id\":\"Radiologist ID\"},\n                   title=\"<b>Number of annotatons by the radiologists</b>\", \n                  ).update_xaxes(categoryorder=\"total descending\")\nfig.update_layout(legend_title=\"<b>RADIOLOGIST ID</b>\",\n                  xaxis_title=\"<b>Radiologist ID</b>\",\n                  yaxis_title=\"<b>Number of Annotations Made</b>\",\n                  font=FIG_FONT,)\nfig.show()'''\n\n\nfig = go.Figure() ### PLOTLY graph object interesting usage \nint_2_str = {i:train_csv[train_csv[\"class_id\"]==i].iloc[0][\"class_name\"] for i in range(15)}\nstr_2_int = {v:k for k,v in int_2_str.items()}\nint_2_clr = {str_2_int[k]:LABEL_COLORS[i] for i,k in enumerate(sorted(str_2_int.keys()))}\n\nfor i in range(15):\n    fig.add_trace(go.Histogram(\n        y=train_csv[train_csv[\"class_id\"]==i][\"rad_id\"],\n        marker_color=int_2_clr[i],\n        name=f\"<b>{i, int_2_str[i]}</b>\", orientation='h'))\n\nfig.update_xaxes(categoryorder=\"total descending\")\nfig.update_layout(title=\"<b>Radiologsits annotation for each anamoly</b>\",\n                  barmode='stack',\n                  xaxis_title=\"<b>Radiologist ID</b>\",\n                  yaxis_title=\"<b>Number of Annotations Made</b>\",\n                  font=FIG_FONT)\nfig.show()\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# 5-Conclusions from radiologists data skews\n    \n    * Most of the annotations come from 3 of the radiologists, R8, R9, R10. \n    * 7 out of 14 have 'No findings' as the output how to take care of this skew?\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"def get_bbox_area(row):\n    return (row['x_max']-row['x_min'])*(row['y_max']-row['y_min'])\ndef get_bbox_height(row):\n    return ((row['y_max']-row['y_min']))\ndef get_bbox_width(row):\n    return (row['x_max']-row['x_min'])\ndef get_bbox_aspect_ratio(row):\n    return ((row['x_max']-row['x_min'])/(row['y_max']-row['y_min']))\n\nle = preprocessing.LabelEncoder()  # encode rad_id\ntrain_csv['rad_label'] = le.fit_transform(train_csv['rad_id'])\n\ntrain_csv_good = train_csv[train_csv['class_id'] != 14]\ntrain_csv_good['bbox_area'] = train_csv_good.apply(get_bbox_area, axis=1)\ntrain_csv_good['bbox_height'] = train_csv_good.apply(get_bbox_height, axis=1)\ntrain_csv_good['bbox_width'] = train_csv_good.apply(get_bbox_width, axis=1)\ntrain_csv_good['bbox_aspect_ratio'] = train_csv_good.apply(get_bbox_aspect_ratio, axis=1)\n\ntrain_csv_good.head()\n\n\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"fig = px.bar(x=[int_2_str[x] for x in range(14)], y=train_csv_good.groupby(\"class_id\").mean()[\"bbox_aspect_ratio\"], \n             color=[int_2_str[x] for x in range(14)], opacity=0.85,\n             labels={\"x\":\"Class Name\", \"y\":\"Aspect Ratio (W/H)\"},\n             title=\"<b>Aspect Ratios For Bounding Boxes By Class</b>\",)\nfig.update_layout(font=FIG_FONT,\n                  yaxis_title=\"<b>Aspect Ratio (W/H)</b>\",\n                  xaxis_title=None,\n                  legend_title_text=None)\n\nfig.add_hline(y=1, line_width=2, line_dash=\"dot\", \n              annotation_font_size=10, \n              annotation_text=\"<b>SQUARE ASPECT RATIO</b>\", \n              annotation_position=\"bottom left\", \n              annotation_font_color=\"black\")\nfig.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"rad_id_bad = [1,3,4,5,6,7]\n\ncond = (train_csv['class_id']==14) & (train_csv['rad_id']=='R1')\ntrain_csv[cond].sample(n=4)\nprint ('Now let us look at those DICOM images')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# 6- No findings treatment\nAn interesting result ... will come back to it later\n[Check out this discussion on the topic.](http://https://www.kaggle.com/c/vinbigdata-chest-xray-abnormalities-detection/discussion/217886)"},{"metadata":{"trusted":true},"cell_type":"code","source":"\ndf_no_finding = train_csv[train_csv['class_id']==14]\n### Using pivot table\n#dups = df_no_finding.pivot_table(index = ['image_id'], aggfunc ='size') \ndf_no_finding_duplicates = df_no_finding.groupby('image_id')['image_id'].count()\nprint((df_no_finding_duplicates.unique()))\nprint ('!!! All no findings are marked by 3 radiologists as no findings')\nprint ('Question:--- which 1000 images have real no findings ???')\ncond1 = (df_no_finding['rad_id']== \"R8\") | (df_no_finding['rad_id']== \"R9\") | (df_no_finding['rad_id']== \"R10\")\nn_no_finding_reliable = len(df_no_finding[ cond1]['image_id'].unique())\nprint ('For now how about we pick random 1000 images \\\nfrom the reliable radiologists, R8, R9, R10, out of ',n_no_finding_reliable)\n#.groupby('rad_id').filter(lambda group: group.size > X)#.count().plot.bar()\n#print (x.unique())\n#df_no_finding.groupby([\"rad_id\"])rad_id.count().sort_values(ascending=False).head(20).plot.bar()\n\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# 7-Visualizing X-ray images "},{"metadata":{"trusted":true},"cell_type":"code","source":"\n### Reference https://www.kaggle.com/trungthanhnguyen0502/eda-vinbigdata-chest-x-ray-abnormalities \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    '''\n    new_shape = tuple([int(x / downscale_factor) for x in data.shape])\n    data = cv2.resize(data, (new_shape[1], new_shape[0]))\n    '''\n    return data\n        \n    \ndef plot_img(img, size=(7, 7), is_rgb=True, title=\"\", cmap='gray'):\n    plt.figure(figsize=size)\n    plt.imshow(img, cmap=cmap)\n    plt.suptitle(title)\n    plt.show()\n\n\ndef plot_imgs(imgs, cols=4, size=7, is_rgb=True, title=\"\", cmap='gray', img_size=None): #(500,500)\n    rows = len(imgs)//cols + 1\n    fig = plt.figure(figsize=(cols*size, rows*size))\n    for i, img in enumerate(imgs):\n        if img_size is not None:\n            img = cv2.resize(img, img_size)\n        fig.add_subplot(rows, cols, i+1)\n        plt.imshow(img, cmap=cmap)\n    plt.suptitle(title)\n    #plt.show()\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#dicom_paths = glob.glob(primary_dir+'/train/*.dicom')\ndicom_paths = [primary_dir + '/train/'+train_csv['image_id'][x]+'.dicom' for x in range(4)]\nprint (dicom_paths)\nimgs = [dicom2array(path) for path in dicom_paths[:4]]\nplot_imgs(imgs, size=9)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"### not sure if we need this.\n#imgs = [exposure.equalize_hist(img) for img in imgs]\n#plot_imgs(imgs)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"imgs = []\nimg_ids = train_csv_good['image_id'].values\nclass_ids = train_csv_good['class_id'].unique()\n\n# map label_id to specify color\nlabel2color = {class_id:[randint(0,255) for i in range(3)] for class_id in class_ids}\nthickness = 3\nscale = 5\n\n\nfor i in range(8):\n    img_id = random.choice(img_ids)\n    img_path = primary_dir+f'/train/{img_id}.dicom'\n    img = dicom2array(path=img_path)\n    img = cv2.resize(img, None, fx=1/scale, fy=1/scale)\n    img = np.stack([img, img, img], axis=-1)\n    \n    boxes = train_csv_good.loc[train_csv_good['image_id'] == img_id, ['x_min', 'y_min', 'x_max', 'y_max']].values/scale\n    labels = train_csv_good.loc[train_csv_good['image_id'] == img_id, ['class_id']].values.squeeze()\n    \n    for label_id, box in zip(labels, boxes):\n        color = label2color[label_id]\n        img = cv2.rectangle(\n            img,\n            (int(box[0]), int(box[1])),\n            (int(box[2]), int(box[3])),\n            color, thickness\n    )\n        \n    img = cv2.resize(img, (500,500))\n    imgs.append(img)\n    \nplot_imgs(imgs, size = 9, cmap=None)\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# 8-Merging boxes\n\n[Follwing this notebook\n](https://www.kaggle.com/sreevishnudamodaran/vinbigdata-fusing-bboxes-coco-dataset)"},{"metadata":{"trusted":true},"cell_type":"code","source":"print('Number of total good annotations', len(train_csv_good['image_id']))\nprint('Number of unique image with good annotations', len(train_csv_good['image_id'].unique()))\nprint ('Original data including NO findings',  len(train_csv), len(train_csv['image_id'].unique()))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"!pip install ensemble_boxes\n#https://github.com/ZFTurbo/Weighted-Boxes-Fusion\nfrom ensemble_boxes import nms, weighted_boxes_fusion\nfrom path import Path\nfrom collections import Counter\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\niou_thr = 0.5\nskip_box_thr = 0.0001\nfinal_images = []\nsigma = 0.1\n\nthickness = 3 \nscale = 5\n\n\n\ntrain_csv_good['image_path_dicom'] = train_csv_good['image_id'].map(lambda x:os.path.join(primary_dir + '/train', str(x)+'.dicom'))\nimage_paths = train_csv_good['image_path_dicom'].unique()\n\n\nfor i, path in enumerate(image_paths[4:8]):\n    #print (path)\n    img_array = dicom2array(path=path)\n    img_basename = Path(path).stem\n    print (img_basename)\n    img_annotations = train_csv_good[train_csv_good.image_id==img_basename]\n    \n    \n    ### plotting the image before merging the boxes\n    \n    boxes_before = img_annotations[['x_min', 'y_min', 'x_max', 'y_max']].to_numpy().tolist()\n    labels_before = img_annotations['class_id'].to_numpy().tolist()\n    \n    \n    img_array = np.stack([img_array, img_array, img_array], axis=-1)\n\n    img_before = img_array.copy()\n    for box, label in zip(boxes_before, labels_before):\n        color = label2color[int(label)]\n        img_before = cv2.rectangle(img_before,\\\n                                   (int(box[0]), int(box[1])), (int(box[2]), int(box[3])),\\\n                                   color = color, thickness =10)\n\n    \n    img_before = cv2.resize(img_before, (500,500))\n    final_images.append(img_before)\n    ##########################\n    ### Start meging now After\n    ##########\n    '''\n    # from the github repo. ---https://github.com/ZFTurbo/Weighted-Boxes-Fusion\n    boxes, scores, labels = weighted_boxes_fusion(boxes_list, scores_list, labels_list, weights=weights, iou_thr=iou_thr, skip_box_thr=skip_box_thr)\n    \n    \n        \n    boxes_list = [[\n    [0.00, 0.51, 0.81, 0.91],\n    [0.10, 0.31, 0.71, 0.61],\n    [0.01, 0.32, 0.83, 0.93],\n    [0.02, 0.53, 0.11, 0.94],\n    [0.03, 0.24, 0.12, 0.35],\n    ],[\n    [0.04, 0.56, 0.84, 0.92],\n    [0.12, 0.33, 0.72, 0.64],\n    [0.38, 0.66, 0.79, 0.95],\n    [0.08, 0.49, 0.21, 0.89],\n    ]]\n    scores_list = [[0.9, 0.8, 0.2, 0.4, 0.7], [0.5, 0.8, 0.7, 0.3]]\n    labels_list = [[0, 1, 0, 1, 1], [1, 1, 1, 0]]\n    weights = [2, 1]\n\n    iou_thr = 0.5\n    skip_box_thr = 0.0001\n    sigma = 0.1\n    \n    '''\n    boxes_list = []\n    scores_list = []\n    labels_list = []\n    weights = []\n    \n    ### when no need to merge as we have only one box\n    boxes_single = []\n    labels_single = []\n    \n    unique_classes = img_annotations['class_id'].unique().tolist()\n    count_classes = Counter(img_annotations['class_id'].tolist())\n\n    for cls in unique_classes:       \n        ## when there is only one box --- no need to do anything\n        if count_classes[cls]==1:\n            labels_single.append(cls)\n            boxes_single.append(img_annotations[img_annotations.class_id==cls][['x_min', 'y_min', 'x_max', 'y_max']].to_numpy().squeeze().tolist())\n        ### multiple boxes then do merging based on iou\n        else:\n            cls_list = img_annotations[img_annotations.class_id==cls]['class_id'].tolist()\n            labels_list.append(cls_list)\n            bbox = img_annotations[img_annotations.class_id==cls][['x_min', 'y_min', 'x_max', 'y_max']].to_numpy()\n        \n            ## remember to normalize the bbox for image size\n        \n            bbox = bbox/(img_array.shape[1], img_array.shape[0], img_array.shape[1], img_array.shape[0])\n            ## the github code needs boxes_list relative to image size \n\n            bbox = np.clip(bbox, 0, 1)\n            boxes_list.append(bbox.tolist())\n            scores_list.append(np.ones(len(cls_list)).tolist())\n            ## weights are meanignless here if we are using just one method to fuse the boxes\n            weights.append(1)\n            \n\n    # Perform the fusion now\n    boxes, scores, box_labels= weighted_boxes_fusion(boxes_list, scores_list, labels_list, weights=weights,\n                                                     iou_thr=iou_thr, skip_box_thr=skip_box_thr)\n    \n    # rescale boxes back to normal\n    boxes = boxes*(img_array.shape[1], img_array.shape[0], img_array.shape[1], img_array.shape[0])\n    boxes = boxes.round(1).tolist()\n    box_labels = box_labels.astype(int).tolist()\n\n    boxes.extend(boxes_single)\n    box_labels.extend(labels_single)\n    \n    \n    ## Visualize Bboxes after operation\n    img_after = img_array.copy()\n    for box, label in zip(boxes, box_labels):\n        color = label2color[int(label)]\n        img_after = cv2.rectangle(img_after,\\\n                                   (int(box[0]), int(box[1])), (int(box[2]), int(box[3])),\\\n                                   color = color, thickness =10)\n\n    img_after = cv2.resize(img_after, (500,500))\n\n    final_images.append(img_after)\n\n    \nplot_imgs(final_images, size=9,)\nplt.figtext(0.20, 0.9,\" Before WBF\", va=\"top\", ha=\"center\", size=25)\nplt.figtext(0.60, 0.9,\"Before WBF\", va=\"top\", ha=\"center\", size=25)\n\nplt.figtext(0.40, 0.9,\"After WBF\", va=\"top\", ha=\"center\", size=25)\nplt.figtext(0.80, 0.9,\"After WBF\", va=\"top\", ha=\"center\", size=25)\n\nplt.show()\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Next steps\n- understand the bounding box statistics more carefully. Look for the skewness in them \n- Get rid of overlapping bounding boxes. \n- MaskRCNN for making the bounding boxes \n- Faster RCNN + FPN for training the images with findings\n- Train 2 class with resnet34\n- combine both the results from the traning \n"},{"metadata":{"trusted":true},"cell_type":"code","source":"# https://www.kaggle.com/c/vinbigdata-chest-xray-abnormalities-detection/discussion/212287\ndef iou_calculator(bbox_1, bbox_2):\n    ## overlap area/total area\n    ### determine the edges of the overlap\n    x_left = max(bbox_1[0], bbox_2[0])\n    y_top = max(bbox_1[1], bbox_2[1])\n    x_right = min(bbox_1[2], bbox_2[2])\n    y_bottom = min(bbox_1[3], bbox_2[3])\n    # do the boxes overlap???\n    \n    if x_right < x_left or y_bottom < y_top:\n        return 0.0\n    else:\n        overlap_area = (x_right - x_left) * (y_bottom - y_top)\n        bbox_1_area = (bbox_1[2] - bbox_1[0]) * (bbox_1[3] - bbox_1[1])\n        bbox_2_area = (bbox_2[2] - bbox_2[0]) * (bbox_2[3] - bbox_2[1])\n        \n        iou = overlap_area / float(bbox_1_area + bbox_2_area - overlap_area)\n        return iou","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"'''\nImage preprocessing \nUsing this https://github.com/sneddy/pneumothorax-segmentation\n\nalbu.Compose([\n    albu.HorizontalFlip(),\n    albu.OneOf([\n        albu.RandomContrast(),\n        albu.RandomGamma(),\n        albu.RandomBrightness(),\n        ], p=0.3),\n    albu.OneOf([\n        albu.ElasticTransform(alpha=120, sigma=120 * 0.05, alpha_affine=120 * 0.03),\n        albu.GridDistortion(),\n        albu.OpticalDistortion(distort_limit=2, shift_limit=0.5),\n        ], p=0.3),\n    albu.ShiftScaleRotate(),\n    albu.Resize(img_size,img_size,always_apply=True),\n])\n'''","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"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}