Supervision:计算机视觉工具链的「瑞士军刀」
posts posts 2026-05-14T20:33:15+08:00Supervision 是 Roboflow 推出的模块化计算机视觉 Python 工具库,提供从数据加载、检测框处理到区域统计的全流程工具,支持 Ultralytics、Transformers、MMDetection 等主流模型,目标让开发者专注业务而非底层工程。技术笔记计算机视觉, Python, 目标检测, Roboflow, 开源工具Supervision:计算机视觉工具链的「瑞士军刀」
Supervision(roboflow/supervision)解决的是计算机视觉工程里一个具体而反复出现的痛点:模型推理已经跑通,但不同模型的输出格式各不相同,后续的过滤、标注、计数、追踪、数据集转换全部要针对每种模型重写一遍。它用 sv.Detections 这个统一数据结构承接 Ultralytics、Transformers、MMDetection、Detectron2、Roboflow Inference、rfdetr 等来源的推理结果,把模型输出到业务逻辑之间的胶水代码收敛到一处。最新版本 0.28.0(2026 年 4 月),Python >= 3.9,MIT 协议。
视觉技术栈中的定位
视觉应用大致分四层:数据层(图片、视频、标注文件)、模型层(YOLO、DETR、SAM、Grounding DINO 等)、后处理与应用逻辑层(结果转换、过滤、可视化、追踪、区域计数、数据集转换、指标评估)、业务系统层(交通分析、工业质检、机器人、安防)。Supervision 位于第三层,向下适配各种模型输出格式,向上给业务系统提供稳定的中间表示。
模型库关心"推理结果是什么",Supervision 关心"拿到结果之后怎么办"。Ultralytics 返回 Results 对象,Transformers 返回张量和字典,SAM 返回 mask,rfdetr 返回 sv.Detections。一个项目里如果同时接入多个模型,业务代码很快会被各种私有输出格式绑死。Supervision 的做法是先把不同来源转换成统一的 sv.Detections,下游的标注、过滤、统计、评估只围绕这个对象写。
sv.Detections:统一中间表示
sv.Detections 是整个库的基础数据结构,承载检测和分割结果:
| 字段 | 含义 | 类型 |
|---|---|---|
xyxy | 目标框坐标,左上右下 | np.ndarray[N, 4] |
confidence | 置信度 | np.ndarray[N] |
class_id | 类别 ID | np.ndarray[N] |
tracker_id | 追踪 ID(可选) | np.ndarray[N] |
mask | 实例分割掩码(可选) | np.ndarray[N, H, W] |
data | 扩展字段(类别名、自定义属性、VLM 解析结果) | dict |
转换接口按模型来源命名,调用一次即可:
import supervision as sv
# Ultralytics YOLO
detections = sv.Detections.from_ultralytics(result)
# Hugging Face Transformers
detections = sv.Detections.from_transformers(result)
# Roboflow Inference
detections = sv.Detections.from_inference(result)
# Detectron2
detections = sv.Detections.from_detectron2(result)
# MMDetection
detections = sv.Detections.from_mmdetection(result)rfdetr 比较特殊,它的 predict 方法直接返回 sv.Detections,不需要转换:
from rfdetr import RFDETRSmall
from PIL import Image
model = RFDETRSmall()
image = Image.open("input.jpg")
detections = model.predict(image, threshold=0.5)
len(detections)
# 5转换之后,过滤操作用 NumPy 布尔索引完成,和操作数组没有区别:
# 按置信度过滤
detections = detections[detections.confidence > 0.5]
# 按类别过滤(假设类别 0 是人)
person_detections = detections[detections.class_id == 0]这个设计的关键在于:下游代码(标注器、区域计数、追踪器)只认 sv.Detections,不关心数据来自哪个模型。从 YOLO 切到 Transformers 或 Detectron2,只要转换接口存在,下游逻辑不必推倒重写。
一次完整的检测-标注-计数流程
以视频中的车辆区域计数为例,展示任务如何流过 Supervision 的各个组件:
import cv2
import supervision as sv
from ultralytics import YOLO
model = YOLO("yolo11n.pt")
box_annotator = sv.BoxAnnotator()
label_annotator = sv.LabelAnnotator()
# 定义多边形计数区域
zone = sv.PolygonZone(
polygon=[[0, 400], [1280, 400], [1280, 720], [0, 720]],
)
def callback(frame: cv2.Mat, frame_index: int) -> cv2.Mat:
# 1. 模型推理
result = model(frame)[0]
# 2. 转换为统一结构
detections = sv.Detections.from_ultralytics(result)
# 3. 区域内过滤
zone.trigger(detections=detections)
# 4. 标注
annotated = box_annotator.annotate(scene=frame.copy(), detections=detections)
annotated = label_annotator.annotate(scene=annotated, detections=detections)
return annotated
sv.process_video(
source_path="input.mp4",
target_path="output.mp4",
callback=callback,
)数据流是:模型输出 → sv.Detections 转换 → 区域过滤 → 标注器叠加 → 写出新视频。每一步都只处理 sv.Detections,模型可以随时替换。
Annotator 体系
标注器是 Supervision 里数量最多的一组组件,每个负责一种可视化元素:
| 标注器 | 绘制内容 |
|---|---|
BoxAnnotator | 检测框 |
LabelAnnotator | 类别标签和置信度 |
MaskAnnotator | 分割掩码(半透明覆盖) |
TraceAnnotator | 目标追踪轨迹(保留最近 N 帧) |
PolygonZoneAnnotator | 多边形区域边界和计数 |
LineZoneAnnotator | 穿线计数线和方向箭头 |
RoundBoxAnnotator | 圆角检测框 |
KeyPointAnnotator | 关键点(姿态估计) |
CornerAnnotator | 检测框角点 |
标注器的意义不只是"画得好看"。误检、漏检、追踪 ID 跳变、区域判断错误,这些问题只有画出来才容易定位。手写 OpenCV 绘图代码时,标签超出画面边界、同类目标同色、不同 tracker_id 配色、mask 半透明叠加、多行标签排版这些细节会逐渐堆积成样板代码。标注器把这些封装成可组合的调用,每个标注器只接收 scene 和 detections 两个核心参数。
区域计数与穿线计数
PolygonZone 和 LineZone 处理两类常见业务逻辑。
PolygonZone 回答"区域内有多少目标":给定多边形顶点,调用 trigger 后,zone.current_count 返回当前帧区域内的目标数量。目标框用哪个点判断(中心点、底部中心点)是可配置的,因为不同场景下"目标在区域内"的判定标准不同——行人用脚底位置,车辆用框中心。
LineZone 回答"有多少目标从左往右(或反方向)穿过了这条线":它维护 in_count 和 out_count 两个计数器。穿线计数本身的边界问题不少:目标在边界上抖动导致反复跨线、目标框中心点判定不准、遮挡后重新出现 ID 跳变。Supervision 把这些封装在 LineZone 内部,调用方要做的是定义线和方向。
目标追踪与版本变化
检测告诉你"这一帧有多少辆车",追踪告诉你"这辆车是不是刚才那辆"。只有有了稳定的 tracker_id,才能做穿线计数、区域停留、轨迹分析和速度估计。
Supervision 0.28.0 起追踪接口有重要变化:sv.ByteTrack 标记为 deprecated,计划在 0.30.0 移除。新代码应使用独立的 trackers 包,接口形如 ByteTrackTracker。从旧教程复制代码时要注意这一点,避免引入即将废弃的 API。
InferenceSlicer:大图切片推理
工业质检、遥感、航拍、医学影像中,4K 或 8K 图片里的小目标直接缩放到模型输入尺寸会丢失。常见做法是把大图切成多个重叠 patch,分别推理,再把结果合并回原图坐标系。这种 tiled inference 的工程量不小:切片重叠率、边界目标去重、坐标变换、batch 推理。
sv.InferenceSlicer 把这套流程封装成一个可调用对象,传入推理函数即可:
slicer = sv.InferenceSlicer(min_overlap=0.1)
detections = slicer(image=lambda: image, callback=model.predict)小目标检测不只是模型能力问题,输入策略同样关键。
数据集加载与格式转换
sv.DetectionDataset 支持 COCO、YOLO、Pascal VOC 三种格式的加载、保存和互转:
# 从 YOLO 格式加载
dataset = sv.DetectionDataset.from_yolo(
images_directory_path="data/images",
annotations_directory_path="data/labels",
data_yaml_path="data/data.yaml",
)
# 转换为 COCO 格式保存
dataset.as_coco(
images_directory_path="output/images",
annotations_path="output/annotations.json",
)
# 数据集划分
train_ds, test_ds = dataset.split(split_ratio=0.7)
test_ds, valid_ds = test_ds.split(split_ratio=0.5)
# 多个数据集合并
merged = sv.DetectionDataset.merge([ds_1, ds_2])合并时类别名会自动去重和统一索引。数据集对象支持按索引访问,图像按需加载,不会一次性读入内存。
与 torchvision / detectron2 后处理工具的对比
| 维度 | torchvision | detectron2 | Supervision |
|---|---|---|---|
| 定位 | 通用视觉工具库 | 端到端检测/分割框架 | 模型无关的后处理工具库 |
| 模型输出处理 | 各模型自带 Result 结构,需手动提取 | 绑定 detectron2 自己的 Instances | 统一 sv.Detections,适配多来源 |
| 可视化 | torchvision.utils.draw_bounding_boxes 等基础函数 | DefaultPredictor + Visualizer,绑定 detectron2 格式 | 独立 Annotator 体系,可组合 |
| 区域计数 | 无内置 | 无内置 | PolygonZone / LineZone |
| 追踪 | 无内置 | 无内置 | trackers 包(ByteTrack 等) |
| 数据集格式 | 需自定义 | 绑定 detectron2 注册表 | COCO / YOLO / VOC 互转 |
| 模型耦合 | 低,但需手写适配 | 高,与 detectron2 训练流程绑定 | 零,不参与训练 |
torchvision 提供的是基础积木(NMS、draw_bounding_boxes),需要自己组装成完整流程。detectron2 的后处理和可视化绑定它自己的 Instances 结构,换模型就要换处理代码。Supervision 的差异在于模型无关——它不训练模型,不定义模型结构,只处理"模型输出之后"的事情。
Roboflow 生态协作
Supervision 是 Roboflow 工具链的一环,和几个项目形成上下游配合:
- Autodistill:自动标注。用大模型(如 Grounding DINO、SAM)给未标注数据生成初始标签,输出可直接用 Supervision 加载的格式。
- Inference:推理服务器。提供 HTTP API 和 Python SDK,
sv.Detections.from_inference()直接承接其输出。部署时 Inference 负责模型服务和硬件加速,Supervision 负责后处理。 - Maestro:多模态提示管理,和 Supervision 的 VLM 解析器配合。
这条链路覆盖"标注 → 训练 → 推理 → 后处理"的本地化工作流。Supervision 本身不依赖 Roboflow 平台,可以独立使用,但接入生态后能减少格式转换的摩擦。
性能边界
Supervision 是纯 Python 库,数据结构基于 NumPy。它的性能边界由几个因素决定:
sv.Detections的字段是 NumPy 数组,过滤和索引操作是向量化的,单帧检测结果的过滤开销可忽略。- 视频处理的瓶颈在模型推理,不在 Supervision 的标注和计数。
process_video逐帧调用 callback,帧间没有并行。 InferenceSlicer会成倍增加推理次数(取决于切片数量),适合离线分析,实时场景要评估吞吐量。- 追踪器的状态维护在内存中,长视频下
TraceAnnotator保留的轨迹历史会占用内存,trace_history参数控制保留帧数。
对于实时性要求高的场景(>30 FPS),Supervision 的后处理开销通常不是瓶颈,模型推理才是。但如果单帧检测目标数量极大(数千个框),标注器的绘制开销会上升,这时可以先用 sv.Detections 过滤再标注。
采用建议
Supervision 适合的团队:已经跑通模型推理,需要在业务系统中集成视觉能力,不想把后处理代码绑死在某个模型的私有输出格式上。尤其是需要视频分析、区域计数、目标追踪的项目,Supervision 能省去大量重复工程。
不适合的场景:需要端到端训练流程(Supervision 不训练模型)、对后处理有极低延迟要求且目标数量极大(纯 Python 绘制可能成为瓶颈)、模型来源单一且不会变化(直接用模型库自带的后处理更轻量)。
采用顺序上,先从 sv.Detections 的转换接口开始,把现有模型输出统一进来;再按需引入 Annotator 做可视化调试;区域计数和追踪等业务逻辑组件按场景逐步加入。如果项目里已经在用 Roboflow Inference 做推理服务,Supervision 是自然的后处理搭档。注意 0.28.0 起追踪接口的变化,新代码直接用 trackers 包,避免复制旧教程里的 sv.ByteTrack。