目录

Supervision:计算机视觉工具链的「瑞士军刀」

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类别 IDnp.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 半透明叠加、多行标签排版这些细节会逐渐堆积成样板代码。标注器把这些封装成可组合的调用,每个标注器只接收 scenedetections 两个核心参数。

区域计数与穿线计数

PolygonZoneLineZone 处理两类常见业务逻辑。

PolygonZone 回答"区域内有多少目标":给定多边形顶点,调用 trigger 后,zone.current_count 返回当前帧区域内的目标数量。目标框用哪个点判断(中心点、底部中心点)是可配置的,因为不同场景下"目标在区域内"的判定标准不同——行人用脚底位置,车辆用框中心。

LineZone 回答"有多少目标从左往右(或反方向)穿过了这条线":它维护 in_countout_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 后处理工具的对比

维度torchvisiondetectron2Supervision
定位通用视觉工具库端到端检测/分割框架模型无关的后处理工具库
模型输出处理各模型自带 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