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