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