X-Git-Url: https://fleuret.org/cgi-bin/gitweb/gitweb.cgi?p=folded-ctf.git;a=blobdiff_plain;f=pose.cc;fp=pose.cc;h=ed6c7058afc321edac0301f2e8e9e964d8a8876d;hp=0000000000000000000000000000000000000000;hb=d922ad61d35e9a6996730bec24b16f8bf7bc426c;hpb=3bb118f5a9462d02ff7d99ef28ecc0d7e23529f9 diff --git a/pose.cc b/pose.cc new file mode 100644 index 0000000..ed6c705 --- /dev/null +++ b/pose.cc @@ -0,0 +1,190 @@ + +/////////////////////////////////////////////////////////////////////////// +// This program is free software: you can redistribute it and/or modify // +// it under the terms of the version 3 of the GNU General Public License // +// as published by the Free Software Foundation. // +// // +// This program is distributed in the hope that it will be useful, but // +// WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // +// General Public License for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +// // +// Written by Francois Fleuret, (C) IDIAP // +// Contact for comments & bug reports // +/////////////////////////////////////////////////////////////////////////// + +#include + +#include "pose.h" + +Pose::Pose() { + memset(this, 0, sizeof(*this)); +} + +void Pose::horizontal_flip(scalar_t scene_width) { + _head_xc = scene_width - 1 - _head_xc; + _body_xc = scene_width - 1 - _body_xc; +} + +void Pose::translate(scalar_t dx, scalar_t dy) { + _bounding_box_xmin += dx; + _bounding_box_ymin += dy; + _bounding_box_xmax += dx; + _bounding_box_ymax += dy; + _head_xc += dx; + _head_yc += dy; + _body_xc += dx; + _body_yc += dy; +} + +void Pose::scale(scalar_t factor) { + _bounding_box_xmin *= factor; + _bounding_box_ymin *= factor; + _bounding_box_xmax *= factor; + _bounding_box_ymax *= factor; + _head_xc *= factor; + _head_yc *= factor; + _head_radius *= factor; + _body_xc *= factor; + _body_yc *= factor; +} + +const scalar_t tolerance_scale_ratio_for_hit = 1.5; +const scalar_t tolerance_distance_factor_for_hit = 1.0; + +bool Pose::hit(int level, Pose *pose) { + + // Head size + + if(_head_radius/pose->_head_radius > tolerance_scale_ratio_for_hit || + pose->_head_radius/_head_radius > tolerance_scale_ratio_for_hit) + return false; + + scalar_t sq_delta = _head_radius * pose->_head_radius * sq(tolerance_distance_factor_for_hit); + + // Head location + + if(sq(_head_xc - pose->_head_xc) + sq(_head_yc - pose->_head_yc) > sq_delta) + return false; + + if(level == 0) return true; + + // Belly location + + if(sq(_body_xc - pose->_body_xc) + sq(_body_yc - pose->_body_yc) > 4 * sq_delta) + return false; + + if(level == 1) return true; + + cerr << "Hit criterion is undefined for level " << level << endl; + + abort(); +} + +const scalar_t tolerance_scale_ratio_for_collide = 1.2; +const scalar_t tolerance_distance_factor_for_collide = 0.25; + +bool Pose::collide(int level, Pose *pose) { + + // Head size + + if(_head_radius/pose->_head_radius > tolerance_scale_ratio_for_collide || + pose->_head_radius/_head_radius > tolerance_scale_ratio_for_collide) + return false; + + scalar_t sq_delta = _head_radius * pose->_head_radius * sq(tolerance_distance_factor_for_collide); + + // Head location + + if(sq(_head_xc - pose->_head_xc) + sq(_head_yc - pose->_head_yc) <= sq_delta) + return true; + + if(level == 0) return false; + + // Belly location + + if(sq(_body_xc - pose->_body_xc) + sq(_body_yc - pose->_body_yc) <= sq_delta) + return true; + + if(level == 1) return false; + + cerr << "Colliding criterion is undefined for level " << level << endl; + + abort(); +} + +void Pose::draw(int thickness, int r, int g, int b, int level, RGBImage *image) { + // Draw the head circle + + image->draw_ellipse(thickness, r, g, b, + _head_xc, _head_yc, _head_radius, _head_radius, 0); + + // int vx = int(cos(_head_tilt) * _head_radius); + // int vy = int(sin(_head_tilt) * _head_radius); + // image->draw_line(thickness, r, g, b, _head_xc, _head_yc, _head_xc + vx, _head_yc + vy); + + if(level == 1) { + + // image->draw_line(thickness, r, g, b, + // int(_body_xc) - delta, int(_body_yc), + // int(_body_xc) + delta, int(_body_yc)); + + // image->draw_line(thickness, r, g, b, + // int(_body_xc), int(_body_yc) - delta, + // int(_body_xc), int(_body_yc) + delta); + + scalar_t vx = _body_xc - _head_xc, vy = _body_yc - _head_yc; + scalar_t l = sqrt(vx * vx + vy * vy); + vx /= l; + vy /= l; + + scalar_t body_radius = 12 + thickness / 2; + + if(l > _head_radius + thickness + body_radius) { + image->draw_line(thickness, r, g, b, + _head_xc + vx * (_head_radius + thickness/2), + _head_yc + vy * (_head_radius + thickness/2), + _body_xc - vx * (body_radius - thickness/2), + _body_yc - vy * (body_radius - thickness/2)); + } + + // An ugly way to make a filled disc + for(scalar_t u = 0; u < body_radius; u += thickness / 2) { + image->draw_ellipse(thickness, r, g, b, _body_xc, _body_yc, u, u, 0); + } + + } +} + +void Pose::print(ostream *out) { + (*out) << " _head_xc " << _head_xc << endl; + (*out) << " _head_yc " << _head_yc << endl; + (*out) << " _head_radius " << _head_radius << endl; + (*out) << " _body_xc " << _body_xc << endl; + (*out) << " _body_yc " << _body_yc << endl; +} + +void Pose::write(ostream *out) { + write_var(out, &_bounding_box_xmin); + write_var(out, &_bounding_box_ymin); + write_var(out, &_bounding_box_xmax); + write_var(out, &_bounding_box_ymax); + write_var(out, &_head_xc); write_var(out, &_head_yc); + write_var(out, &_head_radius); + write_var(out, &_body_xc); + write_var(out, &_body_yc); +} + +void Pose::read(istream *in) { + read_var(in, &_bounding_box_xmin); + read_var(in, &_bounding_box_ymin); + read_var(in, &_bounding_box_xmax); + read_var(in, &_bounding_box_ymax); + read_var(in, &_head_xc); read_var(in, &_head_yc); + read_var(in, &_head_radius); + read_var(in, &_body_xc); + read_var(in, &_body_yc); +}