{"cells":[{"metadata":{},"cell_type":"markdown","source":"## Global Wheat Detection: Can you help identify wheat heads using image analysis?\n\n> Open up your pantry and you’re likely to find several wheat products. Indeed, your morning toast or cereal may rely upon this common grain. Its popularity as a food and crop makes wheat widely studied. To get large and accurate data about wheat fields worldwide, plant scientists use image detection of \"wheat heads\"—spikes atop the plant containing grain. These images are used to estimate the density and size of wheat heads in different varieties. Farmers can use the data to assess health and maturity when making management decisions in their fields.\n\n![](https://storage.googleapis.com/kaggle-media/competitions/UofS-Wheat/descriptionimage.png)\n\n> However, accurate wheat head detection in outdoor field images can be visually challenging. There is often overlap of dense wheat plants, and the wind can blur the photographs. Both make it difficult to identify single heads. Additionally, appearances vary due to maturity, color, genotype, and head orientation. Finally, because wheat is grown worldwide, different varieties, planting densities, patterns, and field conditions must be considered. Models developed for wheat phenotyping need to generalize between different growing environments. Current detection methods involve one- and two-stage detectors (Yolo-V3 and Faster-RCNN), but even when trained with a large dataset, a bias to the training region remains."},{"metadata":{},"cell_type":"markdown","source":">In this competition, you’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. You 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."},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import os\nimport cv2\nimport glob\nimport pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport seaborn as sns","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"!ls ../input/global-wheat-detection","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"data_dir = '../input/global-wheat-detection'","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train = pd.read_csv(f'{data_dir}/train.csv')\ntrain.sample(10)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"> The CSV data is simple - the image ID matches up with the filename of a given image, and the width and height of the image are included, along with a bounding box. There is a row in train.csv for each bounding box. Not all images have bounding boxes."},{"metadata":{"trusted":true},"cell_type":"code","source":"print(\"Shape of train.csv: \", train.shape)\nprint(\"Unique image_ids in train.csv: \", len(train.image_id.unique()))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Since there is a row for each bounding box in train.csv, the shape is `147793` but when we consider just the unique image_ids, the number reduces down to `3373`.\nNow let's take a look at the images present in `train` folder"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_images = glob.glob(f'{data_dir}/train/*')\nlen(train_images), train_images[0]","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"There are `3422` images in `train` folder, but the number of unique image_ids in `train.csv` is just `3373`. This means that there are images in train-folder which doesn't have any kind of wheat present in it. Let's take a look at some of the images with bouding box plotted on them"},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"def overlay_box(im, box, rgb, stroke=1):\n    \"\"\"\n    Method to overlay single box on image\n\n    \"\"\"\n    # --- Convert coordinates to integers\n    box = box[1:-1].split(',')\n    box = [float(b) for b in box]\n    box = [int(b) for b in box]\n    \n    # --- Extract coordinates\n    x1, y1, width, height = box # xmin, ymin, width, height\n    y2 = y1 + height\n    x2 = x1 + width\n\n    im[y1:y1 + stroke, x1:x2] = rgb\n    im[y2:y2 + stroke, x1:x2] = rgb\n    im[y1:y2, x1:x1 + stroke] = rgb\n    im[y1:y2, x2:x2 + stroke] = rgb\n\n    return im","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"def draw_bbox(image, bbox):\n    for box in bbox:\n        rgb = np.floor(np.random.rand(3) * 1024).astype('int')\n        image = overlay_box(im=image, box=box, rgb=rgb, stroke=6)\n    return image","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"fig=plt.figure(figsize=(25, 25))\ncolumns = 3\nrows = 3\nfor i in range(1, columns*rows +1):\n    name = train_images[i].split('/')[-1]\n    img = cv2.imread(train_images[i])\n    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n    fig.add_subplot(rows, columns, i)\n    bbox = train.loc[train['image_id']==name.split('.')[0], 'bbox'].values\n    img = draw_bbox(img, bbox)\n    plt.imshow(img)\n    plt.title(name)\n    plt.axis('off')\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"The images looks pretty good and each image has numerous wheat heads and detecting the correct number of wheat heads along with bounding-box coordinates might be a challenging(and fun) task in this competition. Let's explore the count(number) of bounding boxes for one-particular image_id."},{"metadata":{"trusted":true},"cell_type":"code","source":"df_train = train[['image_id', 'bbox']]\ndf_counted = df_train.groupby('image_id').count()\ndf_counted = df_counted.rename(columns={'bbox': 'count'})\ndf_counted.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df_counted['count'].mean()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"So, there are roughly 43 bounding boxes for each image_id. The overall distribution is plotted below"},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(25, 20))\ndf_counted['count'].value_counts().plot(kind='bar');\nplt.ylabel('number of images', fontsize=12);\nplt.xlabel('number of bboxes', fontsize=12);","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Now, let's take a look at images in the test-folder, for which we need to make predictions\n>You 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."},{"metadata":{"trusted":true},"cell_type":"code","source":"sub = pd.read_csv(f'{data_dir}/sample_submission.csv')\nsub.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sub.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_images = glob.glob(f'{data_dir}/test/*')\nlen(test_images), test_images[0]","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Interestingly, there are just 10-images available to us for making prediction as most of the test-images are hidden. I guess the organizers have their own reasons for hiding most of the test-images. My best guess would be that they want to prevent pseudo-labeling of test-images "},{"metadata":{"trusted":true},"cell_type":"code","source":"fig=plt.figure(figsize=(25, 25))\ncolumns = 3\nrows = 3\nfor i in range(1, columns*rows +1):\n    name = test_images[i].split('/')[-1]\n    img = cv2.imread(test_images[i])\n    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n    fig.add_subplot(rows, columns, i)\n    plt.imshow(img)\n    plt.title(name)\n    plt.axis('off')\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"This will be a fun competition to participate as this is a detection-based competition. It would be a nice opportunity to learn(and use) the recent advancements in Image-Detection domain such as [EfficientDet](https://arxiv.org/abs/1911.09070) and [YoloV4](https://arxiv.org/abs/2004.10934)\n> Expect a lot of computer-vision loving Kagglers to join as the dataset is not that huge compared to other ongoing vision competitions. "}],"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}