contrib/brl/bbas/bsol/bsol_hough_line_index.cxx
Go to the documentation of this file.
00001 #include "bsol_hough_line_index.h"
00002 //:
00003 // \file
00004 //
00005 // Modifications : see bsol_hough_line_index.h
00006 //
00007 //-----------------------------------------------------------------------------
00008 
00009 #include <vcl_cmath.h>
00010 
00011 #ifdef VCL_VC_6
00012 //Get rid of warning generated by fault deep inside MS supplied library
00013 # pragma warning(disable:4715 )
00014 #endif
00015 
00016 #include <vcl_algorithm.h> // vcl_find()
00017 #include <vnl/vnl_math.h>
00018 #include <vsol/vsol_line_2d.h>
00019 #include <vsol/vsol_point_2d.h>
00020 #include <vsol/vsol_point_2d_sptr.h>
00021 #undef DEGTORAD
00022 #define DEGTORAD 0.017453293f // = float(vnl_math::pi_over_180)
00023 
00024 class nlines
00025 {
00026  public:
00027   bool operator()(const vcl_vector<vsol_line_2d_sptr> & v1,
00028                   const vcl_vector<vsol_line_2d_sptr> & v2)
00029   {
00030     return v1.size() > v2.size();
00031   }
00032 };
00033 
00034 //--------------------------------------------------------------
00035 //
00036 // Constructor and Destructor Functions
00037 //
00038 //--------------------------------------------------------------
00039 
00040 //---------------------------------------------------------------
00041 //: Simple Constructor
00042 //
00043 bsol_hough_line_index::bsol_hough_line_index(const int r_dimension,
00044                                              const int theta_dimension)
00045 {
00046   xo_ = 0; yo_ = 0;
00047   ysize_ = xsize_ = (float)vcl_ceil(r_dimension/vnl_math::sqrt2);
00048   angle_range_ = (float)theta_dimension;
00049   angle_increment_ = 1.0f;
00050 
00051   this->init(r_dimension, theta_dimension);
00052 }
00053 
00054 //--------------------------------------------------------------
00055 //: Constructors from given bounds
00056 //
00057 bsol_hough_line_index::bsol_hough_line_index(const float x0,
00058                                              const float y0,
00059                                              const float xsize,
00060                                              const float ysize,
00061                                              const float angle_range,
00062                                              const float angle_increment)
00063 {
00064   xo_ = x0;  yo_ = y0;
00065   xsize_ = xsize;
00066   ysize_ = ysize;
00067   angle_range_ = angle_range;
00068   angle_increment_ = angle_increment;
00069 
00070   int theta_dimension = (int)vcl_ceil(angle_range_/angle_increment_);
00071   theta_dimension++; //Include both 0 and angle_range_
00072   float diag = vcl_sqrt(xsize*xsize + ysize*ysize);
00073   int rmax = int(diag);
00074   rmax++; //Round off.
00075   this->init(rmax, theta_dimension);
00076 }
00077 
00078 bsol_hough_line_index::
00079 bsol_hough_line_index(vbl_bounding_box<double, 2> const& box,
00080                       const float angle_range,
00081                       const float angle_increment)
00082 {
00083   xo_ = float(box.xmin());  yo_ = float(box.ymin());
00084   xsize_ = float(box.xmax()-xo_);
00085   ysize_ = float(box.ymax()-yo_);
00086   angle_range_ = angle_range;
00087   angle_increment_ = angle_increment;
00088 
00089   int theta_dimension = (int)vcl_ceil(angle_range_/angle_increment_);
00090   theta_dimension++; //Include both 0 and angle_range_
00091   float diag = vcl_sqrt(xsize_*xsize_ + ysize_*ysize_);
00092   int rmax = int(diag);
00093   rmax++; //Round off.
00094   this->init(rmax, theta_dimension);
00095 }
00096 
00097 //: Destructor
00098 bsol_hough_line_index::~bsol_hough_line_index()
00099 {
00100   for (int r=0;r<r_dim_;r++)
00101     for (int th=0;th<th_dim_;th++)
00102       delete index_[r][th];
00103 }
00104 
00105 //-----------------------------------------------------------------------------
00106 //
00107 //: Compute the bsol_hough_line_index array locations corresponding to a line
00108 //
00109 void bsol_hough_line_index::array_loc(vsol_line_2d_sptr const& line,
00110                                       float& r, float& theta)
00111 {
00112   //Compute angle index
00113   float angle = (float)line->tangent_angle();
00114   if (angle >= 180.0f)
00115     angle -= 180.0f;
00116 
00117   if (angle > angle_range_)
00118   {
00119     vcl_cout << "Warning - bsol_hough_line_index angle outside of range!\n";
00120     return;
00121   }
00122 
00123   theta = angle;
00124 
00125   float angrad = DEGTORAD*angle;
00126 
00127   //Compute distance indices
00128   vsol_point_2d_sptr mid = line->middle();
00129   float midx = float(mid->x()-xo_);
00130   float midy = float(mid->y()-yo_);
00131   float xs2 = xsize_/2.0f;
00132   float ys2 = ysize_/2.0f;
00133 
00134   double cx = -(midx-xs2)*vcl_sin(angrad);
00135   double cy =  (midy-ys2)*vcl_cos(angrad);
00136 
00137   //We use the middle of the ranges as the origin to insure minimum error
00138   //Also, the distance index is guaranteed to be positive
00139   r = float(cx + cy + vcl_sqrt(xs2*xs2 + ys2*ys2));
00140 }
00141 
00142 //-----------------------------------------------------------------------------
00143 //
00144 //: Compute the bsol_hough_line_index array locations corresponding to a line
00145 //
00146 void bsol_hough_line_index::array_loc(vsol_line_2d_sptr const& line,
00147                                       int& r, int& theta)
00148 {
00149   float angle = 0, radius = 0;
00150   this->array_loc(line, radius, angle);
00151   theta = (int)vcl_floor(angle/angle_increment_);
00152   r = int(radius);
00153 }
00154 
00155 //-----------------------------------------------------------------------------
00156 //
00157 //: Modify bsol_hough_line_index array R location under translation
00158 //
00159 int bsol_hough_line_index::trans_loc(const int transx, const int transy,
00160                                      const int r, const int theta)
00161 {
00162   float angle = angle_increment_*theta;
00163   float angrad = DEGTORAD*angle;
00164   int new_cx = -int(transx*vcl_sin(angrad));
00165   int new_cy =  int(transy*vcl_cos(angrad));
00166   int newr = new_cx + new_cy;
00167   newr += r;
00168   if (newr < 0)
00169     return 0;
00170   else if (newr > r_dim_)
00171     return r_dim_;
00172   else
00173     return newr;
00174 }
00175 
00176 //-----------------------------------------------------------------------------
00177 //
00178 //: Return the count at a given r and theta
00179 //
00180 //-----------------------------------------------------------------------------
00181 int bsol_hough_line_index::count(const int r, const int theta)
00182 {
00183   if (r<0||theta<0||r>=r_dim_||theta>=th_dim_)
00184   {
00185     vcl_cout << "Warning - bsol_hough_line_index index outside of range!\n";
00186     return 0;
00187   }
00188 
00189   return index_[r][theta]->size();
00190 }
00191 
00192 //-----------------------------------------------------------------------------
00193 //
00194 //: Method to index into bsol_hough_line_index index given a vsol_line_2d_sptr.
00195 //  The timestamp is not updated to facilitate lazy insertion of
00196 //  multiple items.
00197 bool bsol_hough_line_index::index(vsol_line_2d_sptr const& line)
00198 {
00199   if (!line)
00200   {
00201     vcl_cout << "In bsol_hough_line_index::index(..) NULL line\n";
00202     return false;
00203   }
00204   int r, theta;
00205   this->array_loc(line, r, theta);
00206   if (!(r < r_dim_)||!(theta < th_dim_))
00207     return false;
00208 
00209   index_[r][theta]->push_back(line);
00210   return true;
00211 }
00212 
00213 //-----------------------------------------------------------------------------
00214 //
00215 //: Method to index into bsol_hough_line_index index given a vsol_line_2d_sptr.
00216 //  Only new vsol_line_2d_sptr pointers are added to the bin.
00217 bool bsol_hough_line_index::index_new(vsol_line_2d_sptr const& line)
00218 {
00219   if (!line)
00220   {
00221     vcl_cout << "In bsol_hough_line_index::index_new(..) NULL line\n";
00222     return false;
00223   }
00224 
00225   int r, theta;
00226   //Check array bounds and uniqueness of line
00227   this->array_loc(line, r, theta);
00228   if (!(r < r_dim_)||!(theta < th_dim_))
00229     return false;
00230 
00231   vcl_vector<vsol_line_2d_sptr>* lines = index_[r][theta];
00232   if (!(vcl_find(lines->begin(), lines->end(), line) == lines->end()))
00233     return false;
00234 
00235   index_[r][theta]->push_back(line);
00236   return true;
00237 }
00238 
00239 //-----------------------------------------------------------------------------
00240 //
00241 //: find if a line is in the array
00242 bool bsol_hough_line_index::find(vsol_line_2d_sptr const& line)
00243 {
00244   int r, theta;
00245   this->array_loc(line, r, theta);
00246   vcl_vector<vsol_line_2d_sptr>* lines = index_[r][theta];
00247   return !(vcl_find(lines->begin(), lines->end(), line) == lines->end());
00248 }
00249 
00250 //-----------------------------------------------------------------------------
00251 //
00252 //: remove a line from the Hough index
00253 //  The timestamp is not updated to facilitate lazy insertion of
00254 //  multiple items.  See vsol_line_2d_sptrGroup as an example.
00255 bool bsol_hough_line_index::remove(vsol_line_2d_sptr const& line)
00256 {
00257   int r, theta;
00258   this->array_loc(line, r, theta);
00259   if (!(r < r_dim_)||!(theta < th_dim_))
00260     return false;
00261   vcl_vector<vsol_line_2d_sptr>* lines = index_[r][theta];
00262 
00263   vcl_vector<vsol_line_2d_sptr>::iterator lit =
00264     vcl_find(lines->begin(), lines->end(), line);
00265   if (lit == lines->end())
00266     return false;
00267   lines->erase(lit);
00268   return true;
00269 }
00270 
00271 //-----------------------------------------------------------------------------
00272 //
00273 //: Fill a vector of vsol_line_2d_sptr(s) which are at the index location
00274 //
00275 //-----------------------------------------------------------------------------
00276 void
00277 bsol_hough_line_index::lines_at_index(const int r, const int theta,
00278                                       vcl_vector<vsol_line_2d_sptr>& lines)
00279 {
00280   lines.clear();
00281   if ((theta<0)||(theta>=th_dim_)||(r<0)||(r>=r_dim_))
00282     return;
00283 
00284   int count = this->count(r, theta);
00285   if (count==0)
00286     return;
00287 
00288   for (int i = 0; i<count; i++)
00289     lines.push_back((*index_[r][theta])[i]);
00290 }
00291 
00292 //-----------------------------------------------------------------------------
00293 //
00294 //: Return a list of vsol_line_2d_sptr(s) which are at the index location
00295 //
00296 //-----------------------------------------------------------------------------
00297 vcl_vector<vsol_line_2d_sptr> bsol_hough_line_index::
00298 lines_at_index(const int r, const int theta)
00299 {
00300   vcl_vector<vsol_line_2d_sptr> out;
00301   this->lines_at_index(r, theta, out);
00302   return out;
00303 }
00304 
00305 //-----------------------------------------------------------------------------
00306 //
00307 //: Fill a list of vsol_line_2d_sptr(s) which are within a distance(radius) of the r,theta values of a given line.
00308 //
00309 //-----------------------------------------------------------------------------
00310 
00311 void bsol_hough_line_index::
00312 lines_in_interval(vsol_line_2d_sptr const & l,
00313                   const float r_dist,
00314                   const float theta_dist,
00315                   vcl_vector<vsol_line_2d_sptr>& lines)
00316 {
00317   lines.clear();
00318   if (!l)
00319   {
00320     vcl_cout << "In bsol_hough_line_index::lines_in_interval(..) NULL line\n";
00321     return;
00322   }
00323   int r, theta;
00324   this->array_loc(l, r, theta);
00325   int angle_radius = (int)vcl_ceil(theta_dist/angle_increment_);
00326   int r_radius = (int)vcl_ceil(r_dist);
00327   int th_dim_m1 = th_dim_ - 1;
00328 
00329   for (int i = -angle_radius; i<=angle_radius; i++)
00330   {
00331     //The angle space is circular
00332     int t_indx = (theta + i) % (th_dim_m1);
00333     if (t_indx<0)
00334       t_indx += th_dim_m1;
00335 
00336     for (int j = -r_radius; j<=r_radius; j++)
00337     {
00338       int r_indx = r + j;
00339       if ((r_indx<0)||(r_indx>=r_dim_))
00340         continue;
00341       vcl_vector<vsol_line_2d_sptr> temp;
00342       this->lines_at_index(r_indx, t_indx,temp);
00343       for (vcl_vector<vsol_line_2d_sptr>::iterator lit = temp.begin();
00344            lit != temp.end(); lit++)
00345       {
00346         //Note, these tests should eventually be more
00347         //sophisticated - JLM
00348         vsol_line_2d_sptr line = *lit;
00349         float l_angle, line_angle;
00350         float l_ndist, line_ndist;
00351         this->array_loc(l, l_ndist, l_angle);
00352         this->array_loc(line, line_ndist, line_angle);
00353 
00354         //Test error in normal distance
00355         bool within_r_radius = vcl_fabs(l_ndist - line_ndist) < r_dist;
00356         if (!within_r_radius)
00357           continue;
00358 
00359         //Test angular error
00360         bool within_angle_radius = vcl_fabs(l_angle - line_angle) < theta_dist;
00361         if (!within_angle_radius)
00362           continue;
00363 
00364         //line, passed both tests
00365         lines.push_back(line);
00366       }
00367     }
00368   }
00369 }
00370 
00371 //-----------------------------------------------------------------------------
00372 //
00373 //: Return a list of vsol_line_2d_sptr(s) which are within a distance(radius) of the r,theta values of a given line.
00374 //
00375 //-----------------------------------------------------------------------------
00376 
00377 vcl_vector<vsol_line_2d_sptr>
00378 bsol_hough_line_index::lines_in_interval(vsol_line_2d_sptr const & l,
00379                                          const float r_dist,
00380                                          const float theta_dist)
00381 {
00382   vcl_vector<vsol_line_2d_sptr> out;
00383   if (!l)
00384   {
00385     vcl_cout << "In bsol_hough_line_index::lines_in_interval(..) NULL line\n";
00386     return out;
00387   }
00388 
00389   this->lines_in_interval(l, r_dist, theta_dist, out);
00390   return out;
00391 }
00392 
00393 //-----------------------------------------------------------------------------
00394 //
00395 //: Fill a list of vsol_line_2d_sptr(s) which are within angle_dist of a given angle
00396 //
00397 //-----------------------------------------------------------------------------
00398 
00399 void
00400 bsol_hough_line_index::parallel_lines(const float angle,
00401                                       const float angle_dist,
00402                                       vcl_vector<vsol_line_2d_sptr>& lines)
00403 {
00404   lines.clear();
00405 
00406   //Compute angle index and tolerance
00407   float ang = vcl_fmod(angle,180.f);
00408   if (ang < 0) ang = 180.0f-ang;
00409 
00410   if (ang > angle_range_)
00411   {
00412     vcl_cout << "Warning - bsol_hough_line_index angle outside of range!\n";
00413     return;
00414   }
00415   int theta = (int)vcl_floor(ang/angle_increment_);
00416   int angle_radius = (int)vcl_ceil(angle_dist/angle_increment_);
00417   int th_dim_m1 = th_dim_ - 1;
00418 
00419   for (int i = -angle_radius; i<=angle_radius; i++)
00420   {
00421     //The angle space is circular
00422     int t_indx = (theta + i) % (th_dim_m1);
00423     if (t_indx<0)
00424       t_indx += th_dim_m1;
00425     for (int j = 0; j<r_dim_; j++)
00426     {
00427       if (!(this->count(j, t_indx)>0))
00428         continue;
00429       vcl_vector<vsol_line_2d_sptr> temp;
00430       this->lines_at_index(j, t_indx, temp);
00431 
00432       for (vcl_vector<vsol_line_2d_sptr>::iterator lit = temp.begin();
00433            lit != temp.end(); lit++)
00434       {
00435         vsol_line_2d_sptr line = *lit;
00436         //Test angular error
00437         float line_angle = (float)line->tangent_angle();
00438         if (line_angle >= 180.0f)
00439           line_angle -= 180.0f;
00440         float ang_error = vcl_fabs(ang - line_angle);
00441         if (ang_error<angle_dist)
00442           lines.push_back(line);
00443         ang_error-=180.0f;//anti-parallel lines are included
00444         if (vcl_fabs(ang_error)<angle_dist)
00445           lines.push_back(line);
00446       }
00447     }
00448   }
00449 }
00450 
00451 //-----------------------------------------------------------------------------
00452 //
00453 //: Return a list of vsol_line_2d_sptr(s) which are within angle_dist of a given angle
00454 //
00455 //-----------------------------------------------------------------------------
00456 
00457 vcl_vector<vsol_line_2d_sptr >
00458 bsol_hough_line_index::parallel_lines(const float angle,
00459                                       const float angle_dist)
00460 {
00461   vcl_vector<vsol_line_2d_sptr> out;
00462   this->parallel_lines(angle, angle_dist, out);
00463   return out;
00464 }
00465 
00466 //-----------------------------------------------------------------------------
00467 //
00468 //: Fill a list of vsol_line_2d_sptr(s) which are oriented at an angle with respect to a given line.
00469 //  A specified angular tolerance can be given.
00470 //
00471 //-----------------------------------------------------------------------------
00472 
00473 void
00474 bsol_hough_line_index::lines_at_angle(vsol_line_2d_sptr const &l,
00475                                       const float angle,
00476                                       const float angle_dist,
00477                                       vcl_vector<vsol_line_2d_sptr >& lines)
00478 {
00479   lines.clear();
00480   if (!l)
00481   {
00482     vcl_cout << "In bsol_hough_line_index::lines_at_angle(..) NULL line\n";
00483     return;
00484   }
00485   float ang = (float)l->tangent_angle() + angle;
00486   this->parallel_lines(ang, angle_dist, lines);
00487 }
00488 
00489 //-----------------------------------------------------------------------------
00490 //
00491 //: Return a new list of vsol_line_2d_sptr(s) which are oriented at an angle with respect to a given line.
00492 //  A specified angular tolerance can be given.
00493 //-----------------------------------------------------------------------------
00494 
00495 vcl_vector<vsol_line_2d_sptr>
00496 bsol_hough_line_index::lines_at_angle(vsol_line_2d_sptr const &l,
00497                                       const float angle,
00498                                       const float angle_dist)
00499 {
00500   vcl_vector<vsol_line_2d_sptr> out;
00501   this->lines_at_angle(l, angle, angle_dist, out);
00502   return out;
00503 }
00504 
00505 //-----------------------------------------------------------------------------
00506 //
00507 //: Fill a list of vsol_line_2d_sptr(s) which are within angle_dist of the orientation of a given line.
00508 //
00509 //-----------------------------------------------------------------------------
00510 
00511 void
00512 bsol_hough_line_index::parallel_lines(vsol_line_2d_sptr const &l,
00513                                       const float angle_dist,
00514                                       vcl_vector<vsol_line_2d_sptr>& lines)
00515 {
00516   lines.clear();
00517   if (!l)
00518   {
00519     vcl_cout << "In bsol_hough_line_index::parallel_lines(..) NULL line\n";
00520     return;
00521   }
00522   float angle = (float)l->tangent_angle();
00523   this->parallel_lines(angle, angle_dist, lines);
00524 }
00525 
00526 //-----------------------------------------------------------------------------
00527 //
00528 //: Return a list of vsol_line_2d_sptr(s) which are within angle_dist of the orientation of a given line.
00529 //
00530 //-----------------------------------------------------------------------------
00531 
00532 vcl_vector<vsol_line_2d_sptr>
00533 bsol_hough_line_index::parallel_lines(vsol_line_2d_sptr const &l,
00534                                       const float angle_dist)
00535 {
00536   vcl_vector<vsol_line_2d_sptr> out;
00537   if (!l)
00538   {
00539     vcl_cout << "In bsol_hough_line_index::parallel_lines(..) NULL line\n";
00540     return out;
00541   }
00542   this->parallel_lines(l, angle_dist, out);
00543   return out;
00544 }
00545 
00546 //-----------------------------------------------------------------------------
00547 //
00548 //: Clear the bsol_hough_line_index index space
00549 //
00550 //-----------------------------------------------------------------------------
00551 void bsol_hough_line_index::clear_index()
00552 {
00553   for (int r=0;r<r_dim_;r++)
00554     for (int th=0;th<th_dim_;th++)
00555       index_[r][th]->clear();
00556 }
00557 
00558 //-----------------------------------------------------------------
00559 //: Constructor Utility
00560 //
00561 
00562 void bsol_hough_line_index::init(const int r_dimension,
00563                                  const int theta_dimension)
00564 {
00565   r_dim_ = r_dimension;
00566   th_dim_ = theta_dimension;
00567   index_.resize(r_dim_, th_dim_);
00568   for (int r=0;r<r_dim_;r++)
00569     for (int th=0;th<th_dim_;th++)
00570       index_.put(r,th, new vcl_vector<vsol_line_2d_sptr>);
00571 }
00572 
00573 //-----------------------------------------------------------------
00574 //: Fill the angle histogram
00575 //
00576 vcl_vector<int> bsol_hough_line_index::angle_histogram()
00577 {
00578   vcl_vector<int> angle_hist(th_dim_);
00579   for (int x = 0; x<th_dim_; x++)
00580   {
00581     angle_hist[x]=0;
00582     for (int y = 0; y<r_dim_; y++)
00583     {
00584       vcl_vector<vsol_line_2d_sptr>* lines = index_[y][x];
00585       if (lines)
00586         angle_hist[x]+=lines->size();
00587     }
00588   }
00589   return angle_hist;
00590 }
00591 
00592 //-------------------------------------------------------------------
00593 //:
00594 // Provides the correct values for angle histogram counts when the bin index
00595 // extends outside the valid range of the counts array.  This function
00596 // permits easy access logic for the non_maximum_suppression algorithm.
00597 static int get_extended_count(int bin, vcl_vector<int> const& ang_hist)
00598 {
00599   int n_bins = ang_hist.size();
00600   int nbm = n_bins-1;
00601   //Abnormal Cases
00602   if (bin<0)
00603     return ang_hist[nbm+bin];
00604 
00605   if (bin >= n_bins)
00606     return ang_hist[bin-n_bins];
00607   //Normal Case
00608   return ang_hist[bin];
00609 }
00610 
00611 //---------------------------------------------------------------------
00612 //: Prune any sequences of more than one maximum value.
00613 // That is, it is possible to have a "flat" top peak with an arbitrarily
00614 // long sequence of equal, but maximum values.
00615 static void remove_flat_peaks(vcl_vector<int>& angle_hist)
00616 {
00617   int nbins = angle_hist.size();
00618   int nbm = nbins-1;
00619 
00620   //Here we define a small state machine - parsing for runs of peaks
00621   //init is the state corresponding to an initial run (starting at i ==0)
00622   bool init= get_extended_count(0, angle_hist)>0;
00623   int init_end =0;
00624 
00625   //start is the state corresponding to any other run of peaks
00626   bool start=false;
00627   int start_index=0;
00628 
00629   //The scan of the state machine
00630   for (int i = 0; i < nbins; i++)
00631   {
00632     int v = get_extended_count(i, angle_hist);
00633 
00634     //State init: a string of non-zeroes at the beginning.
00635     if (init && v!=0)
00636       continue;
00637 
00638     if (init && v==0)
00639     {
00640       init_end = i;
00641       init = false;
00642       continue;
00643     }
00644 
00645     //State !init&&!start: a string of "0s"
00646     if (!start && v==0)
00647       continue;
00648 
00649     //State !init&&start: the first non-zero value
00650     if (!start && v!=0)
00651     {
00652       start_index = i;
00653       start = true;
00654       continue;
00655     }
00656     //State ending flat peak: encountered a subsequent zero after starting
00657     if (start && v==0)
00658     {
00659       int peak_location = (start_index+i-1)/2;//The middle of the run
00660       for (int k = start_index; k<=(i-1); k++)
00661         if (k!=peak_location)
00662           angle_hist[k] = 0;
00663       start = false;
00664     }
00665   }
00666   //Now handle the boundary conditions
00667   if (init_end!=0) { //Is there a run which crosses the cyclic cut?
00668     if (start)
00669     {    //Yes, so define the peak location accordingly
00670       int peak_location = (start_index + init_end - nbm -1)/2;
00671       int k;
00672       if (peak_location < 0) //Is the peak to the left of the cut?
00673       {   // Yes, to the left
00674         peak_location += nbm;
00675         for ( k = 0; k< init_end; k++)
00676           angle_hist[k]=0;
00677         for ( k= start_index; k <nbins; k++)
00678           if (k!=peak_location)
00679             angle_hist[k] = 0;
00680       }
00681       else
00682       {   //No, on the right.
00683         for ( k = start_index; k< nbins; k++)
00684           angle_hist[k]=0;
00685         for ( k= 0; k < init_end; k++)
00686           if (k!=peak_location)
00687             angle_hist[k] = 0;
00688       }
00689     }
00690     else
00691     {   //There wasn't a final run so just clean up the initial run
00692       int init_location = (init_end-1)/2;
00693       for (int k = 0; k<=init_end; k++)
00694         if (k!=init_location)
00695           angle_hist[k] = 0;
00696     }
00697   }
00698 }
00699 
00700 //----------------------------------------------------------
00701 //: Suppress values in the angle histogram which are not locally a maximum.
00702 //  The neighborhood for computing the local maximum
00703 //  is [radius X radius], e.g. for radius =1 the neighborhood
00704 //  is [-X-], for radius = 2, the neighborhood is [--X--], etc.
00705 //
00706 vcl_vector<int>
00707 bsol_hough_line_index::non_maximum_suppress(const int radius,
00708                                             vcl_vector<int> const& bins)
00709 {
00710   int num = bins.size();
00711   vcl_vector<int> out(num);
00712   if (4*radius +2 > num)
00713   {
00714     vcl_cout << "bsol_hough_line_index::non_maximum_suppress(..) - radius is too large\n";
00715     return out;
00716   }
00717 
00718   //Clear the output
00719   for (int indx =0; indx < num; indx++)
00720     out[indx] = 0;
00721 
00722   //Find local maxima
00723   for (int indx = 0; indx<num; indx++)
00724   {
00725     //find the maximum value in the current kernel
00726     int max_count = bins[indx];
00727     for (int k = -radius; k <= radius ;k++)
00728     {
00729       int index = indx+k;
00730       int c = get_extended_count(index, bins);
00731       if ( c > max_count)
00732         max_count = c;
00733     }
00734     //Is position th a local maximum?
00735     if (max_count == bins[indx])
00736       out[indx] = max_count;//Yes. So set the counts to the max value
00737   }
00738   remove_flat_peaks(out);
00739   return out;
00740 }
00741 
00742 //-----------------------------------------------------------------
00743 //: Find the dominant peaks in the direction histogram.
00744 //  The output vector contains the theta indices of dominant direction peaks.
00745 //  \param thresh is the minimum number of lines in a valid peak.
00746 //  \param angle tol is the width of the peak in degrees.
00747 int bsol_hough_line_index::
00748 dominant_directions(const int thresh, const float angle_tol,
00749                     vcl_vector<int>& dirs)
00750 {
00751   int radius = int(0.5f+angle_tol/angle_increment_); // round to nearest int
00752   vcl_vector<int> angle_hist = this->angle_histogram();
00753   vcl_vector<int> suppressed_hist =
00754     this->non_maximum_suppress(radius, angle_hist);
00755   for (int i = 0; i<th_dim_; i++)
00756     if (suppressed_hist[i]>=thresh)
00757       dirs.push_back(i);
00758   return dirs.size();
00759 }
00760 
00761 //------------------------------------------------------------------
00762 //: Get the dominant line groups in the hough index.
00763 //  Sets of lines belonging to distinct orientations are returned.
00764 //
00765 int bsol_hough_line_index::
00766 dominant_line_groups(const int thresh, const float angle_tol,
00767                      vcl_vector<vcl_vector<vsol_line_2d_sptr> >& groups)
00768 {
00769   groups.clear();
00770   vcl_vector<int> dirs;
00771   int n_groups = this->dominant_directions(thresh, angle_tol, dirs);
00772   if (!n_groups)
00773     return 0;
00774   for (int gi = 0; gi<n_groups; gi++)
00775   {
00776     vcl_vector<vsol_line_2d_sptr> lines;
00777     float angle = dirs[gi]*angle_increment_;
00778     this->parallel_lines(angle, angle_tol, lines);
00779     groups.push_back(lines);
00780   }
00781   vcl_sort(groups.begin(), groups.end(), nlines());
00782   return n_groups;
00783 }
00784 
00785 //-----------------------------------------------------------------
00786 //: An image of the hough index, useful for debugging applications that use this class
00787 vbl_array_2d<unsigned char> bsol_hough_line_index::get_hough_image()
00788 {
00789   vbl_array_2d<unsigned char> out(r_dim_, th_dim_);
00790   int nmax = 0;
00791   for (int r=0;r<r_dim_;r++)
00792     for (int th=0;th<th_dim_;th++)
00793     {
00794       int n_lines = index_[r][th]->size();
00795       if (n_lines>nmax)
00796         nmax = n_lines;
00797     }
00798   float scale = 1;
00799   if (nmax != 0)
00800     scale /= 1.0f/nmax;
00801   for (int r=0;r<r_dim_;r++)
00802     for (int th=0;th<th_dim_;th++)
00803     {
00804       unsigned char val;
00805       int n_lines = index_[r][th]->size();
00806       float v = 255*n_lines/scale;
00807       val = (unsigned char)v;
00808       out.put(r,th,val);
00809     }
00810   return out;
00811 }