wangrong
2025-01-18 8b0e31121a9a29b92a41fc575138a2e9b4c12d8e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
 
#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++;
            }
        }
    }
}