labelme 实例分割标注与 VOC/COCO 数据集转换实战指南
【免费下载链接】labelmeImage annotation with Python. Supports polygon, rectangle, circle, line, point, and AI-assisted annotation.项目地址: https://gitcode.com/gh_mirrors/la/labelme
本指南以仓库中的 examples/instance_segmentation 为例,完整讲解如何用 labelme 对图片进行实例分割标注,并将标注结果一键转换为 Pascal VOC 与 MS COCO 两种主流数据格式。读完本文,你将掌握--validate-label、--label-flags、--config等关键命令行参数的实际用法,理解labelme2voc.py与labelme2coco.py的转换原理(包括类别编号、实例合并、标签像素值约定),并能独立复现从原始图片到可训练数据集的完整流水线。
一、示例工程结构总览
examples/instance_segmentation是一个完整的实例分割工作区,同时包含"标注前"与"转换后"两个阶段的数据,结构如下:
examples/instance_segmentation/ ├── data_annotated/ # 标注产物:3 张图片 + 3 个 JSON 标注文件 ├── data_dataset_voc/ # labelme2voc.py 的转换输出 ├── data_dataset_coco/ # labelme2coco.py 的转换输出 ├── labelme2voc.py # VOC 格式转换脚本 ├── labelme2coco.py # COCO 格式转换脚本 ├── labels.txt # 类别清单(VOC 20 类) └── README.md # 本文对应的官方说明其中data_annotated内含2011_000003.jpg、2011_000006.jpg、2011_000025.jpg三张示例图片及其同名.json标注文件;data_dataset_voc与data_dataset_coco则是运行转换脚本后生成的成品数据集,可直接对照验证你的转换结果。转换脚本依赖同目录下示例所需的 examples/utils.py 与 examples/tutorial/draw_label_png.py 等辅助工具。
二、数据准备:labels.txt 与标注 JSON 格式
2.1 类别清单 labels.txt
实例分割的第一步是定义类别清单。本示例的 labels.txt 内容如下:
__ignore__ _background_ aeroplane bicycle bird boat bottle bus car cat chair cow diningtable dog horse motorbike person potted plant sofa train tv/monitor前两行是两个特殊约定,需要特别注意:
__ignore__:占位类别,在转换时会被映射为"忽略区域",其像素值在 PNG 中记为255(npy 中为-1),用于遮盖不希望参与训练的物体或区域;_background_:背景类别,像素值恒为0。
其余 20 行即标准 Pascal VOC 的 20 个语义类别。标注时形状的 label 必须能在该清单中找到精确匹配,否则后续转换会报错。
2.2 标注 JSON 的结构
以 data_annotated/2011_000003.json 为例,labelme 4.x 的标注文件顶层结构为:
{ "version": "4.0.0", "flags": {}, "shapes": [ { "label": "person", "points": [[250.8, 107.3], [229.8, 119.3], "...", [270.8, 121.3]], "group_id": 0, "shape_type": "polygon", "flags": {} } ], "imagePath": "2011_000003.jpg", "imageData": null, "imageHeight": 338, "imageWidth": 500 }每个 shape 的关键字段含义:
| 字段 | 含义 | 实例分割中的角色 |
|---|---|---|
label | 形状所属类别 | 决定该形状写入类别层(class 层)的编号 |
points | 顶点坐标列表 | 定义多边形/矩形/圆等几何区域 |
shape_type | 形状类型(polygon/rectangle/circle/line/point/linestrip 等) | 决定栅格化方式 |
group_id | 实例分组标识(可空) | 实例分割的核心:决定多个形状是否属于同一实例 |
flags | 该形状的自定义标志 | 不参与分割掩码,仅作属性记录 |
group_id 与实例划分是本例最值得注意的细节:在2011_000003.json中,前两个person形状共享group_id: 0,说明它们是同一个人的两块多边形碎片,转换时会被合并为一个实例;而第三个person的group_id为null,会作为独立实例处理。__ignore__形状则用于圈出画面中需要忽略的区域。这一约定直接决定了后续实例掩码的生成逻辑。
三、启动标注:命令行参数深度解析
原文档给出的标注命令有两条,分别对应两种典型配置场景。
3.1 指定类别清单与颜色自动分配
labelme data_annotated --labels labels.txt --validate-label exact --config '{shape_color: {mode: auto, auto: {shift: -2}}}'三个参数的作用:
--labels labels.txt:指定类别清单文件。从 labelme/main.py 的解析逻辑看,--labels既支持文件路径,也支持逗号分隔的内联文本;--validate-label exact:开启标签校验。在 labelme/_config/init.py 中可以看到validate_label配置项只接受None与"exact"两种取值,且启用时必须同时提供--labels,否则启动会直接报错。exact的含义是强制标注标签必须与类别清单中的名称完全一致,从 labelme/_app.py 中的validate_label()实现可以看出,它会拿用户输入的标签与已加载的类别集合做精确匹配,匹配失败则阻止创建/修改该形状——这是保证转换阶段不出现"未知类别"异常的第一道防线;--config '{shape_color: {mode: auto, auto: {shift: -2}}}':以 YAML 字符串形式覆盖配置。shape_color.mode: auto表示形状颜色自动分配(可选值为auto/uniform/by_label,见 labelme/_config/default_config.yaml),auto.shift的默认值是0,这里设为-2表示在自动生成的颜色序列上做偏移,让相邻形状呈现可区分的颜色渐变,便于在画布上快速分辨不同标注对象。
3.2 按标签规则批量配置标志(flags)
labelme data_annotated --labels labels.txt --label-flags '{.*: [occluded, truncated], person: [male]}'--label-flags用于建立"标签 → 可选标志列表"的映射,采用 YAML 格式的正则表达式: [标志...]结构:
.*: [occluded, truncated]:所有形状都可勾选occluded(遮挡)与truncated(截断)两个标志;person: [male]:标签为person的形状额外提供male标志。
从 labelme/main.py 的解析实现看,该参数既可以是内联 YAML 字符串(如本例),也可以是 YAML/JSON 文件的路径。标志最终会写入每个 shape 的flags字段,虽然不参与掩码生成,但可携带重要的属性信息(如遮挡、性别、天气等),供训练或后处理阶段使用。
标注完成后,data_annotated目录下每个图片都会生成同名.json文件,这就是后续两个转换脚本的输入。
四、转换为 VOC 格式数据集
4.1 转换命令与输出目录
./labelme2voc.py data_annotated data_dataset_voc --labels labels.txt该命令生成如下目录结构:
data_dataset_voc/ ├── JPEGImages/ # 原图(RGB JPEG) ├── SegmentationClass/ # 类别标签 PNG ├── SegmentationClassNpy/ # 类别标签 npy(int32 数组) ├── SegmentationClassVisualization/ # 类别标签可视化(叠加在灰度图上的伪彩色 JPEG) ├── SegmentationObject/ # 实例标签 PNG ├── SegmentationObjectNpy/ # 实例标签 npy ├── SegmentationObjectVisualization/ # 实例标签可视化 └── class_names.txt # 写入的类别清单4.2 命令行参数
labelme2voc.py 支持三个可选开关:
| 参数 | 默认行为 | 作用 |
|---|---|---|
--noobject | 生成实例层 | 跳过 SegmentationObject 系列目录 |
--nonpy | 生成 npy | 跳过 SegmentationClassNpy / SegmentationObjectNpy |
--noviz | 生成可视化 | 跳过 SegmentationClassVisualization / SegmentationObjectVisualization |
注意:输出目录已存在时脚本会直接报错退出(Output directory already exists),因此重复转换需先清理或更换目录名。
4.3 转换原理:类别编号与实例合并
理解转换结果,关键是看懂脚本内部的编号约定(见 examples/utils.py 与 labelme2voc.py):
- 类别编号从 -1 开始:
_load_class_names()中class_id = i - 1,因此__ignore__对应-1、_background_对应0、aeroplane对应1,以此类推; - 语义层与实例层分别生成:
utils.shapes_to_label()对每个形状调用shape_to_mask()栅格化出布尔掩码,然后写入两个 int32 数组——cls(类别编号)与ins(实例编号,从 1 开始,相同(label, group_id)组合共享同一编号,即自动合并碎片); - 忽略区域清零:
ins[cls == -1] = 0将__ignore__区域的实例值置 0; - PNG 存 8-bit,npy 存 int32:
imgviz.io.lblsave()把标签写入 uint8 PNG,因此负值(-1)会被存储为255;而 npy 保留原始 int32,__ignore__仍为-1; - 实例名按编号命名:
SegmentationObject的 label_names 为0, 1, 2, ...,可视化时每个实例显示其编号; - 转换同时把类别清单写回输出目录的
class_names.txt,供训练框架直接读取。
4.4 标签值约定:为什么只有 0、4、14
原文档特别提醒:查看生成的标签 PNG,会发现其中只包含非常低的标签值(例如0, 4, 14),而255表示__ignore__标签值(npy 中为-1)。原因在于:
- 背景区域占绝大多数,值为
0; - 画面中实际出现的类别数量很少(示例图中只有 person、bottle 等少数类别),因此编号
4、14这类低值即可覆盖全部前景像素; 255是 uint8 下对-1的编码,用于标记被__ignore__形状圈出的区域,训练时通常应将其排除在损失计算之外。
4.5 查看标签 PNG
../tutorial/draw_label_png.py data_dataset_voc/SegmentationClass/2011_000003.png # 左:语义标签 ../tutorial/draw_label_png.py data_dataset_voc/SegmentationObject/2011_000003.png # 右:实例标签注:原文档中该命令的
../tutorial/是相对于examples/instance_segmentation的写法,对应的仓库根目录路径为 examples/tutorial/draw_label_png.py。
draw_label_png.py 会读取标签 PNG,自动把255还原为-1(见其中UNLABELED_PNG_VALUE = 255的处理逻辑),打印标签值分布与标签名映射,并用 matplotlib 叠加伪彩色可视化(也可通过--image参数同时叠加原图)。
下图为本示例 VOC 转换输出的三张代表性产物(左:原始 JPEG;中:类别标签可视化;右:实例标签可视化,来自 examples/instance_segmentation/data_dataset_voc):
五、转换为 COCO 格式数据集
5.1 转换命令与输出目录
./labelme2coco.py data_annotated data_dataset_coco --labels labels.txt该命令生成:
data_dataset_coco/ ├── JPEGImages/ # 原图(RGB JPEG) ├── Visualization/ # 实例分割可视化(每张图一张) └── annotations.json # COCO 格式标注文件同样地,输出目录已存在会直接退出。可选的--noviz参数用于关闭可视化目录的生成。前置依赖:该脚本需要pycocotools(labelme2coco.py 在缺失时会提示pip install pycocotools并退出),以及imgviz、numpy。
5.2 annotations.json 结构与生成逻辑
脚本首先构造 COCO 顶层结构(labelme2coco.py 中main()的前半部分):
{ "info": { "year": 2026, "date_created": "2026-09-20 07:24:57.000000" }, "licenses": [{ "id": 0, "name": null }], "type": "instances", "images": [], "categories": [], "annotations": [] }各部分的生成规则如下:
- categories:同样按
class_id = i - 1编号,__ignore__被跳过不进入类别表,_background_为0; - images:每张图一个条目,包含
file_name(相对输出目录的路径)、height、width、id(按文件排序的自增编号); - annotations:每个实例一个条目,包含
id、image_id、category_id、segmentation、area、bbox、iscrowd。
5.3 形状到 COCO segmentation 的转换细节
COCO 的segmentation需要多边形坐标列表,脚本对三种常见形状做了专门处理:
- polygon(多边形):顶点坐标直接展平为
[x1, y1, x2, y2, ...]; - rectangle(矩形):两个对角点排序后展开为 4 个顶点
[x1, y1, x2, y1, x2, y2, x1, y2]; - circle(圆):调用
_circle_to_polygon_segmentation()做多边形近似——从最少 12 个顶点开始,只要弦高误差超过 1 像素容差(CIRCLE_APPROXIMATION_TOLERANCE_PX = 1.0)就翻倍顶点数,直至近似误差在 1 像素以内。
5.4 实例合并与掩码计算
与 VOC 转换一致,实例划分同样以(label, group_id)为键:
group_id为null时生成uuid.uuid1()作为临时分组;- 同一实例的多个形状掩码按位OR合并(
masks[instance] = masks[instance] | mask); - 掩码转为 Fortran 序 uint8 后交给
pycocotools.mask.encode()得到 RLE 编码,area与bbox也由pycocotools.mask.area()/pycocotools.mask.toBbox()从掩码计算,保证面积与包围盒与掩码严格一致; iscrowd恒为0。
5.5 可视化输出
每张图还会生成一张实例可视化(Visualization/<basename>.jpg),通过imgviz.instances2rgb()在图上叠加彩色实例掩码、类别标签文字与边框,例如 examples/instance_segmentation/data_dataset_coco/Visualization/2011_000003.jpg,可用于快速目检标注质量与转换正确性。
六、运行前提与依赖
- 标注工具:按仓库常规方式安装 labelme 本体后使用
labelme命令; - 转换脚本依赖:
numpy、imgviz、PIL(VOC 与 COCO 共用),COCO 转换额外需要pycocotools; - examples/utils.py 是自包含的 JSON 标注读取与栅格化工具,其模块注释明确指出它刻意不依赖 labelme 包本身,只依赖标准库、numpy 与 PIL——这既是本示例的工作参考实现,也可以直接复制到你自己的数据加载代码中(例如 PyTorch 的
Dataset),无论 labelme 内部如何演进都能稳定工作。
七、总结
从本示例可以提炼出一条完整的实例分割数据生产流水线:
- 用
labels.txt定义类别(含__ignore__、_background_两个特殊条目); - 用
labelme配合--validate-label exact与--label-flags完成高质量标注,注意通过group_id表达"同一实例的多个碎片"; - 用 labelme2voc.py 输出 VOC 格式(JPEGImages + SegmentationClass/Object 的 PNG/npy/可视化),供语义与实例分割模型使用;
- 用 labelme2coco.py 输出 COCO 格式(JPEGImages + annotations.json),供基于 COCO API 的检测/分割框架直接消费;
- 最后用 draw_label_png.py 或
Visualization目录核对标签值与实例划分是否符合预期。
理解class_id = i - 1、255 = -1(ignore)以及(label, group_id)实例合并这三条核心约定,你就能完全掌握 labelme 实例分割数据在 VOC 与 COCO 两大生态之间的自由转换。
【免费下载链接】labelmeImage annotation with Python. Supports polygon, rectangle, circle, line, point, and AI-assisted annotation.项目地址: https://gitcode.com/gh_mirrors/la/labelme
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考