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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Help converting LabelMe Annotation Tool JSON format to YOLO text file format.
If you've already marked your segmentation dataset by LabelMe, it's easy to use this tool to help converting to YOLO format dataset.

## Parameters Explain
**--json_dir** LabelMe JSON files folder path.
**--json_dir** LabelMe JSON files folder path. (single folder with images and json files)

**--val_size (Optional)** Validation dataset size, for example 0.2 means 20% for validation and 80% for training.

Expand Down
129 changes: 63 additions & 66 deletions labelme2yolo.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

from sklearn.model_selection import train_test_split
from labelme import utils
import yaml
from tqdm import tqdm


class Labelme2YOLO(object):
Expand All @@ -26,19 +28,16 @@ def __init__(self, json_dir):
self._label_id_map = self._get_label_id_map(self._json_dir)

def _make_train_val_dir(self):
self._label_dir_path = os.path.join(self._json_dir,
'YOLODataset/labels/')
self._image_dir_path = os.path.join(self._json_dir,
'YOLODataset/images/')

for yolo_path in (os.path.join(self._label_dir_path + 'train/'),
os.path.join(self._label_dir_path + 'val/'),
os.path.join(self._image_dir_path + 'train/'),
os.path.join(self._image_dir_path + 'val/')):
self._dataset_dir_path = os.path.join(self._json_dir, 'YOLODataset/')

for yolo_path in (os.path.join(self._dataset_dir_path, 'train/labels'),
os.path.join(self._dataset_dir_path, 'train/images'),
os.path.join(self._dataset_dir_path, 'val/labels'),
os.path.join(self._dataset_dir_path, 'val/images')):
if os.path.exists(yolo_path):
shutil.rmtree(yolo_path)

os.makedirs(yolo_path)
os.makedirs(yolo_path)

def _get_label_id_map(self, json_dir):
label_set = set()
Expand All @@ -49,20 +48,24 @@ def _get_label_id_map(self, json_dir):
data = json.load(open(json_path))
for shape in data['shapes']:
label_set.add(shape['label'])

return OrderedDict([(label, label_id) \
for label_id, label in enumerate(label_set)])


# sort label_set
label_list = list(label_set)
label_list.sort()

return OrderedDict([(label, label_id)
for label_id, label in enumerate(label_list)])

def _train_test_split(self, folders, json_names, val_size):
if len(folders) > 0 and 'train' in folders and 'val' in folders:
train_folder = os.path.join(self._json_dir, 'train/')
train_json_names = [train_sample_name + '.json' \
for train_sample_name in os.listdir(train_folder) \
train_json_names = [train_sample_name + '.json'
for train_sample_name in os.listdir(train_folder)
if os.path.isdir(os.path.join(train_folder, train_sample_name))]

val_folder = os.path.join(self._json_dir, 'val/')
val_json_names = [val_sample_name + '.json' \
for val_sample_name in os.listdir(val_folder) \
val_json_names = [val_sample_name + '.json'
for val_sample_name in os.listdir(val_folder)
if os.path.isdir(os.path.join(val_folder, val_sample_name))]

return train_json_names, val_json_names
Expand All @@ -75,37 +78,29 @@ def _train_test_split(self, folders, json_names, val_size):
return train_json_names, val_json_names

def convert(self, val_size):
json_names = [file_name for file_name in os.listdir(self._json_dir) \
if os.path.isfile(os.path.join(self._json_dir, file_name)) and \
json_names = [file_name for file_name in os.listdir(self._json_dir)
if os.path.isfile(os.path.join(self._json_dir, file_name)) and
file_name.endswith('.json')]
folders = [file_name for file_name in os.listdir(self._json_dir) \
if os.path.isdir(os.path.join(self._json_dir, file_name))]
train_json_names, val_json_names = self._train_test_split(folders, json_names, val_size)


train_json_names, val_json_names = train_test_split(json_names, test_size=val_size)

self._make_train_val_dir()

# convert labelme object to yolo format object, and save them to files
# also get image from labelme json file and save them under images folder
for target_dir, json_names in zip(('train/', 'val/'),
(train_json_names, val_json_names)):
for json_name in json_names:

for target_dir, json_names_sub in zip(('train/', 'val/'), (train_json_names, val_json_names)):
print('\nConverting for %s set ...' % target_dir.replace('/', ''))
for json_name in tqdm(json_names_sub):
json_path = os.path.join(self._json_dir, json_name)
json_data = json.load(open(json_path))

print('Converting %s for %s ...' % (json_name, target_dir.replace('/', '')))

img_path = self._save_yolo_image(json_data,
json_name,
self._image_dir_path,
target_dir)

# print('Converting %s for %s ...' % (json_name, target_dir.replace('/', '')))

img_path = self._save_yolo_image(json_data, json_name, self._dataset_dir_path, target_dir + 'images/')

yolo_obj_list = self._get_yolo_object_list(json_data, img_path)
self._save_yolo_label(json_name,
self._label_dir_path,
target_dir,
yolo_obj_list)
self._save_yolo_label(json_name, self._dataset_dir_path, target_dir + 'labels/', yolo_obj_list)

print('Generating dataset.yaml file ...')
print(f"\nSuccessfully converted {len(json_names)} json files to YOLO format.")
print('\nGenerating dataset.yaml file ...')
self._save_dataset_yaml()

def convert_one(self, json_name):
Expand Down Expand Up @@ -156,9 +151,9 @@ def _get_circle_shape_yolo_object(self, shape, img_h, img_w):

def _get_other_shape_yolo_object(self, shape, img_h, img_w):
def __get_object_desc(obj_port_list):
__get_dist = lambda int_list: max(int_list) - min(int_list)
x_lists = [port[0] for port in obj_port_list]
def __get_dist(int_list): return max(int_list) - min(int_list)

x_lists = [port[0] for port in obj_port_list]
y_lists = [port[1] for port in obj_port_list]

return min(x_lists), __get_dist(x_lists), min(y_lists), __get_dist(y_lists)
Expand Down Expand Up @@ -197,20 +192,17 @@ def _save_yolo_image(self, json_data, json_name, image_dir_path, target_dir):
return img_path

def _save_dataset_yaml(self):
yaml_path = os.path.join(self._json_dir, 'YOLODataset/', 'dataset.yaml')

with open(yaml_path, 'w+') as yaml_file:
yaml_file.write('train: %s\n' % \
os.path.join(self._image_dir_path, 'train/'))
yaml_file.write('val: %s\n\n' % \
os.path.join(self._image_dir_path, 'val/'))
yaml_file.write('nc: %i\n\n' % len(self._label_id_map))

names_str = ''
for label, _ in self._label_id_map.items():
names_str += "'%s', " % label
names_str = names_str.rstrip(', ')
yaml_file.write('names: [%s]' % names_str)
dataset_yaml = {
'train': os.path.join('train/images'),
'val': os.path.join('val/images'),
'nc': len(self._label_id_map),
'names': list(self._label_id_map.keys())
}

with open(os.path.join(self._dataset_dir_path, 'dataset.yaml'), 'w') as yaml_file:
yaml.dump(dataset_yaml, yaml_file, default_flow_style=False)

print(f"\ndataset.yaml file saved in {self._dataset_dir_path}\n")


if __name__ == '__main__':
Expand All @@ -222,10 +214,15 @@ def _save_dataset_yaml(self):
parser.add_argument('--json_name',type=str, nargs='?', default=None,
help='If you put json name, it would convert only one json file to YOLO.')
args = parser.parse_args(sys.argv[1:])

convertor = Labelme2YOLO(args.json_dir)
if args.json_name is None:
convertor.convert(val_size=args.val_size)
else:
convertor.convert_one(args.json_name)


# for debug
json_dir = "<path to json dir>"
convertor = Labelme2YOLO(json_dir)
convertor.convert(val_size=0.1) # 10% for validation

# convertor = Labelme2YOLO(args.json_dir)

# if args.json_name is None:
# convertor.convert(val_size=args.val_size)
# else:
# convertor.convert_one(args.json_name)
Loading