跳转到主要内容
TjMakeBot 博客tjmakebot.com

多格式标注:YOLO/VOC/COCO格式深度解析

TjMakeBot 团队技术教程11 分钟
技术教程格式详解
多格式标注:YOLO/VOC/COCO格式深度解析

📦 引言:格式的重要性

数据标注格式是 AI 项目的“数据接口协议”。同一套图片与同一组框,如果格式不匹配,常见结果不是“训练效果差一点”,而是直接出现:

  • 训练脚本读不到数据:路径组织、字段名或类别映射不符合框架约定。
  • 坐标含义被误解:(xywh) vs (xyxy)、归一化 vs 像素、左上角 vs 中心点,轻则框偏移,重则全错。
  • 类别 ID 全部错位:例如把 category_id=1 当成第 1 类,但你的训练配置是从 0 开始。
  • 后续难维护:跨团队/跨工具交付时,缺少元数据(类别表、图片尺寸、分割信息)会导致反复返工。

本文以“目标检测(bounding box)”为主线,深入拆解三种主流格式:YOLO、VOC(Pascal VOC)与 COCO。你将学到:

  • 每种格式到底在表达什么(坐标系统、文件组织、元数据)
  • 训练框架最在意的约定(类别映射、切分集合、空标注)
  • 格式转换的关键细节(公式、边界裁剪、映射表)

🎯 YOLO格式

格式特点

YOLO 系列(尤其是 YOLOv5/v8/v9/v10)最常见的“YOLO 标注格式”,本质是:每张图片一个 .txt 文件,每行一个目标框。它追求极简与高吞吐,因此元数据通常放在一个额外的配置文件(如 data.yaml)。

文件结构

dataset/
├── images/
│   ├── image001.jpg
│   └── image002.jpg
└── labels/
    ├── image001.txt
    └── image002.txt

更贴近训练习惯的组织方式通常包含 train/val/test(或 train/valid/test):

dataset/
├── images/
│   ├── train/
│   ├── val/
│   └── test/
├── labels/
│   ├── train/
│   ├── val/
│   └── test/
└── data.yaml

标注文件格式image001.txt):

class_id center_x center_y width height
0 0.5 0.5 0.3 0.4
1 0.2 0.3 0.1 0.2

格式说明

  • class_id:类别 ID(通常从 0 开始,与类别表严格一一对应)
  • center_x, center_y:边界框中心点坐标,相对图片宽高归一化到 ([0,1])
  • width, height:边界框宽高,相对图片宽高归一化到 ([0,1])

坐标系统(最容易踩坑)

YOLO 的 xywh 是“中心点 + 宽高”,且通常是归一化:

  • 从 YOLO(归一化)转像素 (xyxy)

    • (x_{center}=center_x \times W),(y_{center}=center_y \times H)
    • (w=width \times W),(h=height \times H)
    • (x_{min}=x_{center}-\frac{w}{2}),(y_{min}=y_{center}-\frac{h}{2})
    • (x_{max}=x_{center}+\frac{w}{2}),(y_{max}=y_{center}+\frac{h}{2})
  • 从像素 (xyxy) 转 YOLO(归一化)

    • (x_{center}=\frac{x_{min}+x_{max}}{2W}),(y_{center}=\frac{y_{min}+y_{max}}{2H})
    • (width=\frac{x_{max}-x_{min}}{W}),(height=\frac{y_{max}-y_{min}}{H})

建议在转换/导出时做两件事:

  • 裁剪与夹紧(clamp):确保结果落在 ([0,1]) 或 ([0,W/H]) 的合法范围内,避免训练时报错或出现 NaN。
  • 保留足够小数:一般保留 6 位小数即可;过度四舍五入会让小目标“抖动”。

关键特点

  • ✅ 使用归一化坐标(0-1)
  • ✅ 格式简洁,文件小
  • ✅ 适合YOLO系列模型

类别表与 data.yaml

YOLO 训练通常还需要一个数据配置(以 Ultralytics/YOLOv5 生态为例):

# data.yaml
path: /abs/path/to/dataset
train: images/train
val: images/val
test: images/test

names:
  0: car
  1: person

这里的 names 顺序/ID 必须与你的 class_id 完全一致。如果你在不同数据集或不同导出之间改了类别顺序,模型会“学错标签”但不报错,这是最隐蔽也最昂贵的坑之一。

空标注与缺失文件

  • 空标注图片:建议保留对应的空 .txt(文件存在但为空),或按训练框架要求处理;不要“直接缺文件”,否则数据加载逻辑可能把它当成异常。
  • 图片与标签同名image001.jpg 对应 image001.txt。更换扩展名(jpg/png)通常不影响,但文件名(不含扩展名)必须一致

适用场景

推荐使用

  • YOLOv5/v8/v9/v10训练
  • 目标检测项目
  • 需要快速训练

不推荐使用

  • 需要像素级精度的项目
  • 需要详细元数据的项目

补充说明:YOLO 格式并不是“不支持”更复杂任务。以 YOLOv8 为例,分割/关键点等任务会在标签行里追加多边形点/关键点字段。但一旦进入这些扩展格式,不同工具与训练代码的约定差异会显著变大,建议统一使用同一套工具链导出与训练。

📋 VOC格式

格式特点

VOC(Pascal VOC)以 XML 表达一张图像的标注信息,可读性强、字段明确,适合“人肉排查”和传统检测框架(如早期 Faster R-CNN 系工具链)。

文件结构

dataset/
├── images/
│   ├── image001.jpg
│   └── image002.jpg
└── annotations/
    ├── image001.xml
    └── image002.xml

经典 VOC 数据集目录通常更“标准化”:

VOCdevkit/
└── VOC2007/
    ├── JPEGImages/
    ├── Annotations/
    └── ImageSets/
        └── Main/
            ├── train.txt
            ├── val.txt
            └── test.txt

其中 train.txt/val.txt/test.txt 存放的是图片 id(不带扩展名),用于明确划分数据集切分。

标注文件格式image001.xml):

<annotation>
    <filename>image001.jpg</filename>
    <size>
        <width>640</width>
        <height>480</height>
        <depth>3</depth>
    </size>
    <object>
        <name>car</name>
        <bndbox>
            <xmin>100</xmin>
            <ymin>50</ymin>
            <xmax>300</xmax>
            <ymax>200</ymax>
        </bndbox>
    </object>
</annotation>

格式说明

  • 绝对像素坐标:通常以图片左上角为原点 ((0,0)),向右为 x 正方向,向下为 y 正方向。
  • 边界框语义为 (xyxy)xmin,ymin,xmax,ymax(左上角与右下角)。
  • 内含图片尺寸size/width,height,depth 用于校验坐标有效性与可视化。
  • 可扩展元数据:如 pose、truncated、difficult 等字段在许多 VOC 工具链中仍会被读取。

关键字段速查(常用但容易忽略)

一个较完整的 object 往往长这样:

<object>
  <name>car</name>
  <pose>Unspecified</pose>
  <truncated>0</truncated>
  <difficult>0</difficult>
  <bndbox>
    <xmin>100</xmin>
    <ymin>50</ymin>
    <xmax>300</xmax>
    <ymax>200</ymax>
  </bndbox>
</object>
  • truncated:目标是否被截断(例如被画面边缘裁掉)。
  • difficult:难样本标记。某些评估/训练流程会选择忽略 difficult=1 的目标。

VOC 坐标的“闭区间”争议

不同工具对 xmax/ymax 是否“包含像素点”理解不同(历史遗留)。最安全的实践是:

  • 转换时保证 (xmax > xmin)、(ymax > ymin)
  • 避免生成越界坐标(小于 0 或大于宽高)
  • 在可视化抽查中确认边框是否偏移 1 像素(如果偏移,统一在导出端修正)

关键特点

  • ✅ 使用绝对坐标
  • ✅ 包含详细元数据
  • ✅ 适合Faster R-CNN等模型

适用场景

推荐使用

  • Faster R-CNN训练
  • 需要详细元数据的项目
  • 需要可读性好的格式

不推荐使用

  • YOLO训练(需要转换)
  • 需要快速训练的项目

补充说明:如果你的项目需要频繁跨工具协作(标注→质检→训练→回流),VOC 的“人可读 XML”优势非常明显;但当数据量很大时,海量 XML 的读写性能与管理成本会逐渐显现。

🗂️ COCO格式

格式特点

COCO 是“数据工程友好型”的标注格式:用一个(或少量)JSON 文件描述全量图片、类别与标注,天然适合做统计、检索、过滤、合并与版本管理。它不仅支持检测框,还原生支持实例分割(segmentation)、**关键点(keypoints)**等任务。

文件结构

dataset/
├── images/
│   ├── image001.jpg
│   └── image002.jpg
└── annotations/
    └── instances_train.json

标注文件格式instances_train.json):

{
    "images": [
        {
            "id": 1,
            "file_name": "image001.jpg",
            "width": 640,
            "height": 480
        }
    ],
    "annotations": [
        {
            "id": 1,
            "image_id": 1,
            "category_id": 1,
            "bbox": [100, 50, 200, 150],
            "area": 30000,
            "iscrowd": 0
        }
    ],
    "categories": [
        {
            "id": 1,
            "name": "car"
        }
    ]
}

格式说明

  • bbox 语义为 (xywh)bbox=[x, y, w, h],其中 x,y左上角像素坐标,不是中心点。
  • image_id:标注所属图片(关联 images[].id)。
  • category_id:标注所属类别(关联 categories[].id)。注意:COCO 的 category_id 往往不是从 0 开始,也不要求连续
  • area:目标面积,常见为 w*h(检测框)或多边形面积(分割)。
  • iscrowd:是否是“群体/拥挤目标”,与分割的 RLE/多边形表达有关。

segmentation / keypoints(为什么 COCO 更“全能”)

即使你当前只做检测,也建议理解 COCO 的两个强项字段,因为很多公开数据集与训练框架会依赖它们:

  • segmentation:实例分割掩码
    • iscrowd=0 时常用多边形数组:[[x1,y1,x2,y2,...], ...]
    • iscrowd=1 时常用 RLE(Run-Length Encoding)压缩掩码
  • keypoints:关键点任务(如人体姿态),通常是长度为 (3K) 的数组(x,y,v),v 表示可见性

COCO 的“全局一致性”约束(工程上很重要)

COCO JSON 往往需要满足:

  • images[].id 唯一、annotations[].id 唯一
  • annotations[].image_id 必须能在 images 中找到
  • annotations[].category_id 必须能在 categories 中找到

当你做“合并多个数据集”或“增量追加标注”时,ID 冲突是最常见的问题。最佳实践是:在合并时重写(rebase)id,并建立稳定的类别映射表。

关键特点

  • ✅ 使用绝对坐标
  • ✅ 结构化数据
  • ✅ 适合多种模型

适用场景

推荐使用

  • COCO数据集训练
  • 需要结构化数据的项目
  • 需要丰富元数据的项目

不推荐使用

  • YOLO训练(需要转换)
  • 需要快速训练的项目

补充说明:COCO 并不“慢”,慢的是你用一个超大的 JSON 在每个 epoch 全量解析。实际工程通常会做缓存、索引或转成更快的内部格式,但“对外交付/对齐标准”时 COCO 依旧是首选。

🔄 格式对比

特性 YOLO VOC COCO
坐标系统 归一化(0-1) 绝对像素 绝对像素
文件格式 TXT XML JSON
文件大小
可读性
元数据
适用模型 YOLO系列 Faster R-CNN 多种模型
转换难度

补充维度(更贴近真实项目选型):

维度 YOLO VOC COCO
原生支持任务 检测(扩展可做分割/关键点) 检测为主 检测 + 分割 + 关键点
类别体系 依赖外部 names 映射 <name> 直接写类名 category_id 需查表
数据集切分 依赖目录或列表文件 传统用 ImageSets/Main/*.txt 常见为多个 json(train/val)
合并/过滤/统计 需要遍历大量小文件 需要遍历大量 XML 对数据工程最友好
人肉排查 一般 非常方便 需要工具或脚本

💡 格式选择指南

你可以用下面这个“决策思路”快速选型:

  • 你训练的是 YOLO 生态(Ultralytics/YOLOv5 系)且只做检测 → 优先 YOLO
  • 你要做实例分割/关键点,或数据要与主流公开数据集对齐 → 优先 COCO
  • 你更依赖人工可读、需要在 XML 里挂一些业务字段,或使用传统检测工具链 → VOC 依然好用

选择YOLO格式

适合场景

  • 使用YOLO系列模型
  • 需要快速训练
  • 文件大小敏感

优势

  • 格式简洁
  • 文件小
  • 训练快

注意事项

  • 确保 namesclass_id 永远一致(强烈建议纳入版本管理)
  • 做数据增强/裁剪后要同步更新标签(尤其是 mosaic、random crop)

选择VOC格式

适合场景

  • 使用Faster R-CNN
  • 需要详细元数据
  • 需要可读性

优势

  • 可读性好
  • 元数据丰富
  • 兼容性好

注意事项

  • 保持 xmin<xmaxymin<ymax,并确保不越界
  • 跨工具时确认 xmax/ymax 的边界语义,避免 1 像素偏差

选择COCO格式

适合场景

  • 使用COCO数据集
  • 需要结构化数据
  • 需要丰富元数据

优势

  • 结构化数据
  • 元数据丰富
  • 兼容多种模型

注意事项

  • 类别 id 不一定连续,训练时通常需要建立 category_id -> 0..N-1 的映射
  • 合并数据集要处理 images.id/annotations.id 冲突

🔧 格式转换

转换前的“必做三件事”

无论你要在 YOLO/VOC/COCO 之间怎么转,先把这三点定死,后面才能稳定:

  1. 类别映射表
    • VOC 用类名、COCO 用 category_id、YOLO 用 class_id
    • 建议维护一个统一的 class_name -> yolo_id 映射,再派生到 VOC/COCO。
  2. 坐标约定
    • YOLO:中心点归一化 (xywh)
    • VOC:像素 (xyxy)
    • COCO:像素 (xywh)(左上角 + 宽高)
  3. 边界与空标注策略
    • 统一裁剪越界框,过滤面积过小框(例如 (w<1) 或 (h<1))
    • 空标注样本是否保留(建议保留)

YOLO → VOC

转换步骤

  1. 读取YOLO格式文件
  2. 获取图片尺寸
  3. 计算绝对坐标
  4. 生成XML文件

代码示例

def yolo_to_voc(yolo_file, img_width, img_height):
    # 读取YOLO格式
    with open(yolo_file, 'r') as f:
        lines = f.readlines()
    
    # 转换为VOC格式
    annotations = []
    for line in lines:
        class_id, cx, cy, w, h = map(float, line.split())
        xmin = int((cx - w/2) * img_width)
        ymin = int((cy - h/2) * img_height)
        xmax = int((cx + w/2) * img_width)
        ymax = int((cy + h/2) * img_height)
        annotations.append((class_id, xmin, ymin, xmax, ymax))
    
    return annotations

VOC → YOLO

转换步骤

  1. 读取XML文件
  2. 获取图片尺寸
  3. 计算归一化坐标
  4. 生成TXT文件

代码示例(最小可用版,演示核心公式;你需要自行补 class_name -> class_id 映射):

import xml.etree.ElementTree as ET

def voc_to_yolo(xml_file, class_name_to_id):
    tree = ET.parse(xml_file)
    root = tree.getroot()

    size = root.find("size")
    img_w = float(size.find("width").text)
    img_h = float(size.find("height").text)

    yolo_lines = []
    for obj in root.findall("object"):
        name = obj.find("name").text.strip()
        if name not in class_name_to_id:
            continue

        bnd = obj.find("bndbox")
        xmin = float(bnd.find("xmin").text)
        ymin = float(bnd.find("ymin").text)
        xmax = float(bnd.find("xmax").text)
        ymax = float(bnd.find("ymax").text)

        # clamp & sanity
        xmin = max(0.0, min(xmin, img_w))
        xmax = max(0.0, min(xmax, img_w))
        ymin = max(0.0, min(ymin, img_h))
        ymax = max(0.0, min(ymax, img_h))
        if xmax <= xmin or ymax <= ymin:
            continue

        cx = (xmin + xmax) / 2.0 / img_w
        cy = (ymin + ymax) / 2.0 / img_h
        w = (xmax - xmin) / img_w
        h = (ymax - ymin) / img_h

        class_id = class_name_to_id[name]
        yolo_lines.append(f"{class_id} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}")

    return yolo_lines

COCO → YOLO

转换步骤

  1. 读取JSON文件
  2. 获取图片尺寸
  3. 计算归一化坐标
  4. 生成TXT文件

代码示例(演示 COCO bbox (xywh) → YOLO 归一化中心点 (xywh)):

import json
from collections import defaultdict

def coco_to_yolo(coco_json_path, category_id_to_yolo_id):
    data = json.load(open(coco_json_path, "r", encoding="utf-8"))

    images = {img["id"]: img for img in data.get("images", [])}
    ann_by_image = defaultdict(list)
    for ann in data.get("annotations", []):
        ann_by_image[ann["image_id"]].append(ann)

    # 返回:file_name -> yolo_lines
    result = {}
    for image_id, img in images.items():
        W, H = float(img["width"]), float(img["height"])
        file_name = img["file_name"]
        lines = []

        for ann in ann_by_image.get(image_id, []):
            cid = ann["category_id"]
            if cid not in category_id_to_yolo_id:
                continue
            x, y, w, h = map(float, ann["bbox"])  # COCO: top-left xywh
            if w <= 0 or h <= 0:
                continue

            cx = (x + w / 2.0) / W
            cy = (y + h / 2.0) / H
            nw = w / W
            nh = h / H

            # clamp
            cx = max(0.0, min(1.0, cx))
            cy = max(0.0, min(1.0, cy))
            nw = max(0.0, min(1.0, nw))
            nh = max(0.0, min(1.0, nh))
            if nw == 0 or nh == 0:
                continue

            yolo_id = category_id_to_yolo_id[cid]
            lines.append(f"{yolo_id} {cx:.6f} {cy:.6f} {nw:.6f} {nh:.6f}")

        result[file_name] = lines

    return result

建议增加“转换后验收”

格式转换完成后,务必做一个轻量验收流程(能省掉大量训练时间):

  • 随机可视化抽查:至少抽 50 张,看框是否整体偏移、尺寸是否异常。
  • 统计检查:每类目标数、每张图目标数、框面积分布是否与预期一致。
  • 空标注占比:空标注突然大幅上升通常意味着匹配/映射出了问题(如文件名不一致或 ID 断链)。

🎁 使用TjMakeBot进行多格式标注

TjMakeBot的优势

  1. 多格式支持

    • YOLO格式
    • VOC格式
    • COCO格式
    • CSV格式
  2. 格式转换

    • 支持格式间转换
    • 一键导出多种格式
    • 兼容主流训练框架

    你真正需要关注的是:导出时的类别映射与坐标约定是否被“锁死”。一个好的工具应当能:

    • 固化类别表(导出时携带/生成 namescategories 等)
    • 统一坐标约定(清如 YOLO 归一化中心点、COCO 左上角 (xywh))
    • 对越界/异常框做可控处理(裁剪、过滤或报警)
  3. 批量处理

    • 批量导出
    • 批量转换
    • 提高效率
  4. 免费(基础功能免费)

    • 无使用限制
    • 无功能限制
    • 降低使用门槛

立即免费使用TjMakeBot进行多格式标注 →

📚 相关阅读

💬 结语

选择正确的标注格式是AI项目成功的基础。YOLO、VOC、COCO各有特点,根据你的项目需求选择最适合的格式。

记住

  • YOLO格式适合YOLO系列模型
  • VOC格式适合Faster R-CNN
  • COCO格式适合多种模型
  • 格式转换是可行的

额外建议(来自真实项目踩坑总结):

  • 把“类别表”当成代码一样管理:版本化、可追溯、可回滚。
  • 不要只在训练时发现问题:把可视化抽查和统计检查做成导出后的固定步骤。
  • 统一团队坐标约定:在项目 README 或数据规范里写清楚((xywh)/(xyxy)、是否归一化、是否包含边界)。

选择TjMakeBot,支持多格式标注和转换!


法律声明:本文内容仅供参考,不构成任何法律、商业或技术建议。使用任何工具或方法时,请遵守相关法律法规,尊重知识产权,获得必要的授权。本文提及的所有公司名称、产品名称和商标均为其各自所有者的财产。

关于作者:TjMakeBot团队专注于AI数据标注工具开发,致力于支持多种标注格式,满足不同项目需求。

📚 推荐阅读

关键词:YOLO格式、VOC格式、COCO格式、标注格式、格式转换、多格式标注、TjMakeBot