- 导入了一些Python的标准库和第三方库。
- 从
boxmot.utils
模块中导入了一些常量,这些常量用于指定与数据集、权重和示例相关的路径。 - 从
tracking.utils
模块中导入了一些函数,这些函数与下载、解压缩多目标跟踪数据集以及设置评估环境有关。
# 导入Python的正则表达式库,用于处理字符串和文本。
import re
# 导入Python的系统特定参数和函数库,例如访问命令行参数。
import sys
# 导入Python的命令行参数解析库,用于从命令行读取参数。
import argparse
# 导入Python的子进程管理库,用于启动新应用和与它们通信。
import subprocess
# 从boxmot.utils模块中导入几个常量,可能用于定义数据集的示例、根目录、权重和数据路径。
from boxmot.utils import EXAMPLES, ROOT, WEIGHTS, DATA
# 导入Path类,它是pathlib模块中的一个类,用于表示文件系统路径。
from pathlib import Path
# 从tracking.utils模块中导入多个函数。
# 这些函数可能涉及下载多目标跟踪评估工具、下载多目标跟踪数据集、解压缩数据集以及设置评估环境。
from tracking.utils import (
download_mot_eval_tools, # 下载多目标跟踪评估工具的函数。
download_mot_dataset, # 下载多目标跟踪数据集的函数。
unzip_mot_dataset, # 解压缩多目标跟踪数据集的函数。
eval_setup # 设置评估环境的函数。
)
from ultralytics.utils.files import increment_path
这段代码的功能是从一个字符串 results
中解析出 MOT(多目标跟踪)挑战的结果,具体是提取 COMBINED HOTA、MOTA 和 IDF1 这三个指标的值。以下是代码的逐行解释:
def parse_mot_results(results):
"""
从 run_mot_challenge.py 脚本生成的结果中提取 COMBINED HOTA、MOTA 和 IDF1。
Args:
results (str): MOT 挑战的结果字符串
Returns:
(dict): 包含 'HOTA'、'MOTA' 和 'IDF1' 的字典,格式为 {'HOTA': x, 'MOTA': y, 'IDF1': z}
"""
# 将结果字符串以 'COMBINED' 为分隔符进行分割,并取第三个元素到倒数第二个元素,这通常包含 COMBINED HOTA, MOTA, IDF1 的结果
combined_results = results.split('COMBINED')[2:-1]
# 使用正则表达式从每个字符串中找到第一个整数或浮点数,并将其转换为浮点数
# re.findall("[-+]?(?:\d*\.*\d+)", f) 查找所有可能的整数或浮点数,但使用 [0] 仅取第一个
combined_results = [float(re.findall("[-+]?(?:\d*\.*\d+)", f)[0]) for f in combined_results]
# 使用 zip 函数将键列表 ['HOTA', 'MOTA', 'IDF1'] 和转换后的浮点数列表结合,生成字典
combined_results = {key: value for key, value in zip(['HOTA', 'MOTA', 'IDF1'], combined_results)}
# 返回包含 COMBINED HOTA, MOTA, IDF1 的字典
return combined_results
def trackeval(
args, # 传递的命令行参数,通常包含用于执行trackeval所需的参数配置
seq_paths, # 包含序列路径的列表或字典,用于指定哪些序列将被用于评估
save_dir, # 保存评估结果的目录路径
MOT_results_folder,# 包含MOT跟踪结果的文件夹路径
gt_folder, # 包含真实标签(ground truth)的文件夹路径
metrics = ["HOTA", "CLEAR", "Identity"] # 评估时使用的指标列表,默认为HOTA, CLEAR, Identity
):
"""
使用指定的指标执行Python脚本以评估MOT挑战跟踪结果。
Parameters:
args (dict or argparse.Namespace): 包含执行trackeval所需参数的字典或命名空间对象。
seq_paths (list or dict): 包含序列路径的列表或字典,用于指定哪些序列将被用于评估。
save_dir (str): 保存评估结果的目录路径。
MOT_results_folder (str): 包含MOT跟踪结果的文件夹路径。
gt_folder (str): 包含真实标签(ground truth)的文件夹路径。
metrics (list): 一个列表,包含用于评估的指标。默认为["HOTA", "CLEAR", "Identity"]。
Returns:
None. 该函数主要执行评估并打印评估脚本的标准输出和标准错误。
"""
# Define paths
# 获取每个序列路径的父目录名称(通常是序列的名称),并将它们存储在列表d中
d = [seq_path.parent.name for seq_path in seq_paths]
# Prepare arguments for subprocess call
# 准备用于子进程调用的命令行参数列表
args = [
# 使用当前Python解释器来执行脚本
sys.executable,
# 评估脚本的路径
EXAMPLES / 'val_utils' / 'scripts' / 'run_mot_challenge.py',
# 真实标签(ground truth)文件夹的路径
"--GT_FOLDER", str(gt_folder),
# 基准测试名称,这里为空字符串,可能需要在其他地方设置
"--BENCHMARK", "",
# 跟踪结果文件夹的路径,args.exp_folder_path应该是一个在函数外部定义的变量
"--TRACKERS_FOLDER", args.exp_folder_path,
# 要评估的跟踪器名称,这里为空字符串,可能需要在其他地方设置
"--TRACKERS_TO_EVAL", "",
# 要评估的数据拆分,这里设置为"train"
"--SPLIT_TO_EVAL", "train",
# 评估指标列表,使用*metrics来展开列表中的每个元素
"--METRICS", *metrics,
# 是否使用并行评估,这里设置为"True"
"--USE_PARALLEL", "True",
# 跟踪器子文件夹名称,这里为空字符串,可能需要在其他地方设置
"--TRACKER_SUB_FOLDER", "",
# 并行评估时使用的核心数,这里设置为4
"--NUM_PARALLEL_CORES", str(4),
# 是否跳过某些拆分文件夹,这里设置为"True"
"--SKIP_SPLIT_FOL", "True",
# 序列信息,使用*d来展开列表中的每个序列名称
"--SEQ_INFO", *d
]
# 使用subprocess模块来执行评估脚本
# Execute the evaluation script
p = subprocess.Popen(
# 传递前面准备好的命令行参数列表
args=args,
# 将标准输出重定向到PIPE,以便在Python中捕获它
stdout=subprocess.PIPE,
# 将标准错误重定向到PIPE,以便在Python中捕获它
stderr=subprocess.PIPE,
# 设置text=True以确保输出以文本形式而不是字节形式返回
text=True
)
# 等待进程完成,并获取其标准输出和标准错误
stdout, stderr = p.communicate()
# 输出脚本运行时的标准输出内容
# Output the results
print("Standard Output:\n", stdout)
# 检查是否有标准错误输出,如果有则输出
if stderr:
print("Standard Error:\n", stderr)
# 返回脚本运行时的标准输出内容,通常用于进一步处理或分析
return stdout
def parse_opt():
# 创建一个命令行参数解析器
parser = argparse.ArgumentParser()
# 添加参数:YOLO模型的路径
parser.add_argument('--yolo-model', type=Path, default=WEIGHTS / 'yolov8n',
help='指定YOLO模型的路径。默认为WEIGHTS目录下的yolov8n模型。')
# 添加参数:Re-ID模型的路径
parser.add_argument('--reid-model', type=Path, default=WEIGHTS / 'osnet_x0_25_msmt17.pt',
help='指定Re-ID模型的路径。默认为WEIGHTS目录下的osnet_x0_25_msmt17.pt模型。')
# 添加参数:跟踪方法
parser.add_argument('--tracking-method', type=str, default='deepocsort',
help='指定跟踪方法,可选值为deepocsort, botsort, strongsort, ocsort, bytetrack。默认为deepocsort。')
# 添加参数:输入源
parser.add_argument('--source', type=str, default='0',
help='指定输入源,可以是文件路径、目录、URL或者glob模式,如果为0则使用摄像头。默认为0。')
# 添加参数:推理尺寸
parser.add_argument('--imgsz', '--img', '--img-size', nargs='+', type=int, default=[640],
help='指定推理(inference)的尺寸,可以是高度和宽度的组合。默认为宽度640。')
# 添加参数:置信度阈值
parser.add_argument('--conf', type=float, default=0.5,
help='设置置信度阈值,用于过滤掉低置信度的检测结果。默认为0.5。')
# 添加参数:非极大值抑制IoU阈值
parser.add_argument('--iou', type=float, default=0.7,
help='设置非极大值抑制(NMS)的交并比(IoU)阈值。默认为0.7。')
# 添加参数:计算设备
parser.add_argument('--device', default='',
help='指定计算设备,可以是CUDA设备编号(如0或0,1,2,3)或者cpu。默认为空字符串,表示自动选择。')
# 添加参数:是否显示跟踪结果
parser.add_argument('--show', action='store_true',
help='如果设置,则显示跟踪视频结果。')
# 添加参数:是否保存跟踪结果
parser.add_argument('--save', action='store_true',
help='如果设置,则保存视频跟踪结果。')
# 类别编号:0代表行人,1代表自行车,2代表汽车,... 79代表烤箱
parser.add_argument('--classes', nargs='+', type=int, default=0,
help='通过类别进行过滤,例如:--classes 0 或者 --classes 0 2 3')
# 添加参数:项目路径
# 结果将被保存到project/name目录下
parser.add_argument('--project', default=ROOT / 'runs' / 'mot', type=Path,
help='将结果保存到project/name目录下')
# 添加参数:结果保存名称
# 结果将被保存到project/name目录下
parser.add_argument('--name', default='yolov8n_osnet_x0_25_msmt17',
help='将结果保存到project/name目录下')
# 添加参数:检测文件夹名称
# 从项目下的哪个文件夹加载检测结果
parser.add_argument('--dets', type=str, default='yolov8n',
help='在项目下从哪个文件夹加载检测结果')
# 添加参数:嵌入文件夹名称
# 在项目/检测文件夹下从哪个子文件夹加载嵌入特征
parser.add_argument('--embs', type=str, default='osnet_x0_25_msmt17',
help='在项目/dets文件夹下从哪个子文件夹加载嵌入特征')
# 添加参数:允许覆盖
# 如果指定的项目/名称已存在,是否允许覆盖
parser.add_argument('--exist-ok', action='store_true', default=True,
help='如果项目/名称已存在,则允许覆盖,不递增名称')
# 添加参数:半精度推理
# 是否使用FP16半精度进行推理
parser.add_argument('--half', action='store_true',
help='使用FP16半精度进行推理')
# 添加参数:视频帧率步长
# 用于控制视频帧的采样频率
parser.add_argument('--vid-stride', type=int, default=1,
help='视频帧率的步长')
# 添加参数:是否显示标签
# 是否在显示时显示所有标签或仅显示边界框
parser.add_argument('--show-labels', action='store_false',
help='显示所有内容或仅显示边界框')
# 添加参数:是否显示置信度
# 在显示时是否隐藏置信度
parser.add_argument('--show-conf', action='store_false',
help='在显示时隐藏置信度')
# 添加参数:是否保存为txt文件
# 是否将跟踪结果保存为txt文件
parser.add_argument('--save-txt', action='store_true',
help='将跟踪结果保存为txt文件')
# 添加参数:是否保存ID对应的裁剪图像
# 是否将每个裁剪图像保存到其对应的ID文件夹下
parser.add_argument('--save-id-crops', action='store_true',
help='将每个裁剪图像保存到其对应的ID文件夹下')
# 添加参数:是否保存为MOT格式
# 是否将跟踪结果保存为MOT格式的单个txt文件
parser.add_argument('--save-mot', action='store_true',
help='将跟踪结果保存为MOT格式的单个txt文件')
# 添加参数:边界框线宽
# 边界框的线宽。如果为None,则根据图像大小进行缩放
parser.add_argument('--line-width', default=None, type=int,
help='边界框的线宽。如果为None,则根据图像大小进行缩放。')
# 添加参数:按类别追踪
# 在追踪时是否不混合类别
parser.add_argument('--per-class', default=False, action='store_true',
help='在追踪时是否不混合类别。')
# 添加参数:详细输出
# 是否打印每帧的结果
parser.add_argument('--verbose', default=True, action='store_true',
help='是否打印每帧的结果。')
# 添加参数:类别无关的非极大值抑制
# 是否使用类别无关的非极大值抑制
parser.add_argument('--agnostic-nms', default=False, action='store_true',
help='是否使用类别无关的非极大值抑制。')
# 添加参数:基准数据集
# 使用的基准数据集,如MOT16、MOT17或MOT20
parser.add_argument('--benchmark', type=str, default='MOT17',
help='使用的基准数据集,如MOT16、MOT17或MOT20。')
# 添加参数:数据集分割
# 使用的数据集分割,如train、test等
parser.add_argument('--split', type=str, default='train',
help='使用的数据集分割,如train、test等。')
opt = parser.parse_args()
return opt
def run_trackeval(opt):
"""
运行跟踪评估任务。
Args:
opt (argparse.Namespace): 包含任务配置选项的命名空间对象。
Returns:
dict: 跟踪评估结果的汇总字典。
"""
if opt is None:
# 如果没有提供选项参数,则解析命令行参数
opt = parse_opt()
# 根据检测、嵌入和跟踪方法构建实验文件夹路径
exp_folder_path = opt.project / (str(opt.dets) + "_" + str(opt.embs) + "_" + str(opt.tracking_method))
# 如果路径已存在,则自动增加序号以创建新路径
exp_folder_path = increment_path(path=exp_folder_path, sep="_", exist_ok=opt.exist_ok)
# 更新选项中的实验文件夹路径
opt.exp_folder_path = exp_folder_path
else:
# 如果提供了选项参数,则直接使用它,并设置exist_ok为False,不自动增加路径序号
opt = opt
opt.exist_ok = False
# 定义验证工具的路径
val_tools_path = EXAMPLES / 'val_utils'
# 下载MOT评估工具
download_mot_eval_tools(val_tools_path)
# 下载MOT数据集
zip_path = download_mot_dataset(val_tools_path, opt.benchmark)
# 解压MOT数据集
unzip_mot_dataset(zip_path, val_tools_path, opt.benchmark)
# 设置评估环境,包括序列路径、保存目录、结果文件夹和真实标签文件夹
seq_paths, save_dir, MOT_results_folder, gt_folder = eval_setup(opt, val_tools_path)
# 运行跟踪评估任务
results = trackeval(opt, seq_paths, save_dir, MOT_results_folder, gt_folder)
# 解析MOT评估结果
combined_results = parse_mot_results(results)
# 打印汇总结果
print(combined_results)
# 返回汇总结果
return combined_results