Added the fields force_empty_first_frame and force_empty_last_frame in MTPTracker.
[mtp.git] / mtp_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 "mtp_tracker.h"
26
27 #include <iostream>
28
29 using namespace std;
30
31 void MTPTracker::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 MTPTracker::allocate(int t, int l) {
41   free();
42
43   nb_locations = l;
44   nb_time_steps = t;
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   force_empty_first_frame = 0;
67   force_empty_last_frame = 0;
68
69   _edge_lengths = 0;
70   _graph = 0;
71 }
72
73 void MTPTracker::write(ostream *os) {
74   (*os) << nb_locations << " " << nb_time_steps << endl;
75
76   (*os) << endl;
77
78   for(int l = 0; l < nb_locations; l++) {
79     for(int m = 0; m < nb_locations; m++) {
80       (*os) << allowed_motion[l][m];
81       if(m < nb_locations - 1) (*os) << " "; else (*os) << endl;
82     }
83   }
84
85   (*os) << endl;
86
87   (*os) << force_empty_first_frame << " " << force_empty_last_frame << endl;
88
89   (*os) << endl;
90
91   for(int l = 0; l < nb_locations; l++) {
92     (*os) << entrances[l];
93     if(l < nb_locations - 1) (*os) << " "; else (*os) << endl;
94   }
95
96   (*os) << endl;
97
98   for(int l = 0; l < nb_locations; l++) {
99     (*os) << exits[l];
100     if(l < nb_locations - 1) (*os) << " "; else (*os) << endl;
101   }
102
103   (*os) << endl;
104
105   for(int t = 0; t < nb_time_steps; t++) {
106     for(int l = 0; l < nb_locations; l++) {
107       (*os) << detection_scores[t][l];
108       if(l < nb_locations - 1) (*os) << " "; else (*os) << endl;
109     }
110   }
111 }
112
113 void MTPTracker::read(istream *is) {
114   int l, t;
115
116   (*is) >> l >> t;
117
118   allocate(t, l);
119
120   for(int l = 0; l < nb_locations; l++) {
121     for(int m = 0; m < nb_locations; m++) {
122       (*is) >> allowed_motion[l][m];
123     }
124   }
125
126   (*is) >> force_empty_first_frame >> force_empty_last_frame;
127
128   for(int l = 0; l < nb_locations; l++) {
129     (*is) >> entrances[l];
130   }
131
132   for(int l = 0; l < nb_locations; l++) {
133     (*is) >> exits[l];
134   }
135
136   for(int t = 0; t < nb_time_steps; t++) {
137     for(int l = 0; l < nb_locations; l++) {
138       (*is) >> detection_scores[t][l];
139     }
140   }
141 }
142
143 void MTPTracker::write_trajectories(ostream *os) {
144   (*os) << nb_trajectories() << endl;
145   for(int t = 0; t < nb_trajectories(); t++) {
146     (*os) << t
147          << " " << trajectory_entrance_time(t)
148          << " " << trajectory_duration(t)
149          << " " << trajectory_score(t);
150     for(int u = 0; u < trajectory_duration(t); u++) {
151       (*os) << " " << trajectory_location(t, u);
152     }
153     (*os) << endl;
154   }
155 }
156
157 MTPTracker::MTPTracker() {
158   nb_locations = 0;
159   nb_time_steps = 0;
160
161   detection_scores = 0;
162   allowed_motion = 0;
163
164   entrances = 0;
165   exits = 0;
166
167   _edge_lengths = 0;
168   _graph = 0;
169 }
170
171 MTPTracker::~MTPTracker() {
172   delete[] _edge_lengths;
173   delete _graph;
174   deallocate_array<scalar_t>(detection_scores);
175   deallocate_array<int>(allowed_motion);
176   delete[] exits;
177   delete[] entrances;
178 }
179
180 int MTPTracker::early_pair_node(int t, int l) {
181   return 1 + (2 * t + 0) * nb_locations + l;
182 }
183
184 int MTPTracker::late_pair_node(int t, int l) {
185   return 1 + (2 * t + 1) * nb_locations + l;
186 }
187
188 void MTPTracker::build_graph() {
189   // Delete the existing graph if there was one
190   delete[] _edge_lengths;
191   delete _graph;
192
193   int nb_motions = 0, nb_exits = 0, nb_entrances = 0;
194
195   for(int l = 0; l < nb_locations; l++) {
196     if(exits[l]) nb_exits++;
197     if(entrances[l]) nb_entrances++;
198     for(int m = 0; m < nb_locations; m++) {
199       if(allowed_motion[l][m]) nb_motions++;
200     }
201   }
202
203   int nb_vertices = 2 + 2 * nb_time_steps * nb_locations;
204
205   int nb_edges =
206     // The edges from the source to the entrances and from the exits
207     // to the sink (in every time frames but the first for the
208     // entrances, and last for the exits)
209     (nb_time_steps - 1) * (nb_exits + nb_entrances) +
210     // The edges for the motions, between every successive frames
211     (nb_time_steps - 1) * nb_motions +
212     // The edges inside the duplicated nodes
213     nb_locations * nb_time_steps;
214
215   // Edges from the source to the first frame
216   if(force_empty_first_frame) {
217     nb_edges += nb_entrances;
218   } else {
219     nb_edges += nb_locations;
220   }
221
222   // Edges from the last frame to the sink
223   if(force_empty_last_frame) {
224     nb_edges += nb_exits;
225   } else {
226     nb_edges += nb_locations;
227   }
228
229   int *node_from = new int[nb_edges];
230   int *node_to = new int[nb_edges];
231
232   int source = 0, sink = nb_vertices - 1;
233   int e = 0;
234
235   _edge_lengths = new scalar_t[nb_edges];
236
237   // We put the in-node edges first, since these are the ones whose
238   // lengths we will have to change before tracking, according to the
239   // detection scores
240
241   for(int t = 0; t < nb_time_steps; t++) {
242     for(int l = 0; l < nb_locations; l++) {
243       node_from[e] = early_pair_node(t, l);
244       node_to[e] = late_pair_node(t, l);
245       e++;
246     }
247   }
248
249   // The edges from the source to the first time frame
250
251   for(int l = 0; l < nb_locations; l++) {
252     if(!force_empty_first_frame || entrances[l]) {
253       node_from[e] = source;
254       node_to[e] = 1 + l + 0 * nb_locations;
255       _edge_lengths[e] = 0.0;
256       e++;
257     }
258   }
259
260   // The edges from the last frame to the sink
261
262   for(int l = 0; l < nb_locations; l++) {
263     if(!force_empty_last_frame || exits[l]) {
264       node_from[e] = late_pair_node(nb_time_steps - 1, l);
265       node_to[e] = sink;
266       _edge_lengths[e] = 0.0;
267       e++;
268     }
269   }
270
271   // The edges between frames, corresponding to allowed motions
272
273   for(int t = 0; t < nb_time_steps - 1; t++) {
274     for(int l = 0; l < nb_locations; l++) {
275       for(int k = 0; k < nb_locations; k++) {
276         if(allowed_motion[l][k]) {
277           node_from[e] = late_pair_node(t, l);
278           node_to[e] = early_pair_node(t+1, k);
279           _edge_lengths[e] = 0.0;
280           e++;
281         }
282       }
283     }
284   }
285
286   // The edges from the source to the entrances, and from the exits to
287   // the sink
288
289   for(int t = 0; t < nb_time_steps; t++) {
290     for(int l = 0; l < nb_locations; l++) {
291       if(t > 0 && entrances[l]) {
292         node_from[e] = source;
293         node_to[e] = early_pair_node(t, l);
294         _edge_lengths[e] = 0.0;
295         e++;
296       }
297       if(t < nb_time_steps - 1 && exits[l]) {
298         node_from[e] = late_pair_node(t, l);
299         node_to[e] = sink;
300         _edge_lengths[e] = 0.0;
301         e++;
302       }
303     }
304   }
305
306   // We are done, build the graph
307
308   _graph = new MTPGraph(nb_vertices, nb_edges,
309                         node_from, node_to,
310                         source, sink);
311
312   delete[] node_from;
313   delete[] node_to;
314 }
315
316 void MTPTracker::print_graph_dot(ostream *os) {
317   int e = 0;
318   for(int t = 0; t < nb_time_steps; t++) {
319     for(int l = 0; l < nb_locations; l++) {
320       _edge_lengths[e++] = - detection_scores[t][l];
321     }
322   }
323   _graph->print_dot(os);
324 }
325
326 void MTPTracker::track() {
327   ASSERT(_graph);
328
329   int e = 0;
330   for(int t = 0; t < nb_time_steps; t++) {
331     for(int l = 0; l < nb_locations; l++) {
332       _edge_lengths[e++] = - detection_scores[t][l];
333     }
334   }
335
336   _graph->find_best_paths(_edge_lengths);
337   _graph->retrieve_disjoint_paths();
338
339 #ifdef VERBOSE
340   for(int p = 0; p < _graph->nb_paths; p++) {
341     Path *path = _graph->paths[p];
342     cout << "PATH " << p << " [length " << path->nb_nodes << "] " << path->nodes[0];
343     for(int n = 1; n < path->nb_nodes; n++) {
344       cout << " -> " << path->nodes[n];
345     }
346     cout << endl;
347   }
348 #endif
349 }
350
351 int MTPTracker::nb_trajectories() {
352   return _graph->nb_paths;
353 }
354
355 scalar_t MTPTracker::trajectory_score(int k) {
356   return -_graph->paths[k]->length;
357 }
358
359 int MTPTracker::trajectory_entrance_time(int k) {
360   return (_graph->paths[k]->nodes[1] - 1) / (2 * nb_locations);
361 }
362
363 int MTPTracker::trajectory_duration(int k) {
364   return (_graph->paths[k]->nb_nodes - 2) / 2;
365 }
366
367 int MTPTracker::trajectory_location(int k, int time_from_entry) {
368   return (_graph->paths[k]->nodes[2 * time_from_entry + 1] - 1) % nb_locations;
369 }