{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import os\nimport cv2\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\nimport matplotlib.pyplot as plt\nimport pydicom as dicom","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df=pd.read_csv('/kaggle/input/vinbigdata-chest-xray-abnormalities-detection/train.csv')\nclass_name=list(np.unique(train_df['class_name']))\nprint(f'The total number of classes is {len(class_name)}')\nprint('Five random rows of training dataframe train_df are shown below. ')\ntrain_df.sample(5)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class_sample_counts=train_df.groupby(['class_name','class_id']).size().reset_index().rename(columns={0:'count'})\nclass_sample_counts.sort_values(by='class_id',inplace=True)\nclass_sample_counts","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(15,5))\nsns.set(font_scale = 1.5)\ng=sns.barplot(x='class_name',y='count',data=class_sample_counts)\ng=g.set_xticklabels(g.get_xticklabels(), rotation=90)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Preprocessing data"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df_abnormal=train_df[train_df['class_id']!=14].reset_index(drop=True)\ntrain_df_abnormal","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df_abnormal['height']=train_df_abnormal['x_max']-train_df_abnormal['x_min']\ntrain_df_abnormal['width']=train_df_abnormal['y_max']-train_df_abnormal['y_min']\ntrain_df_abnormal['area']=train_df_abnormal['width']*train_df_abnormal['height']\ntrain_df_abnormal","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class_wise_area=train_df_abnormal.groupby(['class_name','class_id'])['area'].mean().reset_index()\nclass_wise_area","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(train_df_abnormal['area'].min())\nprint(train_df_abnormal['area'].max())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(15,5))\nsns.set(font_scale = 1.5)\ng=sns.barplot(x='class_name',y='area',data=class_wise_area)\ng=g.set_xticklabels(g.get_xticklabels(), rotation=90)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df_abnormal","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Find wrong annotation (Area size less than size 5000 )\ntrain_df_abnormal_pruned = train_df_abnormal[train_df_abnormal['area'] > 5000].reset_index(drop=True)\ntrain_df_abnormal_pruned.drop(['class_name','rad_id','height','width','area'],axis=1,inplace=True)\ntrain_df_abnormal_pruned","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Preprocessing image "},{"metadata":{},"cell_type":"markdown","source":"The Xray images are preprocessed and cropped based on a bounding box detected around lungs. "},{"metadata":{"trusted":true},"cell_type":"code","source":"from skimage import morphology, io, color, exposure, img_as_float, transform\n\n# Load lung segmentation model\n\nfrom keras.models import load_model\nmodel_name = '../input/lungsegmentation-model/trained_model.hdf5'\nUNet = load_model(model_name) \n#https://github.com/imlab-uiip/lung-segmentation-2d.git\n\ndef preprocess_for_segmentation(img,im_shape):\n    img = transform.resize(img, im_shape)\n    img = exposure.equalize_hist(img)\n    img = np.expand_dims(img, -1)\n    X = np.array(img)\n    y = np.array(img)\n    X -= X.mean()\n    X /= X.std()\n    return X\n\ndef preprocessing_pixel_values(dicom_image):\n    pixel_data = dicom_image.pixel_array   \n    pi = dicom_image['PhotometricInterpretation'].value\n    if pi == 'RGB':\n        pixel_data = cv2.cvtColor(pixel_data,cv2.COLOR_RGB2GRAY)\n\n    pixel_data = (pixel_data - pixel_data.min()) / (pixel_data.max() - pixel_data.min())\n    if pi == 'MONOCHROME1':    \n        pixel_data = np.abs(np.max(pixel_data)- pixel_data)\n    xray_image=np.asarray(pixel_data*255,np.uint8)    \n    return xray_image\n\ndef removal_of_white_text(img):\n    ret,image=cv2.threshold(img,250,255,cv2.THRESH_TOZERO_INV)\n    return image\n\ndef find_cropping_area(xray_image,seg_model):\n    # inputs: @xray_image preprocessed dicom image @seg_model The segmentation model \n    # returns:@pr prediction of segmentation model \n        #@(x1,y1) left top point of the crop area\n        #@(x2,y2) bottom right point of the crop area\n    \n    \n    im_shape = (256, 256) # of the segmentation model \n    width_scale=xray_image.shape[1]/256 # width-scaling factor for resize\n    height_scale=xray_image.shape[0]/256 # height-scaling factor for resize\n    # The scaling factors are later used to find the cropping region for original image size\n    \n    img=preprocess_for_segmentation(xray_image,im_shape) # preprocessing the Xray image for segmentation\n    inp_shape=img.shape \n    X=np.expand_dims(img, axis=0)\n    pred = seg_model.predict(X)[..., 0].reshape(inp_shape[:2]) #predicted segmentation \n    \n    # find bounding box around the two lungs\n    ret,pr=cv2.threshold(pred,0.95,1,cv2.THRESH_BINARY)\n    kernel = np.ones((3, 3), np.uint8) \n    pr=np.array(pr*255,dtype=np.uint8)\n    pr = cv2.morphologyEx(pr, cv2.MORPH_OPEN, kernel,iterations = 3)\n    pr_canny=cv2.Canny(pr,170,255)\n    cnts = cv2.findContours(pr_canny,cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)\n    cntsSorted = sorted(cnts[0], key=lambda x: cv2.contourArea(x), reverse=True)\n    x_c=[]\n    y_c=[]\n    b=0\n    for i in range(len(cntsSorted)):\n            x,y,w,h = cv2.boundingRect(cntsSorted[i])\n            x_c.append(x)\n            x_c.append(x+w)\n            y_c.append(y)\n            y_c.append(y+h)\n    w=max(x_c)-min(x_c)    \n    crp_p1=(max([min(x_c)-w//6,0]),max([min(y_c)-w//10,0]))\n    crp_p2=(min([max(x_c)+w//6,pr.shape[0]]),min([max(y_c)+w//5,pr.shape[1]]))\n    # the crop area is scaled to the original image size\n    x1=int(crp_p1[0]*width_scale)\n    y1=int(crp_p1[1]*height_scale)\n    x2=int(crp_p2[0]*width_scale)\n    y2=int(crp_p2[1]*height_scale)\n    pr=cv2.cvtColor(pr,cv2.COLOR_GRAY2RGB)\n    \n    cv2.rectangle(pr,(min(x_c),min(y_c)),(max(x_c),max(y_c)), (255, 0, 0), 1)\n    cv2.rectangle(pr,crp_p1,crp_p2, (0, 255, 0), 2)\n    return pr,(x1,y1),(x2,y2)\n\ndef crop_image_and_box(xray_image,pt1,pt2):  \n    #input @xray_image=input image (output from function preprocessing_pixel_values(dicom_image))\n    #output @xray_image_cropped=cropped image\n        #@b_pt1=left top point of the bounding box\n        #@b_pt2=right left point of the bounding box\n        \n    xray_image=removal_of_white_text(xray_image)\n    pr,c_pt1,c_pt2=find_cropping_area(xray_image,UNet)     \n    \n    ## Check if the bounding box lies inside crop region\n    \n    if pt1[0]<c_pt1[0]:  # if x_min of bounding box lies outside crop area\n        cropx_min=pt1[0]\n    else:\n        cropx_min=c_pt1[0]\n        \n    if pt1[1]<c_pt1[1]: # if y_min of bounding box lies outside crop area\n        cropy_min=pt1[1]\n    else:\n        cropy_min=c_pt1[1]\n    nc_pt1=(cropx_min,cropy_min)\n   \n    if pt2[0]>c_pt2[0]:  # if x_max bottom right corner lies outside crop area\n        cropx_max=pt2[0]\n    else:\n        cropx_max=c_pt2[0]\n        \n    if pt2[1]>c_pt2[1]: # if y_max bottom right corner lies outside crop area\n        cropy_max=pt2[1]\n    else:\n        cropy_max=c_pt2[1]  \n    nc_pt2=(cropx_max,cropy_max)  \n    \n    width=nc_pt2[0]-nc_pt1[0]\n    height=nc_pt2[1]-nc_pt1[1]\n    bias=0\n    #print(width)\n    #print(height)\n    if width>height:\n        #print('Check')\n        bias=(width-height)   \n    xray_image_cropped=xray_image[nc_pt1[1]:nc_pt2[1]+bias,nc_pt1[0]:nc_pt2[0]]\n    \n    box_x_new=pt1[0]-nc_pt1[0]\n    box_y_new=pt1[1]-nc_pt1[1]\n    box_x1_new=pt2[0]-nc_pt1[0]\n    box_y1_new=pt2[1]-nc_pt1[1]       \n    b_pt1=(box_x_new,box_y_new)\n    b_pt2=(box_x1_new,box_y1_new)\n    \n    return pr,xray_image_cropped,b_pt1,b_pt2","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Plot the cropped region of randomly selected X-ray"},{"metadata":{"trusted":true},"cell_type":"code","source":"\nr=np.random.randint(low=0,high=len(train_df_abnormal_pruned),size=1)\n#r=[6352]\ntrain_folder='/kaggle/input/vinbigdata-chest-xray-abnormalities-detection/train'\ndicom_image=dicom.dcmread(os.path.join(train_folder,train_df_abnormal_pruned['image_id'][r[0]])+'.dicom') \nbox_x=int(train_df_abnormal['x_min'][r[0]])\nbox_y=int(train_df_abnormal['y_min'][r[0]])\nbox_x1=int(train_df_abnormal['x_max'][r[0]])\nbox_y1=int(train_df_abnormal['y_max'][r[0]])\npt1=(box_x,box_y)\npt2=(box_x1,box_y1)\nxray_image=preprocessing_pixel_values(dicom_image)\npr1,xray_image_cropped, pt1_new,pt2_new=crop_image_and_box(xray_image,pt1,pt2)\n\nplt.subplots(1,3,figsize=(20,5))\nplt.subplot(1, 3, 1)\nplt.title('Original Image:  '+ train_df_abnormal['class_name'][r[0]])\ncv2.rectangle(xray_image,pt1,pt2,(0,255,0),10)\nplt.imshow(xray_image, cmap='gray')\n\nplt.subplot(1, 3, 2)\nplt.title('Segmentation output')\nplt.imshow(pr1, cmap='gray')\n\nplt.subplot(1,3,3)\nplt.title('Cropped mage with bounding box')\ncv2.rectangle(xray_image_cropped,pt1_new,pt2_new, (0, 0, 0), 10)\ng=plt.imshow(xray_image_cropped,'gray')\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}