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       if(level >= 2)
49         return PiReferential::RM_BODY;
50       break;
51
52     case 5:
53       if(level >= 2)
54         return PiReferential::RM_BODY_EDGES;
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 //   if(!global.pictures_for_article) {
149 //     int tag = referential->register_edge(_registration_a, _tag);
150
151 //     referential->draw_edge_and_scale(image, _registration_a, &registered_window_a,
152 //                                      tag, _edge_scale);
153 //   }
154 }
155
156 void PiFeature::print_edge_thresholding(ostream *os) {
157   (*os) << "_tag " << _tag << endl;
158   (*os) << "_edge_scale " << _edge_scale << endl;
159   (*os) << "_window_a.xmin " << _window_a.xmin << endl;
160   (*os) << "_window_a.ymin " << _window_a.ymin << endl;
161   (*os) << "_window_a.xmax " << _window_a.xmax << endl;
162   (*os) << "_window_a.ymax " << _window_a.ymax << endl;
163 }
164
165 //////////////////////////////////////////////////////////////////////
166 // PF_EDGE_HISTOGRAM_COMPARISON
167
168 scalar_t PiFeature::response_edge_histogram_comparison(RichImage *image,
169                                                        PiReferential *referential) {
170
171   Rectangle registered_window_a;
172
173   referential->register_rectangle(_registration_a,
174                                   &_window_a,
175                                   &registered_window_a);
176
177   int xmin_a = int(registered_window_a.xmin) >> _edge_scale;
178   int ymin_a = int(registered_window_a.ymin) >> _edge_scale;
179   int xmax_a = int(registered_window_a.xmax) >> _edge_scale;
180   int ymax_a = int(registered_window_a.ymax) >> _edge_scale;
181
182   Rectangle registered_window_b;
183
184   referential->register_rectangle(_registration_b,
185                                   &_window_b,
186                                   &registered_window_b);
187
188   int xmin_b = int(registered_window_b.xmin) >> _edge_scale;
189   int ymin_b = int(registered_window_b.ymin) >> _edge_scale;
190   int xmax_b = int(registered_window_b.xmax) >> _edge_scale;
191   int ymax_b = int(registered_window_b.ymax) >> _edge_scale;
192
193   int scale = referential->common_scale() + _edge_scale * global.nb_scales_per_power_of_two;
194
195   scalar_t result = 0.0;
196
197   scalar_t ne_a = scalar_t(image->nb_tags_in_window(scale, RichImage::variance_tag,
198                                                     xmin_a, ymin_a,
199                                                     xmax_a, ymax_a) + 1);
200
201   scalar_t ne_b = scalar_t(image->nb_tags_in_window(scale, RichImage::variance_tag,
202                                                     xmin_b, ymin_b,
203                                                     xmax_b, ymax_b) + 1);
204
205   for(int t = RichImage::first_edge_tag; t < RichImage::first_edge_tag + RichImage::nb_edge_tags; t++)
206     result += sq(scalar_t(image->nb_tags_in_window(scale, t,
207                                                    xmin_a, ymin_a,
208                                                    xmax_a, ymax_a)) / ne_a
209                  -
210                  scalar_t(image->nb_tags_in_window(scale, t,
211                                                    xmin_b, ymin_b,
212                                                    xmax_b, ymax_b)) / ne_b);
213
214   ASSERT(!isnan(result));
215
216   return result;
217 }
218
219 void PiFeature::draw_edge_histogram_comparison(RGBImage *image,
220                                                int r, int g, int b,
221                                                PiReferential *referential) {
222
223   (*global.log_stream) << "draw_edge_histogram_comparison" << endl;
224
225   Rectangle registered_window;
226   {
227
228     referential->register_rectangle(_registration_a,
229                                     &_window_a,
230                                     &registered_window);
231     referential->draw_window(image, _registration_a, &registered_window, 0);
232   }
233
234   {
235     referential->register_rectangle(_registration_b,
236                                     &_window_b,
237                                     &registered_window);
238
239     referential->draw_window(image, _registration_b, &registered_window, 0);
240   }
241 }
242
243 void PiFeature::print_edge_histogram_comparison(ostream *os) {
244   (*os) << "_edge_scale " << _edge_scale << endl;
245   (*os) << "_window_a.xmin " << _window_a.xmin << endl;
246   (*os) << "_window_a.ymin " << _window_a.ymin << endl;
247   (*os) << "_window_a.xmax " << _window_a.xmax << endl;
248   (*os) << "_window_a.ymax " << _window_a.ymax << endl;
249   (*os) << "_window_b.xmin " << _window_a.xmin << endl;
250   (*os) << "_window_b.ymin " << _window_a.ymin << endl;
251   (*os) << "_window_b.xmax " << _window_a.xmax << endl;
252   (*os) << "_window_b.ymax " << _window_a.ymax << endl;
253 }
254
255 //////////////////////////////////////////////////////////////////////
256 // PF_GRAYSCALE_HISTOGRAM_COMPARISON
257
258 scalar_t PiFeature::response_grayscale_histogram_comparison(RichImage *image,
259                                                             PiReferential *referential) {
260   Rectangle registered_window_a;
261
262   referential->register_rectangle(_registration_a,
263                                   &_window_a,
264                                   &registered_window_a);
265
266   int xmin_a = int(registered_window_a.xmin);
267   int ymin_a = int(registered_window_a.ymin);
268   int xmax_a = int(registered_window_a.xmax);
269   int ymax_a = int(registered_window_a.ymax);
270
271   Rectangle registered_window_b;
272
273   referential->register_rectangle(_registration_b,
274                                   &_window_b,
275                                   &registered_window_b);
276
277   int xmin_b = int(registered_window_b.xmin);
278   int ymin_b = int(registered_window_b.ymin);
279   int xmax_b = int(registered_window_b.xmax);
280   int ymax_b = int(registered_window_b.ymax);
281
282   int scale = referential->common_scale();
283
284   scalar_t result = 0.0;
285
286   scalar_t ne_a = scalar_t((xmax_a - xmin_a) * (ymax_a - ymin_a));
287   scalar_t ne_b = scalar_t((xmax_b - xmin_b) * (ymax_b - ymin_b));
288
289   for(int t = RichImage::first_gray_tag; t < RichImage::first_gray_tag + RichImage::nb_gray_tags; t++)
290     result += sq(scalar_t(image->nb_tags_in_window(scale, t,
291                                                    xmin_a, ymin_a,
292                                                    xmax_a, ymax_a))/ne_a
293                  -
294                  scalar_t(image->nb_tags_in_window(scale, t,
295                                                    xmin_b, ymin_b,
296                                                    xmax_b, ymax_b))/ne_b);
297   ASSERT(!isnan(result));
298
299   return result;
300 }
301
302 void PiFeature::draw_grayscale_histogram_comparison(RGBImage *image,
303                                                     int r, int g, int b,
304                                                     PiReferential *referential) {
305
306   (*global.log_stream) << "draw_grayscale_histogram_comparison" << endl;
307
308   Rectangle registered_window;
309   {
310
311     referential->register_rectangle(_registration_a,
312                                     &_window_a,
313                                     &registered_window);
314
315     referential->draw_window(image, _registration_a, &registered_window, 0);
316   }
317
318   {
319     referential->register_rectangle(_registration_b,
320                                     &_window_b,
321                                     &registered_window);
322
323     referential->draw_window(image, _registration_b, &registered_window, 0);
324   }
325 }
326
327 void PiFeature::print_grayscale_histogram_comparison(ostream *os) {
328   (*os) << "_window_a.xmin " << _window_a.xmin << endl;
329   (*os) << "_window_a.ymin " << _window_a.ymin << endl;
330   (*os) << "_window_a.xmax " << _window_a.xmax << endl;
331   (*os) << "_window_a.ymax " << _window_a.ymax << endl;
332   (*os) << "_window_b.xmin " << _window_a.xmin << endl;
333   (*os) << "_window_b.ymin " << _window_a.ymin << endl;
334   (*os) << "_window_b.xmax " << _window_a.xmax << endl;
335   (*os) << "_window_b.ymax " << _window_a.ymax << endl;
336 }
337
338 //////////////////////////////////////////////////////////////////////
339 //////////////////////////////////////////////////////////////////////
340 //////////////////////////////////////////////////////////////////////
341
342 void PiFeature::randomize(int level) {
343
344   // We randomize all parameters, even those which will not be used
345   // due to the feature type
346
347   _tag = int(drand48() * (RichImage::nb_edge_tags + 1));
348
349   if(_tag < RichImage::nb_edge_tags)
350     _tag += RichImage::first_edge_tag;
351   else
352     _tag = RichImage::variance_tag;
353
354   _edge_scale = int(drand48() * 3);
355
356   // Windows can not be defined in different frames unless we allow
357   // head-belly registration
358
359   if(global.force_head_belly_independence) {
360     if(level == 0) {
361       _registration_a = PiReferential::RM_HEAD_NO_POLARITY;
362       _registration_b = PiReferential::RM_HEAD_NO_POLARITY;
363     } else if(level == 1) {
364       _registration_a = PiReferential::RM_BELLY_NO_POLARITY;
365       _registration_b = PiReferential::RM_BELLY_NO_POLARITY;
366     } else {
367       abort();
368     }
369   } else {
370     _registration_a = random_registration_mode(level);
371     _registration_b = random_registration_mode(level);
372   }
373
374   randomize_window(_registration_a, &_window_a);
375   randomize_window(_registration_b, &_window_b);
376
377   switch(int(drand48() * 3)) {
378
379   case 0:
380     _type = PF_EDGE_THRESHOLDING;
381     break;
382
383   case 1:
384     _type = PF_EDGE_HISTOGRAM_COMPARISON;
385     break;
386
387   case 2:
388     _type = PF_GRAYSCALE_HISTOGRAM_COMPARISON;
389     break;
390
391   default:
392     abort();
393   }
394 }
395
396 scalar_t PiFeature::response(RichImage *image, PiReferential *referential) {
397   scalar_t r;
398
399   switch(_type) {
400
401   case PF_EDGE_THRESHOLDING:
402     r = response_edge_thresholding(image, referential);
403     break;
404
405   case PF_EDGE_HISTOGRAM_COMPARISON:
406     r = response_edge_histogram_comparison(image, referential);
407     break;
408
409   case PF_GRAYSCALE_HISTOGRAM_COMPARISON:
410     r = response_grayscale_histogram_comparison(image, referential);
411     break;
412
413   default:
414     abort();
415   }
416
417   ASSERT(!isnan(r));
418
419   return r;
420 };
421
422 void PiFeature::draw(RGBImage *image,
423                      int r, int g, int b, PiReferential *referential) {
424
425   switch(_type) {
426
427   case PF_EDGE_THRESHOLDING:
428     draw_edge_thresholding(image, r, g, b, referential);
429     break;
430
431   case PF_EDGE_HISTOGRAM_COMPARISON:
432     draw_edge_histogram_comparison(image, r, g, b, referential);
433     break;
434
435   case PF_GRAYSCALE_HISTOGRAM_COMPARISON:
436     draw_grayscale_histogram_comparison(image, r, g, b, referential);
437     break;
438
439   default:
440     abort();
441   }
442 }
443
444 void PiFeature::print(ostream *os) {
445
446   (*os) << "registration_a ";
447   PiReferential::print_registration_mode(os, _registration_a);
448   (*os) << endl;
449
450   (*os) << "registration_b ";
451   PiReferential::print_registration_mode(os, _registration_b);
452   (*os) << endl;
453
454   switch(_type) {
455
456   case PF_EDGE_THRESHOLDING:
457     print_edge_thresholding(os);
458     break;
459
460   case PF_EDGE_HISTOGRAM_COMPARISON:
461     print_edge_histogram_comparison(os);
462     break;
463
464   case PF_GRAYSCALE_HISTOGRAM_COMPARISON:
465     print_grayscale_histogram_comparison(os);
466     break;
467
468   default:
469     abort();
470   }
471 }