Removed the definition of basename, which confuses an existing system one.
[folded-ctf.git] / pi_referential.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 version 3 as
13  *  published by the Free Software Foundation.
14  *
15  *  folded-ctf is distributed in the hope that it will be useful, but
16  *  WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  *  General Public License for more details.
19  *
20  *  You should have received a copy of the GNU General Public License
21  *  along with folded-ctf.  If not, see <http://www.gnu.org/licenses/>.
22  *
23  */
24
25 #include "pi_referential.h"
26 #include "global.h"
27 #include "rich_image.h"
28
29 void PiReferential::draw_frame(RGBImage *image,
30                                int registration_mode,
31                                int x1, int y1,
32                                int x2, int y2,
33                                int x3, int y3,
34                                int x4, int y4) {
35
36   int r, g, b;
37
38   switch(registration_mode) {
39
40   case PiReferential::RM_HEAD:
41     r = 0; g = 255; b = 0;
42     break;
43
44   case PiReferential::RM_HEAD_NO_POLARITY:
45     r = 128; g = 255; b = 128;
46     break;
47
48   case PiReferential::RM_BELLY:
49     r = 64; g = 0; b = 255;
50     break;
51
52   case PiReferential::RM_BELLY_NO_POLARITY:
53     r = 192; g = 128; b = 255;
54     break;
55
56   case PiReferential::RM_HEAD_BELLY:
57   case PiReferential::RM_HEAD_BELLY_EDGES:
58     r = 255; g = 0; b = 0;
59     break;
60
61   default:
62     cerr << "INCONSISTENCY" << endl;
63     abort();
64   }
65
66   if(global.pictures_for_article) {
67     r = 255; g = 255; b = 255;
68     image->draw_line(6, r, g, b, x1, y1, x2, y2);
69     image->draw_line(6, r, g, b, x2, y2, x3, y3);
70     image->draw_line(6, r, g, b, x3, y3, x4, y4);
71     image->draw_line(6, r, g, b, x4, y4, x1, y1);
72
73     r =   0; g =   0; b =   0;
74     image->draw_line(2, r, g, b, x1, y1, x2, y2);
75     image->draw_line(2, r, g, b, x2, y2, x3, y3);
76     image->draw_line(2, r, g, b, x3, y3, x4, y4);
77     image->draw_line(2, r, g, b, x4, y4, x1, y1);
78   } else {
79     image->draw_line(2, r, g, b, x1, y1, x2, y2);
80     image->draw_line(2, r, g, b, x2, y2, x3, y3);
81     image->draw_line(2, r, g, b, x3, y3, x4, y4);
82     image->draw_line(2, r, g, b, x4, y4, x1, y1);
83   }
84 }
85
86 void PiReferential::draw_window(RGBImage *image,
87                                 int registration_mode, Rectangle *window,
88                                 int filled) {
89   int r, g, b;
90
91   switch(registration_mode) {
92
93   case PiReferential::RM_HEAD:
94     r = 0; g = 255; b = 0;
95     break;
96
97   case PiReferential::RM_HEAD_NO_POLARITY:
98     r = 128; g = 255; b = 128;
99     break;
100
101   case PiReferential::RM_BELLY:
102     r = 64; g = 0; b = 255;
103     break;
104
105   case PiReferential::RM_BELLY_NO_POLARITY:
106     r = 192; g = 128; b = 255;
107     break;
108
109   case PiReferential::RM_HEAD_BELLY:
110   case PiReferential::RM_HEAD_BELLY_EDGES:
111     r = 255; g = 0; b = 0;
112     break;
113
114   default:
115     cerr << "INCONSISTENCY" << endl;
116     abort();
117   }
118
119   int xmin = int(window->xmin);
120   int ymin = int(window->ymin);
121   int xmax = int(window->xmax);
122   int ymax = int(window->ymax);
123
124   if(global.pictures_for_article) {
125     r = 255; g = 255; b = 255;
126     image->draw_line(6, r, g, b, xmin, ymin, xmax, ymin);
127     image->draw_line(6, r, g, b, xmax, ymin, xmax, ymax);
128     image->draw_line(6, r, g, b, xmax, ymax, xmin, ymax);
129     image->draw_line(6, r, g, b, xmin, ymax, xmin, ymin);
130
131     r =   0; g =   0; b =   0;
132     image->draw_line(2, r, g, b, xmin, ymin, xmax, ymin);
133     image->draw_line(2, r, g, b, xmax, ymin, xmax, ymax);
134     image->draw_line(2, r, g, b, xmax, ymax, xmin, ymax);
135     image->draw_line(2, r, g, b, xmin, ymax, xmin, ymin);
136
137   } else {
138     image->draw_line(2, r, g, b, xmin, ymin, xmax, ymin);
139     image->draw_line(2, r, g, b, xmax, ymin, xmax, ymax);
140     image->draw_line(2, r, g, b, xmax, ymax, xmin, ymax);
141     image->draw_line(2, r, g, b, xmin, ymax, xmin, ymin);
142     if(filled) {
143       int delta = 4;
144       for(int d = ymin - ymax; d <= xmax - xmin; d += delta) {
145         int x1 = xmin + d;
146         int y1 = ymin;
147         int x2 = xmin + d + ymax - ymin;
148         int y2 = ymax;
149         if(x1 < xmin) { y1 = y1 + (xmin - x1); x1 = xmin; }
150         if(x2 > xmax) { y2 = y2 - (x2 - xmax); x2 = xmax; }
151         image->draw_line(1, r, g, b, x1, y1, x2, y2);
152       }
153     }
154   }
155
156 }
157
158 PiReferential::PiReferential(PoseCell *cell) {
159   scalar_t head_radius = sqrt(scalar_t(cell->_head_radius.min * cell->_head_radius.max));
160
161   _common_scale = global.scale_to_discrete_log_scale(head_radius / global.min_head_radius);
162
163   scalar_t discrete_scale_ratio = global.discrete_log_scale_to_scale(_common_scale);
164
165   //////////////////////////////////////////////////////////////////////
166   // Locations and scales
167
168   // Head location
169
170   _head_xc = cell->_head_xc.middle() * discrete_scale_ratio;
171   _head_yc = cell->_head_yc.middle() * discrete_scale_ratio;
172   _head_radius = cell->_head_radius.middle() * discrete_scale_ratio;
173   _head_window_scaling = _head_radius * 2.0;
174
175   // Body location
176
177   // **********************************************************************
178   // Useless code, but necessary to keep the exact same results with
179   // g++ 4.1 and -O3 options on reference experiments.
180   _body_xc = cell->_belly_xc.middle() * discrete_scale_ratio;
181   _body_yc = cell->_belly_yc.middle() * discrete_scale_ratio;
182   _body_tilt = 0;
183   if((_head_xc - _body_xc) * cos(_body_tilt) + (_head_yc - _body_yc) * sin(_body_tilt) > 0) {
184     _body_tilt += M_PI;
185   }
186   // **********************************************************************
187
188   // Belly location
189
190   const scalar_t belly_frame_factor = 2.0;
191
192   _belly_xc = cell->_belly_xc.middle() * discrete_scale_ratio;
193   _belly_yc = cell->_belly_yc.middle() * discrete_scale_ratio;
194   _belly_window_scaling = _head_window_scaling * belly_frame_factor;
195
196   // Head-belly location
197
198   _head_belly_xc = (_head_xc + _belly_xc) * 0.5;
199   _head_belly_yc = (_head_yc + _belly_yc) * 0.5;
200
201   //////////////////////////////////////////////////////////////////////
202   // Frames
203
204   if(_body_xc >= _head_xc) {
205     //   if(_belly_xc >= _head_xc) {
206     _horizontal_polarity = 1;
207   } else {
208     _horizontal_polarity = -1;
209   }
210
211   // Head frame
212
213   if(_horizontal_polarity < 0) {
214     _head_ux = _head_radius * 2.0;
215     _head_uy = 0;
216   } else {
217     _head_ux = - _head_radius * 2.0;
218     _head_uy = 0;
219   }
220
221   _head_vx = 0;
222   _head_vy = - _head_radius * 2.0;
223
224   _head_ux_nopolarity = _head_radius * 2.0;
225   _head_uy_nopolarity = 0;
226   _head_vx_nopolarity = 0;
227   _head_vy_nopolarity = - _head_radius * 2.0;
228
229   // Belly frame
230
231   _belly_ux = _head_ux * belly_frame_factor;
232   _belly_uy = _head_uy * belly_frame_factor;
233   _belly_vx = _head_vx * belly_frame_factor;
234   _belly_vy = _head_vy * belly_frame_factor;
235
236   _belly_ux_nopolarity = _head_ux_nopolarity * belly_frame_factor;
237   _belly_uy_nopolarity = _head_uy_nopolarity * belly_frame_factor;
238   _belly_vx_nopolarity = _head_vx_nopolarity * belly_frame_factor;
239   _belly_vy_nopolarity = _head_vy_nopolarity * belly_frame_factor;
240
241   // Head-belly frame
242
243   _head_belly_ux = 2 * (_head_xc - _head_belly_xc);
244   _head_belly_uy = 2 * (_head_yc - _head_belly_yc);
245
246   if(_horizontal_polarity < 0) {
247     _head_belly_vx =   _head_belly_uy;
248     _head_belly_vy = - _head_belly_ux;
249   } else {
250     _head_belly_vx = - _head_belly_uy;
251     _head_belly_vy =   _head_belly_ux;
252   }
253
254   scalar_t l = sqrt(_head_belly_vx * _head_belly_vx + _head_belly_vy * _head_belly_vy);
255
256   _head_belly_vx = (_head_belly_vx / l) * _head_radius * 2;
257   _head_belly_vy = (_head_belly_vy / l) * _head_radius * 2;
258   _head_belly_edge_shift = int(floor(- RichImage::nb_edge_tags * atan2(_head_belly_ux, _head_belly_uy) / (2 * M_PI) + 0.5));
259   _head_belly_edge_shift = (RichImage::nb_edge_tags + _head_belly_edge_shift) % RichImage::nb_edge_tags;
260 }
261
262 int PiReferential::common_scale() {
263   return _common_scale;
264 }
265
266 void PiReferential::register_rectangle(int registration_mode,
267                                        Rectangle *original,
268                                        Rectangle *result) {
269   scalar_t alpha, beta , xc, yc, w, h;
270
271   alpha = (original->xmin + original->xmax) * 0.5;
272   beta  = (original->ymin + original->ymax) * 0.5;
273
274   switch(registration_mode) {
275
276   case RM_HEAD:
277     {
278       xc = _head_xc + alpha * _head_ux + beta * _head_vx;
279       yc = _head_yc + alpha * _head_uy + beta * _head_vy;
280       w = (original->xmax - original->xmin) * _head_window_scaling;
281       h = (original->ymax - original->ymin) * _head_window_scaling;
282     }
283     break;
284
285   case RM_HEAD_NO_POLARITY:
286     {
287       xc = _head_xc + alpha * _head_ux_nopolarity + beta * _head_vx_nopolarity;
288       yc = _head_yc + alpha * _head_uy_nopolarity + beta * _head_vy_nopolarity;
289       w = (original->xmax - original->xmin) * _head_window_scaling;
290       h = (original->ymax - original->ymin) * _head_window_scaling;
291     }
292     break;
293
294   case RM_BELLY:
295     {
296       xc = _belly_xc + alpha * _belly_ux + beta * _belly_vx;
297       yc = _belly_yc + alpha * _belly_uy + beta * _belly_vy;
298       w = (original->xmax - original->xmin) * _belly_window_scaling;
299       h = (original->ymax - original->ymin) * _belly_window_scaling;
300     }
301     break;
302
303   case RM_BELLY_NO_POLARITY:
304     {
305       xc = _belly_xc + alpha * _belly_ux_nopolarity + beta * _belly_vx_nopolarity;
306       yc = _belly_yc + alpha * _belly_uy_nopolarity + beta * _belly_vy_nopolarity;
307       w = (original->xmax - original->xmin) * _belly_window_scaling;
308       h = (original->ymax - original->ymin) * _belly_window_scaling;
309     }
310     break;
311
312   case RM_HEAD_BELLY:
313   case RM_HEAD_BELLY_EDGES:
314     {
315       xc = _head_belly_xc + alpha * _head_belly_ux + beta * _head_belly_vx;
316       yc = _head_belly_yc + alpha * _head_belly_uy + beta * _head_belly_vy;
317       w = (original->xmax - original->xmin) * _head_window_scaling;
318       h = (original->ymax - original->ymin) * _head_window_scaling;
319     }
320     break;
321
322   default:
323     cerr << "Undefined registration mode." << endl;
324     abort();
325   }
326
327   result->xmin = xc - 0.5 * w;
328   result->ymin = yc - 0.5 * h;
329   result->xmax = xc + 0.5 * w;
330   result->ymax = yc + 0.5 * h;
331
332   ASSERT(result->xmin < result->xmax && result->ymin < result->ymax);
333 }
334
335 int PiReferential::register_edge(int registration_mode, int edge_type) {
336
337   if(edge_type >= RichImage::first_edge_tag &&
338      edge_type < RichImage::first_edge_tag + RichImage::nb_edge_tags) {
339
340     int e = edge_type - RichImage::first_edge_tag;
341
342     switch(registration_mode) {
343     case PiReferential::RM_HEAD_NO_POLARITY:
344     case PiReferential::RM_BELLY_NO_POLARITY:
345       break;
346
347     case PiReferential::RM_HEAD:
348     case PiReferential::RM_BELLY:
349     case PiReferential::RM_HEAD_BELLY:
350       if(_horizontal_polarity < 0) {
351         e = (RichImage::nb_edge_tags - e) % RichImage::nb_edge_tags;
352       }
353       break;
354
355     case PiReferential::RM_HEAD_BELLY_EDGES:
356       if(_horizontal_polarity < 0) {
357         e = (RichImage::nb_edge_tags - e) % RichImage::nb_edge_tags;
358       }
359       e += _head_belly_edge_shift;
360       break;
361
362     default:
363       cerr << "INCONSISTENCY" << endl;
364       abort();
365     }
366
367     e = e % RichImage::nb_edge_tags;
368
369     return RichImage::first_edge_tag + e;
370
371   }
372
373   else return edge_type;
374 }
375
376 void PiReferential::draw(RGBImage *image, int level) {
377   int x1, y1, x2, y2, x3, y3, x4, y4;
378
379   if(level >= 1) {
380
381     // Draw the RM_BELLY reference frame
382
383     x1 = int(_belly_xc + _belly_ux + _belly_vx);
384     y1 = int(_belly_yc + _belly_uy + _belly_vy);
385     x2 = int(_belly_xc - _belly_ux + _belly_vx);
386     y2 = int(_belly_yc - _belly_uy + _belly_vy);
387     x3 = int(_belly_xc - _belly_ux - _belly_vx);
388     y3 = int(_belly_yc - _belly_uy - _belly_vy);
389     x4 = int(_belly_xc + _belly_ux - _belly_vx);
390     y4 = int(_belly_yc + _belly_uy - _belly_vy);
391
392     draw_frame(image, RM_BELLY, x1, y1, x2, y2, x3, y3, x4, y4);
393
394     // Draw the RM_HEAD_BELLY reference frame
395
396     x1 = int(_head_belly_xc + _head_belly_ux + _head_belly_vx);
397     y1 = int(_head_belly_yc + _head_belly_uy + _head_belly_vy);
398     x2 = int(_head_belly_xc - _head_belly_ux + _head_belly_vx);
399     y2 = int(_head_belly_yc - _head_belly_uy + _head_belly_vy);
400     x3 = int(_head_belly_xc - _head_belly_ux - _head_belly_vx);
401     y3 = int(_head_belly_yc - _head_belly_uy - _head_belly_vy);
402     x4 = int(_head_belly_xc + _head_belly_ux - _head_belly_vx);
403     y4 = int(_head_belly_yc + _head_belly_uy - _head_belly_vy);
404
405     draw_frame(image, RM_HEAD_BELLY, x1, y1, x2, y2, x3, y3, x4, y4);
406   }
407
408   // Draw the RM_HEAD reference frame
409
410   x1 = int(_head_xc + _head_ux + _head_vx);
411   y1 = int(_head_yc + _head_uy + _head_vy);
412   x2 = int(_head_xc - _head_ux + _head_vx);
413   y2 = int(_head_yc - _head_uy + _head_vy);
414   x3 = int(_head_xc - _head_ux - _head_vx);
415   y3 = int(_head_yc - _head_uy - _head_vy);
416   x4 = int(_head_xc + _head_ux - _head_vx);
417   y4 = int(_head_yc + _head_uy - _head_vy);
418
419   draw_frame(image, RM_HEAD, x1, y1, x2, y2, x3, y3, x4, y4);
420 }
421
422 void PiReferential::print_registration_mode(ostream *out, int registration_mode) {
423   switch(registration_mode) {
424   case RM_HEAD:
425     (*out) << "RM_HEAD";
426     break;
427   case RM_HEAD_NO_POLARITY:
428     (*out) << "RM_HEAD_NO_POLARITY";
429     break;
430   case RM_BELLY:
431     (*out) << "RM_BELLY";
432     break;
433   case RM_BELLY_NO_POLARITY:
434     (*out) << "RM_BELLY_NO_POLARITY";
435     break;
436   case RM_HEAD_BELLY:
437     (*out) << "RM_HEAD_BELLY";
438     break;
439   case RM_HEAD_BELLY_EDGES:
440     (*out) << "RM_HEAD_BELLY_EDGES";
441     break;
442   default:
443     abort();
444   }
445 }