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