{"cells":[{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":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\n# import numpy as np # linear algebra\n# import 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\n# import os\n# for dirname, _, filenames in os.walk('/kaggle/input'):\n#     for filename in filenames:\n#         print(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":{"_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\nimport matplotlib.image as mpimg\nimport skimage.io\nfrom tqdm.notebook import tqdm\nimport random\nimport cv2\nimport seaborn as sns\nimport os\n# plt.rcParams['figure.figsize'] = [15,8]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"DATA_DIR = '/kaggle/input/global-wheat-detection/'\ntrain_csv = pd.read_csv(DATA_DIR + 'train.csv')\ntrain_csv.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"bounding box values = (value 1) = topleft x cooordinate of box (value 2) = topleft y cooordinate of box (value 3) = width of box (value 4) = height of box\n\ntrain_csv['width'] = width of image train_csv['height'] = height of image"},{"metadata":{"trusted":true},"cell_type":"code","source":"import re\ndef expand_bbox(x):\n    r = np.array(re.findall(\"([0-9]+[.]?[0-9]*)\", x))\n    if len(r) == 0:\n        r = [-1, -1, -1, -1]\n    return r\n\ntrain_csv['x'] = -1.0\ntrain_csv['y'] = -1.0\ntrain_csv['w'] = -1.0\ntrain_csv['h'] = -1.0\n\ntrain_csv[['x', 'y', 'w', 'h']] = np.stack(train_csv['bbox'].apply(lambda x: expand_bbox(x)))\n\ntrain_csv['x'] = train_csv['x'].astype(np.float)\ntrain_csv['y'] = train_csv['y'].astype(np.float)\ntrain_csv['w'] = train_csv['w'].astype(np.float)\ntrain_csv['h'] = train_csv['h'].astype(np.float)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Input argument format for opencv rectangle function = ( (topleft x coordinate, topleft y coordinate), (bottomright x coordinate, bottomright y coordinate) bordor colour, border width) = ( (train_csv[x], train_csv[y]), (train_csv[x]+train_csv[w], train_csv[y]+train_csv[h]), red, 2)"},{"metadata":{"trusted":true},"cell_type":"code","source":"import cv2\nN=147793\nrandom_index = random.randint(0,N)\nimg_path = DATA_DIR + 'train/' + '2c7241d19' + '.jpg'\nimg = cv2.imread(img_path)\n\nimage_id = train_csv.iloc[random_index]['image_id']\nimage_id='2c7241d19'\nboxes = train_csv[train_csv['image_id'] == image_id][['x', 'y', 'w', 'h']].values\n\nfig, ax = plt.subplots(1, 1, figsize=(16, 8))\nfor box in boxes:\n    xmin = np.int(box[0])\n    ymin = np.int(box[1])\n    width = np.int(box[2])\n    height = np.int(box[3])\n    img = cv2.rectangle(img,(xmin,ymin),(xmin+width,ymin+height),(255,0,0),2)\nax.set_axis_off()\nax.imshow(img)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Plan:\n\nTrain training set images on a pretrained model of YOLOv3 or miniYOLO\n\nTo do the same we need to first prepare the dataset in the format that the model accepts. This link clearly explains how we could do this: https://github.com/AlexeyAB/darknet#how-to-train-to-detect-your-custom-objects\n\nOur first step in this process would be to convert our bounding box representation. Current representation = (x, y, w, h) = (topleft x coordinate, topleft y coordinate, width of bounding box, height of bounding box)\n\nRequired representation = (yolox, yoloy, yolow, yoloh) = (centre x coordinate of bounding box w.r.t image width, centre y coordinate of bounding box w.r.t image height, width of bounding box w.r.t image width, height of bounding box w.r.t image height) = ( ((x + (w/2))/width, ((y + (h/2))/height, w/width, h/height )"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_csv['yolox'] = (train_csv['x'] + (train_csv['w']/2))/train_csv['width']\ntrain_csv['yoloy'] = (train_csv['y'] + (train_csv['h']/2))/train_csv['height']\ntrain_csv['yolow'] = (train_csv['w'])/train_csv['width']\ntrain_csv['yoloh'] = (train_csv['h'])/train_csv['height']\ntrain_csv['class'] = 0\n\ntrain_csv.head()\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Not able to run the YOLO model in kaggle as the github folder is in the /input folder and that folder is read only in Kaggle.\n\nCouldn't train the model in personal laptop as GPU is not CUDA supported and we need a GPU with CUDA support (usually NVIDIA GPUs) to train this model. So decided to train the model in Google colab and then upload the trained weights to kaggle.\nHere is the link to the code in Google colab to train the model. (wheat-detection-yolo.ipynb).\nhttps://colab.research.google.com/drive/1MdD-8JSQO0CyVj9sXqhBVQLC9hPAspok\n\nThe following changes needed to be made to the prepared dataset/github folder to train the model:\n1. set GPU=1, CUDNN=1, OPENCV=1 in the Makefile under the /darknet folder (the root folder)\n2. Had to change the following values in the build/darknet/x64/cfg/yolo-obj.cfg file:\n    a. subdivisions = 64\n    b. height = 512\n    c. width = 512\n    Decreasing the height and width values from 1024(the image height and width) to 512 could decrease the quality in object detection but the GPU memory wasn't enough, so had to decrease. Maybe there is a way to increase the GPU memory in Google colab.\n3. Had to change all the paths in build/darknet/x64/data/obj.data file to build/darknet/x64/data\n4. Had to chane all paths in build/darknet/x64/data/train.txt file to build/darknet/x64/\n5. Had to add the file paths of images with no object present in the build/darknet/x64/data/train.txt file as I had forgotten to add them earlier.\n6. Had to change all the paths in the command to train the model from:\n./darknet detector train data/obj.data yolo-obj.cfg yolov4.conv.137 to \n!./darknet detector train build/darknet/x64/data/obj.data build/darknet/x64/cfg/yolo-obj.cfg build/darknet/x64/yolov4.conv.137 -dont_show\n7. To train the model, the above command was run in the darknet folder that is the root folder /\n8. Added the -dont_show option in the above command as it was causing errors while training the model, to display certain results.\n\nTo run the model in Google colab, additionally the following steps were needed:\n1. Add the kaggle key (json) file to Google colab.\n2. Download the dataset, using the API command for the dataset in Kaggle and unzip it: kaggle datasets download -d sneha5gsm/yolowheatdetection\n3. Download dos2unix package to convert the (config, data, txt) files to Unix format.\n4. Initially wasn't able to train the model in Google colab, the notebook used to crash, so created the following issue in Github for that repo, the suggestions provided by @waelausy solved the issue:\nhttps://github.com/AlexeyAB/darknet/issues/5554#issuecomment-626318806\n\n\n\nNext steps:\n1. Get the weights after training the model in Google colab and test it out.\n2. If the results seem ok, upload the weights into kaggle.\n3. Copy the logs generated in Google colab to analyse cost details, etc.\n4. See if a different pretrained weight, or model gives better results.\n5. Browse how different parameter values in Makefile, config file can affect the results.\n\nNext steps:\n1. Got weights after training the model for almost 12 hours in Google Colab. Could get upto 2000 iterations.\n2. Testing train images and random images from internet with the weights and network is giving pretty impressive results.\n3. Try to run the detect command in kaggle. Currently I can think of two options:\n    a. Upload the customized darknet folder to github and clone it in Kaggle.\n    b. Try to figure out a way to use the uploaded zip folder in kaggle in the working directory section, rather than input folder section.   --- this seems like a better option as of now\n4. Convert the output bounding box result into csvs.\n5. Generate a submission.csv file for the test images in the dataset.\n6. Submit the submission and check out the score.\n\nFinally, We cannot use internet in this competition. So, created a zip with the darknet executable, uploaded it as a dataset. Copying it from input directory to working directory and then run the detect cmd.\n\nBest results(weights) after training have been uploaded in this notebook for testing and submission."},{"metadata":{"trusted":true},"cell_type":"code","source":"!cp -r /kaggle/input/yolowheatdetectionnoopencv /kaggle/working","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#turn on GPU to run this\nos.chdir(\"/kaggle/working/yolowheatdetectionnoopencv/darknet-master\")\n!chmod +x ./darknet\n# !./darknet detector test build/darknet/x64/data/obj.data build/darknet/x64/cfg/yolo-obj.cfg build/darknet/x64/yolo-obj_2000.weights","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# %%capture cap\nimport fileinput\nimport re\nimport glob\n\ntest_image_ids = []\nfor dirname, _, filenames in os.walk('/kaggle/input/global-wheat-detection/test/'):\n    for filename in filenames:\n#         print(os.path.join(dirname, filename))\n        test_image_ids.append(filename)\n\nPAT = 'wheathead:'\nFILES = 'output.txt'\nvalues = []\nfor image_id in test_image_ids:\n    image_path = '/kaggle/input/global-wheat-detection/test/' + image_id\n#     print(image_path)\n    output = !./darknet detector test build/darknet/x64/data/obj.data build/darknet/x64/cfg/yolo-obj.cfg build/darknet/x64/yolo-obj_2000.weights -ext_output $image_path -dont_show\n    boxes = ''\n    for line in output:\n        if re.search(PAT, line):\n            arrtemp = line.split()\n            left_x = int(arrtemp[3])\n            if left_x<0:\n                left_x = 0\n            top_y = int(arrtemp[5])\n            if top_y<0:\n                top_y = 0\n            boxes = boxes + str(int(arrtemp[1][:-1])/100) + ' ' + str(left_x) + ' ' + str(top_y) + ' ' + str(arrtemp[7]) + ' ' + str(arrtemp[9][:-1]) + ' '\n    boxes = boxes[:-1]\n    values.append([image_id[:-4], boxes])\nsample_submission = pd.DataFrame(values, columns=['image_id', 'PredictionString'])\nsample_submission.to_csv('submission.csv', index=False)\n# !cp  submission.csv /kaggle/working\n    \n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# PAT = 'wheathead:'\n# FILES = 'output.txt'\n# image_id = '00b70a919.jpg'\n# image_path = '/kaggle/input/global-wheat-detection/train/' + image_id\n# img = cv2.imread(image_path)\n# #     print(image_path)\n# output = !./darknet detector test build/darknet/x64/data/obj.data build/darknet/x64/cfg/yolo-obj.cfg build/darknet/x64/yolo-obj_2000.weights -ext_output $image_path -dont_show\n# fig, ax = plt.subplots(1, 1, figsize=(16, 8))\n# for line in output:\n#     if re.search(PAT, line):\n#         arrtemp = line.split()\n#         left_x = int(arrtemp[3])\n#         if left_x<0:\n#             left_x = 0\n#         top_y = int(arrtemp[5])\n#         if top_y<0:\n#             top_y = 0\n#         xmin = np.int(left_x)\n#         ymin = np.int(top_y)\n#         width = np.int(arrtemp[7])\n#         height = np.int(arrtemp[9][:-1])\n#         img = cv2.rectangle(img,(xmin,ymin),(xmin+width,ymin+height),(255,0,0),2)\n# ax.set_axis_off()\n# ax.imshow(img)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# %ls\n!cp submission.csv /kaggle/working\nos.chdir(\"/kaggle/working\")\n!rm -rf yolowheatdetectionnoopencv","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# from PIL import Image, ImageEnhance \n# im = Image.open(\"wheat3.jpg\")\n# enhancer = ImageEnhance.Brightness(im)\n# enhanced_im = enhancer.enhance(1)\n# enhanced_im.save(\"enhanced.sample5.png\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"collapsed":true},"cell_type":"code","source":"# !./darknet detector test build/darknet/x64/data/obj.data build/darknet/x64/cfg/yolo-obj.cfg build/darknet/x64/yolo-obj_2000.weights -ext_output color_img.jpg -dont_show\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# image = cv2.imread(\"wheat3.jpg\")\n\n# new_image = np.zeros(image.shape, image.dtype)\n# alpha = 1.3 # Simple contrast control\n# beta =40    # Simple brightness control\n# # Initialize values\n# # alpha = float(input('* Enter the alpha value [1.0-3.0]: '))\n# # beta = int(input('* Enter the beta value [0-100]: '))\n# # Do the operation new_image(i,j) = alpha*image(i,j) + beta\n# # Instead of these 'for' loops we could have used simply:\n# # new_image = cv.convertScaleAbs(image, alpha=alpha, beta=beta)\n# # but we wanted to show you how to access the pixels :)\n# for y in range(image.shape[0]):\n#     for x in range(image.shape[1]):\n#         for c in range(image.shape[2]):\n#             new_image[y,x,c] = np.clip(alpha*image[y,x,c] + beta, 0, 255)\n# fig, ax = plt.subplots(1, 1, figsize=(16, 8))\n# # cv2.imshow('Original Image', image)\n# # cv2.imshow('New Image', new_image)\n# ax.set_axis_off()\n# ax.imshow(image)\n# # ax.imshow(new_image)\n# cv2.imwrite('color_img.jpg', image)\n# # new_image.save(\"enhanced.sample5.png\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# def adjust_gamma(image, gamma=1.0):\n# # build a lookup table mapping the pixel values [0, 255] to\n# # their adjusted gamma values\n#     invGamma = 1.0 / gamma\n#     table = np.array([((i / 255.0) ** invGamma) * 255\n#     for i in np.arange(0, 256)]).astype(\"uint8\")\n# # apply gamma correction using the lookup table\n#     return cv2.LUT(image, table)\n\n# original = cv2.imread(\"wheat3.jpg\")\n# adjusted = adjust_gamma(original, 0.5)\n# fig, ax = plt.subplots(1, 1, figsize=(16, 8))\n# # cv2.imshow('Original Image', image)\n# # cv2.imshow('New Image', new_image)\n# ax.set_axis_off()\n# ax.imshow(adjusted)\n# # ax.imshow(new_image)\n# cv2.imwrite('color_img.jpg', adjusted)","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}