在图像上为每个目标绘制精确的轮廓,做到"像素级"的形状标注。是医学影像、自动驾驶可行驶区域、卫星遥感等高精度场景的核心——比检测框精确 10 倍,但标注成本也高得多。
沿目标轮廓描点形成多边形,或直接对每个像素涂色,精确标注目标形状的边界
医学影像(肿瘤/器官)、自动驾驶(车道/路沿)、卫星遥感(建筑/农田)、AR 背景抠图等
★★★★★ 最高级,每个目标 10-50 个点,耗时约为检测框的 5-10 倍
按类别给每个像素涂色——同类目标不区分个体。例如所有"道路"都是蓝色,所有"建筑"都是红色,不论有几条路几栋楼。
不仅要分出类别,还要区分同类目标的不同个体——每个人、每辆车都有自己独立的 Mask。
语义 + 实例的合体——图像中每个像素都有标签:可数目标(人/车)分实例,不可数目标(天空/道路)分语义,一张图全标注。
确定要分割哪些类别、每个类别的轮廓精度,产出 seg_guide.md。
分割标注对工具要求高——必须支持多边形描点、笔刷涂色、SAM 辅助
分割标注最大的效率提升来自 SAM——从描 50 个点变成点 1-3 下
分割标注的数据量远大于检测——每个目标是一组轮廓点或一个 Mask 图像
| 工具 | 类型 | 费用 | 分割标注 | 亮点 |
|---|---|---|---|---|
| Labelme ▼ | 桌面 GUI | 免费 | ✅ 强 | 多边形描点,轻量单机 |
| CVAT ▼ | Web 服务 | 免费 | ✅ 极强 | 内置 SAM2,分割标注效率 10x |
| Label Studio ▼ | Web 服务 | 免费 | ✅ 强 | 笔刷+多边形,SAM backend 可接 |
| ITK-SNAP ▼ | 桌面 GUI | 免费 | ✅ 专用 | 医学影像 3D 分割首选 |
# === 1. 目录结构(语义分割 PNG Mask 格式) === dataset/ ├── images/ │ ├── train/ # 0001.jpg, 0002.jpg ... │ └── val/ ├── masks/ # 与 images 同名,但 PNG,像素=class_id │ ├── train/ # 0001.png, 0002.png ... │ └── val/ └── config.yaml # === 2. 多边形 JSON → PNG Mask 转换 === import json, glob, os import cv2, numpy as np # 类别映射:label_name → class_id CLASS_MAP = {'road': 1, 'building': 2, 'sky': 3} for json_path in glob.glob("labels/*.json"): data = json.load(open(json_path)) h, w = data['imageHeight'], data['imageWidth'] mask = np.zeros((h, w), dtype=np.uint8) # 0=背景 for shape in data['shapes']: cls_id = CLASS_MAP[shape['label']] points = np.array(shape['points'], dtype=np.int32) cv2.fillPoly(mask, [points], cls_id) # 填充多边形 out_name = os.path.basename(json_path).replace('.json', '.png') cv2.imwrite(f"masks/train/{out_name}", mask) # === 3. 检查 Mask 质量 === from collections import Counter mask = cv2.imread("masks/train/0001.png", cv2.IMREAD_GRAYSCALE) print("各类像素数:", dict(Counter(mask.flatten()))) # {0: 150000, 1: 80000, 2: 50000, 3: 30000} ← 背景 150k 最多 # === 4. 训练 U-Net(segmentation_models_pytorch) === import torch from torch.utils.data import DataLoader import segmentation_models_pytorch as smp model = smp.Unet( encoder_name="resnet34", encoder_weights="imagenet", in_channels=3, classes=4 # 背景+road+building+sky ) # 损失函数:Dice Loss(分割专用,解决类别不平衡) loss_fn = smp.losses.DiceLoss(mode='multiclass') optimizer = torch.optim.AdamW(model.parameters(), lr=1e-4) # 训练循环... for epoch in range(100): for imgs, masks in train_loader: preds = model(imgs) loss = loss_fn(preds, masks) optimizer.zero_grad(); loss.backward(); optimizer.step() print(f"Epoch {epoch}, Loss: {loss:.4f}") # 训练完 → model 为分割模型,输入图片输出每像素类别