4、常见标注格式详解(中):Pascal VOC XML格式、YOLO TXT格式

好,咱们接着聊标注格式。上一节我们把 COCO 的 JSON 格式拆了个七七八八,这一节轮到另外两个“老熟人”——Pascal VOC 和 YOLO。

说实话,这两个格式在工业界和学术界的出场率极高。我最早接触目标检测时,用的就是 VOC 格式。那时候年轻,觉得 XML 好啰嗦,后来才发现,啰嗦有啰嗦的好处。

4.1 Pascal VOC XML 格式:老牌标杆

Pascal VOC 是什么?它最初是一个视觉竞赛(Visual Object Classes),后来它的标注格式成了行业标准。很多开源检测模型,比如 Faster R-CNN、SSD,原生就支持这种格式。

它的核心是 XML 文件。每张图片对应一个同名的 XML 文件。比如 cat.jpg 对应 cat.xml

4.1.1 文件结构长什么样?

我直接给你看一个典型的 VOC XML 文件。你感受一下它的“骨架”:

<annotation>
    <folder>images</folder>
    <filename>cat_001.jpg</filename>
    <size>
        <width>640</width>
        <height>480</height>
        <depth>3</depth>
    </size>
    <object>
        <name>cat</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>
</annotation>

嗯,结构很清晰。根节点是 <annotation>,里面包含图片信息和所有目标。

我个人习惯把 <size><object> 才是真正的标注内容。

4.1.2 核心字段解读

字段 含义 说明
filename 图片文件名 不含路径,只含文件名
size 图片尺寸 width、height、depth(通道数)
object 目标实例 一个图片可以有多个 object
name 类别名称 比如 cat、dog、person
bndbox 边界框 xmin、ymin、xmax、ymax(像素坐标)
truncated 是否被截断 0 表示完整,1 表示被图片边界截断
difficult 是否难识别 1 表示该目标很难辨认,通常训练时忽略

这里有个细节我想提一下。<truncated><difficult> 这两个字段,很多新手会忽略。我在项目中遇到过,有些目标只有半个身子露在画面里,如果不标记 truncated,模型会学到“猫只有半截身子”这种错误特征。你想想看,这多坑。

4.1.3 坐标格式:左上右下

VOC 的坐标是 绝对像素坐标。也就是 xminymin 是框的左上角,xmaxymax 是右下角。

举个例子:

  • 图片宽 640,高 480
  • 框的左上角在 (100, 50)
  • 框的右下角在 (300, 200)

那这个框的宽度就是 300 - 100 = 200,高度是 200 - 50 = 150。

小技巧: 如果你需要把 VOC 格式转成 YOLO 格式,核心就是把这个绝对坐标转成归一化的中心点坐标。后面我们会详细讲。

4.2 YOLO TXT 格式:简洁至上

YOLO 格式,说白了就是“极简主义”。它没有 XML 那么啰嗦,一个 TXT 文件搞定所有标注信息。

我第一次用 YOLO 格式时,心里想的是:“这才对嘛,标注数据就该这么干净。” 但后来发现,简洁的代价是——你必须严格遵守它的目录结构。

4.2.1 文件结构

YOLO 格式的目录通常长这样:

dataset/
├── images/
│   ├── train/
│   │   ├── img_001.jpg
│   │   └── img_002.jpg
│   └── val/
│       └── img_003.jpg
└── labels/
    ├── train/
    │   ├── img_001.txt
    │   └── img_002.txt
    └── val/
        └── img_003.txt

看到了吗?图片和标注文件是分开存放的。图片在 images/ 下,标注在 labels/ 下。而且文件名必须一一对应,只是后缀不同。

注意: 我曾经犯过一个低级错误——把标注文件放错了子目录。训练时模型死活不收敛,查了两天才发现是路径配错了。所以,目录结构一定要严格遵循。

4.2.2 TXT 文件内容

一个 YOLO 标注文件的内容长这样:

0 0.546875 0.260417 0.312500 0.416667
1 0.750000 0.520833 0.250000 0.291667

每一行代表一个目标。每行有 5 个数字,用空格分隔:

  1. 类别索引:从 0 开始。比如 0 代表 cat,1 代表 dog
  2. 中心点 x:归一化后的 x 坐标(值在 0~1 之间)
  3. 中心点 y:归一化后的 y 坐标(值在 0~1 之间)
  4. 宽度 w:归一化后的宽度(值在 0~1 之间)
  5. 高度 h:归一化后的高度(值在 0~1 之间)

说白了,YOLO 不存绝对坐标,它存的是 相对比例。这样做的好处是:不管图片怎么缩放,标注数据都不用改。

4.2.3 坐标转换:从 VOC 到 YOLO

这是面试常考题,也是实际工作中最常用的技能。我直接给你公式:

# 假设图片宽为 W,高为 H
# VOC 坐标:xmin, ymin, xmax, ymax

# 计算中心点
center_x = (xmin + xmax) / 2.0 / W
center_y = (ymin + ymax) / 2.0 / H

# 计算宽高
width = (xmax - xmin) / W
height = (ymax - ymin) / H

# 输出 YOLO 格式
# class_id center_x center_y width height

举个例子:

  • 图片宽 640,高 480
  • VOC 框:xmin=100, ymin=50, xmax=300, ymax=200
  • 计算:center_x = (100+300)/2/640 = 0.3125
  • 计算:center_y = (50+200)/2/480 = 0.2604
  • 计算:width = (300-100)/640 = 0.3125
  • 计算:height = (200-50)/480 = 0.3125
  • 最终结果:0 0.3125 0.2604 0.3125 0.3125
核心要点: 归一化后的值一定在 0~1 之间。如果算出来大于 1,说明你的坐标或者图片尺寸算错了。

4.3 两种格式的对比

我整理了一张对比表,方便你快速决策:

对比维度 Pascal VOC XML YOLO TXT
文件格式 XML(可读性强) TXT(极简)
坐标类型 绝对像素坐标 归一化相对坐标
坐标表示 左上角 + 右下角 中心点 + 宽高
每张图片 一个 XML 文件 一个 TXT 文件
类别信息 类别名称(字符串) 类别索引(整数)
额外信息 支持 truncated、difficult 等 无额外信息
适用场景 学术研究、通用检测 YOLO 系列模型、工业部署

我个人建议:如果你在做学术研究或者需要保留丰富的标注信息(比如遮挡、截断),选 VOC。如果你在落地 YOLO 项目,直接上 TXT 格式,省心省力。

4.4 知识体系结构图

下面这张图,帮你理清这两种格式的核心逻辑:

常见标注格式核心逻辑 Pascal VOC XML 文件:每张图片一个 .xml 坐标:绝对像素 (xmin, ymin, xmax, ymax) 类别:字符串名称 (cat, dog) 特点:信息丰富,可读性强 适用:学术研究、通用检测 转换 归一化 YOLO TXT 文件:每张图片一个 .txt 坐标:归一化 (cx, cy, w, h) 类别:整数索引 (0, 1, 2) 特点:极简,高效,无冗余 适用:YOLO 系列、工业部署 核心:VOC 存绝对坐标,YOLO 存相对比例。转换就是做归一化。

4.5 避坑指南

最后,分享几个我踩过的坑:

  • 类别索引别搞错:YOLO 的类别索引从 0 开始。如果你有 3 个类别,索引是 0、1、2。我曾经把索引写成 1、2、3,结果模型把猫认成了狗。
  • 归一化别除错:计算 YOLO 坐标时,分母是图片的宽和高。别把宽高搞反了。我见过有人用宽去除高度,结果框全变形了。
  • XML 解析注意编码:VOC 的 XML 文件默认是 UTF-8 编码。如果你用 Python 的 xml.etree.ElementTree 解析,记得指定编码,否则中文路径会报错。
  • 空图片的处理:如果一张图片里没有目标,VOC 格式可以没有 <object> 节点。但 YOLO 格式必须有一个空的 TXT 文件(0 字节),不能没有文件。

嗯,这两种格式就先讲到这里。你只要记住:VOC 是“详细派”,YOLO 是“极简派”。实际工作中,两者经常需要互相转换。下一节我们会聊更复杂的格式,比如 JSON 和 COCO 的变体,到时候你就知道这些基础有多重要了。


公众号:蓝海资料掘金营,微信deep3321