Supervision 关键点标注器全解析:Vertex、Edge 与 Ellipse 系列 Annotators 使用指南
2026/9/8 20:24:34 网站建设 项目流程

Supervision 关键点标注器全解析:Vertex、Edge 与 Ellipse 系列 Annotators 使用指南

【免费下载链接】supervisionWe write your reusable computer vision tools. 💜项目地址: https://gitcode.com/GitHub_Trending/su/supervision

导读

本篇文章基于 Supervision 官方文档 keypoint/annotators.md 编写,围绕人体姿态、手部骨骼与面部关键点可视化这一主题,系统讲解六个骨骼关键点标注器:VertexAnnotatorEdgeAnnotatorVertexLabelAnnotatorVertexEllipseAreaAnnotatorVertexEllipseOutlineAnnotatorVertexEllipseHaloAnnotator。读完本篇,你将掌握如何用统一的sv.KeyPoints数据结构驱动不同风格的关键点渲染,学会用源码级参数(颜色、半径、线宽、sigma 椭圆层级、透明度、防重叠标签等)快速产出可直接用于质检与展示的标注画面。

前置准备:一个可以被标注的KeyPoints

在 Supervision 中,关键点标注器的输入统一是sv.KeyPoints对象。它把来自不同框架的姿态/关键点结果标准化为一致的字段:

  • xy:形状(n, m, 2)的坐标数组,n为检测到的目标数,m为每个目标的特征点数;
  • class_id:形状(n,)的目标类别 ID,可为None
  • keypoint_confidence:形状(n, m)的逐点置信度;
  • visible:形状(n, m)的可选布尔矩阵,标记哪些关键点是可见的,None时全部视为可见(core.py 的字段定义见该文件 docstring);
  • data:附加数据的字典,与关键点对齐。

你可以通过不同模型的适配器生成KeyPoints:如KeyPoints.from_ultralytics()(接收 YOLO pose 结果)、KeyPoints.from_mediapipe()KeyPoints.from_inference()KeyPoints.from_transformers()KeyPoints.from_detectron2()KeyPoints.from_yolo_nas(),详见 keypoint/core.md 与 core.py。

生成之后,即可像官方文档示例那样,把坐标交给任意标注器:

import supervision as sv image = ... # 读取一帧画面,numpy.ndarray 或 PIL.Image 均可 key_points = sv.KeyPoints(...) # 来自任意模型适配器

接下来按能力分三组介绍六个标注器。

六个标注器速览

标注器作用核心参数(构造函数默认值见源码 annotators.py)
VertexAnnotator在每个关键点画实心圆color=Color.ROBOFLOWradius=4
EdgeAnnotator在关键点之间连线形成骨架color=Color.ROBOFLOWthickness=2edges=None
VertexLabelAnnotator为每个关键点绘制带背景的文字标签color=Color.ROBOFLOWtext_color=Color.WHITEtext_scale=0.5text_thickness=1text_padding=10border_radius=0smart_position=False
VertexEllipseAreaAnnotator基于协方差绘制多层级半透明填充椭圆sigma=(1.0, 2.0, 3.0)color=(GREEN, YELLOW, RED)opacity=0.4max_axis=None
VertexEllipseOutlineAnnotator基于协方差绘制多层级空心椭圆环同上,另有thickness=2
VertexEllipseHaloAnnotator基于协方差绘制径向渐变发光椭圆同 Area,opacity=0.6,内部_DECAY=2.0

需要留意的是:官方文档示例中的数值(如radius=10thickness=5)属于演示取值,构造函数在源码中的默认值如上表所示,实际使用时两套值都合法。

VertexAnnotator:标注关键点顶点

VertexAnnotator负责把每个关键点画成实心圆(即骨骼的“顶点/关节点”)。

import supervision as sv image = ... key_points = sv.KeyPoints(...) vertex_annotator = sv.VertexAnnotator( color=sv.Color.GREEN, radius=10, ) annotated_frame = vertex_annotator.annotate( scene=image.copy(), key_points=key_points, )

源码层面的执行规则(annotators.py 中VertexAnnotator.annotate):

  • 遍历key_points.xy,对每个目标内的每个点调用cv2.circle画实心圆,thickness=-1表示填充;
  • 坐标为(0, 0)的占位点会被跳过;
  • key_points.visible存在且对应位置为False时,该点被跳过(visible is None时不做过滤,全部绘制);
  • key_points为空时直接返回原始scene,不会报错。

因此visible与“坐标零值”共同决定了哪些顶点会被画出,这对存在遮挡、模型输出置信度低的关键点尤为重要。

EdgeAnnotator:连接关键点绘制骨架边

EdgeAnnotator把关键点两两连线,得到完整的骨架结构:

import supervision as sv image = ... key_points = sv.KeyPoints(...) edge_annotator = sv.EdgeAnnotator( color=sv.Color.GREEN, thickness=5, ) annotated_frame = edge_annotator.annotate( scene=image.copy(), key_points=key_points, )

edges参数有三种传法(源码中EdgeAnnotator.__init__annotate的处理逻辑):

  1. edges=None(默认)自动检测骨架:根据每个目标的关键点数量,在skeletons.py定义的SKELETONS_BY_VERTEX_COUNT字典中查找预设骨架。该字典由内建Skeleton枚举(COCOHANDGHUMFACEMESH_TESSELATION_NO_IRIS等多个标准骨架)按去重后的顶点数自动索引构建(skeletons.py)。若按顶点数查不到匹配,会打印警告并跳过该目标。
  2. Sequence[tuple[int, int]](单骨架):对所有目标实例应用同一组边,例如edges=[(1, 2), (1, 3)]表示把 1 号点分别连向 2、3 号点。
  3. dict[int, Sequence[tuple[int, int]]](按类别多骨架):以class_id为键、各自映射一组边,适合“同一批检测里混有多种骨架类型”的数据集,例如edges={0: [(1, 2), (1, 3)], 1: [(1, 2)]}

关于边索引的 1-based 约定:公共 API 中的边索引采用1-based编号(从 1 到m),内部会通过_validate_edge_indices校验范围并转换为 0-based 下标后再访问xy数组(见源码annotators.py)。若索引越界(超出[1, m])会抛出ValueError

绘制时若边两端任一坐标为零值,或任一端点被visible标记为不可见,则该边被跳过(源码annotate逻辑)。完整的多骨架用例可见源码 docstring 中的示例代码。

VertexLabelAnnotator:给关键点挂上文字标签

当需要直接读出“哪个点是什么关节”时,使用VertexLabelAnnotator在每个关键点旁绘制带圆角背景的文字框:

import supervision as sv image = ... key_points = sv.KeyPoints(...) vertex_label_annotator = sv.VertexLabelAnnotator( color=sv.Color.GREEN, text_color=sv.Color.BLACK, border_radius=5, ) annotated_frame = vertex_label_annotator.annotate( scene=image.copy(), key_points=key_points, )

annotate()labels参数同样支持三种形态(源码annotate/_resolve_labels):

  • None:默认以关键点的下标"0"、"1"、...作为标签;
  • list[str]:长度必须等于关键点数量,作用于每个实例,如labels=["head", "L-foot", "R-foot"]
  • dict[int, list[str]]:按class_id给不同骨架类型配置各自的标签列表。

颜色参数colortext_color既可以是单个Color,也可以是按关键点逐个配置的Color列表(长度需与点数一致,否则抛ValueError)。

细节特性(源码层面):

  • border_radius:背景圆角半径,设成较大值可把背景渲染成圆形;
  • smart_position=True:利用pad_boxes先扩张每个标签框,再交给spread_out_boxes把重叠标签“摊开”,最后再内缩回原尺寸,从而避免标签互相遮挡(相关工具函数来自 detection/utils/boxes.py);
  • 标签框居中于关键点:先用cv2.getTextSize测量文字尺寸得到文本包围盒,再以其中心对齐关键点坐标,背景矩形通过draw_rounded_rectangle绘制;
  • 与顶点标注一致:visibleFalse的点、或visibleNone时坐标为(0,0)的点会被跳过。

椭圆家族:把不确定度可视化出来

VertexEllipseAreaAnnotatorVertexEllipseOutlineAnnotatorVertexEllipseHaloAnnotator三个标注器用于不确定性/概率分布的可视化:它们不依赖模型输出的固定坐标,而是依据每个关键点的 2×2 协方差矩阵,画出与置信区间对应的椭圆。

数据要求:key_points.data["covariance"]

三个椭圆标注器共用一个私有基类_BaseVertexEllipseAnnotator,并依赖key_points.data中键为"covariance"的数据,其形状必须为(N, K, 2, 2)N目标数、K每目标关键点数),矩阵以像素坐标表示。缺少该字段或形状不匹配时,_get_covariances会抛出ValueError。官方文档与本源码 docstring 均给出构造示例:

key_points = sv.KeyPoints( xy=..., class_id=..., data={ "covariance": np.array( [[[[800, 0], [0, 400]], # 第 1 个关键点的 2x2 协方差 [[400, 0], [0, 800]], # 第 2 个关键点 [[600, 0], [0, 600]]]], # 第 3 个关键点 dtype=np.float32, ) }, )

sigma、color 与 max_axis 的语义

三个椭圆标注器共享sigmacolormax_axis三个参数(_BaseVertexEllipseAnnotator.__init__):

  • sigma:每个椭圆环的倍率,可传单个浮点数或浮点序列,默认(1.0, 2.0, 3.0)。内部会把 sigma 按降序排列,因此绘制顺序是“最外圈先画、最内圈最后画”。
  • color:每个 sigma 层级对应的颜色,可传单个Color或颜色序列,默认(Color.GREEN, Color.YELLOW, Color.RED);颜色数量必须与 sigma 数量一致,否则抛ValueError
  • max_axis:椭圆半轴长度的像素上限(可选)。约束在max_axis非空时必须为正。

绘制几何的底层逻辑(源码_iter_ellipse_params):

  1. 对每个可见、非零坐标的关键点取出其 2×2 协方差矩阵;
  2. np.linalg.eigh做特征分解,得到特征值与特征向量,按特征值降序排列(第一主轴方向对应最大方差方向,椭圆倾角即由该特征向量经arctan2换算为角度);
  3. 每个 sigma 层级的椭圆半轴长度为sigma * sqrt(特征值),中心落在关键点坐标上;
  4. 协方差含非有限值或特征值非正的矩阵会被安全跳过,不做绘制。

Area / Outline / Halo 三者的差异

VertexEllipseAreaAnnotator —— 半透明实心填充

area_annotator = sv.VertexEllipseAreaAnnotator( color=sv.Color.GREEN, sigma=2.0, )

将所有椭圆先在 overlay 副本上用cv2.ellipsethickness=-1、抗锯齿LINE_AA)填充,再通过cv2.addWeighted(overlay, opacity, scene, 1 - opacity, 0)融合回原图,opacity默认 0.4。多层同心圆叠加后呈现“靶心”效果:内圈颜色代表更高的概率密度。

VertexEllipseOutlineAnnotator —— 空心描边环

outline_annotator = sv.VertexEllipseOutlineAnnotator( color=sv.Color.GREEN, sigma=2.0, thickness=2, )

只画椭圆轮廓(cv2.ellipse使用给定的thickness),不做任何透明融合,适合需要清晰边界、不遮挡底层图像内容的场景。

VertexEllipseHaloAnnotator —— 径向渐变的辉光

halo_annotator = sv.VertexEllipseHaloAnnotator( color=sv.Color.GREEN, sigma=2.0, )

不依赖 cv2.ellipse,而是对每个椭圆外接矩形 ROI 内的像素逐点计算归一化距离dist_sq,内部像素的透明度按(1 - dist_sq) ** decay衰减(_DECAY = 2.0的幂曲线),峰值透明度取opacity(默认 0.6),从而得到“中心最亮、边界渐隐”的柔光效果。

兼容别名:VertexEllipseAnnotator

官方文档特别注明:sv.VertexEllipseAnnotatorsv.VertexEllipseAreaAnnotator兼容别名。这一点在源码中由模块级赋值VertexEllipseAnnotator = VertexEllipseAreaAnnotator直接落实(annotators.py),并且顶层包supervision同时导出了这两个名字(见init.py)。迁移/升级时代码若使用旧名仍能正常工作。

源码级共通细节与注意事项

  1. 场景类型自适应:所有标注器的annotate(scene, key_points)都通过@ensure_cv2_image_for_class_method装饰器包装(来自 utils/conversion.py),因此scene同时接受numpy.ndarrayPIL.Image.Image,返回值与输入类型一致;若传入其他类型则抛出TypeError。文档示例统一用image.copy()传入,避免在原始帧上原地修改。

  2. 统一基类与返回约定:六个标注器(除VertexLabelAnnotator单独定义外)都继承自抽象基类BaseKeyPointAnnotator,接口完全一致,便于在视频处理管线里互相替换;空KeyPoints一律原样返回scene,不会中断逐帧处理流程。

  3. 可见性过滤语义:顶点、边、标签三类标注都尊重visible掩码;椭圆族还会额外跳过协方差矩阵异常的点。若想把低置信度关键点“不删除、只不画”,可参考KeyPoints.visible的文档建议:key_points.visible = key_points.keypoint_confidence > 0.3(core.py)。

  4. 模块路径与兼容性:核心实现位于supervision.key_points.annotatorssupervision.key_points.core(单复数形式为key_points)。仓库中旧命名空间的 keypoint/init.py 会在导入时发出弃用警告,提示从0.27.0起改用supervision.key_points,请在新代码中统一使用后者。对应测试覆盖见 tests/key_points。

结语

从画点(VertexAnnotator)、连线(EdgeAnnotator)、打标签(VertexLabelAnnotator),到把预测不确定度可视化为多层椭圆(VertexEllipseArea/Outline/HaloAnnotator),Supervision 的关键点标注器家族覆盖了姿态、手部与面部等主流应用的全部基础渲染需求。实际使用时只需遵循三条规则:先用统一适配器得到sv.KeyPoints,再按需在data中提供协方差数据(椭圆族),最后选择标注器并合理设置visible掩码即可获得干净、专业且利于排查的可视化结果。

【免费下载链接】supervisionWe write your reusable computer vision tools. 💜项目地址: https://gitcode.com/GitHub_Trending/su/supervision

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询