--- /dev/null
+
+///////////////////////////////////////////////////////////////////////////
+// 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 <http://www.gnu.org/licenses/>. //
+// //
+// Written by Francois Fleuret, (C) IDIAP //
+// Contact <francois.fleuret@idiap.ch> for comments & bug reports //
+///////////////////////////////////////////////////////////////////////////
+
+#include "pi_feature.h"
+
+#include "global.h"
+#include "rectangle.h"
+
+int PiFeature::random_registration_mode(int level) {
+ while(1) {
+ switch(int(6 * drand48())) {
+
+ case 0:
+ return PiReferential::RM_HEAD;
+ break;
+
+ case 1:
+ if(level >= 1)
+ return PiReferential::RM_BELLY;
+ break;
+
+ case 2:
+ if(level >= 1)
+ return PiReferential::RM_HEAD_BELLY;
+ break;
+
+ case 3:
+ if(level >= 1)
+ return PiReferential::RM_HEAD_BELLY_EDGES;
+ break;
+
+ case 4:
+ if(level >= 2)
+ return PiReferential::RM_BODY;
+ break;
+
+ case 5:
+ if(level >= 2)
+ return PiReferential::RM_BODY_EDGES;
+ break;
+
+ default:
+ abort();
+ }
+ }
+}
+
+void PiFeature::randomize_window(int registration_mode, Rectangle *window) {
+ scalar_t xc, yc, w, h;
+
+ do {
+ xc = 2 * drand48() - 1.0;
+ yc = 2 * drand48() - 1.0;
+
+ w = 2 * drand48();
+
+ // If we are in a non-rotating frame, allow rectangular window,
+ // otherwise force it to be squared
+
+ if(registration_mode == PiReferential::RM_HEAD ||
+ registration_mode == PiReferential::RM_BELLY ||
+ registration_mode == PiReferential::RM_HEAD_NO_POLARITY ||
+ registration_mode == PiReferential::RM_BELLY_NO_POLARITY) {
+ h = 2 * drand48();
+ } else {
+ h = w;
+ }
+ } while(w < global.pi_feature_window_min_size ||
+ h < global.pi_feature_window_min_size ||
+ xc - w/2 < -1.0 || xc + w/2 > 1.0 ||
+ yc - h/2 < -1.0 || yc + h/2 > 1.0);
+
+ window->xmin = xc - w/2;
+ window->ymin = yc - h/2;
+ window->xmax = xc + w/2;
+ window->ymax = yc + h/2;
+}
+
+//////////////////////////////////////////////////////////////////////
+// PF_EDGE_THRESHOLDING
+
+scalar_t PiFeature::response_edge_thresholding(RichImage *image,
+ PiReferential *referential) {
+ Rectangle registered_window_a;
+
+ referential->register_rectangle(_registration_a,
+ &_window_a,
+ ®istered_window_a);
+
+ int tag = referential->register_edge(_registration_a, _tag);
+
+ int xmin_a = int(registered_window_a.xmin) >> _edge_scale;
+ int ymin_a = int(registered_window_a.ymin) >> _edge_scale;
+ int xmax_a = int(registered_window_a.xmax) >> _edge_scale;
+ int ymax_a = int(registered_window_a.ymax) >> _edge_scale;
+
+ int scale = referential->common_scale() + _edge_scale * global.nb_scales_per_power_of_two;
+
+ scalar_t ne, nt;
+
+ ASSERT((tag >= RichImage::first_edge_tag &&
+ tag < RichImage::first_edge_tag + RichImage::nb_edge_tags) ||
+ tag == RichImage::variance_tag);
+
+ if(tag != RichImage::variance_tag) {
+ ne = scalar_t(image->nb_tags_in_window(scale, tag,
+ xmin_a, ymin_a, xmax_a, ymax_a));
+ nt = scalar_t(image->nb_tags_in_window(scale, RichImage::variance_tag,
+ xmin_a, ymin_a, xmax_a, ymax_a) + 1);
+ } else {
+ ne = scalar_t(image->nb_tags_in_window(scale, RichImage::variance_tag,
+ xmin_a, ymin_a, xmax_a, ymax_a));
+ nt = scalar_t((xmax_a - xmin_a) * (ymax_a - ymin_a)) + 1;
+ }
+
+ return ne / nt;
+}
+
+void PiFeature::draw_edge_thresholding(RGBImage *image,
+ int r, int g, int b,
+ PiReferential *referential) {
+
+ (*global.log_stream) << "draw_edge_thresholding" << endl;
+
+ Rectangle registered_window_a;
+
+ referential->register_rectangle(_registration_a,
+ &_window_a,
+ ®istered_window_a);
+
+ referential->draw_window(image, _registration_a, ®istered_window_a, 0);
+
+// if(!global.pictures_for_article) {
+// int tag = referential->register_edge(_registration_a, _tag);
+
+// referential->draw_edge_and_scale(image, _registration_a, ®istered_window_a,
+// tag, _edge_scale);
+// }
+}
+
+void PiFeature::print_edge_thresholding(ostream *os) {
+ (*os) << "_tag " << _tag << endl;
+ (*os) << "_edge_scale " << _edge_scale << endl;
+ (*os) << "_window_a.xmin " << _window_a.xmin << endl;
+ (*os) << "_window_a.ymin " << _window_a.ymin << endl;
+ (*os) << "_window_a.xmax " << _window_a.xmax << endl;
+ (*os) << "_window_a.ymax " << _window_a.ymax << endl;
+}
+
+//////////////////////////////////////////////////////////////////////
+// PF_EDGE_HISTOGRAM_COMPARISON
+
+scalar_t PiFeature::response_edge_histogram_comparison(RichImage *image,
+ PiReferential *referential) {
+
+ Rectangle registered_window_a;
+
+ referential->register_rectangle(_registration_a,
+ &_window_a,
+ ®istered_window_a);
+
+ int xmin_a = int(registered_window_a.xmin) >> _edge_scale;
+ int ymin_a = int(registered_window_a.ymin) >> _edge_scale;
+ int xmax_a = int(registered_window_a.xmax) >> _edge_scale;
+ int ymax_a = int(registered_window_a.ymax) >> _edge_scale;
+
+ Rectangle registered_window_b;
+
+ referential->register_rectangle(_registration_b,
+ &_window_b,
+ ®istered_window_b);
+
+ int xmin_b = int(registered_window_b.xmin) >> _edge_scale;
+ int ymin_b = int(registered_window_b.ymin) >> _edge_scale;
+ int xmax_b = int(registered_window_b.xmax) >> _edge_scale;
+ int ymax_b = int(registered_window_b.ymax) >> _edge_scale;
+
+ int scale = referential->common_scale() + _edge_scale * global.nb_scales_per_power_of_two;
+
+ scalar_t result = 0.0;
+
+ scalar_t ne_a = scalar_t(image->nb_tags_in_window(scale, RichImage::variance_tag,
+ xmin_a, ymin_a,
+ xmax_a, ymax_a) + 1);
+
+ scalar_t ne_b = scalar_t(image->nb_tags_in_window(scale, RichImage::variance_tag,
+ xmin_b, ymin_b,
+ xmax_b, ymax_b) + 1);
+
+ for(int t = RichImage::first_edge_tag; t < RichImage::first_edge_tag + RichImage::nb_edge_tags; t++)
+ result += sq(scalar_t(image->nb_tags_in_window(scale, t,
+ xmin_a, ymin_a,
+ xmax_a, ymax_a)) / ne_a
+ -
+ scalar_t(image->nb_tags_in_window(scale, t,
+ xmin_b, ymin_b,
+ xmax_b, ymax_b)) / ne_b);
+
+ ASSERT(!isnan(result));
+
+ return result;
+}
+
+void PiFeature::draw_edge_histogram_comparison(RGBImage *image,
+ int r, int g, int b,
+ PiReferential *referential) {
+
+ (*global.log_stream) << "draw_edge_histogram_comparison" << endl;
+
+ Rectangle registered_window;
+ {
+
+ referential->register_rectangle(_registration_a,
+ &_window_a,
+ ®istered_window);
+ referential->draw_window(image, _registration_a, ®istered_window, 0);
+ }
+
+ {
+ referential->register_rectangle(_registration_b,
+ &_window_b,
+ ®istered_window);
+
+ referential->draw_window(image, _registration_b, ®istered_window, 0);
+ }
+}
+
+void PiFeature::print_edge_histogram_comparison(ostream *os) {
+ (*os) << "_edge_scale " << _edge_scale << endl;
+ (*os) << "_window_a.xmin " << _window_a.xmin << endl;
+ (*os) << "_window_a.ymin " << _window_a.ymin << endl;
+ (*os) << "_window_a.xmax " << _window_a.xmax << endl;
+ (*os) << "_window_a.ymax " << _window_a.ymax << endl;
+ (*os) << "_window_b.xmin " << _window_a.xmin << endl;
+ (*os) << "_window_b.ymin " << _window_a.ymin << endl;
+ (*os) << "_window_b.xmax " << _window_a.xmax << endl;
+ (*os) << "_window_b.ymax " << _window_a.ymax << endl;
+}
+
+//////////////////////////////////////////////////////////////////////
+// PF_GRAYSCALE_HISTOGRAM_COMPARISON
+
+scalar_t PiFeature::response_grayscale_histogram_comparison(RichImage *image,
+ PiReferential *referential) {
+ Rectangle registered_window_a;
+
+ referential->register_rectangle(_registration_a,
+ &_window_a,
+ ®istered_window_a);
+
+ int xmin_a = int(registered_window_a.xmin);
+ int ymin_a = int(registered_window_a.ymin);
+ int xmax_a = int(registered_window_a.xmax);
+ int ymax_a = int(registered_window_a.ymax);
+
+ Rectangle registered_window_b;
+
+ referential->register_rectangle(_registration_b,
+ &_window_b,
+ ®istered_window_b);
+
+ int xmin_b = int(registered_window_b.xmin);
+ int ymin_b = int(registered_window_b.ymin);
+ int xmax_b = int(registered_window_b.xmax);
+ int ymax_b = int(registered_window_b.ymax);
+
+ int scale = referential->common_scale();
+
+ scalar_t result = 0.0;
+
+ scalar_t ne_a = scalar_t((xmax_a - xmin_a) * (ymax_a - ymin_a));
+ scalar_t ne_b = scalar_t((xmax_b - xmin_b) * (ymax_b - ymin_b));
+
+ for(int t = RichImage::first_gray_tag; t < RichImage::first_gray_tag + RichImage::nb_gray_tags; t++)
+ result += sq(scalar_t(image->nb_tags_in_window(scale, t,
+ xmin_a, ymin_a,
+ xmax_a, ymax_a))/ne_a
+ -
+ scalar_t(image->nb_tags_in_window(scale, t,
+ xmin_b, ymin_b,
+ xmax_b, ymax_b))/ne_b);
+ ASSERT(!isnan(result));
+
+ return result;
+}
+
+void PiFeature::draw_grayscale_histogram_comparison(RGBImage *image,
+ int r, int g, int b,
+ PiReferential *referential) {
+
+ (*global.log_stream) << "draw_grayscale_histogram_comparison" << endl;
+
+ Rectangle registered_window;
+ {
+
+ referential->register_rectangle(_registration_a,
+ &_window_a,
+ ®istered_window);
+
+ referential->draw_window(image, _registration_a, ®istered_window, 0);
+ }
+
+ {
+ referential->register_rectangle(_registration_b,
+ &_window_b,
+ ®istered_window);
+
+ referential->draw_window(image, _registration_b, ®istered_window, 0);
+ }
+}
+
+void PiFeature::print_grayscale_histogram_comparison(ostream *os) {
+ (*os) << "_window_a.xmin " << _window_a.xmin << endl;
+ (*os) << "_window_a.ymin " << _window_a.ymin << endl;
+ (*os) << "_window_a.xmax " << _window_a.xmax << endl;
+ (*os) << "_window_a.ymax " << _window_a.ymax << endl;
+ (*os) << "_window_b.xmin " << _window_a.xmin << endl;
+ (*os) << "_window_b.ymin " << _window_a.ymin << endl;
+ (*os) << "_window_b.xmax " << _window_a.xmax << endl;
+ (*os) << "_window_b.ymax " << _window_a.ymax << endl;
+}
+
+//////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////
+
+void PiFeature::randomize(int level) {
+
+ // We randomize all parameters, even those which will not be used
+ // due to the feature type
+
+ _tag = int(drand48() * (RichImage::nb_edge_tags + 1));
+
+ if(_tag < RichImage::nb_edge_tags)
+ _tag += RichImage::first_edge_tag;
+ else
+ _tag = RichImage::variance_tag;
+
+ _edge_scale = int(drand48() * 3);
+
+ // Windows can not be defined in different frames unless we allow
+ // head-belly registration
+
+ if(global.force_head_belly_independence) {
+ if(level == 0) {
+ _registration_a = PiReferential::RM_HEAD_NO_POLARITY;
+ _registration_b = PiReferential::RM_HEAD_NO_POLARITY;
+ } else if(level == 1) {
+ _registration_a = PiReferential::RM_BELLY_NO_POLARITY;
+ _registration_b = PiReferential::RM_BELLY_NO_POLARITY;
+ } else {
+ abort();
+ }
+ } else {
+ _registration_a = random_registration_mode(level);
+ _registration_b = random_registration_mode(level);
+ }
+
+ randomize_window(_registration_a, &_window_a);
+ randomize_window(_registration_b, &_window_b);
+
+ switch(int(drand48() * 3)) {
+
+ case 0:
+ _type = PF_EDGE_THRESHOLDING;
+ break;
+
+ case 1:
+ _type = PF_EDGE_HISTOGRAM_COMPARISON;
+ break;
+
+ case 2:
+ _type = PF_GRAYSCALE_HISTOGRAM_COMPARISON;
+ break;
+
+ default:
+ abort();
+ }
+}
+
+scalar_t PiFeature::response(RichImage *image, PiReferential *referential) {
+ scalar_t r;
+
+ switch(_type) {
+
+ case PF_EDGE_THRESHOLDING:
+ r = response_edge_thresholding(image, referential);
+ break;
+
+ case PF_EDGE_HISTOGRAM_COMPARISON:
+ r = response_edge_histogram_comparison(image, referential);
+ break;
+
+ case PF_GRAYSCALE_HISTOGRAM_COMPARISON:
+ r = response_grayscale_histogram_comparison(image, referential);
+ break;
+
+ default:
+ abort();
+ }
+
+ ASSERT(!isnan(r));
+
+ return r;
+};
+
+void PiFeature::draw(RGBImage *image,
+ int r, int g, int b, PiReferential *referential) {
+
+ switch(_type) {
+
+ case PF_EDGE_THRESHOLDING:
+ draw_edge_thresholding(image, r, g, b, referential);
+ break;
+
+ case PF_EDGE_HISTOGRAM_COMPARISON:
+ draw_edge_histogram_comparison(image, r, g, b, referential);
+ break;
+
+ case PF_GRAYSCALE_HISTOGRAM_COMPARISON:
+ draw_grayscale_histogram_comparison(image, r, g, b, referential);
+ break;
+
+ default:
+ abort();
+ }
+}
+
+void PiFeature::print(ostream *os) {
+
+ (*os) << "registration_a ";
+ PiReferential::print_registration_mode(os, _registration_a);
+ (*os) << endl;
+
+ (*os) << "registration_b ";
+ PiReferential::print_registration_mode(os, _registration_b);
+ (*os) << endl;
+
+ switch(_type) {
+
+ case PF_EDGE_THRESHOLDING:
+ print_edge_thresholding(os);
+ break;
+
+ case PF_EDGE_HISTOGRAM_COMPARISON:
+ print_edge_histogram_comparison(os);
+ break;
+
+ case PF_GRAYSCALE_HISTOGRAM_COMPARISON:
+ print_grayscale_histogram_comparison(os);
+ break;
+
+ default:
+ abort();
+ }
+}