{"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":"### **download external packages**","metadata":{}},{"cell_type":"code","source":"HELPER_DIR = '/kaggle/input/pydicom-conda-helper/'\n\n!conda install {HELPER_DIR+'libjpeg-turbo-2.1.0-h7f98852_0.tar.bz2'} -c conda-forge -y -q\n!conda install {HELPER_DIR+'libgcc-ng-9.3.0-h2828fa1_19.tar.bz2'} -c conda-forge -y -q\n!conda install {HELPER_DIR+'gdcm-2.8.9-py37h500ead1_1.tar.bz2'} -c conda-forge -y -q\n!conda install {HELPER_DIR+'conda-4.10.1-py37h89c1867_0.tar.bz2'} -c conda-forge -y -q\n!conda install {HELPER_DIR+'certifi-2020.12.5-py37h89c1867_1.tar.bz2'} -c conda-forge -y -q\n!conda install {HELPER_DIR+'openssl-1.1.1k-h7f98852_0.tar.bz2'} -c conda-forge -y -q","metadata":{"execution":{"iopub.status.busy":"2021-06-17T08:40:31.698377Z","iopub.execute_input":"2021-06-17T08:40:31.698945Z","iopub.status.idle":"2021-06-17T08:41:43.208953Z","shell.execute_reply.started":"2021-06-17T08:40:31.698817Z","shell.execute_reply":"2021-06-17T08:41:43.207546Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **import dependencies**","metadata":{}},{"cell_type":"code","source":"import os\nimport shutil\nimport numpy as np \nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport cv2\nimport PIL\nimport pydicom\n\nimport tensorflow as tf\nfrom tensorflow.keras.applications.vgg16 import preprocess_input, VGG16\n\nfrom collections import Counter\nfrom pathlib import Path\nfrom tqdm.auto import tqdm","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2021-06-17T08:41:49.42412Z","iopub.execute_input":"2021-06-17T08:41:49.424461Z","iopub.status.idle":"2021-06-17T08:41:54.962359Z","shell.execute_reply.started":"2021-06-17T08:41:49.424426Z","shell.execute_reply":"2021-06-17T08:41:54.961231Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **configuration and initialization**","metadata":{}},{"cell_type":"code","source":"SIIM_COVID19_DETECTION_DIR = '/kaggle/input/siim-covid19-detection/'\nPART1_DIR = '/kaggle/input/part1-siim-covid19-model-image-yolov5/'\nPART2_DIR = '/kaggle/input/part2-siim-covid19-model-study-vgg16/'\nWORKING_DIR = '/kaggle/working/'\n\nINPUT_DIR = SIIM_COVID19_DETECTION_DIR+'test/'\n\nTEMP_DIR = '/kaggle/temp/'\nOUTPUT_DIR = TEST_DIR = '/kaggle/temp/test/'\n\nYOLOV5_DIR = PART1_DIR+'yolov5/yolov5/'\nVGG16_DIR = PART2_DIR+'vgg16/'\n\nRESULT_NAME = 'inference'\nDETECT_DIR = 'runs/detect/'+RESULT_NAME+'/labels/'\n\nSAMPLE_SUBMISSION_PATH = SIIM_COVID19_DETECTION_DIR+'sample_submission.csv'\n\n\nIMG_SIZE = WIDTH = HEIGHT = 512\nINTERPOLATION = cv2.INTER_LANCZOS4\nN_IMAGE_TO_VISUALIZE = 25","metadata":{"execution":{"iopub.status.busy":"2021-06-17T08:41:54.964205Z","iopub.execute_input":"2021-06-17T08:41:54.964572Z","iopub.status.idle":"2021-06-17T08:41:54.970319Z","shell.execute_reply.started":"2021-06-17T08:41:54.964539Z","shell.execute_reply":"2021-06-17T08:41:54.968817Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"os.makedirs(OUTPUT_DIR, exist_ok=True)","metadata":{"execution":{"iopub.status.busy":"2021-06-17T08:41:54.97268Z","iopub.execute_input":"2021-06-17T08:41:54.973139Z","iopub.status.idle":"2021-06-17T08:41:54.997538Z","shell.execute_reply.started":"2021-06-17T08:41:54.973092Z","shell.execute_reply":"2021-06-17T08:41:54.996239Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **load submission file and split df study/image**","metadata":{}},{"cell_type":"code","source":"df_submission = pd.read_csv(SAMPLE_SUBMISSION_PATH)\n\ndf_submission_study = df_submission.loc[df_submission.id.str.contains('_study')].copy().reset_index(drop=True)\ndf_submission_image = df_submission.loc[df_submission.id.str.contains('_image')].copy().reset_index(drop=True)","metadata":{"execution":{"iopub.status.busy":"2021-06-17T08:41:55.000179Z","iopub.execute_input":"2021-06-17T08:41:55.001444Z","iopub.status.idle":"2021-06-17T08:41:55.038353Z","shell.execute_reply.started":"2021-06-17T08:41:55.001402Z","shell.execute_reply":"2021-06-17T08:41:55.037423Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **get path dicom files**","metadata":{}},{"cell_type":"code","source":"path_dicom_files = []\n\ntotal = sum([len(f) for r, d, f in os.walk(INPUT_DIR)])\n\nwith tqdm(total=total) as pbar:\n    for dirname, _, filenames in os.walk(INPUT_DIR):\n        for file in filenames:\n            path_dicom_files.append(Path(os.path.join(dirname, file)))\n            pbar.update(1)","metadata":{"execution":{"iopub.status.busy":"2021-06-17T08:41:55.040029Z","iopub.execute_input":"2021-06-17T08:41:55.040426Z","iopub.status.idle":"2021-06-17T08:42:00.099532Z","shell.execute_reply.started":"2021-06-17T08:41:55.040382Z","shell.execute_reply":"2021-06-17T08:42:00.098371Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **rescale all test images and save to jpg / save original width and height**","metadata":{}},{"cell_type":"code","source":"df_submission_image.loc[:,\"width\"] = np.nan\ndf_submission_image.loc[:,\"height\"] = np.nan\n\n\nfor p in tqdm(path_dicom_files):\n    dcm = pydicom.dcmread(p)\n    img = dcm.pixel_array\n    img_name = p.parts[-1][0:-4]\n    \n    index = df_submission_image[df_submission_image['id'].str.contains(img_name)].index\n    df_submission_image.loc[index, ['width']] = img.shape[0]\n    df_submission_image.loc[index, ['height']] = img.shape[1]\n\n    if dcm.PhotometricInterpretation == \"MONOCHROME1\":\n        img = cv2.bitwise_not(img)\n    img = cv2.normalize(img, None, 0, 255, cv2.NORM_MINMAX, dtype=cv2.CV_8U)\n    img = cv2.resize(img, (WIDTH, HEIGHT), interpolation = INTERPOLATION)\n    \n    cv2.imwrite(OUTPUT_DIR+img_name+'.jpg', img)","metadata":{"execution":{"iopub.status.busy":"2021-06-17T08:42:00.101076Z","iopub.execute_input":"2021-06-17T08:42:00.101493Z","iopub.status.idle":"2021-06-17T08:47:20.450056Z","shell.execute_reply.started":"2021-06-17T08:42:00.101447Z","shell.execute_reply":"2021-06-17T08:47:20.448907Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **visualize N sample images (optional)**","metadata":{}},{"cell_type":"code","source":"\"\"\"import plotly.express as px\nimport plotly.graph_objects as go\nfrom plotly.subplots import make_subplots\nfrom skimage import io\nfrom skimage.transform import rotate\n\nN_ROWS = N_COLUMNS = int(np.ceil(np.sqrt(N_IMAGE_TO_VISUALIZE)))\nSIZE_LAYOUT = int(IMG_SIZE*N_ROWS/3.3)\n\nfig = make_subplots(rows=N_ROWS, cols=N_COLUMNS,horizontal_spacing = 0.01,vertical_spacing = 0.01)\n\nfor i, file in enumerate(os.listdir(OUTPUT_DIR)[0:N_IMAGE_TO_VISUALIZE],1):\n    \n    row=int(np.ceil(i/N_ROWS))\n    col=int(i-(row-1)*N_COLUMNS)\n    img = rotate(io.imread(OUTPUT_DIR+file, as_gray=True),angle=180)\n    fig.add_trace(go.Heatmap(z=img, colorscale='gray',showscale=False), row, col)\n    \nfig.update_xaxes(showticklabels=False)\nfig.update_yaxes(showticklabels=False)\nfig.update_layout(height=SIZE_LAYOUT,width=SIZE_LAYOUT, showlegend=False)\nfig.show()\n#fig.write_image(TEMP_DIR+\"visualization_\"+str(N_IMAGE_TO_VISUALIZE)+\".jpeg\")\"\"\"","metadata":{"_kg_hide-output":true,"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-06-17T08:47:20.451655Z","iopub.execute_input":"2021-06-17T08:47:20.451976Z","iopub.status.idle":"2021-06-17T08:47:20.463615Z","shell.execute_reply.started":"2021-06-17T08:47:20.451938Z","shell.execute_reply":"2021-06-17T08:47:20.462768Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **object detection image with yoloV5 pretrained**","metadata":{}},{"cell_type":"code","source":"YOLOV5_WEIGHTS_PATH = YOLOV5_DIR+'weights/best.pt'\nYOLOV5_DETECT_PATH = YOLOV5_DIR+'detect.py'\n\n!python {YOLOV5_DETECT_PATH}    --weights {YOLOV5_WEIGHTS_PATH} \\\n                                --source {OUTPUT_DIR} \\\n                                --img {IMG_SIZE} \\\n                                --conf 0.21 \\\n                                --iou-thres 0.5 \\\n                                --max-det 4 \\\n                                --name {RESULT_NAME} \\\n                                --save-txt \\\n                                --save-conf \\\n                                --nosave","metadata":{"_kg_hide-output":true,"scrolled":true,"execution":{"iopub.status.busy":"2021-06-17T08:47:20.466029Z","iopub.execute_input":"2021-06-17T08:47:20.46631Z","iopub.status.idle":"2021-06-17T08:51:21.241689Z","shell.execute_reply.started":"2021-06-17T08:47:20.466282Z","shell.execute_reply":"2021-06-17T08:51:21.240479Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **convert results .txt to df submission image**","metadata":{}},{"cell_type":"code","source":"def correct_bbox_format(bboxes):\n    correct_bboxes = []\n    for b in bboxes:\n        xc, yc = int(np.round(b[0]*IMG_SIZE)), int(np.round(b[1]*IMG_SIZE))\n        w, h = int(np.round(b[2]*IMG_SIZE)), int(np.round(b[3]*IMG_SIZE))\n\n        xmin = xc - int(np.round(w/2))\n        ymin = yc - int(np.round(h/2))\n        xmax = xc + int(np.round(w/2))\n        ymax = yc + int(np.round(h/2))\n        \n        correct_bboxes.append([xmin, ymin, xmax, ymax])\n        \n    return correct_bboxes\n\ndef scale_bboxes_to_original(row, bboxes):\n    # Get scaling factor\n    scale_x = IMG_SIZE/row.width\n    scale_y = IMG_SIZE/row.height\n    \n    scaled_bboxes = []\n    for bbox in bboxes:\n        xmin, ymin, xmax, ymax = bbox\n        \n        xmin = int(np.round(xmin/scale_x))\n        ymin = int(np.round(ymin/scale_y))\n        xmax = int(np.round(xmax/scale_x))\n        ymax = int(np.round(ymax/scale_y))\n        \n        scaled_bboxes.append([xmin, ymin, xmax, ymax])\n\n\ndef get_conf_bboxes(file_path):\n    confidence = []\n    bboxes = []\n    with open(file_path, 'r') as file:\n        for line in file:\n            preds = line.strip('\\n').split(' ')\n            preds = list(map(float, preds))\n            confidence.append(preds[-1])\n            bboxes.append(preds[1:-1])\n    return confidence, bboxes","metadata":{"execution":{"iopub.status.busy":"2021-06-17T08:51:21.246089Z","iopub.execute_input":"2021-06-17T08:51:21.246452Z","iopub.status.idle":"2021-06-17T08:51:21.257895Z","shell.execute_reply.started":"2021-06-17T08:51:21.246407Z","shell.execute_reply":"2021-06-17T08:51:21.257069Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"results = os.listdir(DETECT_DIR)","metadata":{"execution":{"iopub.status.busy":"2021-06-17T08:51:21.2592Z","iopub.execute_input":"2021-06-17T08:51:21.259509Z","iopub.status.idle":"2021-06-17T08:51:21.273142Z","shell.execute_reply.started":"2021-06-17T08:51:21.25948Z","shell.execute_reply":"2021-06-17T08:51:21.271958Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"image_pred_strings = []\nfor i in tqdm(range(len(df_submission_image))):\n    row = df_submission_image.loc[i]\n    img_name = row.id[:-6]\n    \n    if f'{img_name}.txt' in results:\n        confidence, bboxes = get_conf_bboxes(f'{DETECT_DIR}/{img_name}.txt')\n        bboxes = correct_bbox_format(bboxes)\n        pred_string = ''\n        for j, conf in enumerate(confidence):\n            pred_string += f'opacity {conf:.6f} ' + ' '.join(map(str, bboxes[j])) + ' '\n        image_pred_strings.append(pred_string[:-1]) \n    else:\n        image_pred_strings.append(\"None 1 0 0 1 1\")","metadata":{"execution":{"iopub.status.busy":"2021-06-17T08:51:21.27443Z","iopub.execute_input":"2021-06-17T08:51:21.274698Z","iopub.status.idle":"2021-06-17T08:51:21.694325Z","shell.execute_reply.started":"2021-06-17T08:51:21.27467Z","shell.execute_reply":"2021-06-17T08:51:21.693563Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_submission_image['PredictionString'] = image_pred_strings\ndf_submission_image = df_submission_image.loc[:, ['id','PredictionString']]","metadata":{"execution":{"iopub.status.busy":"2021-06-17T08:51:21.69529Z","iopub.execute_input":"2021-06-17T08:51:21.695645Z","iopub.status.idle":"2021-06-17T08:51:21.706051Z","shell.execute_reply.started":"2021-06-17T08:51:21.695616Z","shell.execute_reply":"2021-06-17T08:51:21.705104Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **classification study with vgg16 pretrained**","metadata":{}},{"cell_type":"markdown","source":"**create df image with opacity dectect by yolov5**","metadata":{}},{"cell_type":"code","source":"df_image_opacity = df_submission_image.loc[~(df_submission_image['PredictionString'] == 'None 1 0 0 1 1')]\ndf_image_opacity = df_image_opacity.apply(lambda row: row.id.split('_')[0], axis=1)\ndf_image_opacity = df_image_opacity.reset_index(drop=True)\n\nprint(\"shape df_image_opacity : \",df_image_opacity.shape)\ndf_image_opacity.sample(1)","metadata":{"execution":{"iopub.status.busy":"2021-06-17T08:51:21.708671Z","iopub.execute_input":"2021-06-17T08:51:21.709076Z","iopub.status.idle":"2021-06-17T08:51:21.745483Z","shell.execute_reply.started":"2021-06-17T08:51:21.709044Z","shell.execute_reply":"2021-06-17T08:51:21.744391Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**create df study with path of images of the study**","metadata":{}},{"cell_type":"code","source":"df_study = df_submission_study.copy().drop('PredictionString', axis=1)\ndf_study['id'] = df_study.apply(lambda row: row.id.split('_')[0], axis=1)\ndf_study['paths_image'] = df_study.apply(lambda row: [], axis=1)\n\nfor p in tqdm(path_dicom_files):\n    study_name = p.parts[-3]\n    img_name = p.parts[-1][0:-4]\n    for index, row in df_study.iterrows():\n        if row.id == study_name:\n            df_study.loc[index, 'paths_image'].append(img_name+'.jpg')\n\nprint(\"shape df_study : \",df_study.shape)\ndf_study.sample(1)","metadata":{"execution":{"iopub.status.busy":"2021-06-17T08:51:21.746591Z","iopub.execute_input":"2021-06-17T08:51:21.746877Z","iopub.status.idle":"2021-06-17T08:53:22.525037Z","shell.execute_reply.started":"2021-06-17T08:51:21.746848Z","shell.execute_reply":"2021-06-17T08:53:22.523981Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**drop row in df study that dont have image with opacity**","metadata":{}},{"cell_type":"code","source":"with tqdm(total=len(df_study)) as pbar:\n    for index, row in df_study.iterrows():\n        paths_image = df_study.loc[index, 'paths_image']\n        if df_image_opacity.apply(lambda x: any([k[0:-4] in x for k in paths_image])).any():\n            df_study = df_study.drop(index)\n        pbar.update()\n\ndf_study = df_study.reset_index(drop=True)\n\nprint(\"shape df_study : \",df_study.shape)\ndf_study.sample(1)","metadata":{"execution":{"iopub.status.busy":"2021-06-17T08:53:22.526339Z","iopub.execute_input":"2021-06-17T08:53:22.526616Z","iopub.status.idle":"2021-06-17T08:53:23.988375Z","shell.execute_reply.started":"2021-06-17T08:53:22.526588Z","shell.execute_reply":"2021-06-17T08:53:23.987327Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**predictions study on VGG16**","metadata":{}},{"cell_type":"code","source":"MODEL_VGG16 = tf.keras.models.load_model(VGG16_DIR)\nIMG_SIZE_VGG16 = 224\n\nCLASSES = {\n    0: 'atypical 1 0 0 1 1',\n    1: 'indeterminate 1 0 0 1 1',\n    2: 'negative 1 0 0 1 1',\n    3: 'typical 1 0 0 1 1'\n }","metadata":{"execution":{"iopub.status.busy":"2021-06-17T08:53:23.989853Z","iopub.execute_input":"2021-06-17T08:53:23.990239Z","iopub.status.idle":"2021-06-17T08:53:28.150381Z","shell.execute_reply.started":"2021-06-17T08:53:23.990196Z","shell.execute_reply":"2021-06-17T08:53:28.149537Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def predict(path_file) :\n    img = tf.keras.preprocessing.image.load_img(path_file, target_size=(IMG_SIZE_VGG16, IMG_SIZE_VGG16), interpolation='lanczos')\n    img = tf.keras.preprocessing.image.img_to_array(img)\n    img = img.reshape((1, img.shape[0], img.shape[1], img.shape[2]))\n    img = preprocess_input(img)\n    predictions = MODEL_VGG16.predict(img)\n    predictions = np.argmax(predictions, axis=1)\n    return predictions[0] ","metadata":{"execution":{"iopub.status.busy":"2021-06-17T08:53:28.151626Z","iopub.execute_input":"2021-06-17T08:53:28.152235Z","iopub.status.idle":"2021-06-17T08:53:28.15959Z","shell.execute_reply.started":"2021-06-17T08:53:28.152181Z","shell.execute_reply":"2021-06-17T08:53:28.158376Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def study_predictions(paths_image):\n    predictions = []\n    for file_name in paths_image:\n        path_file = OUTPUT_DIR+file_name\n        predictions.append(predict(path_file))\n    \n    return CLASSES.get(Counter(predictions).most_common(1)[0][0])\n        \n\ndf_study['PredictionString'] = df_study['paths_image'].apply(study_predictions)\ndf_study = df_study.drop(columns=['paths_image'])\ndf_study['id'] = df_study.apply(lambda row: row.id+'_study', axis=1)\ndf_study.sample(5)","metadata":{"execution":{"iopub.status.busy":"2021-06-17T08:53:28.161102Z","iopub.execute_input":"2021-06-17T08:53:28.16148Z","iopub.status.idle":"2021-06-17T08:55:53.865764Z","shell.execute_reply.started":"2021-06-17T08:53:28.161439Z","shell.execute_reply":"2021-06-17T08:55:53.864791Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_study = df_study.merge(df_submission_study, on='id' , how='outer')\ndf_study = df_study.drop(columns=['PredictionString_y'])\ndf_study = df_study.rename(columns={'PredictionString_x':'PredictionString'})\ndf_study['PredictionString'] = df_study['PredictionString'].apply(lambda x: CLASSES.get(2) if pd.isnull(x) else x)\n\ndf_submission_study = df_study","metadata":{"execution":{"iopub.status.busy":"2021-06-17T08:55:53.866899Z","iopub.execute_input":"2021-06-17T08:55:53.867295Z","iopub.status.idle":"2021-06-17T08:55:53.891128Z","shell.execute_reply.started":"2021-06-17T08:55:53.867263Z","shell.execute_reply":"2021-06-17T08:55:53.890239Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **remove output runs, merge submission files then export**","metadata":{}},{"cell_type":"code","source":"!rm -r 'runs'","metadata":{"execution":{"iopub.status.busy":"2021-06-17T08:55:53.892108Z","iopub.execute_input":"2021-06-17T08:55:53.892477Z","iopub.status.idle":"2021-06-17T08:55:54.727452Z","shell.execute_reply.started":"2021-06-17T08:55:53.892449Z","shell.execute_reply":"2021-06-17T08:55:54.726398Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_submission = pd.concat([df_submission_image, df_submission_study], ignore_index=True)\ndf_submission.to_csv(WORKING_DIR+'submission.csv', index=False)","metadata":{"execution":{"iopub.status.busy":"2021-06-17T08:55:54.728708Z","iopub.execute_input":"2021-06-17T08:55:54.729226Z","iopub.status.idle":"2021-06-17T08:55:54.746386Z","shell.execute_reply.started":"2021-06-17T08:55:54.729183Z","shell.execute_reply":"2021-06-17T08:55:54.745388Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **ref**","metadata":{}},{"cell_type":"markdown","source":"\n* https://www.kaggle.com/xhlulu\n* https://www.kaggle.com/yujiariyasu\n* https://www.kaggle.com/ayuraj\n* https://www.kaggle.com/dschettler8845   \n....","metadata":{}}]}