1 // Copyright (C) 2014  Davis E. King (davis@dlib.net)
2 // License: Boost Software License   See LICENSE.txt for the full license.
3 
4 
5 #include <sstream>
6 #include "tester.h"
7 #include <dlib/svm_threaded.h>
8 #include <dlib/rand.h>
9 
10 
11 
12 namespace
13 {
14     using namespace test;
15     using namespace dlib;
16     using namespace std;
17 
18     logger dlog("test.learning_to_track");
19 
20 // ----------------------------------------------------------------------------------------
21 
22     struct detection_dense
23     {
24         typedef struct track_dense track_type;
25         matrix<double,0,1> measurements;
26     };
27 
28 
29     struct track_dense
30     {
31         typedef matrix<double,0,1> feature_vector_type;
32 
track_dense__anon8852b6760111::track_dense33         track_dense()
34         {
35             time_since_last_association = 0;
36         }
37 
get_similarity_features__anon8852b6760111::track_dense38         void get_similarity_features(const detection_dense det, feature_vector_type& feats) const
39         {
40             feats = abs(last_measurements - det.measurements);
41         }
42 
update_track__anon8852b6760111::track_dense43         void update_track(const detection_dense det)
44         {
45             last_measurements = det.measurements;
46             time_since_last_association = 0;
47         }
48 
propagate_track__anon8852b6760111::track_dense49         void propagate_track()
50         {
51             ++time_since_last_association;
52         }
53 
54         matrix<double,0,1> last_measurements;
55         unsigned long time_since_last_association;
56     };
57 
58 // ----------------------------------------------------------------------------------------
59 
60     struct detection_sparse
61     {
62         typedef struct track_sparse track_type;
63         matrix<double,0,1> measurements;
64     };
65 
66 
67     struct track_sparse
68     {
69         typedef std::vector<std::pair<unsigned long,double> > feature_vector_type;
70 
track_sparse__anon8852b6760111::track_sparse71         track_sparse()
72         {
73             time_since_last_association = 0;
74         }
75 
get_similarity_features__anon8852b6760111::track_sparse76         void get_similarity_features(const detection_sparse det, feature_vector_type& feats) const
77         {
78             matrix<double,0,1> temp = abs(last_measurements - det.measurements);
79             feats.clear();
80             for (long i = 0; i < temp.size(); ++i)
81                 feats.push_back(make_pair(i, temp(i)));
82         }
83 
update_track__anon8852b6760111::track_sparse84         void update_track(const detection_sparse det)
85         {
86             last_measurements = det.measurements;
87             time_since_last_association = 0;
88         }
89 
propagate_track__anon8852b6760111::track_sparse90         void propagate_track()
91         {
92             ++time_since_last_association;
93         }
94 
95         matrix<double,0,1> last_measurements;
96         unsigned long time_since_last_association;
97     };
98 
99 // ----------------------------------------------------------------------------------------
100 // ----------------------------------------------------------------------------------------
101 // ----------------------------------------------------------------------------------------
102 
103     dlib::rand rnd;
104     const long num_objects = 4;
105     const long num_properties = 6;
106     std::vector<matrix<double,0,1> > object_properties(num_objects);
107 
initialize_object_properties()108     void initialize_object_properties()
109     {
110         rnd.set_seed("23ja2oirfjaf");
111         for (unsigned long i = 0; i < object_properties.size(); ++i)
112             object_properties[i] = randm(num_properties,1,rnd);
113     }
114 
115     template <typename detection>
sample_detection_from_sensor(long object_id)116     detection sample_detection_from_sensor(long object_id)
117     {
118         DLIB_CASSERT(object_id < num_objects,
119             "You can't ask to sample a detection from an object that doesn't exist.");
120         detection temp;
121         // Set the measurements equal to the object's true property values plus a little bit of
122         // noise.
123         temp.measurements = object_properties[object_id] + randm(num_properties,1,rnd)*0.1;
124         return temp;
125     }
126 
127 // ----------------------------------------------------------------------------------------
128 
129 
130     template <typename detection>
make_random_tracking_data_for_training()131     std::vector<std::vector<labeled_detection<detection> > > make_random_tracking_data_for_training()
132     {
133         typedef std::vector<labeled_detection<detection> > detections_at_single_time_step;
134         typedef std::vector<detections_at_single_time_step> track_history;
135 
136         track_history data;
137 
138         // At each time step we get a set of detections from the objects in the world.
139         // Simulate 100 time steps worth of data where there are 3 objects present.
140         const int num_time_steps = 100;
141         for (int i = 0; i < num_time_steps; ++i)
142         {
143             detections_at_single_time_step dets(3);
144             // sample a detection from object 0
145             dets[0].det = sample_detection_from_sensor<detection>(0);
146             dets[0].label = 0;
147 
148             // sample a detection from object 1
149             dets[1].det = sample_detection_from_sensor<detection>(1);
150             dets[1].label = 1;
151 
152             // sample a detection from object 2
153             dets[2].det = sample_detection_from_sensor<detection>(2);
154             dets[2].label = 2;
155 
156             randomize_samples(dets, rnd);
157             data.push_back(dets);
158         }
159 
160         // Now let's imagine object 1 and 2 are gone but a new object, object 3 has arrived.
161         for (int i = 0; i < num_time_steps; ++i)
162         {
163             detections_at_single_time_step dets(2);
164             // sample a detection from object 0
165             dets[0].det = sample_detection_from_sensor<detection>(0);
166             dets[0].label = 0;
167 
168             // sample a detection from object 3
169             dets[1].det = sample_detection_from_sensor<detection>(3);
170             dets[1].label = 3;
171 
172             randomize_samples(dets, rnd);
173             data.push_back(dets);
174         }
175 
176         return data;
177     }
178 
179 // ----------------------------------------------------------------------------------------
180 
181     template <typename detection>
make_random_detections(long num_dets)182     std::vector<detection> make_random_detections(long num_dets)
183     {
184         DLIB_CASSERT(num_dets <= num_objects,
185             "You can't ask for more detections than there are objects in our little simulation.");
186 
187         std::vector<detection> dets(num_dets);
188         for (unsigned long i = 0; i < dets.size(); ++i)
189         {
190             dets[i] = sample_detection_from_sensor<detection>(i);
191         }
192         randomize_samples(dets, rnd);
193         return dets;
194     }
195 
196 // ----------------------------------------------------------------------------------------
197 
198     template <typename detection>
test_tracking_stuff()199     void test_tracking_stuff()
200     {
201         print_spinner();
202 
203 
204         typedef std::vector<labeled_detection<detection> > detections_at_single_time_step;
205         typedef std::vector<detections_at_single_time_step> track_history;
206         std::vector<track_history> data;
207         data.push_back(make_random_tracking_data_for_training<detection>());
208         data.push_back(make_random_tracking_data_for_training<detection>());
209         data.push_back(make_random_tracking_data_for_training<detection>());
210         data.push_back(make_random_tracking_data_for_training<detection>());
211         data.push_back(make_random_tracking_data_for_training<detection>());
212 
213 
214         structural_track_association_trainer trainer;
215         trainer.set_c(1000);
216         track_association_function<detection> assoc = trainer.train(data);
217 
218         double test_val = test_track_association_function(assoc, data);
219         DLIB_TEST_MSG( test_val == 1, test_val);
220         test_val = cross_validate_track_association_trainer(trainer, data, 5);
221         DLIB_TEST_MSG ( test_val == 1, test_val);
222 
223 
224 
225         typedef typename detection::track_type track;
226         std::vector<track> tracks;
227 
228         std::vector<detection> dets = make_random_detections<detection>(3);
229         assoc(tracks, dets);
230         DLIB_TEST(tracks.size() == 3);
231 
232         dets = make_random_detections<detection>(3);
233         assoc(tracks, dets);
234         DLIB_TEST(tracks.size() == 3);
235 
236         dets = make_random_detections<detection>(3);
237         assoc(tracks, dets);
238         DLIB_TEST(tracks.size() == 3);
239 
240         dets = make_random_detections<detection>(4);
241         assoc(tracks, dets);
242         DLIB_TEST(tracks.size() == 4);
243 
244         dets = make_random_detections<detection>(3);
245         assoc(tracks, dets);
246         DLIB_TEST(tracks.size() == 4);
247         unsigned long total_miss = 0;
248         for (unsigned long i = 0; i < tracks.size(); ++i)
249             total_miss += tracks[i].time_since_last_association;
250         DLIB_TEST(total_miss == 1);
251 
252         dets = make_random_detections<detection>(3);
253         assoc(tracks, dets);
254         DLIB_TEST(tracks.size() == 4);
255         total_miss = 0;
256         unsigned long num_zero = 0;
257         for (unsigned long i = 0; i < tracks.size(); ++i)
258         {
259             total_miss += tracks[i].time_since_last_association;
260             if (tracks[i].time_since_last_association == 0)
261                 ++num_zero;
262         }
263         DLIB_TEST(total_miss == 2);
264         DLIB_TEST(num_zero == 3);
265 
266 
267 
268         ostringstream sout;
269         serialize(assoc, sout);
270 
271         istringstream sin(sout.str());
272         deserialize(assoc, sin);
273         DLIB_TEST( test_track_association_function(assoc, data) == 1);
274     }
275 
276 
277 // ----------------------------------------------------------------------------------------
278 
279     class test_learning_to_track : public tester
280     {
281     public:
test_learning_to_track()282         test_learning_to_track (
283         ) :
284             tester ("test_learning_to_track",
285                 "Runs tests on the assignment learning code.")
286         {}
287 
perform_test()288         void perform_test (
289         )
290         {
291             initialize_object_properties();
292             for (int i = 0; i < 3; ++i)
293             {
294                 dlog << LINFO << "run test_tracking_stuff<detection_dense>()";
295                 test_tracking_stuff<detection_dense>();
296                 dlog << LINFO << "run test_tracking_stuff<detection_sparse>()";
297                 test_tracking_stuff<detection_sparse>();
298             }
299         }
300     } a;
301 
302 // ----------------------------------------------------------------------------------------
303 
304 }
305 
306 
307