十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

YOLOv10 多目标追踪注册机制源码解析:`trackers/track.py` 中的回调管线与追踪器初始化

YOLOv10 多目标追踪注册机制源码解析:`trackers/track.py` 中的回调管线与追踪器初始化 YOLOv10 多目标追踪注册机制源码解析trackers/track.py中的回调管线与追踪器初始化【免费下载链接】yolov10YOLOv10: Real-Time End-to-End Object Detection [NeurIPS 2024]项目地址: https://gitcode.com/GitHub_Trending/yo/yolov10本篇文章聚焦 YOLOv10 仓库中多目标追踪的核心接线模块 ultralytics/trackers/track.py深入拆解on_predict_start、on_predict_postprocess_end与register_tracker三个函数如何把 ByteTrack / BoT-SORT 追踪器无缝接入预测流水线。读完本文你将掌握追踪器何时被创建、检测结果如何被追踪结果替换、追踪 ID 如何跨帧保持以及如何通过配置文件自定义追踪行为。一、模块定位追踪功能在预测流水线中的接线层在 YOLOv10 中多目标追踪MOT并非独立于推理之外的另一套流程而是以回调callback方式挂载在标准预测管线之上。track.py就是这一接线层的实现它不自己实现卡尔曼滤波或数据关联而是负责在合适的时机创建 ByteTrack / BoT-SORT 实例、把每帧检测结果喂给追踪器、再把带 ID 的追踪结果写回Results对象。从源码结构看追踪链路涉及以下文件ultralytics/trackers/track.py回调定义与追踪器注册本文主角ultralytics/trackers/byte_tracker.pyBYTETracker与STrack实现ultralytics/trackers/bot_sort.pyBOTSORT与BOTrack实现ultralytics/trackers/init.py对外导出register_trackerultralytics/cfg/trackers/botsort.yaml 与 ultralytics/cfg/trackers/bytetrack.yaml追踪器参数配置track.py只暴露 3 个公开函数模块结构非常精简函数职责on_predict_start(predictor, persist)预测开始前初始化追踪器实例on_predict_postprocess_end(predictor, persist)每帧后处理结束后执行追踪更新register_tracker(model, persist)把前两个函数注册为模型回调二、TRACKER_MAP追踪器类型注册表track.py顶部定义了一张将配置名映射到追踪器类的字典from .bot_sort import BOTSORT from .byte_tracker import BYTETracker # A mapping of tracker types to corresponding tracker classes TRACKER_MAP {bytetrack: BYTETracker, botsort: BOTSORT}这张表决定了tracker_type配置项可用的取值范围。从 ultralytics/trackers/byte_tracker.py 与 ultralytics/trackers/bot_sort.py 的类定义可以看到两者差异BYTETracker基于卡尔曼滤波KalmanFilterXYAH即中心点 x/y 宽高比 高度的两阶段关联算法通过track_high_thresh/track_low_thresh区分高、低置信度检测框低置信度框用于二次关联找回遮挡目标BOTSORT继承自BYTETracker的扩展版本改用KalmanFilterXYWH额外引入 GMCGlobal Motion Compensation全局运动补偿默认sparseOptFlow与可选的 ReID 外观特征with_reid在相机运动场景下更鲁棒。__init__.py中还对外导出了BOTSORT与BYTETracker允许开发者直接 import 这两个追踪器类做更底层的调用。三、on_predict_start预测开始时初始化追踪器def on_predict_start(predictor: object, persist: bool False) - None: if hasattr(predictor, trackers) and persist: return tracker check_yaml(predictor.args.tracker) cfg IterableSimpleNamespace(**yaml_load(tracker)) if cfg.tracker_type not in [bytetrack, botsort]: raise AssertionError(fOnly bytetrack and botsort are supported for now, but got {cfg.tracker_type}) trackers [] for _ in range(predictor.dataset.bs): tracker TRACKER_MAPcfg.tracker_type trackers.append(tracker) if predictor.dataset.mode ! stream: # only need one tracker for other modes. break predictor.trackers trackers predictor.vid_path [None] * predictor.dataset.bs # for determining when to reset tracker on new video该函数执行三个关键动作幂等检查若persistTrue且 predictor 已有trackers属性直接返回避免重复创建追踪器配置装载通过check_yaml解析predictor.args.tracker默认botsort.yaml见 ultralytics/cfg/default.yaml再经yaml_load载入并用IterableSimpleNamespace包装使cfg.tracker_type等字段可以点号访问。如果tracker_type不是bytetrack或botsort会抛出AssertionError按 batch 大小创建追踪器for _ in range(predictor.dataset.bs)循环按批次大小实例化追踪器frame_rate固定传 30。stream 模式的特殊处理是这里的重点——只有在流式输入dataset.mode stream下才为 batch 中每个视频各建一个追踪器其余模式只创建 1 个。初始化完成后函数还在 predictor 上挂载vid_path [None] * bs用于后续判断是否切换到了新视频文件从而决定何时重置追踪器状态。四、on_predict_postprocess_end每帧后处理结束时的追踪更新def on_predict_postprocess_end(predictor: object, persist: bool False) - None: path, im0s predictor.batch[:2] is_obb predictor.args.task obb is_stream predictor.dataset.mode stream for i in range(len(im0s)): tracker predictor.trackers[i if is_stream else 0] vid_path predictor.save_dir / Path(path[i]).name if not persist and predictor.vid_path[i if is_stream else 0] ! vid_path: tracker.reset() predictor.vid_path[i if is_stream else 0] vid_path det (predictor.results[i].obb if is_obb else predictor.results[i].boxes).cpu().numpy() if len(det) 0: continue tracks tracker.update(det, im0s[i]) if len(tracks) 0: continue idx tracks[:, -1].astype(int) predictor.results[i] predictor.results[i][idx] update_args dict() update_args[obb if is_obb else boxes] torch.as_tensor(tracks[:, :-1]) predictor.results[i].update(**update_args)这是追踪管线的核心数据通路逻辑可拆解为五步视频切换重置vid_path用于检测当前帧是否属于新视频。当persistFalse且视频路径发生变化时调用tracker.reset()清空上一视频的追踪状态reset()方法在 ultralytics/trackers/byte_tracker.py 中定义会重置tracked_stracks、lost_stracks、frame_id与卡尔曼滤波器提取检测结果根据任务类型obb或普通检测取出results[i].obb或results[i].boxes转为 NumPy 数组。这意味着追踪不仅支持 detect 任务也支持旋转框 OBB 任务调用追踪器tracker.update(det, im0s[i])把原始图像与检测框交给 ByteTrack / BoT-SORT内部完成卡尔曼预测、IoU 关联、轨迹状态迁移返回形如[x1, y1, x2, y2, id, conf, cls, idx]OBB 场景为[x, y, w, h, angle, id, conf, cls, idx]的轨迹数组按追踪索引重排结果tracks[:, -1]是检测索引predictor.results[i][idx]把原始检测结果按被追踪保留的检测框重新索引保证后续可视化时框与轨迹一一对应写回追踪坐标去掉索引列后把带 ID 的轨迹通过results.update(...)定义于 ultralytics/engine/results.py替换原有 boxes/OBB 数据。之后用户即可通过results[i].boxes.id读取每个目标的追踪 ID。五、register_tracker回调注册的入口def register_tracker(model: object, persist: bool) - None: model.add_callback(on_predict_start, partial(on_predict_start, persistpersist)) model.add_callback(on_predict_postprocess_end, partial(on_predict_postprocess_end, persistpersist))函数本身极简但意义重大它用functools.partial把persist参数固化进两个回调函数再注册到模型的两个预测阶段钩子上。实际触发点在 ultralytics/engine/predictor.py第 237 行self.run_callbacks(on_predict_start)—— 数据遍历开始前执行第 256 行self.run_callbacks(on_predict_postprocess_end)—— 每帧postprocess完成之后执行。因此整个追踪生命周期可以概括为model.track(source, persist...) └─ model.track() 首次调用时检测到 predictor 无 trackers └─ register_tracker(self, persist) 注册两个回调 └─ predictor 进入预测循环 ├─ on_predict_start → 解析 tracker yaml实例化追踪器 └─ 每帧: inference → postprocess └─ on_predict_postprocess_end → tracker.update() → 写回结果六、persist参数与model.track()的关联persist是理解追踪行为的关键开关它有两个作用点在on_predict_start中避免重复初始化hasattr(predictor, trackers) and persist在on_predict_postprocess_end中决定是否在新视频上重置追踪器。入口位于 ultralytics/engine/model.py 的track()方法if not hasattr(self.predictor, trackers): from ultralytics.trackers import register_tracker register_tracker(self, persist) kwargs[conf] kwargs.get(conf) or 0.1 # ByteTrack-based method needs low confidence predictions as input kwargs[batch] kwargs.get(batch) or 1 # batch-size 1 for tracking in videos kwargs[mode] track return self.predict(sourcesource, streamstream, **kwargs)值得注意的是track()还强制了两条追踪前置条件置信度阈值默认降为 0.1ByteTrack 系算法依赖低置信度框做二次关联太高会丢失遮挡目标的轨迹以及batch 强制为 1视频追踪按帧顺序处理且on_predict_start中按dataset.bs创建追踪器。典型用法from ultralytics import YOLO model YOLO(yolov8n.pt) # 视频文件非 persist 场景切换视频自动重置追踪器 results model.track(sourcevideo.mp4, showTrue) # 逐帧循环persistTrue 告诉追踪器当前帧是上一帧的延续 cap cv2.VideoCapture(video.mp4) while cap.isOpened(): success, frame cap.read() if success: results model.track(frame, persistTrue) annotated results[0].plot()CLI 等价命令为yolo track modelyolov8n.pt sourcevideo.mp4 yolo track modelyolov8n.pt sourcevideo.mp4 trackerbytetrack.yaml conf0.3七、追踪器配置参数详解tracker_type决定实例化哪个类其余参数在on_predict_start中被装载进cfg并传给追踪器构造函数。仓库内置两份配置文件ultralytics/cfg/trackers/bytetrack.yamltracker_type: bytetrack # tracker type, [botsort, bytetrack] track_high_thresh: 0.5 # threshold for the first association track_low_thresh: 0.1 # threshold for the second association new_track_thresh: 0.6 # threshold for init new track if the detection does not match any tracks track_buffer: 30 # buffer to calculate the time when to remove tracks match_thresh: 0.8 # threshold for matching tracksultralytics/cfg/trackers/botsort.yaml 在此基础上追加 BoT-SORT 专有项tracker_type: botsort track_high_thresh: 0.5 track_low_thresh: 0.1 new_track_thresh: 0.6 track_buffer: 30 match_thresh: 0.8 # BoT-SORT settings gmc_method: sparseOptFlow # method of global motion compensation proximity_thresh: 0.5 appearance_thresh: 0.25 with_reid: False各参数在源码中的实际作用参数默认值源码消费位置含义track_high_thresh0.5byte_tracker.update()第一轮关联的高分检测框阈值track_low_thresh0.1byte_tracker.update()第二轮关联的低分检测框阈值new_track_thresh0.6byte_tracker.update()未匹配检测框新建轨迹的最低分数track_buffer30BYTETracker.__init__经int(frame_rate/30*args.track_buffer)换算为max_time_lost超过该帧数未匹配的 lost 轨迹将被移除match_thresh0.8两轮linear_assignment关联距离阈值gmc_methodsparseOptFlowBOTSORT.__init__中GMC(method...)全局运动补偿方法BoT-SORTproximity_thresh0.5BOTSORT.get_dists空间邻近度阈值IoUappearance_thresh0.25BOTSORT.get_distsReID 外观相似度阈值with_reidFalseBOTSORT.__init__/get_dists是否启用 ReID 外观特征当前encoder仍为 None即尚未实际启用自定义追踪器只需复制上述任一 yaml 并修改参数tracker_type除外通过trackercustom_tracker.yaml传入即可。八、底层原理BYTETracker 的一轮更新tracker.update(det, im0s[i])内部ultralytics/trackers/byte_tracker.py 的BYTETracker.update执行的正是 ByteTrack 论文中的经典五步流程按track_high_thresh划分高置信度检测框按[low, high)区间收集低置信度检测框第一轮关联联合tracked_stracks与lost_stracks用共享卡尔曼滤波器multi_predict预测新位置以 IoU 分数融合距离fuse_score做线性分配第二轮关联对未匹配轨迹用低置信度检测框iou_distance 阈值 0.5二次匹配找回被遮挡的物体新轨迹激活仍未匹配且分数达new_track_thresh的检测框通过track.activate(kalman_filter, frame_id)建立新轨迹STrack.activate会分配新的全局track_id状态清理超过max_time_lost的 lost 轨迹被mark_removed重复轨迹按 IoU 距离与存活时长去重removed_stracks列表裁剪至 1000 以内。BoT-SORT 的差异在于卡尔曼状态量是xywh而非xyahupdate前先用 GMC 估计单应矩阵并通过STrack.multi_gmc校正全局运动get_dists中在 IoU 基础上叠加尚未启用的ReID 外观距离。九、验证与测试仓库测试 tests/test_engine.py 覆盖了回调机制本身通过pred.add_callback(on_predict_start, test_func)注册自定义回调再断言test_func in pred.callbacks[on_predict_start]验证了run_callbacks/add_callback框架的正确性——register_tracker使用的正是同一套回调 API。这从侧面印证了track.py三个函数的定位它们不是特殊逻辑而是标准预测回调机制的两个挂载点加上一个注册入口。十、小结ultralytics/trackers/track.py是 YOLOv10 多目标追踪的神经中枢register_tracker用两行代码把追踪能力注入模型预测管线on_predict_start按 batch 与 stream 模式合理实例化追踪器并强制校验tracker_typeon_predict_postprocess_end完成检测 → 关联 → 写回的每帧闭环支持 detect 与 OBB 两类任务persist与vid_path共同管理跨视频、跨帧的追踪状态生命周期。理解这个模块后无论是更换追踪算法、自定义阈值参数还是基于回调机制扩展新的追踪策略你都能在源码层面找到清晰的落点。【免费下载链接】yolov10YOLOv10: Real-Time End-to-End Object Detection [NeurIPS 2024]项目地址: https://gitcode.com/GitHub_Trending/yo/yolov10创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表