Files
VideoPipe/nodes/track/vp_track_node.cpp
2026-06-03 12:43:14 +08:00

128 lines
5.7 KiB
C++

#include "vp_track_node.h"
//#include "../objects/shapes/vp_rect.h"
namespace vp_nodes {
vp_track_node::vp_track_node(std::string node_name,
vp_track_for track_for):
vp_node(node_name),
track_for(track_for) {
}
vp_track_node::~vp_track_node() {
}
std::shared_ptr<vp_objects::vp_meta> vp_track_node::handle_control_meta(std::shared_ptr<vp_objects::vp_control_meta> meta) {
return meta;
}
std::shared_ptr<vp_objects::vp_meta> vp_track_node::handle_frame_meta(std::shared_ptr<vp_objects::vp_frame_meta> meta) {
// channel_index can be different each call
auto channel_index = meta->channel_index;
// data used for tracking
std::vector<vp_objects::vp_rect> rects; // rects of targets
std::vector<std::vector<float>> embeddings; // embeddings of targets
std::vector<int> track_ids; // track ids of targets
// step 1, collect data
preprocess(meta, rects, embeddings);
// step 2, track by channel
track(channel_index, rects, embeddings, track_ids);
// step 3, postprocess
postprocess(meta, rects, embeddings, track_ids);
return meta;
}
void vp_track_node::preprocess(std::shared_ptr<vp_objects::vp_frame_meta> frame_meta,
std::vector<vp_objects::vp_rect>& target_rects,
std::vector<std::vector<float>>& target_embeddings) {
if (track_for == vp_track_for::NORMAL) {
for(auto& i: frame_meta->targets) {
target_rects.push_back(i->get_rect()); // rect fo target (via i variable)
target_embeddings.push_back(i->embeddings); // embeddings of target (via i variable)
}
}
if (track_for == vp_track_for::FACE) {
for(auto& i: frame_meta->face_targets) {
target_rects.push_back(i->get_rect()); // rect of face target (via i variable)
target_embeddings.push_back(i->embeddings); // embeddings of face target (via i variable)
}
}
/* ... extend for more track for... */
}
// write track_ids back to frame meta
// we can also cache history rects for each target, and then push them back to tracks field (such as vp_frame_target::tracks)
void vp_track_node::postprocess(std::shared_ptr<vp_objects::vp_frame_meta> frame_meta,
const std::vector<vp_objects::vp_rect>& target_rects,
const std::vector<std::vector<float>>& target_embeddings,
const std::vector<int>& track_ids) {
if (track_ids.empty()) {
return;
}
// assert for length of vectors since they are generated by step1 & step2 separately
// assert(target_rects.size() == target_embeddings.size());
assert(target_rects.size() == track_ids.size());
// support multi channels
auto& tracks_by_id = all_tracks_by_id[frame_meta->channel_index];
auto& last_tracked_frame_indexes = all_last_tracked_frame_indexes[frame_meta->channel_index];
if (track_for == vp_track_for::NORMAL) {
//assert(target_rects.size() == frame_meta->targets.size());
for (int i = 0; i < frame_meta->targets.size(); i++) {
auto& target = frame_meta->targets[i];
auto& rect = target_rects[i];
auto& track_id = track_ids[i];
// -1 means no track result returned yet
if (track_id != -1) {
tracks_by_id[track_id].push_back(rect); // cache
last_tracked_frame_indexes[track_id] = frame_meta->frame_index; // update stamp
target->track_id = track_id; // write track_id back to target
target->tracks = tracks_by_id[track_id]; // write tracks back to target
}
}
}
if (track_for == vp_track_for::FACE) {
// assert(target_rects.size() == frame_meta->face_targets.size());
for (int i = 0; i < frame_meta->face_targets.size(); i++) {
auto& face = frame_meta->face_targets[i];
auto& rect = target_rects[i];
auto& track_id = track_ids[i];
// -1 means no track result returned yet
if (track_id != -1) {
tracks_by_id[track_id].push_back(rect); // cache
last_tracked_frame_indexes[track_id] = frame_meta->frame_index; // update stamp
face->track_id = track_id; // write track_id back to face target
face->tracks = tracks_by_id[track_id]; // write tracks back to face target
}
}
}
/* ... extend for more track for... */
// remove cache tracks if has been long time since last updated (maybe it disappeared already).
for (auto i = last_tracked_frame_indexes.begin(); i != last_tracked_frame_indexes.end();) {
if (frame_meta->frame_index - (i->second) > max_allowed_disappear_frames
|| frame_meta->frame_index < i->second) {
VP_DEBUG(vp_utils::string_format("[%s] [tracking] long time no update, so erase cache of tracks for track_id:`%d`, size of tracks is:`%d`", node_name.c_str(), i->first, tracks_by_id[i->first].size()));
tracks_by_id.erase(i->first); // erase tracks first
i = last_tracked_frame_indexes.erase(i); // erase stamp then
}
else {
i++;
}
}
}
}