尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

基于YOLO与ByteTrack构建视频半自动标注流水线,告别逐帧手动标注

基于YOLO与ByteTrack构建视频半自动标注流水线,告别逐帧手动标注 如果你正在做视频目标检测或行为分析项目一定经历过这个痛苦阶段面对一段30分钟的视频需要标注出每一帧里每个行人的位置。传统工具如LabelImg、CVAT本质上是“图片标注器”你需要逐帧暂停、手动拉框、保存再下一帧。一个目标跟踪30秒900帧就是900次重复劳动。更崩溃的是当目标被短暂遮挡后重现你需要重新找到它手动建立关联——整个过程枯燥、低效且极易出错标注成本常常占到项目总成本的60%以上。这不仅仅是“费时间”的问题。手动逐帧标注引入的标注不一致框的大小、位置有轻微抖动、ID切换错误遮挡后目标ID混乱和大量漏标会直接污染你的训练数据导致模型在跟踪任务上表现不稳定、ID频繁跳变。你花费巨大代价标注的数据集可能因为标注质量问题让模型训练陷入瓶颈。今天要介绍的不是另一个“更好用的拉框工具”而是一种范式上的转变从“手动标注每一帧”转向“引导算法完成大部分跟踪人工仅做关键修正”。一个能实现多目标视频跟踪标注的工具它应该能让你在视频第一帧标出目标之后自动跟踪生成后续帧的标注框支持在跟踪过程中动态增删目标当目标丢失后能重连并最终输出标准格式的标注文件。本文将深入拆解如何利用现有开源生态搭建这样一套半自动标注流水线并提供一个可直接运行、复现的完整方案。1. 核心痛点为什么视频标注必须告别“纯手动”时代在讨论解决方案前我们必须先明确问题到底出在哪里。视频标注的核心挑战在于其时序关联性。与图像标注独立处理每一张图片不同视频标注要求对同一个目标在不同帧中的状态进行连续、一致的标识。这带来了三个层面的难题效率瓶颈人力有极限。以25FPS的视频计算标注1分钟的视频1500帧假设每帧有3个目标理想情况下需要绘制4500个框。这几乎是不可能完成的任务实践中往往采用稀疏采样如每秒标1帧但这会损失大量的运动信息对于需要精细运动分析的行为识别任务来说是致命的。质量陷阱人工标注在长时间、重复性劳动下必然出现疲劳导致的误差。框的位置偏移几个像素、大小略有不同在单张图片上或许可以接受但在视频序列中这些微小的不一致会被放大为模型的噪声导致学习到的运动模型不稳定。关联性缺失这是最棘手的问题。手动为每一帧的每个目标分配一个唯一且持续的ID即多目标跟踪任务中的ID几乎不可能。当目标交叉、遮挡后重现时人眼都难以分辨更不用说保持ID一致。而不正确的ID关联会直接训练出一个“ID切换”频繁的失败跟踪器。因此一个现代化的视频标注方案其核心思想必须是“人机协作”将机器擅长的快速、不知疲倦的视觉计算、时序关联与人类擅长的高层语义理解、关键决策、纠错结合起来。工具的价值在于将人从重复劳动中解放出来聚焦于监督、修正和关键帧标注这些真正需要智能介入的环节。2. 技术选型构建半自动标注流水线的核心组件要实现“动态跟踪标注”我们不能从零造轮子。幸运的是开源社区已经为我们提供了强大的基础组件。我们的流水线将围绕以下几个核心构建跟踪算法Tracker这是流水线的“发动机”。负责接收初始目标位置并在后续帧中持续预测其位置。我们需要选择一款平衡精度、速度和易用性的跟踪器。考虑到标注场景对实时性要求较高最好能达到实时或准实时预览且需要处理多目标ByteTrack或BoT-SORT这类基于检测的强关联多目标跟踪器是优秀的选择。它们依托于强大的目标检测器如YOLO系列检测每一帧的目标再通过关联算法如Kalman滤波匈牙利匹配跨帧关联形成轨迹。检测模型Detector为跟踪器提供每一帧的候选目标。对于通用场景预训练的YOLOv8或YOLO-NAS模型是很好的起点。它们速度快、精度高、易于部署。如果你的场景特殊如遥感图像、显微细胞则需要准备领域数据微调一个专用检测器。标注工具前端Annotation UI这是人机交互的界面。它需要提供视频播放、框体绘制、轨迹显示、ID管理、关键帧跳转、修正框体等功能。CVAT和Label Studio是两款功能强大的开源标注平台它们本身就支持视频标注和一定程度的AI辅助。我们可以通过其插件或后端集成方式接入我们的跟踪算法。后端服务Backend Service作为桥梁连接UI和算法。它接收前端传来的用户标注初始框、修正框、视频流调用跟踪/检测算法进行处理并将生成的跟踪框返回给前端显示。一个典型的协作流程是用户在视频第一帧画几个框或由检测器自动提议- 后端启动跟踪器生成后续帧的轨迹 - 用户在时间轴上浏览发现跟踪漂移或丢失时在问题帧进行修正拖动框体或重标- 后端根据修正信息进行局部重跟踪或全局优化 - 如此迭代直至整段视频标注完成。3. 环境准备搭建你的自动化标注工作台在开始编码之前我们需要准备好基础环境。以下方案基于Python因其在AI和计算机视觉领域的生态最为丰富。操作系统推荐 Ubuntu 20.04/22.04 或 Windows 10/11 with WSL2。macOS也可行但GPU支持可能稍复杂。Python版本3.8 或 3.9。深度学习框架PyTorch 1.10。我们首先创建一个干净的虚拟环境并安装核心依赖# 创建并激活虚拟环境 conda create -n video_anno python3.9 -y conda activate video_anno # 安装PyTorch (请根据你的CUDA版本访问PyTorch官网获取对应命令) # 例如对于CUDA 11.8 pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118 # 安装计算机视觉和跟踪相关库 pip install opencv-python opencv-contrib-python pip install ultralytics # 用于YOLOv8和目标跟踪 pip install supervision # 强大的检测和跟踪结果可视化、处理工具 pip install lap # 线性分配问题求解用于跟踪关联 pip install loguru # 更好的日志管理关键依赖说明ultralytics提供了YOLOv8的官方实现其YOLO类不仅支持检测还内置了track方法可以非常方便地调用ByteTrack等算法进行跟踪是我们流水线的核心。supervision一个新兴但极其强大的工具库。它提供了sv.Detections和sv.ByteTrack等类能够以简洁、统一的方式处理来自不同检测器YOLO, Detectron2等的结果并完成跟踪、可视化、过滤如按置信度、类别等操作极大简化了代码。opencv-python用于视频文件的读取、帧处理和显示。4. 核心流程拆解从视频到标注文件的四步走我们的半自动标注流程可以抽象为四个核心步骤下图清晰地展示了数据与指令在其中的流动过程flowchart TD A[输入待标注视频] -- B[“步骤1: 初始帧标注br人工或检测器提议”] B -- C[“步骤2: 自动跟踪传播br算法生成后续帧框”] C -- D[“步骤3: 人工审查与修正br处理遮挡、漂移、增删目标”] D -- E{是否遍历所有关键帧?} E -- 否 -- C E -- 是 -- F[“步骤4: 导出标准标注文件brCOCO, MOT Challenge格式”]步骤1初始化标注这是人机协作的起点。有两种方式人工初始化在工具UI中于视频起始帧或任何一个你认为具有代表性的帧手动绘制边界框并为每个框分配一个初始ID。检测器初始化工具自动运行检测模型如YOLOv8在起始帧生成候选框用户只需确认或删除这些提议框并分配ID。这种方式能进一步减少初始工作量。步骤2自动跟踪传播系统以初始帧的标注框为“种子”启动多目标跟踪算法。算法会逐帧预测这些目标的位置形成连续的轨迹。在这个过程中算法会自动处理目标的运动、尺度变化并尝试在目标短暂消失遮挡后重新关联重连。步骤3人工审查与交互式修正算法并非完美。用户需要在时间轴上快速浏览或跳转到系统置信度低的帧如目标重叠、严重遮挡、外观剧变进行检查。发现跟踪错误时用户可以进行以下操作修正框体直接拖动错误框的边角进行调整。重设ID当发生ID切换时手动指定正确的ID。删除轨迹目标离开视野或标注错误删除整条轨迹。新增目标在视频中途出现新目标时在对应帧画框系统会以此为起点开始新的跟踪。每次修正后系统可以局部重播跟踪从修正帧开始向后重新跟踪若干帧实现快速迭代。步骤4导出标注文件标注完成后将所有的轨迹数据帧号 目标ID 框坐标 类别等导出为标准格式如COCO格式用于检测/分割任务或MOT Challenge格式用于多目标跟踪任务方便直接用于模型训练。5. 代码实现构建一个轻量级跟踪标注脚本我们不急于搭建一个完整的Web UI而是先用一个命令行脚本验证核心流程。这个脚本将模拟“初始化-跟踪-导出”的过程你可以在此基础上扩展出交互界面。我们将使用ultralytics的跟踪能力和supervision的增强功能。文件结构video_annotation_pipeline/ ├── core/ │ ├── __init__.py │ ├── tracker.py # 封装跟踪逻辑 │ └── utils.py # 工具函数 ├── configs/ │ └── default.yaml # 配置文件 ├── main.py # 主脚本入口 └── requirements.txt第一步实现核心跟踪器 (core/tracker.py)# core/tracker.py import cv2 from ultralytics import YOLO import supervision as sv from typing import List, Optional, Tuple import numpy as np class VideoTracker: 视频跟踪标注器的核心类。 使用YOLOv8作为检测器集成ByteTrack进行多目标跟踪。 def __init__(self, model_path: str yolov8n.pt, device: str cuda:0): 初始化跟踪器。 Args: model_path: YOLO模型权重路径。可以是官方模型名如yolov8n.pt)或自定义模型。 device: 运行设备cuda:0 或 cpu。 self.model YOLO(model_path) self.model.to(device) self.tracker sv.ByteTrack() self.device device # 用于存储跟踪结果 {frame_index: sv.Detections} self.tracks {} def init_from_detection(self, frame: np.ndarray, classes: Optional[List[int]] None) - sv.Detections: 在初始帧通过检测器自动提议目标。 Args: frame: 初始帧图像 (H, W, C)。 classes: 只检测特定类别ID列表为None则检测所有类别。 Returns: sv.Detections: 初始检测结果。 results self.model(frame, verboseFalse)[0] detections sv.Detections.from_ultralytics(results) # 可选按类别过滤 if classes is not None: mask np.isin(detections.class_id, classes) detections detections[mask] # 可选按置信度过滤 confidence_mask detections.confidence 0.5 detections detections[confidence_mask] return detections def track_video(self, video_path: str, init_detections: Optional[sv.Detections] None) - None: 对视频进行跟踪。 Args: video_path: 输入视频文件路径。 init_detections: 可选的初始帧检测结果。如果为None则在第一帧自动检测。 cap cv2.VideoCapture(video_path) frame_idx 0 while True: ret, frame cap.read() if not ret: break if frame_idx 0 and init_detections is not None: # 使用用户提供的初始标注进行跟踪初始化 # 这里需要将人工标注的框转换为带tracker_id的detections # 假设init_detections已经包含了tracker_id tracked_detections self.tracker.update_with_detections(init_detections) else: # 正常检测跟踪流程 results self.model(frame, verboseFalse)[0] detections sv.Detections.from_ultralytics(results) tracked_detections self.tracker.update_with_detections(detections) self.tracks[frame_idx] tracked_detections frame_idx 1 # 可选实时显示跟踪结果用于调试 # self._display_frame(frame, tracked_detections, frame_idx) cap.release() print(f跟踪完成共处理 {frame_idx} 帧。) def get_tracks_at_frame(self, frame_idx: int) - Optional[sv.Detections]: 获取指定帧的跟踪结果。 return self.tracks.get(frame_idx) def export_to_mot_format(self, output_path: str) - None: 将跟踪结果导出为MOT Challenge格式的txt文件。 格式frame, id, bb_left, bb_top, bb_width, bb_height, conf, x, y, z 注意我们只使用前6列后3列设为-1。 with open(output_path, w) as f: for frame_idx, detections in self.tracks.items(): if detections is None: continue for i in range(len(detections.xyxy)): bbox detections.xyxy[i] tracker_id detections.tracker_id[i] conf detections.confidence[i] if detections.confidence is not None else 1.0 # 转换为 MOT 格式 frame, id, x1, y1, w, h, conf, -1, -1, -1 mot_line f{frame_idx1},{tracker_id},{bbox[0]:.2f},{bbox[1]:.2f},{bbox[2]-bbox[0]:.2f},{bbox[3]-bbox[1]:.2f},{conf:.2f},-1,-1,-1\n f.write(mot_line) print(f跟踪结果已导出至: {output_path}) def _display_frame(self, frame: np.ndarray, detections: sv.Detections, frame_idx: int): 辅助函数显示带跟踪框的帧调试用。 annotated_frame frame.copy() box_annotator sv.BoxAnnotator() label_annotator sv.LabelAnnotator() # 绘制边界框 annotated_frame box_annotator.annotate(annotated_frame, detections) # 绘制标签 (ID 类别) labels [ f#{tracker_id} {self.model.names[class_id]} for tracker_id, class_id in zip(detections.tracker_id, detections.class_id) ] annotated_frame label_annotator.annotate(annotated_frame, detections, labelslabels) cv2.putText(annotated_frame, fFrame: {frame_idx}, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2) cv2.imshow(Tracking, annotated_frame) if cv2.waitKey(1) 0xFF ord(q): raise KeyboardInterrupt第二步编写主程序入口 (main.py)# main.py import argparse from core.tracker import VideoTracker import supervision as sv import cv2 import numpy as np def main(): parser argparse.ArgumentParser(description半自动视频跟踪标注脚本) parser.add_argument(--video, typestr, requiredTrue, help输入视频文件路径) parser.add_argument(--model, typestr, defaultyolov8n.pt, helpYOLO模型路径) parser.add_argument(--output, typestr, defaulttracks.txt, helpMOT格式输出文件路径) parser.add_argument(--device, typestr, defaultcuda:0, help计算设备cuda:0 或 cpu) parser.add_argument(--init_frame, typeint, default0, help从第几帧开始处理用于断点续标) args parser.parse_args() # 1. 初始化跟踪器 tracker VideoTracker(model_pathargs.model, deviceargs.device) # 2. 如果需要可以在特定帧进行人工初始化这里用自动检测模拟 # 在实际工具中这里会调用UI让用户画框 if args.init_frame 0: cap cv2.VideoCapture(args.video) ret, init_frame cap.read() cap.release() if ret: print(正在初始帧进行自动目标检测...) init_detections tracker.init_from_detection(init_frame, classes[0]) # 只检测person类 (COCO ID 0) print(f初始帧检测到 {len(init_detections)} 个目标。) # 这里可以模拟人工选择例如只保留置信度最高的前3个目标 if len(init_detections) 0: # 按置信度排序 sorted_indices np.argsort(-init_detections.confidence) if init_detections.confidence is not None else range(len(init_detections)) selected_indices sorted_indices[:min(3, len(sorted_indices))] init_detections init_detections[selected_indices] print(f模拟人工选择后保留 {len(init_detections)} 个目标。) else: init_detections None print(无法读取初始帧。) else: init_detections None print(f从第 {args.init_frame} 帧开始跳过初始标注。) # 3. 执行视频跟踪 print(开始视频跟踪...) tracker.track_video(args.video, init_detections) # 4. 导出结果 tracker.export_to_mot_format(args.output) print(流程结束。) if __name__ __main__: main()第三步创建配置文件 (configs/default.yaml)# configs/default.yaml tracker: model: yolov8n.pt device: cuda:0 # 或 cpu confidence_threshold: 0.5 classes_of_interest: [0] # COCO类别ID0person annotation: output_format: mot # 可选: mot, coco output_path: ./output/tracks.txt video: start_frame: 0 end_frame: null # null表示处理到结尾6. 运行与验证从命令行到可视化结果现在让我们运行这个脚本并验证其效果。运行命令# 确保在 video_annotation_pipeline 目录下 python main.py --video ./your_video.mp4 --model yolov8n.pt --output ./my_tracks.txt将./your_video.mp4替换为你的视频文件路径。脚本会加载YOLOv8n模型首次运行会自动下载。读取视频第一帧并运行检测器找出“人”类别0。模拟人工选择保留置信度最高的3个目标。以这3个目标为种子对整个视频进行多目标跟踪。将跟踪轨迹以MOT格式保存到my_tracks.txt。验证输出文件my_tracks.txt的内容大致如下1,1,345.20,120.50,45.30,120.80,0.98,-1,-1,-1 1,2,500.10,200.30,50.25,180.60,0.92,-1,-1,-1 1,3,700.80,150.75,48.90,160.20,0.95,-1,-1,-1 2,1,348.50,118.90,45.80,121.50,0.97,-1,-1,-1 2,2,503.30,198.10,50.50,181.30,0.91,-1,-1,-1 2,3,703.20,148.50,49.10,161.00,0.94,-1,-1,-1 ...每一行代表一个目标在某一帧的检测框。列依次为帧号 目标ID 框左上角x 框左上角y 框宽度 框高度 置信度 3D信息未使用设为-1。可视化验证 为了直观检查跟踪质量我们可以写一个简单的可视化脚本# visualize_tracks.py import cv2 import numpy as np def visualize_mot_tracks(video_path: str, mot_txt_path: str, output_video_path: str None): 读取MOT格式的跟踪结果并在视频上绘制出来。 cap cv2.VideoCapture(video_path) width int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) height int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) fps cap.get(cv2.CAP_PROP_FPS) # 读取跟踪结果 tracks {} with open(mot_txt_path, r) as f: for line in f: parts line.strip().split(,) frame_idx int(parts[0]) - 1 # MOT格式帧号从1开始 obj_id int(parts[1]) bbox list(map(float, parts[2:6])) # x1, y1, w, h if frame_idx not in tracks: tracks[frame_idx] [] tracks[frame_idx].append((obj_id, bbox)) # 准备输出 if output_video_path: fourcc cv2.VideoWriter_fourcc(*mp4v) out cv2.VideoWriter(output_video_path, fourcc, fps, (width, height)) frame_idx 0 colors {} # 为每个ID分配固定颜色 while True: ret, frame cap.read() if not ret: break if frame_idx in tracks: for obj_id, bbox in tracks[frame_idx]: x1, y1, w, h bbox x2, y2 int(x1 w), int(y1 h) x1, y1 int(x1), int(y1) # 为每个ID生成固定颜色 if obj_id not in colors: # 使用HSV颜色空间均匀分布颜色 hue (obj_id * 50) % 180 # OpenCV HSV中Hue范围是0-179 color tuple(map(int, cv2.cvtColor(np.uint8([[[hue, 255, 255]]]), cv2.COLOR_HSV2BGR)[0,0])) colors[obj_id] color else: color colors[obj_id] # 画框和ID cv2.rectangle(frame, (x1, y1), (x2, y2), color, 2) cv2.putText(frame, fID:{obj_id}, (x1, y1-10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, color, 2) cv2.putText(frame, fFrame: {frame_idx}, (20, 40), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,255,0), 2) if output_video_path: out.write(frame) cv2.imshow(Track Visualization, frame) if cv2.waitKey(1) 0xFF ord(q): break frame_idx 1 cap.release() if output_video_path: out.release() cv2.destroyAllWindows() print(可视化完成。) if __name__ __main__: visualize_mot_tracks(./your_video.mp4, ./my_tracks.txt, ./output_viz.mp4)运行此脚本你将看到一个带有彩色跟踪框和ID的视频窗口。观察ID是否在目标被遮挡或交叉时保持稳定是评估跟踪质量最直观的方法。7. 常见问题与排查思路在实际部署和使用过程中你可能会遇到以下典型问题问题现象可能原因排查方式解决方案跟踪器完全丢失目标1. 初始检测置信度过低。2. 目标运动过快或超出模型感受野。3. 视频分辨率过低或目标太小。1. 检查初始帧检测结果的可视化。2. 查看丢失目标前后帧的检测器输出。1. 降低检测置信度阈值 (conf)。2. 使用更大、更精准的检测模型如yolov8m.pt或yolov8l.pt。3. 尝试在丢失帧附近手动重新初始化目标。ID切换频繁1. 目标外观相似且距离近。2. 跟踪器的关联阈值设置不当。3. 遮挡时间过长重连失败。1. 观察ID切换发生的场景交叉、遮挡。2. 检查跟踪器如ByteTrack的track_buffer、match_thresh参数。1. 调整跟踪器关联参数增加外观特征权重如果使用BoT-SORT。2. 在工具中提供便捷的“ID合并”或“ID重设”功能让人工快速修正。标注框抖动大小/位置不稳定1. 检测框本身存在抖动。2. 跟踪器的运动模型如Kalman滤波参数需要调整。1. 对比纯检测结果和跟踪结果。2. 观察抖动是高频噪声还是系统性偏移。1. 对检测结果进行后处理平滑如移动平均滤波。2. 调整Kalman滤波的过程噪声和测量噪声参数。处理速度慢无法实时1. 使用的检测模型过大如YOLOv8x。2. 在CPU上运行。3. 视频分辨率过高。1. 使用time模块对检测、跟踪步骤分别计时。2. 监控GPU/CPU使用率。1. 换用轻量模型如YOLOv8n, YOLOv8s。2. 确保使用GPU (devicecuda:0)。3. 对输入视频进行下采样处理。导出的标注文件格式错误1. 坐标格式不符合标准XYWH vs. XYXY。2. 帧编号起始值错误应为1。3. 缺少必要字段。1. 用官方验证工具如MOTChallenge的devkit检查文件。2. 对比自己生成的文件和标准示例文件。1. 严格按照目标数据集的格式要求编写导出函数。2. 提供多种格式COCO, MOT, Pascal VOC的导出选项。8. 工程化与最佳实践打造健壮的标注工具将上述脚本升级为一个团队可用的生产级工具还需要考虑以下方面1. 状态管理与撤销/重做标注是一个试错过程。工具必须支持完整的撤销Undo和重做Redo栈操作应涵盖添加/删除目标、修改框体、更改ID、添加关键帧等。在内存中维护完整的标注历史状态。2. 智能交互与提示关键帧建议算法可以自动检测跟踪置信度低的帧如目标重叠度高、运动模糊提示用户优先检查。插值与传播用户修正了第N帧和第M帧的框工具可以自动线性插值生成中间帧的框大幅减少修正工作量。批量操作支持框选多个目标进行统一删除、ID重设或类别修改。3. 模型管理与迭代自定义模型加载允许用户上传自己训练的、针对特定场景如车辆、动物、细胞的YOLO权重文件。在线学习可选在用户修正标注后能否用这些修正数据对跟踪器进行微调使其在后续视频或同类视频中表现更好这是一个高级功能可以作为一个研究方向。4. 项目与数据管理多视频项目管理支持创建项目批量导入视频统一管理标注任务和人员分配。标注进度保存支持随时保存进度下次打开可继续工作避免数据丢失。版本控制对同一视频的标注结果进行版本管理方便对比不同版本的差异。5. 前端技术选型建议对于构建交互式UI可以考虑Streamlit / Gradio快速构建Python Web原型的利器适合算法工程师快速验证想法和交付内部工具。React / Vue OpenCV.js构建功能丰富、体验流畅的专业级标注平台。前端用Canvas渲染视频和框体后端用Flask/FastAPI提供算法接口。CVAT和Label Studio都采用类似架构。6. 安全与性能视频处理对于超长视频应采用流式处理避免一次性将整个视频加载到内存。数据安全如果处理敏感数据确保工具可以本地部署标注数据不离开用户环境。备份机制自动定时备份标注结果到本地或指定存储。从“手动逐帧标注”到“算法跟踪为主人工修正为辅”这不仅仅是工具的升级更是工作流的革命。本文提供的方案从核心原理、环境搭建、代码实现到问题排查为你构建自己的半自动视频标注系统铺平了道路。真正的价值不在于完全取代人工而是将人的精力投入到算法不擅长的、需要高层语义理解和决策的关键环节从而将标注效率提升一个数量级同时保障数据质量。你可以从运行我们提供的脚本开始在本地视频上体验自动跟踪的效果。然后尝试用Gradio或Streamlit为其包裹一个简单的Web界面实现框体修正功能。接下来考虑如何集成更强大的跟踪器如OC-SORT, StrongSORT或加入ReID特征来提升ID保持能力。最终一个贴合你自身业务需求的、高效的视频标注工具将成为你AI项目数据 pipeline 中最坚实的一环。
返回列表