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 //   if(!global.pictures_for_article) {
143 //     int tag = referential->register_edge(_registration_a, _tag);
144
145 //     referential->draw_edge_and_scale(image, _registration_a, &registered_window_a,
146 //                                      tag, _edge_scale);
147 //   }
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 }