语义分割:边界能不能用
mIoU 高不代表边界够抓、小物体 recall 够;部署要看 boundary IoU、稀有类 recall 和 downstream 碰撞 margin。

1. mIoU 高,避障仍撞
室外导航语义分割 mask 平均 IoU 0.82,RViz 叠加看着干净。真机却在 curb 边缘反复触发急停,细杆在 stride-8 输出上只剩两三个像素——大类(路面、天空、建筑)把 mIoU 抬上去,决策用的边界几何却不可靠。上次底盘联调,我们花了一下午调膨胀半径,最后发现根因是分割边界系统性内缩十五厘米,不是导航参数问题。机器人要的不是像素准确率,是「这条边能不能信、漏检会不会致命」。评测若只报一个 mIoU 数字,现场工程师会被 dashboard 误导。
2. 指标:别只看一个 average
mIoU 是类平均交并比,路面、天空等大类像素占绝对多数,会把整体分数抬上去,稀有类(行人、锥桶、路缘、细杆)全漏也可能显示「良好」。Boundary IoU 在边界带(通常两到三像素宽)内单独算交并比,与抓取安全裕度、避障膨胀高度直接相关,是比 mIoU 更诚实的部署指标。小物体 recall 统计面积低于阈值的实例召回率——stride 十六的输出上采样后,细结构常在此段全漏。per-class IoU 表格必看;大类零点九、稀有类零点三的组合在报表上仍可能绿色。部署前把 mask 叠加原图做实例级肉眼审查,比数字诚实。
3. OpenCV 部署链路
深度学习模型导出 ONNX 后,cv2.dnn 是常见落地路径。关键是张量布局与预处理契约必须和训练一致:
net = cv2.dnn.readNet('seg.onnx')
blob = cv2.dnn.blobFromImage(
img, scalefactor=1/255.0, size=(512, 512),
mean=(0, 0, 0), swapRB=True)
net.setInput(blob)
out = net.forward()[0] # 通道×高×宽 或 高×宽×通道,看导出 layout
mask = out.argmax(axis=0).astype(np.uint8)
mask = cv2.resize(mask, (w, h), interpolation=cv2.INTER_NEAREST)INTER_NEAREST 保 label 不被双线性插值混成伪类——边界毛刺的常见根因。cv2.connectedComponentsWithStats 可滤小连通域,是廉价的部署后处理。传统交互分割 cv2.watershed、cv2.grabCut 在标注稀缺、样本少的小场景仍是 baseline,不必被「必须深度学习」绑架。
4. 输出步长与上采样陷阱
stride 八或十六的输出上采样到原图,细杆可能只剩几个像素,mIoU 仍高因为背景像素占绝对多数。训练侧加权交叉熵或 focal loss 缓解类不均衡;部署侧 resize 策略必须一致——训练用五百一十二输入、部署用全高清,若 letterbox 与 stretch 不一致,mIoU 和边界都会漂。颜色空间转换、均值方差归一化、蓝绿红通道顺序必须与训练一致;室内训练、室外测试的指标下跌常是光照与类分布偏移,不是后处理能救。
5. 与 downstream 的契约
避障要对 obstacle mask 做 cv2.dilate 膨胀若干像素,测碰撞率与最坏情况片段;抓取要 boundary error 对真实物体边缘(毫米级)。分割输出是下游模块的行为接口——mask 偏五个像素,膨胀十个像素可能刚好 cover,也可能在窄道漏检。延迟加 mask 帧率与 mIoU 一起报;只报 mIoU 的评测是自欺欺人。我会把膨胀半径、最小连通域面积、输入分辨率写进部署配置,启动时断言与标定分辨率一致。
6. 域差与失败模式
室内训、室外测,指标跌常是光照和类分布偏移。逆光、雨夜、强背光是必测 slice,不能只在晴天停车场验收集。常见失败:边界毛刺(双线性上采样)、小目标消失(步长或训练采样)、夜间崩溃(训练域无夜间样本)、逆光误分(曝光域偏移)。
| 现象 | 根因 |
|---|---|
| 边界毛刺 | 双线性上采样 |
| 小目标消失 | 步长 / 训练采样 |
| 夜间崩 | 训练域无 night |
| 逆光误分 | 曝光域偏移 |
7. 验收
分场景 per-class IoU 加 boundary IoU;小物体 recall(面积低于阈值);downstream 碰撞率(膨胀后);延迟加 mask 帧率与精度一起报。分割指标是像素游戏的平均;机器人要的是空间决策够不够安全。mIoU 高不代表边界够抓——验收必须落到下游可观察行为,而不是实验室数字。
8. 案例:膨胀半径救不了内缩边界
某次室外测试,膨胀半径从五个像素加到二十个,碰撞率略降但窄道仍漏检细杆。回看分割 overlay,边界系统性内缩八厘米,膨胀只是在错误边界外多包一圈。换 boundary IoU 作部署门槛、加小物体 recall 后,才定位到 stride 八上采样是根因。指标对齐任务,比调下游参数有效。
相关
也可以看看
johan's blog