Cityscapes数据集深度解析:从数据标注到模型训练的全流程指南

1次阅读
没有评论

共计 3490 个字符,预计需要花费 9 分钟才能阅读完成。

image.webp

Cityscapes 数据集深度解析

背景与痛点

Cityscapes 数据集是自动驾驶和计算机视觉领域的重要基准数据集,包含来自 50 个不同城市的街景图像,具有精细的像素级标注。该数据集在语义分割、实例分割等任务中被广泛使用,但许多开发者在实际使用过程中会遇到以下挑战:

Cityscapes 数据集深度解析:从数据标注到模型训练的全流程指南

  • 标注格式复杂,包含多种 ID 映射关系(labelIds、instanceIds 等)
  • 数据量大(5000 张精细标注图像 +20000 张粗略标注图像),导致加载效率问题
  • 标注类别多(30+ 类别),需要正确处理 ignoreInEval 类标签
  • 街景图像的特殊性(透视变形、光照变化等)对数据增强提出更高要求

数据格式解析

Cityscapes 数据集的主要目录结构如下:

cityscapes/
├── gtFine/
│   ├── train/
│   ├── val/
│   └── test/
├── leftImg8bit/
│   ├── train/
│   ├── val/
│   └── test/
├── gtCoarse/
│   ├── train/
│   ├── train_extra/
│   └── val/

关键标注文件说明:

  1. labelIds.png:每个像素值对应预定义的类别 ID
  2. instanceIds.png:每个对象实例有唯一 ID,同一类别的不同实例 ID 不同
  3. polygons.json:包含对象的多边形边界信息

标注 ID 与类别名称的映射关系可以通过官方提供的 cityscapesscripts 工具获取。

代码实现

1. 安装官方工具包

pip install cityscapesscripts

2. 标注可视化示例

from cityscapesscripts.helpers.labels import trainId2label
from cityscapesscripts.visualization.labels import label2rgb
import matplotlib.pyplot as plt
import numpy as np
from PIL import Image

# 加载标注图像
label_img = np.array(Image.open("gtFine/train/munich/munich_000000_000019_gtFine_labelIds.png"))

# 转换为彩色可视化
color_img = label2rgb(label_img)
plt.imshow(color_img)
plt.show()

3. PyTorch 自定义 Dataset 实现

import os
from PIL import Image
import torch
from torch.utils.data import Dataset

class CityscapesDataset(Dataset):
    def __init__(self, root_dir, split='train', transforms=None):
        self.root_dir = root_dir
        self.split = split
        self.transforms = transforms
        self.image_dir = os.path.join(root_dir, 'leftImg8bit', split)
        self.label_dir = os.path.join(root_dir, 'gtFine', split)

        # 收集所有图像文件
        self.image_files = []
        for city in os.listdir(self.image_dir):
            city_dir = os.path.join(self.image_dir, city)
            for file in os.listdir(city_dir):
                if file.endswith('_leftImg8bit.png'):
                    self.image_files.append(os.path.join(city, file))

    def __len__(self):
        return len(self.image_files)

    def __getitem__(self, idx):
        img_path = os.path.join(self.image_dir, self.image_files[idx])
        label_path = os.path.join(self.label_dir, 
                                 self.image_files[idx].replace('_leftImg8bit.png', 
                                 '_gtFine_labelIds.png'))

        image = Image.open(img_path).convert('RGB')
        label = Image.open(label_path)

        if self.transforms:
            image, label = self.transforms(image, label)

        return image, label

4. 数据增强策略

针对街景图像的特殊性,推荐以下增强组合:

import random
import torchvision.transforms.functional as F

class CityscapesTransform:
    def __init__(self, crop_size=(512, 1024), scale_range=(0.5, 2.0)):
        self.crop_size = crop_size
        self.scale_range = scale_range

    def __call__(self, image, label):
        # 随机缩放
        scale = random.uniform(*self.scale_range)
        new_size = (int(image.size[1]*scale), int(image.size[0]*scale))
        image = F.resize(image, new_size, Image.BILINEAR)
        label = F.resize(label, new_size, Image.NEAREST)

        # 随机裁剪
        i, j, h, w = transforms.RandomCrop.get_params(image, output_size=self.crop_size)
        image = F.crop(image, i, j, h, w)
        label = F.crop(label, i, j, h, w)

        # 颜色抖动(概率 50%)if random.random() > 0.5:
            image = F.adjust_brightness(image, random.uniform(0.8, 1.2))
            image = F.adjust_contrast(image, random.uniform(0.8, 1.2))
            image = F.adjust_saturation(image, random.uniform(0.8, 1.2))

        # 转换为 Tensor
        image = F.to_tensor(image)
        label = torch.from_numpy(np.array(label, dtype=np.uint8))

        return image, label

性能优化

处理大规模 Cityscapes 数据时,可以考虑以下优化策略:

  1. 使用 LMDB 加速 IO:将图像和标注转换为 LMDB 格式存储
  2. 多进程数据加载 :设置num_workers=4 或更高
  3. 预加载部分数据:对于小内存机器,可以预先加载文件列表和元数据
  4. 使用混合精度训练:减少显存占用

避坑指南

  1. 忽略 train_extra 子集:这是 20000 张粗略标注图像,可以显著增加训练数据量
  2. 错误处理 ignoreInEval 类标签:这些标签不应参与损失计算和评估
  3. 混淆 labelId 和 trainId:模型训练应使用 trainId(连续编号,便于交叉熵损失计算)
  4. 不匹配的图像分辨率:确保所有预处理保持原始宽高比(通常 1024×2048)
  5. 不当的数据增强:避免过度旋转 / 翻转导致不合理的街景视角

模型适配建议

语义分割任务(如 PSPNet)

  • 预处理:归一化到 [-1,1] 或[0,1]范围
  • 输出:使用 19 个可评估类别(对应 trainId)
  • 损失函数:加权交叉熵,考虑类别不平衡

实例分割任务(如 Mask R-CNN)

  • 预处理:保持原始分辨率获取更多细节
  • 标注转换:从 instanceIds.png 提取实例边界
  • 后处理:使用 NMS 去除重叠预测

开放性问题

  1. 如何设计更适合 Cityscapes 的评估指标?当前仅使用 mIoU 是否足够?
  2. 对于自动驾驶应用,如何处理动态物体(如行人、车辆)的时序信息?
  3. 如何有效利用粗略标注的 train_extra 数据提升模型性能?
  4. 针对不同天气 / 光照条件的街景图像,是否需要特殊的数据增强策略?

希望这篇指南能帮助你更好地使用 Cityscapes 数据集!如果遇到其他问题,欢迎在评论区讨论。

正文完
 0
评论(没有评论)