共计 3946 个字符,预计需要花费 10 分钟才能阅读完成。
背景痛点
在目标检测任务中,数据标注是模型训练的基础。然而,不同的标注工具生成的标注格式往往不兼容,这给开发者带来了不小的麻烦。特别是当使用 AnyLabeling 进行标注后,想要将数据用于 YOLO 训练时,格式转换的问题就会凸显出来。

AnyLabeling 生成的标注数据通常是 JSON 格式,而 YOLO 训练需要的是 TXT 格式的标注文件。这两种格式在标注框的表示、类别编码等方面存在显著差异,直接使用会导致模型训练失败或性能下降。因此,掌握如何将 AnyLabeling 标注数据高效转换为 YOLO 格式,是每个计算机视觉开发者都需要掌握的技能。
技术对比
AnyLabeling JSON 格式
AnyLabeling 生成的 JSON 文件通常包含以下关键信息:
- 图像的基本信息(如宽度、高度)
- 标注对象的类别名称
- 标注框的坐标(通常是绝对坐标,即像素值)
- 其他元数据(如标注时间、标注者等)
YOLO TXT 格式
YOLO 需要的 TXT 文件格式则更为简洁:
- 每行代表一个标注对象
- 每行的格式为:
类别 ID 中心点 x 中心点 y 宽度 高度 - 坐标是相对坐标(即相对于图像宽度和高度的比例值,范围在 0 到 1 之间)
主要差异
- 坐标系统:AnyLabeling 使用绝对坐标,YOLO 使用相对坐标。
- 类别表示:AnyLabeling 使用类别名称,YOLO 使用类别 ID。
- 文件结构:AnyLabeling 将所有标注信息保存在一个 JSON 文件中,YOLO 要求每个图像对应一个 TXT 文件。
核心实现
Python 转换脚本
以下是一个完整的 Python 脚本,用于将 AnyLabeling 的 JSON 标注文件转换为 YOLO 格式的 TXT 文件。脚本使用 argparse 处理命令行参数,并包含异常处理和关键步骤的注释。
import json
import os
import argparse
# 解析命令行参数
def parse_args():
parser = argparse.ArgumentParser(description='Convert AnyLabeling JSON to YOLO TXT format')
parser.add_argument('--json_path', type=str, required=True, help='Path to the AnyLabeling JSON file')
parser.add_argument('--output_dir', type=str, required=True, help='Directory to save YOLO TXT files')
parser.add_argument('--class_map', type=str, required=True, help='Path to class mapping file (each line: class_name class_id)')
return parser.parse_args()
# 加载类别映射
def load_class_map(class_map_path):
class_map = {}
with open(class_map_path, 'r') as f:
for line in f:
class_name, class_id = line.strip().split()
class_map[class_name] = int(class_id)
return class_map
# 转换标注格式
def convert_annotation(json_data, class_map):
annotations = {}
for item in json_data:
image_path = item['image_path']
image_width = item['image_width']
image_height = item['image_height']
shapes = item['shapes']
yolo_annotations = []
for shape in shapes:
if shape['shape_type'] != 'rectangle':
continue # 暂时只处理矩形标注
class_name = shape['label']
if class_name not in class_map:
continue # 忽略未映射的类别
class_id = class_map[class_name]
points = shape['points']
x1, y1 = points[0]
x2, y2 = points[1]
# 计算相对坐标
x_center = (x1 + x2) / 2 / image_width
y_center = (y1 + y2) / 2 / image_height
width = abs(x2 - x1) / image_width
height = abs(y2 - y1) / image_height
yolo_annotations.append(f"{class_id} {x_center} {y_center} {width} {height}")
annotations[image_path] = yolo_annotations
return annotations
# 保存 YOLO 格式的 TXT 文件
def save_yolo_txt(output_dir, annotations):
for image_path, yolo_annotations in annotations.items():
base_name = os.path.splitext(os.path.basename(image_path))[0]
txt_path = os.path.join(output_dir, f"{base_name}.txt")
with open(txt_path, 'w') as f:
for annotation in yolo_annotations:
f.write(annotation + '\n')
# 主函数
def main():
args = parse_args()
# 加载类别映射
class_map = load_class_map(args.class_map)
# 加载 JSON 文件
with open(args.json_path, 'r') as f:
json_data = json.load(f)
# 转换标注格式
annotations = convert_annotation(json_data, class_map)
# 保存 YOLO 格式的 TXT 文件
os.makedirs(args.output_dir, exist_ok=True)
save_yolo_txt(args.output_dir, annotations)
print(f"Conversion completed. Saved to {args.output_dir}")
if __name__ == '__main__':
main()
脚本功能说明
- 解析 AnyLabeling 的 JSON 标注文件 :脚本通过
json模块加载 JSON 文件,并提取图像路径、标注框坐标等信息。 - 处理坐标系统转换:将绝对坐标转换为相对坐标,这是 YOLO 格式的关键步骤。
- 处理类别 ID 映射:通过外部文件(
class_map)将类别名称映射为 YOLO 所需的类别 ID。 - 生成 YOLO 格式的 TXT 文件:每个图像生成一个对应的 TXT 文件,保存在指定的输出目录中。
验证方案
可视化检查
转换完成后,建议使用 labelImg 等工具打开图像和对应的 TXT 文件,检查标注框是否正确。具体步骤如下:
- 打开
labelImg,加载图像。 - 选择“Open Dir”打开图像目录。
- 确保标注框的位置和类别与原始标注一致。
数据校验
还可以编写简单的脚本检查转换后的 TXT 文件是否符合 YOLO 格式要求:
- 检查每行的字段数量是否为 5(类别 ID + 4 个坐标值)。
- 检查坐标值是否在 0 到 1 之间。
- 检查类别 ID 是否在有效范围内。
避坑指南
图像尺寸不一致
如果数据集中图像的尺寸不一致,需要在转换时动态获取每张图像的宽度和高度,而不是使用固定值。脚本中已经通过 image_width 和image_height实现了这一点。
类别 ID 从 0 开始
YOLO 的类别 ID 通常从 0 开始,因此在类别映射文件中,确保第一个类别的 ID 为 0。例如:
person 0
dog 1
cat 2
多边形标注的转换
AnyLabeling 支持多边形标注,但 YOLO 的 TXT 格式仅支持矩形标注。如果数据集中包含多边形标注,可以将其转换为最小外接矩形,或者使用其他工具(如labelme2yolo)进行转换。
性能优化
批量处理大量文件
如果数据集中包含大量图像,建议使用多进程或并行处理来加速转换过程。以下是一个简单的多进程实现:
import multiprocessing
def process_image(item, class_map):
# 转换单个图像的标注
pass
def main():
args = parse_args()
class_map = load_class_map(args.class_map)
with open(args.json_path, 'r') as f:
json_data = json.load(f)
# 使用多进程
pool = multiprocessing.Pool(processes=multiprocessing.cpu_count())
results = [pool.apply_async(process_image, (item, class_map)) for item in json_data]
pool.close()
pool.join()
内存优化
对于非常大的 JSON 文件,可以考虑逐行读取和处理,而不是一次性加载整个文件到内存中。
结尾互动
希望这篇指南能帮助你顺利将 AnyLabeling 标注数据转换为 YOLO 格式。在实际操作中,你是否遇到过其他问题?或者有其他优化建议?欢迎在评论区分享你的经验和解决方案!
