contrib/brl/bbas/bsta/bsta_int_histogram_2d.cxx
Go to the documentation of this file.
00001 // This is brl/bbas/bsta/bsta_int_histogram_2d.cxx
00002 // see bsta/bsta_int_histogram_2d.h for description of class
00003 #include "bsta_int_histogram_2d.h"
00004 //:
00005 // \file
00006 #include <vcl_cmath.h>
00007 // for gausian parzan window filter
00008 #include "bsta_gauss.h"
00009 #include "bsta_int_histogram_1d.h"
00010 
00011 // constructor
00012 bsta_int_histogram_2d::bsta_int_histogram_2d(const unsigned int nbins_x, const unsigned int nbins_y)
00013 {
00014   nbins_x_ = nbins_x;
00015   nbins_y_ = nbins_y;
00016   float diag_lgth = vcl_sqrt( static_cast<float>(nbins_x_*nbins_x_) + static_cast<float>(nbins_y_*nbins_y_));
00017   diag_ = static_cast<long int>(diag_lgth) + 2;
00018 
00019 // create the array for histogram nbins_x_ by nbins_y_ wide
00020   counts_.resize(nbins_y_);
00021   for (unsigned row =0; row<nbins_y_; ++row)
00022   {
00023     vcl_vector<long int> temp(nbins_x_, 0); // zero out all bins (always a good idea)
00024     counts_[row]=temp;
00025   }
00026 }
00027 
00028 // destructor
00029 bsta_int_histogram_2d::~bsta_int_histogram_2d() {}
00030 
00031 // ------------------------------------------------
00032 // get total counts in entire histogram
00033 unsigned long int bsta_int_histogram_2d::get_area()
00034 {
00035   register unsigned long int area = 0;
00036   for (unsigned int j=0; j<nbins_y_; j++) {
00037     for (unsigned int i=0; i<nbins_x_; i++) {
00038       area = area + counts_[j][i];
00039     }
00040   }
00041     return area;
00042 }
00043 
00044 // (get_counts() and set_counts() defined as inline in .h file
00045 
00046 // get highest value in histogram; returns max value; index of max is available in imax
00047 unsigned long int bsta_int_histogram_2d::get_max_val(unsigned int &imax, unsigned int &jmax)
00048 {
00049   register long int max = 0;
00050   for (unsigned int j=0; j<nbins_y_; j++)
00051   {
00052     for (unsigned int i=0; i<nbins_x_; i++)
00053     {
00054       if (counts_[j][i] > max)
00055       {
00056         max = counts_[j][i];
00057         imax = i;
00058         jmax = j;
00059       }
00060     }
00061   }
00062 return max;
00063 }
00064 
00065 
00066 // smooth the histogram with a 2D parzan window (which is a gaussian filter)
00067 void bsta_int_histogram_2d::parzen(const float sigma)
00068 {
00069   if (sigma<=0)
00070     return;
00071   double sd = (double)sigma;
00072   double val = 0.0;
00073   int nx = nbins_x_;  // arguments to create vbl_array_2d are ints
00074   int ny = nbins_y_;
00075   vbl_array_2d<double> in(nx, ny), out(nx, ny);
00076   for (unsigned int j=0; j<nbins_y_; j++)
00077   {
00078     for (unsigned int i=0; i<nbins_x_; i++)
00079     {
00080       val = (double)(counts_[j][i]);
00081       in.put((int)i, (int)j, val);
00082     }
00083   }
00084   bsta_gauss::bsta_2d_gaussian(sd, in, out);
00085   for (unsigned int j=0; j<nbins_y_; j++)
00086   {
00087     for (unsigned int i=0; i<nbins_x_; i++)
00088     {
00089       // as we are going back to a long int, round off here
00090       val = out.get((int)i, (int)j);
00091       counts_[j][i] = (unsigned int)(val +0.5);
00092     }
00093   }
00094   return;
00095 }
00096 
00097 
00098 //: Form a profile histogram with max value normal to diagonal buckets
00099 void bsta_int_histogram_2d::profile_histogram( bsta_int_histogram_1d &phist,
00100                                                bsta_int_histogram_1d &phist_x,
00101                                                bsta_int_histogram_1d &phist_y )
00102 {
00103   // Calculate slope and increments along diagonal
00104   float slope = static_cast<float>(nbins_y_)/static_cast<float>(nbins_x_);
00105   float inverse_slope = 1.0f/slope;
00106 #if 0 // unused variables ?!
00107   float diag_lgth = vcl_sqrt(1.0f + (inverse_slope*inverse_slope));
00108   float deltay = inverse_slope/diag_lgth;
00109   float deltax = 1.0f/diag_lgth;
00110 #endif
00111   // find intercepts of slopes and calculate box that must be examined
00112   float dxintcpt = vcl_sqrt(1 + (slope*slope));
00113   float dyintcpt = vcl_sqrt(1 + (inverse_slope*inverse_slope));
00114   unsigned int xbox = static_cast<unsigned int>(vcl_ceil(dxintcpt));
00115   unsigned int ybox = static_cast<unsigned int>(vcl_ceil(dyintcpt));
00116 
00117   // For each bucket in the diagonal histogram, search normal to the diagonal
00118   //   in the 2D histogram for a "max" value.
00119   // Step along the diagonal i.  Project the normal to the diagonal onto the X
00120   //   axis and step up the normal line to the Y axis.  Start filling phist at
00121   //   the phist[0] bin and go up to end of phist.  But don't search outside of
00122   //   the 2D histogram.
00123 
00124   for (unsigned int i=0; i<diag_; i++)
00125   {
00126     phist.set_count(i, 0);                // starting value for normal line
00127     float xaxis_proj = vcl_sqrt((i*i) + ((i*slope)+(i*slope)));
00128     float yaxis_proj = vcl_sqrt((i*i) + ((i/slope)+(i/slope)));
00129 
00130     // starting position on X axis
00131     float xpos = xaxis_proj;            // start on X axis and step up to Y axis
00132     float ypos = 0.0;                    // start at Y = 0.0
00133 
00134     // Only try to test 2D hist bucket if projection falls in its range.
00135     //   At the high end of phist[] most projections will fall out of range.
00136     while (xpos >= 0.0 && ypos < yaxis_proj)
00137     {
00138       unsigned int xindex = static_cast<int>(vcl_floor(xpos));        // integer projection onto 2D axis
00139       unsigned int yindex = static_cast<int>(vcl_floor(ypos));
00140 
00141       // The integer diagonal normal line will miss some buckets in the 2D hist
00142       //   unless a "box" of buckets is tested for each bucket on the normal of
00143       //   the diagonal hist, so ...
00144       for (unsigned int j=0; j<ybox-1; j++)
00145       {
00146         unsigned int yi = yindex + j;
00147         for (unsigned int k=0; k<xbox-1; k++)
00148         {
00149           unsigned int xi = xindex + k;
00150 
00151           // Smoothed 2D hist range is [0:nbins_x_-1, 0:nbins_y_-1].  Loop starts
00152           //   at X = xaxis_proj and decreases down to 0 while Y starts at 0
00153           //   and increases up to yaxis_proj.  However, we only test smoothed
00154           //   2D buckets within the range of [0:nbins_x_-1, 0:nbins_y_-1].
00155           if (xi < nbins_x_ && yi < nbins_y_)
00156           {
00157             if (phist.get_count(i) < counts_[yi][xi])
00158             {
00159               phist.set_count(i, counts_[yi][xi]);
00160               phist_x.set_count(i, xi);
00161               phist_y.set_count(i, yi);
00162             }
00163           }
00164         }
00165       }
00166     }
00167   }
00168 
00169   return;
00170 }
00171 
00172 
00173  // Find where peak drops to X% along normal on either front or rear edge of
00174  //   diagonal slope.  Here the "front is the top edge, "rear" is the bottom edge
00175  bool bsta_int_histogram_2d::find_edge( unsigned int peak_y, unsigned int peak_x,
00176                                       float newslope, float edge_pct,
00177                                       unsigned int &edge_x, unsigned int &edge_y,
00178                                       bool front)
00179 {
00180   bool success = false;
00181 
00182   long int peak_height = counts_[peak_y][peak_x];        // the highest peak of the 2D histogram
00183   if (peak_height == 0) return success;                // exit if peak is zero
00184   long int limit = static_cast<long int>(peak_height * edge_pct);    // Value to reach to determine edge
00185 
00186   float diag_lgth = vcl_sqrt(1.0f + (newslope*newslope));
00187   float delta_x = 1.0f / diag_lgth;
00188   float delta_y = newslope / diag_lgth;
00189 
00190   float x_point = static_cast<float>(peak_x);
00191   float y_point = static_cast<float>(peak_y);
00192 
00193   // Test to make sure we are checking within range of 2D histogram
00194   while (x_point >= 0 && x_point < nbins_x_ && y_point >=0 && y_point < nbins_y_ )
00195   {
00196     if (front)        // look at top side of peak, Y increases, X decreases
00197     {
00198       x_point -= delta_x;
00199       y_point += delta_y;
00200     }
00201     else            // look at bottom side of peak, X increases, Y decreases
00202     {
00203       x_point += delta_x;
00204       y_point -= delta_y;
00205     }
00206     edge_x = static_cast<unsigned int>(x_point);    // Convert to unsigned int
00207     edge_y = static_cast<unsigned int>(y_point);
00208 
00209     if ( counts_[edge_y][edge_x] <= limit)            // Have we have reached edge?
00210     {
00211       success = true;
00212       return success;
00213     }
00214   }
00215 
00216   // failed to find edge, some perverse situation, return success = false
00217   return success;
00218 }