contrib/brl/bseg/brip/brip_para_cvrg.cxx
Go to the documentation of this file.
00001 #include "brip_para_cvrg.h"
00002 //:
00003 // \file
00004 
00005 #include <vul/vul_timer.h>
00006 #include <vcl_cstdlib.h>
00007 #include <vcl_cmath.h>
00008 #include <vcl_cassert.h>
00009 #include "brip_vil_float_ops.h"
00010 
00011 //-----------------------------------------------------------------------
00012 //: Variable Initialization
00013 void brip_para_cvrg::init_variables()
00014 {
00015   width_ = int(3*sigma_);
00016   proj_n_ = 2*proj_width_ + 1;
00017   sup_proj_ = vcl_vector<float>(proj_n_, 0.0f);
00018   proj_0_ = vcl_vector<float>(proj_n_, 0.0f);
00019   proj_45_ = vcl_vector<float>(proj_n_, 0.0f);
00020   proj_90_ = vcl_vector<float>(proj_n_, 0.0f);
00021   proj_135_ = vcl_vector<float>(proj_n_, 0.0f);
00022 }
00023 
00024 
00025 //-----------------------------------------------------------------------
00026 //:  Image Initialization
00027 void brip_para_cvrg::init(vil_image_resource_sptr const & image)
00028 {
00029   vul_timer t;
00030   // we don't have roi capability so just use the whole image for now
00031   int w = image->ni(), h = image->nj();
00032   xstart_ = 0;
00033   ystart_ = 0;
00034   xsize_ = w;
00035   ysize_ = h;
00036 
00037   vcl_cout << "xstart = " << xstart_ << " ystart_ = " << ystart_ << '\n'
00038            << "xsize = " << xsize_ << " ysize_ = " << ysize_ << '\n'
00039            << vcl_flush;
00040 
00041   image_ = brip_vil_float_ops::convert_to_float(image);
00042   avg_.set_size(w,h);
00043   grad0_.set_size(w,h);
00044   grad45_.set_size(w,h);
00045   grad90_.set_size(w,h);
00046   grad135_.set_size(w,h);
00047   det_.set_size(w,h);
00048   dir_.set_size(w,h);
00049   this->init_variables();
00050   vcl_cout << "Do Initialization in " << t.real() << " msecs\n"
00051            << vcl_flush;
00052 }
00053 
00054 //-----------------------------------------------------------------------------
00055 //: Constructor s
00056 brip_para_cvrg::brip_para_cvrg(float sigma, float thresh,
00057                                float gauss_tail, int proj_width,
00058                                int proj_height, int sup_radius,
00059                                bool v) :
00060   brip_para_cvrg_params(sigma, thresh, gauss_tail, proj_width, proj_height,
00061                         sup_radius, v)
00062 {
00063   this->init_variables();
00064 }
00065 
00066 brip_para_cvrg::brip_para_cvrg(brip_para_cvrg_params& pdp) :
00067   brip_para_cvrg_params(pdp)
00068 {
00069   this->init_variables();
00070 }
00071 
00072 //-----------------------------------------------------------------------------
00073 //: Destructor.
00074 brip_para_cvrg::~brip_para_cvrg()
00075 {
00076 }
00077 
00078 //-----------------------------------------------------------------------------
00079 //: Convolves the image with the smoothing kernel.  Private.
00080 void brip_para_cvrg::smooth_image()
00081 {
00082   vul_timer t;
00083   smooth_ = brip_vil_float_ops::gaussian(image_, sigma_);
00084   vcl_cout << "Smooth image in " << t.real() << " msecs\n"
00085            << vcl_flush;
00086 }
00087 
00088 
00089 //----------------------------------------------------------
00090 //: Compute the average value in the 7x7 window
00091 void brip_para_cvrg::avg(int x, int y, vil_image_view<float> const& smooth, vil_image_view<float>& avg)
00092 {
00093   float sum =0;
00094   for (int i = -3; i<=3; i++)
00095     for (int j = -3; j<=3; j++)
00096     {
00097       sum += smooth(x+i, y+j);
00098     }
00099 
00100   avg(x,y) = sum/49.0f;
00101 }
00102 
00103 
00104 //----------------------------------------------------------
00105 //: Compute a gradient operator at x,y along the x axis
00106 void brip_para_cvrg::grad0(int x, int y, vil_image_view<float> const& smooth,
00107                            vil_image_view<float>& grad0)
00108 {
00109   float plus = 0.5f*smooth(x+1,y+3) + smooth(x+1,y+2) + smooth(x+1,y+1) +
00110     smooth(x+1,y) + smooth(x+1,y-1) + smooth(x+1,y-2)
00111     + 0.5f*smooth(x+1,y-3);
00112   float minus = 0.5f*smooth(x-1,y+3) + smooth(x-1,y+2) + smooth(x-1,y+1) +
00113     smooth(x-1,y) + smooth(x-1,y-1) + smooth(x-1,y-2) + 0.5f*smooth(x-1,y-3);
00114   grad0(x,y) = (plus-minus);
00115 }
00116 
00117 
00118 //----------------------------------------------------------
00119 //: Compute a gradient operator at x,y at 45 degrees
00120 void brip_para_cvrg::grad45(int x, int y, vil_image_view<float> const& smooth,
00121                             vil_image_view<float>& grad45)
00122 {
00123   float plus = smooth(x-2,y+3) + smooth(x-1,y+2) + smooth(x,y+1)
00124     + smooth(x+1,y) + smooth(x+2,y-1) + smooth(x+3,y-2);
00125   float minus = smooth(x-3,y+2) + smooth(x-2,y+1) + smooth(x-1,y)
00126     + smooth(x,y-1) + smooth(x+1,y-2) + smooth(x+2,y-3);
00127 
00128   grad45(x,y) = 1.30f*(plus-minus);
00129 }
00130 
00131 
00132 //----------------------------------------------------------
00133 //: Compute a gradient operator at x,y at 90 degrees
00134 void brip_para_cvrg::grad90(int x, int y, vil_image_view<float> const& smooth,
00135                             vil_image_view<float>& grad90)
00136 {
00137   float plus = 0.5f*smooth(x+3,y+1) + smooth(x+2,y+1) + + smooth(x+1,y+1) +
00138     smooth(x,y+1) + smooth(x-1,y+1) + smooth(x-2,y+1) + 0.5f*smooth(x-3,y+1);
00139   float minus =0.5f*smooth(x+3,y-1) + smooth(x+2,y-1)+ smooth(x+1,y-1) +
00140     smooth(x,y-1) + smooth(x-1,y-1) + smooth(x-2,y-1) + 0.5f*smooth(x-3,y-1);
00141   grad90(x, y) = (plus-minus);
00142 }
00143 
00144 
00145 //----------------------------------------------------------
00146 //: Compute a gradient operator at x,y at 135 degrees
00147 void brip_para_cvrg::grad135(int x, int y, vil_image_view<float> const& smooth,
00148                              vil_image_view<float>& grad135)
00149 {
00150   float plus = smooth(x+3,y+2) + smooth(x+2,y+1) + smooth(x+1,y)
00151     + smooth(x,y-1) + smooth(x-1,y-2) + smooth(x-2,y-3);
00152   float minus = smooth(x+2,y+3) + smooth(x+1,y+2) + smooth(x,y+1)
00153     + smooth(x-1,y) + smooth(x-2,y-1) + smooth(x-3,y-2);
00154 
00155   grad135(x, y) = 1.3f*(plus-minus);
00156 }
00157 
00158 
00159 //-----------------------------------------------------------------------------
00160 //: Convolves with the kernel in the x direction, to compute the local derivative in that direction.
00161 //  Private.
00162 void brip_para_cvrg::compute_gradients()
00163 {
00164   vul_timer t;
00165   int x,y;
00166   int radius = width_+3;
00167   grad0_.fill(0.0f);
00168   grad45_.fill(0.0f);
00169   grad90_.fill(0.0f);
00170   grad135_.fill(0.0f);
00171   for (y=radius;y<ysize_ - radius;y++)
00172     for (x=radius;x<xsize_ - radius;x++)
00173     {
00174       this->avg(x, y, smooth_, avg_);
00175       this->grad0(x, y, smooth_, grad0_);
00176       this->grad45(x, y, smooth_, grad45_);
00177       this->grad90(x, y, smooth_, grad90_);
00178       this->grad135(x, y, smooth_, grad135_);
00179     }
00180   vcl_cout << "Compute gradients in " << t.real() << " msecs\n"
00181            << vcl_flush;
00182 }
00183 
00184 
00185 //------------------------------------------------------------
00186 //: Project the gradient magnitude along a given direction.
00187 //  The result is a 1-d projection plot.
00188 //  \verbatim
00189 //                     .
00190 //                    *  .
00191 //                   ^  *  .
00192 //                 /   ^  *  .
00193 //                  \    ^  *  .
00194 //                         ^  *  \ .
00195 //   2*proj_width_+1   x     ^  x-----2*proj_height_+1
00196 //                        \ / \ .
00197 // \endverbatim
00198 float brip_para_cvrg::project(int x, int y, int dir,
00199                               vcl_vector<float>& projection)
00200 {
00201   int w,h;
00202   int w0 = proj_width_;
00203   // float energy = 0.0f;
00204   for (h=-proj_height_; h<=proj_height_; h++)
00205     for (w=-w0; w<=w0; w++)
00206     {
00207       switch (dir)
00208       {
00209       case 0:
00210         projection[w+w0] += grad0_(x+w,y+h);
00211         break;
00212       case 45:
00213         projection[w+w0] += grad45_(x+h+w,y+w-h);
00214         break;
00215       case 90:
00216         projection[w+w0] += grad90_(x+h,y+w);
00217         break;
00218       case 135:
00219         projection[w+w0] += grad135_(x+h-w,y+w+h);
00220         break;
00221       default:
00222         projection[w+w0] += 0; // no-op
00223         break;
00224       }
00225     }
00226   float max_energy = 0;
00227   for (int i =0; i<proj_n_; i++)
00228   {
00229     float val = vcl_fabs(projection[i]);
00230     if (val>max_energy)
00231       max_energy = val;
00232   }
00233   return max_energy;
00234 }
00235 
00236 
00237 //: Prune any sequences of more than one maximum value.
00238 // That is, it is possible to have a "flat" top peak with an arbitrarily
00239 // long sequence of equal, but maximum values.
00240 //
00241 void brip_para_cvrg::remove_flat_peaks(int n, vcl_vector<float>& array)
00242 {
00243   int nbm = n-1;
00244 
00245   // Here we define a small state machine - parsing for runs of peaks
00246   // init is the state corresponding to an initial run (starting at i ==0)
00247   bool init= array[0]==0;
00248   int init_end =0;
00249 
00250   // start is the state corresponding to any other run of peaks
00251   bool start=false;
00252   int start_index=0;
00253 
00254   // The scan of the state machine
00255   for (int i = 0; i < n; i++)
00256   {
00257     float v = array[i];
00258 
00259     // State init: a string of non-zeroes at the beginning.
00260     if (init&&v!=0)
00261       continue;
00262 
00263     if (init&&v==0)
00264     {
00265       init_end = i;
00266       init = false;
00267       continue;
00268     }
00269 
00270     // State !init&&!start: a string of "0s"
00271     if (!start&&v==0)
00272       continue;
00273 
00274     // State !init&&start: the first non-zero value
00275     if (!start&&v!=0)
00276     {
00277       start_index = i;
00278       start = true;
00279       continue;
00280     }
00281     // State ending flat peak: encountered a subsequent zero after starting
00282     if (start&&v==0)
00283     {
00284       int peak_location = (start_index+i-1)/2; // The middle of the run
00285       for (int k = start_index; k<=(i-1); k++)
00286         if (k!=peak_location)
00287           array[k] = 0;
00288       start = false;
00289     }
00290   }
00291   // Now handle the boundary conditions
00292   if (init_end!=0)  // Was there an initial run of peaks?
00293   {
00294     int init_location = (init_end-1)/2;
00295     for (int k = 0; k<init_end; k++)
00296       if (k!=init_location)
00297         array[k] = 0;
00298   }
00299   if (start)       // Did we reach the end of the array in a run of pks?
00300   {
00301     int end_location = (start_index + nbm)/2;
00302     for (int k = start_index; k<n; k++)
00303       if (k!=end_location)
00304         array[k] = 0;
00305   }
00306 }
00307 
00308 
00309 //------------------------------------------------------------------
00310 //: Find locally maximum peaks in the input array
00311 void brip_para_cvrg::non_maximum_supress(vcl_vector<float> const& input_array,
00312                                          vcl_vector<float>& sup_array)
00313 {
00314   if ((2*sup_radius_ +1)> proj_width_)
00315   {
00316     vcl_cout << "In brip_para_cvrg::NonMaximumSupress(..) the kernel is too large\n";
00317   }
00318   vcl_vector<float> tmp(proj_n_);
00319   for (int i=0; i<proj_n_; i++)
00320     tmp[i]=vcl_fabs(input_array[i]);
00321   // Get the counts array of "this"
00322   // Make a new Histogram for the suppressed
00323 
00324   for (int i = sup_radius_; i < (proj_n_-sup_radius_); i++)
00325   {
00326     // find the maximum value in the current kernel
00327     float max_val = 0;
00328     for (int k = -sup_radius_; k <= sup_radius_ ;k++)
00329     {
00330       int index = i+k;
00331       if (tmp[index] > max_val)
00332         max_val = tmp[index];
00333     }
00334     // Is position i a local maximum?
00335     if (vcl_fabs(max_val-tmp[i])<1e-03)
00336       sup_array[i] = max_val; // Yes. So set the counts to the max value
00337   }
00338   this->remove_flat_peaks(proj_n_, sup_array);
00339 }
00340 
00341 
00342 //---------------------------------------------------------------
00343 //: Find the amount of overlapping parallel coverage
00344 float brip_para_cvrg::parallel_coverage(vcl_vector<float> const& input_array)
00345 {
00346   sup_proj_.resize(proj_n_, 0.0f);
00347   this->non_maximum_supress(input_array, sup_proj_);
00348   int n_peaks = 0;
00349   float proj_sum = 0;
00350   for (int i = 0; i<proj_n_; i++)
00351     if (sup_proj_[i]>0)
00352     {
00353       n_peaks++;
00354       proj_sum += sup_proj_[i];
00355     }
00356   if (n_peaks<2)
00357     return 0;
00358   return proj_sum/float(n_peaks);
00359 }
00360 
00361 
00362 //----------------------------------------------------------
00363 //: Find the direction with maximum parallel coverage.  Return the normalized coverage value.
00364 void brip_para_cvrg::compute_parallel_coverage()
00365 {
00366   vul_timer t;
00367   // float min_sum = .01f;
00368   det_.fill(0.0f);
00369   dir_.fill(0.0f);
00370   float direct;
00371   int radius = proj_width_+proj_height_ + 3;
00372 
00373   for (int y=radius; y<(ysize_-radius);y++)
00374     for (int x=radius ;x<(xsize_-radius);x++)
00375     {
00376       // zero arrays
00377       proj_0_ = vcl_vector<float>(proj_n_, 0.0f);
00378       proj_45_ = vcl_vector<float>(proj_n_, 0.0f);
00379       proj_90_ = vcl_vector<float>(proj_n_, 0.0f);
00380       proj_135_ = vcl_vector<float>(proj_n_, 0.0f);
00381       float coverage[4];
00382       this->project(x, y, 0, proj_0_);
00383       coverage[0] = this->parallel_coverage(proj_0_);
00384       float max_coverage = coverage[0];
00385       direct = 0.f;
00386       this->project(x, y, 45, proj_45_);
00387       coverage[1] = this->parallel_coverage(proj_45_);
00388       if (coverage[1]>max_coverage)
00389       {
00390         max_coverage = coverage[1];
00391         direct = 45.f;
00392       }
00393       this->project(x, y, 90, proj_90_);
00394       coverage[2] = this->parallel_coverage(proj_90_);
00395       if (coverage[2]>max_coverage)
00396       {
00397         max_coverage = coverage[2];
00398         direct = 90.f;
00399       }
00400       this->project(x, y, 135, proj_135_);
00401       coverage[3] = this->parallel_coverage(proj_135_);
00402       if (coverage[3]>max_coverage)
00403       {
00404         max_coverage = coverage[3];
00405         direct = 135.f;
00406       }
00407 #ifdef DEBUG
00408       vcl_cout << '(' << x << ',' << y << ") coverage:\n"
00409                << "   O degrees = " << coverage[0] << '\n'
00410                << "  45 degrees = " << coverage[1] << '\n'
00411                << "  90 degrees = " << coverage[2] << '\n'
00412                << " 135 degrees = " << coverage[3] << '\n'
00413                << "max_coverage = " << max_coverage << '\n';
00414 #endif
00415 
00416       det_(x,y) = max_coverage;
00417       dir_(x,y) = direct;
00418     }
00419   vcl_cout << "Do parallel coverage in " << t.real() << " msecs\n"
00420            << vcl_flush;
00421 }
00422 
00423 
00424 //------------------------------------------------------------------
00425 //: Compute a 8-bit image from the projected gradients
00426 void brip_para_cvrg::compute_image(vil_image_view<float> const& data,
00427                                    vil_image_view<unsigned char>& image)
00428 {
00429   image = vil_image_view<unsigned char>(xsize_, ysize_);
00430   // find the maximum value
00431   float max_val = 0;
00432   for (int y = 0; y<ysize_; y++)
00433     for (int x = 0; x<xsize_; x++)
00434       if (data(x,y)>max_val)
00435         max_val = data(x,y);
00436   if (max_val<1e-06)
00437     max_val = 1e-06f;
00438   // Normalize the data and load the image
00439   for (int y = 0; y<ysize_; y++)
00440     for (int x = 0; x<xsize_; x++)
00441     {
00442       float temp = 255*data(x,y)/max_val;
00443       unsigned char val;
00444       val = (unsigned char)temp;
00445       image(x, y)=val;
00446     }
00447 }
00448 
00449 
00450 void brip_para_cvrg::do_coverage(vil_image_resource_sptr const& image)
00451 {
00452   this->init(image);
00453   this->smooth_image();
00454   this->compute_gradients();
00455   this->compute_parallel_coverage();
00456 }
00457 
00458 
00459 //------------------------------------------------------------
00460 //: Get the float image of detections. Scale onto [0, max]
00461 vil_image_view<float>
00462 brip_para_cvrg::get_float_detection_image(const float max)
00463 {
00464   vil_image_view<float> out(xsize_, ysize_);
00465   out.fill(0);
00466   float max_val = 0;
00467   for (int y = 0; y<ysize_; y++)
00468     for (int x = 0; x<xsize_; x++)
00469       if (det_(x,y)>max_val)
00470         max_val = det_(x,y);
00471 
00472   if (max_val==0)
00473     return out;
00474   float s = max/max_val;
00475   for (int y = 0; y<ysize_; y++)
00476     for (int x = 0; x<xsize_; x++)
00477       out(x,y) = s*det_(x,y);
00478   return out;
00479 }
00480 
00481 
00482 //------------------------------------------------------------
00483 //: Get the unsigned char image of detections
00484 vil_image_view<unsigned char> brip_para_cvrg::get_detection_image()
00485 {
00486   if (!det_image_)
00487     this->compute_image(det_, det_image_);
00488   return det_image_;
00489 }
00490 
00491 
00492 //------------------------------------------------------------
00493 //: Get the direction image (unsigned char)
00494 vil_image_view<unsigned char>  brip_para_cvrg::get_dir_image()
00495 {
00496   if (!dir_image_) {
00497     dir_image_ = vil_image_view<unsigned char>(xsize_, ysize_);
00498   }
00499   for (int y = 0; y<ysize_; y++)
00500     for (int x = 0; x<xsize_; x++)
00501       dir_image_(x,y) = static_cast<unsigned char>(dir_(x,y));
00502   return dir_image_;
00503 }
00504 
00505 //------------------------------------------------------------
00506 //: Get the combination of coverage and direction as a color image
00507 vil_image_view<vil_rgb<unsigned char> >
00508 brip_para_cvrg::get_combined_image()
00509 {
00510   // "arbitrary" color assignments to the 4 directions: cyan,yellow,green,red:
00511   unsigned char r[4] ={0, 255, 0, 255};
00512   unsigned char g[4] ={255, 0, 255, 0};
00513   unsigned char b[4] ={255, 255, 0, 0};
00514   vil_image_view<unsigned char> cvrg_image = this->get_detection_image();
00515   vil_image_view<unsigned char> dir_image = this->get_dir_image();
00516   vil_image_view<vil_rgb<unsigned char> > out(xsize_, ysize_);
00517   for (int y = 0; y<ysize_; y++)
00518     for (int x = 0; x<xsize_; x++)
00519     {
00520       unsigned int direct = ((unsigned int)dir_image(x,y))/45;
00521       //      assert (direct<=3);
00522       if (direct>3) continue;
00523       unsigned char c = cvrg_image(x,y),
00524                     red  = r[direct]&c,
00525                     green= g[direct]&c,
00526                     blue = b[direct]&c;
00527       out(x, y) = vil_rgb<unsigned char>(red, green, blue);
00528     }
00529   return out;
00530 }