contrib/gel/vifa/vifa_group_pgram.cxx
Go to the documentation of this file.
00001 // This is gel/vifa/vifa_group_pgram.cxx
00002 #include "vifa_group_pgram.h"
00003 //:
00004 // \file
00005 
00006 #include <vcl_cmath.h>
00007 #include <vnl/vnl_math.h>
00008 #include <vgl/vgl_point_2d.h>
00009 #include <vgl/vgl_vector_2d.h>
00010 #include <vgl/vgl_clip.h>
00011 
00012 #ifndef DEGTORAD
00013 #define DEGTORAD  (vnl_math::pi_over_180)
00014 #endif
00015 
00016 
00017 vifa_group_pgram::
00018 vifa_group_pgram(imp_line_list&                  lg,
00019                  const vifa_group_pgram_params&  old_params,
00020                  double                          angle_range)
00021   : vifa_group_pgram_params(old_params)
00022 {
00023   angle_range_ = angle_range;
00024   th_dim_ = (int)vcl_ceil(angle_range_/angle_increment());
00025   th_dim_++; //Include both 0 and angle_range_
00026   bb_ = new vifa_bbox;
00027 
00028   for (int i = 0; i < th_dim_; i++)
00029   {
00030     imp_line_list*  illp = new imp_line_list;
00031     curves_.push_back(illp);
00032   }
00033   this->Index(lg);
00034 }
00035 
00036 //------------------------------------------------------------
00037 //: Destructor
00038 vifa_group_pgram::
00039 ~vifa_group_pgram()
00040 {
00041   for (imp_line_table::iterator ilti = curves_.begin(); ilti != curves_.end();
00042        ilti++)
00043   {
00044     imp_line_list*  illp = (*ilti);
00045     for (imp_line_iterator ili = illp->begin(); ili != illp->end(); ili++)
00046     {
00047       (*ili) = 0;
00048     }
00049 
00050     delete illp;
00051   }
00052 }
00053 
00054 //-----------------------------------------------------
00055 //: Add an ImplicitLine to the index
00056 void vifa_group_pgram::
00057 Index(imp_line_sptr il)
00058 {
00059   int  ang_bin = this->AngleLoc(il);
00060   curves_[ang_bin]->push_back(il);
00061 
00062   this->touch();
00063 }
00064 
00065 //------------------------------------------------------------
00066 //: Add a set of ImplicitLines to the angular index
00067 void vifa_group_pgram::
00068 Index(imp_line_list& lg)
00069 {
00070   for (imp_line_iterator ili = lg.begin(); ili != lg.end(); ili++)
00071     Index(*ili);
00072 }
00073 
00074 //------------------------------------------------------------
00075 //: Clear all lines from the index
00076 void vifa_group_pgram::
00077 Clear()
00078 {
00079   for (imp_line_table::iterator ilti = curves_.begin(); ilti != curves_.end();
00080        ilti++)
00081   {
00082     imp_line_list*  illp = (*ilti);
00083     for (imp_line_iterator ili = illp->begin(); ili != illp->end(); ili++)
00084       (*ili) = 0;
00085 
00086     delete illp;
00087     (*ilti) = new imp_line_list;
00088   }
00089 
00090   this->touch();
00091 }
00092 
00093 //-----------------------------------------------------------------
00094 //: Compute a histogram of parallel line coverage
00095 //
00096 vifa_histogram_sptr vifa_group_pgram::
00097 GetCoverageHist(void)
00098 {
00099   vifa_histogram_sptr  h = new vifa_histogram(th_dim_, 0.0f, float(angle_range_));
00100 
00101   float*  cnts = h->GetCounts();
00102   for (int i = 0; i < th_dim_; i++)
00103     cnts[i] = float(this->LineCoverage(i));
00104   return h;
00105 }
00106 
00107 //--------------------------------------------------------------
00108 //: Get a populated line coverage corresponding to a given angle bin
00109 //
00110 vifa_line_cover_sptr vifa_group_pgram::
00111 GetLineCover(int  angle_bin)
00112 {
00113   imp_line_sptr  il = this->LineAtAngle(angle_bin);
00114 
00115   // Get all the lines which are within +- angular resolution of angle_bin.
00116   imp_line_list  lg;
00117   this->CollectAdjacentLines(angle_bin, lg);
00118 
00119   if (!lg.size())
00120   {
00121     return NULL;
00122   }
00123 
00124   // Construct a bounding box from the ROI and clip
00125   // the line defined by angle_bin
00126   double  bx;
00127   double  by;
00128   double  ex;
00129   double  ey;
00130   this->CheckUpdateBoundingBox();
00131   if (!vgl_clip_line_to_box(il->a(), il->b(), il->c(),
00132                             bb_->min_x(), bb_->min_y(),
00133                             bb_->max_x(), bb_->max_y(),
00134                             bx, by, ex, ey))
00135   {
00136     vcl_cerr << "In vifa_group_pgram::GetLineCover(): No intersection found\n";
00137     return NULL;
00138   }
00139 
00140   // Here we set the clipping bounds.
00141   vgl_point_2d<double>  b(bx, by);
00142   vgl_point_2d<double>  e(ex, ey);
00143   il->set_points(b, e);
00144 
00145   // The line is cut into 1 pixel bins
00146   int len = int(il->length());
00147   if (!len)
00148   {
00149     return NULL;
00150   }
00151 
00152   vifa_line_cover_sptr  cov = new vifa_line_cover(il, len);
00153   for (imp_line_iterator ili = lg.begin(); ili != lg.end(); ili++)
00154   {
00155     cov->InsertLine(*ili);
00156   }
00157 
00158   return cov;
00159 }
00160 
00161 //--------------------------------------------------------------
00162 //: Compute parallel line overlap on a line at the same orientation with midpoint at the center of the region of the line group.
00163 //
00164 double vifa_group_pgram::
00165 LineCoverage(int  angle_bin)
00166 {
00167   vifa_line_cover_sptr  lc = this->GetLineCover(angle_bin);
00168   return lc ? lc->GetCoverage() : 0.0;
00169 }
00170 
00171 //--------------------------------------------------------------
00172 //: Collect implicit line(s) from the angle array at orientations +- the given bin orientation.
00173 //  Wrap around the end of the array so that 0 degrees and 180 degrees are considered parallel.
00174 void vifa_group_pgram::
00175 CollectAdjacentLines(int             angle_bin,
00176                      imp_line_list&  lg)
00177 {
00178   if (angle_bin >= 0 && angle_bin < th_dim_)
00179   {
00180     if (angle_bin == 0)
00181     {
00182       // Case I - At the beginning of the array
00183       lg.insert(lg.end(), curves_[th_dim_ - 1]->begin(),
00184                 curves_[th_dim_ - 1]->end());
00185       lg.insert(lg.end(), curves_[0]->begin(),
00186                 curves_[0]->end());
00187       lg.insert(lg.end(), curves_[1]->begin(),
00188                 curves_[1]->end());
00189     }
00190     else if (angle_bin == th_dim_ - 1)
00191     {
00192       // Case II - At the end of the array
00193       lg.insert(lg.end(), curves_[th_dim_ - 2]->begin(),
00194                 curves_[th_dim_ - 2]->end());
00195       lg.insert(lg.end(), curves_[th_dim_ - 1]->begin(),
00196                 curves_[th_dim_ - 1]->end());
00197       lg.insert(lg.end(), curves_[0]->begin(),
00198                 curves_[0]->end());
00199     }
00200     else
00201     {
00202       // Case III - not near ends of the array
00203       lg.insert(lg.end(), curves_[angle_bin - 1]->begin(),
00204                 curves_[angle_bin - 1]->end());
00205       lg.insert(lg.end(), curves_[angle_bin]->begin(),
00206                 curves_[angle_bin]->end());
00207       lg.insert(lg.end(), curves_[angle_bin + 1]->begin(),
00208                 curves_[angle_bin + 1]->end());
00209     }
00210   }
00211   else
00212     vcl_cerr << "vifa_group_pgram::CollectAdjacentLines(): bad angle_bin\n";
00213 }
00214 
00215 //------------------------------------------------------------------
00216 //: Get Total length of parallel lines adjacent and including a bin
00217 //
00218 double vifa_group_pgram::
00219 GetAdjacentPerimeter(int  bin)
00220 {
00221   imp_line_list  lg;
00222   this->CollectAdjacentLines(bin, lg);
00223 
00224   double  sum = 0;
00225   for (imp_line_iterator ili = lg.begin(); ili != lg.end(); ili++)
00226   {
00227     vgl_vector_2d<double>  v = (*ili)->point2() - (*ili)->point1();
00228     sum += v.length();
00229   }
00230 
00231   return sum;
00232 }
00233 
00234 //------------------------------------------------------
00235 //: Compute the total length of parallel lines normalized by the total edge perimeter
00236 double vifa_group_pgram::
00237 norm_parallel_line_length(void)
00238 {
00239   this->ComputeDominantDirs();
00240   if (dominant_dirs_.size() < 1)
00241   {
00242     // No basis
00243     return 0.0;
00244   }
00245 
00246   double max_cover = 0.0;
00247   int    max_dir = 0;
00248   vcl_vector<int>::iterator  iit = dominant_dirs_.begin();
00249   for (; iit != dominant_dirs_.end(); iit++)
00250   {
00251     int            dir = (*iit);
00252     vifa_line_cover_sptr  lc = this->GetLineCover(dir);
00253     if (!(lc.ptr()))
00254     {
00255 //      vcl_cout << "vgg::norm_parallel_line_length(): "
00256 //               << "No line cover found for dir " << dir << vcl_endl;
00257 
00258       // Is this right?  What about other dominant directions?
00259       // return 0.0;
00260       continue;
00261     }
00262 
00263     double  cov = lc->GetCoverage();
00264 
00265     if (cov > max_cover)
00266     {
00267       max_cover = cov;
00268       max_dir = dir;
00269     }
00270   }
00271 
00272   double  per = this->GetAdjacentPerimeter(max_dir);
00273 
00274 //  vcl_cout << "vgg::norm_parallel_line_length(): per = " << per
00275 //           << ", tmp1_ = " << tmp1_ << vcl_endl;
00276 
00277   return 1.5 * per / tmp1_;
00278 }
00279 
00280 //---------------------------------------------------------
00281 //: Find the angle bin corresponding to an implicit_line
00282 int vifa_group_pgram::
00283 AngleLoc(imp_line_sptr  il)
00284 {
00285   // Compute angle index
00286   double  angle = vcl_fmod(il->slope_degrees(), 180.0);
00287   if (angle < 0.0)
00288     angle += 180.0;
00289 
00290   if (angle > angle_range_)
00291   {
00292     vcl_cerr << "In vifa_group_pgram::AngleLoc(): angle " << angle
00293              << " was outside the angle range " << angle_range_ << vcl_endl;
00294     return 0;
00295   }
00296 
00297   return (int)(vcl_floor(angle / angle_increment()));
00298 }
00299 
00300 //--------------------------------------------------------------
00301 //: Define a line passing through the center of the Hough ROI and at an angle corresponding to the angle bin
00302 imp_line_sptr vifa_group_pgram::
00303 LineAtAngle(int  angle_bin)
00304 {
00305   // Get the new line's direction unit vector
00306   double          ang_rad = DEGTORAD * angle_bin * angle_increment();
00307   vgl_vector_2d<double>  d(vcl_cos(ang_rad), vcl_sin(ang_rad));
00308 
00309   // Get the new line's midpoint (bounding box centroid)
00310   this->CheckUpdateBoundingBox();
00311   vgl_point_2d<double>  m = bb_->centroid();
00312 
00313   // Return a new line
00314   imp_line_sptr      il = new imp_line(d, m);
00315   return il;
00316 }
00317 
00318 //------------------------------------------------------
00319 //: Compute the bounding box of the current index
00320 //
00321 void vifa_group_pgram::
00322 ComputeBoundingBox(void)
00323 {
00324   // Reset the bounding box
00325   bb_->empty();
00326 
00327   for (imp_line_table::iterator ilti = curves_.begin(); ilti != curves_.end();
00328        ilti++)
00329   {
00330     imp_line_list*  illp = (*ilti);
00331     for (imp_line_iterator ili = illp->begin(); ili != illp->end(); ili++)
00332     {
00333       imp_line_sptr  il = (*ili);
00334 
00335       bb_->add(il->point1());
00336       bb_->add(il->point2());
00337     }
00338   }
00339 
00340   // Update the bounding box timestamp
00341   bb_->touch();
00342 }
00343 
00344 //---------------------------------------------------------
00345 //: Compute the dominant directions using the coverage histogram.
00346 //  A dominant direction is a local maximum in the coverage distribution.
00347 //
00348 void vifa_group_pgram::
00349 ComputeDominantDirs(void)
00350 {
00351   dominant_dirs_.clear();
00352 
00353   // Get the coverage histogram and do find local maxima.
00354   vifa_histogram_sptr  h = this->GetCoverageHist();
00355   vifa_histogram_sptr  h_sup = h->NonMaximumSupress(max_suppress_radius(), true);
00356   float*               cnts = h_sup->GetCounts();
00357   int                  max_idx = h_sup->GetRes();
00358 
00359   // Rebuild the dominant direction array
00360   for (int i = 0; i < max_idx; i++)
00361     if (cnts[i] > 0)
00362       dominant_dirs_.push_back(i);
00363 
00364 //  vcl_cout << "vgg::ComputeDominantDirs(): max_idx = " << max_idx << ", "
00365 //           << dominant_dirs_.size() << " dominant directions found\n";
00366 }