{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import time\nimport datetime\nimport numpy as np\nimport pydicom\nimport cv2\nimport os\nfrom pydicom.pixel_data_handlers.util import apply_voi_lut\nimport pandas as pd","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"!mkdir ./downsized\n!mkdir ./downsized/train\n!mkdir ./downsized/test","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"# get the current sizes of the images\nBASE_PATH = \"../input/vinbigdata-chest-xray-abnormalities-detection/\"\nftrain = os.listdir(BASE_PATH + 'train')\nftest = os.listdir(BASE_PATH + 'test')\n\nwidths = []\nheights = []\n\n# # only examine the first 500 images to avoid this taking forever\n# for i, file in enumerate(ftrain):\n#     dicom = pydicom.read_file(BASE_PATH + \"train/\" + file)\n#     data = apply_voi_lut(dicom.pixel_array, dicom)\n#     widths.append(data.shape[1])\n#     heights.append(data.shape[0])\n    \n#     if i > 500:\n#         break\n\n# print(\"Mean\", np.mean(heights), np.mean(widths))\n# print(\"Min\", np.min(heights), np.min(widths))\n# print(\"Max\", np.max(heights), np.max(widths))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# update the csv files\ndata = pd.read_csv(\"../input/vinbigdata-chest-xray-abnormalities-detection/train.csv\")\ndata.loc[data['class_name'] != 'No finding', 'x_min'] /= 2\ndata.loc[data['class_name'] != 'No finding', 'x_max'] /= 2\ndata.loc[data['class_name'] != 'No finding', 'y_min'] /= 2\ndata.loc[data['class_name'] != 'No finding', 'y_max'] /= 2\ndata.to_csv(\"downsized/train.csv\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\ndef read_xray(path, voi_lut = True, fix_monochrome = True, downscale_factor = 2):\n    dicom = pydicom.read_file(path)\n\n    # VOI LUT (if available by DICOM device) is used to 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\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\n    data = data - np.min(data)\n    data = data / np.max(data)\n    data = (data * 255.0).astype(np.uint8)\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\nfor i in range(len(ftrain)):\n    img = read_xray(BASE_PATH + 'train/'+ftrain[i])\n    cv2.imwrite('./downsized/train/'+ftrain[i].replace('.dicom','.jpg'), img)\n    if i % 500 == 0:\n        print(datetime.datetime.now(), i,\"out of\", len(ftrain))\n\nfor i in range(len(ftest)):\n    img = read_xray(BASE_PATH + 'test/'+ftest[i])\n    cv2.imwrite('./downsized/test/'+ftest[i].replace('.dicom','.jpg'), img)  ","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Write Data to COCO Format\n\nUsing code from https://www.kaggle.com/sreevishnudamodaran/vinbigdata-fusing-bboxes-coco-dataset\n\nThis code has been altered to include images with NO objects, whereas the original code only included images with objects."},{"metadata":{"trusted":true},"cell_type":"code","source":"!pip install ensemble_boxes","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"%matplotlib inline\n\nimport os\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nfrom matplotlib import rcParams\nsns.set(rc={\"font.size\":9,\"axes.titlesize\":15,\"axes.labelsize\":9,\n            \"axes.titlepad\":11, \"axes.labelpad\":9, \"legend.fontsize\":7,\n            \"legend.title_fontsize\":7, 'axes.grid' : False})\nimport cv2\nimport json\nimport pandas as pd\nimport glob\nimport os.path as osp\nfrom path import Path\nimport datetime\nimport numpy as np\nfrom tqdm.auto import tqdm\nimport random\nimport shutil\nfrom sklearn.model_selection import train_test_split\n\nfrom ensemble_boxes import *\nimport warnings\nfrom collections import Counter","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_annotations = pd.read_csv(\"downsized/train.csv\")\nlabel2color = [[0,0,0], [59, 238, 119], [222, 21, 229], [94, 49, 164], [206, 221, 133], [117, 75, 3],\n                 [210, 224, 119], [211, 176, 166], [63, 7, 197], [102, 65, 77], [194, 134, 175],\n                 [209, 219, 50], [255, 44, 47], [89, 125, 149], [110, 27, 100]]\n\nthickness = 3\nimgs = []","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"labels =  [\n            \"__ignore__\",\n            \"Aortic_enlargement\",\n            \"Atelectasis\",\n            \"Calcification\",\n            \"Cardiomegaly\",\n            \"Consolidation\",\n            \"ILD\",\n            \"Infiltration\",\n            \"Lung_Opacity\",\n            \"Nodule/Mass\",\n            \"Other_lesion\",\n            \"Pleural_effusion\",\n            \"Pleural_thickening\",\n            \"Pneumothorax\",\n            \"Pulmonary_fibrosis\"\n            ]\n\nnow = datetime.datetime.now()\n\ndata = dict(\n    info=dict(\n        description=None,\n        url=None,\n        version=None,\n        year=now.year,\n        contributor=None,\n        date_created=now.strftime('%Y-%m-%d %H:%M:%S.%f'),\n    ),\n    licenses=[dict(\n        url=None,\n        id=0,\n        name=None,\n    )],\n    images=[\n        # license, url, file_name, height, width, date_captured, id\n    ],\n    type='instances',\n    annotations=[\n        # segmentation, area, iscrowd, image_id, bbox, category_id, id\n    ],\n    categories=[\n        # supercategory, id, name\n    ],\n)\n\nclass_name_to_id = {}\nfor i, each_label in enumerate(labels):\n    class_id = i - 1  # starts with -1\n    class_name = each_label\n    class_name_to_id[class_name] = class_id\n    data['categories'].append(dict(\n        supercategory=None,\n        id=class_id,\n        name=class_name,\n    ))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_output_dir = \"./data/train_images\"\nval_output_dir = \"./data/val_images\"\n\nif not osp.exists(train_output_dir):\n    os.makedirs(train_output_dir)\n    print('Coco Train Image Directory:', train_output_dir)\n    \nif not osp.exists(val_output_dir):\n    os.makedirs(val_output_dir)\n    print('Coco Val Image Directory:', val_output_dir)\n    \nwarnings.filterwarnings(\"ignore\", category=UserWarning)    ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"## Setting the output annotations json file path\ntrain_out_file = './downsized/train_annotations.json'\n\ndata_train = data.copy()\ndata_train['images'] = []\ndata_train['annotations'] = []\n\niou_thr = 0.5\nskip_box_thr = 0.0001\nviz_images = []\n\nfor i, path in tqdm(enumerate(os.listdir(\"downsized/train\"))):\n    img_array  = cv2.imread(os.path.join(\"downsized\", \"train\", path))\n    image_basename = Path(path).stem\n    \n    \n    ## Add Images to annotation\n    data_train['images'].append(dict(\n        license=0,\n        url=None,\n        file_name=os.path.join(path),\n        height=img_array.shape[0],\n        width=img_array.shape[1],\n        date_captured=None,\n        id=i\n    ))\n    \n    img_annotations = train_annotations[train_annotations.image_id==image_basename]\n    boxes_viz = img_annotations[['x_min', 'y_min', 'x_max', 'y_max']].to_numpy().tolist()\n    labels_viz = img_annotations['class_id'].to_numpy().tolist()\n    \n    boxes_list = []\n    scores_list = []\n    labels_list = []\n    weights = []\n    \n    boxes_single = []\n    labels_single = []\n\n    cls_ids = img_annotations['class_id'].unique().tolist()\n    \n    count_dict = Counter(img_annotations['class_id'].tolist())\n\n    for cid in cls_ids:\n        ## Performing Fusing operation only for multiple bboxes with the same label\n        if count_dict[cid]==1:\n            labels_single.append(cid)\n            boxes_single.append(img_annotations[img_annotations.class_id==cid][['x_min', 'y_min', 'x_max', 'y_max']].to_numpy().squeeze().tolist())\n\n        else:\n            cls_list =img_annotations[img_annotations.class_id==cid]['class_id'].tolist()\n            labels_list.append(cls_list)\n            bbox = img_annotations[img_annotations.class_id==cid][['x_min', 'y_min', 'x_max', 'y_max']].to_numpy()\n            \n            ## Normalizing Bbox by Image Width and Height\n            bbox = bbox/(img_array.shape[0], img_array.shape[1], img_array.shape[0], img_array.shape[1])\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.append(1)\n    \n    ## Perform WBF\n    boxes, scores, box_labels = weighted_boxes_fusion(boxes_list=boxes_list, scores_list=scores_list,\n                                                  labels_list=labels_list, weights=weights,\n                                                  iou_thr=iou_thr, skip_box_thr=skip_box_thr)\n    \n    boxes = boxes*(img_array.shape[0], img_array.shape[1], img_array.shape[0], img_array.shape[1])\n    boxes = boxes.round(1).tolist()\n    box_labels = box_labels.astype(int).tolist()\n    boxes.extend(boxes_single)\n    box_labels.extend(labels_single)\n    \n    img_after = img_array.copy()\n    for box, label in zip(boxes, box_labels):\n        x_min, y_min, x_max, y_max = (box[0], box[1], box[2], box[3])\n        if str(x_min) != 'nan':\n            bbox =[\n                    round(x_min, 1),\n                    round(y_min, 1),\n                    round((x_max-x_min), 1),\n                    round((y_max-y_min), 1)\n                    ]\n            area = (bbox[2] * bbox[3])\n            data_train['annotations'].append(dict( id=len(data_train['annotations']), image_id=i,\n                                                category_id=int(label), area=area, bbox=bbox,\n                                                iscrowd=0))\n\nwith open(train_out_file, 'w') as f:\n    json.dump(data_train, f, indent=4)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"## create COCO file for test data\nnow = datetime.datetime.now()\n\ndata = dict(\n    info=dict(\n        description=None,\n        url=None,\n        version=None,\n        year=now.year,\n        contributor=None,\n        date_created=now.strftime('%Y-%m-%d %H:%M:%S.%f'),\n    ),\n    licenses=[dict(\n        url=None,\n        id=0,\n        name=None,\n    )],\n    images=[\n        # license, url, file_name, height, width, date_captured, id\n    ],\n    type='instances',\n    annotations=[\n        # segmentation, area, iscrowd, image_id, bbox, category_id, id\n    ],\n    categories=[\n        # supercategory, id, name\n    ],\n)\n\nclass_name_to_id = {}\nfor i, each_label in enumerate(labels):\n    class_id = i - 1  # starts with -1\n    class_name = each_label\n    class_name_to_id[class_name] = class_id\n    data['categories'].append(dict(\n        supercategory=None,\n        id=class_id,\n        name=class_name,\n    ))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"for i, path in enumerate(os.listdir(\"downsized/test\")):\n    image = cv2.imread(os.path.join(\"downsized\", \"test\", path))\n    \n    data['images'].append({\"id\": i, \"file_name\": path, \"height\": image.shape[0], \"width\": image.shape[1], \"license\": 0, \"url\": None})\n\nwith open(\"downsized/test_annotations.json\", \"w\") as f:\n    f.write(json.dumps(data))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# zip the results\n!zip -rq dataset.zip ./downsized/\n!rm -rf downsized/","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}