contrib/brl/bseg/sdet/sdet_nonmax_suppression.cxx
Go to the documentation of this file.
00001 // This is brl/bseg/sdet/sdet_nonmax_suppression.cxx
00002 #include "sdet_nonmax_suppression.h"
00003 //:
00004 // \file
00005 #include <vcl_cstdlib.h>   // for vcl_abs(int) and vcl_sqrt()
00006 #include <vsol/vsol_point_2d.h>
00007 #include <vsol/vsol_line_2d.h>
00008 #include <vgl/vgl_point_2d.h>
00009 #include <vnl/vnl_matrix.h>
00010 #include <vnl/algo/vnl_svd.h>
00011 #include <vgl/vgl_homg_point_2d.h>
00012 #include <vgl/algo/vgl_homg_operators_2d.h>
00013 #include <vcl_cassert.h>
00014 
00015 //---------------------------------------------------------------
00016 // Constructors
00017 //
00018 //----------------------------------------------------------------
00019 
00020 //: Constructor from a parameter block, and gradients along x and y directions given as arrays
00021 //
00022 sdet_nonmax_suppression::sdet_nonmax_suppression(sdet_nonmax_suppression_params& nsp,
00023                                                  vbl_array_2d<double> &grad_x,
00024                                                  vbl_array_2d<double> &grad_y)
00025   : sdet_nonmax_suppression_params(nsp)
00026 {
00027   width_ = grad_x.rows();
00028   height_ = grad_x.cols();
00029   grad_x_.resize(width_, height_);
00030   grad_y_.resize(width_, height_);
00031   grad_mag_.resize(width_, height_);
00032   grad_x_ = grad_x;
00033   grad_y_ = grad_y;
00034 
00035   for (int j = 0; j < height_; j++)
00036   {
00037     for (int i = 0; i < width_; i++)
00038     {
00039       double val = vcl_sqrt(vcl_pow(grad_x_(i,j),2.0) + vcl_pow(grad_y_(i,j),2.0));
00040       grad_mag_(i,j) = val;
00041       if (val > max_grad_mag_)
00042         max_grad_mag_ = val;
00043     }
00044   }
00045   points_valid_ = false;
00046   parabola_fit_type_ = nsp.pfit_type_;
00047 }
00048 
00049 //: Constructor from a parameter block, gradient magnitudes given as an array and directions given as component arrays
00050 //
00051 sdet_nonmax_suppression::sdet_nonmax_suppression(sdet_nonmax_suppression_params& nsp,
00052                                                  vbl_array_2d<double> &dir_x,
00053                                                  vbl_array_2d<double> &dir_y,
00054                                                  vbl_array_2d<double> &grad_mag)
00055   : sdet_nonmax_suppression_params(nsp)
00056 {
00057   width_ = grad_mag.rows();
00058   height_ = grad_mag.cols();
00059   grad_x_.resize(width_, height_);
00060   grad_y_.resize(width_, height_);
00061   grad_mag_.resize(width_, height_);
00062   grad_x_ = dir_x;
00063   grad_y_ = dir_y;
00064   grad_mag_ = grad_mag;
00065 
00066   for (int j = 0; j < height_; j++)
00067   {
00068     for (int i = 0; i < width_; i++)
00069     {
00070       double val = grad_mag_(i,j);
00071       if (val > max_grad_mag_)
00072         max_grad_mag_ = val;
00073     }
00074   }
00075   points_valid_ = false;
00076   parabola_fit_type_ = nsp.pfit_type_;
00077 }
00078 
00079 //: Constructor from a parameter block, gradient magnitudes given as an array and the search directions
00080 //
00081 sdet_nonmax_suppression::sdet_nonmax_suppression(sdet_nonmax_suppression_params& nsp,
00082                                                  vbl_array_2d<double> &grad_mag,
00083                                                  vbl_array_2d<vgl_vector_2d <double> > &directions)
00084   : sdet_nonmax_suppression_params(nsp)
00085 {
00086   width_ = grad_mag.rows();
00087   height_ = grad_mag.cols();
00088   grad_x_.resize(width_, height_);
00089   grad_y_.resize(width_, height_);
00090   grad_mag_.resize(width_, height_);
00091   grad_mag_ = grad_mag;
00092   for (int j = 0; j < height_; j++)
00093   {
00094     for (int i = 0; i < width_; i++)
00095     {
00096       vgl_vector_2d<double> direction = directions(i,j);
00097       normalize(direction);
00098       grad_x_(i,j) = grad_mag_(i,j) * direction.x();
00099       grad_y_(i,j) = grad_mag_(i,j) * direction.y();
00100       double val = grad_mag_(i,j);
00101       if (val > max_grad_mag_)
00102         max_grad_mag_ = val;
00103     }
00104   }
00105   points_valid_ = false;
00106   parabola_fit_type_ = nsp.pfit_type_;
00107 }
00108 
00109 //: Constructor from a parameter block, and gradients along x and y directions given as images
00110 //
00111 sdet_nonmax_suppression::sdet_nonmax_suppression(sdet_nonmax_suppression_params& nsp,
00112                                                  vil_image_view<double> &grad_x,
00113                                                  vil_image_view<double> &grad_y)
00114   : sdet_nonmax_suppression_params(nsp)
00115 {
00116   width_ = grad_x.ni();
00117   height_ = grad_x.nj();
00118   grad_x_.resize(width_, height_);
00119   grad_y_.resize(width_, height_);
00120   grad_mag_.resize(width_, height_);
00121 
00122   for (int j = 0; j < height_; j++)
00123   {
00124     for (int i = 0; i < width_; i++)
00125     {
00126       double val_x = grad_x(i,j);
00127       double val_y = grad_y(i,j);
00128       grad_x_(i,j) = val_x;
00129       grad_y_(i,j) = val_y;
00130       double val = vcl_sqrt(vcl_pow(val_x,2.0) + vcl_pow(val_y,2.0));
00131       grad_mag_(i,j) = val;
00132       if (val > max_grad_mag_)
00133         max_grad_mag_ = val;
00134     }
00135   }
00136   points_valid_ = false;
00137   parabola_fit_type_ = nsp.pfit_type_;
00138 }
00139 
00140 //: Constructor from a parameter block, gradient magnitudes given as an image and directions given as component image
00141 //
00142 sdet_nonmax_suppression::sdet_nonmax_suppression(sdet_nonmax_suppression_params& nsp,
00143                                                  vil_image_view<double> &dir_x,
00144                                                  vil_image_view<double> &dir_y,
00145                                                  vil_image_view<double> &grad_mag)
00146   : sdet_nonmax_suppression_params(nsp)
00147 {
00148   width_ = grad_mag.ni();
00149   height_ = grad_mag.nj();
00150   grad_x_.resize(width_, height_);
00151   grad_y_.resize(width_, height_);
00152   grad_mag_.resize(width_, height_);
00153 
00154   for (int j = 0; j < height_; j++)
00155   {
00156     for (int i = 0; i < width_; i++)
00157     {
00158       grad_x_(i,j) = dir_x(i,j);
00159       grad_y_(i,j) = dir_y(i,j);
00160       double val = grad_mag(i,j);
00161       grad_mag_(i,j) = val;
00162       if (val > max_grad_mag_)
00163         max_grad_mag_ = val;
00164     }
00165   }
00166   points_valid_ = false;
00167   parabola_fit_type_ = nsp.pfit_type_;
00168 }
00169 
00170 //: Constructor from a parameter block, gradient magnitudes given as an image and the search directions
00171 //
00172 sdet_nonmax_suppression::sdet_nonmax_suppression(sdet_nonmax_suppression_params& nsp,
00173                                                  vil_image_view<double> &grad_mag,
00174                                                  vbl_array_2d<vgl_vector_2d <double> > &directions)
00175   : sdet_nonmax_suppression_params(nsp)
00176 {
00177   width_ = grad_mag.ni();
00178   height_ = grad_mag.nj();
00179   grad_x_.resize(width_, height_);
00180   grad_y_.resize(width_, height_);
00181   grad_mag_.resize(width_, height_);
00182   for (int j = 0; j < height_; j++)
00183   {
00184     for (int i = 0; i < width_; i++)
00185     {
00186       double val = grad_mag(i,j);
00187       grad_mag_(i,j) = val;
00188       vgl_vector_2d<double> direction = directions(i,j);
00189       normalize(direction);
00190       grad_x_(i,j) = val * direction.x();
00191       grad_y_(i,j) = val * direction.y();
00192       if (val > max_grad_mag_)
00193         max_grad_mag_ = val;
00194     }
00195   }
00196   points_valid_ = false;
00197   parabola_fit_type_ = nsp.pfit_type_;
00198 }
00199 
00200 //:Default Destructor
00201 sdet_nonmax_suppression::~sdet_nonmax_suppression()
00202 {
00203 }
00204 
00205 //-------------------------------------------------------------------------
00206 //: Apply the algorithm
00207 //
00208 void sdet_nonmax_suppression::apply()
00209 {
00210   if (points_valid_)
00211     return;
00212   points_.clear();
00213 
00214   // run non-maximum suppression at every point
00215 
00216   for (int y = 1; y < height_-1; y++)
00217   {
00218     for (int x = 1; x < width_-1; x++)
00219     {
00220       //if (grad_mag_(x,y) > max_grad_mag_ * thresh_ / 100.0)
00221       if (grad_mag_(x,y) > thresh_)
00222       {
00223         double gx = grad_x_(x,y);
00224         double gy = grad_y_(x,y);
00225         vgl_vector_2d<double> direction(gx,gy);
00226         normalize(direction);
00227         if (vcl_abs(gx) > 10e-6 && vcl_abs(gy) > 10e-6)
00228         {
00229           int face_num = intersected_face_number(gx, gy);
00230           assert(face_num != -1);
00231           double s = intersection_parameter(gx, gy, face_num);
00232           assert(s != -1000);
00233           double f[3];
00234           f_values(x, y, gx, gy, s, face_num, f);
00235           double s_list[3];
00236           s_list[0] = -s;
00237           s_list[1] = 0.0;
00238           s_list[2] = s;
00239           if (f[1] > f[0] && f[1] > f[2])
00240           {
00241             double s_star = (parabola_fit_type_ == PFIT_3_POINTS)
00242                           ? subpixel_s(s_list, f)
00243                           : subpixel_s(x, y, direction);
00244             if (-1.5 < s_star && s_star < 1.5)
00245             {
00246               vgl_point_2d<double> subpix(x + s_star * direction.x(), y + s_star * direction.y());
00247               vsol_point_2d_sptr p = new vsol_point_2d(subpix.x(), subpix.y());
00248               vsol_point_2d_sptr line_start = new vsol_point_2d(subpix.x()-direction.y()*0.5, subpix.y()+direction.x()*0.5);
00249               vsol_point_2d_sptr line_end = new vsol_point_2d(subpix.x()+direction.y()*0.5, subpix.y()-direction.x()*0.5);
00250               vsol_line_2d_sptr l = new vsol_line_2d(line_start, line_end);
00251               points_.push_back(p);
00252               lines_.push_back(l);
00253               directions_.push_back(direction);
00254             }
00255           }
00256         }
00257       }
00258     }
00259   }
00260   points_valid_ = true;
00261 }
00262 
00263 int sdet_nonmax_suppression::intersected_face_number(double gx, double gy)
00264 {
00265   if (gx >= 0 && gy >= 0)
00266   {
00267     if (gx >= gy)
00268       return 1;
00269     else
00270       return 2;
00271   }
00272   else if (gx < 0 && gy >= 0)
00273   {
00274     if (vcl_abs(gx) < gy)
00275       return 3;
00276     else
00277       return 4;
00278   }
00279   else if (gx < 0 && gy < 0)
00280   {
00281     if (vcl_abs(gx) >= vcl_abs(gy))
00282       return 5;
00283     else
00284       return 6;
00285   }
00286   else if (gx >= 0 && gy < 0)
00287   {
00288     if (gx < vcl_abs(gy))
00289       return 7;
00290     else
00291       return 8;
00292   }
00293   return -1;
00294 }
00295 
00296 double sdet_nonmax_suppression::intersection_parameter(double gx, double gy, int face_num)
00297 {
00298   vgl_vector_2d<double> direction(gx,gy);
00299   normalize(direction);
00300   if (face_num == 1 || face_num == 8)
00301     return 1.0/direction.x();
00302   else if (face_num == 2 || face_num == 3)
00303     return 1.0/direction.y();
00304   else if (face_num == 4 || face_num == 5)
00305     return -1.0/direction.x();
00306   else if (face_num == 6 || face_num == 7)
00307     return -1.0/direction.y();
00308   return -1000.0;
00309 }
00310 
00311 void sdet_nonmax_suppression::f_values(int x, int y, double gx, double gy, double s, int face_num, double *f)
00312 {
00313   vgl_vector_2d<double> direction(gx,gy);
00314   normalize(direction);
00315 
00316   int corners[4];
00317   get_relative_corner_coordinates(face_num, corners);
00318 
00319   vgl_vector_2d<double> intersection_point = s * direction;
00320   vgl_vector_2d<double> corner1(corners[0], corners[1]); //have to convert to double for subtraction
00321   vgl_vector_2d<double> corner2(corners[2], corners[3]); //have to convert to double for subtraction
00322   double distance1 = length(intersection_point - corner1);
00323   double distance2 = length(intersection_point - corner2);
00324   double value1 = grad_mag_(x+corners[0], y+corners[1]);
00325   double value2 = grad_mag_(x+corners[2], y+corners[3]);
00326   double f_plus = value1 * distance2 + value2 * distance1;
00327 
00328   intersection_point = -s * direction;
00329   corner1.set(-corners[0], -corners[1]); //have to convert to double for subtraction
00330   corner2.set(-corners[2], -corners[3]); //have to convert to double for subtraction
00331   distance1 = length(intersection_point - corner1);
00332   distance2 = length(intersection_point - corner2);
00333   value1 = grad_mag_(x-corners[0], y-corners[1]);
00334   value2 = grad_mag_(x-corners[2], y-corners[3]);
00335   double f_minus = value1 * distance2 + value2 * distance1;
00336 
00337   f[0] = f_minus;
00338   f[1] = grad_mag_(x,y);
00339   f[2] = f_plus;
00340 }
00341 
00342 void sdet_nonmax_suppression::get_relative_corner_coordinates(int face_num, int *corners)
00343 {
00344   switch (face_num)
00345   {
00346    case 1:
00347      corners[0] = 1;
00348      corners[1] = 0;
00349      corners[2] = 1;
00350      corners[3] = 1;
00351      break;
00352    case 2:
00353      corners[0] = 1;
00354      corners[1] = 1;
00355      corners[2] = 0;
00356      corners[3] = 1;
00357      break;
00358    case 3:
00359      corners[0] = 0;
00360      corners[1] = 1;
00361      corners[2] = -1;
00362      corners[3] = 1;
00363     break;
00364    case 4:
00365      corners[0] = -1;
00366      corners[1] = 1;
00367      corners[2] = -1;
00368      corners[3] = 0;
00369     break;
00370    case 5:
00371      corners[0] = -1;
00372      corners[1] = 0;
00373      corners[2] = -1;
00374      corners[3] = -1;
00375     break;
00376    case 6:
00377      corners[0] = -1;
00378      corners[1] = -1;
00379      corners[2] = 0;
00380      corners[3] = -1;
00381     break;
00382    case 7:
00383      corners[0] = 0;
00384      corners[1] = -1;
00385      corners[2] = 1;
00386      corners[3] = -1;
00387     break;
00388    case 8:
00389      corners[0] = 1;
00390      corners[1] = -1;
00391      corners[2] = 1;
00392      corners[3] = 0;
00393     break;
00394    default:
00395      corners[0] = 0;
00396      corners[1] = 0;
00397      corners[2] = 0;
00398      corners[3] = 0;
00399   }
00400 }
00401 
00402 double sdet_nonmax_suppression::subpixel_s(double *s, double *f)
00403 {
00404   double A = f[2] / ((s[2]-s[0])*(s[2]-s[1]));
00405   double B = f[1] / ((s[1]-s[0])*(s[1]-s[2]));
00406   double C = f[0] / ((s[0]-s[1])*(s[0]-s[2]));
00407   double s_star = ((A+B)*s[0] + (A+C)*s[1] + (B+C)*s[2]) / (2*(A+B+C));
00408   return s_star;
00409 }
00410 
00411 double sdet_nonmax_suppression::subpixel_s(int x, int y, vgl_vector_2d<double> direction)
00412 {
00413   double d;
00414   double s;
00415   double f;
00416   vgl_homg_point_2d<double> p1(0.0, 0.0);
00417   vgl_homg_point_2d<double> p2(direction.x(), direction.y());
00418   vgl_homg_line_2d<double> line1(p1,p2);
00419   //construct the matrices
00420   vnl_matrix<double> A(9, 3);
00421   vnl_matrix<double> B(9, 1);
00422   vnl_matrix<double> P(3, 1);
00423   int index = 0;
00424   for (int j = -1; j <= 1; j++)
00425   {
00426     for (int i = -1; i <= 1; i++)
00427     {
00428       find_distance_s_and_f_for_point(i, j, line1, d, s, direction);
00429       f = grad_mag_(x+i,y+j);
00430       A(index, 0) = vcl_pow(s,2.0);
00431       A(index, 1) = s;
00432       A(index, 2) = 1.0;
00433       B(index, 0) = f;
00434       index++;
00435     }
00436   }
00437 #if 0
00438   vnl_matrix<double> A_trans = A.transpose();
00439   P = (vnl_matrix_inverse<double>(A_trans*A) * A_trans) * B;
00440 #else
00441   vnl_svd<double> svd(A);
00442   P = svd.solve(B);
00443 #endif
00444   double s_star = -P(1,0)/(2*P(0,0));
00445   return s_star;
00446 }
00447 
00448 void sdet_nonmax_suppression::find_distance_s_and_f_for_point(int x, int y, vgl_homg_line_2d<double> line,
00449                                                               double &d, double &s, vgl_vector_2d<double> direction)
00450 {
00451   vgl_homg_point_2d<double> point(x,y);
00452   vgl_homg_line_2d<double> perp_line = vgl_homg_operators_2d<double>::perp_line_through_point(line, point);
00453   vgl_homg_point_2d<double> intersection_point_homg = vgl_homg_operators_2d<double>::intersection(line, perp_line);
00454   vgl_point_2d<double> intersection_point(intersection_point_homg);
00455   vgl_vector_2d<double> d_helper(x-intersection_point.x(), y-intersection_point.y());
00456   d = length(d_helper);
00457   s = intersection_point.x() / direction.x();
00458 }
00459 
00460 //----------------------------------------------------------
00461 //: Clear internal storage
00462 //
00463 void sdet_nonmax_suppression::clear()
00464 {
00465   points_.clear();
00466   points_valid_ = false;
00467 }