详解MOT多目标跟踪评价指标及计算代码

作者 | 的泼墨佛给克呢  编辑 | 汽车人

原文链接:https://zhuanlan.zhihu.com/p/405983694

点击下方卡片,关注“自动驾驶之心”公众号

ADAS巨卷干货,即可获取

点击进入→自动驾驶之心【目标跟踪】技术交流群

后台回复【目标跟踪综述】获取单目标、多目标、基于学习方法的领域综述!

介绍

多目标跟踪的评价指标有很多,本文就来详细汇总解释一下,并使用介绍了用于计算这些指标的py-motmetrics库的使用方法。由于自己刚入门MOT领域,本文只是基于自己目前的理解,如有错误请指正。在MOTChallenge中,有下面这些常用的指标:

8654df94ffda70db0a3d867813effc9d.png

总览如下:

6030b5b989581baaf6db80154bc58616.png

基础

要理解这些指标,首先回顾一下在分类和检测任务中常见的几种基本概念

  • GT:Ground Truth,是指真实的标签或真实的对象

  • TP:真正(True Positive)是指被模型预测为正的正样本(或被检测出来的GT)

  • TN:真负(True Negative)是指被模型预测为负的负样本。

  • FP:假正(False Positive,)是指被模型预测为正的负样本,也称为误报。

  • FN:假负(FALSE Negative,)是指被模型预测为负的正样本,也称为漏报。

后面四个概念很容易混淆,怎么记忆呢,可以把第一个字母看成是模型是否预测正确(对T或错F),把第二个字母看成是标签(正样本P和负样本N)。这些概念在分类任务里面的含义十分清楚,在检测任务中可以用下图来帮助理解:

c3d45ac5d161452074eff59169ca06a7.png

最左边的图中有个企鹅,而且被检测出来了,是我们希望的;中间图是背景,但也被错误地检测出来了,误报;最右边有企鹅但没有检测出来,漏报。在检测任务中TN没有啥意义,因为背景中的任何地方都可以看作是负样本,我们也不希望模型关注背景。其实在MOT中,这些概念与在检测任务中的差不多,毕竟Detection-Based Tracking(基于检测的跟踪)的第一步就是检测。

由这几个概念又可以推导出下面几个指标:

  • Accuracy:准确度是指被分类器判定正确的比重,这个指标就太简单了,其实就是分类正确的例子占总数的比例:

20c43170a153cdf2933a3213e7274a0e.png
  • Precision:精确度是指被分类器判定的正例中真正的正例样本的比重:

175b8deefc34d54c69d03a3cacd243d3.png
  • Recall:召回率是指被分类器正确判定的正例占总的正例的比重:

fe73157b1e3f2e0ba9c8a7bb0dacd70e.png

MOT指标

接下来会按时间顺序分三个种类来介绍MOT指标,我是照搬了[1]中的分类方式,感兴趣的可以看原论文。其中在MOTChallenge中出现的指标我会强调显示。

Classical metrics

  • MT:Mostly Tracked trajectories,成功跟踪的帧数占总帧数的80%以上的GT轨迹数量

  • Fragments:碎片数,成功跟踪的帧数占总帧数的80%以下的预测轨迹数量

  • ML:Mostly Lost trajectories,成功跟踪的帧数占总帧数的20%以下的GT轨迹数量

  • False trajectories:预测出来的轨迹匹配不上GT轨迹,相当于跟踪了个寂寞

  • ID switches:因为跟踪的每个对象都是有ID的,一个对象在整个跟踪过程中ID应该不变,但是由于跟踪算法不强大,总会出现一个对象的ID发生切换,这个指标就说明了ID切换的次数,指前一帧和后一帧中对于相同GT轨迹的预测轨迹ID发生切换,跟丢的情况不计算在ID切换中。

a68245889b3c4351c6e06abce532ae96.png

注意上图中箭头的指向,是红色线还是蓝色线。

CLEAR MOT metrics

  • FP:总的误报数量,即整个视频中的FP数量,即对每帧的FP数量求和

  • FN:总的漏报数量,即整个视频中的FN数量,即对每帧的FN数量求和

  • Fragm(FM):总的fragmentation数量,every time a ground truth object tracking is interrupted and later resumed is counted as a fragmentation,注意这个指标和Classical metrics中的Fragments有点不一样

  • IDSW:总的ID Switch数量,即整个视频中的ID Switch数量,即对每帧发生的ID Switch数量求和,这个和Classical metrics中的ID switches基本一致

  • MOTA:注意MOTA最大为1,由于IDSW的存在,MOTA最小可以为负无穷。

b83e52a79ec720d2b1f8ec2a594b128c.png
  • MOTP:衡量跟踪的位置误差,其中t表示第t帧, 表示第t帧中预测轨迹和GT轨迹成功匹配上的数目, 表示t帧中第i个匹配对的距离。这个距离可以用IOU或欧式距离来度量,IOU大于某阈值或欧氏距离小于某阈值视为匹配上了。可以看出来MOTP这个指标相比于评估跟踪效果,更注重检测质量。

d32442c4a796136c10ca80444c8a2c04.png

ID scores

MOTA的缺点如下图描述:

9a682690f5b1399d700bfca35ca4fb0b.png

有如上三个跟踪器,对于GT轨迹A的跟踪效果如图显示。在(a)中有2个fragments,在(b)(c)中有8个。在(a)(b)中预测轨迹1占据了4/6的帧数,而在(c)中占据了5/6的帧数。由于(c)的IDSW会更多,它的MOTA指标会更低。但(c)中匹配时间要更长一些,如果我们关注跟踪时长的话,显然(c)这个跟踪器会更好一些,于是ID scores就被提出来了。总之,MOTA的主要问题是它考虑了跟踪器做出错误决定的次数,比如IDSW。而在某些情况下不想丢失跟踪对象的位置,我们更关心这个跟踪器跟踪某个对象的时间长短。因此,ID scores被提出,它们是在介绍MTMC的一篇论文中被提出的。

但目前的问题是如何将GT和预测出来的轨迹匹配上,比如(a)中为何不将GT与预测轨迹2匹配来算出正确跟踪时间是2/6 ?因此,我们希望将每一个GT与一个计算轨迹匹配起来,并最小化所有GT轨迹和计算轨迹的不匹配帧数(FP+FN的数量),可以建立一个二分匹配问题来解决。然后ID scores相关指标都基于匹配的结果来进行计算。具体的二分匹配问题如下:

a6cacc3a369286456d891556def806a9.png

具体的举例如下

08f57f2923f1d3e74c373c634abeb3c4.png

根据这几个概念又可以推导出以下三个指标,其中前两个指标的公式和前文中提到的精确度和召回率差不多

  • IDP:Identification precision

9ad68c9d03f0c04613d80c463a568b80.png
  • IDR:Identification recall

668062a90ca7b4bfd33bacb54008a6c7.png
  • IDF1:Identification F1,是IDP和IDR的调和均值

88a875d179c95ad76d3d0d3157ff2362.png

其他指标

  • RecallPrecision:计算公式同基础中的介绍

  • 待补充

具体过程

MOT评价指标的计算一般分为两步:

  1. 将真实和计算的ID一一映射对应(Mapping true and computed identities)

  2. 在这种对应下计算再具体指标(Computing a score on top of the mapping)

如前文中ID scores节的介绍:第一步一般是构建一个二分图,左侧节点包含真实ID(和FP),右侧节点包含计算ID(和FN),如果两个ID对应,则边上的成本为错误分配的帧数。然后使用最小成本二分匹配寻找最佳对应。找到对应后再计算具体指标。

Clear MOT指标和ID指标的区别:

  • Clear MOT指标映射通常是多对多,而ID指标依赖于一对一关系。

  • Clear MOT的多对多映射允许存在IDSW,而ID指标中没有IDSW的概念。

  • 当计算出的ID正确切换回其原始真实ID时(比如在遮挡后),MOTA和FRG仍会将其计为错误。

  • Clear MOT指标映射没有优化全局目标,而ID指标中的映射找到二分图的最优匹配,最大化IDF1。

  • Clear MOT指标在应用于不相交的摄像机时存在问题,因为它对每个摄像机中离开\进入的情况敏感,而ID指标不受此问题的影响,因为ID映射时全局的。

代码(py-motmetrics的使用方式)

调用别人写好的轮子,即py-motmetrics库:

https://github.com/cheind/py-motmetrics

安装方式:

pip install motmetrics

使用这个库的流程就是,先导入两个txt文件(分别是GT和自己生成的结果,且都是标准的MOTChallenge格式,具体格式在MOTChallenge网站上有详细介绍),再创建accumulator,然后逐帧将每帧的GT和自己跟踪的结果(用hypotheses表示)填充至该accumulator中,然后使用度量器计算即可得到字符串summary,里面就是计算的结果,再将summary打印出来即可。

创建accumulator并填充

首先介绍一下不导入txt文件,直接使用自己定义的数组来创建accumulator并填充

import motmetrics as mm  # 导入该库
import numpy as np

metrics = list(mm.metrics.motchallenge_metrics)  # 即支持的所有metrics的名字列表
"""
['idf1', 'idp', 'idr', 'recall', 'precision', 'num_unique_objects', 'mostly_tracked', 'partially_tracked', 'mostly_lost', 'num_false_positives', 'num_misses', 'num_switches', 'num_fragmentations', 'mota', 'motp', 'num_transfer', 'num_ascend', 'num_migrate']
"""

acc = mm.MOTAccumulator(auto_id=True)  #创建accumulator

# 用第一帧填充该accumulator
acc.update(
    [1, 2],                     # Ground truth objects in this frame
    [1, 2, 3],                  # Detector hypotheses in this frame
    [
        [0.1, np.nan, 0.3],     # Distances from object 1 to hypotheses 1, 2, 3
        [0.5,  0.2,   0.3]      # Distances from object 2 to hypotheses 1, 2, 3
    ]
)

# 查看该帧的事件
print(acc.events) # a pandas DataFrame containing all events
"""
                Type  OId HId    D
FrameId Event
0       0        RAW    1   1  0.1
        1        RAW    1   2  NaN
        2        RAW    1   3  0.3
        3        RAW    2   1  0.5
        4        RAW    2   2  0.2
        5        RAW    2   3  0.3
        6      MATCH    1   1  0.1
        7      MATCH    2   2  0.2
        8         FP  NaN   3  NaN
"""

# 只查看MOT事件,不查看RAW
print(acc.mot_events) # a pandas DataFrame containing MOT only events
"""
                Type  OId HId    D
FrameId Event
0       6      MATCH    1   1  0.1
        7      MATCH    2   2  0.2
        8         FP  NaN   3  NaN
"""

# 继续填充下一帧
frameid = acc.update(
    [1, 2],  # GT
    [1],     # hypotheses
    [
        [0.2],
        [0.4]
    ]
)
print(acc.mot_events.loc[frameid])
"""
        Type OId  HId    D
Event
2      MATCH   1    1  0.2
3       MISS   2  NaN  NaN
"""

# 继续填充下一帧
frameid = acc.update(
    [1, 2], # GT
    [1, 3], # hypotheses
    [
        [0.6, 0.2],
        [0.1, 0.6]
    ]
)
print(acc.mot_events.loc[frameid])
"""
         Type OId HId    D
Event
4       MATCH   1   1  0.6
5      SWITCH   2   3  0.6
"""

再介绍一下导入txt文件来创建accumulator并填充

gt_file="/path/gt.txt"
"""  文件格式如下
1,0,1255,50,71,119,1,1,1
2,0,1254,51,71,119,1,1,1
3,0,1253,52,71,119,1,1,1
...
"""

ts_file="/path/test.txt"
"""  文件格式如下
1,1,1240.0,40.0,120.0,96.0,0.999998,-1,-1,-1
2,1,1237.0,43.0,119.0,96.0,0.999998,-1,-1,-1
3,1,1237.0,44.0,117.0,95.0,0.999998,-1,-1,-1
...
"""

gt = mm.io.loadtxt(gt_file, fmt="mot15-2D", min_confidence=1)  # 读入GT
ts = mm.io.loadtxt(ts_file, fmt="mot15-2D")  # 读入自己生成的跟踪结果

acc=mm.utils.compare_to_groundtruth(gt, ts, 'iou', distth=0.5)  # 根据GT和自己的结果,生成accumulator,distth是距离阈值

创建度量器并计算

mh = mm.metrics.create()

# 打印单个accumulator
summary = mh.compute(acc,
                     metrics=['num_frames', 'mota', 'motp'], # 一个list,里面装的是想打印的一些度量
                     name='acc') # 起个名
print(summary)
"""
     num_frames  mota  motp
acc           3   0.5  0.34
"""

# 打印多个accumulators
summary = mh.compute_many([acc, acc.events.loc[0:1]], # 多个accumulators组成的list
                          metrics=['num_frames', 'mota', 'motp'], 
                          name=['full', 'part']) # 起个名
print(summary)
"""
      num_frames  mota      motp
full           3   0.5  0.340000
part           2   0.5  0.166667
"""

将summary转为自己想要的显示格式

# 自定义显示格式
strsummary = mm.io.render_summary(
    summary,
    formatters={'mota' : '{:.2%}'.format},  # 将MOTA的格式改为百分数显示
    namemap={'mota': 'MOTA', 'motp' : 'MOTP'}  # 将列名改为大写
)
print(strsummary)
"""
      num_frames   MOTA      MOTP
full           3 50.00%  0.340000
part           2 50.00%  0.166667
"""

# mh模块中有内置的显示格式
summary = mh.compute_many([acc, acc.events.loc[0:1]],
                          metrics=mm.metrics.motchallenge_metrics,
                          names=['full', 'part'])

strsummary = mm.io.render_summary(
    summary,
    formatters=mh.formatters,
    namemap=mm.io.motchallenge_metric_names
)
print(strsummary)
"""
      IDF1   IDP   IDR  Rcll  Prcn GT MT PT ML FP FN IDs  FM  MOTA  MOTP
full 83.3% 83.3% 83.3% 83.3% 83.3%  2  1  1  0  1  1   1   1 50.0% 0.340
part 75.0% 75.0% 75.0% 75.0% 75.0%  2  1  1  0  1  1   0   0 50.0% 0.167
"""

总结

通常,几乎别人论文中报告的指标都是CLEAR MOT metrics中的所有指标,再加上MT、ML和IDF1。此外,跟踪器可以处理的每秒帧数(FPS)经常被报告,然而,这种度量很难在不同的算法之间进行比较,因为有些方法包括检测阶段的计算,而另一些方法跳过了该计算,而且该指标与使用的硬件有关。

附加内容(关于代码运行)

因为有很多人在评估时出了问题,因此我新建了一个github仓库,给出了一些数据格式和代码解释,也可以直接跑,结果是正常的。这个库的说明还是比较全面的,应该能解决评论区的大部分问题。如果有其他问题可以在这个库里提issue,附链接:

https://github.com/ddz16/py-motmetrics

References

  1. DEEP LEARNING IN VIDEO MULTI-OBJECT TRACKING: A SURVEY

  2. Multi-Target Multi-Camera Tracking评价指标

https://zhuanlan.zhihu.com/p/35391826

  1. 深入理解MOT评价指标

https://blog.csdn.net/jackzhang11/article/details/110456883

  1. MOT Metrics—MOTA vs IDF1?

https://blog.csdn.net/qq_42191914/article/details/105057117

  1. ID measures for Multi-Target Tracking

web.archive.org/web/20190413133409/http://vision.cs.duke.edu:80/DukeMTMC/IDmeasures.html

  1. MOT多目标跟踪评价指标代码py-motmetrics

https://blog.csdn.net/sleepinghm/article/details/119538354

  1. py-motmetrics官方库

GitHub - cheind/py-motmetrics: Benchmark multiple object trackers (MOT) in Python

(一)视频课程来了!

自动驾驶之心为大家汇集了毫米波雷达视觉融合、高精地图、BEV感知、多传感器标定、传感器部署、自动驾驶协同感知、语义分割、自动驾驶仿真、L4感知、决策规划、轨迹预测等多个方向学习视频,欢迎大家自取(扫码进入学习)

ab6cb560e8006455ffbb1401b7a4d37c.png

(扫码学习最新视频)

视频官网:www.zdjszx.com

(二)国内首个自动驾驶学习社区

近1000人的交流社区,和20+自动驾驶技术栈学习路线,想要了解更多自动驾驶感知(分类、检测、分割、关键点、车道线、3D目标检测、Occpuancy、多传感器融合、目标跟踪、光流估计、轨迹预测)、自动驾驶定位建图(SLAM、高精地图)、自动驾驶规划控制、领域技术方案、AI模型部署落地实战、行业动态、岗位发布,欢迎扫描下方二维码,加入自动驾驶之心知识星球,这是一个真正有干货的地方,与领域大佬交流入门、学习、工作、跳槽上的各类难题,日常分享论文+代码+视频,期待交流!

afde7fe100547d1b6f58a1b6ed65888b.jpeg

(三)自动驾驶之心】全栈技术交流群

自动驾驶之心是首个自动驾驶开发者社区,聚焦目标检测、语义分割、全景分割、实例分割、关键点检测、车道线、目标跟踪、3D目标检测、BEV感知、多传感器融合、SLAM、光流估计、深度估计、轨迹预测、高精地图、NeRF、规划控制、模型部署落地、自动驾驶仿真测试、产品经理、硬件配置、AI求职交流等方向;

daf74c15b5ed156aa7876279ebd082b2.jpeg

添加汽车人助理微信邀请入群

备注:学校/公司+方向+昵称

  • 4
    点赞
  • 57
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
对于多目标优化问题的评价指标,可以使用以下代码进行计算: ```python import numpy as np from pymotmetrics import metrics # 定义真实帕累托前沿的参考点集合P P = np.array(\[\[1, 2\], \[3, 4\], \[5, 6\]\]) # 定义算法求解得到的非占优解集合X X = np.array(\[\[1.5, 2.5\], \[3.5, 4.5\], \[5.5, 6.5\]\]) # 计算超体积度量(Hypervolume, HV) hv = metrics.hypervolume(X, P) print("HV指标值:", hv) # 计算得到的非占优解集与真实帕累托前沿之间的度量(Inverted Generational Distance, IGD) igd = metrics.igd(X, P) print("IGD指标值:", igd) # 计算二元指标Coverage metric指标 coverage = metrics.coverage(X, P) print("Coverage指标值:", coverage) ``` 这段代码使用了`pymotmetrics`库来计算多目标优化问题的评价指标。其中,`P`表示真实帕累托前沿的参考点集合,`X`表示算法求解得到的非占优解集合。通过调用`metrics.hypervolume`、`metrics.igd`和`metrics.coverage`函数,分别可以计算超体积度量(HV)、得到的非占优解集与真实帕累托前沿之间的度量(IGD)和二元指标Coverage metric指标的值。 请注意,以上代码仅为示例,实际使用时需要根据具体情况进行调整和修改。 #### 引用[.reference_title] - *1* [多目标粒子群优化算法matlab_多目标优化算法 — 8个常用的评估指标](https://blog.csdn.net/weixin_39775127/article/details/110240608)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [多目标优化算法的性能指标_简介](https://blog.csdn.net/zhangkkit/article/details/105947834)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [详解MOT多目标跟踪评价指标计算代码](https://blog.csdn.net/CV_Autobot/article/details/131027819)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值