2 * folded-ctf is an implementation of the folded hierarchy of
3 * classifiers for object detection, developed by Francois Fleuret
6 * Copyright (c) 2008 Idiap Research Institute, http://www.idiap.ch/
7 * Written by Francois Fleuret <francois.fleuret@idiap.ch>
9 * This file is part of folded-ctf.
11 * folded-ctf is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published
13 * by the Free Software Foundation, either version 3 of the License,
14 * or (at your option) any later version.
16 * folded-ctf is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with folded-ctf. If not, see <http://www.gnu.org/licenses/>.
26 #include "pi_referential.h"
28 #include "rich_image.h"
30 void PiReferential::draw_frame(RGBImage *image,
31 int registration_mode,
39 switch(registration_mode) {
41 case PiReferential::RM_HEAD:
42 r = 0; g = 255; b = 0;
45 case PiReferential::RM_HEAD_NO_POLARITY:
46 r = 128; g = 255; b = 128;
49 case PiReferential::RM_BELLY:
50 r = 64; g = 0; b = 255;
53 case PiReferential::RM_BELLY_NO_POLARITY:
54 r = 192; g = 128; b = 255;
57 case PiReferential::RM_HEAD_BELLY:
58 case PiReferential::RM_HEAD_BELLY_EDGES:
59 r = 255; g = 0; b = 0;
63 cerr << "INCONSISTENCY" << endl;
67 if(global.pictures_for_article) {
68 r = 255; g = 255; b = 255;
69 image->draw_line(6, r, g, b, x1, y1, x2, y2);
70 image->draw_line(6, r, g, b, x2, y2, x3, y3);
71 image->draw_line(6, r, g, b, x3, y3, x4, y4);
72 image->draw_line(6, r, g, b, x4, y4, x1, y1);
75 image->draw_line(2, r, g, b, x1, y1, x2, y2);
76 image->draw_line(2, r, g, b, x2, y2, x3, y3);
77 image->draw_line(2, r, g, b, x3, y3, x4, y4);
78 image->draw_line(2, r, g, b, x4, y4, x1, y1);
80 image->draw_line(2, r, g, b, x1, y1, x2, y2);
81 image->draw_line(2, r, g, b, x2, y2, x3, y3);
82 image->draw_line(2, r, g, b, x3, y3, x4, y4);
83 image->draw_line(2, r, g, b, x4, y4, x1, y1);
87 void PiReferential::draw_window(RGBImage *image,
88 int registration_mode, Rectangle *window,
92 switch(registration_mode) {
94 case PiReferential::RM_HEAD:
95 r = 0; g = 255; b = 0;
98 case PiReferential::RM_HEAD_NO_POLARITY:
99 r = 128; g = 255; b = 128;
102 case PiReferential::RM_BELLY:
103 r = 64; g = 0; b = 255;
106 case PiReferential::RM_BELLY_NO_POLARITY:
107 r = 192; g = 128; b = 255;
110 case PiReferential::RM_HEAD_BELLY:
111 case PiReferential::RM_HEAD_BELLY_EDGES:
112 r = 255; g = 0; b = 0;
116 cerr << "INCONSISTENCY" << endl;
120 int xmin = int(window->xmin);
121 int ymin = int(window->ymin);
122 int xmax = int(window->xmax);
123 int ymax = int(window->ymax);
125 if(global.pictures_for_article) {
126 r = 255; g = 255; b = 255;
127 image->draw_line(6, r, g, b, xmin, ymin, xmax, ymin);
128 image->draw_line(6, r, g, b, xmax, ymin, xmax, ymax);
129 image->draw_line(6, r, g, b, xmax, ymax, xmin, ymax);
130 image->draw_line(6, r, g, b, xmin, ymax, xmin, ymin);
133 image->draw_line(2, r, g, b, xmin, ymin, xmax, ymin);
134 image->draw_line(2, r, g, b, xmax, ymin, xmax, ymax);
135 image->draw_line(2, r, g, b, xmax, ymax, xmin, ymax);
136 image->draw_line(2, r, g, b, xmin, ymax, xmin, ymin);
139 image->draw_line(2, r, g, b, xmin, ymin, xmax, ymin);
140 image->draw_line(2, r, g, b, xmax, ymin, xmax, ymax);
141 image->draw_line(2, r, g, b, xmax, ymax, xmin, ymax);
142 image->draw_line(2, r, g, b, xmin, ymax, xmin, ymin);
145 for(int d = ymin - ymax; d <= xmax - xmin; d += delta) {
148 int x2 = xmin + d + ymax - ymin;
150 if(x1 < xmin) { y1 = y1 + (xmin - x1); x1 = xmin; }
151 if(x2 > xmax) { y2 = y2 - (x2 - xmax); x2 = xmax; }
152 image->draw_line(1, r, g, b, x1, y1, x2, y2);
159 PiReferential::PiReferential(PoseCell *cell) {
160 scalar_t head_radius = sqrt(scalar_t(cell->_head_radius.min * cell->_head_radius.max));
162 _common_scale = global.scale_to_discrete_log_scale(head_radius / global.min_head_radius);
164 scalar_t discrete_scale_ratio = global.discrete_log_scale_to_scale(_common_scale);
166 //////////////////////////////////////////////////////////////////////
167 // Locations and scales
171 _head_xc = cell->_head_xc.middle() * discrete_scale_ratio;
172 _head_yc = cell->_head_yc.middle() * discrete_scale_ratio;
173 _head_radius = cell->_head_radius.middle() * discrete_scale_ratio;
174 _head_window_scaling = _head_radius * 2.0;
178 // **********************************************************************
179 // Useless code, but necessary to keep the exact same results with
180 // g++ 4.1 and -O3 options on reference experiments.
181 _body_xc = cell->_belly_xc.middle() * discrete_scale_ratio;
182 _body_yc = cell->_belly_yc.middle() * discrete_scale_ratio;
184 if((_head_xc - _body_xc) * cos(_body_tilt) + (_head_yc - _body_yc) * sin(_body_tilt) > 0) {
187 // **********************************************************************
191 const scalar_t belly_frame_factor = 2.0;
193 _belly_xc = cell->_belly_xc.middle() * discrete_scale_ratio;
194 _belly_yc = cell->_belly_yc.middle() * discrete_scale_ratio;
195 _belly_window_scaling = _head_window_scaling * belly_frame_factor;
197 // Head-belly location
199 _head_belly_xc = (_head_xc + _belly_xc) * 0.5;
200 _head_belly_yc = (_head_yc + _belly_yc) * 0.5;
202 //////////////////////////////////////////////////////////////////////
205 if(_body_xc >= _head_xc) {
206 // if(_belly_xc >= _head_xc) {
207 _horizontal_polarity = 1;
209 _horizontal_polarity = -1;
214 if(_horizontal_polarity < 0) {
215 _head_ux = _head_radius * 2.0;
218 _head_ux = - _head_radius * 2.0;
223 _head_vy = - _head_radius * 2.0;
225 _head_ux_nopolarity = _head_radius * 2.0;
226 _head_uy_nopolarity = 0;
227 _head_vx_nopolarity = 0;
228 _head_vy_nopolarity = - _head_radius * 2.0;
232 _belly_ux = _head_ux * belly_frame_factor;
233 _belly_uy = _head_uy * belly_frame_factor;
234 _belly_vx = _head_vx * belly_frame_factor;
235 _belly_vy = _head_vy * belly_frame_factor;
237 _belly_ux_nopolarity = _head_ux_nopolarity * belly_frame_factor;
238 _belly_uy_nopolarity = _head_uy_nopolarity * belly_frame_factor;
239 _belly_vx_nopolarity = _head_vx_nopolarity * belly_frame_factor;
240 _belly_vy_nopolarity = _head_vy_nopolarity * belly_frame_factor;
244 _head_belly_ux = 2 * (_head_xc - _head_belly_xc);
245 _head_belly_uy = 2 * (_head_yc - _head_belly_yc);
247 if(_horizontal_polarity < 0) {
248 _head_belly_vx = _head_belly_uy;
249 _head_belly_vy = - _head_belly_ux;
251 _head_belly_vx = - _head_belly_uy;
252 _head_belly_vy = _head_belly_ux;
255 scalar_t l = sqrt(_head_belly_vx * _head_belly_vx + _head_belly_vy * _head_belly_vy);
257 _head_belly_vx = (_head_belly_vx / l) * _head_radius * 2;
258 _head_belly_vy = (_head_belly_vy / l) * _head_radius * 2;
259 _head_belly_edge_shift = int(floor(- RichImage::nb_edge_tags * atan2(_head_belly_ux, _head_belly_uy) / (2 * M_PI) + 0.5));
260 _head_belly_edge_shift = (RichImage::nb_edge_tags + _head_belly_edge_shift) % RichImage::nb_edge_tags;
263 int PiReferential::common_scale() {
264 return _common_scale;
267 void PiReferential::register_rectangle(int registration_mode,
270 scalar_t alpha, beta , xc, yc, w, h;
272 alpha = (original->xmin + original->xmax) * 0.5;
273 beta = (original->ymin + original->ymax) * 0.5;
275 switch(registration_mode) {
279 xc = _head_xc + alpha * _head_ux + beta * _head_vx;
280 yc = _head_yc + alpha * _head_uy + beta * _head_vy;
281 w = (original->xmax - original->xmin) * _head_window_scaling;
282 h = (original->ymax - original->ymin) * _head_window_scaling;
286 case RM_HEAD_NO_POLARITY:
288 xc = _head_xc + alpha * _head_ux_nopolarity + beta * _head_vx_nopolarity;
289 yc = _head_yc + alpha * _head_uy_nopolarity + beta * _head_vy_nopolarity;
290 w = (original->xmax - original->xmin) * _head_window_scaling;
291 h = (original->ymax - original->ymin) * _head_window_scaling;
297 xc = _belly_xc + alpha * _belly_ux + beta * _belly_vx;
298 yc = _belly_yc + alpha * _belly_uy + beta * _belly_vy;
299 w = (original->xmax - original->xmin) * _belly_window_scaling;
300 h = (original->ymax - original->ymin) * _belly_window_scaling;
304 case RM_BELLY_NO_POLARITY:
306 xc = _belly_xc + alpha * _belly_ux_nopolarity + beta * _belly_vx_nopolarity;
307 yc = _belly_yc + alpha * _belly_uy_nopolarity + beta * _belly_vy_nopolarity;
308 w = (original->xmax - original->xmin) * _belly_window_scaling;
309 h = (original->ymax - original->ymin) * _belly_window_scaling;
314 case RM_HEAD_BELLY_EDGES:
316 xc = _head_belly_xc + alpha * _head_belly_ux + beta * _head_belly_vx;
317 yc = _head_belly_yc + alpha * _head_belly_uy + beta * _head_belly_vy;
318 w = (original->xmax - original->xmin) * _head_window_scaling;
319 h = (original->ymax - original->ymin) * _head_window_scaling;
324 cerr << "Undefined registration mode." << endl;
328 result->xmin = xc - 0.5 * w;
329 result->ymin = yc - 0.5 * h;
330 result->xmax = xc + 0.5 * w;
331 result->ymax = yc + 0.5 * h;
333 ASSERT(result->xmin < result->xmax && result->ymin < result->ymax);
336 int PiReferential::register_edge(int registration_mode, int edge_type) {
338 if(edge_type >= RichImage::first_edge_tag &&
339 edge_type < RichImage::first_edge_tag + RichImage::nb_edge_tags) {
341 int e = edge_type - RichImage::first_edge_tag;
343 switch(registration_mode) {
344 case PiReferential::RM_HEAD_NO_POLARITY:
345 case PiReferential::RM_BELLY_NO_POLARITY:
348 case PiReferential::RM_HEAD:
349 case PiReferential::RM_BELLY:
350 case PiReferential::RM_HEAD_BELLY:
351 if(_horizontal_polarity < 0) {
352 e = (RichImage::nb_edge_tags - e) % RichImage::nb_edge_tags;
356 case PiReferential::RM_HEAD_BELLY_EDGES:
357 if(_horizontal_polarity < 0) {
358 e = (RichImage::nb_edge_tags - e) % RichImage::nb_edge_tags;
360 e += _head_belly_edge_shift;
364 cerr << "INCONSISTENCY" << endl;
368 e = e % RichImage::nb_edge_tags;
370 return RichImage::first_edge_tag + e;
374 else return edge_type;
377 void PiReferential::draw(RGBImage *image, int level) {
378 int x1, y1, x2, y2, x3, y3, x4, y4;
382 // Draw the RM_BELLY reference frame
384 x1 = int(_belly_xc + _belly_ux + _belly_vx);
385 y1 = int(_belly_yc + _belly_uy + _belly_vy);
386 x2 = int(_belly_xc - _belly_ux + _belly_vx);
387 y2 = int(_belly_yc - _belly_uy + _belly_vy);
388 x3 = int(_belly_xc - _belly_ux - _belly_vx);
389 y3 = int(_belly_yc - _belly_uy - _belly_vy);
390 x4 = int(_belly_xc + _belly_ux - _belly_vx);
391 y4 = int(_belly_yc + _belly_uy - _belly_vy);
393 draw_frame(image, RM_BELLY, x1, y1, x2, y2, x3, y3, x4, y4);
395 // Draw the RM_HEAD_BELLY reference frame
397 x1 = int(_head_belly_xc + _head_belly_ux + _head_belly_vx);
398 y1 = int(_head_belly_yc + _head_belly_uy + _head_belly_vy);
399 x2 = int(_head_belly_xc - _head_belly_ux + _head_belly_vx);
400 y2 = int(_head_belly_yc - _head_belly_uy + _head_belly_vy);
401 x3 = int(_head_belly_xc - _head_belly_ux - _head_belly_vx);
402 y3 = int(_head_belly_yc - _head_belly_uy - _head_belly_vy);
403 x4 = int(_head_belly_xc + _head_belly_ux - _head_belly_vx);
404 y4 = int(_head_belly_yc + _head_belly_uy - _head_belly_vy);
406 draw_frame(image, RM_HEAD_BELLY, x1, y1, x2, y2, x3, y3, x4, y4);
409 // Draw the RM_HEAD reference frame
411 x1 = int(_head_xc + _head_ux + _head_vx);
412 y1 = int(_head_yc + _head_uy + _head_vy);
413 x2 = int(_head_xc - _head_ux + _head_vx);
414 y2 = int(_head_yc - _head_uy + _head_vy);
415 x3 = int(_head_xc - _head_ux - _head_vx);
416 y3 = int(_head_yc - _head_uy - _head_vy);
417 x4 = int(_head_xc + _head_ux - _head_vx);
418 y4 = int(_head_yc + _head_uy - _head_vy);
420 draw_frame(image, RM_HEAD, x1, y1, x2, y2, x3, y3, x4, y4);
423 void PiReferential::print_registration_mode(ostream *out, int registration_mode) {
424 switch(registration_mode) {
428 case RM_HEAD_NO_POLARITY:
429 (*out) << "RM_HEAD_NO_POLARITY";
432 (*out) << "RM_BELLY";
434 case RM_BELLY_NO_POLARITY:
435 (*out) << "RM_BELLY_NO_POLARITY";
438 (*out) << "RM_HEAD_BELLY";
440 case RM_HEAD_BELLY_EDGES:
441 (*out) << "RM_HEAD_BELLY_EDGES";