{"cells":[{"metadata":{},"cell_type":"markdown","source":"# 100 Days of Kaggle challenge: Day 1\n\nHi, I'm a Machine Learning enthusiast looking forward to provide you with valuable information, from notebooks like this.\nIn this notebook, we will start with the first step in tackling a DL problem - Getting familiar with data.\nFor this example, I'll use the wheat dataset, which was supplied by the organisers for [Global Wheat Detection](https://www.kaggle.com/c/global-wheat-detection/overview) Competition. I highly suggest you to go to that link and get a high level overview of what is present inside this dataset. The techniques used in this notebook is inspired from [this](https://www.kaggle.com/reighns/augmentations-data-cleaning-and-bounding-boxes) notebook by [reigHns](https://www.kaggle.com/reighns)\nFor best learning experience, fork this notebook and follow along","execution_count":null},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"# Importing the bread and butter for every Deep-Learning problem\nimport numpy as np\nimport pandas as pd\n\n# Importing OS for accessing data\nimport os\n\n# For plotting stuff\nimport matplotlib.pyplot as plt\n\n# For reading images\nimport cv2\n\n%matplotlib inline\n\n# Setting the random seed so that y'all don't get different images when you run the notebook yourself\nnp.random.seed(0)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Setting the root directory, so that we don't have to type the same path everytime\nroot_dir = '/kaggle/input/global-wheat-detection/'\n\n#Let's see what files do we have here\nfor file in os.listdir(root_dir):\n    print(file)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Just in case you didn't check out the [Global Wheat Detection](https://www.kaggle.com/c/global-wheat-detection/overview), we have bounding boxes for 'Wheat heads' inside the 'train.csv' file. The csv file has a row for every bounding box. They have also mentioned that not every image has a bounding box. All in all we can conclude that a single image may have many bounding boxes, whereas some images might not have a bounding box at all. That's good information. Let's look at the csv for now.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"train = pd.read_csv(root_dir+'train.csv')\ntrain.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**The fields look self explanatory, but just in case if you're a noob**\n\nImage_id - Name of the image\n\nwidth, height - how wide and how tall the image is, with respect to pixels\n\nbbox - Contains 4 set of points [starting x co-ordinate, starting_y_co-ordinate, width_of_bb, height_of_bb\n\nsource - Not sure but I guess it's some sort of username of the guy/girl who provided this dataset. Kudos for same!\n","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"# Sneak peek at the pictures\nLet's look at some images because let's be honest we'd rather see images than code. We still gotta type code to see the images tho.\n","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"nncols = 4\ntrain_path = os.path.join(root_dir, 'train') \nimage_files_list = os.listdir(train_path)\nmain_title = \"Just some pictures of Wheat\"\n\n# Here's a generic function to plot multiple images at once\ndef plot_random_images(image_files_list, image_path, nrows=3, ncols=4, main_title=\"\"):\n    \"\"\"\n    image_files_list : List containing all of the image files, stacked on axis 0\n    nrows            : Number of rows of pictures\n    ncols            : Number of columns of pictures\n    main_title       : Main title for sub-plots\n    \"\"\"\n    \n    # Selecting a random number of images from the given list\n    random_img_list = np.random.choice(image_files_list, nrows * ncols)\n    \n    # Reading images and appending them to the image_matrix_list\n    image_matrix_list = []\n    for file in random_img_list:\n        img = cv2.imread(os.path.join(image_path, file))\n        image_matrix_list.append(img)\n        \n    # Setting the subplots as per inputs provided\n    fig, axes = plt.subplots(nrows=nrows, ncols=ncols, figsize = (20, 15), squeeze=False)\n    fig.suptitle('Wheat', fontsize=30)\n    num=0\n    for i in range(nrows):\n        for j in range(ncols):\n            axes[i][j].imshow(image_matrix_list[num])\n            axes[i][j].set_title(random_img_list[num], fontsize=14)\n            num += 1\n    plt.show()\n    \n# Finally plotting the images\nplot_random_images(image_files_list, train_path, 3, 4, main_title)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Plotting Images with Bounding Boxes\nThese images look good, but nobody will take you seriously if you don't show bounding boxes for the wheat heads. Let's work on that!","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"For quicker plotting of the data, it would be much better if we manipulate the csv itself.\nThis is how the csv looks right now\n![image.png](attachment:image.png)","attachments":{"image.png":{"image/png":"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"}},"execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"train.describe()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Damn, this means only these two columns are storing numeric values. But the values look same for every row, so they're kinda  useless right now. Get your surgical gloves on, because we'll need to do some serious operations on this thing.\n","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"\"\"\"\nFor starters, we will restructure the way bounding boxes are stored, so that it's easier for us to plot them on the images\nLet's get these bb's\n\nHere, we apply a lambda function to the bbox column, to extract the 4 numbers from the string. Since the first and the last characters\nare '[' and ']' respectively, we started the slicing from index 1, and left out the last index, and using \",\" as seperator\n\n\"\"\"\nbboxes = np.stack(train['bbox'].apply(lambda x : np.fromstring(x[1:-1], sep = \",\")))\n\n# Now we add new columns, namely x_min and y_min to the csv file\nfor i, column in enumerate(['x_min', 'y_min', 'width', 'height']):\n    train[column] = bboxes[:, i]\n    \n# These lines will add the columns x_max and y_max to the csv file, and fill them with appropriate data\ntrain[\"x_max\"] = train.apply(lambda col: col.x_min+col.width, axis=1)\ntrain[\"y_max\"] = train.apply(lambda col: col.y_min + col.height, axis=1)\n\n# Let's see if how our operation looks like for now\ntrain.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Impresssive! We don't need width, height and bbox anymore, so they gotta go.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"train.drop(columns=['bbox', 'width', 'height'], inplace=True)\ntrain.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Sweet! CSV looks crisp. We gotta do a small validation to ensure that x_max and y_max do not exceed the value (1024), since the image is of size 1024 * 1024","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"x_max = np.array(train[\"x_max\"].values.tolist())\ny_max = np.array(train[\"y_max\"].values.tolist())\n\n\"\"\"\nnp.where works like a conditional statement. for eg. if x_max>1024, replace the value with 1024, else retain the original value of xmax. This is ofcourse done for every value in the numpy array.\n\"\"\"\ntrain[\"x_max\"] = np.where(x_max > 1024, 1024, x_max).tolist()\ntrain[\"y_max\"] = np.where(y_max > 1024, 1024, y_max).tolist()\n ","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Also, we might as well add '.jpg' at the end of every image id, since that is the actual name of the image. But are all the images .jpgs? ","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"extensions = []\nfor file in os.listdir(os.path.join(root_dir, 'train')):\n    extension = file.split(\".\")[1]\n    if extension not in extensions:\n        extensions.append(extension)\n\nif len(extensions) == 1:\n    print(f\"All images are of extension '{extensions[0]}'\")\nelse:\n    print(f\"Looks like we have a problem. Not all the images have same extensions.\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Sweet!, now we can rename the values\ntrain[\"image_id\"] = train['image_id'].apply(lambda x: x + '.jpg')\ntrain.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Let's save our csv\ntrain.to_csv(\"wheat.csv\", index=False)\nwheat = pd.read_csv(\"wheat.csv\")\n\n#Selecting the first image from the csv file. The same image id appears multiple times, because there are multiple bounding boxes inside that image\nchosen_image = cv2.imread(os.path.join(train_path, \"b6ab77fd7.jpg\"))\nchosen_image_df = wheat.loc[wheat[\"image_id\"]==\"b6ab77fd7.jpg\", [\"x_min\", \"y_min\", \"x_max\", \"y_max\"]]\nbbox_array = np.array(chosen_image_df.values.tolist())\nbbox_array.shape\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Looks like there are 47 bounding boxes in this image. Let's plot them on our image and show everyone that we mean business!","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"for i in range(len(bbox_array)):\n    # Apparenetly this cv2.rectangle function fails when we pass points which are floats. That's why we gotta convert our rectangle points to integers\n    \"\"\"\n    pt 1 contains (x_min, y_min)\n    pt 2 contains (x_max, y_max)\n    \"\"\"\n    pt1 = (int(bbox_array[i][0]), int(bbox_array[i][1]))\n    pt2 = (int(bbox_array[i][2]), int(bbox_array[i][3]))\n    draw_chosen_image = cv2.rectangle(chosen_image, pt1, pt2, (0, 255, 0), 5)\nplt.imshow(draw_chosen_image)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\"\"\"\nCool. Let's scale it for multiple images. We will use the generic function we defined above (plot_random_images()). \nWe will draw the rectangles on images, and then pass the image matrix\n\"\"\"\n\nimages_list = os.listdir(train_path)\n\ndef draw_images_with_bboxes(images_list, image_annotation_file, nrows, ncols, main_title=\"\"):\n    image_matrix = []\n    random_list = np.random.choice(images_list, 12)\n    for image in random_list:\n        img = cv2.imread(os.path.join(train_path, image))\n        img_df = image_annotation_file.loc[image_annotation_file['image_id'] == image, [\"x_min\", \"y_min\", \"x_max\", \"y_max\"]]\n        bboxes = np.array(img_df.values.tolist())\n\n        for i,bbox in enumerate(bboxes):\n            pt1 = (int(bbox[0]), int(bbox[1]))\n            pt2 = (int(bbox[2]), int(bbox[3]))\n            img = cv2.rectangle(img, pt1, pt2, (255, 0, 0), 5)\n\n        image_matrix.append(img)\n    fig, axes = plt.subplots(nrows, ncols, figsize=(20, 15))\n    fig.suptitle(main_title, fontsize=30)\n    num = 0\n    for i in range(nrows):\n        for j in range(ncols):\n            axes[i][j].imshow(image_matrix[num])\n            axes[i][j].set_title(random_list[num], fontsize=14)\n            num += 1\n            \ndraw_images_with_bboxes(images_list, wheat, 3, 4, \"Wheat heads with Bounding boxes\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Conclusion\nNow we know how our csv needs to be for plotting the bounding boxes on images. We also saw how to plot bb's on images. We have two generic functions to plot a random sample of our dataset, and another one to plot random images from the same dataset, but with bb's. That's all for day one, I can't wait to start with day 2!","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}