简介:Cityscapes 数据集的 gtFine 子集标注文件,是面向城市街景语义分割任务的核心数据资源。这套压缩包内含 2000 个 JSON 文件,整体约 730MB,每个文件保存一张高分辨率街景图像的精细多边形标注,覆盖道路、建筑、行人、车辆等 30 个类别,可供研究者直接用于训练 FCN、U-Net、DeepLab 等分割网络,或结合原始 RGB 图进行数据增强与预处理。由于标注精度达到像素级、且来自多个欧洲城市的不同天气与时段,它在自动驾驶、智能交通等场景中具有很强的实用价值,能够有效验证模型在真实复杂城市环境下的泛化能力。已有 2130 人学习/下载,适合计算机视觉、深度学习领域的学生与工程师使用,可省去大量人工标注成本,专注开展模型设计与调优。配合其他分卷还可构建完整训练流程,支撑城市级场景理解与无人驾驶技术研究。 做语义分割和自动驾驶视觉这块的人,几乎绕不开 Cityscapes 这个数据集。不管是发论文刷榜单,还是做工业级感知模型的评估基准,Cityscapes 都是默认的“第一站”。我最初接触这个数据集是在做车道线检测和可行驶区域分割时,当时为了把数据下载下来并且正确解析标注文件,折腾了不少时间。这篇就把 Cityscapes 数据集本身讲透,包括它的任务定义、目录结构、标注体系,以及实际操作中容易踩的坑,给后面要上手的朋友一个完整的参考。
1. 项目背景与核心价值
1.1 Cityscapes 是做什么的
Cityscapes 是一个面向城市街道场景理解的图像数据集,由奔驰实验室联合多个学术机构在 2016 年发布,CVPR 上那篇论文《The Cityscapes Dataset for Semantic Urban Scene Understanding》是它的官方出处。数据集采集了德国和法国多个城市的街道影像,涵盖 50 个不同城市的白天、良好天气条件下的驾驶场景,一共包含 5000 张精细标注图像和 20000 张粗糙标注图像。
从任务角度来看,Cityscapes 主要支持三类视觉任务:
- 语义分割:把图像中每个像素分类到预定义的类别,比如道路、人行道、建筑、车辆、行人等。这是 Cityscapes 最核心的任务,也是绝大多数人使用它的目的。
- 实例分割:在语义分割的基础上区分同一类别的不同个体,比如两辆相邻的汽车要分为 car 1 和 car 2。Cityscapes 对车辆、行人、自行车等类别提供了实例级标注。
- 全景分割:将语义分割和实例分割统一起来,既要给每个像素语义标签,又要区分可数物体的个体。Cityscapes 的标注结构天然支持全景分割任务。
所以,不管你是研究语义分割、实例分割还是全景分割,Cityscapes 都是一个绕不开的标准数据集。
1.2 为什么它这么重要
Cityscapes 之所以能成为行业标准,原因有三点。
第一是数据质量高。图像分辨率达到 2048x1024,远高于当时其他数据集(比如 CamVid 只有 960x720),标注精细到像素级多边形轮廓,而不是简单的矩形框。这意味着模型能学到更精细的边界信息。
第二是场景复杂度高。Cityscapes 采集的真实道路画面包含大量挑战性元素——行人遮挡、车辆密集、建筑阴影、光照变化、不同材质的路面等。一个模型如果能在 Cityscapes 上取得好的表现,基本可以说明它在真实城市场景中有较强的泛化能力。
第三是评估体系成熟。官方提供了严格的 train/val/test 划分,test 集的标注不公开,需要提交到官网服务器评估,这保证了论文之间对比的公平性。语义分割、实例分割、全景分割三种任务都有独立的评估指标,大家可以在同一起跑线上比较算法效果。
1.3 适合谁使用这个数据集
如果你是下面这几类人,Cityscapes 会是你需要认真研究的数据集:
- 刚入门语义分割的研究生或工程师,需要在一个公认的数据集上验证自己的模型效果;
- 做自动驾驶感知的算法工程师,需要训练道路场景的分割模型(比如用 mmsegmentation 训练 Cityscapes 是很多公司内部的标准流程);
- 做模型压缩、知识蒸馏、域自适应等方向的研究者,Cityscapes 常作为源域数据集或基准数据集使用;
- 用 nnUNet 等框架做医疗或其他领域分割的同学,也经常先把 Cityscapes 作为算法验证的标准数据集。
这篇先讲透数据集的获取、目录结构、标注文件格式和可视化方法,下一部分再展开训练细节。
2. 数据集获取与目录结构详解
2.1 下载方式与账号注册
Cityscapes 的下载入口在官网,和很多学术数据集不同,它不是直接给一个链接让你点,而是需要先注册账号,同意数据使用协议后才能下载。这个流程卡住了不少人,我第一次下载时就因为网络延迟和注册审核等了两天。
具体操作流程是:
- 访问 Cityscapes 官网,点击右上角的 Register 注册账号。
- 填写个人信息,包括姓名、单位、邮箱、使用目的等。这里建议使用学校或公司的企业邮箱,审核通过率更高。
- 提交后等待审核,通常在 1-2 个工作日内会收到激活邮件。
- 激活账号后登录,在 Downloads 页面就能看到数据集的 6 个部分:gtFine、gtCoarse、leftImg8bit、leftImg8bit_trainextra、camera、vehicle、disparity。
下载时建议用官方提供的脚本,在服务器上直接拉取比较方便。官方 GitHub 仓库 cityscapesScripts 里提供了prepare_cityscapes_dataset.py和Download相关脚本,也可以用简单的 wget 或者 curl 加上账号 cookie 下载。
注意:登录后的下载链接是临时的,带有 session 信息,直接用 wget 下载时需要在浏览器里复制带有 token 的完整链接,或者用脚本配合账号密码自动获取。手动复制链接时不要用迅雷等多线程工具,容易被服务器断开连接。
2.2 六大文件包的职责划分
下载解压后,你会看到 6 个文件夹,每个文件夹的职责非常清晰,我整理成了一张表:
| 文件夹 | 内容 | 作用 |
|---|---|---|
| leftImg8bit | 原始图像,8-bit PNG,分辨率 2048x1024 | 模型输入图像 |
| gtFine | 精细标注,包含语义、实例、多边形等 | 语义/实例/全景分割训练与评估 |
| gtCoarse | 粗糙标注,包含语义标签 | 大规模预训练或半监督学习 |
| camera | 相机参数,内外参矩阵 | 3D 重建、深度估计等任务 |
| vehicle | 车辆轨迹、GPS、速度等信息 | 轨迹预测、多任务学习 |
| disparity | 视差图,DispNet 预测结果 | 深度估计任务 |
其中,最常用的是leftImg8bit和gtFine。leftImg8bit其实就是原始拍摄图像,按城市和序列组织成 train/val/test 三个子集。gtFine则是人工精细标注的结果,也是我们做语义分割时最关心的部分。
2.3 图像文件命名规则
Cityscapes 的文件命名非常规范,从文件名就能提取全部信息。格式是:
城市名_序列号_帧号_leftImg8bit.png比如:
aachen_000000_000019_leftImg8bit.png对应的是 aachen 城市、序列 000000、第 000019 帧的图像。注意leftImg8bit表示这是左侧摄像头拍摄的 8-bit 图像。
对应的标注文件命名格式是:
aachen_000000_000019_gtFine_labelIds.png aachen_000000_000019_gtFine_instanceIds.png aachen_000000_000019_gtFine_color.png aachen_000000_000019_gtFine_polygons.json这里能看到 gtFine 下会有多种文件,分别是:
_labelIds.png:像素值为 0~33 的语义标签图,每个像素的数值直接对应类别 ID,这也是训练模型时实际使用的文件。_instanceIds.png:像素值为实例 ID 的图,其中物体实例的 ID 编码是"类别 ID * 1000 + 实例编号",背景区域像素值为 0。_color.png:用彩色标注的语义可视化图,方便人眼查看。_polygons.json:JSON 格式的多边形标注文件,记录了每个物体实例的轮廓点坐标。
理解这些文件命名规则很重要,因为后续写数据加载代码时,你需要根据leftImg8bit的文件名去拼接出对应的标注文件路径。
3. 标注体系与任务类型全面拆解
3.1 33 类标注与 19 类评估
Cityscapes 的标签体系经过精心设计,官方定义了 30 个类别,加上 ignore 区域共 33 个标签值。这 30 个类别被划分为 8 个大类:平面(flat)、人(human)、车辆(vehicle)、建筑(construction)、物体(object)、自然(nature)、天空(sky)、未知(void)。
但在实际训练和评估时,我们通常只用 19 个类别。原因在于,很多类别在真实场景中出现频率极低,比如卡车、巴士、房车,如果都参与训练和评估,会造成严重的类别不平衡,模型会偏向学习高频类别。
官方推荐使用的 19 类分别是:
- 道路、人行道、建筑、墙、围栏、电线杆、交通灯、交通标志、植被、地形、天空、人、骑手、汽车、卡车、巴士、火车、摩托车、自行车
这 19 个类别是语义分割论文中通行的标准(mIoU 的计算基准)。下载的gtFine_labelIds.png中像素值虽然包含 0~33,但在实际训练时需要做一个映射,把 33 类映射到 19 类,映射关系在官方脚本labels.py中有定义。
3.2 精细标注与粗糙标注的区别
Cityscapes 提供两套标注:精细标注(gtFine)和粗糙标注(gtCoarse)。
- gtFine:5000 张图像,像素级精细标注,质量高。分为 train(2975 张)、val(500 张)、test(1525 张)。这是官方推荐的训练和评估标准。
- gtCoarse:20000 张图像,标注相对粗糙,多边形轮廓没有那么精细。主要用于大规模预训练,或者作为半监督学习中的无标注数据补充。
需要注意的是,gtCoarse 只有 train 和 val 的划分,对应leftImg8bit_trainextra文件夹(额外的 20000 张原始图像)。如果你决定用 gtCoarse 做预训练,需要额外下载leftImg8bit_trainextra,因为它不在默认的leftImg8bit里。
3.3 三种任务的数据支撑
Cityscapes 的标注结构可以同时支撑三种分割任务,这也是它的设计精妙之处。
语义分割:直接使用_labelIds.png。每个像素的值就是 19 类(映射后)的类别 ID。模型输出的预测图也是 19 通道的概率图,计算交叉熵损失时直接用这个文件做 ground truth。这是最简单直接的方式,也是入门第一个要做对的任务。
实例分割:使用_instanceIds.png。这张图中每个像素的值为category_id * 1000 + instance_id。比如一辆汽车的实例 ID 是 24000(汽车类别 ID 24 + 实例 0),另一辆是 24001。背景和不可数类别(比如道路、建筑)的像素值为 0。处理时,先对 instanceIds 除以 1000 取整得到语义类别,对 1000 取余得到实例编号。Cityscapes 官方对实例标注的范围覆盖 person、rider、car、truck、bus、train、motorcycle、bicycle 这 8 个类别。
全景分割:结合_labelIds.png和_instanceIds.png。全景分割的评价体系分 stuff 类和 thing 类,Cityscapes 已经把这套体系设计好了。不可数的 stuff 类别直接用语义标签,可数的 thing 类别用实例标签。有些框架如 mmsegmentation 在训练全景分割时,会直接读取这两个文件并将其合并成全景标签图(panoptic label)。
我个人的经验是,先把语义分割跑通,再扩展实例分割和全景分割,不要一上来就三线作战,容易在数据加载时出各种问题。
4. 数据读取与可视化实操
4.1 安装官方工具包 cityscapesscripts
Cityscapes 官方提供了一个 Python 工具包cityscapesscripts,它不仅能帮我们验证标注文件是否完整、可视化标注结果,还提供将 labelIds 映射到 trainIds 的完整逻辑。这个工具包很重要,因为官方训练时使用的 trainId 和原始 labelId 不同。
安装非常简单:
pip install cityscapesscripts然后把项目仓库克隆下来(或者直接从 pip 的安装路径下找脚本):
git clone https://github.com/mcordts/cityscapesScripts.git cd cityscapesScripts仓库里的helpers/labels.py定义了所有类别信息,包括name、id、trainId、category、color等关键字段。这个文件是我做数据处理时最重要的参考文件。
4.2 将标注转换为训练可用的 trainId 格式
原始的gtFine_labelIds.png中,像素值对应的是id字段(0~33),其中很多类别的 id 是不连续的,比如汽车是 24,自行车是 33。在语义分割训练中,类别 ID 必须是连续的 0~18(对应 19 类),这样在计算交叉熵损失和评估 mIoU 时才不会出错。
官方提供了createTrainIdLabelImgs.py,用于将 labelIds 转换为使用 trainId 的图片:
python cityscapesscripts/preparation/createTrainIdLabelImgs.py \ --gtFineDir /path/to/gtFine \ --outputDir /path/to/gtFine_trainIds \ --trainId转换后,每个标注图的像素值就是 0~18(或 255 表示 ignore 区域)。实际训练时,我都是直接读取转换后的 trainId 图像,而不是在训练时动态映射,这样可以少写不少调试代码。
4.3 可视化标注,快速理解数据
在动手训练之前,强烈建议先可视化几张标注图,直观理解数据长什么样。官方提供了visualizeAnnotations.py脚本:
python cityscapesscripts/visualization/visualizeAnnotations.py \ --city aachen \ --sequence 000000 \ --frame 000019它会显示原始图像、语义标注、实例标注三者的对比。另外,你也可以直接用 OpenCV 读取_color.png文件,这个文件就是官方预先做好的人眼可读的彩色标注图。
我自己还写过一个简单的可视化脚本,把原始图和 labelIds 叠加起来,半透明显示,方便快速查看某个区域的标注是否精细。这个步骤对排查标注边界模糊、类别空洞等问题很有帮助。
4.4 数据加载的两种常见方式
在实际项目里,Cityscapes 数据加载有两种常见方式。
第一种是直接写一个 Dataset 类,用 OpenCV 或者 PIL 读取图像文件。流程是:
- 读取
leftImg8bit图像。 - 根据文件名拼接出对应的 trainId 标注图路径。
- 对原始图像做数据增强(缩放、裁剪、翻转、色彩抖动等),对标注图做相同的几何变换(注意不要对标注图做颜色增强)。
- 将图像转为 Tensor,进行归一化。
- 返回图像、标注和文件名。
第二种是使用现成的框架,比如 mmsegmentation。mmsegmentation 里已经内置了 Cityscapes 数据集的加载器,你只需要配置好数据路径和类别信息即可:
dataset_type = 'CityscapesDataset' data_root = 'data/cityscapes/'这种方式的好处是不用重复造轮子,mmsegmentation 的 dataloader 已经把 trainId 映射、ignore_index 处理等细节都封装好了。
我目前更多的训练流程用的是 mmsegmentation,但建议初学者还是先自己写一遍 Dataset 类,彻底理解图像和标注的对应关系,遇到问题才能自己排查。
5. 常见问题与避坑指南
5.1 下载慢、断连怎么办
Cityscapes 官方服务器在欧洲,国内访问速度不稳定,经常下载到一半断开。我实测过的几个方案:
- 使用浏览器直接下载,不要用多线程下载工具。浏览器会带着 session 信息,基本能保持连接,速度慢点但稳定。
- 分割下载,把每个压缩包单独下载,不要一次性下载整个文件夹。比如先下载 gtFine,再下载 leftImg8bit,每个包都独立传输。
- 如果服务器在国外,可以用
wget --user=账号 --password=密码配合官方脚本。如果服务器在国内,建议用 filezilla 等 FTP 工具配合浏览器复制出的带 token 的完整链接,断点续传能力更强,实测比 wget 更稳。
5.2 解压后路径对不上
很多人在配置 mmsegmentation 时会遇到路径对不上的问题。Cityscapes 解压后的原始目录结构是:
cityscapes/ ├── leftImg8bit/ │ ├── train/ │ ├── val/ │ └── test/ ├── gtFine/ │ ├── train/ │ ├── val/ │ └── test/ └── gtCoarse/而 mmsegmentation 期望的目录结构通常是把数据集放在data/cityscapes下,并且gtFine中要有 trainId 转换后的文件。如果直接拷贝原始数据进去,训练时会报"找不到 gtFine_trainIds"之类的错误。
解决办法是先运行createTrainIdLabelImgs.py生成 trainId 文件,或者注意 mmsegmentation 的数据预处理说明,有时根本不需要转换而是要在配置中指定reduce_zero_label=True和ignore_index=255。我在这里踩过坑,明明数据路径对,但训练时 loss 一直不下降,查了半天发现是标签映射没有对齐。
5.3 trainId 映射错误导致 mIoU 异常
Cityscapes 训练时最容易出问题的就是类别映射。直接使用原始的 labelIds(0~33)去算损失,会导致:
- 某些类别缺失,因为训练时只会使用出现过的类别 ID;
- 评估时类别 ID 和 mIoU 计算不匹配,导致结果完全错误。
正确做法是严格使用 trainId 映射。官方labels.py中的映射关系是固定的,下面是常用的几个:
| 原始 id | 名称 | trainId |
|---|---|---|
| 0 | road | 0 |
| 1 | sidewalk | 1 |
| 2 | building | 2 |
| 3 | wall | 3 |
| 4 | fence | 4 |
| 5 | pole | 5 |
| 6 | traffic light | 6 |
| 7 | traffic sign | 7 |
| 8 | vegetation | 8 |
| 9 | terrain | 9 |
| 10 | sky | 10 |
| 11 | person | 11 |
| 12 | rider | 12 |
| 13 | car | 13 |
| 14 | truck | 14 |
| 15 | bus | 15 |
| 16 | train | 16 |
| 17 | motorcycle | 17 |
| 18 | bicycle | 18 |
| -1 | ignore | 255 |
5.4 类别不平衡问题
Cityscapes 中类别分布极不平衡,道路像素占比远超行人、摩托车等类别。直接用交叉熵损失训练,模型会偏向把大部分像素预测为道路,导致小车类别的 mIoU 很低。
实际处理中,我常用的策略是:
- 使用带类别权重的损失函数(
CrossEntropyLoss(weight=...)),权重和类别像素占比成反比。 - 使用 OHEM(在线难例挖掘)或多尺度监督,加强对小目标区域的学习。
- 在数据增强时增加随机裁剪和多尺度缩放,让模型能看到更多小物体的细节。
很多开源实现里默认是不加类别权重的,需要自己根据数据集统计计算。如果想偷懒,可以直接用 mmsegmentation 提供的OHEMPixelSampler,效果也不错。
5.5 粗糙标注与精细标注混用导致评估失真
有些朋友为了提升训练数据量,把 gtCoarse 也加入训练集,但评估时还是用 val 的 500 张精细标注图。注意 gtCoarse 的标注质量比 gtFine 差,轮廓粗糙,边缘噪声大。直接混用会导致模型在精边缘上的表现下降。建议的做法是:
- 用 gtCoarse 做预训练或半监督学习的伪标签增强,但权重要调低;
- 或者在 fine-tune 阶段(最后几十个 epoch)只用 gtFine,让模型适应精细标注的分布。
6. 关于 Cityscapes 的进一步规划
在做完基本的数据解析和可视化之后,Cityscapes 数据集的下一步通常就是训练分割模型。从我个人的实际体验来看,在动手训练前把数据准备、类别映射、评估指标这些问题彻底搞明白,能帮你节省至少一周的排错时间。
对于后面要发的系列文章,我大致规划了三个方向:一是用 mmsegmentation 从零训练 Cityscapes 语义分割模型,包括配置文件的详细解读和训练命令;二是深入解读 Cityscapes 在实例分割与全景分割上的数据加载与评估细节;三是在实际工业项目中,Cityscapes 预训练模型如何迁移到自有数据集(比如无人机航拍、x 光安检物品检测等场景)上的经验。每个方向都有不少坑值得单独写一篇。
Cityscapes 虽然是个老数据集,但凡是做视觉感知的人,总会在某个时刻和它打交道。把基础打牢,后续无论换什么数据集、什么框架,你都会轻松很多。这篇先到这里,下一篇我们直接上手训练。
本文还有配套的精品资源,点击获取