{"cells":[{"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\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\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","collapsed":true,"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":false},"cell_type":"markdown","source":"## In order to use Yolo, we need to perform several pre-processing steps. \n\n1. Given the training csv, we will need to conevrt the labels for each box from COCO format to yolo format. \n\n2. Create a .txt file with all annotations for each image. One line per box and a class identifier\n\n3. Create a blank .txt for the images without boxes.\n\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"from ast import literal_eval\nimport cv2\nimport matplotlib.pyplot as plt\n\n\ntrain_df = pd.read_csv(\"../input/global-wheat-detection/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":"* The bounding box format as given is [xmin, ymin, widht, height] in pixels. For yolov4, we have to convert these labels into Yolo format. Below is how to do so. "},{"metadata":{"trusted":true},"cell_type":"code","source":"def convert(size, box):\n    dw = 1. / size[0]\n    dh = 1. / size[1]\n    x = (box[0] + box[1]) / 2.0\n    y = (box[2] + box[3]) / 2.0\n    w = box[1] - box[0]\n    h = box[3] - box[2]\n    x = x * dw\n    w = w * dw\n    y = y * dh\n    h = h * dh\n    return [x, y, w, h]\n\ndef convert_to_yolo_label(coco_format_box, w = 1024, h = 1024):\n    bbox = literal_eval(coco_format_box)\n    xmin = bbox[0]\n    xmax = bbox[0] + bbox[2]\n    ymin = bbox[1]\n    ymax = bbox[1] + bbox[3]\n    b = (float(xmin), float(xmax), float(ymin), float(ymax))\n    yolo_box = convert((w, h), b)\n    if np.max(yolo_box) > 1 or np.min(yolo_box) < 0: # Take this opportunity to check that conversion works\n        print(\"BOX HAS AN ISSUE\")\n    return yolo_box\n\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"%%time\ntrain_df['yolo_box'] = train_df.bbox.apply(convert_to_yolo_label)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Now we have a column in our train data frame with the yolo format"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### As a sanity check, lets convert back to Pascal format and see if we get the right answer:\n\nUsing the first line of the dataframe, we see we get a correct converion back to Pascal (and then we cna do quick math to confirm in COCO format)"},{"metadata":{"trusted":true},"cell_type":"code","source":"def convertYoloToPascal(size, coord):\n    x2 = int(((2*size[0]*float(coord[0]))+(size[0]*float(coord[2])))/2)\n    x1 = int(((2*size[0]*float(coord[0]))-(size[0]*float(coord[2])))/2)\n\n    y2 = int(((2*size[1]*float(coord[1]))+(size[1]*float(coord[3])))/2)\n    y1 = int(((2*size[1]*float(coord[1]))-(size[1]*float(coord[3])))/2)\n    return (x1,y1,x2,y2)\n\nconvertYoloToPascal((1024, 1024), [0.841796875, 0.234375, 0.0546875, 0.03515625])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### Another spot check we can do is check a bounding box on the image:"},{"metadata":{"trusted":true},"cell_type":"code","source":"## Check that we can visualize boxes as Coco format:\nfr = cv2.imread(\"../input/global-wheat-detection/train/b6ab77fd7.jpg\")\nframe_rgb = cv2.cvtColor(fr, cv2.COLOR_BGR2RGB)\nframe_rgb = cv2.rectangle(frame_rgb, (834, 222), (834+56, 222+36), (255, 0, 0), 5)\nplt.imshow(frame_rgb)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Now that conversion looks good, lets write the label files for images with boxes (positives) :\n\nMake a folder where the data will be saved to. For some version of YOLO, all the training iamges and label files are in the same directory. So we can create a directory with all the text files with the lables in the same place. "},{"metadata":{"trusted":true},"cell_type":"code","source":"print(\"We have {} unique images with boxes.\".format(len(train_df.image_id.unique())))\nunique_img_ids = train_df.image_id.unique()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"if not os.path.exists(\"wheat_yolo_train_data\"):\n    os.makedirs(\"wheat_yolo_train_data\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"folder_location = \"wheat_yolo_train_data\"\n#change  unique_img_ids[:2] to unique_img_ids to iterate through all images\nfor img_id in unique_img_ids[:2]: # loop through all unique image ids. Remove the slice to do all images\n    print(img_id)\n    filt_df = train_df.query(\"image_id == @img_id\") # filter the df to a specific id\n    #print(filt_df.shape[0])\n    all_boxes = filt_df.yolo_box.values\n    file_name = \"{}/{}.txt\".format(folder_location,img_id) # specify the name of the folder and get a file name\n\n    s = \"0 %s %s %s %s \\n\" # the first number is the identifier of the class. If you are doing multi-class, make sure to change that\n    with open(file_name, 'a') as file: # append lines to file\n        for i in all_boxes:\n            new_line = (s % tuple(i))\n            file.write(new_line)  \n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"!ls wheat_yolo_train_data/","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"!head wheat_yolo_train_data/b53afdf5c.txt","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### We need to also make labels for the training images that do not have bounding boxes in them.\n\n* This should be a lot easier since we just need an empty file with the name of the image"},{"metadata":{"trusted":true},"cell_type":"code","source":"import glob\nall_imgs = glob.glob(\"../input/global-wheat-detection/train/*.jpg\")\nall_imgs = [i.split(\"/\")[-1].replace(\".jpg\", \"\") for i in all_imgs]\npositive_imgs = train_df.image_id.unique()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"negative_images = set(all_imgs) - set(positive_imgs)\nprint(len(all_imgs), len(positive_imgs))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"len(negative_images)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"for i in list(negative_images)[:2]:\n    file_name = \"wheat_yolo_train_data/{}.txt\".format(i)\n    print(file_name)\n    with open(file_name, 'w') as fp: \n        pass","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"!cat wheat_yolo_train_data/91d4e3750.txt","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### As a last step, move all your training images into the same directory. Makse sure to do this with the test set as well if you want to use this as validation.\n\nHope this helps"},{"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}