
supervision 中 DetectionsSmoother 深度解析基于滑动窗口实现跨帧检测框平滑【免费下载链接】supervisionWe write your reusable computer vision tools. 项目地址: https://gitcode.com/GitHub_Trending/su/supervisionDetectionsSmoother是 supervisionRoboflow 开源的计算机视觉后处理工具库口号为 We write your reusable computer vision tools提供的检测平滑工具位于检测工具集sv.detection.tools中。它针对视频追踪场景下目标检测框逐帧抖动的问题为每个追踪目标维护一段固定长度的历史窗口并对窗口内的坐标做均值平滑从而让标注框、下游统计结果更加稳定。读完本文你将掌握它的完整 API、逐帧更新与轨道管理的工作机制、置信度与旋转框OBB的特殊处理规则以及如何把它接入 Ultralytics / RF-DETR 等检测 追踪流水线。工具定位平滑解决什么问题在视频目标检测中即使模型输出稳定检测框的坐标也会因每帧预测误差而轻微跳动若再叠加遮挡、短暂漏检再重现等情况视觉上的抖动会更明显。DetectionsSmoother的思路是不再单独信任当前帧的检测框而是取该追踪目标track最近length帧检测框的均值作为平滑后的输出。类定义见 DetectionsSmoother并通过包级入口导出可直接以sv.DetectionsSmoother使用见 supervision 包初始化文件from supervision.detection.tools.smoother import DetectionsSmoother及__all__中的DetectionsSmoother条目。官方文档页入口为 docs/detection/tools/smoother.md追踪流程的完整用法可在 追踪目标指南 的 Bonus: Smoothing 一节中看到。官方文档给出了三条必须注意的前提约束必须提供tracker_id平滑以追踪 ID 为单位组织历史没有追踪 ID 就无法区分同一个目标在不同帧的检测。若检测到tracker_id is Noneupdate_with_detections会发出SupervisionWarnings警告并原样返回输入跳过平滑源码 smoother.py 第 148–155 行。不兼容分割模型该类只处理xyxy框以及可选的旋转框角点不适用于 mask 类输出。置信度不一致时的降级规则当同一帧中部分追踪携带置信度、部分不携带时该帧所有平滑检测的confidence会被统一置为None以避免合并时的字段冲突源码 smoother.py 第 244–249 行。快速上手最小示例与数值验证官方文档附带的交互式示例doctest是理解其数学行为的最快方式用length3创建一个 smoother送入两个带tracker_id的检测观察平滑结果。import numpy as np import supervision as sv smoother sv.Detectionssmoother if False else sv.DetectionsSmoother(length3) detections_1 sv.Detections( xyxynp.array([[0, 0, 10, 10]]), confidencenp.array([0.5]), tracker_idnp.array([1]), ) detections_2 sv.Detections( xyxynp.array([[2, 2, 12, 12]]), confidencenp.array([0.7]), tracker_idnp.array([1]), ) smoothed smoother.update_with_detections(detections_1) print(smoothed.xyxy) # array([[ 0., 0., 10., 10.]]) —— 窗口内只有 1 帧即原框 smoothed smoother.update_with_detections(detections_2) print(smoothed.xyxy) # array([[ 1., 1., 11., 11.]]) —— 两帧坐标的均值 print(smoothed.confidence) # array([0.6]) —— 两帧置信度的均值可以看到两点规律框坐标是窗口内所有有效帧xyxy的逐元素均值第一帧输出等于自身第二帧是两帧均值(02)/2, (02)/2, (1012)/2, (1012)/2。置信度同样在窗口内取均值但只统计携带置信度的帧若整个窗口都没有置信度则保持None。完整流水线接入检测 追踪官方文档给出的标准用法是检测模型 → 追踪器 → smoother → 标注器四级流水线以下示例基于 RF-DETR 与内置 ByteTrackimport supervision as sv from rfdetr import RFDETRMedium video_info sv.VideoInfo.from_video_path(video_pathSOURCE_FILE_PATH) frame_generator sv.get_video_frames_generator(source_pathSOURCE_FILE_PATH) model RFDETRMedium() tracker sv.ByteTrack(frame_ratevideo_info.fps) smoother sv.DetectionsSmoother() box_annotator sv.BoxAnnotator() with sv.VideoSink(TARGET_FILE_PATH, video_infovideo_info) as sink: for frame in frame_generator: detections model.predict(frame[:, :, ::-1]) detections tracker.update_with_detections(detections) # 先分配 tracker_id detections smoother.update_with_detections(detections) # 再做平滑 annotated_frame box_annotator.annotate(frame.copy(), detections) sink.write_frame(annotated_frame)顺序很关键必须先过追踪器拿到tracker_id再送入 smoother。同样的模式也出现在关键点追踪场景见 docs/how_to/track_objects.md 中 Ultralytics / Inference 两套示例均为tracker.update_with_detections(...)之后紧跟smoother.update_with_detections(...)再交给BoxAnnotator与TraceAnnotator画框和轨迹。一个需要留意的版本信息示例中使用的内置sv.ByteTrack自 supervision-0.28.0 起标记为弃用并计划在 0.31.0 移除建议改用trackers包的ByteTrackTracker且更新方法由update_with_detections()改名为update()说明见 ByteTrack 类文档。本文示例忠实保留当前文档给出的写法若你使用 0.28.0 之后的版本建议将追踪器替换为外部实现其余平滑代码不变。API 详解__init__(length: int 5)唯一构造参数length参与平滑的最大帧数即每个追踪历史的滑动窗口长度默认 5。从源码看length通过defaultdict(lambda: deque(maxlenlength))落实为每个追踪 ID 一条独立、有上限的deque队列见 smoother.py 第 103–111 行。因此length越大平滑越强、输出滞后越大框对目标真实位置的反应越慢length越小如 1–2输出越贴近原始检测但抖动抑制有限每个轨道的历史相互独立窗口满后最早帧自动滑出不占用额外内存。update_with_detections(detections) - Detections核心更新入口每处理一帧调用一次。它在 smoother.py 第 140–174 行的实现分四步前置校验detections.tracker_id is None时发出SupervisionWarnings警告并原样返回输入写入历史逐条检测取出tracker_id用detections.select(detection_idx)复制出单目标Detections后追加进该轨道的队列select保证每帧历史都是独立副本见 Detections.select缺席补记对本帧未出现的历史轨道追加一个None占位若某轨道整个窗口全是None长时间未再出现则从缓存中删除该轨道防止内存无限增长输出调用get_smoothed_detections(track_ids当前帧活跃轨道)只输出本帧活跃轨道的平滑结果——缺席轨道保留历史但不输出幽灵框。其中第 3 步的活跃 ID 判断使用集合成员检查而非逐轨道扫描这是仓库变更日志中记录的一次性能优化无输出变化。get_track(track_id) - Detections | None返回单个轨道的平滑Detections规则源码第 176–226 行取窗口内所有非None帧对xyxy逐元素求均值confidence仅在携带它的帧上求均值全部缺失时为None其余字段如class_id取自窗口中最早的有效帧轨道未知或整窗为空时返回None。get_smoothed_detections(track_idsNone) - Detections将多条轨道的平滑结果用Detections.merge合并为一个对象见 Detections.merge。两个细节值得注意track_ids用于过滤本帧活跃轨道缺席轨道的历史仍保留在缓存中只是不参与本次输出若任一轨道的confidence为None则全部平滑检测的confidence统一置None——这是为了规避Detections.merge对可选字段全有或全无的合并约束源码第 244–249 行的注释明确说明了这一点结果为空时会补一个tracker_idnp.array([], dtypeint)保证返回对象字段完整。reset()清空所有轨道的历史但保留配置的length让同一个实例可以复用于不同视频流而不携带上一流的残帧。变更日志显示该方法是近期为与TraceAnnotator、HeatMapAnnotator保持接口一致而补充的。深入实现置信度、缺席轨道与旋转框缺席与重现历史不丢输出不撒谎测试 tests/detection/tools/test_smoother.py 的test_smoother_reappearing_track_keeps_history验证了这一行为第 1 帧有检测、第 2 帧空轨道缺席、第 3 帧目标重新出现。期望结果是——第 2 帧平滑输出长度为 0不输出幽灵框而第 3 帧输出的坐标[1, 1, 11, 11]与置信度0.6是跨越缺席帧、对第 1 帧与第 3 帧历史求均值得到的。这说明None占位只用于淘汰整窗空轨道并不打断平滑连续性对短暂漏检后重现的目标尤其友好。test_smoother_does_not_emit_missing_tracks则从另一角度断言了缺席不输出这一点。置信度的三种窗口情形test_smoother_confidence_scenarios用参数化用例覆盖了三种情形窗口内置信度分布平滑结果两帧均有0.5、0.7均值 0.6两帧均无None混合0.5、无仅对存在的帧取均值得 0.5test_smoother_window_full_averages_all_frames进一步验证满窗length3坐标 0/3/6、置信度 0.3/0.6/0.9时是对全部 3 帧而非最近 2 帧求平均输出恰为中间帧的坐标[3, 3, 13, 13]与置信度0.6——这正是均值平滑 移动平均滤波的直观体现。旋转框OBB的平滑仓库较新的一个能力是当Detections.data中带有旋转框角点ORIENTED_BOX_COORDINATES时smoother 会把角点与轴对齐框一起平滑保证两者描述同一位置。实现要点仅当窗口内所有有效帧都携带形状一致的角点时才平滑角点否则丢弃该字段、回退为普通xyxy平滑test_mixed_oriented_box_metadata_is_dropped验证混合窗口不残留陈旧 OBB 数据求均值前先做角点对齐不同帧的角点起点与绕行方向可能不同_align_oriented_cornerssmoother.py 第 13–25 行通过枚举 4 个循环移位 × 2 个方向正序/逆序共 8 种候选选取与参考帧欧氏距离最小的对齐方式test_corner_order_is_aligned_before_averaging专门验证了循环移位等价角点不会把正方形搅成交叉形平滑角点算出后xyxy由角点包络xyxyxyxy_to_xyxy重新派生保证两者严格一致test_corners_agree_with_the_smoothed_box、test_rotated_rectangle_keeps_xyxy_and_obb_envelopes_consistent。测试类注释说明这修复的问题此前其余字段都拷贝自窗口最早帧导致角点与平滑后的轴对齐框位置互相矛盾普通轴对齐检测不受影响不会凭空多出 OBB 键test_detections_without_oriented_boxes_are_unaffected。重置语义test_reset_clears_track_history验证reset()之后输出不再受旧框污染新轨道首帧输出即原始框test_reset_preserves_window_length验证重置后新轨道的deque.maxlen仍等于构造时的length2即重置只清数据、不清配置。实践建议与适用边界综合源码与测试使用DetectionsSmoother时的几点建议length与帧率的换算默认 5 帧在 30 fps 视频中约覆盖 1/6 秒的历史。目标运动越快越应减小length以免标注框拖在目标后面目标基本静止如固定设备计数时则可适当加大。追踪器是前置依赖没有稳定tracker_id时平滑无从谈起建议先调好追踪器参数如激活阈值、丢失缓冲帧数再叠加平滑。注意输出滞后均值平滑本质上引入滞后若下游需要当前时刻的精确位置如测速应评估滞后带来的偏差或缩短窗口。不适用场景分割 mask 输出官方明确不兼容、以及需要逐帧实时响应的低延迟场景。多路复用同一实例复用于不同流前调用reset()避免上一流的轨迹污染新一流的平滑结果。DetectionsSmoother以极小的 API 面构造、逐帧更新、按轨查询、重置实现了滑窗均值 缺席容忍 字段一致性三件事是 supervision 检测工具集中用于压制视频标注抖动的标准组件其每帧 O(n_tracks) 的更新开销主要来自活跃 ID 的集合判断与各轨道一次窗口均值窗口长度length又通常很小因此叠加进检测管线的成本可以忽略。参考路径文档入口docs/detection/tools/smoother.md核心实现src/supervision/detection/tools/smoother.py单元测试含置信度、缺席轨道、重置、旋转框各场景tests/detection/tools/test_smoother.py追踪 平滑的完整用法docs/how_to/track_objects.md合并/选取等基础Detections方法src/supervision/detection/core.py【免费下载链接】supervisionWe write your reusable computer vision tools. 项目地址: https://gitcode.com/GitHub_Trending/su/supervision创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考