第一章 使用说明
类别自己在代码中改,其他四个参数
--json-folder:json文件夹路径
--txt-folder:转换成功后txt的存放路径
--images-dir:图片文件夹路径
--save-dir:转换完成分割后所有文件的路径
终端命令行:python split_conversion.py --json-folder "" --txt-folder "" --images-dir "" --save-dir ""
""处是四个路径
第二章 导包
import json
import os
from tqdm import tqdm
import shutil
import random
import argparse
第三章 转换格式函数
def labelme_json_to_yolo(txt_save_path, json_path, class_map):
"""
将LabelMe格式JSON转换为YOLO TXT标注文件
:param txt_save_path: TXT保存路径
:param json_path: LabelMe JSON文件路径
:param class_map: 类别名映射字典(如{"person": 0})
"""
with open(json_path, 'r', encoding='utf-8') as f:
data = json.load(f)
img_height = data["imageHeight"]
img_width = data["imageWidth"]
img_name = os.path.basename(data["imagePath"]) # 提取图片文件名
txt_name = os.path.splitext(img_name)[0] + ".txt"
txt_path = os.path.join(txt_save_path, txt_name)
lines = []
for shape in data["shapes"]:
label = shape["label"]
if label not in class_map:
continue # 跳过未定义类别
cls_id = class_map[label]
# 解析多边形/矩形标注为边界框(xmin, ymin, xmax, ymax)
points = shape["points"]
x_coords = [p[0] for p in points]
y_coords = [p[1] for p in points]
xmin = min(x_coords)
ymin = min(y_coords)
xmax = max(x_coords)
ymax = max(y_coords)
# 计算YOLO格式坐标(归一化中心坐标+宽高)
x_center = (xmin + xmax) / (2 * img_width)
y_center = (ymin + ymax) / (2 * img_height)
w = (xmax - xmin) / img_width
h = (ymax - ymin) / img_height
# 过滤无效坐标(避免越界)
if 0 <= x_center <= 1 and 0 <= y_center <= 1 and w > 0 and h > 0:
lines.append(f"{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}")
# 保存TXT文件
with open(txt_path, 'w') as f:
f.write('\n'.join(lines))
第四章 划分函数
def batch_convert_labelme_to_yolo(json_folder, txt_folder, class_map):
"""
批量转换LabelMe格式JSON文件夹到YOLO TXT
:param json_folder: JSON文件夹路径
:param txt_folder: TXT保存路径
:param class_map: 类别名映射字典(如{"person": 0})
"""
os.makedirs(txt_folder, exist_ok=True)
json_files = [f for f in os.listdir(json_folder) if f.lower().endswith('.json')]
for json_file in tqdm(json_files, desc="转换中"):
json_path = os.path.join(json_folder, json_file)
labelme_json_to_yolo(txt_folder, json_path, class_map)
print(f"批量转换完成!共处理{len(json_files)}个JSON文件,保存到:{txt_folder}")
第五章 确认文件夹是否存在
def mkdir(path):
if not os.path.exists(path):
os.makedirs(path)
第六章主函数
def main(image_dir, txt_dir, save_dir):
# 创建文件夹
mkdir(save_dir)
images_dir = os.path.join(save_dir, 'images')
labels_dir = os.path.join(save_dir, 'labels')
img_train_path = os.path.join(images_dir, 'train')
img_test_path = os.path.join(images_dir, 'test')
img_val_path = os.path.join(images_dir, 'val')
label_train_path = os.path.join(labels_dir, 'train')
label_test_path = os.path.join(labels_dir, 'test')
label_val_path = os.path.join(labels_dir, 'val')
mkdir(images_dir)
mkdir(labels_dir)
mkdir(img_train_path)
mkdir(img_test_path)
mkdir(img_val_path)
mkdir(label_train_path)
mkdir(label_test_path)
mkdir(label_val_path)
# 数据集划分比例,训练集80%,验证集10%,测试集10%,按需修改
train_percent = 0.8
val_percent = 0.1
test_percent = 0.1
total_txt = os.listdir(txt_dir)
num_txt = len(total_txt)
list_all_txt = range(num_txt) # 范围 range(0, num)
num_train = int(num_txt * train_percent)
num_val = int(num_txt * val_percent)
num_test = num_txt - num_train - num_val
train = random.sample(list_all_txt, num_train)
# 在全部数据集中取出train
val_test = [i for i in list_all_txt if not i in train]
# 再从val_test取出num_val个元素,val_test剩下的元素就是test
val = random.sample(val_test, num_val)
print("训练集数目:{}, 验证集数目:{}, 测试集数目:{}".format(len(train), len(val), len(val_test) - len(val)))
for i in list_all_txt:
name = total_txt[i][:-4]
srcImage = os.path.join(image_dir, name + '.jpg')
srcLabel = os.path.join(txt_dir, name + '.txt')
if i in train:
dst_train_Image = os.path.join(img_train_path, name + '.jpg')
dst_train_Label = os.path.join(label_train_path, name + '.txt')
shutil.copyfile(srcImage, dst_train_Image)
shutil.copyfile(srcLabel, dst_train_Label)
elif i in val:
dst_val_Image = os.path.join(img_val_path, name + '.jpg')
dst_val_Label = os.path.join(label_val_path, name + '.txt')
shutil.copyfile(srcImage, dst_val_Image)
shutil.copyfile(srcLabel, dst_val_Label)
else:
dst_test_Image = os.path.join(img_test_path, name + '.jpg')
dst_test_Label = os.path.join(label_test_path, name + '.txt')
shutil.copyfile(srcImage, dst_test_Image)
shutil.copyfile(srcLabel, dst_test_Label)
第七章 主函数调用
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Convert LabelMe JSON to YOLO TXT and split datasets')
parser.add_argument('--json-folder', type=str, default=r'',
help='LabelMe JSON folder path')
parser.add_argument('--txt-folder', type=str, default=r'',
help='YOLO TXT save path')
parser.add_argument('--class-map', default={"自己的类别": 0}, type=dict,
help='Class name mapping dictionary (e.g. {"person": 0})')
parser.add_argument('--images-dir', type=str, default=r'', help='images path dir')
parser.add_argument('--save-dir', default=r'', type=str, help='save dir')
args = parser.parse_args()
json_folder = args.json_folder
txt_folder = args.txt_folder
class_map = args.class_map
image_dir = args.images_dir
save_dir = args.save_dir
# 转换LabelMe JSON到YOLO TXT
batch_convert_labelme_to_yolo(json_folder, txt_folder, class_map)
# 划分数据集
main(image_dir, txt_folder, save_dir)
全部代码如下:
import json
import os
from tqdm import tqdm # 可选进度条库
import shutil
import random
import argparse
def labelme_json_to_yolo(txt_save_path, json_path, class_map):
"""
将LabelMe格式JSON转换为YOLO TXT标注文件
:param txt_save_path: TXT保存路径
:param json_path: LabelMe JSON文件路径
:param class_map: 类别名映射字典(如{"person": 0})
"""
with open(json_path, 'r', encoding='utf-8') as f:
data = json.load(f)
img_height = data["imageHeight"]
img_width = data["imageWidth"]
img_name = os.path.basename(data["imagePath"]) # 提取图片文件名
txt_name = os.path.splitext(img_name)[0] + ".txt"
txt_path = os.path.join(txt_save_path, txt_name)
lines = []
for shape in data["shapes"]:
label = shape["label"]
if label not in class_map:
continue # 跳过未定义类别
cls_id = class_map[label]
# 解析多边形/矩形标注为边界框(xmin, ymin, xmax, ymax)
points = shape["points"]
x_coords = [p[0] for p in points]
y_coords = [p[1] for p in points]
xmin = min(x_coords)
ymin = min(y_coords)
xmax = max(x_coords)
ymax = max(y_coords)
# 计算YOLO格式坐标(归一化中心坐标+宽高)
x_center = (xmin + xmax) / (2 * img_width)
y_center = (ymin + ymax) / (2 * img_height)
w = (xmax - xmin) / img_width
h = (ymax - ymin) / img_height
# 过滤无效坐标(避免越界)
if 0 <= x_center <= 1 and 0 <= y_center <= 1 and w > 0 and h > 0:
lines.append(f"{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}")
# 保存TXT文件
with open(txt_path, 'w') as f:
f.write('\n'.join(lines))
def batch_convert_labelme_to_yolo(json_folder, txt_folder, class_map):
"""
批量转换LabelMe格式JSON文件夹到YOLO TXT
:param json_folder: JSON文件夹路径
:param txt_folder: TXT保存路径
:param class_map: 类别名映射字典(如{"person": 0})
"""
os.makedirs(txt_folder, exist_ok=True)
json_files = [f for f in os.listdir(json_folder) if f.lower().endswith('.json')]
for json_file in tqdm(json_files, desc="转换中"):
json_path = os.path.join(json_folder, json_file)
labelme_json_to_yolo(txt_folder, json_path, class_map)
print(f"批量转换完成!共处理{len(json_files)}个JSON文件,保存到:{txt_folder}")
# 检查文件夹是否存在
def mkdir(path):
if not os.path.exists(path):
os.makedirs(path)
def main(image_dir, txt_dir, save_dir):
# 创建文件夹
mkdir(save_dir)
images_dir = os.path.join(save_dir, 'images')
labels_dir = os.path.join(save_dir, 'labels')
img_train_path = os.path.join(images_dir, 'train')
img_test_path = os.path.join(images_dir, 'test')
img_val_path = os.path.join(images_dir, 'val')
label_train_path = os.path.join(labels_dir, 'train')
label_test_path = os.path.join(labels_dir, 'test')
label_val_path = os.path.join(labels_dir, 'val')
mkdir(images_dir)
mkdir(labels_dir)
mkdir(img_train_path)
mkdir(img_test_path)
mkdir(img_val_path)
mkdir(label_train_path)
mkdir(label_test_path)
mkdir(label_val_path)
# 数据集划分比例,训练集80%,验证集10%,测试集10%,按需修改
train_percent = 0.8
val_percent = 0.1
test_percent = 0.1
total_txt = os.listdir(txt_dir)
num_txt = len(total_txt)
list_all_txt = range(num_txt) # 范围 range(0, num)
num_train = int(num_txt * train_percent)
num_val = int(num_txt * val_percent)
num_test = num_txt - num_train - num_val
train = random.sample(list_all_txt, num_train)
# 在全部数据集中取出train
val_test = [i for i in list_all_txt if not i in train]
# 再从val_test取出num_val个元素,val_test剩下的元素就是test
val = random.sample(val_test, num_val)
print("训练集数目:{}, 验证集数目:{}, 测试集数目:{}".format(len(train), len(val), len(val_test) - len(val)))
for i in list_all_txt:
name = total_txt[i][:-4]
srcImage = os.path.join(image_dir, name + '.jpg')
srcLabel = os.path.join(txt_dir, name + '.txt')
if i in train:
dst_train_Image = os.path.join(img_train_path, name + '.jpg')
dst_train_Label = os.path.join(label_train_path, name + '.txt')
shutil.copyfile(srcImage, dst_train_Image)
shutil.copyfile(srcLabel, dst_train_Label)
elif i in val:
dst_val_Image = os.path.join(img_val_path, name + '.jpg')
dst_val_Label = os.path.join(label_val_path, name + '.txt')
shutil.copyfile(srcImage, dst_val_Image)
shutil.copyfile(srcLabel, dst_val_Label)
else:
dst_test_Image = os.path.join(img_test_path, name + '.jpg')
dst_test_Label = os.path.join(label_test_path, name + '.txt')
shutil.copyfile(srcImage, dst_test_Image)
shutil.copyfile(srcLabel, dst_test_Label)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Convert LabelMe JSON to YOLO TXT and split datasets')
parser.add_argument('--json-folder', type=str, default=r'',
help='LabelMe JSON folder path')
parser.add_argument('--txt-folder', type=str, default=r'',
help='YOLO TXT save path')
parser.add_argument('--class-map', default={"自己的类别": 0}, type=dict,
help='Class name mapping dictionary (e.g. {"person": 0})')
parser.add_argument('--images-dir', type=str, default=r'', help='images path dir')
parser.add_argument('--save-dir', default=r'', type=str, help='save dir')
args = parser.parse_args()
json_folder = args.json_folder
txt_folder = args.txt_folder
class_map = args.class_map
image_dir = args.images_dir
save_dir = args.save_dir
# 转换LabelMe JSON到YOLO TXT
batch_convert_labelme_to_yolo(json_folder, txt_folder, class_map)
# 划分数据集
main(image_dir, txt_folder, save_dir)