Oups, some renaming of variables was a bit too brutal. Fixed.
[mtp.git] / tracker.cc
1
2 /*
3  *  mtp is the ``Multi Tracked Paths'', an implementation of the
4  *  k-shortest paths algorithm for multi-target tracking.
5  *
6  *  Copyright (c) 2012 Idiap Research Institute, http://www.idiap.ch/
7  *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
8  *
9  *  This file is part of mtp.
10  *
11  *  mtp is free software: you can redistribute it and/or modify it
12  *  under the terms of the GNU General Public License version 3 as
13  *  published by the Free Software Foundation.
14  *
15  *  mtp is distributed in the hope that it will be useful, but WITHOUT
16  *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17  *  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
18  *  License for more details.
19  *
20  *  You should have received a copy of the GNU General Public License
21  *  along with selector.  If not, see <http://www.gnu.org/licenses/>.
22  *
23  */
24
25 #include "tracker.h"
26
27 #include <iostream>
28
29 using namespace std;
30
31 void Tracker::free() {
32   delete[] _edge_lengths;
33   delete _graph;
34   deallocate_array<scalar_t>(detection_scores);
35   deallocate_array<int>(allowed_motion);
36   delete[] exits;
37   delete[] entrances;
38 }
39
40 void Tracker::allocate(int nb_time_steps, int nb_locations) {
41   free();
42
43   _nb_locations = nb_locations;
44   _nb_time_steps = nb_time_steps;
45
46   detection_scores = allocate_array<scalar_t>(_nb_time_steps, _nb_locations);
47   allowed_motion = allocate_array<int>(_nb_locations, _nb_locations);
48
49   entrances = new int[_nb_locations];
50   exits = new int[_nb_locations];
51
52   for(int l = 0; l < _nb_locations; l++) {
53     entrances[l] = 0;
54     exits[l] = 0;
55     for(int m = 0; m < _nb_locations; m++) {
56       allowed_motion[l][m] = 0;
57     }
58   }
59
60   for(int t = 0; t < _nb_time_steps; t++) {
61     for(int l = 0; l < _nb_locations; l++) {
62       detection_scores[t][l] = 0.0;
63     }
64   }
65
66   _edge_lengths = 0;
67   _graph = 0;
68 }
69
70 void Tracker::write(ostream *os) {
71   (*os) << _nb_locations << " " << _nb_time_steps <<endl;
72
73   (*os) << endl;
74
75   for(int l = 0; l < _nb_locations; l++) {
76     for(int m = 0; m < _nb_locations; m++) {
77       (*os) << allowed_motion[l][m];
78       if(m < _nb_locations - 1) (*os) << " "; else (*os) << endl;
79     }
80   }
81
82   (*os) << endl;
83
84   for(int l = 0; l < _nb_locations; l++) {
85     (*os) << entrances[l];
86     if(l < _nb_locations - 1) (*os) << " "; else (*os) << endl;
87   }
88
89   (*os) << endl;
90
91   for(int l = 0; l < _nb_locations; l++) {
92     (*os) << exits[l];
93     if(l < _nb_locations - 1) (*os) << " "; else (*os) << endl;
94   }
95
96   (*os) << endl;
97
98   for(int t = 0; t < _nb_time_steps; t++) {
99     for(int l = 0; l < _nb_locations; l++) {
100       (*os) << detection_scores[t][l];
101       if(l < _nb_locations - 1) (*os) << " "; else (*os) << endl;
102     }
103   }
104 }
105
106 void Tracker::read(istream *is) {
107   int nb_locations, nb_time_steps;
108
109   (*is) >> nb_locations >> nb_time_steps;
110
111   allocate(nb_time_steps, nb_locations);
112
113   for(int l = 0; l < _nb_locations; l++) {
114     for(int m = 0; m < _nb_locations; m++) {
115       (*is) >> allowed_motion[l][m];
116     }
117   }
118
119   for(int l = 0; l < _nb_locations; l++) {
120     (*is) >> entrances[l];
121   }
122
123   for(int l = 0; l < _nb_locations; l++) {
124     (*is) >> exits[l];
125   }
126
127   for(int t = 0; t < _nb_time_steps; t++) {
128     for(int l = 0; l < _nb_locations; l++) {
129       (*is) >> detection_scores[t][l];
130     }
131   }
132 }
133
134 void Tracker::write_trajectories(ostream *os) {
135   for(int t = 0; t < nb_trajectories(); t++) {
136     (*os) << t
137          << " " << trajectory_entrance_time(t)
138          << " " << trajectory_duration(t)
139          << " " << trajectory_score(t);
140     for(int u = 0; u < trajectory_duration(t); u++) {
141       (*os) << " " << trajectory_location(t, u);
142     }
143     (*os) << endl;
144   }
145 }
146
147 Tracker::Tracker() {
148   _nb_locations = 0;
149   _nb_time_steps = 0;
150
151   detection_scores = 0;
152   allowed_motion = 0;
153
154   entrances = 0;
155   exits = 0;
156
157   _edge_lengths = 0;
158   _graph = 0;
159 }
160
161 Tracker::~Tracker() {
162   delete[] _edge_lengths;
163   delete _graph;
164   deallocate_array<scalar_t>(detection_scores);
165   deallocate_array<int>(allowed_motion);
166   delete[] exits;
167   delete[] entrances;
168 }
169
170 int Tracker::early_pair_node(int t, int l) {
171   return 1 + (2 * (t + 0) + 0) * _nb_locations + l;
172 }
173
174 int Tracker::late_pair_node(int t, int l) {
175   return 1 + (2 * (t + 0) + 1) * _nb_locations + l;
176 }
177
178 void Tracker::build_graph() {
179   // Delete the existing graph if there was one
180   delete[] _edge_lengths;
181   delete _graph;
182
183   int nb_motions = 0, nb_exits = 0, nb_entrances = 0;
184
185   for(int l = 0; l < _nb_locations; l++) {
186     if(exits[l]) nb_exits++;
187     if(entrances[l]) nb_entrances++;
188     for(int m = 0; m < _nb_locations; m++) {
189       if(allowed_motion[l][m]) nb_motions++;
190     }
191   }
192
193   int nb_vertices = 2 + 2 * _nb_time_steps * _nb_locations;
194
195   int nb_edges =
196     // The edges from the source to the first frame, and from the last
197     // frame to the sink
198     _nb_locations * 2 +
199     // The edges from the source to the entrances and from the exits
200     // to the sink (in every time frames but the first for the
201     // entrances, and last for the exits)
202     (_nb_time_steps - 1) * (nb_exits + nb_entrances) +
203     // The edges for the motions, between every successive frames
204     (_nb_time_steps - 1) * nb_motions +
205     // The edges inside the duplicated nodes
206     _nb_locations * _nb_time_steps;
207
208   int *node_from = new int[nb_edges];
209   int *node_to = new int[nb_edges];
210
211   int source = 0, sink = nb_vertices - 1;
212   int e = 0;
213
214   _edge_lengths = new scalar_t[nb_edges];
215
216   // We put the in-node edges first, since these are the ones whose
217   // lengths we will have to change before tracking, according to the
218   // detection scores
219
220   for(int t = 0; t < _nb_time_steps; t++) {
221     for(int l = 0; l < _nb_locations; l++) {
222       node_from[e] = early_pair_node(t, l);
223       node_to[e] = late_pair_node(t, l);
224       e++;
225     }
226   }
227
228   // The edges from the source to the first time frame
229
230   for(int l = 0; l < _nb_locations; l++) {
231     node_from[e] = source;
232     node_to[e] = 1 + l + 0 * _nb_locations;
233     _edge_lengths[e] = 0.0;
234     e++;
235   }
236
237   // The edges from the last frame to the sink
238
239   for(int l = 0; l < _nb_locations; l++) {
240     node_from[e] = late_pair_node(_nb_time_steps - 1, l);
241     node_to[e] = sink;
242     _edge_lengths[e] = 0.0;
243     e++;
244   }
245
246   // The edges between frames, corresponding to allowed motions
247
248   for(int t = 0; t < _nb_time_steps - 1; t++) {
249     for(int l = 0; l < _nb_locations; l++) {
250       for(int k = 0; k < _nb_locations; k++) {
251         if(allowed_motion[l][k]) {
252           node_from[e] = late_pair_node(t, l);
253           node_to[e] = early_pair_node(t+1, k);
254           _edge_lengths[e] = 0.0;
255           e++;
256         }
257       }
258     }
259   }
260
261   // The edges from the source to the entrances, and from the exits to
262   // the sink
263
264   for(int t = 0; t < _nb_time_steps; t++) {
265     for(int l = 0; l < _nb_locations; l++) {
266       if(t > 0 && entrances[l]) {
267         node_from[e] = source;
268         node_to[e] = early_pair_node(t, l);
269         _edge_lengths[e] = 0.0;
270         e++;
271       }
272       if(t < _nb_time_steps - 1 && exits[l]) {
273         node_from[e] = late_pair_node(t, l);
274         node_to[e] = sink;
275         _edge_lengths[e] = 0.0;
276         e++;
277       }
278     }
279   }
280
281   // We are done, build the graph
282
283   _graph = new MTPGraph(nb_vertices, nb_edges,
284                         node_from, node_to,
285                         source, sink);
286
287   delete[] node_from;
288   delete[] node_to;
289 }
290
291 void Tracker::print_graph_dot(ostream *os) {
292   int e = 0;
293   for(int t = 0; t < _nb_time_steps; t++) {
294     for(int l = 0; l < _nb_locations; l++) {
295       _edge_lengths[e++] = - detection_scores[t][l];
296     }
297   }
298   _graph->print_dot(os);
299 }
300
301 void Tracker::track() {
302   ASSERT(_graph);
303
304   int e = 0;
305   for(int t = 0; t < _nb_time_steps; t++) {
306     for(int l = 0; l < _nb_locations; l++) {
307       _edge_lengths[e++] = - detection_scores[t][l];
308     }
309   }
310
311   _graph->find_best_paths(_edge_lengths);
312   _graph->retrieve_disjoint_paths();
313
314 #ifdef VERBOSE
315   for(int p = 0; p < _graph->nb_paths; p++) {
316     Path *path = _graph->paths[p];
317     cout << "PATH " << p << " [length " << path->nb_nodes << "] " << path->nodes[0];
318     for(int n = 1; n < path->nb_nodes; n++) {
319       cout << " -> " << path->nodes[n];
320     }
321     cout << endl;
322   }
323 #endif
324 }
325
326 int Tracker::nb_trajectories() {
327   return _graph->nb_paths;
328 }
329
330 scalar_t Tracker::trajectory_score(int k) {
331   return -_graph->paths[k]->length;
332 }
333
334 int Tracker::trajectory_entrance_time(int k) {
335   return (_graph->paths[k]->nodes[1] - 1) / (2 * _nb_locations);
336 }
337
338 int Tracker::trajectory_duration(int k) {
339   return (_graph->paths[k]->nb_nodes - 2) / 2;
340 }
341
342 int Tracker::trajectory_location(int k, int time_from_entry) {
343   return (_graph->paths[k]->nodes[2 * time_from_entry + 1] - 1) % _nb_locations;
344 }