Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added Images/001/framey00001.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Images/001/framey00002.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Images/001/framey00003.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Images/001/framey00004.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Images/001/framey00005.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Images/001/framey00006.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Images/001/framey00007.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Images/001/framey00008.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Images/001/framey00009.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Images/001/framey00010.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed Images/001/test.JPEG
Binary file not shown.
Binary file removed Images/001/test2.JPEG
Binary file not shown.
Binary file removed Images/001/test3.JPEG
Binary file not shown.
7 changes: 7 additions & 0 deletions Labels/001/framey00001.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
3
Car
788 409 988 640
2 wheeler
1048 256 1136 384
2 wheeler
1508 521 1680 787
7 changes: 7 additions & 0 deletions Labels/001/framey00002.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
3
2 wheeler
1056 264 1142 384
2 wheeler
1538 544 1690 800
Car
788 400 1000 624
3 changes: 3 additions & 0 deletions Labels/001/framey00003.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
1
2 wheeler
1006 624 1162 888
3 changes: 3 additions & 0 deletions Labels/001/framey00004.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
1
Auto
648 592 912 912
2 changes: 0 additions & 2 deletions Labels/001/test.txt

This file was deleted.

2 changes: 0 additions & 2 deletions Labels/001/test2.txt

This file was deleted.

2 changes: 0 additions & 2 deletions Labels/001/test3.txt

This file was deleted.

13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
195 changes: 152 additions & 43 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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("<Button-1>", self.mouseClick)
self.mainPanel.bind("<Motion>", self.mouseMove)
self.parent.bind("<Escape>", self.cancelBBox) # press <Espace> 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("<Left>", self.prevImage) #arrow keys for navigation
self.parent.bind("<Right>", self.nextImage)
self.parent.bind("<Button-3>", self.nextImage) # right click to go forward
self.mainPanel.grid(row = 1, column = 1, rowspan = 4, sticky = W+N)

# showing bbox info & delete bbox
Expand Down Expand Up @@ -115,23 +142,16 @@ 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()
self.parent.focus()
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
Expand All @@ -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)
Expand All @@ -149,27 +169,30 @@ 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)

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)
Expand All @@ -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)

Expand All @@ -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):
Expand Down Expand Up @@ -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()
Expand All @@ -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)
Expand Down