{"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":"code","source":"import os\nimport sys \nimport json\nimport glob\nimport random\nimport collections\nimport time\nimport re\nimport math\nimport numpy as np\nimport pandas as pd\nimport cv2\nimport random\n\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport pydicom\nfrom pydicom.pixel_data_handlers.util import apply_voi_lut\n\nfrom random import shuffle\nfrom sklearn import model_selection as sk_model_selection\n\nfrom tensorflow import keras\nfrom tensorflow.keras import layers\nfrom tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping, ReduceLROnPlateau\nfrom keras.metrics import AUC\n\nimport tensorflow as tf\n\nfrom skimage.metrics import structural_similarity as compare_ssim","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2021-09-28T04:57:17.18263Z","iopub.execute_input":"2021-09-28T04:57:17.183827Z","iopub.status.idle":"2021-09-28T04:57:24.756716Z","shell.execute_reply.started":"2021-09-28T04:57:17.18366Z","shell.execute_reply":"2021-09-28T04:57:24.754545Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data_directory = '../input/rsna-miccai-png'\nmri_types = ['FLAIR','T1w','T1wCE','T2w']\nIMAGE_SIZE = 256\nNUM_IMAGES = 128\ntrain_df = pd.read_csv(\"../input/rsna-miccai-brain-tumor-radiogenomic-classification/train_labels.csv\")\ntrain_df['BraTS21ID5'] = [format(x, '05d') for x in train_df.BraTS21ID]\ntrain_df = train_df.loc[train_df.BraTS21ID!=109]\ntrain_df = train_df.loc[train_df.BraTS21ID!=709]\ntrain_df = train_df.loc[train_df.BraTS21ID!=123]\ntrain_df = train_df.reset_index(drop=True)\ntrain_df.head(3)","metadata":{"execution":{"iopub.status.busy":"2021-09-28T04:57:24.758455Z","iopub.execute_input":"2021-09-28T04:57:24.758888Z","iopub.status.idle":"2021-09-28T04:57:24.833018Z","shell.execute_reply.started":"2021-09-28T04:57:24.758846Z","shell.execute_reply":"2021-09-28T04:57:24.831826Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Instead of feeding random N number of images of each patient to the model, we can feed images which contains the tumor. For that we need to first detect the tumor from the images.","metadata":{}},{"cell_type":"markdown","source":"## Tumor Detection using Opencv","metadata":{}},{"cell_type":"code","source":"from matplotlib import animation, rc\nrc('animation', html='jshtml')\n\ndef create_animation(ims):\n    fig = plt.figure()\n    plt.axis('off')\n    im = plt.imshow(ims[0], cmap=\"gray\")\n\n    def animate_func(i):\n        im.set_array(ims[i])\n        return [im]\n\n    return animation.FuncAnimation(fig, animate_func, frames = len(ims), interval = 1000//24)\n\ndef get_gray(org_img):\n    gray_img=cv2.cvtColor(org_img.copy(),cv2.COLOR_RGB2GRAY)\n    return gray_img\n\ndef get_RGB(gray_img):\n    rgb_img=cv2.cvtColor(gray_img.copy(),cv2.COLOR_GRAY2RGB)\n    return rgb_img\n\ndef get_threshold(org_img,blur=False,erode=False,dilate=False):\n    gray_img=get_gray(org_img.copy())\n    if blur:\n        img=cv2.GaussianBlur(gray_img.copy(), (5, 5), 0)\n    img=cv2.threshold(img,5,255,cv2.THRESH_BINARY)[1]\n    if erode:\n        img=cv2.erode(img, None, iterations=2)\n    if dilate:\n        img=cv2.dilate(img, None, iterations=2)\n    return img\n\ndef get_contours(th_img):\n    cnts,_ = cv2.findContours(th_img.copy(),cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)\n    return cnts\n   \ndef edge_smoothing(org_img,cnts):\n    gray_img=get_gray(org_img.copy())\n    if len(cnts)==0:  \n        return gray_img\n    c = max(cnts, key=cv2.contourArea)\n    black_img=np.zeros_like(gray_img)\n    black_cnt=cv2.drawContours(black_img.copy(),c,-1, (255, 255, 255), 2)\n    black_cnt=cv2.dilate(black_cnt.copy(), None, iterations=10)\n    white_cnt=cv2.bitwise_not(black_cnt.copy())\n    white_cnt=get_RGB(white_cnt)\n    smooth_img=cv2.bitwise_and(white_cnt.copy(),org_img.copy())\n    return smooth_img\n\ndef get_iou(bb1, bb2):\n    assert bb1[0] < bb1[2]\n    assert bb1[1] < bb1[3]\n    assert bb2[0] < bb2[2]\n    assert bb2[1] < bb2[3]\n    x_left = max(bb1[0], bb2[0])\n    y_top = max(bb1[1], bb2[1])\n    x_right = min(bb1[2], bb2[2])\n    y_bottom = min(bb1[3], bb2[3])\n    if x_right < x_left or y_bottom < y_top:\n        return 0.0\n\n    intersection_area = (x_right - x_left) * (y_bottom - y_top)\n    bb1_area = (bb1[2] - bb1[0]) * (bb1[3] - bb1[1])\n    bb2_area = (bb2[2] - bb2[0]) * (bb2[3] - bb2[1])\n    iou = intersection_area / float(bb1_area + bb2_area - intersection_area)\n    assert iou >= 0.0\n    assert iou <= 1.0\n    return iou\n\ndef check_overlapping(prev_cnt,curr_cnt):\n    x,y,w,h=cv2.boundingRect(prev_cnt)\n    bb1=[x,y,x+w,y+h]\n    x,y,w,h=cv2.boundingRect(curr_cnt)\n    bb2=[x,y,x+w,y+h]\n    iou=get_iou(bb1,bb2)\n    return iou\n    \n\ndef load_patient_images(path,threshold=False,roi_threshold=False,matchpattern=False,template_path=None):\n    t_paths = sorted(\n        glob.glob(os.path.join(path, \"*\")), \n        key=lambda x: int(x[:-4].split(\"-\")[-1]),\n    )\n    templates=[]\n    if not template_path is None:\n        for t_path in template_path:\n            templates.append(cv2.imread(t_path))\n    \n    images = []\n    for filename in t_paths:\n        data = cv2.imread(filename)\n        if data.max() == 0:\n            continue\n        images.append(data)\n    \n    mid_idx=len(images)//2\n    th_middle_image=get_threshold(images[mid_idx].copy(),blur=True,erode=True,dilate=True)\n    x1,y1,w1,h1=cv2.boundingRect(th_middle_image)\n    print('-->',x1,y1,w1,h1)\n    max_area=w1*h1\n    \n    images=np.array(images)\n    new_images=[]\n    if images[0].shape[0]<=256 or images[1].shape[0]<=256:\n        t_size=1\n    elif images[0].shape[0]>=500 or images[1].shape[0]>=500:\n        t_size=3\n    else:\n        t_size=2\n    print('text size: ',t_size)\n     \n    prev_cnt=0\n    initialize_prev_cnt=False\n    for i,data in enumerate(images):\n        th_data=get_threshold(data.copy(),blur=True,erode=True,dilate=True)\n        x,y,w,h=cv2.boundingRect(th_data)\n        area=w*h\n        ratio=area/max_area\n        if ratio<0.4:\n            continue\n            \n        org_cnts=get_contours(th_data.copy())\n        if org_cnts:\n            org_max = max(org_cnts, key=cv2.contourArea)\n            org_cnts_area=cv2.contourArea(org_max)\n        \n        if matchpattern:\n            image=data.copy()\n            comm_image=image.copy()\n            result=cv2.matchTemplate(image, template, cv2.TM_CCOEFF_NORMED)\n            (minVal, maxVal, minLoc, maxLoc) = cv2.minMaxLoc(result)\n            (startX, startY) = maxLoc\n            endX = startX + template.shape[1]\n            endY = startY + template.shape[0]\n        \n        if roi_threshold:\n            image=data.copy()\n            g_image=cv2.cvtColor(image.copy(),cv2.COLOR_BGR2GRAY)\n            thresh=g_image.mean()+((g_image.max()-g_image.mean())//3)\n            th_data=cv2.threshold(g_image,thresh,g_image.max(),cv2.THRESH_BINARY)[1]\n            g_image=cv2.putText(g_image,f\"{i}\",(20,25),3,1,(255,255,0),2) \n            data=np.hstack([g_image,th_data])   \n        \n        if threshold:\n            image=data.copy()  \n            \n            g_image=cv2.cvtColor(image.copy(),cv2.COLOR_BGR2GRAY)\n            mean_values=g_image[np.nonzero(g_image)]\n            thresh=mean_values.mean()+((mean_values.max()-mean_values.mean())//2)\n            smooth_image=edge_smoothing(image,org_cnts)\n            smooth_image=cv2.putText(smooth_image,f\"{i}\",(20,25),t_size,1,(thresh+1,thresh+1,thresh+1),2)\n            gray_smooth_image=get_gray(smooth_image)\n            \n            th_image=cv2.threshold(gray_smooth_image.copy(),thresh,g_image.max(),cv2.THRESH_BINARY)[1]\n            cnts,_ = cv2.findContours(th_image.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)\n            c = max(cnts, key=cv2.contourArea)\n            data=cv2.drawContours(image.copy(),c,-1, (0, 255, 255), 2)\n\n        new_images.append(data)        \n               \n    return new_images\n\ndef get_images(i,mri_type,threshold=False,roi_threshold=False,matchpattern=False,template_path=None):\n    patient_id=train_df['BraTS21ID5'][i]\n    mgmt=train_df['MGMT_value'][i]\n    path=f'{data_directory}/train/{patient_id}/{mri_type}'\n    print('Path: ',path)\n    print('MGMT: ',mgmt)\n    images=load_patient_images(path,threshold,roi_threshold,matchpattern,template_path)\n    print(np.array(images).shape)\n    return images","metadata":{"execution":{"iopub.status.busy":"2021-09-28T05:04:17.643368Z","iopub.execute_input":"2021-09-28T05:04:17.643804Z","iopub.status.idle":"2021-09-28T05:04:17.678078Z","shell.execute_reply.started":"2021-09-28T05:04:17.643768Z","shell.execute_reply":"2021-09-28T05:04:17.677274Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Play the video","metadata":{}},{"cell_type":"code","source":"i=80\nmri_type=mri_types[2]\nimages=get_images(i,mri_type,threshold=True)\ncreate_animation(images)","metadata":{"execution":{"iopub.status.busy":"2021-09-28T05:02:22.57088Z","iopub.execute_input":"2021-09-28T05:02:22.571257Z","iopub.status.idle":"2021-09-28T05:02:23.216765Z","shell.execute_reply.started":"2021-09-28T05:02:22.571223Z","shell.execute_reply":"2021-09-28T05:02:23.215584Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"i=40\nmri_type=mri_types[2]\nimages=get_images(i,mri_type,threshold=True)\ncreate_animation(images)","metadata":{"execution":{"iopub.status.busy":"2021-09-28T05:06:10.124144Z","iopub.execute_input":"2021-09-28T05:06:10.124567Z","iopub.status.idle":"2021-09-28T05:06:14.178393Z","shell.execute_reply.started":"2021-09-28T05:06:10.124531Z","shell.execute_reply":"2021-09-28T05:06:14.177019Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Data Pipeline ","metadata":{}},{"cell_type":"markdown","source":"### Image Resize with padding","metadata":{}},{"cell_type":"code","source":"fig=plt.figure(figsize=(15,15))\npath=glob.glob(f\"{data_directory}/train/00777/FLAIR/*.png\")\npath=sorted(path,key=lambda var:[int(x) if x.isdigit() else x for x in re.findall(r'[^0-9]|[0-9]+', var)])\nimg=cv2.imread(path[30])\norg_img=cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)\nimg=cv2.GaussianBlur(org_img, (5, 5), 0)\nplt.subplot(1,4,1)\nplt.imshow(img,cmap='gray')\n\nimg=cv2.threshold(img,30,255,cv2.THRESH_BINARY)[1]\nplt.subplot(1,4,2)\nplt.imshow(img,cmap='gray')\n\nimg=cv2.erode(img, None, iterations=2)\nplt.subplot(1,4,3)\nplt.imshow(img,cmap='gray')\n\nimg=cv2.dilate(img, None, iterations=2)\nplt.subplot(1,4,4)\nplt.imshow(img,cmap='gray')\n\ncv2.boundingRect(img)\nfig=plt.figure(figsize=(15,15))\nimg=cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE)\norg_img=cv2.rotate(org_img, cv2.ROTATE_90_CLOCKWISE)\ncnts,_ = cv2.findContours(img.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)\nc = max(cnts, key=cv2.contourArea)\nc_img=cv2.drawContours(img.copy(),c,-1, (0, 255, 255), 2)\nplt.subplot(1,4,1)\nplt.title('Roatate_90')\nplt.imshow(c_img,cmap='gray')\n\nx,y,w,h=cv2.boundingRect(c)\nimg_3ch=cv2.cvtColor(img.copy(),cv2.COLOR_GRAY2RGB)\nrect_c_img=cv2.rectangle(img_3ch.copy(),(x,y),(x+w,y+h),(0,255,255),2)\nplt.subplot(1,4,2)\nplt.title('Bounding Box')\nplt.imshow(rect_c_img,cmap='gray')\n\nnew_size=250\nif (w*h)/(img.shape[0]*img.shape[1])>0.10:\n    cropp_img=org_img[y:y+h,x:x+w]\n    print(cropp_img.shape,cropp_img.max())\n    resize_img=cv2.resize(cropp_img,(new_size,new_size))\n    \ndesired_size = 250\nim = cropp_img.copy()\nold_size = im.shape\nratio = float(desired_size)/max(old_size)\nnew_size = tuple([int(x*ratio) for x in old_size])\nim = cv2.resize(im, (new_size[1], new_size[0]))\nim2 = cv2.resize(im, (new_size[1], new_size[0]),interpolation=cv2.INTER_CUBIC)\nim3 = cv2.resize(im, (new_size[1], new_size[0]),interpolation=cv2.INTER_NEAREST)\ndelta_w = desired_size - new_size[1]\ndelta_h = desired_size - new_size[0]\ntop, bottom = delta_h//2, delta_h-(delta_h//2)\nleft, right = delta_w//2, delta_w-(delta_w//2)\ncolor = [0, 0, 0]\nnew_im = cv2.copyMakeBorder(im, top, bottom, left, right, cv2.BORDER_CONSTANT,value=color)\nnew_im2 = cv2.copyMakeBorder(im2, top, bottom, left, right, cv2.BORDER_CONSTANT,value=color)\nnew_im3 = cv2.copyMakeBorder(im3, top, bottom, left, right, cv2.BORDER_CONSTANT,value=color)\nfig=plt.figure(figsize=(15,15))\nplt.subplot(131)\nplt.title('Crop and Resize')\nplt.imshow(new_im,cmap='gray')\nplt.subplot(132)\nplt.title('Resize : INTER_CUBIC')\nplt.imshow(new_im2,cmap='gray')\nplt.subplot(133)\nplt.title('Resize : INTER_NEAREST')\nplt.imshow(new_im3,cmap='gray')","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def resize_padding(crop_img,desired_size,x,y,w,h):\n    \n    im = crop_img.copy()\n    old_size = im.shape\n    ratio = float(desired_size)/max(old_size)\n    new_size = tuple([int(x*ratio) for x in old_size])\n    im2 = cv2.resize(im, (new_size[1], new_size[0]),interpolation=cv2.INTER_CUBIC)\n    delta_w = desired_size - new_size[1]\n    delta_h = desired_size - new_size[0]\n    top, bottom = delta_h//2, delta_h-(delta_h//2)\n    left, right = delta_w//2, delta_w-(delta_w//2)\n    color = [0, 0, 0]\n    new_im2 = cv2.copyMakeBorder(im2, top, bottom, left, right, cv2.BORDER_CONSTANT,value=color)\n    return new_im2\n    \ndef crop_resize_img(img,desired_size):\n    \n    org_img=cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)\n    img=cv2.GaussianBlur(org_img.copy(), (5, 5), 0)\n    img=cv2.threshold(img,5,255,cv2.THRESH_BINARY)[1]\n    img=cv2.erode(img, None, iterations=2)\n    img=cv2.dilate(img, None, iterations=2)\n    x,y,w,h=cv2.boundingRect(img)\n    if (w*h)/(img.shape[0]*img.shape[1])<0.10:\n        return False,[]     \n    crop_img=org_img[y:y+h,x:x+w]\n    final_img=resize_padding(crop_img,desired_size,x,y,w,h)\n    return True,final_img\n\n    \ndef load_dicom_image(path, img_size=IMAGE_SIZE, voi_lut=False,rotate=0,rot_choice=None):\n    \n    data=cv2.imread(path)   \n    if rotate > 0:\n        print('yes')\n        data = cv2.rotate(data, rot_choice)\n    flag,data=crop_resize_img(data,img_size)\n    return flag,data\n\ndef load_dicom_images_3d(scan_id, num_imgs=NUM_IMAGES, img_size=IMAGE_SIZE, mri_type=\"FLAIR\", split=\"train\", rotate=0):\n\n    rot_choice=None\n    if rotate>0:\n        rot_choices = [cv2.ROTATE_90_CLOCKWISE, cv2.ROTATE_90_COUNTERCLOCKWISE, cv2.ROTATE_180]\n        rot_choice=random.choice(rot_choices)\n        \n    files = sorted(glob.glob(f\"{data_directory}/{split}/{scan_id}/{mri_type}/*.png\"), \n               key=lambda var:[int(x) if x.isdigit() else x for x in re.findall(r'[^0-9]|[0-9]+', var)])\n    \n    img3d=[]\n    for i,f in enumerate(files):\n        flag,data=load_dicom_image(f,rotate=rotate,rot_choice=rot_choice)\n        if not flag:\n            continue\n        if data.sum()==0:\n            continue\n        img3d.append(data)\n    img3d=np.array(img3d).T\n        \n    if img3d.shape[-1] > num_imgs:\n        diff = img3d.shape[-1] - num_imgs\n        half_diff = diff//2\n        p1 = half_diff\n        p2 = img3d.shape[-1]-half_diff\n        img3d=img3d[:,:,p1:p2]\n        if img3d.shape[-1]>num_imgs:\n            img3d=img3d[:,:,:num_imgs]\n            \n    if img3d.shape[-1] < num_imgs:\n        n_zero = np.zeros((img_size, img_size, num_imgs - img3d.shape[-1]))\n        img3d = np.concatenate((img3d,  n_zero), axis = -1)\n    \n        \n    if np.min(img3d) < np.max(img3d):\n        img3d = img3d - np.min(img3d)\n        img3d = img3d / np.max(img3d)\n            \n    img3d=img3d.astype('float32')\n    return np.expand_dims(img3d,0)\n\na = load_dicom_images_3d(\"00003\",rotate=0,mri_type=mri_types[2]) #200, 148\nprint(a.shape)\nprint(np.min(a), np.max(a), np.mean(a), np.median(a))\nimage = a[0]\nprint(\"Dimension of the CT scan is:\", image.shape)\nplt.imshow(np.squeeze(image[:, :, 50]), cmap=\"gray\")","metadata":{"execution":{"iopub.status.busy":"2021-09-28T05:06:40.086227Z","iopub.execute_input":"2021-09-28T05:06:40.086592Z","iopub.status.idle":"2021-09-28T05:06:41.581415Z","shell.execute_reply.started":"2021-09-28T05:06:40.086558Z","shell.execute_reply":"2021-09-28T05:06:41.580296Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"execution":{"iopub.status.busy":"2021-09-09T18:07:30.873696Z","iopub.execute_input":"2021-09-09T18:07:30.874107Z","iopub.status.idle":"2021-09-09T18:07:30.87892Z","shell.execute_reply.started":"2021-09-09T18:07:30.874071Z","shell.execute_reply":"2021-09-09T18:07:30.877764Z"},"trusted":true},"execution_count":null,"outputs":[]}]}