{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Global Wheat Competitions EDA\n"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"_kg_hide-input":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\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        os.path.join(dirname, filename)\n\n# You can write up to 5GB 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":"","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# General Dataset Information\nThe dataset can help farmers knowing how their crops are growing. How close it is to harvest. \n"},{"metadata":{},"cell_type":"markdown","source":"Step 1: Importing Libraries and Datasets"},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nfrom glob import glob\nimport os\nfrom PIL import Image\nfrom matplotlib import patches\n\n\nfrom bokeh.models import ColumnDataSource, HoverTool, Panel\nfrom bokeh.models.widgets import Tabs\nfrom bokeh.plotting import figure\nfrom bokeh.io import output_notebook, show, output_file\n%matplotlib inline\nimport cv2\nfrom bokeh.resources import INLINE\nimport bokeh.io\nbokeh.io.output_notebook(INLINE) ","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":""},{"metadata":{"trusted":true},"cell_type":"code","source":"train_dir ='/kaggle/input/global-wheat-detection/train/'\ntest_dir = '../input/global-wheat-detection/test/'\ntrain_csv_path = '../input/global-wheat-detection/train.csv' ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from bokeh.resources import INLINE\nimport bokeh.io\n\nbokeh.io.output_notebook(INLINE)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train =pd.read_csv(train_csv_path)\ntrain.head()\n\ntrain_images = glob(train_dir+ '*')\ntest_images = glob(test_dir + '*')\nprint(\"The images in train images are \",len(train_images))\nprint(\"The images in test images are \",len(test_images))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"There are very few images for training and testing. We must use data augemntation for this."},{"metadata":{"trusted":true},"cell_type":"code","source":"train.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Step 2: In the dataframe, we have records of every patches of a single image. We have to add all the patches and make it a single image."},{"metadata":{"trusted":true},"cell_type":"code","source":"#train_images\nall_train_images = pd.DataFrame(i.split('/')[-1][:-4] for i in train_images)\nall_train_images.columns = ['image_id']\nall_train_images = all_train_images.merge(train,on = 'image_id',how='left')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"all_train_images.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"all_train_images['bbox'] = all_train_images['bbox'].fillna('[0,0,0,0]')\nbbox_items = all_train_images['bbox'].str.split(',',expand = True)\nall_train_images['bbox_xmin'] = bbox_items[0].str.strip('[').astype(float)\nall_train_images['bbox_ymin'] = bbox_items[1].str.strip(' ').astype(float)\nall_train_images['bbox_width'] = bbox_items[2].str.strip(' ').astype(float)\nall_train_images['bbox_height'] = bbox_items[3].str.strip(']').astype(float)\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"The DataFrame now contains the image id along with the grain patch x and y co-ordinate along with its width and height"},{"metadata":{"trusted":true},"cell_type":"code","source":"all_train_images","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(\"Images without heads is\",len(all_train_images)-len(train))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Step 3: Plot the images along with the patches to find the amount of grain in it.\n"},{"metadata":{},"cell_type":"markdown","source":"We create two function, one to get the coordinates of the patches and one to merge the image of the wheat along with its grain patches"},{"metadata":{"trusted":true},"cell_type":"code","source":"def get_all_boxes(df,image_id):\n    bboxes = []\n    image_bbox = df[df.image_id==image_id]\n    for _,rows in image_bbox.iterrows():\n        bboxes.append((rows.bbox_xmin,rows.bbox_ymin,rows.bbox_width,rows.bbox_height))\n        \n    return bboxes\n\ndef plot_image_examples(df,rows= 3,columns=3,title ='Image Examples'):\n    fig,axs = plt.subplots(rows,columns,figsize=(10,10))\n    for row in range(rows):\n        for col in range(columns):\n            idx = np.random.randint(len(df),size=1)[0]\n            img_id = df.iloc[idx].image_id\n            \n            img = Image.open(train_dir + img_id + '.jpg')\n            \n            axs[row,col].imshow(img)\n            \n            bboxes = get_all_boxes(df,img_id)\n            \n            for bbox in bboxes:\n                \n                rect = patches.Rectangle((bbox[0],bbox[1]),bbox[2],bbox[2],edgecolor='r',linewidth=1,facecolor='none')\n                axs[row,col].add_patch(rect)\n                \n            axs[row,col].axis('off')\n            \n    plt.suptitle(title)\n            \n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plot_image_examples(all_train_images)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"We can see images taken at different lightining conditions and different maturity stages.\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"all_train_images['width'].value_counts()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"   Step 4 We find about different features of the dataset by visualization"},{"metadata":{},"cell_type":"markdown","source":"Count numbers of bounding boxes"},{"metadata":{"trusted":true},"cell_type":"code","source":"all_train_images['counts'] = all_train_images.apply(lambda row: 1 if np.isfinite(row.width) else 0,axis =1)\ntrain_images_count = all_train_images.groupby('image_id').sum().reset_index()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_images_count","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"# See this article on how to plot bar charts with Bokeh:\n# https://towardsdatascience.com/interactive-histograms-with-bokeh-202b522265f3\ndef hist_hover(dataframe, column, colors=[\"#94c8d8\", \"#ea5e51\"], bins=30, title=''):\n    hist, edges = np.histogram(dataframe[column], bins = bins)\n    \n    hist_df = pd.DataFrame({column: hist,\n                             \"left\": edges[:-1],\n                             \"right\": edges[1:]})\n    hist_df[\"interval\"] = [\"%d to %d\" % (left, right) for left, \n                           right in zip(hist_df[\"left\"], hist_df[\"right\"])]\n\n    src = ColumnDataSource(hist_df)\n    plot = figure(plot_height = 400, plot_width = 600,\n          title = title,\n          x_axis_label = column,\n          y_axis_label = \"Count\")    \n    plot.quad(bottom = 0, top = column,left = \"left\", \n        right = \"right\", source = src, fill_color = colors[0], \n        line_color = \"#35838d\", fill_alpha = 0.7,\n        hover_fill_alpha = 0.7, hover_fill_color = colors[1])\n        \n    hover = HoverTool(tooltips = [('Interval', '@interval'),\n                              ('Count', str(\"@\" + column))])\n    plot.add_tools(hover)\n    \n    output_notebook()\n    show(plot)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"hist_hover(train_images_count,'counts','Number of wheat spikes per image')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"As we look at the plot,we find that most of the counts are in range 20-65."},{"metadata":{"trusted":true},"cell_type":"code","source":"#Lets plot some image with less number of count\nless_spikes = train_images_count[train_images_count['counts']<10].image_id","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plot_image_examples(all_train_images[all_train_images.image_id.isin(less_spikes)],title = 'Images with less spikes')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Observations:\n\nMost of the example have more ground\n\nMost of them are zoomed too much"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Plotting the images with highest spikes\nmore_spikes = train_images_count[train_images_count['counts']>100].image_id","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plot_image_examples(all_train_images[all_train_images.image_id.isin(more_spikes)],title= 'High number of Spikes')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"As you can observe the number of spikes are much higher"},{"metadata":{},"cell_type":"markdown","source":"Now we will calculate the area of bounding boxes"},{"metadata":{"trusted":true},"cell_type":"code","source":"all_train_images['bbox_area'] = all_train_images['bbox_width']*all_train_images['bbox_height']","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"hist_hover(all_train_images,'bbox_area',title ='Area of a single bounding box')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#The max area of bounding box\nmax(all_train_images['bbox_area'])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"The distribution of Area of bbox is in very wide range. Lets look at the highest bbox areas"},{"metadata":{"trusted":true},"cell_type":"code","source":"large_area = all_train_images[all_train_images['bbox_area'] >200000].image_id","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plot_image_examples(all_train_images[all_train_images.image_id.isin(large_area)],title = 'Large bbox area in a image')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"As you can see there are many anomally outliers in this images and they will cause a problem when we train, so its better to remove them"},{"metadata":{},"cell_type":"markdown","source":"Lets also check the images with small bbox area"},{"metadata":{"trusted":true},"cell_type":"code","source":"small_area = all_train_images[all_train_images['bbox_area']<50].image_id\nplot_image_examples(all_train_images[all_train_images.image_id.isin(small_area)],title='Small bbox area in images')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"    "},{"metadata":{"trusted":true},"cell_type":"code","source":"area_per_image = all_train_images.groupby(\"image_id\").sum().reset_index()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"area_per_image_percentage = area_per_image.copy()\narea_per_image_percentage['bbox_area'] = area_per_image['bbox_area']/(1024*1024)*100","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"area_per_image.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"area_per_image_percentage.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"This shows the plot of how much percentage of image area is covered by bbox"},{"metadata":{"trusted":true},"cell_type":"code","source":"hist_hover(area_per_image_percentage,'bbox_area',title ='Percentage of image covered by bbox')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"As per the plot, most of the percentage lies in between 18% to 36%\nWe have to check in with the lowest and the highest perecentage covered by bbox"},{"metadata":{"trusted":true},"cell_type":"code","source":"small_percentage = area_per_image_percentage[area_per_image_percentage['bbox_area']<8].image_id\nplot_image_examples(all_train_images[all_train_images.image_id.isin(small_percentage)],title='low area covered by bbox')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"high_percentage = area_per_image_percentage[area_per_image_percentage['bbox_area']>50].image_id\nplot_image_examples(all_train_images[all_train_images.image_id.isin(high_percentage)],title='high area covered by bbox')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Lets plot w.r.t to brightness"},{"metadata":{"trusted":true},"cell_type":"code","source":"def get_brightness(image):\n    \n    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)\n    \n    return np.array(gray).mean()\n    \ndef add_brightness(df):\n    \n    brightness = []\n    for _, row in df.iterrows():\n        img_id = row.image_id\n        image = cv2.imread(train_dir+img_id+'.jpg')\n        brightness.append(get_brightness(image))\n        \n    brightness_df = pd.DataFrame(brightness)\n    brightness_df.columns = ['brightness']\n    df = pd.concat([df,brightness_df],ignore_index = True,axis=1)\n    df.columns = ['image_id','brightness']\n    \n    return df\n\n\n\n\n    \n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"image_df = pd.DataFrame(all_train_images.image_id.unique())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"image_df.columns = ['image_id']","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"brightness_df = add_brightness(image_df)\n\nall_train_images = all_train_images.merge(brightness_df,on='image_id')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"hist_hover(all_train_images,'brightness',title ='Brightness in images')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":" All though, there is a peak the brightness ranges from to 116. Lets check out the outliers."},{"metadata":{"trusted":true},"cell_type":"code","source":"dark_ids = all_train_images[all_train_images['brightness']<25].image_id\nplot_image_examples(all_train_images[all_train_images.image_id.isin(dark_ids)],title='The image with low brightness')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"As you can see, Its harder for even humans to detect."},{"metadata":{"trusted":true},"cell_type":"code","source":"bright_ids = all_train_images[all_train_images['brightness']>130].image_id\nplot_image_examples(all_train_images[all_train_images.image_id.isin(bright_ids)],title='The image with high brightness')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"They are very different from the dark images"},{"metadata":{},"cell_type":"markdown","source":"Now,we should know that color represents a important part because it shows much far from harvest it is. If its Green it requires more time, If its brown, it have ground in them and if its Yellow, its ready to be harvested. "},{"metadata":{"trusted":true},"cell_type":"code","source":"def green_pixels(image):\n    img = cv2.cvtColor(image,cv2.COLOR_BGR2HSV)\n    \n    #Get the green mask. I got from \"https://stackoverflow.com/questions/47483951/how-to-define-a-threshold-value-to-detect-only-green-colour-objects-in-an-image\"\n    low =(40,40,40)\n    high = (70,255,255)\n    green_mask = cv2.inRange(img,low,high)\n    \n    return float( np.sum(green_mask))/255/(1024*1024)\n\ndef yellow_pixels(image):\n    img = cv2.cvtColor(image,cv2.COLOR_BGR2HSV)\n    low= (25,40,40)\n    high = (35,255,255)\n    yellow_mask = cv2.inRange(img,low,high)\n    \n    return float(np.sum(yellow_mask))/255/(1024*1024)\n\n\ndef add_green(df):\n    \n    brightness = []\n    for _, row in df.iterrows():\n        img_id = row.image_id\n        image = cv2.imread(train_dir+img_id+'.jpg')\n        brightness.append(green_pixels(image))\n        \n    brightness_df = pd.DataFrame(brightness)\n    brightness_df.columns = ['green_bright']\n    df = pd.concat([df,brightness_df],ignore_index = True,axis=1)\n    df.columns = ['image_id','green_bright']\n    \n    return df\n\ndef add_yellow(df):\n    \n    brightness = []\n    for _, row in df.iterrows():\n        img_id = row.image_id\n        image = cv2.imread(train_dir+img_id+'.jpg')\n        brightness.append(yellow_pixels(image))\n        \n    brightness_df = pd.DataFrame(brightness)\n    brightness_df.columns = ['yellow_bright']\n    df = pd.concat([df,brightness_df],ignore_index = True,axis=1)\n    df.columns = ['image_id','yellow_bright']\n    \n    return df\n\n\n    ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"green_pixels_df = add_green(image_df)\nall_train_images = all_train_images.merge(green_pixels_df,on='image_id')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Now lets plot on green color pixels\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"hist_hover(all_train_images,'green_bright',title ='Green Colors in images')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":""},{"metadata":{"trusted":true},"cell_type":"code","source":"green_ids = all_train_images[all_train_images['green_bright']>0.4].image_id\nplot_image_examples(all_train_images[all_train_images.image_id.isin(green_ids)],title='The image with high green color')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"The green color suggests that plant is grown near by and doesn't have that much spikes in it"},{"metadata":{"trusted":true},"cell_type":"code","source":"yellow_pixels_df = add_yellow(image_df)\nall_train_images = all_train_images.merge(yellow_pixels_df,on='image_id')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"hist_hover(all_train_images,'yellow_bright',title ='yellow Colors in images')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Lets see the images with high yellow color"},{"metadata":{"trusted":true},"cell_type":"code","source":"yellow_ids = all_train_images[all_train_images['yellow_bright']>0.55].image_id\nplot_image_examples(all_train_images[all_train_images.image_id.isin(yellow_ids)],title='The image with high yellow color')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"As you can see the images with high yellow pixels are ready to be harvest"},{"metadata":{},"cell_type":"markdown","source":"# Why Data Augementation is Important\n\nAs we can see the training image is very less and its then the model will Underfit, thats why we will use albumentation to create new images by augementing them"},{"metadata":{"trusted":true},"cell_type":"code","source":"import albumentations as al\nexample = al.Compose([\n    al.RandomSizedBBoxSafeCrop(512,512,erosion_rate=0.0,interpolation=1,p=1.0),\n    al.HorizontalFlip(p=0.5),\n    al.VerticalFlip(p=0.5),\n    al.OneOf([al.RandomContrast(),\n             al.RandomGamma(),\n             al.RandomBrightness()],p=1.0),\n    al.CLAHE(p=0.1)], p=1.0, bbox_params=al.BboxParams(format='coco', label_fields=['category_id']))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"def apply_transform(transforms,df,n_transforms=3):\n    idx = np.random.randint(len(df),size=1)[0]\n    bboxes = []\n    image_id = df.iloc[idx].image_id\n    image_bbox = df[df.image_id==image_id]\n    for _,rows in image_bbox.iterrows():\n        bboxes.append([rows.bbox_xmin,rows.bbox_ymin,rows.bbox_width,rows.bbox_height])\n        \n    \n\n\n            \n    img = Image.open(train_dir + image_id + '.jpg')\n            \n    fix,axs = plt.subplots(1,n_transforms+1,figsize=(15,7))\n            \n    axs[0].imshow(img)\n    axs[0].set_title(\"Original\")\n            \n    for bbox in bboxes:\n        \n        rect = patches.Rectangle((bbox[0],bbox[1]),bbox[2],bbox[3],edgecolor='r',linewidth=1,facecolor='none')\n        axs[0].add_patch(rect)\n                \n    # apply transforms n_transforms times\n    for i in range(n_transforms):\n        params = {'image': np.asarray(img),\n                  'bboxes': bboxes,\n                  'category_id': [1 for j in range(len(bboxes))]}\n        augmented_boxes = transforms(**params)\n        bboxes_aug = augmented_boxes['bboxes']\n        image_aug = augmented_boxes['image']\n\n        # plot the augmented image and augmented bounding boxes\n        axs[i+1].imshow(image_aug)\n        axs[i+1].set_title('augmented_' + str(i+1))\n        for bbox in bboxes_aug:\n            rect = patches.Rectangle((bbox[0],bbox[1]),bbox[2],bbox[3],linewidth=1,edgecolor='r',facecolor='none')\n            axs[i+1].add_patch(rect)\n    plt.show()\n            \n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"apply_transform(example,all_train_images,n_transforms=3)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"apply_transform(example,all_train_images,n_transforms=3)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Thus we conclude that these points are important for this Competition. I will update my notebook if I got any more ideas. If you like the, pls upvote :=>"},{"metadata":{},"cell_type":"markdown","source":""},{"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}