contrib/gel/vifa/vifa_histogram.cxx
Go to the documentation of this file.
00001 // This is gel/vifa/vifa_histogram.cxx
00002 #include "vifa_histogram.h"
00003 //:
00004 // \file
00005 #include <vcl_algorithm.h>
00006 #include <vcl_cmath.h>
00007 #include <vcl_iostream.h>
00008 #include <vcl_fstream.h>
00009 #include <vcl_cstdio.h>
00010 
00011 static int MEAN_FLAG = 1;
00012 static int SD_FLAG = 2;
00013 
00014 // MPP 7/25/2003  Replaced min & max inline functions w/ vcl_max & vcl_min template functions
00015 
00016 vifa_histogram::vifa_histogram()
00017 {
00018   vals = new float [1];
00019   vals[0] = 0.0f;
00020   counts = new float [1];
00021   counts[0] = 0.0f;
00022   num = 0;
00023   vmin = 0;
00024   vmax = 0;
00025   delta = 0.0f;
00026   mean = 0.0f;
00027   standard_dev = 0.0f;
00028   stats_consistent = 0;
00029   stats_consistent |= (MEAN_FLAG | SD_FLAG);
00030   delimiter = ' ';
00031 }
00032 
00033 vifa_histogram::vifa_histogram(int xres, float val1, float val2)
00034 {
00035   vals = new float [xres];
00036   counts = new float [xres];
00037   num = xres;
00038 
00039   // MPP 7/25/2003
00040   // Swapped argument order so val1 is selected if arguments are equal
00041   vmax = vcl_max(val2, val1);
00042   vmin = vcl_min(val2, val1);
00043 
00044   delta = (vmax - vmin) / xres;
00045   mean = (vmax + vmin) / 2.0f;
00046   standard_dev = (vmax - vmin) / float(2 * vcl_sqrt(3.0));
00047   stats_consistent = 0;
00048   stats_consistent |= (MEAN_FLAG | SD_FLAG);
00049   delimiter = ' ';
00050 
00051   if (vals == NULL || counts == NULL)
00052   {
00053     vcl_cerr << "vifa_histogram : Ran out of array memory.\n\n";
00054     vals = NULL;
00055     counts = NULL;
00056     num = 0;
00057     vmin = 0;
00058     vmax = 0;
00059     delta = 0.0f;
00060   }
00061   else
00062   {
00063     for (int i = 0; i < xres; i++)
00064     {
00065       vals[i] = vmin + (delta * (i + 0.5f));
00066       counts[i] = 0.0f;
00067     }
00068   }
00069 }
00070 
00071 vifa_histogram::vifa_histogram(float* uvals, float* ucounts, int xres)
00072 {
00073   stats_consistent = 0;
00074   vals = uvals;
00075   counts = ucounts;
00076   num = xres;
00077   delta = vals[1] - vals[0]; // Changed this from delta = 1.0f
00078   //  vmax = GetMaxVal();
00079   //  vmin = GetMinVal(); JAF version
00080   // MPP 7/1/2002
00081   // JimG - inconsistent with JLM's definition!
00082   vmin = uvals[0]     - 0.5f * delta;
00083   vmax = uvals[num-1] + 0.5f * delta;
00084 
00085   mean = GetMean();
00086   standard_dev = GetStandardDev();
00087   stats_consistent |= (MEAN_FLAG | SD_FLAG);
00088 
00089   delimiter = ' ';
00090 }
00091 //-----------------------------------------------------------
00092 //: Copy constructor
00093 vifa_histogram::vifa_histogram(const vifa_histogram& h)
00094   : vul_timestamp(), vbl_ref_count()
00095 {
00096   // We know we really aren't changing h, but the array access to h isn't
00097   // strictly speaking const. JLM -Oct 2000
00098   stats_consistent = 0;
00099   vifa_histogram& his = (vifa_histogram&)h; // casting away const !!!
00100 
00101   num = his.GetRes();
00102 
00103   vals = new float[num];
00104   float* his_vals = his.GetVals();
00105 
00106   counts = new float[num];
00107   float* his_counts = his.GetCounts();
00108 
00109   if (vals == NULL || counts == NULL)
00110   {
00111     vcl_cerr << "vifa_histogram : Ran out of array memory.\n\n";
00112     vals = NULL;
00113     counts = NULL;
00114     num = 0;
00115     vmin = 0;
00116     vmax = 0;
00117     delta = 0.0f;
00118     stats_consistent = 0;
00119     return;
00120   }
00121 
00122   mean = his.GetMean();
00123   standard_dev = his.GetStandardDev();
00124 
00125   for (int i = 0; i < num; i++)
00126   {
00127     vals[i] = his_vals[i];
00128     counts[i] = his_counts[i];
00129   }
00130 
00131   // MPP 7/1/2002
00132   // Jim G. found an issue with this code if original histogram had
00133   // zero counts in end buckets.  See Cumulative() for fix.
00134   vmax = his.GetMaxVal();
00135   vmin = his.GetMinVal();
00136 
00137   delta = his.GetBucketSize();
00138   stats_consistent |= (MEAN_FLAG | SD_FLAG);
00139   delimiter = h.delimiter;
00140 }
00141 
00142 //---------------------------------------------------------------------
00143 // Destructor
00144 vifa_histogram::~vifa_histogram()
00145 {
00146   if (vals)
00147     delete [] vals;
00148   if (counts)
00149     delete [] counts;
00150 }
00151 
00152 
00153 //---------------------------------------
00154 //: Resample a histogram
00155 vifa_histogram::vifa_histogram(vifa_histogram const* his, float width, bool preserveCounts)
00156 {
00157   stats_consistent = 0;
00158 
00159   // Attributes of original histogram
00160   // Width of buckets
00161   float org_delta = his->GetBucketSize();
00162 
00163   // Last bucket index
00164   int max_index = his->GetRes() - 1;
00165 
00166   // Range start
00167   float minvalue = his->GetVals()[0] - (org_delta * 0.5f);
00168 
00169   // Range end
00170   float maxvalue = his->GetVals()[max_index] + (org_delta * 0.5f);
00171 
00172   // Initialize a new histogram
00173   if (width == org_delta)
00174   {
00175     num = his->GetRes();
00176   }
00177   else if (!(width == 0.0f))
00178   {
00179     // Any degenerate cases?
00180     num = (int)vcl_ceil((maxvalue - minvalue) / width);
00181   }
00182   else
00183   {
00184     // This shouldn't happen anyway.
00185     num = 1;
00186   }
00187 
00188   vals = new float [num];
00189   counts = new float [num];
00190   delta = width;
00191 
00192   // Entire range of x-values, including endpoints of first & last bin
00193   float mean_val = (maxvalue + minvalue) * 0.5f;
00194   float half_range = (num * delta) * 0.5f;
00195 
00196   // Endpoint to endpoint (inconsistent w/ JLM's definition!)
00197   vmax =  mean_val + half_range;
00198   vmin =  mean_val - half_range;
00199 
00200   if (vals == NULL || counts == NULL)
00201   {
00202     vcl_cerr << "vifa_histogram : Ran out of array memory.\n\n";
00203     vals = NULL;
00204     counts = NULL;
00205     num = 0;
00206     vmin = 0;
00207     vmax = 0;
00208     delta = 0.0f;
00209     mean = 0.0f;
00210     standard_dev = 0.0f;
00211     stats_consistent |= (MEAN_FLAG | SD_FLAG);
00212     return;
00213   }
00214   else
00215   {
00216     for (int i = 0; i < num; i++)
00217     {
00218       // Inconsistent with JLM's definition!
00219       vals[i] = vmin + (delta * (i + 0.5f));
00220       counts[i] = 0.0f;
00221     }
00222   }
00223 
00224   // Cases:
00225 
00226   if (delta == org_delta)    // Then just copy his
00227   {
00228     float* his_counts = his->GetCounts();
00229     for (int i = 0; i < num; i++)
00230       counts[i] = his_counts[i];
00231     mean = GetMean();
00232     standard_dev = GetStandardDev();
00233     stats_consistent |= (MEAN_FLAG | SD_FLAG);
00234     return;
00235   }
00236 
00237   if (org_delta > delta)     // Then interpolate his counts.
00238   {
00239     // Boundary conditions:
00240     //    Start
00241 
00242     // Midpoint of old first bucket
00243     float his_start = minvalue + (0.5f * org_delta);
00244 
00245     // Inconsistent with JLM's definition!
00246     float start = vmin + (0.5f * delta);
00247 
00248     // Contents of first old bucket
00249     float c0 = his->GetCount(his_start);
00250 
00251     // Contents of second old bucket
00252     float c1 = his->GetCount(his_start + org_delta);
00253 
00254     // Slope between first & second old buckets
00255     float s0 = (c1 - c0) / org_delta;
00256 
00257     // Start at first new bucket.  Loop until <= one new delta beyond
00258     // old 2nd bucket; put counts into new histogram buckets.
00259     for (float x = start; x <= (his_start + org_delta + delta);)
00260     {
00261       float x_diff = x - his_start;
00262       float interp = c0 + (s0 * x_diff);
00263 
00264       // MPP 7/1/2002
00265       // JimG - Should never be negative!
00266       if (interp < 0)
00267         interp = 0; // Can be negative
00268 
00269       SetCount(x, interp);
00270       x += delta;
00271     }
00272 
00273     //    End
00274     // Midpoint of last old bucket
00275     float his_end = maxvalue - (0.5f * org_delta);
00276 
00277     // Midpoint of last new bucket
00278     float end = vmax - (0.5f * delta);
00279 
00280     // Contents of last old bucket
00281     float cn = his->GetCount(his_end);
00282 
00283     // Contents of next-to-last old bucket
00284     float cn_1 = his->GetCount(his_end - org_delta);
00285 
00286     // Slope between next-to-last & last buckets
00287     float sn = (cn_1 - cn) / org_delta;
00288 
00289     // MPP 7/1/2002
00290     // JimG - Is "+ delta" an error?  Inconsistent w/ JLM's definition!
00291     for (float y = end; y >= (his_end - org_delta + delta);)
00292     {
00293       float x_diff = his_end - y;
00294       float interp = cn + (sn * x_diff);
00295       if (interp < 0)
00296         interp = 0; // Can be negative
00297 
00298       SetCount(y, interp);
00299       y -= delta;
00300     }
00301 
00302     // Interior Loop
00303     for (float z = his_start + org_delta; z <= (his_end - org_delta);)
00304     {
00305       // Old bucket contents
00306       float ci = his->GetCount(z);
00307       float ci_1 = his->GetCount(z - org_delta);
00308       float cip1 = his->GetCount(z + org_delta);
00309 
00310       // Old bucket first derivative
00311       float deriv = (cip1 - ci_1)/(2.0f * org_delta);
00312 
00313       // Old bucket second derivative
00314       float second_drv =
00315         (((cip1 + ci_1) / 2.0f) - ci) / (org_delta * org_delta);
00316 
00317       // X-index in new histogram, based on old histogram value
00318       int fine_x_index = GetIndex(z);
00319 
00320       // Clamp the index to the allowed bucket range
00321       if (fine_x_index < 0)
00322       {
00323         if (z < vmin)
00324           fine_x_index = 0;
00325         else
00326           fine_x_index = num - 1;
00327       }
00328 
00329       // X-value in new histogram (center of bucket)
00330       float fine_x = vals[fine_x_index];
00331 
00332       // Fill in all of the new histogram buckets within the range
00333       // of the old histogram bucket [z, z+org_delta)
00334       for (float xfine = fine_x; xfine < z + org_delta;)
00335       {
00336         float interp = ci + (deriv * (xfine - z)) +
00337           second_drv * (xfine - z) * (xfine - z);
00338         if (interp < 0)
00339           interp = 0; // Can be negative ???
00340 
00341         SetCount(xfine, interp);
00342         xfine += delta;
00343       }
00344 
00345       z += org_delta;
00346     }
00347 
00348     // MPP 7/2/2002
00349     // If needed, rescale the new histogram's
00350     // counts to preserve overall bucket counts
00351     if (preserveCounts)
00352     {
00353       float scaleFactor = delta / org_delta;
00354       for (int i = 0; i < num; i++)
00355         counts[i] *= scaleFactor;
00356     }
00357   }
00358 
00359   if (org_delta < delta)
00360   {
00361     // Just accumulate samples from his into larger bins
00362     if (org_delta != 0.0f)
00363     {
00364       float his_start = minvalue + (0.5f * org_delta);
00365       float his_end = maxvalue - (0.5f * org_delta);
00366       for (float x = his_start; x <= his_end;)
00367       {
00368         SetCount(x, GetCount(x) + his->GetCount(x));
00369         x += org_delta;
00370       }
00371     }
00372   }
00373 
00374   mean = GetMean();
00375   standard_dev = GetStandardDev();
00376   stats_consistent = (MEAN_FLAG | SD_FLAG);
00377   delimiter = his->delimiter;
00378 }
00379 
00380 //--------------------------------------------------
00381 //: Transform the value axis of a histogram by a translation, transl, and a scale factor, scale.
00382 //    The new histogram has the same resolution as his.
00383 
00384 vifa_histogram* vifa_histogram::Scale(float scale_factor)
00385 {
00386   stats_consistent = 0;
00387   // Extract attributes of self
00388 
00389   //    float lowvalue = vals[0];
00390   float highvalue = vals[num-1];
00391 
00392   // Construct a new histogram
00393 
00394   vifa_histogram* scaled_his = new vifa_histogram(this, delta);
00395   float* new_counts = scaled_his->GetCounts();
00396   for (int i = 0; i < num; i++)  // Initialize
00397     new_counts[i] = 0.0f;
00398 
00399   // Compute scaled values
00400   // We assume that the new histogram is to be scaled down from his
00401 
00402   float scale = scale_factor;
00403   if (scale_factor > 1.0f)
00404     scale = 1.0f;
00405 
00406   for (float x = highvalue; x > vmin;)
00407   {
00408     float trans_x = (x - vmin) * scale + vmin; // Scaled x.
00409     int index = GetIndex(trans_x);
00410     if (index < 0)
00411     {
00412       if (trans_x < vmin)
00413         index = 0;
00414       else
00415         index = num - 1;
00416     }
00417 
00418     float fraction = (trans_x - vals[index])/delta;
00419     float abs_fraction = (float)vcl_fabs(fraction);
00420     int x_index = GetIndex(x);
00421     if (x_index < 0)
00422     {
00423       if (x < vmin)
00424         x_index = 0;
00425       else
00426         x_index = num - 1;
00427     }
00428 
00429     // Distribute the counts in proportion
00430 
00431     new_counts[index] += (1.0f - abs_fraction) * counts[x_index];
00432     if (fraction > 0)
00433     {
00434       if (index < (num - 1))
00435         new_counts[index + 1] += abs_fraction * counts[x_index];
00436       else
00437         new_counts[index] += abs_fraction * counts[x_index];
00438     }
00439     else
00440     {
00441       if (index > 0)
00442         new_counts[index - 1] += abs_fraction * counts[x_index];
00443       else
00444         new_counts[index] += abs_fraction * counts[x_index];
00445     }
00446 
00447     x -= delta;
00448   }
00449 
00450   // Compute new histogram attributes
00451 
00452   mean = scaled_his->GetMean();
00453   standard_dev = scaled_his->GetStandardDev();
00454   stats_consistent |= (MEAN_FLAG | SD_FLAG);
00455   return scaled_his;
00456 }
00457 
00458 //---------------------------------------------------------------------
00459 //: Assuming that "this" is a histogram of population density, construct a new histogram which is the cumulative distribution.
00460 //    Each bin, xi, in his is assumed to represent a density, i.e.,
00461 //            {x | (xi - .5*delta) < x <= (xi + .5*delta)}
00462 //    Each bin, xi, in the result represents a cumulative distribution, i.e.,
00463 //            {x | x <= (xi + .5*delta)}
00464 vifa_histogram* vifa_histogram::Cumulative()
00465 {
00466   vifa_histogram* cum_his = new vifa_histogram(*this);
00467   float* density_counts = this->GetCounts();
00468   int res = this->GetRes();
00469 
00470   // Initialize cumulative counts
00471   float* cum_counts = cum_his->GetCounts();
00472   for (int j=0; j < res; j++)
00473     cum_counts[j] = 0;
00474 
00475   // Accumulate counts
00476   for (int i = (res - 1); i >= 0; i--) // RWMC: cumulative ignored lowest bin
00477     for (int j = i; j >= 0; j--)
00478       cum_counts[j] += density_counts[i];
00479 
00480   // MPP 7/1/2002
00481   // JimG - Another bug: if the original histogram had zero counts in the
00482   //   lower bucket, vmin for cumulative histogram was incorrectly set by
00483   //   copy constructor above.  Let's reset vmin & vmax after cumulative
00484   //   counts have been filled in!
00485   cum_his->vmin = cum_his->GetMinVal() - 0.5f * cum_his->GetBucketSize();
00486   cum_his->vmax = cum_his->GetMaxVal() + 0.5f * cum_his->GetBucketSize();
00487 
00488   return cum_his;
00489 }
00490 
00491 //:
00492 // Provides the correct values for histogram counts when the bin index
00493 // extends outside the valid range of the counts array.  This function
00494 // permits easy array access logic for the NonMaximumSuppression algorithm.
00495 // The cyclic flag indicates that the counts array index is circular, i.e,
00496 // cnts[0] equivalent to cnts[n_bins]
00497 inline float GetExtendedCount(int bin, int n_bins, float* cnts, bool cyclic)
00498 {
00499   int nbm = n_bins-1;
00500   if (!cyclic)
00501   {
00502     if (bin < 0)
00503       return cnts[0];
00504     if (bin >= n_bins)
00505       return cnts[nbm];
00506   }
00507   else
00508   {
00509     if (bin<0)
00510       return cnts[nbm+bin];
00511     if (bin >= n_bins)
00512       return cnts[bin-n_bins];
00513   }
00514   return cnts[bin];
00515 }
00516 
00517 //: Prune any sequences of more than one maximum value
00518 // That is, it is possible to have a "flat" top peak with an arbitrarily
00519 // long sequence of equal, but maximum values. The cyclic flag indicates
00520 // that the sequence wraps around, i.e. cnts[0] equivalent to cnts[nbins]
00521 void vifa_histogram::RemoveFlatPeaks(int nbins, float* cnts, bool cyclic)
00522 {
00523   int nbm = nbins-1;
00524 
00525   // Here we define a small state machine - parsing for runs of peaks
00526   // init is the state corresponding to an initial run (starting at i ==0)
00527   float init=GetExtendedCount(0, nbins, cnts, cyclic);
00528   int init_end =0;
00529 
00530   // start is the state corresponding to any other run of peaks
00531   bool start=false;
00532   int start_index=0;
00533 
00534   // The scan of the state machine
00535   for (int i = 0; i < nbins; i++)
00536   {
00537     float v = GetExtendedCount(i, nbins, cnts, cyclic);
00538 
00539     // State init: a string of non-zeroes at the beginning.
00540     if (init&&v!=0)
00541       continue;
00542 
00543     if (init&&v==0)
00544     {
00545       init_end = i;
00546       // fix to eliminate compiler warning.
00547       // init used to be bool, but now is float.  It should still work.
00548       // init = false;
00549       init = 0;
00550       continue;
00551     }
00552 
00553     // State !init&&!start: a string of "0s"
00554     if (!start&&v==0)
00555       continue;
00556 
00557     // State !init&&start: the first non-zero value
00558     if (!start&&v!=0)
00559     {
00560       start_index = i;
00561       start = true;
00562       continue;
00563     }
00564     // State ending flat peak: encountered a subsequent zero after starting
00565     if (start&&v==0)
00566     {
00567       int peak_location = (start_index+i-1)/2; // The middle of the run
00568       for (int k = start_index; k<=(i-1); k++)
00569         if (k!=peak_location)
00570           cnts[k] = 0;
00571       start = false;
00572     }
00573   }
00574   // Now handle the boundary conditions
00575   // The non-cyclic case
00576   if (!cyclic)
00577   {
00578     if (init_end!=0)  // Was there an initial run of peaks?
00579     {
00580       int init_location = (init_end-1)/2;
00581       for (int k = 0; k<init_end; k++)
00582         if (k!=init_location)
00583           cnts[k] = 0;
00584     }
00585     if (start)       // Did we reach the end of the array in a run of pks?
00586     {
00587       int end_location = (start_index + nbm)/2;
00588       for (int k = start_index; k<nbins; k++)
00589         if (k!=end_location)
00590           cnts[k] = 0;
00591     }
00592   }
00593   else  // The cyclic case
00594   {
00595     if (init_end!=0) { // Is there a run which crosses the cyclic cut?
00596       if (start)
00597       { // Yes, so define the peak location accordingly
00598         int peak_location = (start_index + init_end - nbm -1)/2;
00599         int k;
00600         if (peak_location < 0) // Is the peak to the left of the cut?
00601         {// Yes, to the left
00602           peak_location += nbm;
00603           for ( k = 0; k< init_end; k++)
00604             cnts[k]=0;
00605           for ( k= start_index; k <nbins; k++)
00606             if (k!=peak_location)
00607               cnts[k] = 0;
00608         }
00609         else
00610         { // No, on the right.
00611           for ( k = start_index; k< nbins; k++)
00612             cnts[k]=0;
00613           for ( k= 0; k < init_end; k++)
00614             if (k!=peak_location)
00615               cnts[k] = 0;
00616         }
00617       }
00618       else
00619       { // There wasn't a final run so just clean up the initial run
00620         int init_location = (init_end-1)/2;
00621         for (int k = 0; k<=init_end; k++)
00622           if (k!=init_location)
00623             cnts[k] = 0;
00624       }
00625     }
00626   }
00627 }
00628 
00629 //----------------------------------------------------------
00630 //: Suppress values in the histogram which are not locally
00631 //    The neighborhood for computing the local maximum a maximum.
00632 //    is [radius X radius], e.g. for radius =1 the neighborhood
00633 //    is [-X-], for radius = 2, the neighborhood is [--X--], etc.
00634 //    If the cyclic flag is true then the index space is assumed to
00635 //    be equivalent to a circle. That is, elements "0" and "n_buckets"
00636 //    are in correspondence.
00637 vifa_histogram* vifa_histogram::NonMaximumSupress(int radius, bool cyclic)
00638 {
00639   if ((2*radius +1)> num/2)
00640   {
00641     vcl_cerr << "In vifa_histogram::NonMaximumSupress(): radius is too large\n";
00642     return NULL;
00643   }
00644   // Get the counts array of "this"
00645   vifa_histogram* h_new = new vifa_histogram(*this);
00646   int n_buckets = h_new->GetRes();
00647   float* counts_old = this->GetCounts();
00648 
00649   // Make a new histogram for the suppressed version
00650   float* counts_new = h_new->GetCounts();
00651   int i;
00652   for ( i =0; i < n_buckets; i++)
00653     counts_new[i] = 0;
00654 
00655   // Find local maxima
00656   for ( i = 0; i<  n_buckets; i++)
00657   {
00658     // find the maximum value in the current kernel
00659     float max_count = counts_old[i];
00660     for (int k = -radius; k <= radius ;k++)
00661     {
00662       int index = i+k;
00663       float c = GetExtendedCount(index, n_buckets, counts_old, cyclic);
00664       if ( c > max_count)
00665         max_count = c;
00666     }
00667     // Is position i a local maximum?
00668     if (max_count == counts_old[i])
00669       counts_new[i] = max_count; // Yes. So set the counts to the max value
00670   }
00671   RemoveFlatPeaks(n_buckets, counts_new, cyclic);
00672   return h_new;
00673 }
00674 
00675 
00676 //----------------------------------------------------------
00677 //: Compute the mean of the histogram population
00678 float vifa_histogram::GetMean() const
00679 {
00680   float xsum = 0.0f;
00681   float minv = this->GetMinVal();
00682   float maxv = this->GetMaxVal();
00683   float bucket_size = this->GetBucketSize();
00684 
00685   if (MEAN_FLAG & stats_consistent)
00686     return mean;
00687   else
00688   {
00689     if (bucket_size > 0.0f)
00690     {
00691       for (float x=minv; x<=maxv; x+=bucket_size)
00692         xsum += x*GetCount(x);
00693     }
00694     else
00695     {
00696       stats_consistent |= MEAN_FLAG;
00697       mean = (maxv+minv)/2.0f;
00698       return mean;
00699     }
00700 
00701     float area = ComputeArea(vmin, vmax);
00702     if (area <= 0.0f)
00703     {
00704 #ifdef DEBUG
00705       vcl_cerr << "vifa_histogram::GetMean() : Area <= 0.0\n\n";
00706 #endif
00707       return 0.0f;
00708     }
00709     else
00710     {
00711       stats_consistent |= MEAN_FLAG;
00712       mean = xsum/area;
00713       return mean;
00714     }
00715   }
00716 }
00717 
00718 float vifa_histogram::GetStandardDev() const
00719 {
00720   float sum = 0.0f;
00721   float bucket_size = this->GetBucketSize();
00722 
00723   if (SD_FLAG & stats_consistent)
00724     return standard_dev;
00725   else
00726   {
00727     float xm = this -> GetMean(); // Force an Update of Mean
00728 
00729     if ( this->GetBucketSize() > 0.0f)
00730     {
00731       for (float x=this->GetMinVal(); x<= this->GetMaxVal(); x += bucket_size)
00732         sum += (x-xm)*(x-xm)*GetCount(x);
00733     }
00734     else
00735     {
00736       stats_consistent |= SD_FLAG;
00737       standard_dev = 0.0f;
00738       return standard_dev;
00739     }
00740 
00741     float area = ComputeArea(vmin, vmax);
00742     if (area <= 0.0f)
00743     {
00744 #ifdef DEBUG
00745       vcl_cerr << "vifa_histogram::GetStandardDev() : Area <= 0.0\n\n";
00746 #endif
00747       return 0.0f;
00748     }
00749     else
00750     {
00751       stats_consistent |= SD_FLAG;
00752       standard_dev = (float)vcl_sqrt(sum/area);
00753       return standard_dev;
00754     }
00755   }
00756 }
00757 
00758 float vifa_histogram::GetMedian() const
00759 {
00760   // step through each bin until num_so_far > num_samps / 2
00761   int i = 0;  // bin number
00762   float num_samps_2 = 0.5f * GetNumSamples();
00763   float num_so_far  = 0;
00764   while (num_so_far < num_samps_2)
00765   {
00766     num_so_far += counts[i];
00767     i++;
00768   }
00769 
00770   return vals[i];
00771 }
00772 
00773 int vifa_histogram::GetIndex(float pixelval) const
00774 {
00775   // Done by binary search.  This was taking far too long
00776   // Since there is an implication that the distance between
00777   // bins is near constant, we could probably do even better
00778   // by linear interpolation.
00779 
00780   // The present routine will find the least i such that
00781   // pixelval <= vals[i] + 0.5*delta;
00782 
00783   // MPP 7/1/2002
00784   // JimG - If vmin/vmax defined incorrectly, this test fails & returns -1!
00785   if ((pixelval > vmax) || (pixelval < vmin))
00786     return -1;
00787 
00788   // The required solution must lie between low and high inclusive
00789   // Thus, low-1 is in the no set and high is in the yes set.
00790   int high = num-1;
00791   int low = 0;
00792 
00793   while (high > low)
00794   {
00795     // Get a mid point.  mid will lie strictly in the range [low, high-1]
00796     int mid = (high + low - 1) / 2;
00797 
00798     if (pixelval <= vals[mid] + 0.5f*delta)
00799     {
00800       // mid is in the yes set
00801       high = mid;
00802     }
00803     else
00804     {
00805       // mid is in the no set
00806       low = mid + 1;
00807     }
00808   }
00809 
00810   // Now, low=high, so they are the required solution
00811   return low;
00812 }
00813 
00814 int vifa_histogram::GetValIndex(float pixelval) const
00815 {
00816   if ((pixelval > vmax) || (pixelval < vmin))
00817     return -1;
00818 
00819   int idx = 0;
00820 
00821   for (int i = 0; i < num; i++)
00822   {
00823     if ((pixelval > (vals[i] - 0.5f * delta)) &&
00824         (pixelval <= (vals[i] + 0.5f * delta)))
00825     {
00826       idx = i;
00827       break;
00828     }
00829   }
00830 
00831   return idx;
00832 }
00833 
00834 float vifa_histogram::GetCount(float pixelval) const
00835 {
00836   int index = GetIndex(pixelval);
00837   if (index < 0)
00838     return -1;
00839   else
00840     return counts[index];
00841 }
00842 
00843 float vifa_histogram::GetMinVal() const
00844 {
00845   register int i=0;
00846   while (i<num-1 && !counts[i])
00847     i++;
00848   return vals[i];
00849 }
00850 
00851 float vifa_histogram::GetMaxVal() const
00852 {
00853   register int i=num-1;
00854   while (i>0 && !counts[i])
00855     i--;
00856   if (i < 0)
00857     return 0.0f;
00858   return vals[i];
00859 }
00860 
00861 float vifa_histogram::GetMaxCount() const
00862 {
00863   register int i;
00864   float max = 0.0f;
00865 
00866   for (i=0; i < num; i++)
00867   {
00868     if (counts[i] > max)
00869     {
00870       max = counts[i];
00871     }
00872   }
00873 
00874   return max;
00875 }
00876 
00877 float vifa_histogram::SetCount(float pixelval, float count)
00878 {
00879   stats_consistent = 0;
00880 
00881   int index = GetIndex(pixelval);
00882 
00883   if (index < 0)
00884     return -1;
00885   else
00886   {
00887     counts[index] = count;
00888     return count;
00889   }
00890 }
00891 
00892 void vifa_histogram::UpCount(float pixelval, bool useNewIndexMethod)
00893 {
00894   stats_consistent = 0;
00895   int index = -1;
00896   if (useNewIndexMethod)
00897     index = GetValIndex(pixelval);
00898   else
00899     UpCount(pixelval);
00900 
00901   if (index >= 0)
00902     counts[index] += 1.0f;
00903 }
00904 
00905 void vifa_histogram::UpCount(float pixelval)
00906 {
00907   stats_consistent = 0;
00908   int index = GetIndex(pixelval);
00909   if (index >= 0)  // Originally (index > 0)
00910   {
00911     counts[index] += 1.0f;
00912   }
00913 }
00914 
00915 int vifa_histogram::GetNumSamples() const
00916 {
00917   float num_samps = 0;
00918   for (int i=0; i < num; i++)
00919   {
00920     num_samps += counts[i];
00921   }
00922 
00923   return (int)num_samps;
00924 }
00925 
00926 float vifa_histogram::ComputeArea(float low, float high) const
00927 {
00928   float maxval = GetMaxVal();
00929   float minval = GetMinVal();
00930 
00931   if (low < minval)
00932     low = minval;
00933   if (high > maxval)
00934     high = maxval;
00935 
00936   if (low <= high)
00937   {
00938     int indexlow, indexhigh;
00939     indexlow = (int) GetIndex(low);
00940     if (indexlow < 0)
00941     {
00942       if (low < vmin)
00943         indexlow = 0;
00944       else
00945         indexlow = num-1;
00946     }
00947 
00948     indexhigh = (int) GetIndex(high);
00949     if (indexhigh < 0)
00950     {
00951       if (high < vmin)
00952         indexhigh = 0;
00953       else
00954         indexhigh = num-1;
00955     }
00956 
00957     register int i=indexlow;
00958     float sum = 0.0f;
00959     while (i <= indexhigh)
00960     {
00961       sum += counts[i];
00962       i++;
00963     }
00964 
00965     return sum;
00966   }
00967   else
00968   {
00969     return 0.0f;
00970   }
00971 }
00972 //----------------------------------------------------------------------
00973 //: Compute the total area under the histogram
00974 //
00975 float vifa_histogram::ComputeArea() const
00976 {
00977   float vmin = this->GetMinVal();
00978   float vmax = this->GetMaxVal();
00979 
00980   if (vmin>vmax)
00981   {
00982     float temp = vmin;
00983     vmin = vmax;
00984     vmax = temp;
00985   }
00986 
00987   return this->ComputeArea(vmin, vmax);
00988 }
00989 //----------------------------------------------------------------------
00990 //: Finds the lower bound value which eliminates a given fraction of histogram area.
00991 //
00992 float vifa_histogram::LowClipVal(float clip_fraction)
00993 {
00994   if (clip_fraction < 0)
00995     clip_fraction = 0.0f;
00996   if (clip_fraction > 1.0f)
00997     clip_fraction = 1.0f;
00998 
00999   float area = this->ComputeArea();
01000   if (area == 0.0f)
01001     return this->GetMinVal();
01002 
01003   if (clip_fraction == 0.0f)
01004     return this->GetMinVal();
01005   if (clip_fraction == 1.0f)
01006     return this->GetMaxVal();
01007 
01008   float clip_area = area*clip_fraction;
01009   float* counts = this->GetCounts();
01010   float* vals = this->GetVals();
01011   int res = this->GetRes();
01012   float sum = 0;
01013   int i=0;
01014   for (; i < res; i++)
01015   {
01016     sum += counts[i];
01017     if (sum >= clip_area)
01018       break;
01019   }
01020 
01021   return vals[i];
01022 }
01023 //----------------------------------------------------------------------
01024 //: Finds the lower bound value which eliminates a given fraction of histogram area.
01025 //
01026 float vifa_histogram::HighClipVal(float clip_fraction)
01027 {
01028   if (clip_fraction < 0)
01029     clip_fraction = 0.0f;
01030   if (clip_fraction > 1.0f)
01031     clip_fraction = 1.0f;
01032 
01033   float area = this->ComputeArea();
01034   if (area==0.0f)
01035     return this->GetMaxVal();
01036 
01037   if (clip_fraction == 0.0f)
01038     return this->GetMaxVal();
01039   if (clip_fraction == 1.0f)
01040     return this->GetMinVal();
01041 
01042   float clip_area = area * clip_fraction;
01043   float* counts = this->GetCounts();
01044   float* vals = this->GetVals();
01045   int res = this->GetRes();
01046   float sum = 0;
01047   int i = (res - 1);
01048   for (; i >= 0; i--)
01049   {
01050     sum += counts[i];
01051     if (sum >= clip_area)
01052       break;
01053   }
01054 
01055   return vals[i];
01056 }
01057 //--------------------------------------------------------------------------
01058 //: Prints histogram counts onto vcl_cout
01059 void vifa_histogram::Print()
01060 {
01061   float* vals = this->GetVals();
01062   float* counts = this->GetCounts();
01063   int res = this->GetRes();
01064   int width = 0;
01065   for (int j = 0; j < res; j++)
01066   {
01067     if (width >= 5)
01068     {
01069       width = 0;
01070       vcl_cout << vcl_endl;
01071     }
01072     vcl_printf("%6.1f %5.0f |", vals[j], counts[j]);
01073     width++;
01074   }
01075 
01076   vcl_cout << vcl_endl << " MaxVal " << this->GetMaxVal() << vcl_endl
01077            << " MinVal " << this->GetMinVal() << vcl_endl
01078            << " BucketSize " << this->GetBucketSize() << vcl_endl
01079            << " Resolution " << this->GetRes() << vcl_endl
01080            << " Area " << this->ComputeArea(this->GetMinVal(),this->GetMaxVal()) << vcl_endl
01081            << "------------------------------------------------\n\n";
01082 }
01083 //---------------------------------------------------------------------------
01084 //: dumps histogram  values  to file.
01085 
01086 void vifa_histogram::Dump(char *dumpfile)
01087 {
01088   vcl_ofstream dumpfp(dumpfile, vcl_ios::out);
01089 
01090   if (!dumpfp)
01091   {
01092     vcl_cerr << "Error opening histogram data file.\n";
01093     return;
01094   }
01095 
01096   for (int i = 0; i < num; i++)
01097     dumpfp << vals[i] << ' ' << counts[i] << vcl_endl;
01098 }
01099 
01100 //---------------------------------------------------------------------------
01101 //: Writes histogram in format suitable for plotting tools like Gnuplot.
01102 int vifa_histogram::WritePlot(const char *fname)
01103 {
01104   vcl_ofstream fp(fname, vcl_ios::out); // open the file...
01105 
01106   if (!fp)
01107   {
01108     vcl_cerr << "Error opening histogram plot file.\n";
01109     return 0;
01110   }
01111 
01112   int stat_res = this->GetRes();
01113 
01114   float * x = new float[2*stat_res];
01115   float * y = new float[2*stat_res];
01116 
01117   float * temp_x = this->GetVals();
01118   float * temp_y = this->GetCounts();
01119   float     delt = this->GetBucketSize();
01120 
01121   for (register int i=0; i < stat_res ;i++)
01122   {
01123     x[2*i] = temp_x[i] - 0.5f * delt;
01124     x[2*i+1] = temp_x[i] + 0.5f * delt;
01125     y[2*i] = temp_y[i];
01126     y[2*i+1] = temp_y[i];
01127   }
01128 
01129   for (register int j = 0; j < 2*stat_res; j++)
01130     fp << x[j] << delimiter << y[j] << vcl_endl;
01131 
01132   delete [] x;
01133   delete [] y;
01134   fp.close();
01135 
01136   return 1;
01137 }
01138 //---------------------------------------------------------------------------
01139 //: Compare 'this' histogram to another (passed in).
01140 //    Taken from the old TargetJr class HistEntropy.
01141 //
01142 float vifa_histogram::CompareToHistogram(vifa_histogram* h)
01143 {
01144   // h1 = 'this'
01145   float m1 = this->GetMean();
01146   float m2 = h->GetMean();
01147 
01148   float v1 = this->GetStandardDev();
01149   float v2 = h->GetStandardDev();
01150 
01151   // We don't like singular situations
01152   if ( vcl_fabs(v1) < 1e-6 || vcl_fabs(v2) < 1e-6 ) return 0.0f;
01153   if (m1==0||m2==0) return 0.0f; // means exactly 0 indicate singular histogram
01154 
01155   // scale factor ln(2)/2 = 0.347 means M = 2 at exp = 0.5
01156   return (float)vcl_exp(- vcl_fabs( 0.693 * (m1 - m2) * vcl_sqrt(1.0/(v1*v1) + 1.0/(v2*v2))));
01157 }