{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Global Wheat Detection\n\n## Competition Problem\n- In this competition, we'll detect wheat heads from outdoor images of wheat plants, including wheat datasets from around the globe. Using worldwide data, you will focus on a generalized solution to estimate the number and size of wheat heads. To better gauge the performance for unseen genotypes, environments, and observational conditions, the training dataset covers multiple regions. \n\n- We will use more than 3,000 images from Europe (France, UK, Switzerland) and North America (Canada). The test data includes about 1,000 images from Australia, Japan, and China.","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"## What am I predicting?\n- We are attempting to predict bounding boxes around each wheat head in images that have them. If there are no wheat heads, you must predict no bounding boxes.","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"![Wheat Heads](https://storage.googleapis.com/kaggle-media/competitions/UofS-Wheat/descriptionimage.png)","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"# Import Libraries","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport seaborn as sns\nimport matplotlib.pyplot as plt\nimport cv2\nplt.style.use(\"seaborn\")\n\nimport matplotlib.patches as patches\nfrom glob import glob\nfrom PIL import Image","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#check the contents of the main directory\n!ls ../input/global-wheat-detection","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#check the count of images in the train direcory\n!ls ../input/global-wheat-detection/train | wc -l","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"- There are 3422 images in the train folder taken from Europe and North America.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"#before we start reading the data, create path variables for convience\nfolder_path = '../input/global-wheat-detection/'\nTRAIN_IMAGES_PATH = folder_path + 'train/'\nTEST_IMAGES_PATH = folder_path + 'test/'\nTRAIN_CSV = folder_path + 'train.csv'","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Reading Data\n- Read the train csv file","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"#read the data\ntrain_df = pd.read_csv(TRAIN_CSV)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Basic Statistical Analysis.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"#get the shape of the dataset\ntrain_df.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#count the number of images in each directory using Glob function\n\ntrain_glob = glob(TRAIN_IMAGES_PATH + '*')\ntest_glob = glob(TEST_IMAGES_PATH + '*')\n\nprint(\"Number of images in the train directory is {}\".format(len(train_glob)))\nprint(\"Number of images in the test directory is {}\".format(len(test_glob)))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"- Most of the test set images are hidden. We got only 10 samples of test data to check if our model is working fine without any errors. ","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"#check if all the images have bounding boxes or not. Check the unique number of images in the train data with bounding boxes.\n\nunique_count = len(train_df[\"image_id\"].unique())\nprint(\"Number of unique images in the train dataset: {}\".format(unique_count))\nprint(\"Number of images without bounding boxes is: {}\".format(len(train_glob) - unique_count)) ","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"- Out of 3422 images, 49 images doesn't have a bounding boxes that mean there are no wheat heads in these images.\n- So we need to add these images to the train csv so that the model can learn these specific cases where there are no wheat heads.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"#validate the size of the image. check width and height is equal to 1024\n\n(train_df[\"width\"] == train_df[\"height\"]).all()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#check the number of sources in the train data\n\nlen(train_df[\"source\"].unique())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df[\"source\"].value_counts(normalize = True).plot(kind = \"barh\")\nplt.title(\"Distribution of images from different sources\")\nplt.xlabel(\"Percentage\")\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Total Observations:\n- Train folder has 3422 images in total, taken from Europe and North America.\n- Test folder has only 10 images. Most of the test data is hidden but organisers said that the hidden test data includes about 1,000 images from Australia, Japan, and China.\n- Out of 3422 images, 49 images doesn't have a bounding boxes that mean there are no wheat heads in these images.\n- So we need to add these images to the train csv so that the model can learn these specific cases where there are no wheat heads.\n- All the images have the same size: 1024 x 1024.\n- There are 7 uniques sources of data.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"#Number of bounding box for each image - check the value counts\n\ntrain_df[\"image_id\"].value_counts().nlargest(5)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"- The maximum number of bounding box for one image is 116 while the minumum bounding box is 1 in the image.","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"## Extract Bounding Box data\n- Bounding box data is stored in [xmin,ymin,width,height] format","execution_count":null},{"metadata":{"_kg_hide-output":true,"trusted":true},"cell_type":"code","source":"#create a new dataframe to store bounding box info\ntrain_bbox_df = train_df[[\"image_id\"]]\ntrain_bbox_df[\"source\"] = train_df[\"source\"]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def extract_bbox(bbox_data):\n    \"\"\"Extract bbox data\"\"\"\n    \n    bbox_data = bbox_data.strip(\"[\").strip(\"]\").split(\",\")\n    bbox_xmin = float(bbox_data[0])\n    bbox_ymin = float(bbox_data[1])\n    bbox_xmax = float(bbox_data[0]) + float(bbox_data[2])\n    bbox_ymax = float(bbox_data[1]) + float(bbox_data[3])\n    bbox_w = float(bbox_data[2])\n    bbox_h = float(bbox_data[3])\n    \n    return bbox_xmin, bbox_ymin, bbox_xmax, bbox_ymax, bbox_w, bbox_h","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-output":true,"trusted":true},"cell_type":"code","source":"#extract the bounding box data\ntrain_bbox_df[\"bbox_xmin\"],train_bbox_df[\"bbox_ymin\"], train_bbox_df[\"bbox_xmax\"], train_bbox_df[\"bbox_ymax\"],train_bbox_df[\"bbox_w\"], train_bbox_df[\"bbox_h\"] = zip(*train_df[\"bbox\"].map(extract_bbox))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"- We know that there 49 images without any bounding boxes, so we will add those images also to the dataframe.","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"Display function taken and modified from [GlobalWheatDetection EDA](https://www.kaggle.com/aleksandradeis/globalwheatdetection-eda)","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"#function to display the images\n\ndef get_all_bboxes(df, image_id):\n    image_bboxes = df[df.image_id == image_id]\n    \n    bboxes = []\n    for _,row in image_bboxes.iterrows():\n        bboxes.append((row.bbox_xmin, row.bbox_ymin, row.bbox_w, row.bbox_h))\n    return bboxes\n\ndef plot_image_samples(df, rows=3, cols=3, title='Image examples', bln_bbox = True, bln_save = False):\n    fig, axs = plt.subplots(rows, cols, figsize=(10,10))\n    for row in range(rows):\n        for col in range(cols):\n            idx = np.random.randint(len(df), size=1)[0]\n            img_id = df.iloc[idx].image_id\n            img = Image.open(TRAIN_IMAGES_PATH + img_id + '.jpg')\n            axs[row, col].imshow(img)\n            \n            if bln_bbox == True:                \n                bboxes = get_all_bboxes(df, img_id)\n                for bbox in bboxes:\n                    rect = patches.Rectangle((bbox[0],bbox[1]),bbox[2],bbox[3],linewidth=1,edgecolor='r',facecolor='none')\n                    axs[row, col].add_patch(rect)\n            \n            axs[row, col].axis('off')\n            \n    plt.suptitle(title)\n    if bln_save == True:\n        plt.savefig('sample.png', dpi=200)\n    ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#compute the bounding box area\n\ntrain_bbox_df[\"area\"] = train_bbox_df[\"bbox_w\"] * train_bbox_df[\"bbox_h\"]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_bbox_df.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Exploratory Data Analysis\n- Plot the images from different sources and analyze them.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"#plot images without bounding boxes\n\nplot_image_samples(train_bbox_df, bln_bbox = False, rows = 3, cols = 3, title = \"sample images\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#with bounding box\nplot_image_samples(train_bbox_df, bln_bbox = True, rows = 3, cols = 3, title = \"Image examples with bounding boxes\", bln_save = True)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Images from **usask_1**","execution_count":null},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"#plot images without bounding boxes\nplot_image_samples(train_bbox_df.loc[train_bbox_df[\"source\"] == \"usask_1\"], bln_bbox = True, rows = 3, cols = 3, title = \"Images from `usask_1'\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Images from arvalis_1","execution_count":null},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"#plot images without bounding boxes\nplot_image_samples(train_bbox_df.loc[train_bbox_df[\"source\"] == \"arvalis_1\"], bln_bbox = True, rows = 3, cols = 3, title = \"Images from `arvalis_1'\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Images from inrae_1","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"#plot images without bounding boxes\nplot_image_samples(train_bbox_df.loc[train_bbox_df[\"source\"] == \"inrae_1\"], bln_bbox = True, rows = 3, cols = 3, title = \"Images from `inrae_1'\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Images from ethz_1","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"#plot images without bounding boxes\nplot_image_samples(train_bbox_df.loc[train_bbox_df[\"source\"] == \"ethz_1\"], bln_bbox = True, rows = 3, cols = 3, title = \"Images from `ethz_1'\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Analyzing the bounding boxes\n- Analysis based on the area.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"train_bbox_df.area.value_counts().nlargest(5)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#basic stats of the area\ntrain_bbox_df[\"area\"].describe()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#boxplot to find out any large bounding boxes\nfig, ax = plt.subplots(ncols= 2, figsize = (14,6))    \n\n#boxplot for comparison\nsns.boxplot(y = \"area\", data = train_bbox_df, ax=ax[0])\nax[0].set_title(\"Box plot of bounding box area to analyze abnormal sizes\")\n\n#distribution plot\nax[1].set_title(\"Distribution of bounding box area\")\nax[1].set_ylabel(\"Frequency\")\nsns.distplot(a = train_bbox_df[\"area\"], ax=ax[1], kde=False, bins = 150)\n\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"- The maximum area of the bounding box is `529788` and minimum area is `2`.\n- Both maximum and minimum area indicates an abnormality, needs to be investigated.\n- But 75% of the bounding boxes have an area less than 8300 units.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"#from the boxplot we can see that they are 3 instances where the bounding box area is more than 300,000.\ntrain_bbox_df.loc[train_bbox_df[\"area\"] > 300000]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plot_image_samples(train_bbox_df.loc[train_bbox_df[\"area\"] > 300000], title = \"Images where bounding boxes area is more than 300,000\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# we will look at all the data in the outliers\nplot_image_samples(train_bbox_df.loc[train_bbox_df[\"area\"] > 100000], title = \"Images where bounding boxes area is more than 100,000\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# we will look at all the data in the outliers\nplot_image_samples(train_bbox_df.loc[train_bbox_df[\"area\"] > 100000], title = \"Images where bounding boxes area is more than 100,000\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Observations:**\n* The color of the pictures (wheat heads) are very different from each color. Model needs to robust enough to account for these.\n* Color(Brightness) mostly depends on the source of the image. Region of the image and when the photo was taken. (During hot climate?)\n* Since these images are taken vertically, we can use different augmentation techniques like flip/rotation.\n* Many of the smaller bounding boxes are overlapping with each other.\n* The larger bounding boxes are not very clean. Lot of noise has been captured inside the bounding boxes along with the wheat heads. We need to think whether we need to include these bounding box data into the model.","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"## References\n- [GlobalWheatDetection EDA](https://www.kaggle.com/aleksandradeis/globalwheatdetection-eda)","execution_count":null}],"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}