🧠 第七章 数据标注
📄 一句话概括

3 个标注框、3 个类别,生成 COCO 风格的 JSON,共 869 个字符。原始文件校验 0 个问题; 故意改坏三处(框越界、类别 id 拼错、area 对不上)之后,校验器抓出 4 条问题。

📝 本节和前面几节的关系

前面四个实例都在「取信息」,这一节收口:把标好的东西存成下游能直接读的格式,并且能验出错误。 这是标注流程的最后一公里。

一、标注文件不是随便存存

标完的点、框、多边形,得存成一个大家都能读的格式,否则训练脚本还得为每个标注员写一个解析器。 目标检测里最通用的是 COCO 格式:一个 JSON,三个顶层键——images(图有哪些、多宽多高)、 categories(有哪些类别)、annotations(每个框的位置、类别、面积)。 这套格式看着啰嗦,但每一条都有用:images 让训练脚本知道要不要缩放坐标, categories 保证类别 id 连续,annotations 里的 area 用来分大小目标。 自己定一套简单的格式也行,但一旦要和开源工具对接,就会痛苦。用通用的,省事。

二、三个必须校验的东西

  1. 框在图内。x 加 width 不能超过图宽。越界的框在训练时会被截断或者直接崩,两种都不好。
  2. 类别 id 合法。category_id 必须在 categories 里存在。 拼错一个数字,这条标注就永远学不到,而且不报错。
  3. area 和 bbox 一致。area 必须等于 width 乘 height。 这条最隐蔽——训练不报错,评测算指标时才出问题。 第三条为什么重要?因为目标检测的评测要按目标大小分组算分数(小目标、中目标、大目标)。 分组靠的就是 area。area 错了,分组就错,指标全偏。 所以提交前一定要跑一遍结构校验。这个脚本二十行就能写完,但能省掉几天的排查。

三、校验器抓到了什么

原始文件 0 个问题。改坏三处之后抓出 4 条。 多出来的一条,是因为改坏第一个框那一处同时触发了「越界」和「area 不符」两条规则。 一个问题被两条规则命中,是正常现象,不是重复报错。 改坏的另外两处各触发一条:类别 id 改成 9(不存在),area 从 5400 改成 9999(和 90 乘 70 对不上)。 这说明校验器的规则是独立的、可叠加的。 写校验器时就该这么设计:每条规则只管一件事,别写成一个大 if。

四、界面上的清单(我没有跑)

书里的最后一步是在 VGG 里把标注导出成 JSON。沙箱没有浏览器,没跑。 1. 在 VIA 里把所有图标的框标完。 2. 检查类别名有没有拼错、有没有多余空格——这是最常见的脏数据来源。 3. 用导出功能选 JSON 格式,勾上「包含图片名」。 4. 导出的文件直接用文本编辑器看一眼,确认顶层结构和类别表对得上。 5. 跑结构校验脚本,把问题清零再交给训练。 第 2 步值得强调:路灯 和 路灯 (带尾空格)在两份文件里是不同的类别, 模型会把它们学成两个东西。这种错肉眼几乎看不出来。

五、动手 Demo:标注文件:生成 COCO 风格 JSON 并做一致性校验

造 3 个框和 3 个类别(路灯、配电箱、监控杆),拼成 COCO 风格的三段结构, 序列化成 JSON 并打出前几行;写一个校验器查四件事——id 重复、类别不存在、框越界、area 与 bbox 不符; 然后故意改坏三处,再验一次。

anns.append({'id': i, 'image_id': iid, 'category_id': cid,
             'bbox': [x, y, w, h], 'area': w * h, 'iscrowd': 0})

if x < 0 or y < 0 or x + w > W or y + h > H:
    errs.append(u'标注 %d 的框超出图像边界' % a['id'])
if abs(a['area'] - w * h) > 1e-6:
    errs.append(u'标注 %d 的 area 与 bbox 不符' % a['id'])

实跑输出:

--------------------------------------------------------------------
标注文件:生成 COCO 风格的 JSON 并做一致性校验
--------------------------------------------------------------------
  图像                     640 × 480
  类别数                   3
  标注框                   3 个
  JSON 字符数              869
  顶层键                   images、categories、annotations

  前几行长这样:
  {
    "images": [
      {
        "id": 1,
        "file_name": "street_01.jpg",
        "width": 640,
        "height": 480

  原始文件的校验结果:
  问题数                   0

  故意改坏三处之后再校验:
  问题数                   4
    标注 1 的框超出图像边界
    标注 1 的 area 与 bbox 不符
    标注 2 的类别 9 不存在
    标注 3 的 area 与 bbox 不符

  三处改动被校验器抓出 4 条问题——改坏第一个框那一处同时触发了「越界」和「area 不符」,一个问题会被两条规则同时命中,这是正常的。
  这三类错都是标注文件里最常见的:框越界、类别 id 拼错、area 和 bbox 对不上。
  第三条尤其隐蔽——训练时不报错,评测时算 mAP 要靠 area 分大小目标,area 一错,指标直接偏。所以提交前一定要跑一遍结构校验。

JSON 一共 869 个字符,三个顶层键都在。 这个体积说明 COCO 格式的开销主要不在数据,在结构——三条标注就要这么多字。 原始文件 0 条问题,说明生成逻辑本身是对的,框都在界内、area 都是现算的。 改坏之后 4 条问题。想一下为什么不是 3 条:因为改坏框那一处同时踩了两条规则。 写校验器时这种「一处错触发多条」很常见,梳理时要按问题去重,别按报错条数算。 这三类错在真实标注文件里几乎一定会出现。 特别是 area,很多导出工具压根不写这个字段,或者写的是多边形的面积而不是框的面积。

30 秒实验

  1. 再加一条规则:检查 bbox 的宽高是否为正数,看能不能抓到零宽框。
  2. 把类别名改成带尾空格的「路灯 」,看现有校验器能不能发现。
  3. 想一想:为什么 area 错了训练不报错,评测才出问题?

常见误区

  1. 「JSON 能读出来就行」——结构对不代表语义对,越界和 id 拼错都不报错。
  2. 「area 可以随便填」——评测按 area 分大小目标,填错指标全偏。
  3. 「类别名差个空格无所谓」——会被当成两个不同类别,模型学成两回事。
自测三问(点开对答案) 1. COCO 格式的三个顶层键是什么? —— images、categories、annotations。 2. 为什么 area 和 bbox 必须一致? —— 评测按目标大小分组算分,分组靠 area;area 错了分组错,指标全偏。 3. 为什么改坏三处会报出四条问题? —— 改坏第一个框同时触发越界和 area 不符两条规则,一处错可被多条命中。

第七章到此结束。下一章进神经网络:从感知机一路讲到六种架构。

相关笔记