add output_format option

This commit is contained in:
Wang Xin 2023-03-16 13:48:24 +08:00
parent 14b716e173
commit 1f31b4bae9
5 changed files with 49 additions and 70 deletions

2
.gitignore vendored
View File

@ -1,3 +1,5 @@
dataset/
# Byte-compiled / optimized / DLL files # Byte-compiled / optimized / DLL files
__pycache__/ __pycache__/
*.py[cod] *.py[cod]

View File

@ -14,7 +14,7 @@ If you've already marked your segmentation dataset by LabelMe, it's easy to use
## New ## New
- export data as yolo polygon annotation (for YOLOv5 v7.0 segmentation) - export data as yolo polygon annotation (for YOLOv5 v7.0 segmentation)
- Now you can choose the output format of the label text. The available options are `plygon` and `bbox`.
## Installation ## Installation
```console ```console
@ -30,6 +30,8 @@ pip install labelme2yolo
**--json_name (Optional)** Convert single LabelMe JSON file. **--json_name (Optional)** Convert single LabelMe JSON file.
**--output_format (Optional)** The output format of label.
## How to Use ## How to Use
### 1. Convert JSON files, split training, validation and test dataset by --val_size and --test_size ### 1. Convert JSON files, split training, validation and test dataset by --val_size and --test_size

View File

@ -1,5 +1,5 @@
# SPDX-FileCopyrightText: 2022-present Wang Xin <xinwang614@gmail.com> # SPDX-FileCopyrightText: 2023-present Wang Xin <xinwang614@gmail.com>
# #
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
__version__ = '0.0.8' __version__ = '0.0.9'

View File

@ -16,14 +16,14 @@ def run():
type=float, type=float,
nargs="?", nargs="?",
default=None, default=None,
help="Please input the validation dataset size, for example 0.1 ", help="Please input the validation dataset size, for example 0.1.",
) )
parser.add_argument( parser.add_argument(
"--test_size", "--test_size",
type=float, type=float,
nargs="?", nargs="?",
default=None, default=None,
help="Please input the validation dataset size, for example 0.1 ", help="Please input the test dataset size, for example 0.1.",
) )
parser.add_argument( parser.add_argument(
"--json_name", "--json_name",
@ -32,13 +32,21 @@ def run():
default=None, default=None,
help="If you put json name, it would convert only one json file to YOLO.", help="If you put json name, it would convert only one json file to YOLO.",
) )
parser.add_argument(
"--output_format",
type=str,
default="polygon",
help='The default output format for labelme2yolo is "polygon".'
' However, you can choose to output in bbox format by specifying the "bbox" option.',
)
args = parser.parse_args() args = parser.parse_args()
if not args.json_dir: if not args.json_dir:
parser.print_help() parser.print_help()
return 0 return 0
convertor = Labelme2YOLO(args.json_dir) convertor = Labelme2YOLO(args.json_dir, args.output_format)
if args.json_name is None: if args.json_name is None:
convertor.convert(val_size=args.val_size, test_size=args.test_size) convertor.convert(val_size=args.val_size, test_size=args.test_size)

View File

@ -93,27 +93,28 @@ def get_label_id_map(json_dir):
return OrderedDict([(label, label_id) for label_id, label in enumerate(label_set)]) return OrderedDict([(label, label_id) for label_id, label in enumerate(label_set)])
def extend_point_list(point_list): def extend_point_list(point_list, format="polygon"):
xmin = min([float(point) for point in point_list[::2]]) xmin = min([float(point) for point in point_list[::2]])
xmax = max([float(point) for point in point_list[::2]]) xmax = max([float(point) for point in point_list[::2]])
ymin = min([float(point) for point in point_list[1::2]]) ymin = min([float(point) for point in point_list[1::2]])
ymax = max([float(point) for point in point_list[1::2]]) ymax = max([float(point) for point in point_list[1::2]])
return np.array([xmin, ymin, xmax, ymin, xmax, ymax, xmin, ymax]) if (format == "polygon"):
return np.array([xmin, ymin, xmax, ymin, xmax, ymax, xmin, ymax])
if (format == "bbox"):
return np.array([xmin, ymin, xmax - xmin, ymax - ymin])
def save_yolo_label(json_name, label_dir_path, target_dir, yolo_obj_list): def save_yolo_label(json_name, label_dir_path, target_dir, yolo_obj_list):
txt_path = os.path.join( txt_path = os.path.join(label_dir_path,
label_dir_path, target_dir, json_name.replace(".json", ".txt") target_dir,
) json_name.replace(".json", ".txt"))
with open(txt_path, "w+") as f: with open(txt_path, "w+") as f:
for yolo_obj_idx, yolo_obj in enumerate(yolo_obj_list): for yolo_obj in yolo_obj_list:
yolo_obj_line = ( label, points = yolo_obj
"%s %s %s %s %s\n" % yolo_obj points = [str(item) for item in points]
if yolo_obj_idx + 1 != len(yolo_obj_list) yolo_obj_line = f"{label} {' '.join(points)}\n"
else "%s %s %s %s %s" % yolo_obj
)
f.write(yolo_obj_line) f.write(yolo_obj_line)
@ -130,10 +131,11 @@ def save_yolo_image(json_data, json_name, image_dir_path, target_dir):
class Labelme2YOLO(object): class Labelme2YOLO(object):
def __init__(self, json_dir): def __init__(self, json_dir, output_format):
self._json_dir = json_dir self._json_dir = json_dir
self._output_format = output_format
self._label_id_map = self._get_label_id_map(self._json_dir) self._label_id_map = get_label_id_map(self._json_dir)
def _make_train_val_dir(self): def _make_train_val_dir(self):
self._label_dir_path = os.path.join(self._json_dir, self._label_dir_path = os.path.join(self._json_dir,
@ -152,20 +154,6 @@ class Labelme2YOLO(object):
os.makedirs(yolo_path) os.makedirs(yolo_path)
@staticmethod
def _get_label_id_map(self, json_dir):
label_set = set()
for file_name in os.listdir(json_dir):
if file_name.endswith('json'):
json_path = os.path.join(json_dir, file_name)
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)])
def _train_test_split(self, folders, json_names, val_size, test_size): def _train_test_split(self, folders, json_names, val_size, test_size):
if len(folders) > 0 and 'train' in folders and 'val' in folders and 'test' in folders: if len(folders) > 0 and 'train' in folders and 'val' in folders and 'test' in folders:
train_folder = os.path.join(self._json_dir, 'train/') train_folder = os.path.join(self._json_dir, 'train/')
@ -233,15 +221,15 @@ class Labelme2YOLO(object):
print('Converting %s for %s ...' % print('Converting %s for %s ...' %
(json_name, target_dir.replace('/', ''))) (json_name, target_dir.replace('/', '')))
img_path = self._save_yolo_image(json_data, img_path = save_yolo_image(json_data,
json_name, json_name,
self._image_dir_path, self._image_dir_path,
target_dir) target_dir)
yolo_obj_list = self._get_yolo_object_list(json_data, img_path) yolo_obj_list = self._get_yolo_object_list(json_data, img_path)
self._save_yolo_label(json_name, save_yolo_label(json_name,
self._label_dir_path, self._label_dir_path,
target_dir, target_dir,
yolo_obj_list) yolo_obj_list)
def convert_one(self, json_name): def convert_one(self, json_name):
json_path = os.path.join(self._json_dir, json_name) json_path = os.path.join(self._json_dir, json_name)
@ -249,12 +237,12 @@ class Labelme2YOLO(object):
print('Converting %s ...' % json_name) print('Converting %s ...' % json_name)
img_path = self._save_yolo_image(json_data, json_name, img_path = save_yolo_image(json_data, json_name,
self._json_dir, '') self._json_dir, '')
yolo_obj_list = self._get_yolo_object_list(json_data, img_path) yolo_obj_list = self._get_yolo_object_list(json_data, img_path)
self._save_yolo_label(json_name, self._json_dir, save_yolo_label(json_name, self._json_dir,
'', yolo_obj_list) '', yolo_obj_list)
def _get_yolo_object_list(self, json_data, img_path): def _get_yolo_object_list(self, json_data, img_path):
yolo_obj_list = [] yolo_obj_list = []
@ -298,35 +286,14 @@ class Labelme2YOLO(object):
points[::2] = [float(point[0]) / img_w for point in point_list] points[::2] = [float(point[0]) / img_w for point in point_list]
points[1::2] = [float(point[1]) / img_h for point in point_list] points[1::2] = [float(point[1]) / img_h for point in point_list]
if len(points) == 4: if len(points) == 4:
points = extend_point_list(points) if self._output_format == "polygon":
points = extend_point_list(points)
if self._output_format == "bbox":
points = extend_point_list(points, "bbox")
label_id = self._label_id_map[shape['label']] label_id = self._label_id_map[shape['label']]
return label_id, points.tolist() return label_id, points.tolist()
@staticmethod
def _save_yolo_label(self, json_name, label_dir_path, target_dir, yolo_obj_list):
txt_path = os.path.join(label_dir_path,
target_dir,
json_name.replace('.json', '.txt'))
with open(txt_path, 'w+') as f:
for yolo_obj in yolo_obj_list:
label, points = yolo_obj
points = [str(item) for item in points]
yolo_obj_line = f"{label} {' '.join(points)}\n"
f.write(yolo_obj_line)
@staticmethod
def _save_yolo_image(self, json_data, json_name, image_dir_path, target_dir):
img_name = json_name.replace('.json', '.png')
img_path = os.path.join(image_dir_path, target_dir, img_name)
if not os.path.exists(img_path):
img = img_b64_to_arr(json_data['imageData'])
PIL.Image.fromarray(img).save(img_path)
return img_path
def _save_dataset_yaml(self): def _save_dataset_yaml(self):
yaml_path = os.path.join( yaml_path = os.path.join(
self._json_dir, 'YOLODataset/', 'dataset.yaml') self._json_dir, 'YOLODataset/', 'dataset.yaml')