Skip to content

Commit

Permalink
list readme
Browse files Browse the repository at this point in the history
  • Loading branch information
Cartucho committed Jan 22, 2018
1 parent 7cdec99 commit 9b0c642
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 38 deletions.
77 changes: 68 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,73 @@
# openbbox
# YOLO v2 Bounding Box Tool

Feel free to contribute!
[![New](https://img.shields.io/badge/2018-NEW-brightgreen.svg)](https://github.com/Cartucho/yolo-boundingbox-labeler-GUI/commits/master)
[![GitHub stars](https://img.shields.io/github/stars/Cartucho/yolo-boundingbox-labeler-GUI.svg?style=social&label=Stars)](https://github.com/Cartucho/yolo-boundingbox-labeler-GUI)

An open source bounding box tool using OpenCV 3 and Python.
Bounding box labeler tool to generate the training data in the format YOLO v2 requires.

Easily generate the training data in the format YOLOv2 requires.
<img src="https://media.giphy.com/media/l49JDgDSygJN369vW/giphy.gif" width="40%"><img src="https://media.giphy.com/media/3ohc1csRs9PoDgCeuk/giphy.gif" width="40%">
<img src="https://media.giphy.com/media/3o752fXKwTJJkhXP32/giphy.gif" width="40%"><img src="https://media.giphy.com/media/3ohc11t9auzSo6fwLS/giphy.gif" width="40%">

## Instructions:
## Table of contents

1. Insert images images in the folder 1.insert_images_here.
1.1 YOLO only accepts .jpg and .jpeg images, other types will be ignored
2. Insert class list in the file 2.insert_class_list_here.txt
3. Run the code: python run_this.py
- [Quick start](#quick-start)
- [Prerequisites](#prerequisites)
- [Run project](#run-project)
- [GUI usage](#gui-usage)
- [Authors](#authors)

## Quick start

To start using the YOLO Bounding Box Tool you need to [download the latest release](https://github.com/Cartucho/yolo-boundingbox-labeler-GUI/archive/v1.1.zip) or clone the repo:

```
git clone https://github.com/Cartucho/yolo-boundingbox-labeler-GUI
```

### Prerequisites

You need to install:

- [OpenCV](https://opencv.org/) version >= 3.0
- [Installation in Windows](https://docs.opencv.org/master/d3/d52/tutorial_windows_install.html)
- [Installation in Linux](https://docs.opencv.org/master/d7/d9f/tutorial_linux_install.html)
- [Python](https://www.python.org/downloads/)

### Run project

Step by step:

1. Insert the images in the folder **images/**
2. Insert the class list in the file **class_list.txt**
3. Run the code:
```
python run.py
```
4. You can find the bounding box files in the folder **bbox_txt/**

### GUI usage

Keyboard, press:

<img src="https://github.com/Cartucho/yolo-boundingbox-labeler-GUI/blob/master/keyboard_usage.jpg">

| Key | Description |
| --- | --- |
| h | help |
| q | quit |
| e | edges |
| a/d | previous/next image |
| s/w | previous/next class |


Mouse:
- Use two left clicks to do each bounding box
- Use the middle mouse to zoom in and out

## Authors

* **João Cartucho** - Please give me your feedback: [email protected]

Feel free to contribute

[![GitHub contributors](https://img.shields.io/github/contributors/Cartucho/yolo-boundingbox-labeler-GUI.svg)](https://github.com/Cartucho/yolo-boundingbox-labeler-GUI/graphs/contributors)
File renamed without changes.
File renamed without changes
File renamed without changes
File renamed without changes
Binary file added keyboard_usage.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
130 changes: 101 additions & 29 deletions 3.run_this.py → run.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
class_index = 0
img_index = 0
img = None
img_objects = []
bb_dir = "bbox_txt/"

mouse_x = 0
mouse_y = 0

point_1 = (-1, -1)
point_2 = (-1, -1)

Expand Down Expand Up @@ -72,15 +74,27 @@ def yolo_format(class_index, point_1, point_2, height, width):


def get_txt_path(img_path):
img_name = img_path.split('/')[-1]
img_type = img_path.split('.')[-1]
return img_path.replace(img_type, 'txt')
return bb_dir + img_name.replace(img_type, 'txt')


def save_bb(text_path, line):
with open(text_path, 'a') as myfile:
def save_bb(txt_path, line):
with open(txt_path, 'a') as myfile:
myfile.write(line + "\n") # append line


def delete_bb(txt_path, line_index):
with open(txt_path, "r") as old_file:
lines = old_file.readlines()

with open(txt_path, "w") as new_file:
counter = 0
for line in lines:
if counter is not line_index:
new_file.write(line)
counter += 1

def yolo_to_x_y(x_center, y_center, x_width, y_height, width, height):
x_center *= width
y_center *= height
Expand All @@ -91,16 +105,22 @@ def yolo_to_x_y(x_center, y_center, x_width, y_height, width, height):
return int(x_center - x_width), int(y_center - y_height), int(x_center + x_width), int(y_center + y_height)

def draw_bboxes_from_file(tmp_img, txt_path, width, height):
global img_objects
img_objects = []
if os.path.isfile(txt_path):
with open(txt_path) as f:
content = f.readlines()
for line in content:
values_str = line.split()
class_index, x_center, y_center, x_width, y_height = map(float, values_str)
class_index = int(class_index)
# convert yolo to points
x1, y1, x2, y2 = yolo_to_x_y(x_center, y_center, x_width, y_height, width, height)
color = class_rgb[int(class_index)]
img_objects.append([class_index, x1, y1, x2, y2])
color = class_rgb[class_index]
cv2.rectangle(tmp_img, (x1, y1), (x2, y2), color, 2)
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(tmp_img, class_list[class_index], (x1, y1 - 5), font, 0.6, color, 2, cv2.LINE_AA)
return tmp_img

# mouse callback function
Expand All @@ -111,22 +131,53 @@ def draw_roi(event, x, y, flags, param):
mouse_y = y
elif event == cv2.EVENT_LBUTTONDOWN:
if point_1[0] is -1:
# first click
cv2.displayOverlay(WINDOW_NAME, "Currently selected label:\n"
"" + class_list[class_index] + "", 2000)
# first click (start drawing a bounding box or delete an item)
point_1 = (x, y)
else:
# second click
point_2 = (x, y)


def is_mouse_inside_points(x1, y1, x2, y2):
return mouse_x > x1 and mouse_x < x2 and mouse_y > y1 and mouse_y < y2


def get_close_icon(x1, y1, x2, y2):
percentage = 0.1
height = -1
while height < 15 and percentage < 1.0:
height = int((y2 - y1) * percentage)
percentage += 0.1
return (x2 - height), y1, x2, (y1 + height)


def draw_close_icon(tmp_img, x1_c, y1_c, x2_c, y2_c):
red = (0,0,255)
cv2.rectangle(tmp_img, (x1_c + 1, y1_c - 1), (x2_c, y2_c), red, -1)
white = (255, 255, 255)
cv2.line(tmp_img, (x1_c, y1_c), (x2_c, y2_c), white, 2)
cv2.line(tmp_img, (x1_c, y2_c), (x2_c, y1_c), white, 2)
return tmp_img


def draw_info_if_bb_selected(tmp_img):
for obj in img_objects:
ind, x1, y1, x2, y2 = obj
if is_mouse_inside_points(x1, y1, x2, y2):
x1_c, y1_c, x2_c, y2_c = get_close_icon(x1, y1, x2, y2)
tmp_img = draw_close_icon(tmp_img, x1_c, y1_c, x2_c, y2_c)
return tmp_img


# load img list
image_list = glob.glob('1.insert_images_here/*.jpg')
image_list.extend(glob.glob('1.insert_images_here/*.jpeg'))
print(image_list)
img_dir = "images/"
image_list = glob.glob(img_dir +'*.jpg')
image_list.extend(glob.glob(img_dir + '*.jpeg'))
#print(image_list)
last_img_index = len(image_list) - 1

# load class list
with open('2.insert_class_list_here.txt') as f:
with open('class_list.txt') as f:
class_list = f.read().splitlines()
#print(class_list)
last_class_index = len(class_list) - 1
Expand All @@ -135,7 +186,7 @@ def draw_roi(event, x, y, flags, param):
class_rgb = np.random.random_integers(low=0, high=255, size=(3,len(class_list)))

# create window
WINDOW_NAME = 'openbbox'
WINDOW_NAME = 'Bounding Box Labeler'
cv2.namedWindow(WINDOW_NAME, cv2.WINDOW_KEEPRATIO)
cv2.resizeWindow(WINDOW_NAME, 1000, 700)
cv2.setMouseCallback(WINDOW_NAME, draw_roi)
Expand All @@ -152,8 +203,11 @@ def draw_roi(event, x, y, flags, param):
change_img_index(0)
edges_on = False

cv2.displayOverlay(WINDOW_NAME, "Welcome to openbbox!\n Press [h] for help.", 4000)
print(" Welcome to openbbox!\n Select the window and press [h] for help.")
cv2.displayOverlay(WINDOW_NAME, "Welcome!\n Press [h] for help.", 4000)
print(" Welcome!\n Select the window and press [h] for help.")

if not os.path.exists(bb_dir):
os.makedirs(bb_dir)

# loop
while True:
Expand All @@ -163,28 +217,46 @@ def draw_roi(event, x, y, flags, param):
if edges_on == True:
# draw edges
tmp_img = draw_edges(tmp_img)
# draw vertical yellow lines
draw_line(tmp_img, mouse_x, mouse_y, width, height) # show vertical and horizontal line
# draw vertical and horizong yellow guide lines
draw_line(tmp_img, mouse_x, mouse_y, width, height)
img_path = image_list[img_index]
txt_path = get_txt_path(img_path)
# draw already done bounding boxes
tmp_img = draw_bboxes_from_file(tmp_img, txt_path, width, height)
# if bounding box is selected add extra info
tmp_img = draw_info_if_bb_selected(tmp_img)
# if first click
if point_1[0] is not -1:
color = class_rgb[class_index]
# draw partial bbox
cv2.rectangle(tmp_img, point_1, (mouse_x, mouse_y), color, 2)
# if second click
if point_2[0] is not -1:
# save the bounding box
line = yolo_format(class_index, point_1, point_2, width, height)
save_bb(txt_path, line)
# reset the points
point_1 = (-1, -1)
point_2 = (-1, -1)
removed_an_object = False
# if clicked inside a delete button, then remove that object
for obj in img_objects:
ind, x1, y1, x2, y2 = obj
x1, y1, x2, y2 = get_close_icon(x1, y1, x2, y2)
if is_mouse_inside_points(x1, y1, x2, y2):
# remove that object
delete_bb(txt_path, img_objects.index(obj))
removed_an_object = True
point_1 = (-1, -1)
break

if not removed_an_object:
color = class_rgb[class_index]
# draw partial bbox
cv2.rectangle(tmp_img, point_1, (mouse_x, mouse_y), color, 2)
# if second click
if point_2[0] is not -1:
# save the bounding box
line = yolo_format(class_index, point_1, point_2, width, height)
save_bb(txt_path, line)
# reset the points
point_1 = (-1, -1)
point_2 = (-1, -1)
else:
cv2.displayOverlay(WINDOW_NAME, "Selected label: " + class_list[class_index] + ""
"\nPress [w] or [s] to change.", 120)

cv2.imshow(WINDOW_NAME, tmp_img)
pressed_key = cv2.waitKey(50)
pressed_key = cv2.waitKey(100)

""" Key Listeners START """
if pressed_key == ord('a') or pressed_key == ord('d'):
Expand Down

0 comments on commit 9b0c642

Please sign in to comment.