BYTETrack C++源码解析(BYTETracker.cpp)

 BYTETracker.h

在BYTETracker.h头文件中定义了BYTETracker类。

私有变量

track_thresh:用于区分出高置信度和低置信度检测框,默认0.5;

high_thresh:在cpp文件中的Step4,用于筛选前两次未匹配的检测框,默认0.6;

match_thresh:在cpp文件中Step2第一次匹配高置信度目标时的iou阈值,默认0.8,及iou大于0.2为匹配上;

frame_id:视频第几帧;

max_time_lost:最大失踪次数,Step5中对大于这个次数的失跟踪轨迹(lost_stracks中)标记为remove,并加入remove_stracks中;

tracked_stracks:状态为Tracked的轨迹;

lost_stracks:状态为Lost的轨迹,丢失目标的跟踪轨迹,即失踪轨迹;

removed_stracks:状态为Removed的轨迹,删除的跟踪轨迹;

kalman_filter:卡尔曼滤波器实例。

公有变量/方法

joint_stracks

sub_stracks

remove_duplicate_stracks:

linear_assignment

iou_distance

lapjv

BYTETracker.cpp

Tracked状态表示上一帧匹配到目标的轨迹;

Lost状态表示上一帧没有匹配到目标的轨迹;

Removed状态表示连续丢失目标this->max_time_lost次的轨迹;

在cpp文件中主要实现了构造函数和析构函数,以及BYTETracker::update函数,在cpp文件中定义了一系列局部变量:

activated_stracks:激活状态的跟踪轨迹(状态为Tracked,Step4中中途出现的目标为非激活);

refind_stracks:在Step2和Step3中匹配上的轨迹里不是Tracked状态的轨迹,上一帧中没有匹配上的轨迹在当前帧中匹配到目标的轨迹(状态为变为Tracked,激活);

removed_stracks:删除的跟踪轨迹;

lost_stracks:失踪轨迹,存放的是在Step2和Step3中(高低置信度目标)没有匹配上的轨迹,被标记为Lost状态;

detections:置信度高于track_thresh的检测目标;

detections_low:置信度低于track_thresh的检测目标;

detections_cp:Step3中将Step2中umatched高置信度检测目(detections)标放入detections_cp;

tracked_stracks_swap:Step5中将this->tracked_tracks中状态为Tracked的轨迹放入,并将内容重新放入this->tracked_tracks中,保证this->tracked_tracks中轨迹的状态全部为Tracked

resa,resb

output_stracks:返回this->tracked_tracks中为激活状态的轨迹;

vector<Strack*> unconfirmed:在Step4中,对于没有匹配上轨迹的高分目标初始化为一个新的轨迹,状态为Tracked,是第一帧的话设为激活轨迹,否则不是(中途出现的目标),没有激活的轨迹就是unconfirmed轨迹;如果下一帧匹配上目标(来自高分目标)则将轨迹更新并设为激活;

vector<Strack*> tracked_tracks:保存this->tracked_stracks中激活状态的轨迹地址,并和this->lost_stracks合并到strack_pool中;

vector<Strack*> strack_pool

vector<Strack*> r_tracked_stracks:Step2中没有匹配到的轨迹,用于在Step3中与低置信度的目标进行匹配

cpp代码:

if (objects.size() > 0)
{
    for (int i = 0; i < objects.size(); i++)
    {
       vector<float> tlbr_;
       tlbr_.resize(4);
       tlbr_[0] = objects[i].rect.x;
       tlbr_[1] = objects[i].rect.y;
       tlbr_[2] = objects[i].rect.x + objects[i].rect.width;
       tlbr_[3] = objects[i].rect.y + objects[i].rect.height;

       float score = objects[i].prob;

       STrack strack(STrack::tlbr_to_tlwh(tlbr_), score);
       if (score >= track_thresh)
       {
          detections.push_back(strack);
       }
       else
       {
          detections_low.push_back(strack);
       }
       
    }
}

objects为检测器的检测结果,将检测框tlwh转换为tlbr形式,并且实例化为Strack对象,根据score分为高置信度和低置信度对象。

// Add newly detected tracklets to tracked_stracks
for (int i = 0; i < this->tracked_stracks.size(); i++)
{
    if (!this->tracked_stracks[i].is_activated)
       unconfirmed.push_back(&this->tracked_stracks[i]);
    else
       tracked_stracks.push_back(&this->tracked_stracks[i]);
}

将this->tracked_stracks中的激活状态轨迹地址放入tracked_stracks中,未激活状态轨迹地址放入unconfirmed中。

// Step 2: First association, with IoU //
strack_pool = joint_stracks(tracked_stracks, this->lost_stracks);
STrack::multi_predict(strack_pool, this->kalman_filter);

vector<vector<float> > dists;
int dist_size = 0, dist_size_size = 0;
dists = iou_distance(strack_pool, detections, dist_size, dist_size_size);

vector<vector<int> > matches;
vector<int> u_track, u_detection;
linear_assignment(dists, dist_size, dist_size_size, match_thresh, matches, u_track, u_detection);

for (int i = 0; i < matches.size(); i++)
{
    STrack *track = strack_pool[matches[i][0]];
    STrack *det = &detections[matches[i][1]];
    if (track->state == TrackState::Tracked)
    {
       track->update(*det, this->frame_id);
       activated_stracks.push_back(*track);
    }
    else
    {
       track->re_activate(*det, this->frame_id, false);
       refind_stracks.push_back(*track);
    }
}

1.合并tracked_stracks和this->lost_stracks中的跟踪轨迹,将tracked_stracks中的所有轨迹加入,对于this->lost_stracks中的轨迹只加入不存在的轨迹(根据id确定);

2.使用this->kalman_filter对strack_pool中的所有轨迹预测下一时刻位置;

3.iou代价矩阵dists,dist_size为strack_pool中轨迹的数量,dist_size_size为高置信度detections的数量;

4.linear_assignment匹配得到matches,u_track,u_detection结果;

5.对于matches中,将strack_pool(全为激活状态轨迹)中状态为Tracked的轨迹放入activated_stracks中,并使用匹配上的det更新对应的track,否则使用det re_activate(重新激活,将状态设为Tracked,且激活)激活更新对应的track,并放入refind_stracks中。

// Step 3: Second association, using low score dets //
for (int i = 0; i < u_detection.size(); i++)
{
    detections_cp.push_back(detections[u_detection[i]]);
}
detections.clear();
detections.assign(detections_low.begin(), detections_low.end());

for (int i = 0; i < u_track.size(); i++)
{
    if (strack_pool[u_track[i]]->state == TrackState::Tracked)
    {
       r_tracked_stracks.push_back(strack_pool[u_track[i]]);
    }
}
// 和Step1一样,只是处理的是低置信度检测框和上一步没有匹配的轨迹u_track
dists.clear();
dists = iou_distance(r_tracked_stracks, detections, dist_size, dist_size_size);

matches.clear();
u_track.clear();
u_detection.clear();
linear_assignment(dists, dist_size, dist_size_size, 0.5, matches, u_track, u_detection);
for (int i = 0; i < matches.size(); i++)
{
    STrack *track = r_tracked_stracks[matches[i][0]];
    STrack *det = &detections[matches[i][1]];
    if (track->state == TrackState::Tracked)
    {
        track->update(*det, this->frame_id);
        activated_stracks.push_back(*track);
    }
    else
    {
        track->re_activate(*det, this->frame_id, false);
        refind_stracks.push_back(*track);
    }
}

1.将没有匹配上的高置信度检测结果(u_detection)放入detections_cp(用于暂存高置信度的检测框);

2.清空detections,并将低置信度的检测结果放入,将上一步没有匹配上的轨迹u_track中状态为Tracked的放入r_tracked_stracks中。

for (int i = 0; i < u_track.size(); i++)
{
    STrack *track = r_tracked_stracks[u_track[i]];
    if (track->state != TrackState::Lost)
    {
       track->mark_lost();
       lost_stracks.push_back(*track);
    }
}

将还没有匹配上的轨迹的状态标记为Lost,并放入lost_stracks中。

// Deal with unconfirmed tracks, usually tracks with only one beginning frame
detections.clear();
detections.assign(detections_cp.begin(), detections_cp.end());

dists.clear();
dists = iou_distance(unconfirmed, detections, dist_size, dist_size_size);

matches.clear();
vector<int> u_unconfirmed;
u_detection.clear();
linear_assignment(dists, dist_size, dist_size_size, 0.7, matches, u_unconfirmed, u_detection);

for (int i = 0; i < matches.size(); i++)
{
    unconfirmed[matches[i][0]]->update(detections[matches[i][1]], this->frame_id);
    activated_stracks.push_back(*unconfirmed[matches[i][0]]);
}

for (int i = 0; i < u_unconfirmed.size(); i++)
{
    STrack *track = unconfirmed[u_unconfirmed[i]];
    track->mark_removed();
    removed_stracks.push_back(*track);
}

1.清空detections,将Step2中没有匹配上的高置信度检测框,即在detections_cp中,放入detections,并和unconfirmed(未激活的轨迹)中的轨迹计算代价矩阵;

2.继续进行匹配,用匹配上的检测目标(高置信度)去更新unconfirmed中对应的轨迹,并加入activated_stracks;将没有匹配上的unconfirmed轨迹标记为Removed,并放入removed_stracks中。

// Step 4: Init new stracks //
for (int i = 0; i < u_detection.size(); i++)
{
    STrack *track = &detections[u_detection[i]];
    if (track->score < this->high_thresh)
       continue;
    track->activate(this->kalman_filter, this->frame_id);
    activated_stracks.push_back(*track);
}

此时的u_detection为还没有匹配上的高置信度检测目标,即为detections_cp中的目标,将score大于this->high_thresh的目标使用activate初始化为Tracked状态的轨迹,如果是视频的第一帧,则是激活状态的,否则是未激活状态的轨迹。

// Step 5: Update state //
for (int i = 0; i < this->lost_stracks.size(); i++)
{
    if (this->frame_id - this->lost_stracks[i].end_frame() > this->max_time_lost)
    {
       this->lost_stracks[i].mark_removed();
       removed_stracks.push_back(this->lost_stracks[i]);
    }
}

将this->lost_stracks中满足删除条件的轨迹标记为removed,并放入removed_stracks。

for (int i = 0; i < this->tracked_stracks.size(); i++)
{
    if (this->tracked_stracks[i].state == TrackState::Tracked)
    {
       tracked_stracks_swap.push_back(this->tracked_stracks[i]);
    }
}
this->tracked_stracks.clear();
this->tracked_stracks.assign(tracked_stracks_swap.begin(), tracked_stracks_swap.end());

this->tracked_stracks = joint_stracks(this->tracked_stracks, activated_stracks);
this->tracked_stracks = joint_stracks(this->tracked_stracks, refind_stracks);

//std::cout << activated_stracks.size() << std::endl;
   //将在this->tracked_stracks中的轨迹从this->lost_stracks删除(删除了lost中在tracked中的轨迹)
this->lost_stracks = sub_stracks(this->lost_stracks, this->tracked_stracks);

将this->tracked_stracks中状态为Tracked的轨迹放入tracked_stracks_swap中,并重新放入this->tracked_stracks中,将this->tracked_stracks,activated_stracks,refind_stracks中的轨迹使用joint_stracks向this->tracked_stracks中合并。

for (int i = 0; i < lost_stracks.size(); i++)
{
    this->lost_stracks.push_back(lost_stracks[i]);
}
//将在this->removed_stracks中的轨迹从this->lost_stracks删除(删除了lost中在removed中的轨迹)
this->lost_stracks = sub_stracks(this->lost_stracks, this->removed_stracks);
for (int i = 0; i < removed_stracks.size(); i++)
{
    this->removed_stracks.push_back(removed_stracks[i]);
}

remove_duplicate_stracks(resa, resb, this->tracked_stracks, this->lost_stracks);

this->tracked_stracks.clear();
this->tracked_stracks.assign(resa.begin(), resa.end());
this->lost_stracks.clear();
this->lost_stracks.assign(resb.begin(), resb.end());

for (int i = 0; i < this->tracked_stracks.size(); i++)
{
    if (this->tracked_stracks[i].is_activated)
    {
       output_stracks.push_back(this->tracked_stracks[i]);
    }
}
return output_stracks;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值