automatic commit
[folded-ctf.git] / pi_feature.cc
diff --git a/pi_feature.cc b/pi_feature.cc
new file mode 100644 (file)
index 0000000..300ccee
--- /dev/null
@@ -0,0 +1,471 @@
+
+///////////////////////////////////////////////////////////////////////////
+// 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,
+                                  &registered_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,
+                                  &registered_window_a);
+
+  referential->draw_window(image, _registration_a, &registered_window_a, 0);
+
+//   if(!global.pictures_for_article) {
+//     int tag = referential->register_edge(_registration_a, _tag);
+
+//     referential->draw_edge_and_scale(image, _registration_a, &registered_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,
+                                  &registered_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,
+                                  &registered_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,
+                                    &registered_window);
+    referential->draw_window(image, _registration_a, &registered_window, 0);
+  }
+
+  {
+    referential->register_rectangle(_registration_b,
+                                    &_window_b,
+                                    &registered_window);
+
+    referential->draw_window(image, _registration_b, &registered_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,
+                                  &registered_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,
+                                  &registered_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,
+                                    &registered_window);
+
+    referential->draw_window(image, _registration_a, &registered_window, 0);
+  }
+
+  {
+    referential->register_rectangle(_registration_b,
+                                    &_window_b,
+                                    &registered_window);
+
+    referential->draw_window(image, _registration_b, &registered_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();
+  }
+}