diff --git a/Images/001/framey00001.jpg b/Images/001/framey00001.jpg new file mode 100644 index 00000000..b2e6fd7b Binary files /dev/null and b/Images/001/framey00001.jpg differ diff --git a/Images/001/framey00002.jpg b/Images/001/framey00002.jpg new file mode 100644 index 00000000..47d72597 Binary files /dev/null and b/Images/001/framey00002.jpg differ diff --git a/Images/001/framey00003.jpg b/Images/001/framey00003.jpg new file mode 100644 index 00000000..e560d871 Binary files /dev/null and b/Images/001/framey00003.jpg differ diff --git a/Images/001/framey00004.jpg b/Images/001/framey00004.jpg new file mode 100644 index 00000000..6cd95b0b Binary files /dev/null and b/Images/001/framey00004.jpg differ diff --git a/Images/001/framey00005.jpg b/Images/001/framey00005.jpg new file mode 100644 index 00000000..8f0a93b3 Binary files /dev/null and b/Images/001/framey00005.jpg differ diff --git a/Images/001/framey00006.jpg b/Images/001/framey00006.jpg new file mode 100644 index 00000000..2b040ca1 Binary files /dev/null and b/Images/001/framey00006.jpg differ diff --git a/Images/001/framey00007.jpg b/Images/001/framey00007.jpg new file mode 100644 index 00000000..a8d50c01 Binary files /dev/null and b/Images/001/framey00007.jpg differ diff --git a/Images/001/framey00008.jpg b/Images/001/framey00008.jpg new file mode 100644 index 00000000..9fb151f4 Binary files /dev/null and b/Images/001/framey00008.jpg differ diff --git a/Images/001/framey00009.jpg b/Images/001/framey00009.jpg new file mode 100644 index 00000000..858f0ffe Binary files /dev/null and b/Images/001/framey00009.jpg differ diff --git a/Images/001/framey00010.jpg b/Images/001/framey00010.jpg new file mode 100644 index 00000000..0b3200d4 Binary files /dev/null and b/Images/001/framey00010.jpg differ diff --git a/Images/001/test.JPEG b/Images/001/test.JPEG deleted file mode 100644 index 581e403f..00000000 Binary files a/Images/001/test.JPEG and /dev/null differ diff --git a/Images/001/test2.JPEG b/Images/001/test2.JPEG deleted file mode 100644 index f0778d4b..00000000 Binary files a/Images/001/test2.JPEG and /dev/null differ diff --git a/Images/001/test3.JPEG b/Images/001/test3.JPEG deleted file mode 100644 index bc412890..00000000 Binary files a/Images/001/test3.JPEG and /dev/null differ diff --git a/Labels/001/framey00001.txt b/Labels/001/framey00001.txt new file mode 100644 index 00000000..258c0a32 --- /dev/null +++ b/Labels/001/framey00001.txt @@ -0,0 +1,7 @@ +3 +Car +788 409 988 640 +2 wheeler +1048 256 1136 384 +2 wheeler +1508 521 1680 787 diff --git a/Labels/001/framey00002.txt b/Labels/001/framey00002.txt new file mode 100644 index 00000000..421e8cdf --- /dev/null +++ b/Labels/001/framey00002.txt @@ -0,0 +1,7 @@ +3 +2 wheeler +1056 264 1142 384 +2 wheeler +1538 544 1690 800 +Car +788 400 1000 624 diff --git a/Labels/001/framey00003.txt b/Labels/001/framey00003.txt new file mode 100644 index 00000000..d8efb985 --- /dev/null +++ b/Labels/001/framey00003.txt @@ -0,0 +1,3 @@ +1 +2 wheeler +1006 624 1162 888 diff --git a/Labels/001/framey00004.txt b/Labels/001/framey00004.txt new file mode 100644 index 00000000..d2ead860 --- /dev/null +++ b/Labels/001/framey00004.txt @@ -0,0 +1,3 @@ +1 +Auto +648 592 912 912 diff --git a/Labels/001/test.txt b/Labels/001/test.txt deleted file mode 100644 index 808509e1..00000000 --- a/Labels/001/test.txt +++ /dev/null @@ -1,2 +0,0 @@ -1 -80 8 172 111 diff --git a/Labels/001/test2.txt b/Labels/001/test2.txt deleted file mode 100644 index 22e8a683..00000000 --- a/Labels/001/test2.txt +++ /dev/null @@ -1,2 +0,0 @@ -1 -129 42 389 235 diff --git a/Labels/001/test3.txt b/Labels/001/test3.txt deleted file mode 100644 index e51f2880..00000000 --- a/Labels/001/test3.txt +++ /dev/null @@ -1,2 +0,0 @@ -1 -74 73 171 170 diff --git a/README.md b/README.md index 5c823f37..2f46e5df 100644 --- a/README.md +++ b/README.md @@ -39,4 +39,15 @@ Usage - To delete a existing bounding box, select it from the listbox, and click `Delete`. - To delete all existing bounding boxes in the image, simply click `ClearAll`. 3. After finishing one image, click `Next` to advance. Likewise, click `Prev` to reverse. Or, input an image id and click `Go` to navigate to the speficied image. - - Be sure to click `Next` after finishing a image, or the result won't be saved. + - Be sure to click `Next` after finishing a image, or the result won't be saved. + + **New Feature To Add Labels** + ----------------------------- + 1. The tool now supports adding class labels to a bounding box. + 2. Each class has been assigned a number. + 3. Each bounding box has been assigned a label. If no label is specified, the box is allocated '0'. + 4. To allocate a label to a box select it from the list of bounding boxes and press the button corresponding to the class you want to allocate it to (or press the corresponding number key). + 5. Be sure to click `Next` (or `Prev` ) after finishing to save your changes. + 6. The label number to text correspondance can be changed by editing the map on `line 44` of main.py ( and changing the text on the button too!) + + *NOTE*: The text file with the bounding boxes stores the text and not the number. diff --git a/main.py b/main.py index e19a0888..81886862 100644 --- a/main.py +++ b/main.py @@ -36,11 +36,14 @@ def __init__(self, master): self.outDir = '' self.cur = 0 self.total = 0 - self.category = 0 + self.category = 1 self.imagename = '' self.labelfilename = '' self.tkimg = None + self.label_number_map = ["","Car","2 wheeler","Bus","Truck","Auto"] #map for number to label name + self.reverse_label_map = {"":0,"Car":1,"2 wheeler":2,"Bus":3,"Truck":4,"Auto":5} + # initialize mouse state self.STATE = {} self.STATE['click'] = 0 @@ -52,6 +55,7 @@ def __init__(self, master): self.bboxList = [] self.hl = None self.vl = None + self.bbox_labels_list = [] # ----------------- GUI stuff --------------------- # dir entry & load @@ -62,14 +66,37 @@ def __init__(self, master): self.ldBtn = Button(self.frame, text = "Load", command = self.loadDir) self.ldBtn.grid(row = 0, column = 2, sticky = W+E) + #buttons for adding labels + self.label_1_Btn = Button(self.frame, text = "Car(1)",width = 16,command = self.addLabel1) + self.label_1_Btn.grid(row = 0, column = 3, sticky = N+E) + + self.label_2_Btn = Button(self.frame, text = "2 Wheeler(2)",width = 16,command = self.addLabel2) + self.label_2_Btn.grid(row = 0, column = 4, sticky = N+E) + + self.label_3_Btn = Button(self.frame, text = "Bus(3)",width = 16,command = self.addLabel3) + self.label_3_Btn.grid(row = 1, column = 3, sticky = N+E) + + self.label_4_Btn = Button(self.frame, text = "Truck(4)",width = 16,command = self.addLabel4) + self.label_4_Btn.grid(row = 1, column = 4, sticky = N+E) + + self.label_5_Btn = Button(self.frame, text = "Auto(5)",width = 16,command = self.addLabel5) + self.label_5_Btn.grid(row = 2, column = 3, sticky = N+E) + # main panel for labeling self.mainPanel = Canvas(self.frame, cursor='tcross') self.mainPanel.bind("", self.mouseClick) self.mainPanel.bind("", self.mouseMove) self.parent.bind("", self.cancelBBox) # press to cancel current bbox + self.parent.bind("1",self.addLabel1) #to add the corresponding label + self.parent.bind("2",self.addLabel2) + self.parent.bind("3",self.addLabel3) + self.parent.bind("4",self.addLabel4) + self.parent.bind("5",self.addLabel5) self.parent.bind("s", self.cancelBBox) - self.parent.bind("a", self.prevImage) # press 'a' to go backforward - self.parent.bind("d", self.nextImage) # press 'd' to go forward + self.parent.bind("a", self.prevImage) + self.parent.bind("", self.prevImage) #arrow keys for navigation + self.parent.bind("", self.nextImage) + self.parent.bind("", self.nextImage) # right click to go forward self.mainPanel.grid(row = 1, column = 1, rowspan = 4, sticky = W+N) # showing bbox info & delete bbox @@ -115,10 +142,6 @@ def __init__(self, master): self.frame.columnconfigure(1, weight = 1) self.frame.rowconfigure(4, weight = 1) - # for debugging -## self.setImage() -## self.loadDir() - def loadDir(self, dbg = False): if not dbg: s = self.entry.get() @@ -126,12 +149,9 @@ def loadDir(self, dbg = False): self.category = int(s) else: s = r'D:\workspace\python\labelGUI' -## if not os.path.isdir(s): -## tkMessageBox.showerror("Error!", message = "The specified dir doesn't exist!") -## return - # get image list + self.imageDir = os.path.join(r'./Images', '%03d' %(self.category)) - self.imageList = glob.glob(os.path.join(self.imageDir, '*.JPEG')) + self.imageList = sorted(glob.glob(os.path.join(self.imageDir, '*.jpg'))) if len(self.imageList) == 0: print 'No .JPEG images found in the specified dir!' return @@ -140,7 +160,7 @@ def loadDir(self, dbg = False): self.cur = 1 self.total = len(self.imageList) - # set up output dir + # set up output dir self.outDir = os.path.join(r'./Labels', '%03d' %(self.category)) if not os.path.exists(self.outDir): os.mkdir(self.outDir) @@ -149,19 +169,22 @@ def loadDir(self, dbg = False): self.egDir = os.path.join(r'./Examples', '%03d' %(self.category)) if not os.path.exists(self.egDir): return - filelist = glob.glob(os.path.join(self.egDir, '*.JPEG')) + filelist = glob.glob(os.path.join(self.egDir, '*.jpg')) self.tmp = [] self.egList = [] - random.shuffle(filelist) + print "filelist =",filelist for (i, f) in enumerate(filelist): - if i == 3: - break - im = Image.open(f) - r = min(SIZE[0] / im.size[0], SIZE[1] / im.size[1]) - new_size = int(r * im.size[0]), int(r * im.size[1]) - self.tmp.append(im.resize(new_size, Image.ANTIALIAS)) - self.egList.append(ImageTk.PhotoImage(self.tmp[-1])) - self.egLabels[i].config(image = self.egList[-1], width = SIZE[0], height = SIZE[1]) + print "in the loop" + if i == 3: + print "breing the loop" + break + im = Image.open(f) + print im + r = min(SIZE[0] / im.size[0], SIZE[1] / im.size[1]) + new_size = int(r * im.size[0]), int(r * im.size[1]) + self.tmp.append(im.resize(new_size, Image.ANTIALIAS)) + self.egList.append(ImageTk.PhotoImage(self.tmp[-1])) + self.egLabels[i].config(image = self.egList[-1], width = SIZE[0], height = SIZE[1]) self.loadImage() print '%d images loaded from %s' %(self.total, s) @@ -169,7 +192,7 @@ def loadDir(self, dbg = False): def loadImage(self): # load image imagepath = self.imageList[self.cur - 1] - self.img = Image.open(imagepath) + self.img = (Image.open(imagepath)).resize((960,675))#2,1.6 self.tkimg = ImageTk.PhotoImage(self.img) self.mainPanel.config(width = max(self.tkimg.width(), 400), height = max(self.tkimg.height(), 400)) self.mainPanel.create_image(0, 0, image = self.tkimg, anchor=NW) @@ -181,27 +204,41 @@ def loadImage(self): labelname = self.imagename + '.txt' self.labelfilename = os.path.join(self.outDir, labelname) bbox_cnt = 0 + loaded_label_str = "" + loaded_label_num = 0 if os.path.exists(self.labelfilename): with open(self.labelfilename) as f: for (i, line) in enumerate(f): if i == 0: bbox_cnt = int(line.strip()) continue - tmp = [int(t.strip()) for t in line.split()] -## print tmp - self.bboxList.append(tuple(tmp)) - tmpId = self.mainPanel.create_rectangle(tmp[0], tmp[1], \ - tmp[2], tmp[3], \ - width = 2, \ - outline = COLORS[(len(self.bboxList)-1) % len(COLORS)]) - self.bboxIdList.append(tmpId) - self.listbox.insert(END, '(%d, %d) -> (%d, %d)' %(tmp[0], tmp[1], tmp[2], tmp[3])) - self.listbox.itemconfig(len(self.bboxIdList) - 1, fg = COLORS[(len(self.bboxIdList) - 1) % len(COLORS)]) + elif i%2 == 1: #odd lines contain the label + loaded_label_str = str(line.strip()) + loaded_label_num = self.reverse_label_map[loaded_label_str] + + else: + tmp = [int(t.strip()) for t in line.split()] + tmp = [int(tmp[0]/2),int(tmp[1]/1.6),int(tmp[2]/2),int(tmp[3]/1.6)] + self.bboxList.append(tuple(tmp)) + self.bbox_labels_list.append(loaded_label_num) + tmpId = self.mainPanel.create_rectangle(tmp[0], tmp[1], \ + tmp[2], tmp[3], \ + width = 2, \ + outline = COLORS[(len(self.bboxList)-1) % len(COLORS)]) + self.bboxIdList.append(tmpId) + self.listbox.insert(END, '(%d, %d) -> (%d, %d) : %d' %(tmp[0], tmp[1], tmp[2], tmp[3],loaded_label_num)) + self.listbox.itemconfig(len(self.bboxIdList) - 1, fg = COLORS[(len(self.bboxIdList) - 1) % len(COLORS)]) + def saveImage(self): with open(self.labelfilename, 'w') as f: f.write('%d\n' %len(self.bboxList)) - for bbox in self.bboxList: + for i in range(len(self.bboxList)): + bbox = self.bboxList[i] + bbox = (bbox[0]*2,int(bbox[1]*1.6),bbox[2]*2,int(bbox[3]*1.6)) + + f.write(self.label_number_map[self.bbox_labels_list[i]] + '\n')#writing the label string onto the file and not the number + f.write(' '.join(map(str, bbox)) + '\n') print 'Image No. %d saved' %(self.cur) @@ -213,10 +250,14 @@ def mouseClick(self, event): x1, x2 = min(self.STATE['x'], event.x), max(self.STATE['x'], event.x) y1, y2 = min(self.STATE['y'], event.y), max(self.STATE['y'], event.y) self.bboxList.append((x1, y1, x2, y2)) + + self.bbox_labels_list.append(0) #since no label assigned till now.do that in the button action + self.bboxIdList.append(self.bboxId) self.bboxId = None - self.listbox.insert(END, '(%d, %d) -> (%d, %d)' %(x1, y1, x2, y2)) + self.listbox.insert(END, '(%d, %d) -> (%d, %d) : %d' %(x1, y1, x2, y2,0)) #the last one is the class of the label assigned self.listbox.itemconfig(len(self.bboxIdList) - 1, fg = COLORS[(len(self.bboxIdList) - 1) % len(COLORS)]) + self.STATE['click'] = 1 - self.STATE['click'] def mouseMove(self, event): @@ -251,14 +292,89 @@ def delBBox(self): self.mainPanel.delete(self.bboxIdList[idx]) self.bboxIdList.pop(idx) self.bboxList.pop(idx) + self.bbox_labels_list.pop(idx) self.listbox.delete(idx) + #action for first label button + def addLabel1(self,event = None): + sel = self.listbox.curselection() + if len(sel) != 1 : + return + + #edit the label and what comes in the box + idx = int(sel[0]) + self.bbox_labels_list[idx] = 1 + + temp = self.bboxList[idx] + self.listbox.delete(idx) + self.listbox.insert(idx, '(%d, %d) -> (%d, %d) : %d' %(temp[0],temp[1],temp[2],temp[3],1)) + self.listbox.itemconfig(idx,fg = COLORS[(idx) % len(COLORS)]) + + def addLabel2(self,event = None): + sel = self.listbox.curselection() + if len(sel) != 1 : + return + + #edit the label and what comes in the box + idx = int(sel[0]) + self.bbox_labels_list[idx] = 2 + + temp = self.bboxList[idx] + self.listbox.delete(idx) + self.listbox.insert(idx, '(%d, %d) -> (%d, %d) : %d' %(temp[0],temp[1],temp[2],temp[3],2)) + self.listbox.itemconfig(idx,fg = COLORS[(idx) % len(COLORS)]) + + def addLabel3(self,event = None): + sel = self.listbox.curselection() + if len(sel) != 1 : + return + + #edit the label and what comes in the box + idx = int(sel[0]) + self.bbox_labels_list[idx] = 3 + + temp = self.bboxList[idx] + self.listbox.delete(idx) + self.listbox.insert(idx, '(%d, %d) -> (%d, %d) : %d' %(temp[0],temp[1],temp[2],temp[3],3)) + self.listbox.itemconfig(idx,fg = COLORS[(idx) % len(COLORS)]) + + def addLabel4(self,event = None): + sel = self.listbox.curselection() + if len(sel) != 1 : + return + + #edit the label and what comes in the box + idx = int(sel[0]) + self.bbox_labels_list[idx] = 4 + + temp = self.bboxList[idx] + self.listbox.delete(idx) + self.listbox.insert(idx, '(%d, %d) -> (%d, %d) : %d' %(temp[0],temp[1],temp[2],temp[3],4)) + self.listbox.itemconfig(idx,fg = COLORS[(idx) % len(COLORS)]) + + def addLabel5(self,event = None): + sel = self.listbox.curselection() + if len(sel) != 1 : + return + + #edit the label and what comes in the box + idx = int(sel[0]) + self.bbox_labels_list[idx] = 5 + + temp = self.bboxList[idx] + self.listbox.delete(idx) + self.listbox.insert(idx, '(%d, %d) -> (%d, %d) : %d' %(temp[0],temp[1],temp[2],temp[3],5)) + self.listbox.itemconfig(idx,fg = COLORS[(idx) % len(COLORS)]) + + #too much repeated code. make this neater + def clearBBox(self): for idx in range(len(self.bboxIdList)): self.mainPanel.delete(self.bboxIdList[idx]) self.listbox.delete(0, len(self.bboxList)) self.bboxIdList = [] self.bboxList = [] + self.bbox_labels_list = [] def prevImage(self, event = None): self.saveImage() @@ -279,13 +395,6 @@ def gotoImage(self): self.cur = idx self.loadImage() -## def setImage(self, imagepath = r'test2.png'): -## self.img = Image.open(imagepath) -## self.tkimg = ImageTk.PhotoImage(self.img) -## self.mainPanel.config(width = self.tkimg.width()) -## self.mainPanel.config(height = self.tkimg.height()) -## self.mainPanel.create_image(0, 0, image = self.tkimg, anchor=NW) - if __name__ == '__main__': root = Tk() tool = LabelTool(root)