supervision 中边界框坐标工具详解:boxes 模块六大核心函数的原理、参数与实战
2026/9/7 2:30:16 网站建设 项目流程

supervision 中边界框坐标工具详解:boxes 模块六大核心函数的原理、参数与实战

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

supervision 的detection/utils/boxes模块提供了一组基于 NumPy 的边界框坐标变换工具,覆盖平移、缩放、裁剪、填充、反归一化和旋转框转换六类基本操作。本文围绕官方文档页 Boxes Utils 所列的六个公开函数逐一展开,结合 src/supervision/detection/utils/boxes.py 的源码实现与 tests/detection/utils/test_boxes.py 的测试用例,讲清每个函数的参数约定、边界行为和库内部的实际调用位置,帮助你在后处理检测结果时做出准确的坐标变换。

boxes 模块的定位与公开 API

boxes模块位于 src/supervision/detection/utils/boxes.py,是 supervision 中所有"对框坐标做几何变换"逻辑的汇聚点。从包入口 src/supervision/init.py 可以看到,共有六个函数被提升到顶层命名空间,可通过import supervision as sv直接调用:

公开函数输入形状输出形状核心用途
sv.move_boxes(N, 4)(N, 4)按像素偏移平移所有框
sv.scale_boxes(N, 4)(N, 4)以框中心为基准按比例缩放
sv.clip_boxes(N, 4)(N, 4)将坐标裁剪到帧分辨率[0, width] × [0, height]
sv.pad_boxes(N, 4)(N, 4)向外扩展固定像素的填充
sv.denormalize_boxes(N, 4)(N, 4)归一化坐标还原为绝对像素坐标
sv.xyxyxyxy_to_xyxy(N, 4, 2)(N, 4)旋转框四角点转轴对齐外接框

除这六个公开函数外,模块内还定义了若干内部函数(如move_oriented_boxesspread_out_boxesobb_polygon_area_oriented_box_anchors),它们不通过顶层 API 导出,但被库的其他子系统直接引用,本文最后会统一说明。

move_boxes:按像素偏移平移边界框

move_boxes将一组(x1, y1, x2, y2)格式的框整体平移[dx, dy],源码见 boxes.py 的 move_boxes。

import numpy as np import supervision as sv xyxy = np.array([ [10, 10, 20, 20], [30, 30, 40, 40] ]) offset = np.array([5, 5]) print(sv.move_boxes(xyxy=xyxy, offset=offset)) # array([[15, 15, 25, 25], # [35, 35, 45, 45]])

参数说明:

  • xyxy:形状(N, 4)的数组,每行是一个[x_min, y_min, x_max, y_max]框;
  • offset:形状(2,)的整数数组[dx, dy],负值合法,表示向左/上移动。

从源码结构看,实现只有一行:xyxy + np.hstack([offset, offset])(boxes.py#L200)。offset被复制拼成[dx, dy, dx, dy]后做广播加法,因此左上角和右下角坐标平移相同的量,框的宽高保持不变。tests/detection/utils/test_boxes.py 的 test_move_boxes 覆盖了空数组、零偏移、多框和负偏移四类场景。

库内调用位置:分块推理工具InferenceSlicer在把检测框从"分块局部坐标"搬回"原图全局坐标"时,正是调用本函数。见 src/supervision/detection/tools/inference_slicer.py:move_boxes负责平移轴对齐框,配套的内部函数move_oriented_boxes则平移xyxyxyxy形状(N, 4, 2)的旋转框四个角点(实现为xyxyxyxy + offset的广播加法,见 boxes.py#L203-L249),保证同一次分块平移中两类坐标同步移动。

scale_boxes:以框中心为基准的等比缩放

scale_boxes将每个框的宽和高按factor倍缩放,且缩放以框中心为不动点,源码见 boxes.py 的 scale_boxes。

xyxy = np.array([ [10, 10, 20, 20], [30, 30, 40, 40] ]) print(sv.scale_boxes(xyxy=xyxy, factor=1.5)) # array([[ 7.5, 7.5, 22.5, 22.5], # [27.5, 27.5, 42.5, 42.5]])

参数说明:

  • xyxy:形状(N, 4),格式[x1, y1, x2, y2]
  • factor:缩放倍数。factor > 1放大,factor < 1缩小,factor = 1.0原样返回。

从源码实现看(boxes.py#L457-L459),算法分三步:先求中心centers = (xyxy[:, :2] + xyxy[:, 2:]) / 2,再算新尺寸new_sizes = (xyxy[:, 2:] - xyxy[:, :2]) * factor,最后以中心向两侧各展开new_sizes / 2得到新坐标。也就是说缩放不会改变框的中心位置,这与"从左上角扩张"的直觉不同。tests/detection/utils/test_boxes.py 的 test_scale_boxes 验证了factor=2.0[0,0,10,10]变成[-5,-5,15,15]——中心(5,5)不变,宽高翻倍。

典型用法是给检测框加"外扩余量"以缓解小目标框贴边问题;若只需要整数像素的固定外扩,则应选用下一节的pad_boxes

clip_boxes:把坐标裁剪到帧分辨率内

clip_boxes将所有坐标钳制到[0, width] × [0, height]范围内,源码见 boxes.py 的 clip_boxes。

xyxy = np.array([ [10, 20, 300, 200], [15, 25, 350, 450], [-10, -20, 30, 40] ]) print(sv.clip_boxes(xyxy=xyxy, resolution_wh=(320, 240))) # array([[ 10, 20, 300, 200], # [ 15, 25, 320, 240], # [ 0, 0, 30, 40]])

参数说明:

  • xyxy:形状(N, 4),每行一个(x_min, y_min, x_max, y_max)框;
  • resolution_wh(width, height)元组,即目标帧的分辨率。注意顺序是宽在前、高在后,与 NumPy 图像shape(height, width)顺序相反,传参时容易出错。

从源码实现看(boxes.py#L49-L53),函数先np.copy再对列[0, 2](x 坐标)clip(0, width)、对列[1, 3](y 坐标)clip(0, height)。两个实现细节值得注意:

  1. 函数不会修改输入数组,总是返回新数组;
  2. 裁剪是逐坐标钳制,不保证x_max > x_min。如果原框整体在画面左侧外(如[-10, -20, -5, 40]),裁剪后x1 = x2 = 0,产生退化框。

tests/detection/utils/test_boxes.py 的 test_clip_boxes 参数化了空数组、恰好贴边、负坐标、超宽/超高坐标等六种边界输入。库内调用位置annotators模块中多个标注器在绘制前都会先裁剪坐标,例如BlurAnnotator在 src/supervision/annotators/core.py 中对detections.xyxy执行clip_boxes(...).astype(int),随后跳过x2 <= x1 or y2 <= y1的退化框再取 ROI——这正是上面第 2 条注意事项的实际处理方式。

pad_boxes:固定像素的外扩填充

pad_boxes向每个框的四边外扩固定像素数,源码见 boxes.py 的 pad_boxes。

xyxy = np.array([ [10, 20, 30, 40], [15, 25, 35, 45] ]) print(sv.pad_boxes(xyxy=xyxy, px=5, py=10)) # array([[ 5, 10, 35, 50], # [10, 15, 40, 55]])

参数说明:

  • xyxy:形状(N, 4),格式(x_min, y_min, x_max, y_max)
  • px:左右两侧各扩展的像素数;
  • py:上下两侧各扩展的像素数,可选;缺省时回退为py = px(boxes.py#L93-L94),实现各向同性填充。

px允许传负值,此时函数等效于向内收缩,这一约定在内部代码中有实际使用:关键点标注器在 src/supervision/key_points/annotators.py 中先用pad_boxes(xyxy=xyxy, px=self.text_padding)扩大框以容纳文字,渲染完成后又用pad_boxes(..., px=-self.text_padding)精确还原。tests/detection/utils/test_boxes.py 的 test_pad_boxes 覆盖了单框各向同性、单框不对称、多框与空数组场景。

pad_boxesscale_boxes的选型关系:需要"边距加 N 像素"用pad_boxes;需要"尺寸乘以 k 倍"用scale_boxes

denormalize_boxes:归一化坐标还原为绝对像素坐标

denormalize_boxes将归一化框坐标映射到指定分辨率的绝对像素坐标,源码见 boxes.py 的 denormalize_boxes。

xyxy = np.array([ [0.1, 0.2, 0.5, 0.6], [0.3, 0.4, 0.7, 0.8], [0.2, 0.1, 0.6, 0.5] ]) print(sv.denormalize_boxes(xyxy, (1280, 720))) # array([[128., 144., 640., 432.], # [384., 288., 896., 576.], # [256., 72., 768., 360.]])

参数说明:

  • xyxy:形状(N, 4)归一化框坐标,取值范围为[0, normalization_factor],每行(x_min, y_min, x_max, y_max)
  • resolution_wh:目标图像分辨率(width, height)
  • normalization_factor:输入坐标的最大值,默认1.0。当模型输出不是[0,1]而是如[0,1024]的量化坐标时,需显式传入,例如sv.denormalize_boxes(xyxy, (1280, 720), normalization_factor=1024.0)(见 boxes.py 的第二个文档示例)。

实现上(boxes.py#L159-L169),函数构造缩放向量[width, height, width, height] / normalization_factor后与输入逐元素相乘,即x方向乘width/factory方向乘height/factor。两个值得注意的行为:

  1. dtype 保留策略:浮点输入保留原 dtype(如 float32 输入返回 float32),整数输入则提升为 float64,以免把小数像素坐标静默截断。这一契约由 test_denormalize_boxes_returns_expected_dtype 专门守护,其中"整数输入不得截断小数坐标"也是 test_denormalize_boxes 的一条回归用例;
  2. 弃用提醒:函数通过@deprecated装饰器声明参数重映射——旧参数名normalized_xyxy自 0.27.0 起更名为xyxy,计划在 0.31.0 移除(boxes.py#L103-L108)。调用时请直接使用xyxy关键字参数。

库内调用位置:视觉语言模型(VLM)推理模块 src/supervision/detection/vlm.py 在把模型返回的归一化框还原为像素坐标时多处调用本函数(如 vlm.py#L716、vlm.py#L810),是 VLM 检测管线中坐标还原的标准入口。

xyxyxyxy_to_xyxy:旋转框角点转轴对齐外接框

xyxyxyxy_to_xyxy将旋转框(OBB)的四个角点转换为其轴对齐外接框(AABB),源码见 boxes.py 的 xyxyxyxy_to_xyxy。

corners = np.array([ [[0, 0], [10, 0], [10, 5], [0, 5]], [[5, 5], [15, 5], [15, 10], [5, 10]], ], dtype=np.float32) print(sv.xyxyxyxy_to_xyxy(corners)) # array([[ 0., 0., 10., 5.], # [ 5., 5., 15., 10.]], dtype=float32)

参数说明:

  • xyxyxyxy:形状(N, 4, 2)的 OBB 角点坐标,每个框表示为[[x1,y1], [x2,y2], [x3,y3], [x4,y4]]
  • 返回值:形状(N, 4)(x_min, y_min, x_max, y_max)数组,保留输入 dtype(float32 输入返回 float32)。

从源码实现看(boxes.py#L331-L335),算法即对四个角点分别取min/maxnp.stackx_min = xyxyxyxy[..., 0].min(axis=-1),以此类推。对未旋转的矩形,结果与角点本身一致;对旋转矩形,结果是一个面积更大的外接框。形状校验不通过时会抛出ValueError。test_xyxyxyxy_to_xyxy 用"旋转 45° 的菱形"用例验证了外接框的正确性:菱形[[5,0],[10,5],[5,10],[0,5]]的外接框为[0, 0, 10, 10]

库内调用位置:平滑滤波器DetectionsSmoother在对旋转框角点做时序平滑后,用本函数重新导出detections.xyxy,见 src/supervision/detection/tools/smoother.py;Detections核心类合并 OBB 检测结果时同样调用它(src/supervision/detection/core.py)。

内部函数速览:模块中的其余工具

除文档页列出的六个公开函数外,boxes模块还有三个被库内部子系统依赖的工具函数,了解它们有助于理解模块全貌:

  • spread_out_boxes(xyxy, max_iterations=100)(boxes.py#L462-L531):将相互重叠的框按迭代式"排斥力"推开——每轮用box_iou_batch计算 N×N 的 IoU 矩阵,为每个框合成方向向量(远离所有与之重叠的框)与力度向量(IoU 之和放大 10 倍并限制在 ±2 像素内),直至全部 IoU 为零或达到最大迭代次数。LabelAnnotator等标注器用它避免标签互相压叠(src/supervision/annotators/core.py、src/supervision/key_points/annotators.py);
  • obb_polygon_area(corners)(boxes.py#L252-L295):用鞋带公式(shoelace formula)批量计算 OBB 面积。实现上先把每个框平移到以其首角点为原点的局部坐标系再做叉积运算,避免大地坐标(如地理空间或拼接大图)下大数坐标的浮点舍入误差;tests/detection/utils/test_boxes.py 中的回归测试 验证了原点位于10**10处时面积仍精确为 5000。该函数被几何分发器 src/supervision/detection/_geometry_dispatch.py 引用;
  • _oriented_box_anchors(xyxyxyxy, anchor)(boxes.py#L353-L424):在旋转框本体上定位九宫格锚点(角点映射到角点、边锚点映射到边中点),用于让标签、关键点在旋转框上"贴住"目标本体。源码注释明确了一个边界条件:当旋转角度超过arctan(w/h)时,"宽度边"的判定会翻转,BOTTOM_CENTER等锚点位置会出现约|w - h|像素的跳变,属已知的外观性现象。test_oriented_box_anchors_are_rotation_covariant 验证了锚点随框旋转的协变性质。

组合使用模式与小结

六个公开函数在典型检测管线中往往成对出现,以下是从库内部代码归纳的组合模式:

  1. 归一化 → 像素 → 裁剪:VLM 或归一化模型输出 →denormalize_boxes还原像素坐标 →clip_boxes钳制到帧内 → 交给标注器渲染。库内标注器渲染前几乎都会先做一次clip_boxes(见 src/supervision/annotators/core.py);
  2. 分块推理 → 平移回全局InferenceSlicer分块预测后,用move_boxes/move_oriented_boxes把每块结果平移回原图坐标(src/supervision/detection/tools/inference_slicer.py);
  3. 外扩与还原pad_boxes加正余量做文字区/检测余量,负值精确还原(src/supervision/key_points/annotators.py);
  4. 旋转框 ↔ 轴对齐框xyxyxyxy_to_xyxy在 OBB 平滑、合并等流程中导出 AABB 表示(src/supervision/detection/tools/smoother.py)。

需要牢记的参数约定:resolution_wh一律是(width, height)而非(height, width)scale_boxes以框中心为不动点;clip_boxes不修改输入且不保证裁剪后框非退化,渲染前建议按库内标注器的做法过滤x2 <= x1 or y2 <= y1的框。所有函数均为纯 NumPy 向量化实现,可直接作用于整批(N, 4)数组,适合作为检测结果后处理的基础构件。

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

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

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

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

立即咨询