CVAT 分割掩码数据集实战:Segmentation Mask 格式导出与导入全解
【免费下载链接】cvatComputer Vision Annotation Tool (CVAT) is a leading platform for building high-quality visual datasets for vision AI. It offers open-source, cloud, and enterprise products, as well as labeling services, for image, video, and 3D annotation with AI-assisted labeling, quality assurance, team collaboration, analytics, and developer APIs.项目地址: https://gitcode.com/GitHub_Trending/cvat/cvat
CVAT 内置的 Segmentation Mask 格式面向语义分割、实例分割与全景分割等图像分割任务,提供一套基于 Pascal VOC 分割格式的简化数据交换方案:导出时生成包含逐像素掩码图片与labelmap.txt颜色映射的 ZIP 归档,导入时可将这些掩码还原为 CVAT 中的 Mask 或 Polygon 标注。读完本文,你将掌握该格式的文件结构、labelmap.txt的 3 通道与 1 通道两种编写规则、掩码着色的 Pascal VOC 颜色算法,以及 CVAT 后端在cvat/apps/dataset_manager/formats/mask.py中实现的完整导出/导入流水线。
格式定位:基于 Pascal VOC 的分割掩码
Segmentation Mask 是一种简单的图像分割数据格式,适用于语义分割(semantic segmentation)、实例分割(instance segmentation)和全景分割(panoptic segmentation)任务。它是 CVAT 自定义格式,底层基于 Pascal VOC 分割格式扩展而来(文档中明确了这一定位),因此在文件目录布局、labelmap.txt约定上与 VOC 家族保持一致,但将标注统一落盘为逐像素的 PNG 掩码图像,便于与常见的分割数据集工具和训练框架对接。
Segmentation Mask 导出
支持的标注类型与限制
- 支持的标注:Mask、BoundingBox(转换为掩码)、Polygon(转换为掩码)、Ellipse(转换为掩码)
- 属性(Attributes):不支持
- 轨迹(Tracks):不支持,导出时会拆分为独立的形状
导出文件的目录结构
下载得到的文件是一个.zip归档,结构如下:
taskname.zip/ ├── labelmap.txt # optional, required for non-Pascal VOC labels ├── ImageSets/ │ └── Segmentation/ │ └── default.txt # list of image names without extension ├── SegmentationClass/ # merged class masks │ ├── image1.png │ └── image2.png └── SegmentationObject/ # merged instance masks ├── image1.png └── image2.png # labelmap.txt # label : color (RGB) : 'body' parts : actions background:0,128,0:: aeroplane:10,10,128:: bicycle:10,128,0:: bird:0,108,128:: boat:108,0,100:: bottle:18,0,8:: bus:12,28,0::其中:
ImageSets/Segmentation/default.txt:列出参与导出的图像名(不含扩展名);SegmentationClass/:按类别合并的掩码(merged class masks),同一类别的所有实例像素合并到同一张图上,适合语义分割;SegmentationObject/:按实例合并的掩码(merged instance masks),每个实例占据一个独立颜色索引,适合实例分割。
掩码图像的像素编码规则
每张掩码都是一张 1 通道或 3 通道的.png图像,图像中每个像素的颜色对应一个特定标签。颜色按 Pascal VOC 官方配色算法生成;默认使用颜色(0, 0, 0)表示背景。
labelmap.txt的每一行遵循label : color (RGB) : 'body' parts : actions的格式:冒号分隔 4 个字段,第一行注释说明了这一约定;对 CVAT 来说关键是前两个字段——标签名与 RGB 颜色。
源码级解析:导出流水线
CVAT 后端在 cvat/apps/dataset_manager/formats/mask.py 中注册了该格式,导出函数名为 "Segmentation mask"、扩展名 ZIP、版本号 1.1:
@exporter(name="Segmentation mask", ext="ZIP", version="1.1") def _export(dst_file, temp_dir, instance_data, save_images=False): with GetCVATDataExtractor(instance_data, include_images=save_images) as extractor: dataset = Dataset.from_extractors(extractor, env=dm_env) dataset.transform(RotatedBoxesToPolygons) dataset.transform("polygons_to_masks") dataset.transform("boxes_to_masks") dataset.transform(EllipsesToMasks) dataset.transform("merge_instance_segments") dataset.export( temp_dir, "voc_segmentation", save_media=save_images, apply_colormap=True, label_map=make_colormap(instance_data), ) make_zip_archive(temp_dir, dst_file)从这条调用链可以读出文档中"标注支持"结论的实现依据:
GetCVATDataExtractor从 CVAT 任务/项目中抽取标注数据,构建 Datumaro 数据集;RotatedBoxesToPolygons(定义于 cvat/apps/dataset_manager/formats/transformations.py)先把带旋转角度的 Bounding Box 展开为 Polygon,再经"polygons_to_masks"转为掩码——这就是"BBox 作为掩码导出"的路径;"boxes_to_masks"处理普通 Bounding Box,将其外扩为矩形掩码;EllipsesToMasks使用 OpenCV 的cv2.ellipse绘制填充椭圆并编码为 RLE,实现"Ellipse 作为掩码";"merge_instance_segments"将同图内的掩码合并,从而同时产出SegmentationClass与SegmentationObject两个目录;- 最终以
voc_segmentation格式落盘并打包为 ZIP。
其中label_map=make_colormap(instance_data)决定了labelmap.txt的内容。cvat/apps/dataset_manager/formats/utils.py 中的make_colormap会读取任务的标签定义,若标签列表中不存在background,会自动在首位插入{"name": "background", "color": "#000000"},并把每个标签的十六进制颜色解析为 RGB 三元组。这解释了文档中"默认背景色为(0, 0, 0)"以及labelmap.txt首行为background:0,128,0::这类示例数据的来源(示例中背景颜色来自标签自身的配色,而非强制覆写为黑色)。
另外两点与源码相关的事实:
- 格式注册入口在 cvat/apps/dataset_manager/formats/registry.py 中统一导入
mask模块,导出/导入格式分别登记到EXPORT_FORMATS/IMPORT_FORMATS字典,前端"导出/导入"对话框里的 "Segmentation mask 1.1 (ZIP)" 选项即来自这里; - 标签颜色与预定义颜色表 cvat/apps/dataset_manager/formats/predefined_colors.txt 及 Pascal VOC 哈希配色(
get_color_from_index,将 8 位颜色索引展开为 3 个 8 位颜色通道)保持一致,保证掩码像素颜色可被标准 VOC 工具链正确解析。
Segmentation Mask 导入
支持的标注类型与限制
- 支持的标注:Mask;Polygon(当启用 "Convert masks to polygons" 选项时)
- 属性(Attributes):不支持
- 轨迹(Tracks):不支持
上传的文件是如下结构的.zip归档:
archive.zip/ ├── labelmap.txt # optional, required for non-Pascal VOC labels ├── ImageSets/ │ └── Segmentation/ │ └── <any_subset_name>.txt ├── SegmentationClass/ │ ├── image1.png │ └── image2.png └── SegmentationObject/ ├── image1.png └── image2.png与导出相比,导入对子集名的要求更宽松(<any_subset_name>.txt),且同时支持 3 通道彩色掩码和灰度(1 通道)掩码。
3 通道掩码导入:用 labelmap.txt 声明全部颜色
导入 3 通道掩码时,labelmap.txt必须声明数据集中用到的所有颜色:
# labelmap.txt # label : color (RGB) : 'body' parts : actions background:0,128,0:: aeroplane:10,10,128:: bicycle:10,128,0:: bird:0,108,128:: boat:108,0,100:: bottle:18,0,8:: bus:12,28,0::即每一行把"颜色 (RGB)"与"标签名"绑定,CVAT 按掩码图中的实际像素颜色查表反解出标签。
1 通道掩码导入:无间隙的连续颜色索引
导入 1 通道(灰度)掩码时,labelmap.txt的编写规则完全不同——它按行号即颜色索引的方式声明,且要求:
- 声明的颜色索引不能有空缺(no gaps);
- 行数必须等于掩码图中出现的最大颜色索引(注意文档表述为行数量与最大索引对应的声明关系);
- 行的顺序必须与颜色索引一一对应(第 n 行对应颜色索引 n);
- 每行的颜色字段可以任意且互不相同;
- 若标注中实际使用的颜色索引存在跳号,必须用任意"占位标签"(dummy labels)把空位补齐。
示例:
# labelmap.txt # label : color (RGB) : 'body' parts : actions q:0,128,0:: # color index 0 aeroplane:10,10,128:: # color index 1 _dummy2:2,2,2:: # filler for color index 2 _dummy3:3,3,3:: # filler for color index 3 boat:108,0,100:: # color index 4 ... _dummy198:198,198,198:: # filler for color index 198 _dummy199:199,199,199:: # filler for color index 199 ... the last label:12,28,0:: # color index 200这种约定保证了"像素值 → 行号 → 标签名"的映射是确定的,CVAT 无需知道灰度值本身对应什么 RGB 颜色。
源码级解析:导入流水线与掩码转多边形选项
导入实现同位于 cvat/apps/dataset_manager/formats/mask.py:
@importer(name="Segmentation mask", ext="ZIP", version="1.1") def _import(src_file, temp_dir, instance_data, load_data_callback=None, **kwargs): shutil.unpack_archive(src_file.name, temp_dir, "zip") detect_dataset(temp_dir, format_name="voc", importer=dm_env.importers.get("voc")) dataset = Dataset.import_from(temp_dir, "voc", env=dm_env) dataset = MaskToPolygonTransformation.convert_dataset(dataset, **kwargs) if load_data_callback is not None: load_data_callback(dataset, instance_data) import_dm_annotations(dataset, instance_data)流程与导出形成镜像:解压 ZIP → 用 Datumaro 的voc导入器解析掩码目录(detect_dataset先做合法性校验,格式不符时提前报错)→ 可选地执行掩码到多边形的转换 →import_dm_annotations将 Datumaro 数据集写回 CVAT。
"Convert masks to polygons" 选项对应 cvat/apps/dataset_manager/formats/transformations.py 中的MaskToPolygonTransformation:
class MaskToPolygonTransformation: @classmethod def declare_arg_names(cls): return ["conv_mask_to_poly"] @classmethod def convert_dataset(cls, dataset, **kwargs): if kwargs.get("conv_mask_to_poly", True): dataset.transform("masks_to_polygons") return dataset从源码结构看,该开关的参数名为conv_mask_to_poly,默认值为 True——即默认启用时将导入的掩码转换为 Polygon 以便在 CVAT 界面中以矢量形式编辑;取消勾选后则按 Mask 形状导入。这也解释了文档中"Supported annotations: Masks, Polygons (if Convert masks to polygons is enabled)"的措辞。
值得对比的是 cvat/apps/dataset_manager/formats/pascal_voc.py 中 PASCAL VOC 格式导入器:当归档缺少labelmap.txt时,它会用任务已有标签自动生成一份兜底映射。而 Segmentation Mask 导入器(mask.py)没有这一步——因此对非 Pascal VOC 标签的数据集,labelmap.txt是硬性要求,这一点与文档"optional, required for non-Pascal VOC labels"的说明一致。
格式选型与实操要点
- 如果你的目标是训练语义/实例分割模型,且希望用最少配置得到"一张图一个掩码文件"的经典布局,Segmentation Mask 导出是首选;
SegmentationClass与SegmentationObject两个目录分别对应类级与实例级需求。 - 标签使用 Pascal VOC 标准类别名(aeroplane、bicycle、bird 等)时,
labelmap.txt可省略或保持 VOC 标准配色;自定义标签则必须提供labelmap.txt,且 1 通道掩码要严格遵守"无间隙索引 + 占位补齐"规则,行序即索引。 - 导出侧所有属性信息和轨迹分组都会被丢弃(Tracks 拆分为独立形状),若需要保留属性或时序信息,应改用 CVAT for video 等其他格式。
- 想深入了解底层的 Datumaro 集成与数据集绑定(
GetCVATDataExtractor、import_dm_annotations、detect_dataset等符号),可继续查看 cvat/apps/dataset_manager/bindings.py;格式注册机制见 cvat/apps/dataset_manager/formats/registry.py。
【免费下载链接】cvatComputer Vision Annotation Tool (CVAT) is a leading platform for building high-quality visual datasets for vision AI. It offers open-source, cloud, and enterprise products, as well as labeling services, for image, video, and 3D annotation with AI-assisted labeling, quality assurance, team collaboration, analytics, and developer APIs.项目地址: https://gitcode.com/GitHub_Trending/cvat/cvat
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考