contrib/brl/bbas/bsta/bsta_int_histogram_1d.cxx
Go to the documentation of this file.
00001 // This is brl/bbas/bsta/bsta_int_histogram_1d.cxx
00002 #include "bsta_int_histogram_1d.h"
00003 //:
00004 // \file
00005 
00006 #include "bsta_gauss.h" // for gausian parzan window filter
00007 #include <vcl_iostream.h>
00008 
00009 // constructor
00010 bsta_int_histogram_1d::bsta_int_histogram_1d(unsigned int bins) // const??
00011 {
00012   nbins_ = bins;
00013   counts_.resize(nbins_, 0);  // create the array for histogram nbins wide
00014 }
00015 
00016 // destructor
00017 bsta_int_histogram_1d::~bsta_int_histogram_1d() {}
00018 
00019 // -----------------------------------------------------------
00020 
00021 // get min and max non-zero bins in histogram
00022 unsigned int bsta_int_histogram_1d::get_min_bin()
00023 {
00024   unsigned int i = 0;
00025   while (i<(nbins_-1) && !counts_[i])  // search for the first non-zero bin
00026     i++;
00027   if (i >= nbins_)   // this shouldn't happen unless hist is empty
00028     return 0;        //   (the same answer as if bin[0] has counts_)
00029   return i;
00030 }
00031 
00032 unsigned int bsta_int_histogram_1d::get_max_bin()
00033 {
00034   unsigned int i = nbins_;
00035   while (i>0 && counts_[--i] == 0) // search for the first non-zero bin
00036     ;
00037   return i;
00038 }
00039 
00040 // get total counts_ in entire histogram
00041 unsigned long int bsta_int_histogram_1d::get_area()
00042 {
00043   long int area = 0;
00044   for (unsigned int i=0; i<nbins_; i++)
00045   { area = area + counts_[i]; }
00046   return area;
00047 }
00048 
00049 //: get the count in a given bin
00050 long int bsta_int_histogram_1d::get_count(unsigned int bin)   // const???
00051 {
00052   if (bin < nbins_)
00053     return counts_[bin];
00054   else
00055     return 0;
00056 }
00057 
00058 //: set the count for a given bin
00059 void bsta_int_histogram_1d::set_count(unsigned int bin, long int val) // const??
00060 {
00061   if (bin<nbins_) counts_[bin] = val;
00062 }
00063 
00064 // get highest bin value in histogram; returns max value; index of max is available in imax
00065 unsigned long int bsta_int_histogram_1d::get_max_val(unsigned int &imax)
00066 {
00067   register long int max = 0;
00068   for (unsigned int i=0; i<nbins_; i++)
00069     if ( counts_[i] > max ) {
00070       max = counts_[i];
00071       imax = i;
00072     }
00073   return max;
00074 }
00075 
00076 // trim off a fraction of the histogram at top and bottom ends.  Note that fractions
00077 //    should be less than 0.5, usually considerably less.
00078 void bsta_int_histogram_1d::trim(float low_fract, float high_fract)
00079 {
00080   long int total = this->get_area();    // total counts_ in histogram
00081   long int low_count = static_cast<long int>(((float)total * low_fract) + 0.5);        // # of counts_ to trim
00082   long int high_count = static_cast<long int>(((float)total * high_fract) + 0.5);
00083 
00084   // trim low end
00085   int i = 0;
00086   while (i<(int)nbins_ && low_count > 0)
00087   {
00088     if (counts_[i] > 0) {
00089       if (low_count >= counts_[i]) {
00090         low_count = low_count - counts_[i];
00091         counts_[i] = 0;
00092         ++i;
00093       }
00094       else {
00095         counts_[i] = counts_[i] - low_count;
00096         low_count = 0;
00097         ++i;
00098       }
00099     }
00100   }
00101 
00102   // trim high end
00103   i = nbins_ - 1;
00104   while (i>=0 && high_count > 0)
00105   {
00106     if (counts_[i] > 0) {
00107       if (high_count >= counts_[i]) {
00108         high_count = high_count - counts_[i];
00109         counts_[i] = 0;
00110         --i;
00111       }
00112       else {
00113         counts_[i] = counts_[i] - high_count;
00114         high_count = 0;
00115         --i;
00116       }
00117     }
00118   }
00119   return;
00120 }
00121 
00122 // Zero out bottom n bins.  This is sometimes necessary if image has a black area due
00123 //   to a sensor's failed detectors.
00124 void bsta_int_histogram_1d::zero_low(unsigned int n)
00125 {
00126   for (unsigned int i=0; i<n; i++) counts_[i] = 0;
00127 }
00128 
00129 // Zero out top n bins.  This is sometimes necessary if the sensor doesn't handle too
00130 //    bright pixels gracefully (like from a sunlight glint off a shiney surface).
00131 void bsta_int_histogram_1d::zero_high(unsigned int n)
00132 {
00133   for (unsigned int i=nbins_-1; i>nbins_-n; i--) counts_[i] = 0;
00134 }
00135 
00136 // smooth the histogram with a 1D parzan window (which is a gaussian filter)
00137 void bsta_int_histogram_1d::parzen(const float sigma)
00138 {
00139   if (sigma<=0)
00140     return;
00141   double sd = (double)sigma;
00142   vcl_vector<double> in(nbins_), out(nbins_);
00143   for (unsigned int i=0; i<nbins_; i++)
00144     in[i] = counts_[i];
00145   bsta_gauss::bsta_1d_gaussian(sd, in, out);
00146   for (unsigned int i=0; i<nbins_; i++)
00147     counts_[i] = static_cast<long int>(out[i] +0.5);  // as we are going back to a long int, round off
00148 }
00149 
00150 // Find the "significant" peaks & vallwys in a histogram.  Here "significant" means there is
00151 //   a specified difference in height between the peak and the previous valley, or vice versa.
00152 bool bsta_int_histogram_1d::find_peaks( float perct, int &n_peaks, vcl_vector<unsigned int> &peaks)
00153 {
00154   bool success = false;
00155 
00156   unsigned int peak_index = 0;
00157   long int ymax = get_max_val(peak_index);      // get highest peak & index
00158   long int hysteresis = static_cast<long int>(ymax*perct);  // thresh for setting peaks
00159   n_peaks = 0;
00160 
00161   // The assumption is that 1st "peak" is a valley.  If it isn't, MAJOR ERROR!!
00162   if (counts_[0] > 0)
00163     vcl_cerr << "Warning, counts_[0] in diagonal hist != 0, Major Error!!\n";
00164   if (counts_[0] > hysteresis)
00165     return success;          // if > hysteresis, return failure
00166 
00167   // Set up some indices for algorithm
00168   bool direction = true;        // true = look for peak, false = look for valley
00169 #if 0 // unused variables ?!
00170   bool past_p_thresh = false;      // is delta from last valley large enough for new peak?
00171   bool past_v_thresh = false;      // is delta from last peak large enough for new valley?
00172 #endif // 0
00173   long int last_p_val = 0;        // height of last peak
00174   unsigned int last_p_index = 0;    // index of last peak
00175   long int last_v_val = 0;        // height of last valley
00176   unsigned int last_v_index = 0;    // index of last valley
00177 
00178   // At start, we assume that 1st "peak" is a valley stored in peaks[0] and the next
00179   //   is a peak stored in peaks[1].  So we start at index 0 and find the first bucket
00180   //   where the hist is non-zero and set the 1st valley at the last zero bucket.
00181   unsigned int j = 0;          // index of peaks[] array
00182   unsigned int istart = 0;
00183   for (unsigned int i=1; i<nbins_; i++)    // start at i=1, not i=0
00184   {
00185     if (counts_[i] > 0)
00186     {
00187       peaks[j] = i-1;        // last zero bucket
00188       n_peaks = 1;
00189       last_v_index = i-1;
00190       istart = i;
00191       j = 1;
00192       break;            // when we find it exit for loop
00193     }
00194   }
00195 
00196   // Step through remaining histogram buckets
00197   for (unsigned int i=istart; i<nbins_; i++)
00198   {
00199     long int delta = counts_[i] - counts_[i-1];
00200     if (delta > 0) direction = true;
00201     if (delta < 0) direction = false;
00202     // delta = 0, leave direction the same
00203 
00204     if (direction)      // we are looking for next peak
00205     {
00206       if (counts_[i] - last_v_val > hysteresis)
00207       {
00208         // Only add new valley if past tentative valley has not yet been added
00209         //   to peaks[] array and AND peak hysteresis has been exceeded.  j=1
00210         //   will skip 1st valley because it is already set.
00211         if (j>1 && last_v_index > peaks[j-1])
00212         {
00213           peaks[j] = last_v_index;  // here j is index to "next" p/v
00214           n_peaks++;
00215           j++;            // now j is index to p/v after this one
00216 
00217           // This is tricky.  Set new value of last_p_val to this valley so it
00218           //   will track up.
00219           last_p_val = last_v_val;
00220         }
00221         // Found new tentative peak; this also moves peak along if it's increasing.
00222         //   Only do this if peak height > past peak height (last_p_val).
00223         if (counts_[i] > last_p_val)
00224         {
00225           last_p_val = counts_[i];  // found new tentative peak, set tentative max
00226           last_p_index = i;      //   also set tentative index
00227         }
00228       }
00229     }
00230     else                // we are looking for next valley
00231     {
00232       // Is delta from last peak large enough to have a new valley?
00233       if (last_p_val - counts_[i] > hysteresis)
00234       {
00235         // Only add new peak if past tentative peak has not yet been added to peaks[]
00236         //   array and valley delta has been exceeded
00237         if (last_p_index > peaks[j-1])
00238         {
00239           peaks[j] = last_p_index;
00240           n_peaks++;
00241           j++;
00242           //  The tricky part again
00243           last_v_val = last_p_val;
00244         }
00245         // Finding new tentative valley; this also moves tentative valley along when hist
00246         //   is decreasing.
00247         if (counts_[i] < last_v_val)
00248         {
00249           last_v_val = counts_[i];
00250           last_v_index = i;
00251         }
00252       }
00253     }
00254   }
00255 
00256   // When we get through the histogram, set the last valley if not already set
00257   if (last_v_index > peaks[j-1])
00258   {
00259     peaks[j] = last_v_index;
00260     n_peaks++;
00261   }
00262   // If we get to this point, we have succeeded
00263   success = true;
00264   return success;
00265 }