Removed the definition of basename, which confuses an existing system one.
[folded-ctf.git] / pi_feature.cc
1 /*
2  *  folded-ctf is an implementation of the folded hierarchy of
3  *  classifiers for object detection, developed by Francois Fleuret
4  *  and Donald Geman.
5  *
6  *  Copyright (c) 2008 Idiap Research Institute, http://www.idiap.ch/
7  *  Written by Francois Fleuret <francois.fleuret@idiap.ch>
8  *
9  *  This file is part of folded-ctf.
10  *
11  *  folded-ctf is free software: you can redistribute it and/or modify
12  *  it under the terms of the GNU General Public License version 3 as
13  *  published by the Free Software Foundation.
14  *
15  *  folded-ctf is distributed in the hope that it will be useful, but
16  *  WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  *  General Public License for more details.
19  *
20  *  You should have received a copy of the GNU General Public License
21  *  along with folded-ctf.  If not, see <http://www.gnu.org/licenses/>.
22  *
23  */
24
25 #include "pi_feature.h"
26
27 #include "global.h"
28 #include "rectangle.h"
29
30 int PiFeature::random_registration_mode(int level) {
31   while(1) {
32     switch(int(6 * drand48())) {
33
34     case 0:
35       return PiReferential::RM_HEAD;
36       break;
37
38     case 1:
39       if(level >= 1)
40         return PiReferential::RM_BELLY;
41       break;
42
43     case 2:
44       if(level >= 1)
45         return PiReferential::RM_HEAD_BELLY;
46       break;
47
48     case 3:
49       if(level >= 1)
50         return PiReferential::RM_HEAD_BELLY_EDGES;
51       break;
52
53     case 4:
54     case 5:
55       break;
56
57     default:
58       abort();
59     }
60   }
61 }
62
63 void PiFeature::randomize_window(int registration_mode, Rectangle *window) {
64   scalar_t xc, yc, w, h;
65
66   do {
67     xc = 2 * drand48() - 1.0;
68     yc = 2 * drand48() - 1.0;
69
70     w = 2 * drand48();
71
72     // If we are in a non-rotating frame, allow rectangular window,
73     // otherwise force it to be squared
74
75     if(registration_mode == PiReferential::RM_HEAD ||
76        registration_mode == PiReferential::RM_BELLY ||
77        registration_mode == PiReferential::RM_HEAD_NO_POLARITY ||
78        registration_mode == PiReferential::RM_BELLY_NO_POLARITY) {
79       h = 2 * drand48();
80     } else {
81       h = w;
82     }
83   } while(w < global.pi_feature_window_min_size ||
84           h < global.pi_feature_window_min_size ||
85           xc - w/2 < -1.0 || xc + w/2 > 1.0 ||
86           yc - h/2 < -1.0 || yc + h/2 > 1.0);
87
88   window->xmin = xc - w/2;
89   window->ymin = yc - h/2;
90   window->xmax = xc + w/2;
91   window->ymax = yc + h/2;
92 }
93
94 //////////////////////////////////////////////////////////////////////
95 // PF_EDGE_THRESHOLDING
96
97 scalar_t PiFeature::response_edge_thresholding(RichImage *image,
98                                                PiReferential *referential) {
99   Rectangle registered_window_a;
100
101   referential->register_rectangle(_registration_a,
102                                   &_window_a,
103                                   &registered_window_a);
104
105   int tag = referential->register_edge(_registration_a, _tag);
106
107   int xmin_a = int(registered_window_a.xmin) >> _edge_scale;
108   int ymin_a = int(registered_window_a.ymin) >> _edge_scale;
109   int xmax_a = int(registered_window_a.xmax) >> _edge_scale;
110   int ymax_a = int(registered_window_a.ymax) >> _edge_scale;
111
112   int scale = referential->common_scale() + _edge_scale * global.nb_scales_per_power_of_two;
113
114   scalar_t ne, nt;
115
116   ASSERT((tag >= RichImage::first_edge_tag &&
117           tag < RichImage::first_edge_tag + RichImage::nb_edge_tags) ||
118          tag == RichImage::variance_tag);
119
120   if(tag != RichImage::variance_tag) {
121     ne = scalar_t(image->nb_tags_in_window(scale, tag,
122                                            xmin_a, ymin_a, xmax_a, ymax_a));
123     nt = scalar_t(image->nb_tags_in_window(scale, RichImage::variance_tag,
124                                           xmin_a, ymin_a, xmax_a, ymax_a) + 1);
125   } else {
126     ne = scalar_t(image->nb_tags_in_window(scale, RichImage::variance_tag,
127                                            xmin_a, ymin_a, xmax_a, ymax_a));
128     nt = scalar_t((xmax_a - xmin_a) * (ymax_a - ymin_a)) + 1;
129   }
130
131   return ne / nt;
132 }
133
134 void PiFeature::draw_edge_thresholding(RGBImage *image,
135                                        int r, int g, int b,
136                                        PiReferential *referential) {
137
138   (*global.log_stream) << "draw_edge_thresholding" << endl;
139
140   Rectangle registered_window_a;
141
142   referential->register_rectangle(_registration_a,
143                                   &_window_a,
144                                   &registered_window_a);
145
146   referential->draw_window(image, _registration_a, &registered_window_a, 0);
147 }
148
149 void PiFeature::print_edge_thresholding(ostream *os) {
150   (*os) << "_tag " << _tag << endl;
151   (*os) << "_edge_scale " << _edge_scale << endl;
152   (*os) << "_window_a.xmin " << _window_a.xmin << endl;
153   (*os) << "_window_a.ymin " << _window_a.ymin << endl;
154   (*os) << "_window_a.xmax " << _window_a.xmax << endl;
155   (*os) << "_window_a.ymax " << _window_a.ymax << endl;
156 }
157
158 //////////////////////////////////////////////////////////////////////
159 // PF_EDGE_HISTOGRAM_COMPARISON
160
161 scalar_t PiFeature::response_edge_histogram_comparison(RichImage *image,
162                                                        PiReferential *referential) {
163
164   Rectangle registered_window_a;
165
166   referential->register_rectangle(_registration_a,
167                                   &_window_a,
168                                   &registered_window_a);
169
170   int xmin_a = int(registered_window_a.xmin) >> _edge_scale;
171   int ymin_a = int(registered_window_a.ymin) >> _edge_scale;
172   int xmax_a = int(registered_window_a.xmax) >> _edge_scale;
173   int ymax_a = int(registered_window_a.ymax) >> _edge_scale;
174
175   Rectangle registered_window_b;
176
177   referential->register_rectangle(_registration_b,
178                                   &_window_b,
179                                   &registered_window_b);
180
181   int xmin_b = int(registered_window_b.xmin) >> _edge_scale;
182   int ymin_b = int(registered_window_b.ymin) >> _edge_scale;
183   int xmax_b = int(registered_window_b.xmax) >> _edge_scale;
184   int ymax_b = int(registered_window_b.ymax) >> _edge_scale;
185
186   int scale = referential->common_scale() + _edge_scale * global.nb_scales_per_power_of_two;
187
188   scalar_t result = 0.0;
189
190   scalar_t ne_a = scalar_t(image->nb_tags_in_window(scale, RichImage::variance_tag,
191                                                     xmin_a, ymin_a,
192                                                     xmax_a, ymax_a) + 1);
193
194   scalar_t ne_b = scalar_t(image->nb_tags_in_window(scale, RichImage::variance_tag,
195                                                     xmin_b, ymin_b,
196                                                     xmax_b, ymax_b) + 1);
197
198   for(int t = RichImage::first_edge_tag; t < RichImage::first_edge_tag + RichImage::nb_edge_tags; t++)
199     result += sq(scalar_t(image->nb_tags_in_window(scale, t,
200                                                    xmin_a, ymin_a,
201                                                    xmax_a, ymax_a)) / ne_a
202                  -
203                  scalar_t(image->nb_tags_in_window(scale, t,
204                                                    xmin_b, ymin_b,
205                                                    xmax_b, ymax_b)) / ne_b);
206
207   ASSERT(!isnan(result));
208
209   return result;
210 }
211
212 void PiFeature::draw_edge_histogram_comparison(RGBImage *image,
213                                                int r, int g, int b,
214                                                PiReferential *referential) {
215
216   (*global.log_stream) << "draw_edge_histogram_comparison" << endl;
217
218   Rectangle registered_window;
219   {
220
221     referential->register_rectangle(_registration_a,
222                                     &_window_a,
223                                     &registered_window);
224     referential->draw_window(image, _registration_a, &registered_window, 0);
225   }
226
227   {
228     referential->register_rectangle(_registration_b,
229                                     &_window_b,
230                                     &registered_window);
231
232     referential->draw_window(image, _registration_b, &registered_window, 0);
233   }
234 }
235
236 void PiFeature::print_edge_histogram_comparison(ostream *os) {
237   (*os) << "_edge_scale " << _edge_scale << endl;
238   (*os) << "_window_a.xmin " << _window_a.xmin << endl;
239   (*os) << "_window_a.ymin " << _window_a.ymin << endl;
240   (*os) << "_window_a.xmax " << _window_a.xmax << endl;
241   (*os) << "_window_a.ymax " << _window_a.ymax << endl;
242   (*os) << "_window_b.xmin " << _window_a.xmin << endl;
243   (*os) << "_window_b.ymin " << _window_a.ymin << endl;
244   (*os) << "_window_b.xmax " << _window_a.xmax << endl;
245   (*os) << "_window_b.ymax " << _window_a.ymax << endl;
246 }
247
248 //////////////////////////////////////////////////////////////////////
249 // PF_GRAYSCALE_HISTOGRAM_COMPARISON
250
251 scalar_t PiFeature::response_grayscale_histogram_comparison(RichImage *image,
252                                                             PiReferential *referential) {
253   Rectangle registered_window_a;
254
255   referential->register_rectangle(_registration_a,
256                                   &_window_a,
257                                   &registered_window_a);
258
259   int xmin_a = int(registered_window_a.xmin);
260   int ymin_a = int(registered_window_a.ymin);
261   int xmax_a = int(registered_window_a.xmax);
262   int ymax_a = int(registered_window_a.ymax);
263
264   Rectangle registered_window_b;
265
266   referential->register_rectangle(_registration_b,
267                                   &_window_b,
268                                   &registered_window_b);
269
270   int xmin_b = int(registered_window_b.xmin);
271   int ymin_b = int(registered_window_b.ymin);
272   int xmax_b = int(registered_window_b.xmax);
273   int ymax_b = int(registered_window_b.ymax);
274
275   int scale = referential->common_scale();
276
277   scalar_t result = 0.0;
278
279   scalar_t ne_a = scalar_t((xmax_a - xmin_a) * (ymax_a - ymin_a));
280   scalar_t ne_b = scalar_t((xmax_b - xmin_b) * (ymax_b - ymin_b));
281
282   for(int t = RichImage::first_gray_tag; t < RichImage::first_gray_tag + RichImage::nb_gray_tags; t++)
283     result += sq(scalar_t(image->nb_tags_in_window(scale, t,
284                                                    xmin_a, ymin_a,
285                                                    xmax_a, ymax_a))/ne_a
286                  -
287                  scalar_t(image->nb_tags_in_window(scale, t,
288                                                    xmin_b, ymin_b,
289                                                    xmax_b, ymax_b))/ne_b);
290   ASSERT(!isnan(result));
291
292   return result;
293 }
294
295 void PiFeature::draw_grayscale_histogram_comparison(RGBImage *image,
296                                                     int r, int g, int b,
297                                                     PiReferential *referential) {
298
299   (*global.log_stream) << "draw_grayscale_histogram_comparison" << endl;
300
301   Rectangle registered_window;
302   {
303
304     referential->register_rectangle(_registration_a,
305                                     &_window_a,
306                                     &registered_window);
307
308     referential->draw_window(image, _registration_a, &registered_window, 0);
309   }
310
311   {
312     referential->register_rectangle(_registration_b,
313                                     &_window_b,
314                                     &registered_window);
315
316     referential->draw_window(image, _registration_b, &registered_window, 0);
317   }
318 }
319
320 void PiFeature::print_grayscale_histogram_comparison(ostream *os) {
321   (*os) << "_window_a.xmin " << _window_a.xmin << endl;
322   (*os) << "_window_a.ymin " << _window_a.ymin << endl;
323   (*os) << "_window_a.xmax " << _window_a.xmax << endl;
324   (*os) << "_window_a.ymax " << _window_a.ymax << endl;
325   (*os) << "_window_b.xmin " << _window_a.xmin << endl;
326   (*os) << "_window_b.ymin " << _window_a.ymin << endl;
327   (*os) << "_window_b.xmax " << _window_a.xmax << endl;
328   (*os) << "_window_b.ymax " << _window_a.ymax << endl;
329 }
330
331 //////////////////////////////////////////////////////////////////////
332 //////////////////////////////////////////////////////////////////////
333 //////////////////////////////////////////////////////////////////////
334
335 void PiFeature::randomize(int level) {
336
337   // We randomize all parameters, even those which will not be used
338   // due to the feature type
339
340   _tag = int(drand48() * (RichImage::nb_edge_tags + 1));
341
342   if(_tag < RichImage::nb_edge_tags)
343     _tag += RichImage::first_edge_tag;
344   else
345     _tag = RichImage::variance_tag;
346
347   _edge_scale = int(drand48() * 3);
348
349   // Windows can not be defined in different frames unless we allow
350   // head-belly registration
351
352   if(global.force_head_belly_independence) {
353     if(level == 0) {
354       _registration_a = PiReferential::RM_HEAD_NO_POLARITY;
355       _registration_b = PiReferential::RM_HEAD_NO_POLARITY;
356     } else if(level == 1) {
357       _registration_a = PiReferential::RM_BELLY_NO_POLARITY;
358       _registration_b = PiReferential::RM_BELLY_NO_POLARITY;
359     } else {
360       abort();
361     }
362   } else {
363     _registration_a = random_registration_mode(level);
364     _registration_b = random_registration_mode(level);
365   }
366
367   randomize_window(_registration_a, &_window_a);
368   randomize_window(_registration_b, &_window_b);
369
370   switch(int(drand48() * 3)) {
371
372   case 0:
373     _type = PF_EDGE_THRESHOLDING;
374     break;
375
376   case 1:
377     _type = PF_EDGE_HISTOGRAM_COMPARISON;
378     break;
379
380   case 2:
381     _type = PF_GRAYSCALE_HISTOGRAM_COMPARISON;
382     break;
383
384   default:
385     abort();
386   }
387 }
388
389 scalar_t PiFeature::response(RichImage *image, PiReferential *referential) {
390   scalar_t r;
391
392   switch(_type) {
393
394   case PF_EDGE_THRESHOLDING:
395     r = response_edge_thresholding(image, referential);
396     break;
397
398   case PF_EDGE_HISTOGRAM_COMPARISON:
399     r = response_edge_histogram_comparison(image, referential);
400     break;
401
402   case PF_GRAYSCALE_HISTOGRAM_COMPARISON:
403     r = response_grayscale_histogram_comparison(image, referential);
404     break;
405
406   default:
407     abort();
408   }
409
410   ASSERT(!isnan(r));
411
412   return r;
413 };
414
415 void PiFeature::draw(RGBImage *image,
416                      int r, int g, int b, PiReferential *referential) {
417
418   switch(_type) {
419
420   case PF_EDGE_THRESHOLDING:
421     draw_edge_thresholding(image, r, g, b, referential);
422     break;
423
424   case PF_EDGE_HISTOGRAM_COMPARISON:
425     draw_edge_histogram_comparison(image, r, g, b, referential);
426     break;
427
428   case PF_GRAYSCALE_HISTOGRAM_COMPARISON:
429     draw_grayscale_histogram_comparison(image, r, g, b, referential);
430     break;
431
432   default:
433     abort();
434   }
435 }
436
437 void PiFeature::print(ostream *os) {
438
439   (*os) << "registration_a ";
440   PiReferential::print_registration_mode(os, _registration_a);
441   (*os) << endl;
442
443   (*os) << "registration_b ";
444   PiReferential::print_registration_mode(os, _registration_b);
445   (*os) << endl;
446
447   switch(_type) {
448
449   case PF_EDGE_THRESHOLDING:
450     print_edge_thresholding(os);
451     break;
452
453   case PF_EDGE_HISTOGRAM_COMPARISON:
454     print_edge_histogram_comparison(os);
455     break;
456
457   case PF_GRAYSCALE_HISTOGRAM_COMPARISON:
458     print_grayscale_histogram_comparison(os);
459     break;
460
461   default:
462     abort();
463   }
464 }