├── CovertAnnotations_YOLO_to_COCO_format.ipynb └── README.md /CovertAnnotations_YOLO_to_COCO_format.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 213, 6 | "id": "corresponding-rating", 7 | "metadata": {}, 8 | "outputs": [], 9 | "source": [ 10 | "# This file converts object detection annotations from YOLO format (.txt and .names) to COCO format (.json)\n", 11 | "# The base code is originally from: https://www.programmersought.com/article/76707275021/\n", 12 | "# It was modified extensively as the original code was not working for my needs.\n", 13 | "# More information about the conversion process can be found here: https://prabhjotkaurgosal.com/weekly-learning-blogs/" 14 | ] 15 | }, 16 | { 17 | "cell_type": "code", 18 | "execution_count": 11, 19 | "id": "amino-cleaners", 20 | "metadata": {}, 21 | "outputs": [], 22 | "source": [ 23 | "import os\n", 24 | "import json\n", 25 | "import cv2\n", 26 | "import random\n", 27 | "import time" 28 | ] 29 | }, 30 | { 31 | "cell_type": "code", 32 | "execution_count": 12, 33 | "id": "selective-officer", 34 | "metadata": {}, 35 | "outputs": [], 36 | "source": [ 37 | "# (OPTIONAL) step\n", 38 | "# Preparing the Dataset\n", 39 | "# Convert all images to .jpg (This is not necessary but made my life easier down the line)\n", 40 | "\n", 41 | "from PIL import Image\n", 42 | "#iml = Image.open(r'/absolute/path/to/the/image/directory/followed/by/image/name/with/its/extesnion')\n", 43 | "#rgb_im = iml.convert('RGB')\n", 44 | "#rgb_im.save(r'/absolutae/path/to/the/directory/where/image/must/be/stored/image_name.jpg')\n" 45 | ] 46 | }, 47 | { 48 | "cell_type": "code", 49 | "execution_count": 221, 50 | "id": "posted-moore", 51 | "metadata": {}, 52 | "outputs": [ 53 | { 54 | "name": "stdout", 55 | "output_type": "stream", 56 | "text": [ 57 | "The number of unlabelled files is: 121\n" 58 | ] 59 | } 60 | ], 61 | "source": [ 62 | "# (OPTIONAL) step\n", 63 | "# Preparing the Dataset - remove unlabelled files\n", 64 | "# I chose to remove the image files from the dataset that were not labelled\n", 65 | "# Move the files (jpg and txt that are not labelled) from the working directory and put them in another folder. . .\n", 66 | "\n", 67 | "import shutil\n", 68 | "\n", 69 | "directory_labels = os.fsencode(\"/absolute/path/to/labelled/files\") #absolute path to the directory where all labels are stored\n", 70 | "directory_images = os.fsencode(\"/absolute/path/to/images/files\") #absolute path to the directory where all images are stored\n", 71 | "directory_unlabelled_images = os.fsencode(\"/absolute/path/to/newFolder\")#absolute path to the directory where unlabelled images are to be stored\n", 72 | "\n", 73 | "not_labelled_files = 0\n", 74 | "for file in os.listdir(directory_labels): #Read from the directory where the labels are stored\n", 75 | " filename = os.fsdecode(file)\n", 76 | " if filename.endswith(\".txt\"):\n", 77 | " yolo_annotation_path = (os.path.join(directory_labels.decode(\"utf-8\"), filename))\n", 78 | " base=os.path.basename(yolo_annotation_path)\n", 79 | " file_name_without_ext = os.path.splitext(base)[0] # name of the file without the extension\n", 80 | " img_path = os.path.join(directory_images.decode(\"utf-8\"), file_name_without_ext+ \".\" + 'jpg')\n", 81 | " \n", 82 | " filesize = os.path.getsize(yolo_annotation_path)\n", 83 | " if filesize == 0: #chek if the label file (.txt) is empty - that is it has no labels\n", 84 | " UnlabeledImg_path = os.path.join(directory_unlabelled_images.decode(\"utf-8\"), file_name_without_ext+ \".\" + 'jpg')\n", 85 | " not_labelled_files = not_labelled_files +1\n", 86 | " \n", 87 | " shutil.move(img_path, UnlabeledImg_path) #remove the corresponding image to another directory\n", 88 | "print(\"The number of unlabelled files is: \", not_labelled_files)" 89 | ] 90 | }, 91 | { 92 | "cell_type": "code", 93 | "execution_count": 13, 94 | "id": "precise-sentence", 95 | "metadata": {}, 96 | "outputs": [], 97 | "source": [ 98 | "#### This is where the conversion process starts from YOLO to COCO format\n", 99 | "\n", 100 | "# Category file, one category per line\n", 101 | "yolo_format_classes_path = '/media/jyoti/My Passport/DoorDetectDataset/obj.names'\n", 102 | "# Write the category according to your own data set. \n", 103 | "\n", 104 | "#Read the categories file and extract all categories\n", 105 | "with open(yolo_format_classes_path,'r') as f1:\n", 106 | " lines1 = f1.readlines()\n", 107 | "categories = []\n", 108 | "for j,label in enumerate(lines1):\n", 109 | " label = label.strip()\n", 110 | " categories.append({'id':j+1,'name':label,'supercategory': label})\n", 111 | " \n", 112 | "write_json_context = dict()\n", 113 | "write_json_context['info'] = {'description': '', 'url': '', 'version': '', 'year': 2021, 'contributor': '', 'date_created': '2021-02-12 11:00:08.5'}\n", 114 | "write_json_context['licenses'] = [{'id': 1, 'name': None, 'url': None}]\n", 115 | "write_json_context['categories'] = categories\n", 116 | "write_json_context['images'] = []\n", 117 | "write_json_context['annotations'] = []" 118 | ] 119 | }, 120 | { 121 | "cell_type": "code", 122 | "execution_count": 14, 123 | "id": "north-parade", 124 | "metadata": {}, 125 | "outputs": [], 126 | "source": [ 127 | "# Read the YOLO formatted label files (.txt) to extarct bounding box information and store in COCO format\n", 128 | "\n", 129 | "#Read the label files (.txt) to extarct bounding box information and store in COCO format\n", 130 | "directory_labels = os.fsencode(\"/home/jyoti/Desktop/csc8800/datasets/DoorDetectDataset/labels\")\n", 131 | "#directory_images = os.fsencode(\"/home/jyoti/Desktop/csc8800/datasets/DoorDetectDataset/test\")\n", 132 | "directory_images = os.fsencode(\"/home/jyoti/Desktop/csc8800/datasets/DoorDetectDataset/train\")\n", 133 | "\n", 134 | "file_number = 1\n", 135 | "num_bboxes = 1\n", 136 | "for file in os.listdir(directory_images):\n", 137 | " filename = os.fsdecode(file)\n", 138 | " if filename.endswith(\".jpg\"):\n", 139 | " img_path = (os.path.join(directory_images.decode(\"utf-8\"), filename))\n", 140 | " base=os.path.basename(img_path)\n", 141 | " file_name_without_ext = os.path.splitext(base)[0] # name of the file without the extension\n", 142 | " yolo_annotation_path = os.path.join(directory_labels.decode(\"utf-8\"), file_name_without_ext+ \".\" + 'txt')\n", 143 | " img_name = os.path.basename(img_path) # name of the file without the extension\n", 144 | " img_context = {}\n", 145 | " height,width = cv2.imread(img_path).shape[:2]\n", 146 | " img_context['file_name'] = img_name\n", 147 | " img_context['height'] = height\n", 148 | " img_context['width'] = width\n", 149 | " img_context['date_captured'] = '2021-02-12 11:00:08.5'\n", 150 | " img_context['id'] = file_number # image id\n", 151 | " img_context['license'] = 1\n", 152 | " img_context['coco_url'] =''\n", 153 | " img_context['flickr_url'] = ''\n", 154 | " write_json_context['images'].append(img_context)\n", 155 | " \n", 156 | " with open(yolo_annotation_path,'r') as f2:\n", 157 | " lines2 = f2.readlines() \n", 158 | "\n", 159 | " for i,line in enumerate(lines2): # for loop runs for number of annotations labelled in an image\n", 160 | " line = line.split(' ')\n", 161 | " bbox_dict = {}\n", 162 | " class_id, x_yolo,y_yolo,width_yolo,height_yolo= line[0:]\n", 163 | " x_yolo,y_yolo,width_yolo,height_yolo,class_id= float(x_yolo),float(y_yolo),float(width_yolo),float(height_yolo),int(class_id)\n", 164 | " bbox_dict['id'] = num_bboxes\n", 165 | " bbox_dict['image_id'] = file_number\n", 166 | " bbox_dict['category_id'] = class_id+1\n", 167 | " bbox_dict['iscrowd'] = 0 # There is an explanation before\n", 168 | " h,w = abs(height_yolo*height),abs(width_yolo*width)\n", 169 | " bbox_dict['area'] = h * w\n", 170 | " x_coco = round(x_yolo*width -(w/2))\n", 171 | " y_coco = round(y_yolo*height -(h/2))\n", 172 | " if x_coco <0: #check if x_coco extends out of the image boundaries\n", 173 | " x_coco = 1\n", 174 | " if y_coco <0: #check if y_coco extends out of the image boundaries\n", 175 | " y_coco = 1\n", 176 | " bbox_dict['bbox'] = [x_coco,y_coco,w,h]\n", 177 | " bbox_dict['segmentation'] = [[x_coco,y_coco,x_coco+w,y_coco, x_coco+w, y_coco+h, x_coco, y_coco+h]]\n", 178 | " write_json_context['annotations'].append(bbox_dict)\n", 179 | " num_bboxes+=1\n", 180 | " \n", 181 | " file_number = file_number+1\n", 182 | " continue\n", 183 | " else:\n", 184 | " continue\n", 185 | " \n", 186 | " # Finally done, save!\n", 187 | "#coco_format_save_path = '/home/jyoti/Desktop/csc8800/datasets/DoorDetectDataset/test.json'\n", 188 | "coco_format_save_path = '/home/jyoti/Desktop/csc8800/datasets/DoorDetectDataset/train.json'\n", 189 | "with open(coco_format_save_path,'w') as fw:\n", 190 | " json.dump(write_json_context,fw) \n", 191 | " " 192 | ] 193 | }, 194 | { 195 | "cell_type": "code", 196 | "execution_count": null, 197 | "id": "plain-potential", 198 | "metadata": {}, 199 | "outputs": [], 200 | "source": [] 201 | } 202 | ], 203 | "metadata": { 204 | "kernelspec": { 205 | "display_name": "Python 3", 206 | "language": "python", 207 | "name": "python3" 208 | }, 209 | "language_info": { 210 | "codemirror_mode": { 211 | "name": "ipython", 212 | "version": 3 213 | }, 214 | "file_extension": ".py", 215 | "mimetype": "text/x-python", 216 | "name": "python", 217 | "nbconvert_exporter": "python", 218 | "pygments_lexer": "ipython3", 219 | "version": "3.8.5" 220 | } 221 | }, 222 | "nbformat": 4, 223 | "nbformat_minor": 5 224 | } 225 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ObjectDetectionScripts 2 | This repo contains various scripts to aid Object detection tasks 3 | --------------------------------------------------------------------------------