contrib/brl/bbas/bsol/bsol_distance_histogram.cxx
Go to the documentation of this file.
00001 #include "bsol_distance_histogram.h"
00002 //:
00003 // \file
00004 #include <vcl_cmath.h>
00005 #include <vcl_iostream.h>
00006 #include <vnl/vnl_math.h>
00007 #include <vnl/vnl_numeric_traits.h>
00008 #include <vgl/vgl_homg_line_2d.h>
00009 #include <vsol/vsol_line_2d.h>
00010 
00011 //: Constructors
00012 bsol_distance_histogram::bsol_distance_histogram()
00013 {
00014   delta_ = 0;
00015 }
00016 
00017 //------------------------------------------------------------------------
00018 //: set up the histogram with bin spacing defined by max_val and nbins.
00019 //------------------------------------------------------------------------
00020 bsol_distance_histogram::bsol_distance_histogram(int nbins, double max_val)
00021 {
00022   if (!nbins)
00023   {
00024     delta_=0;
00025     return;
00026   }
00027   bin_counts_.resize(nbins, 0.0);
00028   bin_values_.resize(nbins, 0.0);
00029   weights_.resize(nbins, 0.0);
00030   delta_ = max_val/nbins;
00031 }
00032 
00033 bsol_distance_histogram::
00034 bsol_distance_histogram(const int nbins,
00035                         vcl_vector<vsol_line_2d_sptr> const& lines)
00036 {
00037   if (!nbins)
00038   {
00039     delta_=0;
00040     return;
00041   }
00042   bin_counts_.resize(nbins, 0.0);
00043   bin_values_.resize(nbins, 0.0);
00044   weights_.resize(nbins, 0.0);
00045 
00046   int Nlines = lines.size();
00047   vcl_vector<vgl_homg_line_2d<double> > hlines;
00048   double dmin = vnl_numeric_traits<double>::maxval, dmax = -dmin;
00049   for (int i = 0; i<Nlines; i++)
00050   {
00051     hlines.push_back(lines[i]->vgl_hline_2d());
00052     hlines[i].normalize();
00053     double d = hlines[i].c();
00054     dmin = vnl_math_min(dmin, d);
00055     dmax = vnl_math_max(dmax, d);
00056   }
00057   delta_ = (dmax-dmin)/nbins;
00058 
00059   for (int i = 0; i<Nlines; i++)
00060   {
00061     double ci = hlines[i].c();
00062     double length_i = lines[i]->length();
00063     for (int j = i+1; j<Nlines; j++)
00064     {
00065       double cj = hlines[j].c();
00066       double length = lines[j]->length()+length_i;
00067       double D = vcl_fabs(ci-cj);
00068       this->up_count(D, length, length);
00069     }
00070   }
00071   this->normalize_distance();
00072 }
00073 
00074 //: Destructor
00075 bsol_distance_histogram::~bsol_distance_histogram()
00076 {
00077 }
00078 
00079 
00080 //---------------------------------------------------------------------
00081 //: normalized bin distance = (Sum_i length_i*dist_i)/(Sum_i length_i)
00082 //  Note distances can't be negative so the -1 flag indicates there
00083 //  was no count for that bin.
00084 //---------------------------------------------------------------------
00085 void bsol_distance_histogram::normalize_distance()
00086 {
00087   for (unsigned int k = 0; k<bin_counts_.size(); ++k)
00088   {
00089     if (weights_[k])
00090     {
00091       double val = bin_values_[k];
00092       double w = weights_[k];
00093       bin_values_[k]=val/w;
00094     }
00095     else
00096       bin_values_[k]=-1;
00097   }
00098 }
00099 
00100 void bsol_distance_histogram::up_count(const double value, const double count,
00101                                        const double weight)
00102 {
00103   double val = 0;
00104   bool inserted = false;
00105   for (unsigned int k = 0; k<bin_counts_.size()&&!inserted; ++k, val+=delta_)
00106     if (val>=value)
00107     {
00108       bin_counts_[k]+=count;
00109       bin_values_[k]+=value*weight;
00110       weights_[k]+=weight;
00111       inserted = true;
00112     }
00113 }
00114 
00115 //---------------------------------------------------------------
00116 //: refine the peak location using parabolic interpolation
00117 //
00118 double bsol_distance_histogram::interpolate_peak(int initial_peak)
00119 {
00120   // boundary conditions
00121   if (initial_peak<0)
00122     return 0;
00123   if (initial_peak==0)
00124     return bin_values_[0];
00125   int n = bin_values_.size();
00126   if (initial_peak==(n-1))
00127     return bin_values_[n-1];
00128   if (initial_peak>=n)
00129     return 0;
00130   double fminus = bin_counts_[initial_peak-1];
00131   double fzero = bin_counts_[initial_peak];
00132   double fplus = bin_counts_[initial_peak+1];
00133 
00134   double df = 0.5*(fplus-fminus); // first derivative
00135   double d2f = 0.5*(fplus+fminus-2.0*fzero); // second derivative
00136   if (vcl_fabs(d2f)<1.0e-8)
00137     return bin_values_[initial_peak];
00138 
00139   double root = -0.5*df/d2f;
00140 
00141   // interpolate the bin values within the appropriate interval
00142   double dminus = bin_values_[initial_peak-1];
00143   double dzero = bin_values_[initial_peak];
00144   double dplus = bin_values_[initial_peak+1];
00145 
00146   double result;
00147   if (root<0)
00148     result = (dzero*(1+root)-dminus*root);
00149   else
00150     result = (dzero*(1-root)+dplus*root);
00151 #ifdef DEBUG
00152   vcl_cout << "interpolated distance " << result << '\n';
00153 #endif // DEBUG
00154   return result;
00155 }
00156 
00157 //---------------------------------------------------------------
00158 //: There will typically be a large distance peak at small distances
00159 //  The second distance peak will correspond to periodic line segments
00160 //
00161 bool bsol_distance_histogram::
00162 distance_peaks(double& peak1, double& peak2, double min_peak_height_ratio)
00163 {
00164   int nbins = bin_counts_.size();
00165   // Peak search states
00166   int init = 0, start = 1, down =2 , up=3, s_peak1= 4, down2 = 5, up2 = 6,
00167     s_peak2 = 7, fail=8;
00168   // Initial state assignment
00169   int state=init;
00170   int upi1=0, upi2=0;
00171   double v=0;
00172   double tr=0, peak1_bin_counts=0;
00173   double start_distance = 0;
00174   for (int i = 0; i<nbins&&state!=fail&&state!=s_peak2; i++)
00175   {
00176 #ifdef DEBUG
00177     vcl_cout << "State[" << state << "], D = " << bin_values_[i]
00178              << " C = "<< bin_counts_[i] << " srt_d = " << start_distance
00179              << " v = "<< v << '\n';
00180 #endif
00181     // Begin the scan look for a value above 0
00182     if (state==init)
00183       if (bin_counts_[i]>0)
00184       {
00185         v = bin_counts_[i];
00186         state = start;
00187         start_distance = 0;
00188         continue;
00189       }
00190     // If we are in the start state set the threshold and move down.
00191     if (state==start)
00192     {
00193       //        if (bin_counts_[i]>0)
00194       if (bin_counts_[i]<=v)
00195       {
00196         state = down;
00197         // second peak should be a significant ratio of the starting value
00198         tr = min_peak_height_ratio*v;
00199         v=bin_counts_[i];    // population
00200         continue;
00201       }
00202       else
00203       {
00204         state = start;
00205         v=bin_counts_[i];
00206         start_distance = bin_values_[i];
00207         continue;
00208       }
00209     }
00210 
00211     // we are in the down state looking for a value above the
00212     // ratio threshold and is above the current v value.
00213     if (state==down)
00214     {
00215       if (bin_counts_[i]>tr)
00216       {
00217         if (bin_counts_[i]<=v)
00218           state = down;
00219         else
00220         {
00221           state = up;
00222           // upi1 is the location of the up state
00223           upi1 = i;
00224         }
00225         v = bin_counts_[i];
00226         continue;
00227       }
00228     }
00229     // we are moving up, waiting to capture a peak above the threshold
00230     if (state==up)
00231     {
00232       //        if (bin_counts_[i]>tr)
00233       if (bin_counts_[i]<=v)
00234       {
00235         state = s_peak1;
00236         peak1_bin_counts = bin_counts_[upi1];
00237         tr = min_peak_height_ratio*peak1_bin_counts;
00238       }
00239       else
00240       {
00241         upi1 = i;
00242         state = up;
00243       }
00244       v = bin_counts_[i];
00245       continue;
00246     }
00247     // we have just passed  peak 1
00248     if (state==s_peak1)
00249     {
00250       if (bin_counts_[i]<=peak1_bin_counts)
00251         state = down2;
00252       else
00253         state = fail;
00254       v = bin_counts_[i];
00255       continue;
00256     }
00257     // we are in the second down state looking for a value above the
00258     // ratio threshold and is above the current v value.
00259     if (state==down2)
00260       if (bin_counts_[i]>tr)
00261       {
00262         if (bin_counts_[i]<=v)
00263           state = down2;
00264         else
00265         {
00266           state = up2;
00267           // upi2 is the location of the up state
00268           upi2 = i;
00269         }
00270         v = bin_counts_[i];
00271         continue;
00272       }
00273 
00274     // we are moving up a second time, waiting to capture a peak
00275     // above the threshold
00276     if (state==up2)
00277     {
00278       //        if (bin_counts_[i]>tr)
00279       if (bin_counts_[i]<=v)
00280       {
00281         state = s_peak2;
00282       }
00283       else
00284       {
00285         upi2 = i;
00286         state = up2;
00287       }
00288       v = bin_counts_[i];
00289       continue;
00290     }
00291   }
00292   if (state==up2||state==s_peak2)
00293   {
00294     peak1 = this->interpolate_peak(upi1)-start_distance;
00295     peak2 = this->interpolate_peak(upi2)-start_distance;
00296     return true;
00297   }
00298   return false;
00299 }
00300 
00301 double bsol_distance_histogram::min_val() const
00302 {
00303   int nbins = bin_values_.size();
00304   if (!nbins)
00305     return 0;
00306   return bin_values_[0];
00307 }
00308 
00309 double bsol_distance_histogram::max_val() const
00310 {
00311   int nbins = bin_values_.size();
00312   if (!nbins)
00313     return 0;
00314   return bin_values_[nbins-1];
00315 }
00316 
00317 double bsol_distance_histogram::min_count() const
00318 {
00319   int nbins = bin_counts_.size();
00320   if (!nbins)
00321     return 0;
00322   double min_cnt = bin_counts_[0];
00323   for (int i = 1; i<nbins; i++)
00324     if (bin_counts_[i]<min_cnt)
00325       min_cnt = bin_counts_[i];
00326   return min_cnt;
00327 }
00328 
00329 double bsol_distance_histogram::max_count() const
00330 {
00331   int nbins = bin_counts_.size();
00332   if (!nbins)
00333     return 0;
00334   double max_cnt = bin_counts_[0];
00335   for (int i = 1; i<nbins; i++)
00336     if (bin_counts_[i]>max_cnt)
00337       max_cnt = bin_counts_[i];
00338   return max_cnt;
00339 }
00340 
00341 vcl_ostream& operator << (vcl_ostream& os, const bsol_distance_histogram& h)
00342 {
00343   int nchars = 25; // display resolution
00344   vcl_cout << "Distance Histogram\n";
00345   // get the maximum bin value
00346   double max_cnt = h.max_count();
00347   if (!max_cnt)
00348     return os;
00349 
00350   vcl_vector<double> const& vals = h.values();
00351   vcl_vector<double> const& cnts = h.counts();
00352   for (unsigned int i=0; i<vals.size(); ++i)
00353   {
00354     double val = vals[i];
00355     vcl_cout << val << '|';
00356     double cnt = cnts[i];
00357     int c = int(cnt*nchars/max_cnt);
00358     for (int k = 0; k<c; k++)
00359       vcl_cout << '*';
00360     vcl_cout << '\n';
00361   }
00362   return os;
00363 }