源代码说明
包含对应的python代码,测试用到的图像及其标注文件。
https://download.csdn.net/download/u011775793/88631532
如何使用AnyLabeling进行图像标注?
可以参考: [YOLOv8] - 使用AnyLabeling对数据集进行标注(含安装和使用技巧)
什么是YOLO格式数据集?
可以参考:[YOLOv8] - YOLO数据集格式介绍和案例
转换AnyLabeling的标注数据集为YOLO数据集
编程思路
读取AnyLabeling标注目录底下的所有json文件,遍历并逐个解释每个json文件,根据json中提供的数据(比如,被标注图像的相对路径,标注目标所在位置等),动态生成YOLO格式的图像和标注数据,分别保存到images和labels目录,最后把类别文件classes.txt也复制到目标目录。
源代码
import base64
import os
import json
import shutil
from pathlib import Path
from glob import glob
from wepy import GLOBAL_ENCODING, get_logger, init_logger
from wepy.helper import str_helper
def labelme_to_yolo(label_me_json_file, cls2id_dict):
label_me_json = json.load(open(label_me_json_file, mode='r', encoding=GLOBAL_ENCODING))
shapes = label_me_json['shapes']
img_width, img_height = label_me_json['imageWidth'], label_me_json['imageHeight']
img_path = label_me_json['imagePath']
img_data = label_me_json['imageData'] if 'imageData' in label_me_json else ''
labels = []
for s in shapes:
s_type = s['shape_type']
s_type = s_type.lower()
if s_type == 'rectangle':
pts = s['points']
x1, y1 = pts[0] # left corner
x2, y2 = pts[1] # right corner
x = (x1 + x2) / 2 / img_width
y = (y1 + y2) / 2 / img_height
w = abs(x2 - x1) / img_width
h = abs(y2 - y1) / img_height
cid = cls2id_dict[s['label']]
labels.append(f'{cid} {x} {y} {w} {h}')
return labels, img_path, img_data
class LabelMe2YoloConverter:
def __init__(self, labelme_label_dir, labelme_classes_file, yolo_save_dir, clear_yolo_save_dir=False):
self.labelme_label_dir = labelme_label_dir
self.yolo_save_dir = yolo_save_dir
self.labelme_classes_file = labelme_classes_file
self.clear_yolo_save_dir = clear_yolo_save_dir
def get_cls2id_dict(self):
cls2id_dict = {}
with open(self.labelme_classes_file) as f:
for cls_id, cls_name in enumerate(f.readlines()):
cls_name = cls_name.strip()
if cls_name != '':
cls2id_dict[cls_name] = cls_id
return cls2id_dict
def convert(self):
yolo_dir = Path(self.yolo_save_dir)
if self.clear_yolo_save_dir:
shutil.rmtree(yolo_dir)
get_logger().info(f'clear yolo save dir. yolo_dir:{yolo_dir}')
yolo_label_dir = yolo_dir.joinpath('labels')
yolo_image_dir = yolo_dir.joinpath('images')
os.makedirs(yolo_label_dir, exist_ok=True)
os.makedirs(yolo_image_dir, exist_ok=True)
label_dir = Path(self.labelme_label_dir)
if label_dir.exists():
cls2id_dict = self.get_cls2id_dict()
json_files = glob(pathname='*.json', root_dir=self.labelme_label_dir)
total = len(json_files)
for idx, json_file in enumerate(json_files):
try:
json_file = os.path.join(self.labelme_label_dir, json_file)
get_logger().info(f'convert label. total:{total}, idx:{idx + 1}, json_file:{json_file}')
filename = os.path.basename(json_file).rsplit('.', 1)[0]
labels, img_path, img_data = labelme_to_yolo(json_file, cls2id_dict)
img_prefix = str_helper.get_md5(img_path, prefix_len=8)
if len(labels) > 0:
src_img_path = Path(label_dir).joinpath(img_path)
src_img_path = os.path.normpath(src_img_path) # 正规化路径,对路径中的.和..进行转换
src_img_name = os.path.basename(src_img_path)
target_img_path = Path(yolo_image_dir).joinpath(f'{img_prefix}_{src_img_name}')
if os.path.exists(src_img_path):
shutil.copy(src_img_path, target_img_path)
get_logger().info(f'save yolo img by imagePath. yolo_img_path:{target_img_path}')
elif img_data != '':
with open(target_img_path, mode='wb') as f:
f.write(base64.b64decode(img_data))
get_logger().info(f'save yolo img by imageData. yolo_img_path:{target_img_path}')
else:
get_logger().error(
f'save yolo img fail for no imagePath or imageData. json_file:{json_file}')
continue
yolo_label_path = Path(yolo_label_dir).joinpath(f'{img_prefix}_{filename}.txt')
with open(yolo_label_path, mode='w', encoding=GLOBAL_ENCODING) as f:
f.write('\n'.join(labels))
get_logger().info(f'save yolo label. yolo_label_path:{yolo_label_path}')
else:
get_logger().error(f'there is no labels found. json_file:{json_file}')
except Exception as e:
get_logger().exception(f'exception happen when convert. ex:{e}, json_file:{json_file}')
target_classes_file = Path(yolo_dir).joinpath('classes.txt')
shutil.copy(self.labelme_classes_file, target_classes_file)
get_logger().info(f'save yolo label classes. labelme_classes_file:{self.labelme_classes_file},'
f'yolo_classes_file:{target_classes_file}')
else:
get_logger().error(f'The labelme label dir is not found. labelme_label_dir:{self.labelme_label_dir}')
if __name__ == '__main__':
init_logger('./logs/format_convert.log')
g_labelme_classes_file = 'D:/YOLOv8Train/anylabeling_datasets/mktk_datasets/cut_640_labels/classes.txt'
g_labelme_label_dir = 'D:/YOLOv8Train/anylabeling_datasets/mktk_datasets/cut_640_labels/'
g_yolo_save_dir = 'D:/YOLOv8Train/v8_origin_datasets/mktk_dataset/'
labelme_converter = LabelMe2YoloConverter(g_labelme_label_dir, g_labelme_classes_file, g_yolo_save_dir, True)
labelme_converter.convert()
运行结果
AnyLabeling的图像目录:
AnyLabeling的标注目录和类别文件:
生成的YOLO格式数据集: