X-Git-Url: https://www.fleuret.org/cgi-bin/gitweb/gitweb.cgi?p=folded-ctf.git;a=blobdiff_plain;f=pose_cell_hierarchy.cc;h=baa64599d2895345f32e5a4ef25161539d5cc056;hp=0816f3a2819ce94a2e43bd71a8c2b1eaa4e7b7ec;hb=HEAD;hpb=d922ad61d35e9a6996730bec24b16f8bf7bc426c diff --git a/pose_cell_hierarchy.cc b/pose_cell_hierarchy.cc index 0816f3a..baa6459 100644 --- a/pose_cell_hierarchy.cc +++ b/pose_cell_hierarchy.cc @@ -1,33 +1,39 @@ - -/////////////////////////////////////////////////////////////////////////// -// 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 // -/////////////////////////////////////////////////////////////////////////// +/* + * folded-ctf is an implementation of the folded hierarchy of + * classifiers for object detection, developed by Francois Fleuret + * and Donald Geman. + * + * Copyright (c) 2008 Idiap Research Institute, http://www.idiap.ch/ + * Written by Francois Fleuret + * + * This file is part of folded-ctf. + * + * folded-ctf is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * folded-ctf 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 folded-ctf. If not, see . + * + */ #include "pose_cell_hierarchy.h" #include "gaussian.h" PoseCellHierarchy::PoseCellHierarchy() { - _body_cells = 0; + _belly_cells = 0; } PoseCellHierarchy::PoseCellHierarchy(LabelledImagePool *train_pool) { _nb_levels = global.nb_levels; _min_head_radius = global.min_head_radius; _max_head_radius = global.max_head_radius; - _root_cell_nb_xy_per_scale = global.root_cell_nb_xy_per_scale; + _root_cell_nb_xy_per_radius = global.root_cell_nb_xy_per_radius; LabelledImage *image; int nb_total_targets = 0; @@ -38,7 +44,7 @@ PoseCellHierarchy::PoseCellHierarchy(LabelledImagePool *train_pool) { train_pool->release_image(i); } - RelativeBodyPoseCell targets[nb_total_targets]; + RelativeBellyPoseCell targets[nb_total_targets]; int u = 0; for(int i = 0; i < train_pool->nb_images(); i++) { @@ -53,16 +59,16 @@ PoseCellHierarchy::PoseCellHierarchy(LabelledImagePool *train_pool) { cell_set.get_containing_cell(&pose)->get_centroid(&coarse); - targets[u]._body_xc.set((pose._body_xc - coarse._head_xc) / coarse._head_radius); - targets[u]._body_yc.set((pose._body_yc - coarse._head_yc) / coarse._head_radius); + targets[u]._belly_xc.set((pose._belly_xc - coarse._head_xc) / coarse._head_radius); + targets[u]._belly_yc.set((pose._belly_yc - coarse._head_yc) / coarse._head_radius); u++; pose.horizontal_flip(image->width()); cell_set.get_containing_cell(&pose)->get_centroid(&coarse); - targets[u]._body_xc.set((pose._body_xc - coarse._head_xc) / coarse._head_radius); - targets[u]._body_yc.set((pose._body_yc - coarse._head_yc) / coarse._head_radius); + targets[u]._belly_xc.set((pose._belly_xc - coarse._head_xc) / coarse._head_radius); + targets[u]._belly_yc.set((pose._belly_yc - coarse._head_yc) / coarse._head_radius); u++; } @@ -71,38 +77,30 @@ PoseCellHierarchy::PoseCellHierarchy(LabelledImagePool *train_pool) { scalar_t fattening = 1.1; - Interval body_rxc, body_ryc; + Interval belly_rxc, belly_ryc; - body_rxc.set(&targets[0]._body_xc); - body_ryc.set(&targets[0]._body_yc); + belly_rxc.set(&targets[0]._belly_xc); + belly_ryc.set(&targets[0]._belly_yc); for(int t = 0; t < nb_total_targets; t++) { - body_rxc.swallow(&targets[t]._body_xc); - body_ryc.swallow(&targets[t]._body_yc); + belly_rxc.swallow(&targets[t]._belly_xc); + belly_ryc.swallow(&targets[t]._belly_yc); } - body_rxc.min *= fattening; - body_rxc.max *= fattening; - body_ryc.min *= fattening; - body_ryc.max *= fattening; - - scalar_t body_rxc_min = body_resolution * floor(body_rxc.min / body_resolution); - int nb_body_rxc = int(ceil((body_rxc.max - body_rxc_min) / body_resolution)); + belly_rxc.min *= fattening; + belly_rxc.max *= fattening; + belly_ryc.min *= fattening; + belly_ryc.max *= fattening; - scalar_t body_ryc_min = body_resolution * floor(body_ryc.min / body_resolution); - int nb_body_ryc = int(ceil((body_ryc.max - body_ryc_min) / body_resolution)); + scalar_t belly_rxc_min = belly_resolution * floor(belly_rxc.min / belly_resolution); + int nb_belly_rxc = int(ceil((belly_rxc.max - belly_rxc_min) / belly_resolution)); - (*global.log_stream) << "body_rxc = " << body_rxc << endl - << "body_rxc_min = " << body_rxc_min << endl - << "body_rxc_min + nb_body_rxc * body_resolution = " << body_rxc_min + nb_body_rxc * body_resolution << endl - << endl - << "body_ryc = " << body_ryc << endl - << "body_ryc_min = " << body_ryc_min << endl - << "body_ryc_min + nb_body_ryc * body_resolution = " << body_ryc_min + nb_body_ryc * body_resolution << endl; + scalar_t belly_ryc_min = belly_resolution * floor(belly_ryc.min / belly_resolution); + int nb_belly_ryc = int(ceil((belly_ryc.max - belly_ryc_min) / belly_resolution)); - int used[nb_body_rxc * nb_body_rxc]; + int used[nb_belly_rxc * nb_belly_rxc]; - for(int k = 0; k < nb_body_rxc * nb_body_ryc; k++) { + for(int k = 0; k < nb_belly_rxc * nb_belly_ryc; k++) { used[k] = 1; } @@ -113,129 +111,65 @@ PoseCellHierarchy::PoseCellHierarchy(LabelledImagePool *train_pool) { scalar_t rho = 0; for(int t = 0; t < nb_total_targets; t++) { - rho = min(rho, vx * targets[t]._body_xc.middle() + vy * targets[t]._body_yc.middle()); + rho = min(rho, vx * targets[t]._belly_xc.middle() + vy * targets[t]._belly_yc.middle()); } rho *= fattening; - for(int j = 0; j < nb_body_ryc; j++) { - for(int i = 0; i < nb_body_rxc; i++) { + for(int j = 0; j < nb_belly_ryc; j++) { + for(int i = 0; i < nb_belly_rxc; i++) { if( - vx * (scalar_t(i + 0) * body_resolution + body_rxc_min) + - vy * (scalar_t(j + 0) * body_resolution + body_ryc_min) < rho + vx * (scalar_t(i + 0) * belly_resolution + belly_rxc_min) + + vy * (scalar_t(j + 0) * belly_resolution + belly_ryc_min) < rho && - vx * (scalar_t(i + 1) * body_resolution + body_rxc_min) + - vy * (scalar_t(j + 0) * body_resolution + body_ryc_min) < rho + vx * (scalar_t(i + 1) * belly_resolution + belly_rxc_min) + + vy * (scalar_t(j + 0) * belly_resolution + belly_ryc_min) < rho && - vx * (scalar_t(i + 0) * body_resolution + body_rxc_min) + - vy * (scalar_t(j + 1) * body_resolution + body_ryc_min) < rho + vx * (scalar_t(i + 0) * belly_resolution + belly_rxc_min) + + vy * (scalar_t(j + 1) * belly_resolution + belly_ryc_min) < rho && - vx * (scalar_t(i + 1) * body_resolution + body_rxc_min) + - vy * (scalar_t(j + 1) * body_resolution + body_ryc_min) < rho + vx * (scalar_t(i + 1) * belly_resolution + belly_rxc_min) + + vy * (scalar_t(j + 1) * belly_resolution + belly_ryc_min) < rho ) { - used[i + j * nb_body_rxc] = 0; + used[i + j * nb_belly_rxc] = 0; } } } } - _nb_body_cells = 0; - for(int j = 0; j < nb_body_ryc; j++) { - for(int i = 0; i < nb_body_rxc; i++) { - if(used[i + nb_body_rxc * j]) { - _nb_body_cells++; + _nb_belly_cells = 0; + for(int j = 0; j < nb_belly_ryc; j++) { + for(int i = 0; i < nb_belly_rxc; i++) { + if(used[i + nb_belly_rxc * j]) { + _nb_belly_cells++; } } } - _body_cells = new RelativeBodyPoseCell[_nb_body_cells]; - - for(int j = 0; j < nb_body_ryc; j++) { - for(int i = 0; i < nb_body_rxc; i++) { - if(used[i + nb_body_rxc * j]) { - if(sq(scalar_t(i) * body_resolution + body_resolution/2 + body_rxc_min) + - sq(scalar_t(j) * body_resolution + body_resolution/2 + body_ryc_min) <= 1) { - (*global.log_stream) << "*"; - } else { - (*global.log_stream) << "X"; - } - } else { - (*global.log_stream) << "."; - } - } - (*global.log_stream) << endl; - } + _belly_cells = new RelativeBellyPoseCell[_nb_belly_cells]; int k = 0; - for(int j = 0; j < nb_body_ryc; j++) { - for(int i = 0; i < nb_body_rxc; i++) { - - if(used[i + nb_body_rxc * j]) { - - RelativeBodyPoseCell mother; - - scalar_t x = scalar_t(i) * body_resolution + body_rxc_min; - scalar_t y = scalar_t(j) * body_resolution + body_ryc_min; - - mother._body_xc.set(x, x + body_resolution); - mother._body_yc.set(y, y + body_resolution); + for(int j = 0; j < nb_belly_ryc; j++) { + for(int i = 0; i < nb_belly_rxc; i++) { - // scalar_t dist_min = body_resolution; - scalar_t dist_min = 1e6; + if(used[i + nb_belly_rxc * j]) { - int nb_got; + RelativeBellyPoseCell mother; - Gaussian dist_body_radius_1, dist_body_radius_2, dist_body_tilt; + scalar_t x = scalar_t(i) * belly_resolution + belly_rxc_min; + scalar_t y = scalar_t(j) * belly_resolution + belly_ryc_min; - do { + mother._belly_xc.set(x, x + belly_resolution); + mother._belly_yc.set(y, y + belly_resolution); - nb_got = 0; - - for(int t = 0; t < nb_total_targets; t++) { - - scalar_t dist = - sqrt(sq(targets[t]._body_xc.middle() - x - body_resolution / 2) + - sq(targets[t]._body_yc.middle() - y - body_resolution / 2)); - - if(dist <= dist_min) { - dist_body_radius_1.add_sample(targets[t]._body_radius_1.middle()); - dist_body_radius_2.add_sample(targets[t]._body_radius_2.middle()); - dist_body_tilt.add_sample(targets[t]._body_tilt.middle()); - nb_got++; - } - - } - - dist_min *= 2.0; - } while(nb_got < min(100, nb_total_targets)); - - scalar_t zeta = 4; - - mother._body_radius_1.set(dist_body_radius_1.expectation() - - zeta * dist_body_radius_1.standard_deviation(), - dist_body_radius_1.expectation() + - zeta * dist_body_radius_1.standard_deviation()); - - mother._body_radius_2.set(dist_body_radius_2.expectation() - - zeta * dist_body_radius_2.standard_deviation(), - dist_body_radius_2.expectation() + - zeta * dist_body_radius_2.standard_deviation()); - - mother._body_tilt.set(dist_body_tilt.expectation() - - zeta * dist_body_tilt.standard_deviation(), - dist_body_tilt.expectation() + - zeta * dist_body_tilt.standard_deviation()); - - _body_cells[k++] = mother; + _belly_cells[k++] = mother; } } } - - (*global.log_stream) << _nb_body_cells << " body cells." << endl; } PoseCellHierarchy::~PoseCellHierarchy() { - delete[] _body_cells; + delete[] _belly_cells; } int PoseCellHierarchy::nb_levels() { @@ -267,7 +201,7 @@ void PoseCellHierarchy::add_root_cells(Image *image, PoseCellSet *cell_set) { scalar_t beta = log(2) / scalar_t(global.nb_scales_per_power_of_two); for(int s = 0; s < nb_scales; s++) { - scalar_t cell_xy_size = exp(alpha + scalar_t(s) * beta) / global.root_cell_nb_xy_per_scale; + scalar_t cell_xy_size = exp(alpha + scalar_t(s) * beta) / global.root_cell_nb_xy_per_radius; PoseCell cell; cell._head_radius.min = exp(alpha + scalar_t(s) * beta); cell._head_radius.max = exp(alpha + scalar_t(s+1) * beta); @@ -279,10 +213,10 @@ void PoseCellHierarchy::add_root_cells(Image *image, PoseCellSet *cell_set) { cell._head_xc.max = x + cell_xy_size; cell._head_yc.min = y; cell._head_yc.max = y + cell_xy_size; - cell._body_xc.min = cell._head_xc.min - pseudo_infty; - cell._body_xc.max = cell._head_xc.max + pseudo_infty; - cell._body_yc.min = cell._head_yc.min - pseudo_infty; - cell._body_yc.max = cell._head_yc.max + pseudo_infty; + cell._belly_xc.min = cell._head_xc.min - pseudo_infty; + cell._belly_xc.max = cell._head_xc.max + pseudo_infty; + cell._belly_yc.min = cell._head_yc.min - pseudo_infty; + cell._belly_yc.max = cell._head_yc.max + pseudo_infty; cell_set->add_cell(&cell); } } @@ -295,16 +229,16 @@ void PoseCellHierarchy::add_subcells(int level, PoseCell *root, case 1: { - // Here we split the body-center coordinate cell part + // Here we split the belly-center coordinate cell part PoseCell cell = *root; scalar_t r = sqrt(cell._head_radius.min * cell._head_radius.max); scalar_t x = (cell._head_xc.min + cell._head_xc.max) / 2.0; scalar_t y = (cell._head_yc.min + cell._head_yc.max) / 2.0; - for(int k = 0; k < _nb_body_cells; k++) { - cell._body_xc.min = (_body_cells[k]._body_xc.min * r) + x; - cell._body_xc.max = (_body_cells[k]._body_xc.max * r) + x; - cell._body_yc.min = (_body_cells[k]._body_yc.min * r) + y; - cell._body_yc.max = (_body_cells[k]._body_yc.max * r) + y; + for(int k = 0; k < _nb_belly_cells; k++) { + cell._belly_xc.min = (_belly_cells[k]._belly_xc.min * r) + x; + cell._belly_xc.max = (_belly_cells[k]._belly_xc.max * r) + x; + cell._belly_yc.min = (_belly_cells[k]._belly_yc.min * r) + y; + cell._belly_yc.max = (_belly_cells[k]._belly_yc.max * r) + y; cell_set->add_cell(&cell); } } @@ -372,21 +306,21 @@ int PoseCellHierarchy::nb_incompatible_poses(LabelledImagePool *pool) { void PoseCellHierarchy::write(ostream *os) { write_var(os, &_min_head_radius); write_var(os, &_max_head_radius); - write_var(os, &_root_cell_nb_xy_per_scale); - write_var(os, &_nb_body_cells); - for(int k = 0; k < _nb_body_cells; k++) - write_var(os, &_body_cells[k]); + write_var(os, &_root_cell_nb_xy_per_radius); + write_var(os, &_nb_belly_cells); + for(int k = 0; k < _nb_belly_cells; k++) + write_var(os, &_belly_cells[k]); } void PoseCellHierarchy::read(istream *is) { - delete[] _body_cells; + delete[] _belly_cells; read_var(is, &_min_head_radius); read_var(is, &_max_head_radius); - read_var(is, &_root_cell_nb_xy_per_scale); - read_var(is, &_nb_body_cells); - delete[] _body_cells; - _body_cells = new RelativeBodyPoseCell[_nb_body_cells]; - for(int k = 0; k < _nb_body_cells; k++) { - read_var(is, &_body_cells[k]); + read_var(is, &_root_cell_nb_xy_per_radius); + read_var(is, &_nb_belly_cells); + delete[] _belly_cells; + _belly_cells = new RelativeBellyPoseCell[_nb_belly_cells]; + for(int k = 0; k < _nb_belly_cells; k++) { + read_var(is, &_belly_cells[k]); } }