Merge branch 'main' into package
This commit is contained in:
commit
051c019e3f
|
@ -0,0 +1,11 @@
|
|||
# To get started with Dependabot version updates, you'll need to specify which
|
||||
# package ecosystems to update and where the package manifests are located.
|
||||
# Please see the documentation for all configuration options:
|
||||
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "pip" # See documentation for possible values
|
||||
directory: "/" # Location of package manifests
|
||||
schedule:
|
||||
interval: "weekly"
|
|
@ -157,4 +157,4 @@ cython_debug/
|
|||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
.idea/
|
||||
|
|
53
README.md
53
README.md
|
@ -3,16 +3,25 @@
|
|||
# Labelme2YOLO
|
||||
|
||||
[](https://pypi.org/project/labelme2yolo)
|
||||

|
||||
[](https://pypi.org/project/labelme2yolo)
|
||||
[](https://www.codacy.com/gh/GreatV/labelme2yolo/dashboard?utm_source=github.com&utm_medium=referral&utm_content=GreatV/labelme2yolo&utm_campaign=Badge_Grade)
|
||||
|
||||
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.
|
||||
|
||||
---------
|
||||
|
||||
## New
|
||||
|
||||
- export data as yolo polygon annotation (for YOLOv5 v7.0 segmentation)
|
||||
|
||||
## Installation
|
||||
|
||||
```console
|
||||
pip install labelme2yolo
|
||||
```
|
||||
|
||||
## Parameters Explain
|
||||
**--json_dir** LabelMe JSON files folder path.
|
||||
|
||||
|
@ -27,57 +36,51 @@ If you've already marked your segmentation dataset by LabelMe, it's easy to use
|
|||
### 1. Convert JSON files, split training, validation and test dataset by --val_size and --test_size
|
||||
Put all LabelMe JSON files under **labelme_json_dir**, and run this python command.
|
||||
```bash
|
||||
python labelme2yolo.py --json_dir /home/username/labelme_json_dir/ --val_size 0.15 --test_size 0.15
|
||||
labelme2yolo --json_dir /path/to/labelme_json_dir/ --val_size 0.15 --test_size 0.15
|
||||
```
|
||||
Script would generate YOLO format dataset labels and images under different folders, for example,
|
||||
```bash
|
||||
/home/username/labelme_json_dir/YOLODataset/labels/train/
|
||||
/home/username/labelme_json_dir/YOLODataset/labels/test/
|
||||
/home/username/labelme_json_dir/YOLODataset/labels/val/
|
||||
/home/username/labelme_json_dir/YOLODataset/images/train/
|
||||
/home/username/labelme_json_dir/YOLODataset/images/test/
|
||||
/home/username/labelme_json_dir/YOLODataset/images/val/
|
||||
/path/to/labelme_json_dir/YOLODataset/labels/train/
|
||||
/path/to/labelme_json_dir/YOLODataset/labels/test/
|
||||
/path/to/labelme_json_dir/YOLODataset/labels/val/
|
||||
/path/to/labelme_json_dir/YOLODataset/images/train/
|
||||
/path/to/labelme_json_dir/YOLODataset/images/test/
|
||||
/path/to/labelme_json_dir/YOLODataset/images/val/
|
||||
|
||||
/home/username/labelme_json_dir/YOLODataset/dataset.yaml
|
||||
/path/to/labelme_json_dir/YOLODataset/dataset.yaml
|
||||
```
|
||||
|
||||
### 2. Convert JSON files, split training and validation dataset by folder
|
||||
If you already split train dataset and validation dataset for LabelMe by yourself, please put these folder under labelme_json_dir, for example,
|
||||
```bash
|
||||
/home/username/labelme_json_dir/train/
|
||||
/home/username/labelme_json_dir/val/
|
||||
/path/to/labelme_json_dir/train/
|
||||
/path/to/labelme_json_dir/val/
|
||||
```
|
||||
Put all LabelMe JSON files under **labelme_json_dir**.
|
||||
Script would read train and validation dataset by folder.
|
||||
Run this python command.
|
||||
```bash
|
||||
python labelme2yolo.py --json_dir /home/username/labelme_json_dir/
|
||||
labelme2yolo --json_dir /path/to/labelme_json_dir/
|
||||
```
|
||||
Script would generate YOLO format dataset labels and images under different folders, for example,
|
||||
```bash
|
||||
/home/username/labelme_json_dir/YOLODataset/labels/train/
|
||||
/home/username/labelme_json_dir/YOLODataset/labels/val/
|
||||
/home/username/labelme_json_dir/YOLODataset/images/train/
|
||||
/home/username/labelme_json_dir/YOLODataset/images/val/
|
||||
/path/to/labelme_json_dir/YOLODataset/labels/train/
|
||||
/path/to/labelme_json_dir/YOLODataset/labels/val/
|
||||
/path/to/labelme_json_dir/YOLODataset/images/train/
|
||||
/path/to/labelme_json_dir/YOLODataset/images/val/
|
||||
|
||||
/home/username/labelme_json_dir/YOLODataset/dataset.yaml
|
||||
/path/to/labelme_json_dir/YOLODataset/dataset.yaml
|
||||
```
|
||||
|
||||
### 3. Convert single JSON file
|
||||
Put LabelMe JSON file under **labelme_json_dir**. , and run this python command.
|
||||
```bash
|
||||
python labelme2yolo.py --json_dir /home/username/labelme_json_dir/ --json_name 2.json
|
||||
labelme2yolo --json_dir /path/to/labelme_json_dir/ --json_name 2.json
|
||||
```
|
||||
Script would generate YOLO format text label and image under **labelme_json_dir**, for example,
|
||||
```bash
|
||||
/home/username/labelme_json_dir/2.text
|
||||
/home/username/labelme_json_dir/2.png
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
```console
|
||||
pip install labelme2yolo
|
||||
/path/to/labelme_json_dir/2.text
|
||||
/path/to/labelme_json_dir/2.png
|
||||
```
|
||||
|
||||
## License
|
||||
|
|
|
@ -24,15 +24,16 @@ classifiers = [
|
|||
]
|
||||
dependencies = [
|
||||
"opencv-python>=4.1.2",
|
||||
"Pillow",
|
||||
"scikit-learn"
|
||||
"Pillow>=9.2,<9.4",
|
||||
"scikit-learn~=1.1.1",
|
||||
"numpy~=1.23.1"
|
||||
]
|
||||
dynamic = ["version"]
|
||||
|
||||
[project.urls]
|
||||
Documentation = "https://github.com/unknown/labelme2yolo#readme"
|
||||
Issues = "https://github.com/unknown/labelme2yolo/issues"
|
||||
Source = "https://github.com/unknown/labelme2yolo"
|
||||
Documentation = "https://github.com/greatv/labelme2yolo#readme"
|
||||
Issues = "https://github.com/greatv/labelme2yolo/issues"
|
||||
Source = "https://github.com/greatv/labelme2yolo"
|
||||
|
||||
[tool.hatch.version]
|
||||
path = "src/labelme2yolo/__about__.py"
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
opencv-python>=4.1.2
|
||||
opencv-python
|
||||
Pillow
|
||||
scikit-learn
|
||||
numpy
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# SPDX-FileCopyrightText: 2022-present Wang Xin <xinwang614@gmail.com>
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
__version__ = '0.0.5'
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# SPDX-License-Identifier: MIT
|
||||
import sys
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
from .cli import run
|
||||
|
||||
sys.exit(run())
|
|
@ -2,26 +2,41 @@
|
|||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
import argparse
|
||||
import sys
|
||||
# from labelme2yolo.__about__ import version
|
||||
|
||||
from labelme2yolo.l2y import Labelme2YOLO
|
||||
|
||||
|
||||
def run():
|
||||
parser = argparse.ArgumentParser("labelme2yolo")
|
||||
parser.add_argument('--json_dir',type=str,
|
||||
help='Please input the path of the labelme json files.')
|
||||
parser.add_argument('--val_size',type=float, nargs='?', default=None,
|
||||
help='Please input the validation dataset size, for example 0.1 ')
|
||||
parser.add_argument('--test_size',type=float, nargs='?', default=0.0,
|
||||
help='Please input the validation dataset size, for example 0.1 ')
|
||||
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.')
|
||||
parser.add_argument(
|
||||
"--json_dir", type=str, help="Please input the path of the labelme json files."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--val_size",
|
||||
type=float,
|
||||
nargs="?",
|
||||
default=None,
|
||||
help="Please input the validation dataset size, for example 0.1 ",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--test_size",
|
||||
type=float,
|
||||
nargs="?",
|
||||
default=None,
|
||||
help="Please input the validation dataset size, for example 0.1 ",
|
||||
)
|
||||
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()
|
||||
|
||||
if not args.json_dir:
|
||||
parser.print_help(sys.stderr)
|
||||
sys.exit(1)
|
||||
parser.print_help()
|
||||
return 0
|
||||
|
||||
convertor = Labelme2YOLO(args.json_dir)
|
||||
|
||||
|
@ -29,3 +44,5 @@ def run():
|
|||
convertor.convert(val_size=args.val_size, test_size=args.test_size)
|
||||
else:
|
||||
convertor.convert_one(args.json_name)
|
||||
|
||||
return 0
|
||||
|
|
|
@ -1,26 +1,28 @@
|
|||
'''
|
||||
"""
|
||||
Created on Aug 18, 2021
|
||||
|
||||
@author: xiaosonh
|
||||
@author: GreatV(Wang Xin)
|
||||
'''
|
||||
import os
|
||||
import sys
|
||||
import argparse
|
||||
import shutil
|
||||
import math
|
||||
"""
|
||||
import base64
|
||||
import io
|
||||
import json
|
||||
import math
|
||||
import os
|
||||
import shutil
|
||||
from collections import OrderedDict
|
||||
from multiprocessing import Pool
|
||||
import json
|
||||
|
||||
import cv2
|
||||
from sklearn.model_selection import train_test_split
|
||||
import numpy as np
|
||||
import PIL.ExifTags
|
||||
import PIL.Image
|
||||
import PIL.ImageOps
|
||||
from sklearn.model_selection import train_test_split
|
||||
|
||||
|
||||
# number of LabelMe2YOLO multiprocessing threads
|
||||
NUM_THREADS = max(1, os.cpu_count() - 1)
|
||||
|
||||
|
||||
# copy form https://github.com/wkentaro/labelme/blob/main/labelme/utils/image.py
|
||||
|
@ -68,60 +70,54 @@ def img_arr_to_b64(img_arr):
|
|||
|
||||
# copy form https://github.com/wkentaro/labelme/blob/main/labelme/utils/image.py
|
||||
def img_data_to_png_data(img_data):
|
||||
with io.BytesIO() as f:
|
||||
f.write(img_data)
|
||||
img = PIL.Image.open(f)
|
||||
with io.BytesIO() as f_out:
|
||||
f_out.write(img_data)
|
||||
img = PIL.Image.open(f_out)
|
||||
|
||||
with io.BytesIO() as f:
|
||||
img.save(f, "PNG")
|
||||
f.seek(0)
|
||||
return f.read()
|
||||
with io.BytesIO() as f_in:
|
||||
img.save(f_in, "PNG")
|
||||
f_in.seek(0)
|
||||
return f_in.read()
|
||||
|
||||
|
||||
# copy form https://github.com/wkentaro/labelme/blob/main/labelme/utils/image.py
|
||||
def apply_exif_orientation(image):
|
||||
try:
|
||||
exif = image._getexif()
|
||||
except AttributeError:
|
||||
exif = None
|
||||
def get_label_id_map(json_dir):
|
||||
label_set = set()
|
||||
|
||||
if exif is None:
|
||||
return image
|
||||
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"])
|
||||
|
||||
exif = {
|
||||
PIL.ExifTags.TAGS[k]: v
|
||||
for k, v in exif.items()
|
||||
if k in PIL.ExifTags.TAGS
|
||||
}
|
||||
return OrderedDict([(label, label_id) for label_id, label in enumerate(label_set)])
|
||||
|
||||
orientation = exif.get("Orientation", None)
|
||||
|
||||
if orientation == 1:
|
||||
# do nothing
|
||||
return image
|
||||
elif orientation == 2:
|
||||
# left-to-right mirror
|
||||
return PIL.ImageOps.mirror(image)
|
||||
elif orientation == 3:
|
||||
# rotate 180
|
||||
return image.transpose(PIL.Image.ROTATE_180)
|
||||
elif orientation == 4:
|
||||
# top-to-bottom mirror
|
||||
return PIL.ImageOps.flip(image)
|
||||
elif orientation == 5:
|
||||
# top-to-left mirror
|
||||
return PIL.ImageOps.mirror(image.transpose(PIL.Image.ROTATE_270))
|
||||
elif orientation == 6:
|
||||
# rotate 270
|
||||
return image.transpose(PIL.Image.ROTATE_270)
|
||||
elif orientation == 7:
|
||||
# top-to-right mirror
|
||||
return PIL.ImageOps.mirror(image.transpose(PIL.Image.ROTATE_90))
|
||||
elif orientation == 8:
|
||||
# rotate 90
|
||||
return image.transpose(PIL.Image.ROTATE_90)
|
||||
else:
|
||||
return image
|
||||
def save_yolo_label(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_idx, yolo_obj in enumerate(yolo_obj_list):
|
||||
yolo_obj_line = (
|
||||
"%s %s %s %s %s\n" % yolo_obj
|
||||
if yolo_obj_idx + 1 != len(yolo_obj_list)
|
||||
else "%s %s %s %s %s" % yolo_obj
|
||||
)
|
||||
f.write(yolo_obj_line)
|
||||
|
||||
|
||||
def save_yolo_image(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
|
||||
|
||||
|
||||
|
||||
class Labelme2YOLO(object):
|
||||
|
@ -209,6 +205,7 @@ class Labelme2YOLO(object):
|
|||
for target_dir, json_names in zip(('train/', 'val/', 'test/'),
|
||||
(train_json_names, val_json_names, test_json_names)):
|
||||
pool = Pool(os.cpu_count() - 1)
|
||||
|
||||
for json_name in json_names:
|
||||
pool.apply_async(self.covert_json_to_text,
|
||||
args=(target_dir, json_name))
|
||||
|
@ -252,7 +249,7 @@ class Labelme2YOLO(object):
|
|||
yolo_obj_list = []
|
||||
|
||||
img_h, img_w, _ = cv2.imread(img_path).shape
|
||||
for shape in json_data['shapes']:
|
||||
for shape in json_data["shapes"]:
|
||||
# labelme circle shape is different from others
|
||||
# it only has 2 points, 1st is circle center, 2nd is drag end point
|
||||
if shape['shape_type'] == 'circle':
|
||||
|
@ -329,7 +326,8 @@ class Labelme2YOLO(object):
|
|||
yaml_file.write('nc: %i\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)
|
||||
names_str = names_str.rstrip(", ")
|
||||
yaml_file.write("names: [%s]" % names_str)
|
||||
|
|
Loading…
Reference in New Issue