From a200e506816f62f972e93ce5ead025cd059e8a01 Mon Sep 17 00:00:00 2001 From: Raj Pawan Gumdal Date: Thu, 8 Feb 2018 19:58:06 +0530 Subject: [PATCH 1/4] Changes done to main.py to convert the annotated multiple class into yolo format on the fly --- .gitignore | 3 ++- class.txt | 5 ++--- main.py | 43 ++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index c5c32eb8..d0618fbe 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /Images !/Images/001 /Labels -!Labels/001 \ No newline at end of file +!Labels/001 +.DS_Store diff --git a/class.txt b/class.txt index a931f210..bdc8403c 100644 --- a/class.txt +++ b/class.txt @@ -1,3 +1,2 @@ -dog -cat -baby \ No newline at end of file +person +helmet \ No newline at end of file diff --git a/main.py b/main.py index df680920..34fc4170 100644 --- a/main.py +++ b/main.py @@ -40,6 +40,7 @@ def __init__(self, master): self.category = 0 self.imagename = '' self.labelfilename = '' + self.yoloLabelFileName = '' self.tkimg = None self.currentLabelclass = '' self.cla_can_temp = [] @@ -54,6 +55,7 @@ def __init__(self, master): self.bboxIdList = [] self.bboxId = None self.bboxList = [] + self.yoloList = [] self.hl = None self.vl = None @@ -206,6 +208,8 @@ def loadImage(self): self.imagename = os.path.split(imagepath)[-1].split('.')[0] labelname = self.imagename + '.txt' self.labelfilename = os.path.join(self.outDir, labelname) + yoloLabelName = 'yolo/' + self.imagename + '.txt' + self.yoloLabelFileName = os.path.join(self.outDir, yoloLabelName) bbox_cnt = 0 if os.path.exists(self.labelfilename): with open(self.labelfilename) as f: @@ -226,15 +230,24 @@ def loadImage(self): self.listbox.insert(END, '%s : (%d, %d) -> (%d, %d)' %(tmp[4],int(tmp[0]), int(tmp[1]), \ int(tmp[2]), int(tmp[3]))) self.listbox.itemconfig(len(self.bboxIdList) - 1, fg = COLORS[(len(self.bboxIdList) - 1) % len(COLORS)]) + #Raj: + if os.path.exists(self.yoloLabelFileName): + with open(self.yoloLabelFileName) as f: + for (i, line) in enumerate(f): + tmp = line.split() + self.yoloList.append(tuple(tmp)) def saveImage(self): with open(self.labelfilename, 'w') as f: f.write('%d\n' %len(self.bboxList)) for bbox in self.bboxList: f.write(' '.join(map(str, bbox)) + '\n') + with open(self.yoloLabelFileName, 'w') as fy: + for yoloLine in self.yoloList: + print ('Yolo line: ' + yoloLine) + fy.write(yoloLine + '\n') print 'Image No. %d saved' %(self.cur) - def mouseClick(self, event): if self.STATE['click'] == 0: self.STATE['x'], self.STATE['y'] = event.x, event.y @@ -246,8 +259,32 @@ def mouseClick(self, event): self.bboxId = None self.listbox.insert(END, '%s : (%d, %d) -> (%d, %d)' %(self.currentLabelclass,x1, y1, x2, y2)) self.listbox.itemconfig(len(self.bboxIdList) - 1, fg = COLORS[(len(self.bboxIdList) - 1) % len(COLORS)]) + + #Raj: Code to write the data in Yolo format: + w= int(self.img.size[0]) + h= int(self.img.size[1]) + b = (float(x1), float(x2), float(y1), float(y2)) + sizeVar = (w,h) + bb = self.convert(sizeVar, b) + #Raj: We will add the index of the current class since Yolo training will get this index and match it up in the *.names file for the proper class name + currentClassIndex = self.classcandidate['values'].index(self.currentLabelclass) + self.yoloList.append(str(currentClassIndex) + " " + " ".join([str(a) for a in bb])) + self.STATE['click'] = 1 - self.STATE['click'] + def convert(self, sizetuple, box): + dw = 1./sizetuple[0] + dh = 1./sizetuple[1] + x = (box[0] + box[1])/2.0 + y = (box[2] + box[3])/2.0 + w = box[1] - box[0] + h = box[3] - box[2] + x = x*dw + w = w*dw + y = y*dh + h = h*dh + return (x,y,w,h) + def mouseMove(self, event): self.disp.config(text = 'x: %d, y: %d' %(event.x, event.y)) if self.tkimg: @@ -280,6 +317,8 @@ def delBBox(self): self.mainPanel.delete(self.bboxIdList[idx]) self.bboxIdList.pop(idx) self.bboxList.pop(idx) + #Raj: + self.yoloList.pop(idx) self.listbox.delete(idx) def clearBBox(self): @@ -288,6 +327,8 @@ def clearBBox(self): self.listbox.delete(0, len(self.bboxList)) self.bboxIdList = [] self.bboxList = [] + #Raj: + self.yoloList = [] def prevImage(self, event = None): self.saveImage() From 3c5d983d5ae9f2ef77b4f942c11af0f187ed94ac Mon Sep 17 00:00:00 2001 From: Raj Pawan Gumdal Date: Thu, 8 Feb 2018 21:25:30 +0530 Subject: [PATCH 2/4] Limited the colors due to error, added some logs for debugging purpose --- main.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/main.py b/main.py index 34fc4170..fc82b5fd 100644 --- a/main.py +++ b/main.py @@ -16,7 +16,7 @@ import random # colors for the bboxes -COLORS = ['red', 'blue', 'olive', 'teal', 'cyan', 'green', 'black'] +COLORS = ['red', 'blue', 'green', 'black'] # image sizes for the examples SIZE = 256, 256 @@ -197,6 +197,7 @@ def loadDir(self, dbg = False): def loadImage(self): # load image imagepath = self.imageList[self.cur - 1] + print ('Image loaded: ' + imagepath) self.img = Image.open(imagepath) self.tkimg = ImageTk.PhotoImage(self.img) self.mainPanel.config(width = max(self.tkimg.width(), 400), height = max(self.tkimg.height(), 400)) @@ -244,8 +245,8 @@ def saveImage(self): f.write(' '.join(map(str, bbox)) + '\n') with open(self.yoloLabelFileName, 'w') as fy: for yoloLine in self.yoloList: - print ('Yolo line: ' + yoloLine) - fy.write(yoloLine + '\n') + print ('Yolo line: ' + str(yoloLine)) + fy.write(str(yoloLine)+ '\n') print 'Image No. %d saved' %(self.cur) def mouseClick(self, event): From 58538a74d472928cb50ffeb1270c422935dd9169 Mon Sep 17 00:00:00 2001 From: Raj Pawan Gumdal Date: Fri, 9 Feb 2018 12:57:52 +0530 Subject: [PATCH 3/4] Changed the approach in mainitaining Yolo label list. Instead of maintaining the yolo list on every click basis, we are now writing to the final yolo label file only when bbox file is being written. This ensures single exit point for the output of the Yolo labels which eradicates overhead of synchronising yolo label list with that of bbox label list in code. --- main.py | 44 ++++++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/main.py b/main.py index fc82b5fd..00dbcb63 100644 --- a/main.py +++ b/main.py @@ -55,7 +55,6 @@ def __init__(self, master): self.bboxIdList = [] self.bboxId = None self.bboxList = [] - self.yoloList = [] self.hl = None self.vl = None @@ -231,12 +230,6 @@ def loadImage(self): self.listbox.insert(END, '%s : (%d, %d) -> (%d, %d)' %(tmp[4],int(tmp[0]), int(tmp[1]), \ int(tmp[2]), int(tmp[3]))) self.listbox.itemconfig(len(self.bboxIdList) - 1, fg = COLORS[(len(self.bboxIdList) - 1) % len(COLORS)]) - #Raj: - if os.path.exists(self.yoloLabelFileName): - with open(self.yoloLabelFileName) as f: - for (i, line) in enumerate(f): - tmp = line.split() - self.yoloList.append(tuple(tmp)) def saveImage(self): with open(self.labelfilename, 'w') as f: @@ -244,9 +237,26 @@ def saveImage(self): for bbox in self.bboxList: f.write(' '.join(map(str, bbox)) + '\n') with open(self.yoloLabelFileName, 'w') as fy: - for yoloLine in self.yoloList: - print ('Yolo line: ' + str(yoloLine)) - fy.write(str(yoloLine)+ '\n') + #Raj: Code to write the data in Yolo format: + w= int(self.img.size[0]) + h= int(self.img.size[1]) + sizeVar = (w,h) + for bbox in self.bboxList: + x1 = bbox[0] + x2 = bbox[2] + y1 = bbox[1] + y2 = bbox[3] + className = bbox[4] + b = (float(x1), float(x2), float(y1), float(y2)) + bb = self.convert(sizeVar, b) + #Raj: We will add the index of the current class since Yolo training will get this index and match it up in the *.names file for the proper class name + currentClassIndex = self.classcandidate['values'].index(className) + yoloList = [] + yoloList.append(str(currentClassIndex) + " " + " ".join([str(a) for a in bb])) + + for yoloLine in yoloList: + print ('Yolo line: ' + str(yoloLine)) + fy.write(str(yoloLine)+ '\n') print 'Image No. %d saved' %(self.cur) def mouseClick(self, event): @@ -261,16 +271,6 @@ def mouseClick(self, event): self.listbox.insert(END, '%s : (%d, %d) -> (%d, %d)' %(self.currentLabelclass,x1, y1, x2, y2)) self.listbox.itemconfig(len(self.bboxIdList) - 1, fg = COLORS[(len(self.bboxIdList) - 1) % len(COLORS)]) - #Raj: Code to write the data in Yolo format: - w= int(self.img.size[0]) - h= int(self.img.size[1]) - b = (float(x1), float(x2), float(y1), float(y2)) - sizeVar = (w,h) - bb = self.convert(sizeVar, b) - #Raj: We will add the index of the current class since Yolo training will get this index and match it up in the *.names file for the proper class name - currentClassIndex = self.classcandidate['values'].index(self.currentLabelclass) - self.yoloList.append(str(currentClassIndex) + " " + " ".join([str(a) for a in bb])) - self.STATE['click'] = 1 - self.STATE['click'] def convert(self, sizetuple, box): @@ -318,8 +318,6 @@ def delBBox(self): self.mainPanel.delete(self.bboxIdList[idx]) self.bboxIdList.pop(idx) self.bboxList.pop(idx) - #Raj: - self.yoloList.pop(idx) self.listbox.delete(idx) def clearBBox(self): @@ -328,8 +326,6 @@ def clearBBox(self): self.listbox.delete(0, len(self.bboxList)) self.bboxIdList = [] self.bboxList = [] - #Raj: - self.yoloList = [] def prevImage(self, event = None): self.saveImage() From 2b950d37bfd1894c125bc6c2c894f514b22b7111 Mon Sep 17 00:00:00 2001 From: Raj Pawan Gumdal Date: Fri, 16 Feb 2018 21:02:42 +0530 Subject: [PATCH 4/4] This script is to convert the txt annotation files to appropriate format needed by YOLO --- convert.py | 110 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 convert.py diff --git a/convert.py b/convert.py new file mode 100644 index 00000000..0ccd2fe8 --- /dev/null +++ b/convert.py @@ -0,0 +1,110 @@ +# -*- coding: utf-8 -*- +""" +Created on Wed Dec 9 14:55:43 2015 + +This script is to convert the txt annotation files to appropriate format needed by YOLO + +@author: Guanghan Ning +Email: gnxr9@mail.missouri.edu +""" + +import os +from os import walk, getcwd +from PIL import Image + +classes = ["helmet"] + +def convert(size, box): + dw = 1./size[0] + dh = 1./size[1] + x = (box[0] + box[1])/2.0 + y = (box[2] + box[3])/2.0 + w = box[1] - box[0] + h = box[3] - box[2] + x = x*dw + w = w*dw + y = y*dh + h = h*dh + return (x,y,w,h) + + +"""-------------------------------------------------------------------""" + +""" Configure Paths""" +cls = "helmet" + +#Raj: Changes in code to run it directory specific! working directory needs "images" folder where all images are there! +workingDirectory = "multiple-result" +mypath = "/Users/i305138/SAP/SKOM/BBox-Label-Tool/" + workingDirectory + "/labels/" + cls + "/" +outpath = "/Users/i305138/SAP/SKOM/BBox-Label-Tool/" + workingDirectory + "/labels-yolo/" + cls + "/" + +if cls not in classes: + exit(0) +cls_id = classes.index(cls) + +print ("Found class, class ID: " + str(cls_id)) + +wd = getcwd() +list_file = open('%s/%s/%s_list.txt'%(wd, workingDirectory, cls), 'w') + +""" Get input text file list """ +print ("My Path: " + mypath) +txt_name_list = [] +for (dirpath, dirnames, filenames) in walk(mypath): + txt_name_list.extend(filenames) + break +print(txt_name_list) +if '.DS_Store' in txt_name_list: txt_name_list.remove('.DS_Store') +print(txt_name_list) +""" Process """ +for txt_name in txt_name_list: + # txt_file = open("Labels/stop_sign/001.txt", "r") + + """ Open input text files """ + txt_path = mypath + txt_name + print("Input:" + txt_path) + txt_file = open(txt_path, "r") + lines = txt_file.read().split('\n') #for ubuntu, use "\r\n" instead of "\n" + print ("Source Lines: "+ str (lines)) + """ Open output text files """ + txt_outpath = outpath + txt_name + print("Output:" + txt_outpath) + txt_outfile = open(txt_outpath, "w") + + + """ Convert the data to YOLO format """ + ct = 0 + for line in lines: + #print('lenth of line is: ') + #print(len(line)) + #print('\n') + if(len(line) >= 2): + ct = ct + 1 + print(line + "\n") + elems = line.split(' ') + print(elems) + xmin = elems[0] + xmax = elems[2] + ymin = elems[1] + ymax = elems[3] + # + img_path = str('%s/%s/images/%s/%s.JPEG'%(wd, workingDirectory, cls, os.path.splitext(txt_name)[0])) + #t = magic.from_file(img_path) + #wh= re.search('(\d+) x (\d+)', t).groups() + im=Image.open(img_path) + w= int(im.size[0]) + h= int(im.size[1]) + #w = int(xmax) - int(xmin) + #h = int(ymax) - int(ymin) + # print(xmin) + print(w, h) + b = (float(xmin), float(xmax), float(ymin), float(ymax)) + bb = convert((w,h), b) + print(bb) + txt_outfile.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n') + + """ Save those images with bb into list""" + if(ct != 0): + list_file.write('%s/%s/images/%s/%s.JPEG\n'%(wd, workingDirectory, cls, os.path.splitext(txt_name)[0])) + +list_file.close()