DAMO-YOLO TinyNAS多目标跟踪:DeepSORT算法集成实战
你是不是遇到过这样的场景?用目标检测模型识别出了视频里的行人、车辆,但画面一复杂,目标一多,就分不清谁是谁了。上一帧检测到的“红衣服行人”,下一帧可能就被识别成了另一个新目标,跟踪完全断了线。
这就是单纯目标检测的局限——它只能告诉你“这里有什么”,却没法告诉你“这个东西从哪来、到哪去”。而多目标跟踪技术,就是为了解决这个“身份连续”的问题。今天,我们就来动手把目前速度与精度兼顾的佼佼者——DAMO-YOLO TinyNAS,和经典的多目标跟踪算法DeepSORT“撮合”到一起,打造一个既能实时检测又能稳定跟踪的实用系统。
整个过程并不复杂,我会带你一步步走通,从理解原理到跑通代码,最后还能根据自己的需求调调参数,让跟踪效果更上一层楼。
1. 先搞清楚我们要做什么:检测与跟踪的强强联合
在开始敲代码之前,我们得先弄明白,把DAMO-YOLO和DeepSORT结合起来,到底能解决什么问题。
想象一下交通路口的监控摄像头。如果只用检测模型,每一帧画面都会独立地框出汽车和行人,但你看不到某辆车是如何从左到右穿过马路的,也看不出那个行人是不是在闯红灯。多目标跟踪的核心价值,就是为每个检测到的目标分配一个唯一的ID,并在后续帧中持续地“跟住”这个ID,形成运动轨迹。
DAMO-YOLO TinyNAS在这里扮演“火眼金睛”的角色。它基于神经架构搜索技术,能在给定的计算资源下,自动找到又快又准的网络结构。相比其他YOLO版本,它在速度和精度之间取得了更好的平衡,特别适合需要实时处理的视频流场景。你可以把它理解为一个效率极高的“侦察兵”,能快速发现画面中的所有目标。
DeepSORT则是“记忆大师”和“匹配专家”。它接收DAMO-YOLO侦察到的目标信息(位置、大小),然后做两件事:第一,利用卡尔曼滤波预测目标下一帧会在哪里出现;第二,通过外观特征(比如用深度学习模型提取的行人衣着、体型特征)和运动信息(位置、速度)进行匹配,判断新一帧的哪个检测框对应上一帧的哪个老目标。这样,即使目标被短暂遮挡或外观变化,也能大概率找回正确的ID。
我们的任务,就是搭建一个管道(Pipeline):视频帧输入 → DAMO-YOLO检测 → DeepSORT跟踪 → 输出带ID和轨迹的画面。
2. 动手前的准备工作
理论明白了,接下来我们得把“战场”布置好。这里假设你已经有基本的Python环境,并且有一张支持CUDA的NVIDIA显卡(没有的话用CPU也行,就是慢点)。
2.1 环境搭建
首先,我们需要克隆DAMO-YOLO的官方代码库,并安装其依赖。
# 1. 克隆DAMO-YOLO仓库 git clone https://github.com/tinyvision/DAMO-YOLO.git cd DAMO-YOLO # 2. 创建并激活Python虚拟环境(推荐) conda create -n damo-deepsort python=3.8 -y conda activate damo-deepsort # 3. 安装PyTorch(请根据你的CUDA版本调整) # 例如,CUDA 11.3 pip install torch==1.12.1+cu113 torchvision==0.13.1+cu113 torchaudio==0.12.1 --extra-index-url https://download.pytorch.org/whl/cu113 # 4. 安装DAMO-YOLO的其他依赖 pip install -r requirements.txt # 5. 将当前目录加入Python路径 export PYTHONPATH=`pwd`:$PYTHONPATH # Linux/Mac # 或者 set PYTHONPATH=%cd%;%PYTHONPATH% # Windows cmd2.2 获取模型与DeepSORT代码
DAMO-YOLO需要预训练权重,DeepSORT则需要其本身的代码和用于提取外观特征的重识别(ReID)模型。
# 进入项目目录 cd DAMO-YOLO # 下载一个DAMO-YOLO预训练模型,例如小巧的TinyNAS-L25-S模型 # 你可以从官方Model Zoo(https://github.com/tinyvision/DAMO-YOLO#model-zoo)找到下载链接 # 这里假设我们下载了 damoyolo_tinynasL25_S.pth,放在项目根目录 # wget -O damoyolo_tinynasL25_S.pth <模型下载链接> # 接下来,获取DeepSORT的核心代码。 # 我们可以使用一个流行的PyTorch实现版本。 git clone https://github.com/ZQPei/deep_sort_pytorch.git cd deep_sort_pytorch # 下载DeepSORT所需的ReID模型(mars-small128.pb)和检测文件 # 这个仓库通常自带或提供了下载脚本,请查看其README。 # 例如,可能需要运行: # wget https://drive.google.com/open?id=1uSBXLJcOZOc1RGhVbXgxzvkgV-8X3Qiq -O deep_sort/deep/checkpoint/ckpt.t7 # 由于网络原因,你可能需要手动寻找并下载 mars-small128.pb 文件,放入 deep_sort/deep/checkpoint/ 目录 cd .. # 返回DAMO-YOLO根目录现在,你的目录结构应该大致如下:
DAMO-YOLO/ ├── configs/ ├── tools/ ├── damo/ ├── deep_sort_pytorch/ # 刚克隆的DeepSORT代码 │ ├── deep_sort/ │ │ ├── deep/ │ │ │ └── checkpoint/ # 需要放入ReID模型文件 │ │ └── sort/ │ └── ... ├── damoyolo_tinynasL25_S.pth # 检测模型权重 └── ...3. 核心集成:编写检测与跟踪的桥梁代码
环境准备好了,模型也下载了,最关键的一步来了:写一个脚本,让DAMO-YOLO和DeepSORT能够对话。我们会在tools目录下创建一个新的脚本,比如叫demo_track.py。
这个脚本的主要逻辑是:
- 加载DAMO-YOLO检测模型。
- 初始化DeepSORT跟踪器。
- 循环读取视频帧。
- 对每一帧,用DAMO-YOLO检测目标。
- 将检测结果转换成DeepSORT需要的格式,并更新跟踪器。
- 在画面上绘制带ID的检测框和轨迹。
- 输出结果。
下面是一个高度整合且可运行的示例代码框架:
# tools/demo_track.py import argparse import time import cv2 import torch import numpy as np from pathlib import Path import sys sys.path.insert(0, '.') from damo.apis.detector_infer import Detector from deep_sort_pytorch.deep_sort import DeepSort from deep_sort_pytorch.utils.parser import get_config def main(): parser = argparse.ArgumentParser() parser.add_argument('--video_path', type=str, default='./assets/demo_video.mp4', help='source video path') parser.add_argument('--det_config', type=str, default='./configs/damoyolo_tinynasL25_S.py', help='detector config file path') parser.add_argument('--det_checkpoint', type=str, default='./damoyolo_tinynasL25_S.pth', help='detector checkpoint path') parser.add_argument('--deep_sort_config', type=str, default='./deep_sort_pytorch/configs/deep_sort.yaml') parser.add_argument('--output_path', type=str, default='./output_track.mp4', help='output video path') parser.add_argument('--device', type=str, default='cuda:0', help='compute device, cuda:0 or cpu') parser.add_argument('--conf_threshold', type=float, default=0.5, help='detection confidence threshold') parser.add_argument('--nms_threshold', type=float, default=0.5, help='NMS IoU threshold') parser.add_argument('--show_video', action='store_true', help='display video while processing') args = parser.parse_args() # 1. 初始化DAMO-YOLO检测器 print(f'Loading detector from {args.det_checkpoint}...') detector = Detector(args.det_config, args.det_checkpoint, device=args.device) # 2. 初始化DeepSORT跟踪器 cfg = get_config() cfg.merge_from_file(args.deep_sort_config) deepsort = DeepSort( cfg.DEEPSORT.REID_CKPT, max_dist=cfg.DEEPSORT.MAX_DIST, min_confidence=cfg.DEEPSORT.MIN_CONFIDENCE, nms_max_overlap=cfg.DEEPSORT.NMS_MAX_OVERLAP, max_iou_distance=cfg.DEEPSORT.MAX_IOU_DISTANCE, max_age=cfg.DEEPSORT.MAX_AGE, n_init=cfg.DEEPSORT.N_INIT, nn_budget=cfg.DEEPSORT.NN_BUDGET, use_cuda=(args.device != 'cpu') ) print('DeepSORT tracker initialized.') # 3. 打开视频文件 cap = cv2.VideoCapture(args.video_path) if not cap.isOpened(): print(f"Error opening video file {args.video_path}") return # 获取视频属性,用于创建输出视频 fps = int(cap.get(cv2.CAP_PROP_FPS)) width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) fourcc = cv2.VideoWriter_fourcc(*'mp4v') out = cv2.VideoWriter(args.output_path, fourcc, fps, (width, height)) frame_id = 0 print('Start tracking...') while True: ret, frame = cap.read() if not ret: break # 4. 使用DAMO-YOLO进行检测 # Detector的predict方法通常返回一个包含检测结果的字典或列表 # 具体格式需要参考DAMO-YOLO的API,这里假设它返回(x1, y1, x2, y2, conf, cls)的列表 detections = detector.predict(frame, conf=args.conf_threshold) # 5. 将检测结果转换为DeepSORT需要的格式 [x1, y1, x2, y2, conf] # 注意:这里需要根据DAMO-YOLO的实际输出进行调整,并过滤掉不需要的类别(如只跟踪人) bbox_xywh = [] confidences = [] for det in detections: # det 可能是 tensor 或 numpy array # 假设 det 格式为 [x1, y1, x2, y2, score, class_id] x1, y1, x2, y2, score, cls_id = det[:6] # 假设我们只跟踪类别0(人),根据你的数据集调整 if int(cls_id) == 0 and score > args.conf_threshold: w = x2 - x1 h = y2 - y1 # DeepSORT 需要中心点坐标和宽高 bbox_xywh.append([(x1+x2)/2, (y1+y2)/2, w, h]) confidences.append(float(score)) if len(bbox_xywh) > 0: bbox_xywh = torch.Tensor(bbox_xywh) confidences = torch.Tensor(confidences) # 6. 更新DeepSORT跟踪器 outputs = deepsort.update(bbox_xywh, confidences, frame) # 7. 在帧上绘制跟踪结果 if len(outputs) > 0: for j, output in enumerate(outputs): bbox = output[:4] # x1, y1, x2, y2 id = output[4] # 绘制边界框和ID cv2.rectangle(frame, (int(bbox[0]), int(bbox[1])), (int(bbox[2]), int(bbox[3])), (0, 255, 0), 2) cv2.putText(frame, f'ID:{int(id)}', (int(bbox[0]), int(bbox[1])-10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2) else: # 如果没有检测到目标,DeepSORT也会更新其内部状态 deepsort.update([], [], frame) # 显示帧(可选) if args.show_video: cv2.imshow('Tracking', frame) if cv2.waitKey(1) & 0xFF == ord('q'): break # 写入输出视频 out.write(frame) frame_id += 1 if frame_id % 50 == 0: print(f'Processed {frame_id} frames.') cap.release() out.release() cv2.destroyAllWindows() print(f'Tracking finished. Result saved to {args.output_path}') if __name__ == '__main__': main()注意:上面的代码是一个集成框架,其中最关键的第4步(detector.predict的返回格式)和第5步(数据转换)需要你根据DAMO-YOLO实际提供的推理接口进行调整。你可能需要查阅damo.apis.detector_infer.Detector类的具体文档或源码,看看它的输出到底是什么结构。
4. 让跟踪效果更好:关键参数调优指南
代码跑起来,能看到带ID的框在动,这就算成功了一大半。但你可能发现,有时候ID会跳变,或者目标被遮挡后就跟丢了。别急,我们可以通过调整一些“旋钮”来优化效果。这些参数主要在DeepSORT的配置文件中(例如deep_sort_pytorch/configs/deep_sort.yaml)。
4.1 DeepSORT核心参数解析
打开这个YAML文件,你会看到类似下面的配置。我们来解读几个最重要的:
DEEPSORT: REID_CKPT: "deep_sort/deep/checkpoint/ckpt.t7" # 外观特征模型路径 MAX_DIST: 0.2 # 外观特征匹配的最大距离阈值。值越小,匹配要求越严格。 MIN_CONFIDENCE: 0.3 # 检测结果的最低置信度,低于此值不送入跟踪器。 NMS_MAX_OVERLAP: 0.5 # 用于跟踪器内部检测框NMS的IoU阈值。 MAX_IOU_DISTANCE: 0.7 # 基于IoU匹配的最大距离阈值。用于关联预测框和检测框。 MAX_AGE: 70 # 一个跟踪轨迹在被删除前最多可以丢失多少帧。值越大,抗遮挡能力越强,但也更容易产生ID粘连。 N_INIT: 3 # 需要连续关联多少帧,才将一个检测框初始化为新的跟踪轨迹。防止误检产生短暂轨迹。 NN_BUDGET: 100 # 为每个ID保存的外观特征向量的数量。用于计算平均特征,值越大记忆越久,但计算开销也大。4.2 调参实战建议
- 场景拥挤,ID频繁跳变:这可能是外观相似目标太多,匹配错了。可以尝试调低
MAX_DIST(比如从0.2调到0.15),让外观匹配更严格。同时,可以适当提高MIN_CONFIDENCE,只把确信度高的检测框交给跟踪器,减少噪声。 - 目标被短暂遮挡后就跟丢:可以增大
MAX_AGE(比如从70调到100),给跟踪轨迹更长的“存活”时间,等待目标重新出现。同时,确保你的ReID模型质量较好,能在目标重现时正确匹配。 - 误检(如晃动的树叶)产生短暂的虚假轨迹:增加
N_INIT(比如从3调到5),要求目标必须被连续稳定地检测到更多帧,才被认为是一个有效的跟踪目标。 - 运动匹配与外观匹配的权衡:
MAX_IOU_DISTANCE控制基于运动预测的匹配。如果摄像头静止或目标运动规律,可以依赖它。如果摄像头运动或目标运动复杂,可以适当调低此值,更多地依赖外观特征(MAX_DIST)。
调参是一个观察-调整-再观察的过程。最好的方法是用一段有代表性的视频,固定其他参数,每次只调整一个,观察效果变化,记录下最适合你场景的组合。
5. 试试效果,看看还能怎么用
运行我们写好的脚本,看看效果吧!
conda activate damo-deepsort cd DAMO-YOLO python tools/demo_track.py \ --video_path ./your_video.mp4 \ --det_config ./configs/damoyolo_tinynasL25_S.py \ --det_checkpoint ./damoyolo_tinynasL25_S.pth \ --deep_sort_config ./deep_sort_pytorch/configs/deep_sort.yaml \ --output_path ./tracked_video.mp4 \ --device cuda:0 \ --conf_threshold 0.5 \ --show_video如果一切顺利,你会得到一个tracked_video.mp4文件,里面每个被跟踪的目标都有了自己独一无二的ID。
这个技术组合的用武之地非常广:
- 智慧交通:统计车流量、跟踪车辆轨迹分析行驶行为、检测违章。
- 安防监控:跟踪可疑人员活动路径、计算区域内人数。
- 零售分析:跟踪顾客在店内的移动轨迹,分析热区。
- 体育赛事:自动跟踪运动员和球,生成数据统计。
6. 写在最后
把DAMO-YOLO和DeepSORT集成起来,其实思路很清晰:一个负责精准快速地“看”,一个负责聪明地“记”和“连”。整个过程从环境搭建到代码集成,虽然会遇到一些细节上的小坑(比如API接口对齐、模型文件下载),但一步步拆解下来都是可以解决的。
我建议你先用提供的代码框架跑通一个简单例子,看到跟踪效果。然后,再根据你的具体需求去微调。比如,如果不是跟踪人,而是跟踪车,那么在第5步的数据转换那里就需要修改类别ID;如果对实时性要求极高,可以尝试更小的DAMO-YOLO模型(如Nano系列),或者将推理引擎转换为TensorRT。
动手试试吧,当你看到视频中那些被赋予连续ID并画出运动轨迹的目标时,你会感受到多目标跟踪技术的魅力。它让冰冷的检测框“活”了起来,为我们理解动态世界提供了更强大的工具。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。