Removed the definition of basename, which confuses an existing system one.
[folded-ctf.git] / pose.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 <string.h>
26
27 #include "pose.h"
28
29 Pose::Pose() {
30   memset(this, 0, sizeof(*this));
31 }
32
33 void Pose::horizontal_flip(scalar_t scene_width) {
34   _head_xc = scene_width - 1 - _head_xc;
35   _belly_xc = scene_width - 1 - _belly_xc;
36 }
37
38 const scalar_t tolerance_scale_ratio_for_hit = 1.5;
39 const scalar_t tolerance_distance_factor_for_hit = 1.0;
40
41 bool Pose::hit(int level, Pose *pose) {
42
43   // Head size
44
45   if(_head_radius/pose->_head_radius > tolerance_scale_ratio_for_hit ||
46      pose->_head_radius/_head_radius > tolerance_scale_ratio_for_hit)
47     return false;
48
49   scalar_t sq_delta = _head_radius * pose->_head_radius * sq(tolerance_distance_factor_for_hit);
50
51   // Head location
52
53   if(sq(_head_xc - pose->_head_xc) + sq(_head_yc - pose->_head_yc) > sq_delta)
54     return false;
55
56   if(level == 0) return true;
57
58   // Belly location
59
60   if(sq(_belly_xc - pose->_belly_xc) + sq(_belly_yc - pose->_belly_yc) > 4 * sq_delta)
61     return false;
62
63   if(level == 1) return true;
64
65   cerr << "Hit criterion is undefined for level " << level << endl;
66
67   abort();
68 }
69
70 const scalar_t tolerance_scale_ratio_for_collide = 1.2;
71 const scalar_t tolerance_distance_factor_for_collide = 0.25;
72
73 bool Pose::collide(int level, Pose *pose) {
74
75   // Head size
76
77   if(_head_radius/pose->_head_radius > tolerance_scale_ratio_for_collide ||
78      pose->_head_radius/_head_radius > tolerance_scale_ratio_for_collide)
79     return false;
80
81   scalar_t sq_delta = _head_radius * pose->_head_radius * sq(tolerance_distance_factor_for_collide);
82
83   // Head location
84
85   if(sq(_head_xc - pose->_head_xc) + sq(_head_yc - pose->_head_yc) <= sq_delta)
86     return true;
87
88   if(level == 0) return false;
89
90   // Belly location
91
92   if(sq(_belly_xc - pose->_belly_xc) + sq(_belly_yc - pose->_belly_yc) <= sq_delta)
93     return true;
94
95   if(level == 1) return false;
96
97   cerr << "Colliding criterion is undefined for level " << level << endl;
98
99   abort();
100 }
101
102 void Pose::draw(int thickness, int r, int g, int b, int level, RGBImage *image) {
103
104   // Draw the head circle
105
106   image->draw_ellipse(thickness, r, g, b,
107                       _head_xc, _head_yc, _head_radius, _head_radius, 0);
108
109   if(level == 1) {
110
111     scalar_t vx = _belly_xc - _head_xc, vy = _belly_yc - _head_yc;
112     scalar_t l = sqrt(vx * vx + vy * vy);
113     vx /= l;
114     vy /= l;
115
116     scalar_t belly_radius = 12 + thickness / 2;
117
118     if(l > _head_radius + thickness + belly_radius) {
119       image->draw_line(thickness, r, g, b,
120                        _head_xc + vx * (_head_radius + thickness/2),
121                        _head_yc + vy * (_head_radius + thickness/2),
122                        _belly_xc - vx * (belly_radius - thickness/2),
123                        _belly_yc - vy * (belly_radius - thickness/2));
124     }
125
126     // An ugly way to make a filled disc
127
128     for(scalar_t u = 0; u < belly_radius; u += thickness / 2) {
129       image->draw_ellipse(thickness, r, g, b, _belly_xc, _belly_yc, u, u, 0);
130     }
131
132   }
133 }
134
135 void Pose::print(ostream *out) {
136   (*out) << "  _head_xc " << _head_xc << endl;
137   (*out) << "  _head_yc " << _head_yc << endl;
138   (*out) << "  _head_radius " << _head_radius << endl;
139   (*out) << "  _belly_xc " << _belly_xc << endl;
140   (*out) << "  _belly_yc " << _belly_yc << endl;
141 }
142
143 void Pose::write(ostream *out) {
144   write_var(out, &_bounding_box_xmin);
145   write_var(out, &_bounding_box_ymin);
146   write_var(out, &_bounding_box_xmax);
147   write_var(out, &_bounding_box_ymax);
148   write_var(out, &_head_xc); write_var(out, &_head_yc);
149   write_var(out, &_head_radius);
150   write_var(out, &_belly_xc);
151   write_var(out, &_belly_yc);
152 }
153
154 void Pose::read(istream *in) {
155   read_var(in, &_bounding_box_xmin);
156   read_var(in, &_bounding_box_ymin);
157   read_var(in, &_bounding_box_xmax);
158   read_var(in, &_bounding_box_ymax);
159   read_var(in, &_head_xc); read_var(in, &_head_yc);
160   read_var(in, &_head_radius);
161   read_var(in, &_belly_xc);
162   read_var(in, &_belly_yc);
163 }