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