多目标跟踪-DeepSort分析(一)论文解读及代码架构

5 篇文章 0 订阅
3 篇文章 0 订阅

先引入多目标跟踪DeepSort的论文地址及代码链接(Python版):

论文地址:https://arxiv.org/pdf/1703.07402.pdf

代码链接:https://github.com/nwojke/deep_sort

写在前面:

    这些天看了deepsort的论文及源码,并在网上检索一些相关资料(不是很多),现结合论文、博客及自己的理解进行总结。
    本文为第一篇,首先对论文进行解读,然后对github的代码进行简要的流程分析及解读,后期还会对所用算法进行具体的展开。
    
    本文结构:
        一、论文重点部分解读
        二、代码流程及算法分析

1. 论文重点部分解读

1.1. 轨迹处理及状态估计(track handing and state estimation)

第i时刻的状态用8维状态空间表示:
1
其中,u,v表示目标框的中心坐标;
γ,h(第三和第四个值)表示宽高比(宽高比应该为一个常量)、高度;
以上四个值构成观测变量。
以及图像坐标系下的速度(导数)

对于每条轨迹 k 都有一个阈值a用于记录轨迹从上一次成功匹配到当前时刻的时间。当该值大于提前设置的阈值 Amax 则认为改轨迹终止,直观上说就是长时间匹配不上的轨迹认为已经结束。
轨迹的三种状态:(在代码中定义为枚举变量)
tentative(初始默认状态)
confirmed
deleted

enum TrackState
{
     Tentative = 1
     Confirmed = 2
     Deleted = 3
}

在匹配时,对于没有匹配成功的检测都认为可能产生新的轨迹。但由于这些检测结果可能是一些错误警告,所以:
对这种新生成的轨迹标注状态 tentative (初始默认状态);
然后判定在接下来的连续3帧中是否连续匹配成功,若成功,则标注为 confirmed ,认为是新轨迹产生;
否则,标注为 deleted,删除 。另外,超过预先设置的Amax = 30 的轨迹,也被认为离开场景,并标注为 deleted,删除 。

        if self.state == TrackState.Tentative:
            self.state = TrackState.Deleted
        elif self.time_since_update > self._max_age:
            self.state = TrackState.Deleted

1.2分配(匹配)问题(assignment problem)

这里的匹配,是只当前被标注为“ confirmed ”的轨迹(即有效轨迹)与当前的检测之间的匹配。
使用匈牙利算法进行目标框的匹配;
使用运动匹配和外观匹配对目标框进行匹配。

1.2.1运动匹配

用Mahalanobis距离(马氏距离)来表示第j个检测和第i条轨迹之间的运动匹配程度。公式如下图所示:
1
其中,
dj表示第j个检测的状态;
yi是轨迹在当前时刻的预测值;
si是轨迹,由kalman滤波器预测得到的;
通过该马氏距离对检测框进行筛选,使用卡方分布的0.95分位点作为阈值。

1.2.2外观匹配

在实际中,比如相机运动,都会导致马氏距离匹配失效,因此引入余弦距离(第i次跟踪和第j次检测的最小余弦距离)来进行外观匹配,该匹配对长时间遮挡后恢复尤其有用,公式如下:
1

最后,利用加权的方式对这两个距离进行融合。关联度量的总公式如下所示:
1
其中,λ设置为0(论文中)。

1.3级联匹配(matching cascade)

 //# Run matching cascade.
 typedef std::vector<int> IDS;
 
 struct RR
{
    std::vector<std::pair<int, int>> matches;
    IDS unmatched_detections; 
    IDS unmatched_tracks;
};
 RR _match(const std::vector<Detection> &detections)
    {
        int64_t mtm1 = line_gtm();
        //Split track set into confirmed and unconfirmed kalmanTrackers.
        IDS confirmed_trackIds;
        IDS unconfirmed_trackIds;
        for (int i = 0; i < kalmanTrackers_.size(); i++)
        {
            KalmanTracker t = kalmanTrackers_[i];
            if (t->is_confirmed())
            {
                confirmed_trackIds.push_back(i);
            }
            else
            {
                unconfirmed_trackIds.push_back(i);
            }
        }

        //# Associate confirmed kalmanTrackers using appearance features.
        RR rr = linear_assignment::matching_cascade(
            getCostMatrixByNND,
            NearestNeighborDistanceMetric::Instance()->matching_threshold(),
            max_age_,
            kalmanTrackers_,
            detections,
            &confirmed_trackIds);
        std::vector<std::pair<int, int>> matches_a = rr.matches;
        IDS unmatched_tracks_a = rr.unmatched_tracks;
        IDS unmatched_detections = rr.unmatched_detections;

        int64_t mtm2 = line_gtm();

        //# Associate remaining kalmanTrackers together with unconfirmed kalmanTrackers using IOU.
        IDS iou_track_candidateIds, tmp;
        std::copy(unconfirmed_trackIds.begin(),
                  unconfirmed_trackIds.end(),
                  std::back_inserter(iou_track_candidateIds));
        for (int k = 0; k < unmatched_tracks_a.size(); k++)
        {
            int id = unmatched_tracks_a[k];
            if (kalmanTrackers_[id]->time_since_update_ == 1)
            {
                iou_track_candidateIds.push_back(id);
            }
            else
            {
                tmp.push_back(id);
            }
        }
        unmatched_tracks_a.clear();
        unmatched_tracks_a = tmp;

        int64_t mtm3 = line_gtm();
        
        RR rr1 = linear_assignment::min_cost_matching(
            iou_matching::getCostMatrixByIOU,
            max_iou_distance_,
            kalmanTrackers_,
            detections,
            &iou_track_candidateIds,
            &unmatched_detections);
        std::vector<std::pair<int, int>> matches_b = rr1.matches;
        IDS unmatched_tracks_b = rr1.unmatched_tracks;
        unmatched_detections = rr1.unmatched_detections;

        int64_t mtm4 = line_gtm();
        
        RR re;
        re.matches = matches_a;
        std::copy(matches_b.begin(), matches_b.end(),
                  std::back_inserter(re.matches));
        re.unmatched_detections = unmatched_detections;
        re.unmatched_tracks = unmatched_tracks_a;
        std::copy(unmatched_tracks_b.begin(),
                  unmatched_tracks_b.end(),
                  std::back_inserter(re.unmatched_tracks));
        int64_t mtm5 = line_gtm();
        return re;
    }

    int _NewTrack(const Detection &detection)
    {
        int id = _next_id_;
        std::pair<MEAN, VAR> pa =
            KF::Instance()->initiate(detection.to_xyah());
        KalmanTracker newt(new KalmanTrackerN(
            pa.first, pa.second, _next_id_, n_init_, max_age_,
            detection.feature_, true, detection.oriPos_));
        kalmanTrackers_.push_back(newt); 
        _next_id_ += 1;
        return id;
    }
};
RR rr = this->_match(detections);

当一个目标被遮挡很长时间,Kalman滤波的不确定性就会大大增加,为了解决该问题 ,论文采用级联匹配的策略来提高匹配精度。文中算法如下图所示:
1
其中,T表示目标跟踪集合
D表示目标检测集合
C矩阵存放所有目标跟踪与目标检测之间距离的计算结果
B矩阵存放所有目标跟踪与目标检测之间是否关联的判断(0或者1)
M,U为返回值,分别表示匹配集合和非匹配集合。

1.4深度表观特征(deep appearance descriptor)

论文中,作者用一个深度卷积神经网络去提取目标的特征信息,论文中的预训练的网络是在一个ReID的大数据集上训练得到的,包含1261个人的1100000幅图像,非常适合对人物目标跟踪。
网络结构如下:
CNN
该网络有2,800,864参数和32个目标框,在NVIDIA GTX1050上需要30ms。

2.代码流程及算法分析(待补充)

2.1detection

检测基类。

2.2HungarianOper

匈牙利指派,采用的是匈牙利算法/Hungrain/带权重的二分图指派算法Munkres Alogrithm。

2.3iou_matching

IOU匹配模块。(Iou–重叠区域面积)

2.4kalman_filter

卡尔曼滤波器,该模块实现图像空间的目标状态的预测/创建及移除,即滤波的具体参数化。

2.5linear_assignment

线性匹配–用最小的cost-matirx匹配级联。考虑了运动信息和外观信息。

for (int row = 0; row < track_indices.size(); row++)
        {
            int track_idx = track_indices[row];
            KalmanTracker track = tracks[track_idx];
 //计算detection中边框 dj(u,v,r,h)dj​(u,v,r,h)和Track中的边框 yiyi​之间的马氏距离
//计算 predicted Kalman states 和newly arrived measurements之间的马氏距离
Eigen::Matrix<float, 1, -1> gating_distance = kalmanFilter.gating_distance(
              track->mean_, track->covariance_, measurements, only_position);
          for (int i = 0; i < gating_distance.cols(); i++)
          // gating_distance is a vector
          {
              if (gating_distance(0, i) > gating_threshold)
              {
                  cost_matrix(row, i) = gated_cost;
              }
          }
      }
      return cost_matrix;

2.6nn_matching

最近邻匹配模块。

2.7tracker

目标跟踪。

  • 6
    点赞
  • 85
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
### 回答1: 非常感谢您的提问。我可以回答这个问题。以下是一个基于DeepSORT多目标跟踪代码的Python实现: https://github.com/nwojke/deep_sort 这个代码库包含了一个深度学习模型,可以用于多目标跟踪。它使用了卷积神经网络来提取特征,并使用了一种称为“卡尔曼滤波”的技术来预测目标的位置。这个代码库还包含了一些实用工具,比如可视化工具和数据集处理工具,可以帮助您更好地理解和使用这个模型。 希望这个回答能够帮助到您。如果您有任何其他问题,请随时问我。 ### 回答2: DeepSORT是一种用于多目标跟踪的深度学习算法,它结合了目标检测和目标跟踪的技术。在使用Python编写基于DeepSORT多目标跟踪代码时,你可以按照以下步骤进行操作: 1. 导入所需的Python库,例如OpenCV、NumPy和Tensorflow等。这些库将提供必要的功能和工具来处理图像和运行深度学习模型。 2. 下载或构建一个训练好的目标检测模型,例如YOLOv3或Faster R-CNN,并加载它们到代码中。这些模型能够检测图像中的目标并提取相关特征。 3. 加载保存的DeepSORT模型。这个模型负责跟踪已检测到的目标,并在每个时间步更新目标的位置和属性。 4. 运行一个实时视频流或读取一个视频文件作为输入。使用OpenCV的VideoCapture库从摄像头或文件中读取帧。 5. 对每个帧执行以下操作: - 对帧进行目标检测,获取目标的边界框和相关特征。 - 使用DeepSORT算法跟踪目标,更新目标的位置和属性。 - 绘制目标边界框和轨迹,并在结果视频中显示出来。 6. 处理完所有帧后,保存结果视频或显示最终的多目标跟踪输出。 需要注意的是,上述步骤只是一个简单的基本框架,你可能需要进一步调整代码来适应特定的数据集和任务。此外,你还可以添加其他功能,例如数据关联、目标去重和目标识别等来进一步提升多目标跟踪的准确性和鲁棒性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值