共计 3073 个字符,预计需要花费 8 分钟才能阅读完成。
Cityscapes 数据集特点解析
Cityscapes 是自动驾驶领域最具挑战性的街景理解数据集之一,包含 5000 张精细标注图像(2975 训练 /500 验证 /1525 测试)和 19998 张粗标注图像。其核心价值在于:

- 19 个语义类别:从平坦的 road 到复杂的 traffic sign,覆盖驾驶场景全部关键要素
- 2048×1024 高分辨率:保留真实场景的细节信息
- 3D 立体标注:除 2D 边界框外,还提供深度信息和三维立方体标注
对比其他主流数据集:
| 特性 | Cityscapes | KITTI | BDD100K |
|---|---|---|---|
| 图像数量 | 5k 精细 | 7.5k | 100k |
| 分辨率 | 2048×1024 | 1242×375 | 1280×720 |
| 标注类型 | 多边形 + 掩码 | 2D/3D 框 | 2D 框 + 分割 |
| 场景多样性 | 欧洲城市 | 德国郊区 | 美中多气候 |
| 动态物体占比 | 23% | 18% | 31% |
数据加载实战
JSON 标注解析
Cityscapes 使用 cityscapesscripts 官方工具包处理 JSON 标注。以下是带异常处理的解析示例:
import json
from pathlib import Path
def parse_annotations(json_path):
try:
with open(json_path) as f:
data = json.load(f)
objects = []
for obj in data['objects']:
# 处理多边形标注
if obj['label'] not in IGNORE_LABELS: # 忽略 'group' 等特殊标签
polygon = np.array(obj['polygon']).reshape(-1, 2)
objects.append({'label': obj['label'],
'bbox': [polygon[:,0].min(), polygon[:,1].min(), # x1,y1
polygon[:,0].max(), polygon[:,1].max()], # x2,y2
'polygon': polygon
})
return objects
except (json.JSONDecodeError, KeyError) as e:
print(f"Error parsing {json_path}: {str(e)}")
return []
内存优化 DataLoader
处理高分辨率图像时建议采用两种策略:
- 智能分块加载:
class CityscapesDataset(torch.utils.data.Dataset):
def __init__(self, root, split='train', crop_size=512):
self.crop_size = crop_size
self.images = sorted(Path(root)/split/images/*.png)
def __getitem__(self, idx):
img = Image.open(self.images[idx])
w, h = img.size
# 随机裁剪 + 缩放
i = random.randint(0, h - self.crop_size)
j = random.randint(0, w - self.crop_size)
img = TF.crop(img, i, j, self.crop_size, self.crop_size)
# 使用 GPU 加速的 Albumentations
transform = A.Compose([A.HorizontalFlip(p=0.5),
A.ColorJitter(brightness=0.2, contrast=0.2, p=0.3),
ToTensorV2()], bbox_params=A.BboxParams(format='pascal_voc'))
return transform(image=np.array(img))
- 混合精度训练:
scaler = torch.cuda.amp.GradScaler() with torch.cuda.amp.autocast(): outputs = model(inputs) loss = criterion(outputs, targets) scaler.scale(loss).backward() scaler.step(optimizer) scaler.update()
模型训练关键技巧
类别不平衡解决方案
Cityscapes 中 person 类比 truck 多 30 倍,推荐组合策略:
-
样本加权:
class_weights = 1 / torch.log(freq + 1e-6) # 在损失函数中应用 criterion = nn.CrossEntropyLoss(weight=class_weights.to(device)) -
定制数据增强:
def rare_class_augmentation(img, masks): if random.random() < 0.7 and 'motorcycle' in masks: # 对稀有类别进行复制粘贴增强 motorcycle = masks['motorcycle'] x_offset = random.randint(0, img.width//3) img.paste(motorcycle, (x_offset, 0), motorcycle) return img
标注格式转换
多边形与掩码互转是实际训练中的高频操作:
from shapely.geometry import Polygon
def poly2mask(polygon, shape):
"""将多边形转换为二值掩码"""
img = Image.new('L', shape, 0)
ImageDraw.Draw(img).polygon(polygon.flatten().tolist(), outline=1, fill=1)
return np.array(img)
def mask2poly(mask, epsilon=1.0):
"""掩码转多边形(OpenCV 实现)"""
contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_TC89_KCOS)
polygons = []
for cnt in contours:
polygons.append(cv2.approxPolyDP(cnt, epsilon, True).squeeze())
return polygons
避坑指南
- group 标签处理:
- 同一 group ID 的多个实例(如相邻车辆)应作为整体处理
-
在计算 mAP 时需特殊处理 group 内的 IoU 计算
-
验证集防泄漏:
- 使用官方提供的 predefined_val.txt 划分
- 禁止对验证集进行任何数据增强(除归一化外)
-
帧序列数据需确保前后帧不会同时出现在训练 / 验证集
-
多 GPU 训练优化:
train_sampler = torch.utils.data.distributed.DistributedSampler( dataset, num_replicas=world_size, rank=rank, shuffle=True )
延伸思考
- 如何处理公交车上临时张贴的广告这类动态物体标注?
- 当标注多边形存在自相交时应该怎样规范化处理?
- 怎样利用 Cityscapes 的立体标注提升纯视觉检测器的深度估计能力?
推荐工具链:
– 官方标注工具:https://github.com/mcordts/cityscapesScripts
– 格式转换脚本:https://github.com/waspinator/pycococreator
– 可视化工具:CVAT (Computer Vision Annotation Tool)
正文完
