文章目录
- 前言
- 一、判定遮挡目标
- 二、扩展目标框
- 三、结论
前言
- 目标跟踪在发生遮挡时,极其容易发生Id Switch。
- 网上许多算法忽视跟踪遮挡问题,同时网上相关资料也很少。
- 博主为了解决跟踪遮挡,翻阅大量论文。分享其中一篇论文。论文链接:https://arxiv.org/abs/2103.04147
- 论文介绍了一种思路,但是未提供代码,博主根据论文思路编写了相关代码。验证后发现,效果好得出乎意料。
- 阅读本文需要一定跟踪的基础。如果是新手建议先阅读博主往期博客【目标跟踪】多目标跟踪测距:https://blog.csdn.net/qq_49560248/article/details/134016802
一、判定遮挡目标
要处理遮挡问题,我们先明确什么是遮挡目标,方便与我们后面针对性处理。
- 目标未与新检测目标匹配,此时的目标是预测的目标且没有与新检测的目标匹配上。
- 存在其他目标,在相机与遮挡目标中间
当同时符合上述两个条件时,会判定为遮挡目标
为了判定是否为遮挡目标,我们定义了两个关键的量。
- Ci 目标 i 遮挡置信度
- CPi 目标 i 被覆盖的比例
Ci = min(1, a * (Age / t) * (Ai / Aavg))
a:可调参数,可以默认为1
Age:id 起始帧到当前帧的帧数。如 id 在第 2 帧首次出现,当前第 10 帧还存在,那么 Age = 8
t: 从上一次更新起 连续预测次数。如 目标 i 在第 1 帧匹配了,在第 2 帧未匹配,此时 t = 1,在第 3 帧 匹配上,此时 t = 0。如果是匹配上的目标,不在我们遮挡目标讨论范围内,就不会进入计算 Ci 范围内。
Ai: 目标 i box的面积 box.width * box.height
Aavg: 当前帧所有目标 box 的平均面积
CPi = I(bbi, bbj) / A(bbi)
I(bbi, bbj): 目标 i box 与 目标 j box 的交集
A(bbi): 目标 i box 面积
当 Ci 大于设定值,同时 CPi 大于设定值,则此时目标判定为遮挡目标
for (auto umt:unMatch) {
// 目标置信度 Ci
cv::Rect_<float> trackerBox = trackers[umt].kBox.GetState();
float confidence = (trackers[umt].kBox.mAge / trackers[umt].kBox.mTimeSinceUpdate) * GetBoxArea(trackerBox) / boxAvg;
float maxCoverPercent = 0;
for (int i = 0; i < detNum; i++) {
float percent = GetCoverPercent(trackerBox, deData[i].box); // 覆盖百分比
if (percent > maxCoverPercent) {
maxCoverPercent = percent;
}
}
/* 当 跟踪目标置信度>mTrackConfidence和覆盖百分比>mCoverPercent时, 标记为遮挡目标此时计算扩展目标框 */
if (confidence > mTrackConfidence && maxCoverPercent > mCoverPercent) {
trackers[umt].whetherCover = true;
trackers[umt].kBox.kf.statePost.at<float>(7, 0) = trackers[umt].kBox.kf.statePost.at<float>(7, 0) / 2; // 遮挡目标速率减半
continue;
}
注:代码中有一行遮挡目标面积速率减半,是因为目标在遮挡时那一帧,目标 box 面积会急速变小,除以 2 是为了补偿这个速率。实际效果算是锦上添花。
二、扩展目标框
当目标判定为遮挡目标时,我们才会计算该目标的扩展框
扩展IOU的计算公式
回顾下传统 IOU 计算公式
上述 IOUext 与 IOU 计算 差别 就在于 bbextT(扩展目标框)
现在问题是 bbextT 如何计算呢?
观察红色框与虚线框,红色框是卡尔曼预测框,虚线框就是我们的扩展目标框
当预测的帧数+1,则此时扩展目标框会有一定比例的扩大。由于论文仅仅提供思路,没有说明具体数值,代码也未提供。我是根据实际的数据调试。
if (pBox.whetherCover == true) {
// 如果是遮挡目标, 预测框需要保存扩展框
float ePixe = pBox.box.width * boxExpandScale * (*it).kBox.mTimeSinceUpdate; // boxExpandScale设定的 0.2
pBox.expansionBox = pBox.box + cv::Point_<float>(-ePixe, -ePixe) + cv::Size_<float>(2 * ePixe, 2 * ePixe);
}
如果是遮挡目标,此时用扩展IOU计算匹配矩阵的目标权重
float GetExpansionIou(cv::Rect_<float> boxD, cv::Rect_<float> boxT, cv::Rect_<float> boxExpand)
{
// boxD:检测框, boxT:跟踪框, boxExpand:扩展框
float in = (boxD & boxExpand).area(); // 检测框与扩展框交集面积
float un = boxD.area() + boxT.area() - in;
float result = in / un;
if (result > 1) {
result = 1; // 当iou >1 时赋值为1
}
return result * mExpansionIou;
}
三、结论
- 实际数据测试,在 10 - 20m 的遮挡目标,解决 超过 50% 的 id switch问题