Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members

vifa_histogram.cxx

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

Generated on Thu Jan 10 14:47:30 2008 for contrib/gel/vifa by  doxygen 1.4.4