contrib/gel/gevd/gevd_edgel_regions.cxx
Go to the documentation of this file.
00001 // This is gel/gevd/gevd_edgel_regions.cxx
00002 #include "gevd_edgel_regions.h"
00003 //:
00004 // \file
00005 
00006 #include <vcl_iostream.h>
00007 #include <vcl_cstdlib.h> // for vcl_abs(int)
00008 #include <vcl_cassert.h>
00009 #include <vcl_algorithm.h> // for vcl_sort() and vcl_find()
00010 
00011 #include <vtol/vtol_intensity_face.h>
00012 
00013 #include <vxl_config.h>
00014 #include <vil1/vil1_memory_image_of.h>
00015 #include <vcl_cmath.h>     // for sqrt()
00016 #include <vul/vul_timer.h>
00017 
00018 #include <vsol/vsol_box_2d.h>
00019 #include <vsol/vsol_box_2d_sptr.h>
00020 #include <vtol/vtol_edge.h>
00021 #include <vtol/vtol_edge_2d.h>
00022 #include <vtol/vtol_one_chain.h>
00023 #include <vtol/vtol_cycle_processor.h>
00024 
00025 #include <vdgl/vdgl_digital_curve.h>
00026 #include <vdgl/vdgl_edgel_chain.h>
00027 #include <vdgl/vdgl_interpolator.h>
00028 
00029 
00030 #define bytePixel(buf,x,y)   (*((unsigned char*)buf->GetElementAddr(x,y)))
00031 #define shortPixel(buf,x,y)  (*((short*)buf->GetElementAddr(x,y)))
00032 
00033 #if 0 // not ported to vxl
00034 //----------------------------------------------------------------
00035 //: cache debug info
00036 void edgel_regions::cache_bad_edges(CoolArrayP<Edge*>& bad_edges)
00037 {
00038   vcl_vector<Edge*> corrupt_edges;
00039   for (CoolArrayP<Edge*>::iterator eit = bad_edges.begin();
00040        eit != bad_edges.end(); eit++)
00041     corrupt_edges.push_back(*eit);
00042   corrupt_edges_.push_back(corrupt_edges);
00043 }
00044 
00045 void edgel_regions::cache_bad_edges(vcl_vector<Edge*>& bad_edges)
00046 {
00047   vcl_vector<Edge*> corrupt_edges;
00048   for (vcl_vector<Edge*>::iterator eit = bad_edges.begin();
00049        eit != bad_edges.end(); eit++)
00050     corrupt_edges.push_back(*eit);
00051   corrupt_edges_.push_back(corrupt_edges);
00052 }
00053 
00054 void edgel_regions::cache_bad_verts(CoolArrayP<Vertex*>& bad_verts)
00055 {
00056   vcl_vector<Vertex*> corrupt_verts;
00057   for (CoolArrayP<Vertex*>::iterator vit = bad_verts.begin();
00058        vit != bad_verts.end(); vit++)
00059     corrupt_verts.push_back(*vit);
00060   corrupt_vertices_.push_back(corrupt_verts);
00061 }
00062 #endif
00063 
00064 //--------------------------------------------------------
00065 //: compare function to be used with CoolList<float>::sort() [increasing]
00066 static int increasing_compare(unsigned int const&a, unsigned int const&b)
00067 {
00068   if (a > b) return 1;
00069   if (a < b) return -1;
00070   return 0;
00071 }
00072 
00073 // Print the region label array
00074 void gevd_edgel_regions::print_region_array()
00075 {
00076   vcl_cout << vcl_endl;
00077   for (unsigned int y = yo_; y<=yend_; y++)
00078   {
00079     vcl_cout << vcl_endl; // << setw(2);
00080     for (unsigned int x = xo_; x<=xend_; x++)
00081       if (region_label_array_[Y(y)][X(x)]==EDGE)
00082           //&&edge_boundary_array_[Y(y)][X(x)]->IsVertex()
00083         vcl_cout << "* ";
00084       else
00085         vcl_cout << region_label_array_[Y(y)][X(x)] << ' ';
00086   }
00087   vcl_cout << "\n\n\n";
00088 }
00089 
00090 // Print the contents of the forward equivalence index
00091 void gevd_edgel_regions::print_region_equivalence()
00092 {
00093   vcl_cout << vcl_endl << "Label Equivalence:\n"
00094            << "----------------\n";
00095   vcl_map<unsigned int, vcl_vector<unsigned int>*>::iterator rpf_iterator;
00096   for (rpf_iterator= region_pairs_forward_.begin();
00097        rpf_iterator!=region_pairs_forward_.end(); rpf_iterator++)
00098   {
00099     vcl_cout << (*rpf_iterator).first << " == "
00100              << (*rpf_iterator).second << vcl_endl;
00101   }
00102   vcl_cout << vcl_endl;
00103 }
00104 
00105 // Print the contents of the reverse equivalence index
00106 void gevd_edgel_regions::print_reverse_region_equivalence()
00107 {
00108   vcl_cout << vcl_endl << "Reverse Label Equivalence:\n"
00109            << "----------------\n";
00110   vcl_map<unsigned int, vcl_vector<unsigned int>*>::iterator rpf_iterator;
00111   for (rpf_iterator= region_pairs_reverse_.begin();
00112        rpf_iterator!=region_pairs_reverse_.end(); rpf_iterator++)
00113   {
00114     vcl_cout << (*rpf_iterator).first << " == "
00115              << (*rpf_iterator).second << vcl_endl;
00116   }
00117   vcl_cout << vcl_endl;
00118 }
00119 
00120 // Print the reduced equivalence relation
00121 void gevd_edgel_regions::print_base_equivalence()
00122 {
00123   vcl_cout << vcl_endl << "Base Label Equivalence:\n"
00124            << "----------------\n";
00125 
00126   for (unsigned int i = min_region_label_; i<max_region_label_; i++)
00127     vcl_cout << i << " == " << this->BaseLabel(i) << vcl_endl;
00128 }
00129 
00130 // Print the fitted intensity data for all faces
00131 void gevd_edgel_regions::print_intensity_data()
00132 {
00133   for (vcl_vector<vtol_intensity_face_sptr>::iterator fit =faces_->begin();
00134        fit != faces_->end(); fit++)
00135   {
00136 #if 0
00137     vtol_intensity_face* f = *fit;
00138     vcl_cout << "IntFaceAt(" << f->Xo() << ' ' << f->Yo() << "):\n";
00139     f->PrintFit();
00140 #endif
00141   }
00142 }
00143 
00144 //--------------------------------------------------------------
00145 //: The region array can be offset from the corner of the ROI.
00146 //    The following two methods transform from the ROI coordinate
00147 //    system to the region label array coordinate system
00148 unsigned int gevd_edgel_regions::X(unsigned int x)
00149 {
00150   return x-xo_;
00151 }
00152 
00153 unsigned int gevd_edgel_regions::Y(unsigned int y)
00154 {
00155   return y-yo_;
00156 }
00157 
00158 //---------------------------------------------------------
00159 //: Casts the float x location of a point to an unsigned-int location
00160 unsigned int gevd_edgel_regions::Xf(float x)
00161 {
00162   unsigned int xu = ((unsigned int)(x));
00163   return xu;
00164 }
00165 
00166 //---------------------------------------------------------
00167 //: Casts the float x location of a point to an unsigned-int location
00168 unsigned int gevd_edgel_regions::Yf(float y)
00169 {
00170   unsigned int yu = ((unsigned int)(y));
00171   return yu;
00172 }
00173 
00174 //----------------------------------------------------------
00175 //: Default constructor
00176 gevd_edgel_regions::gevd_edgel_regions(bool debug)
00177 {
00178   verbose_ = false;
00179   debug_ = debug;
00180 #if 0
00181   if (debug_)
00182     debug_data_ = new topo_debug_data;
00183   else
00184     debug_data_ = 0;
00185 #endif
00186     image_ = NULL;
00187   image_source_ = false;
00188   buf_source_ = false;
00189   buf_ = NULL;
00190   edge_boundary_array_ = NULL;
00191   region_label_array_ = NULL;
00192   xo_=0;
00193   yo_=0;
00194   xend_ = 0;
00195   yend_ = 0;
00196   min_region_label_ = LABEL;
00197   max_region_label_ = LABEL;
00198   faces_ = new vcl_vector<vtol_intensity_face_sptr>;
00199   face_edge_index_ = NULL;
00200   intensity_face_index_ = NULL;
00201   failed_insertions_ = new vcl_vector<vtol_edge_2d_sptr>;
00202   ubuf_ = NULL;
00203   sbuf_ = NULL;
00204 }
00205 
00206 //----------------------------------------------------------
00207 //: Default destructor
00208 gevd_edgel_regions::~gevd_edgel_regions()
00209 {
00210   if (image_) {
00211     image_ = NULL;
00212   }
00213 
00214   unsigned int y;
00215   if (region_label_array_)
00216     for (y=yo_; y<=yend_; y++)
00217       delete [] region_label_array_[Y(y)];
00218   delete [] region_label_array_;
00219 
00220 #if 0
00221   for (region_pairs_reverse_.reset(); region_pairs_reverse_.next();)
00222     delete region_pairs_reverse_.value();
00223 
00224   for (region_pairs_forward_.reset(); region_pairs_forward_.next();)
00225     delete region_pairs_forward_.value();
00226   for (equivalence_set_.reset(); equivalence_set_.next();)
00227     delete equivalence_set_.value();
00228 
00229   for (region_edges_.reset(); region_edges_.next();)
00230   {
00231     region_edges_.value()->UnProtect();
00232   }
00233 
00234    if (edge_boundary_array_)
00235      for (y = yo_; y<=yend_; y++)
00236      {
00237        for (x = xo_; x<=xend_; x++)
00238          if (edge_boundary_array_[Y(y)][X(x)])
00239            edge_boundary_array_[Y(y)][X(x)]->UnProtect();
00240        delete [] edge_boundary_array_[Y(y)];
00241      }
00242    delete [] edge_boundary_array_;
00243 
00244   for (region_edge_adjacency_.reset(); region_edge_adjacency_.next();)
00245     delete region_edge_adjacency_.value();
00246 
00247   for (faces_->reset(); faces_->next();)
00248     faces_->value()->UnProtect();
00249   delete faces_;
00250 
00251   if (intensity_face_index_)
00252   {
00253     for (unsigned int i = 0; i<max_region_label_; i++)
00254       if (intensity_face_index_[i])
00255         intensity_face_index_[i]= NULL;
00256     delete [] intensity_face_index_;
00257   }
00258 #endif
00259 
00260   if (face_edge_index_)
00261   {
00262     for (unsigned int i = 0; i<max_region_label_; i++)
00263       delete face_edge_index_[i];
00264     delete [] face_edge_index_;
00265   }
00266   delete failed_insertions_;
00267   delete [] ubuf_;
00268   delete [] sbuf_;
00269 }
00270 
00271 bool gevd_edgel_regions::compute_edgel_regions(gevd_bufferxy* buf,
00272                                                vcl_vector<vtol_edge_2d_sptr>& sgrp,
00273                                                vcl_vector<vtol_intensity_face_sptr>& faces)
00274 {
00275   buf_ = buf;
00276   image_= NULL;
00277   buf_source_=true;
00278   image_source_=false;
00279   return compute_edgel_regions(sgrp, faces);
00280 }
00281 
00282 //-----------------------------------------------------------------
00283 //: The key process loop.
00284 //  Carries out the steps:
00285 //   1) Connected components 2)Edge-label assignment 3)Collect region
00286 //   boundaries 4) Construct vtol_intensity_faces 5)Calculate intensity fit
00287 bool
00288 gevd_edgel_regions::compute_edgel_regions(vil1_image* image,
00289                                           vcl_vector<vtol_edge_2d_sptr>& sgrp,
00290                                           vcl_vector<vtol_intensity_face_sptr>& faces)
00291 {
00292   image_ = image;
00293   buf_ = NULL;
00294   image_source_=true;
00295   buf_source_ = false;
00296   return compute_edgel_regions(sgrp, faces);
00297 }
00298 
00299 bool gevd_edgel_regions::compute_edgel_regions(vcl_vector<vtol_edge_2d_sptr>& sgrp,
00300                                                vcl_vector<vtol_intensity_face_sptr>& faces)
00301 {
00302 //    corrupt_edges_.clear();
00303 //    corrupt_vertices_.clear();
00304 #if 0
00305   if (debug_data_)
00306   {
00307     debug_data_->clear();
00308     if (buf_source_)
00309       debug_data_->set_buf(buf_);
00310   }
00311 #endif
00312   vul_timer t;
00313   if (!sgrp.size())
00314     return false;
00315 
00316   // Set up the region label array with edge boundaries
00317   this->InitRegionArray(sgrp);
00318   if (verbose_)
00319     this->print_region_array();
00320   // Propagate connected components
00321   unsigned int y, x;
00322   for (y=yo_; y<yend_; y++)
00323     for (x=xo_; x<xend_; x++)
00324       this->UpdateConnectedNeighborhood(X(x), Y(y));
00325   if (verbose_)
00326     this->print_region_array();
00327   // Resolve region label equivalence
00328   this->GrowEquivalenceClasses();
00329   this->PropagateEquivalence();
00330   if (verbose_)
00331     this->print_base_equivalence();
00332   this->ApplyRegionEquivalence();
00333   if (verbose_)
00334     this->print_region_array();
00335 
00336   // Associate Edge(s) with region labels
00337   for (y=yo_; y<yend_; y++)
00338     for (x=xo_; x<xend_; x++)
00339       this->AssignEdgeLabels(X(x), Y(y));
00340 
00341   // Collect Edge(s) bounding each region
00342   this->CollectEdges();
00343   vcl_cout << "Propagate Regions and Collect Edges("
00344            << max_region_label_-min_region_label_ << ") in "
00345            << t.real() << " msecs.\n";
00346 
00347   // Collect Face-Edge associations
00348   this->CollectFaceEdges();
00349 
00350   // Construct vtol_intensity_faces
00351   this->ConstructFaces();
00352   if (!faces_||!faces_->size())
00353     return false;
00354 
00355   // Collect intensity data for each region
00356   this->InsertFaceData();
00357 
00358   if (verbose_)
00359     this->print_intensity_data();
00360   // Output the result
00361   faces.clear();
00362   for (vcl_vector<vtol_intensity_face_sptr>::iterator fit = faces_->begin();
00363        fit != faces_->end(); fit++)
00364   {
00365     faces.push_back(*fit);
00366 #if 0 // This caused a big memory leak
00367     faces_->value()->Protect();
00368 #endif // 0
00369   }
00370   vcl_cout << "Compute Edgel Regions Total(" << sgrp.size() << ") in "
00371            << t.real() << " msecs.\n";
00372   return true;
00373 }
00374 
00375 
00376 //----------------------------------------------------------
00377 //: assign equivalence of region label b to region label a
00378 //
00379 bool gevd_edgel_regions::InsertRegionEquivalence(unsigned int label_b,
00380                                                  unsigned int label_a)
00381 {
00382   bool result = true;
00383   result = result && this->add_to_forward(label_b, label_a);
00384   result = result && this->add_to_reverse(label_a, label_b);
00385   return result;
00386 }
00387 
00388 //--------------------------------------------------------------
00389 //: Get the most basic label equivalent to a given label.
00390 //    If the label_map_ is not defined, this function uses the
00391 //    forward label hash table.  Otherwise 0 is returned.
00392 unsigned int gevd_edgel_regions::BaseLabel(unsigned int label)
00393 {
00394   vcl_map<unsigned int, unsigned int >::iterator lmtest;
00395   lmtest = label_map_.find(label);
00396   if ( lmtest != label_map_.end() )
00397     return lmtest->second;
00398   else
00399     return 0;
00400 }
00401 
00402 //------------------------------------------------------------
00403 //:
00404 //  Paint the edgels into the region label array and then
00405 //    output an image where the value is 255 if the pixel is an
00406 //    edge, 0 otherwise
00407 vil1_image* gevd_edgel_regions::GetEdgeImage(vcl_vector<vtol_edge_2d_sptr>& sg)
00408 {
00409   if (!this->InitRegionArray(sg)) return NULL;
00410   int sizex = this->GetXSize(), sizey = this->GetYSize();
00411   unsigned char no_edge = 0, edge = 255;
00412 #if 0
00413   ImageTemplate temp(sizex, sizey, 8, 32, 32);
00414   MemoryImage* image = new MemoryImage(&temp);
00415   for (int y = 0; y<sizey; y++)
00416     for (int x = 0; x<sizex; x++)
00417       if (region_label_array_[y][x] == EDGE)
00418         image->PutPixel(&edge, x, y);
00419       else
00420         image->PutPixel(&no_edge, x, y);
00421 #endif
00422   vil1_memory_image_of<vxl_byte> * image = new vil1_memory_image_of<vxl_byte>(sizex,sizey);
00423 
00424   for (int y = 0; y<sizey; y++)
00425     for (int x = 0; x<sizex; x++)
00426       if (region_label_array_[y][x] == EDGE)
00427         (*image)[y][x] = edge;
00428       else
00429         (*image)[y][x] = no_edge;
00430   return image;
00431 }
00432 
00433 //-----------------------------------------------------------
00434 //: Populate the label_map_ to reflect the equivalences between labels.
00435 //
00436 void gevd_edgel_regions::PropagateEquivalence()
00437 {
00438   vcl_map<unsigned int, vcl_vector<unsigned int>* >::iterator  esi;
00439 
00440   for (esi = equivalence_set_.begin(); esi != equivalence_set_.end(); esi++)
00441   {
00442     unsigned int base = esi->first;
00443     vcl_vector<unsigned int>* labels = esi->second;
00444     if (!labels) continue;
00445     int len = labels->size();
00446     if (!len) continue;
00447     for (int i = 0; i<len; i++)
00448       label_map_[(*labels)[i]] = base;
00449   }
00450   for (unsigned int i = min_region_label_; i<max_region_label_; i++)
00451     if (label_map_.find(i) == label_map_.end())
00452       label_map_[i] = i;
00453 }
00454 
00455 //---------------------------------------------------------------------
00456 //:
00457 //  Find the set of labels equivalent to label from a given hash table
00458 //    and merge into the appropriate equivalence set. cur_label is the
00459 //    equivalence set being formed. label is the table key of equivalences
00460 //    to be merged.
00461 bool gevd_edgel_regions::
00462 merge_equivalence(vcl_map<unsigned int, vcl_vector<unsigned int>* >& tab,
00463                   unsigned int cur_label,
00464                   unsigned int label)
00465 {
00466   vcl_map<unsigned int, vcl_vector<unsigned int>* >::iterator hashi;
00467 
00468   hashi = tab.find(label);
00469   if (hashi == tab.end()) {
00470   return false;
00471   }
00472   vcl_vector<unsigned int>* labels = hashi->second;
00473 
00474   int len = labels->size();
00475   if (!len) {
00476     return false;
00477   }
00478   vcl_vector<unsigned int>* array;
00479 
00480   hashi = equivalence_set_.find(cur_label);
00481   if ( hashi == equivalence_set_.end())
00482   {
00483     array = new vcl_vector<unsigned int>;
00484     equivalence_set_[cur_label] = array;
00485   }
00486   else
00487   {
00488     array = hashi->second;
00489   }
00490   for (int i = 0; i<len; i++)
00491   {
00492     unsigned int l = (*labels)[i];
00493     bool found = false;
00494     for (unsigned int j=0 ; j < array->size() ; j++)
00495     {
00496       if ((*array)[j] == l) found = true;
00497     }
00498     if (!found)
00499     {
00500       array->push_back(l);
00501     }
00502   }
00503 
00504   return true;
00505 }
00506 
00507 //----------------------------------------------------------------
00508 //: Find the next label not accounted for in the current equivalence set.
00509 //    The set of labels is searched to find a label larger than label, but
00510 //    not in the set, labels.
00511 bool gevd_edgel_regions::get_next_label(vcl_vector<unsigned int>* labels,
00512                                         unsigned int& label)
00513 {
00514   unsigned int tmp = label+1;
00515   if (!labels)
00516     if (tmp<max_region_label_)
00517     {
00518       label = tmp;
00519       return true;
00520     }
00521   for (unsigned int i = tmp; i<max_region_label_; i++)
00522   {
00523     bool found = false;
00524     for ( unsigned int j = 0 ; j < labels->size() ; j++ )
00525     {
00526       if ((*labels)[j] == i)
00527       {
00528         found = true;
00529       }
00530     }
00531     if (!found)
00532     {
00533       label = i;
00534       return true;
00535     }
00536   }
00537   return false;
00538 }
00539 
00540 //----------------------------------------------------------------
00541 //: Form equivalence classes by transitive closure on each label.
00542 //    The idea is to add labels to the set, cur_set, by equivalence until no
00543 //    new equivalence groups can be found.  The current equivalence class,
00544 //    cur_set is repeatedly scanned when new labels are added to pick up
00545 //    new equivalence groups.  Old equivalence table entries are removed
00546 //    as they are used.  When the equivalence class corresponding to cur_lable
00547 //    is completely closed, then a new label not in a previously formed
00548 //    equivalence class is used to seed a new equivalence class.
00549 void gevd_edgel_regions::GrowEquivalenceClasses()
00550 {
00551   if ((max_region_label_-min_region_label_) < 2)
00552     return;
00553   unsigned int cur_label = min_region_label_;
00554   vcl_map<unsigned int, vcl_vector<unsigned int>* >::iterator mei;
00555   while (true)
00556   {
00557     bool merging = true;
00558     vcl_vector<unsigned int>* cur_set = NULL;
00559     unsigned int i = cur_label;
00560     int len = 0;
00561     while (merging)
00562     {
00563       int old_len = len;
00564       merging = false;
00565       bool find_forward =
00566         this->merge_equivalence(region_pairs_forward_, cur_label, i);
00567       if (find_forward)
00568         region_pairs_forward_.erase(i);
00569       bool find_reverse =
00570         this->merge_equivalence(region_pairs_reverse_, cur_label, i);
00571       if (find_reverse)
00572         region_pairs_reverse_.erase(i);
00573       mei = equivalence_set_.find(cur_label);
00574       if (mei == equivalence_set_.end()) continue;
00575       cur_set = equivalence_set_[cur_label];
00576       if (!cur_set) continue;
00577       len = cur_set->size();
00578       if (!len) continue;
00579       if (len > old_len)
00580       {
00581         i = cur_label;
00582         vcl_sort(cur_set->begin(), cur_set->end(), &increasing_compare);
00583 #if 0
00584         cur_set->sort(increasing_compare);
00585         //-tpk- need to convert
00586 #endif
00587       }
00588 
00589       for (int j = 0; j<len&&!merging; j++)
00590         if ((*cur_set)[j]>i)
00591         {
00592           i = (*cur_set)[j];
00593           merging = true;
00594         }
00595     }
00596     if (!get_next_label(cur_set, cur_label)) return;
00597   }
00598 }
00599 
00600 //------------------------------------------------------------
00601 //: Check if the SpatialGroup contains Edge(s)
00602 //
00603 bool gevd_edgel_regions::GroupContainsEdges(vcl_vector<vtol_edge_2d_sptr>& /*sg*/)
00604 {
00605   vcl_cerr << "gevd_edgel_regions::GroupContainsEdges() not yet implemented\n";
00606 #if 0
00607   vcl_string type(sg.GetSpatialGroupName());
00608   return type == vcl_string("EdgelGroup") ||
00609          type == vcl_string("FittedEdgeGroup");
00610 #endif
00611   return true; // TODO
00612 }
00613 
00614 //: Advance along a line and generate contiguous pixels on the line.
00615 //  This function assures that the spatial digitization of the Edge(s)
00616 //  produces completely connected boundaries.
00617 static bool line_gen(float xs, float ys, float xe, float ye,
00618                      unsigned int& x, unsigned int& y)
00619 {
00620   assert(xs > 0.0f); assert(ys > 0.0f);
00621   const float pix_edge = 1.0f; // We are working at scale = 1.0
00622   static float xi, yi;
00623   static bool init = true;
00624   static bool done = false;
00625   if (init)
00626   {
00627     xi = xs;
00628     yi = ys;
00629     x = (unsigned int)(xi/pix_edge);
00630     y = (unsigned int)(yi/pix_edge);
00631     init = false;
00632     return true;
00633   }
00634   if (done) return false;
00635   float dx = xe-xs;
00636   float dy = ye-ys;
00637   float mag = vcl_sqrt(dx*dx + dy*dy);
00638   if (mag<pix_edge)// Can't reach the next pixel under any circumstances
00639   {                // so just output the target, xe, ye.
00640     x = (unsigned int)xe; y = (unsigned int)ye;
00641     done = true;
00642     return true;
00643   }
00644   float delta = (0.5f*pix_edge)/mag; // move in 1/2 pixel increments
00645   // Previous pixel location
00646   int xp = int(xi/pix_edge);
00647   int yp = int(yi/pix_edge);
00648   // Increment along the line until the motion is greater than one pixel
00649   for (int i = 0; i<3; i++)
00650   {
00651     xi += dx*delta;
00652     yi += dy*delta;
00653     // Check for end of segment, make sure we emit the end of the segment
00654     if ((xe>=xs&&xi>xe)||(xe<=xs&&xi<xe)||(ye>=ys&&yi>ye)||(ye<=ys&&yi<ye))
00655     {
00656       x = (unsigned int)xe; y = (unsigned int)ye;
00657       done = true;
00658       return true;
00659     }
00660     // Check if we have advanced by more than .5 pixels
00661     x = (unsigned int)(xi/pix_edge);
00662     y = (unsigned int)(yi/pix_edge);
00663     if (vcl_abs(int(x)-xp)>(.5*pix_edge)||vcl_abs(int(y)-yp)>(.5*pix_edge))
00664       return true;
00665   }
00666   vcl_cout << "in gevd_edgel_regions line_gen: - shouldn't happen\n";
00667   return false;
00668 }
00669 
00670 //----------------------------------------------------------
00671 //: A utility for inserting an edgel into the region_label_array_.
00672 //    An edgel and a previous edgel in the chain are used to interpolate
00673 //    intermediate edgels to take account of pixel quantization
00674 bool gevd_edgel_regions::insert_edgel(float pre_x, float pre_y,
00675                                       float xedgel, float yedgel, gevd_region_edge* re)
00676 {
00677   unsigned int xinterp, yinterp;
00678   bool edge_insert = false;
00679   while (line_gen(pre_x, pre_y, xedgel, yedgel, xinterp, yinterp))
00680   {
00681     if (out_of_bounds(X(xinterp), Y(yinterp)))
00682     {
00683       vcl_cout << "In gevd_edgel_regions::insert_edgel - out of bounds "
00684                << "at (" << xinterp << ' ' << yinterp << ")\n";
00685       continue;
00686     }
00687 
00688     region_label_array_[Y(yinterp)][X(xinterp)] = EDGE;
00689 
00690     if (!re) continue;
00691     gevd_region_edge* old_re = edge_boundary_array_[Y(yinterp)][X(xinterp)];
00692     if (old_re&&old_re->get_edge())
00693     {
00694     //        old_re->UnProtect();
00695       edge_boundary_array_[Y(yinterp)][X(xinterp)] = re;
00696       //      re->Protect();
00697       edge_insert = true;
00698     }
00699     if (!old_re)
00700     {
00701       edge_boundary_array_[Y(yinterp)][X(xinterp)] = re;
00702       //      re->Protect();
00703       edge_insert = true;
00704     }
00705   }
00706   return edge_insert;
00707 }
00708 
00709 int gevd_edgel_regions::bytes_per_pix()
00710 {
00711   int bypp = 1;
00712   if (image_source_)
00713     bypp = (image_->components() / image_->bits_per_component());
00714 
00715   if (buf_source_)
00716     bypp = buf_->GetBytesPixel();
00717   return bypp;
00718 }
00719 
00720 //-----------------------------------------------------------
00721 //: Initialize the region label array.
00722 //  There are three types of region label symbols:
00723 //  1) UNLABELED - no label has yet been assigned,
00724 //  2) EDGE, the existence of an edgel boundary pixel.
00725 //  3) An unsigned integer which represents an existing region label.
00726 
00727 bool gevd_edgel_regions::InitRegionArray(vcl_vector< vtol_edge_2d_sptr>& sg)
00728 {
00729   if (!this->GroupContainsEdges(sg))
00730     return false;
00731 
00732   double xmin;
00733   double ymin;
00734   double xmax;
00735   double ymax;
00736   vsol_box_2d_sptr b;
00737 
00738   vcl_vector<vtol_edge_2d_sptr>::iterator i = sg.begin();
00739   assert( i != sg.end() );
00740   b=(*i)->get_bounding_box();
00741   xmin=b->get_min_x();
00742   ymin=b->get_min_y();
00743   xmax=b->get_max_x();
00744   ymax=b->get_max_y();
00745   for (++i; i!=sg.end(); ++i)
00746   {
00747     b=(*i)->get_bounding_box();
00748     if (b->get_min_x()<xmin)
00749       xmin=b->get_min_x();
00750     if (b->get_min_y()<ymin)
00751       ymin=b->get_min_y();
00752     if (b->get_max_x()>xmax)
00753       xmax=b->get_max_x();
00754     if (b->get_max_y()>ymax)
00755       ymax=b->get_max_y();
00756   }
00757 
00758   // Get the size of the arrays
00759   xo_ = (unsigned int)xmin;
00760   yo_ = (unsigned int)ymin;
00761 
00762   xend_ = (unsigned int)xmax;
00763   yend_ = (unsigned int)ymax;
00764 
00765   unsigned int sizex = xend_ - xo_ + 1;
00766   unsigned int sizey = yend_ - yo_ + 1;
00767   // Construct the arrays
00768   edge_boundary_array_ = new gevd_region_edge**[sizey];
00769   unsigned int y;
00770   for (y = yo_; y<=yend_; y++)
00771     edge_boundary_array_[Y(y)] = new gevd_region_edge*[sizex];
00772 
00773   region_label_array_ = new unsigned int*[sizey];
00774   for (y = yo_; y<=yend_; y++)
00775     region_label_array_[Y(y)] = new unsigned int[sizex];
00776 
00777   switch (this->bytes_per_pix())
00778   {
00779    case 1:     // Grey scale image with one byte per pixel
00780     ubuf_ = new unsigned char[sizex];
00781     break;
00782    case 2:     // Grey scale image with an unsigned short per pixel
00783      sbuf_ = new unsigned short[sizex];
00784      break;
00785    default:
00786     vcl_cout<<"In vtol_intensity_face::get_intensity(): bytes/pixel not 1 or 2\n";
00787   }
00788 
00789   // Initialize the arrays
00790   unsigned int x;
00791   if (ubuf_)
00792     for (x = xo_; x<=xend_; x++)
00793       ubuf_[X(x)] = 0;
00794 
00795   if (sbuf_)
00796     for (x = xo_; x<=xend_; x++)
00797       sbuf_[X(x)] = 0;
00798 
00799   for (y = yo_; y<=yend_; y++)
00800     for (x = xo_; x<=xend_; x++)
00801     {
00802       region_label_array_[Y(y)][X(x)] = UNLABELED;
00803       edge_boundary_array_[Y(y)][X(x)] = NULL;
00804     }
00805   // Insert edgels into arrays.
00806 
00807   int counter=0;
00808   for (vcl_vector<vtol_edge_2d_sptr >::iterator sgit = sg.begin();
00809        sgit != sg.end(); sgit++)
00810   {
00811     vtol_edge_2d_sptr e = (*sgit);
00812     if (!e)
00813       continue;
00814     e->set_id(counter++);
00815     vdgl_digital_curve* dc = e->curve()->cast_to_vdgl_digital_curve();
00816     if (!dc)
00817       continue;
00818     // The gevd_region_edge enables the link between a region label and
00819     // an Edge from the input segmentation
00820     gevd_region_edge* re = new gevd_region_edge(e);
00821     region_edges_[e->get_id()] = re;
00822     //      e->Protect(); re->Protect();
00823     //      float * ex = dc->GetX();
00824     //      float * ey = dc->GetY();
00825     vdgl_edgel_chain_sptr xy= dc->get_interpolator()->get_edgel_chain();
00826     int n_edgels = xy->size();
00827 
00828     // Insert the vertices at the ends of the edge
00829     // If there is a gap between the vertex locations and the
00830     // nearest edgels, the insert_edgel function will generate
00831     // edge insertions to prevent any gaps in the region boundary
00832     // There shouldn't be DigitalCurve(s) with this defect but it
00833     // does seem to occur.
00834     gevd_region_edge* vre = new gevd_region_edge(NULL);
00835     float pex1, pey1, pex2, pey2;
00836     if (n_edgels>0)
00837     {
00838       pex1 = float((*xy)[0].x()); pex2 = float((*xy)[n_edgels-1].x());
00839       pey1 = float((*xy)[0].y()); pey2 = float((*xy)[n_edgels-1].y());
00840       this->insert_edgel(pex1, pey1,
00841                          float(e->v1()->cast_to_vertex_2d()->x()),
00842                          float(e->v1()->cast_to_vertex_2d()->y()),
00843                          vre);
00844       this->insert_edgel(pex2, pey2,
00845                          float(e->v2()->cast_to_vertex_2d()->x()),
00846                          float(e->v2()->cast_to_vertex_2d()->y()),
00847                          vre);
00848     }
00849     else
00850     {
00851       pex1 = float(e->v1()->cast_to_vertex_2d()->x());
00852       pey1 = float(e->v1()->cast_to_vertex_2d()->y());
00853       pex2 = float(e->v2()->cast_to_vertex_2d()->x());
00854       pey2 = float(e->v2()->cast_to_vertex_2d()->y());
00855       this->insert_edgel(pex1, pey1, pex1, pey1, vre);
00856       this->insert_edgel(pex1, pey1, pex2, pey2, vre);
00857     }
00858     // Insert the edgels between the vertices
00859     // An edgel cannot be inserted on top of an existing vertex
00860     // insertion.  A vertex is distinguished by having a NULL Edge.
00861     // That is, for vertices it is ambiguous what Edge instance
00862     // exists at that location. Edge insertion fails if no edgels
00863     // of the Edge can be sucessfully inserted.
00864     bool edge_insert = false;
00865     for (int k =0; k < n_edgels; k++)
00866     {
00867       bool inserted = this->insert_edgel(pex1, pey1, float((*xy)[k].x()), float((*xy)[k].y()), re);
00868       edge_insert = edge_insert || inserted;
00869       pex1 = float((*xy)[k].x());
00870       pey1 = float((*xy)[k].y());
00871     }
00872     if (!edge_insert)
00873     {
00874       vcl_cout << "Edge Insert Failed for (" << e->v1() << ' '
00875                << e->v2() << ")N: "<< n_edgels << vcl_endl;
00876       failed_insertions_->push_back(e);
00877     }
00878   }
00879   return true;
00880 }
00881 
00882 //---------------------------------------------------------------
00883 //: Get code for a given label.
00884 //
00885 unsigned char gevd_edgel_regions::label_code(unsigned int label)
00886 {
00887   unsigned char result;
00888   if (label<min_region_label_)
00889     result = (unsigned char)label;
00890   else
00891     result = LABEL;
00892   return result;
00893 }
00894 
00895 //----------------------------------------------------------------
00896 //: Add a new pair to the forward equivalence list.
00897 //    That is, a ==> b. Note that there can be multiple equivalences which are
00898 //    stored in a vcl_vector
00899 bool gevd_edgel_regions::add_to_forward(unsigned int key, unsigned int value)
00900 {
00901   bool result = true;
00902   vcl_map<unsigned int, vcl_vector<unsigned int>* >::iterator rpfi;
00903   rpfi = region_pairs_forward_.find(key);
00904 
00905   if (rpfi !=region_pairs_forward_.end())
00906   {
00907     vcl_vector<unsigned int> * vec = region_pairs_forward_[key];
00908     bool found = false;
00909     for (unsigned int i =0 ; i < vec->size() ; i++)
00910     {
00911       if ((*vec)[i] == value)
00912         found = true;
00913     }
00914     if (!found)
00915     {
00916       vec->push_back(value);
00917     }
00918   }
00919   else
00920   {
00921     vcl_vector<unsigned int>* larray = new vcl_vector<unsigned int>;
00922     larray->push_back(value);
00923     region_pairs_forward_[key]=larray;
00924   }
00925   return result;
00926 }
00927 
00928 //----------------------------------------------------------------
00929 //: Add a new pair to the reverse equivalence list.
00930 //    That is, b==>a. Note that there can be multiple equivalences which are
00931 //    stored in a vcl_vector
00932 //
00933 bool gevd_edgel_regions::add_to_reverse(unsigned int key, unsigned int value)
00934 {
00935   bool result = true;
00936   vcl_map<unsigned int, vcl_vector<unsigned int>* >::iterator rpfi;
00937   rpfi = region_pairs_reverse_.find(key);
00938 
00939   if (rpfi !=region_pairs_reverse_.end())
00940   {
00941     vcl_vector<unsigned int> * vec = region_pairs_reverse_[key];
00942     bool found = false;
00943     for (unsigned int i =0 ; i < vec->size() ; i++)
00944     {
00945       if ((*vec)[i] == value)
00946         found = true;
00947     }
00948     if (!found)
00949     {
00950       vec->push_back(value);
00951     }
00952   }
00953   else
00954   {
00955     vcl_vector<unsigned int>* larray = new vcl_vector<unsigned int>;
00956     larray->push_back(value);
00957     region_pairs_reverse_[key]=larray;
00958   }
00959   return result;
00960 }
00961 
00962 //-------------------------------------------------------------------
00963 //: Encode a 2x2 neighbor hood with the state of the region array for a given location.
00964 //    The Neighborhood    The states are:
00965 //         ul ur          UNLABELED, EDGE, LABEL
00966 //         ll lr              0       1      2
00967 //    The encoding maps the 2x2 pattern to an unsigned char.  The layout
00968 //    of the uchar is:  [ul|ur|ll|lr] with 2 bits for the state of each
00969 //    position.
00970 unsigned char
00971 gevd_edgel_regions::EncodeNeighborhood(unsigned int ul, unsigned int ur,
00972                                        unsigned int ll, unsigned int lr)
00973 {
00974   unsigned char nhood = 0;
00975 
00976   unsigned char nul = label_code(ul);
00977   nul = nul<<6;
00978   nhood |= nul;
00979 
00980   unsigned char nur = label_code(ur);
00981   nur = nur<<4;
00982   nhood |= nur;
00983 
00984   unsigned char nll = label_code(ll);
00985   nll = nll << 2;
00986   nhood |= nll;
00987 
00988   unsigned char nlr = label_code(lr);
00989   nhood |= nlr;
00990 
00991   return nhood;
00992 }
00993 
00994 //----------------------------------------------------------------------
00995 // --This is the fundamental assignment of label equivalence
00996 //
00997 void gevd_edgel_regions::insert_equivalence(unsigned int ll, unsigned int ur, unsigned int& lr)
00998 {
00999   if (ll!=ur) // Is a=b?
01000   { // No. We want the smallest label to be the equivalence base
01001     // Also we don't want to loose earlier equivalences
01002     unsigned int smaller_label, larger_label;
01003     // Get the ordering right
01004     if (ll>ur) { smaller_label = ur; larger_label = ll; }
01005     else       { smaller_label = ll; larger_label = ur; }
01006     this->add_to_forward(larger_label, smaller_label);
01007     this->add_to_reverse(smaller_label, larger_label);
01008     lr = smaller_label;
01009   }
01010   else // yes, a=b the simple case
01011     lr = ur;
01012 }
01013 
01014 //-------------------------------------------------------------------
01015 //: Propagate connected components.
01016 //    Uses an unsigned char encoding
01017 //    a 2x2 neighborhood to propagate region labels. For example:
01018 //    aa ->   aa
01019 //    xx ->   aa
01020 //    Here the lower two labels are set to the upper label.
01021 //    This method operates directly on the region_label_array_.
01022 //
01023 //    Note that the 2x2 neighborhood is encoded as uchar = [ul|ur|ll|lr]
01024 //                                                          2  2  2  2  bits
01025 void gevd_edgel_regions::UpdateConnectedNeighborhood(unsigned int x, unsigned int y)
01026 {
01027   unsigned int ul = region_label_array_[y][x];
01028   unsigned int ur = region_label_array_[y][x+1];
01029   unsigned int& ll = region_label_array_[y+1][x];
01030   unsigned int& lr = region_label_array_[y+1][x+1];
01031 
01032   unsigned char nhood = this->EncodeNeighborhood(ul, ur, ll, lr);
01033   switch (int(nhood))
01034   {
01035     case 0:
01036       // xx xx
01037       // xx xx
01038       return;
01039     case 1:
01040       // xx xx
01041       // xe xe
01042       return;
01043     case 5:
01044       // xx xx
01045       // ee ee
01046       return;
01047 
01048     case 17:
01049       // xe xe
01050       // xe xe
01051       return;
01052 
01053     case 20:
01054       // xe xe
01055       // ex ea
01056       lr = max_region_label_++;
01057       return;
01058 
01059     case 21:
01060       // xe xe
01061       // ee ee
01062       return;
01063 
01064     case 22:
01065       // xe xe
01066       // ea ea
01067       return;
01068 
01069     case 68:
01070       // ex ex
01071       // ex ex
01072       return;
01073 
01074     case 72:
01075       // ex ex
01076       // ax ax
01077       return;
01078 
01079     case 133:
01080       // ax aa
01081       // ee ee
01082       return;
01083 
01084     case 136:
01085       // ax ax
01086       // ax ax
01087       return;
01088 
01089     case 160:
01090       // aa aa
01091       // xx aa
01092       ll = ul;
01093       lr = ul;
01094       return;
01095 
01096     case 161:
01097       // aa aa
01098       // xe ae
01099       ll = ul;
01100       return;
01101 
01102     case 168:
01103       // aa aa
01104       // ax aa
01105       insert_equivalence(ll, ur, lr);
01106       return;
01107 
01108     case 169:
01109       // aa aa
01110       // ae ae
01111       return;
01112 
01113     case 164:
01114       // aa aa
01115       // ex ea
01116       lr = ul;
01117       return;
01118 
01119     case 165:
01120       // aa aa
01121       // ee ee
01122       return;
01123 
01124     case 144:
01125       // ae ae
01126       // xx aa
01127       ll = ul;
01128       lr = ul;
01129       return;
01130 
01131     case 145:
01132       // ae ae
01133       // xe ae
01134       ll = ul;
01135       return;
01136 
01137     case 152:
01138       // ae ae
01139       // ax aa
01140       lr = ul;
01141       return;
01142 
01143     case 153:
01144       // ae ae
01145       // ae ae
01146       return;
01147 
01148     case 148:
01149       // ae ae
01150       // ex eb
01151       lr = max_region_label_++;
01152       return;
01153 
01154     case 149:
01155       // ae ae
01156       // ee ee
01157       return;
01158 
01159     case 96:
01160       // ea ea
01161       // xx aa
01162       ll = ur;
01163       lr = ur;
01164       return;
01165 
01166     case 97:
01167       // ea ea
01168       // xe be
01169       ll = max_region_label_++;
01170       return;
01171 
01172     case 104:
01173       // ea ea
01174       // bx aa
01175       insert_equivalence(ll, ur, lr);
01176       return;
01177 
01178     case 105:
01179       // ea ea
01180       // ae ae
01181       return;
01182 
01183     case 100:
01184       // ea ea
01185       // ex ea
01186       lr = ur;
01187       return;
01188 
01189     case 101:
01190       // ea ea
01191       // ee ee
01192       return;
01193 
01194     case 80:
01195         // ee ee
01196         // xx bb
01197       ll = max_region_label_++;
01198       lr = ll;
01199       return;
01200 
01201     case 81:
01202       // ee ee
01203       // xe be
01204       ll = max_region_label_++;
01205       return;
01206 
01207     case 88:
01208       // ee ee
01209       // ax aa
01210       lr = ll;
01211       return;
01212 
01213     case 89:
01214       // ee ee
01215       // ae ae
01216       return;
01217 
01218     case 84:
01219       // ee ee
01220       // ex eb
01221       lr = max_region_label_++;
01222       return;
01223 
01224     case 85:
01225         // ee ee
01226         // ee ee
01227         return;
01228     default:
01229       vcl_cout << "In gevd_edgel_regions::UpdateNeigborhood(..)"
01230                << "impossible pattern = " << (int)nhood << vcl_endl;
01231   }
01232 }
01233 
01234 static bool reg_edges_neq(gevd_region_edge* r1, gevd_region_edge* r2)
01235 {
01236   if (!r1||!r2) return false;
01237   bool v1 = r1->is_vertex();
01238   bool v2 = r2->is_vertex();
01239   if (v1||v2) return false;
01240   return r1->get_edge()!=r2->get_edge();
01241 }
01242 
01243 // A collision is defined by the condition where an region is bounded
01244 // by two different edges at adjacent pixels without crossing a vertex.
01245 // This can happen since boundary positions are sub-pixel and region
01246 // definition is at pixel granularity.  The edge collison causes a needed
01247 // edge to be superseeded.
01248 void gevd_edgel_regions::print_edge_colis(unsigned int x, unsigned int y,
01249                                           gevd_region_edge* r1, gevd_region_edge* r2)
01250 {
01251   if (reg_edges_neq(r1, r2))
01252     if (verbose_)
01253       vcl_cout << "Collision at (" << x+xo_ << ' ' << y+yo_ << ")\n";
01254 }
01255 
01256 //----------------------------------------------------------
01257 //:
01258 //    In a correct boundary, each vertex must appear twice, i.e.,
01259 //    shared by two edges.  The only exception is a closed loop with
01260 //    one vertex, but in this case, one edge shares the same vertex twice.
01261 //    This routine tests this constraint.
01262 bool gevd_edgel_regions::
01263 corrupt_boundary(vcl_vector<vtol_edge_2d_sptr>& edges,
01264                  vcl_vector<vtol_vertex_sptr>& bad_vertices)
01265 {
01266   bool bad = false;
01267   // Initialize Markers
01268   vcl_vector<vtol_edge_2d_sptr>::iterator eit = edges.begin();
01269   for (;eit != edges.end(); eit++)
01270   {
01271     vtol_vertex_sptr v1 = (*eit)->v1();
01272     vtol_vertex_sptr v2 = (*eit)->v2();
01273     v1->set_id(0);
01274     v2->set_id(0);
01275   }
01276   eit = edges.begin();
01277   for (;eit != edges.end(); eit++)
01278   {
01279     vtol_vertex_sptr v1 = (*eit)->v1();
01280     vtol_vertex_sptr v2 = (*eit)->v2();
01281     int id1 = v1->get_id();
01282     v1->set_id(++id1);
01283     int id2 = v2->get_id();
01284     v2->set_id(++id2);
01285   }
01286   eit = edges.begin();
01287   for (;eit != edges.end(); eit++)
01288   {
01289     vtol_vertex_sptr v1 = (*eit)->v1();
01290     vtol_vertex_sptr v2 = (*eit)->v2();
01291     if ((v1!=v2)&&*v1==*v2)
01292       vcl_cout << "Improper Loop(" << *v1 << *v2 << ")\n\n";
01293     int id1 = v1->get_id(), id2 = v2->get_id();
01294     bool bad1 = id1==1, bad2 = id2==1;
01295     if (bad1)
01296     {
01297 #if 0
01298       bad_vertices.push_back_new(v1);
01299       //-tpk- assuming puch_bask is close enough
01300 #endif
01301       bad_vertices.push_back(v1);
01302       bad = true;
01303     }
01304     if (bad2)
01305     {
01306 #if 0
01307       bad_vertices.push_back_new(v2);
01308 #endif
01309       bad_vertices.push_back(v2);
01310       bad = true;
01311     }
01312     if (verbose_&&(bad1||bad2))
01313       vcl_cout << "Id1 = " << id1 << "  Id2 = " << id2 << vcl_endl;
01314   }
01315   return bad;
01316 }
01317 
01318 //------------------------------------------------------
01319 //:
01320 //  the top of the T is embedded in a boundary.  This routine tests
01321 //  a dangling edge, called "bar" to see if the "T" vertex, "v", joins
01322 //  the contour in a connected chain.  That is, the top of the "T" is
01323 //  part of a chain.  This condition is called "embedded".  This routine
01324 //  is used to remove "hairs" which are extra edges attached to a
01325 //  closed contour by the pixel-level granularity of the region growing
01326 //  process.
01327 static bool embedded_T(vtol_vertex_sptr v, vtol_edge_2d_sptr bar, vcl_vector<vtol_edge_2d_sptr>& real_edges)
01328 {
01329   vcl_vector<vtol_edge_sptr> edges; v->edges(edges);
01330   int tedges = 0;
01331   vcl_vector<vtol_edge_sptr>::iterator eit;
01332   for (eit = edges.begin(); eit != edges.end(); eit++)
01333   {
01334     vtol_edge_2d_sptr e = (*eit)->cast_to_edge_2d();
01335     if (vcl_find(real_edges.begin(), real_edges.end(), e) == real_edges.end())
01336       continue;
01337 
01338     if ((*eit)->cast_to_edge_2d()==bar)
01339     {
01340       tedges++;
01341       continue;
01342     }
01343     int end_count = (*eit)->other_endpoint(*v)->get_id();
01344     if (end_count>1)
01345     {
01346       tedges++;
01347       continue;
01348     }
01349   }
01350   return tedges>=3;
01351 }
01352 
01353 //--------------------------------------------------------------------
01354 //: Remove hairs from region boundary.
01355 //    This condition can occur because
01356 //    the region labels are not sub-pixel.  A "hair" is an extra edge joined
01357 //    at a vertex which is part of a continuous chain. Unattached vertices
01358 //    are detected by incrementing a count at each vertex for each
01359 //    attached edge in the input array, "edges".  Such hairs are removed from
01360 //    the input array.
01361 bool gevd_edgel_regions::remove_hairs(vcl_vector<vtol_edge_2d_sptr>& edges)
01362 {
01363   vcl_vector<vtol_edge_2d_sptr> hairs;
01364   vcl_vector<vtol_edge_2d_sptr> temp;
01365   // Initialize Markers
01366   vcl_vector<vtol_edge_2d_sptr>::iterator eit = edges.begin();
01367   for (;eit != edges.end(); eit++)
01368   {
01369     vtol_vertex_sptr v1 = (*eit)->v1();
01370     vtol_vertex_sptr v2 = (*eit)->v2();
01371     v1->set_id(0);
01372     v2->set_id(0);
01373     temp.push_back(*eit);
01374   }
01375   // Use the vertex id as a counter for the number of edges incident
01376   eit = edges.begin();
01377   for (;eit != edges.end(); eit++)
01378   {
01379     vtol_vertex_sptr v1 = (*eit)->v1();
01380     vtol_vertex_sptr v2 = (*eit)->v2();
01381     int id1 = v1->get_id();
01382     v1->set_id(++id1);
01383     int id2 = v2->get_id();
01384     v2->set_id(++id2);
01385   }
01386   eit = edges.begin();
01387   for (;eit != edges.end(); eit++)
01388   {
01389     vtol_vertex_sptr v1 = (*eit)->v1();
01390     vtol_vertex_sptr v2 = (*eit)->v2();
01391     int id1 = v1->get_id(), id2 = v2->get_id();
01392     // The definition of a "hair" a dangling edge meeting at a "T"
01393     if ((id1==1&&id2>2)||(id1>2&&id2==1))
01394     {
01395       // Make sure the top of the "T" is connected
01396       if (id1>2&&embedded_T(v1, *eit, temp))
01397         hairs.push_back(*eit);
01398       else
01399         if (id2>2&&embedded_T(v2, *eit, temp))
01400           hairs.push_back(*eit);
01401     }
01402   }
01403   for (vcl_vector<vtol_edge_2d_sptr>::iterator hit = hairs.begin();
01404        hit != hairs.end(); hit++)
01405     edges.erase(vcl_find(edges.begin(),edges.end(),*hit));
01406 
01407   return hairs.size() != 0;
01408 }
01409 
01410 //-----------------------------------------------------------
01411 // --Fix up corrupt boundaries by connecting dangling vertices
01412 //   bad_verts has a list of vertices which are not incident
01413 //   on at least two edges. This routine attempts to connect
01414 //   each vertex to another in the list.  A missing connection is
01415 //   constructed only if there already exists an edge between the
01416 //   vertices in the input array, "edges".
01417 //
01418 bool gevd_edgel_regions::connect_ends(vcl_vector<vtol_edge_2d_sptr>& edges,
01419                                       vcl_vector<vtol_vertex_sptr>& bad_verts)
01420 {
01421   bool all_ends_connected = true;
01422   if (!bad_verts.size())
01423     return all_ends_connected;
01424   // Clear the bad vertex flags
01425   vcl_vector<vtol_vertex_sptr> temp; // temporary bad_verts array
01426   vcl_vector<vtol_vertex_sptr>::iterator vit = bad_verts.begin();
01427   for (; vit != bad_verts.end(); vit++)
01428   {
01429     (*vit)->unset_user_flag(VSOL_FLAG1);
01430     temp.push_back(*vit);
01431   }
01432   // Collect the vertices from edges
01433   // VSOL_FLAG1 defines the state of a vertex in the search for a connecting edge
01434   // FLAG2 defines the state of a vertex in forming the set edge_verts,
01435   // that is there should be no duplicate vertices
01436   vcl_vector<vtol_vertex_sptr> edge_verts;
01437   for (vcl_vector<vtol_edge_2d_sptr>::iterator eit = edges.begin();
01438        eit != edges.end(); eit++)
01439   {
01440     vtol_vertex_sptr v1 = (*eit)->v1(), v2 = (*eit)->v2();
01441 
01442     v1->unset_user_flag(VSOL_FLAG1);
01443     v2->unset_user_flag(VSOL_FLAG1);
01444     v1->unset_user_flag(VSOL_FLAG2);
01445     v2->unset_user_flag(VSOL_FLAG2);
01446   }
01447   for (vcl_vector<vtol_edge_2d_sptr>::iterator eit = edges.begin();
01448        eit != edges.end(); eit++)
01449   {
01450     vtol_vertex_sptr v1 = (*eit)->v1(), v2 = (*eit)->v2();
01451     if (!v1->get_user_flag(VSOL_FLAG2))
01452     {
01453       edge_verts.push_back(v1.ptr());
01454       v1->set_user_flag(VSOL_FLAG2);
01455     }
01456     if (!v2->get_user_flag(VSOL_FLAG2))
01457     {
01458       edge_verts.push_back(v2.ptr());
01459       v2->set_user_flag(VSOL_FLAG2);
01460     }
01461   }
01462 
01463   vcl_vector<vtol_vertex_sptr> repaired_verts;
01464   for (vit=bad_verts.begin(); vit != bad_verts.end(); vit++)
01465   {
01466     if ((*vit)->get_user_flag(VSOL_FLAG1)) // skip used vertices
01467       continue;
01468     bool found_edge = false;
01469     vcl_vector<vtol_edge_sptr> vedges; (*vit)->edges(vedges);
01470     for (vcl_vector<vtol_edge_sptr>::iterator eit = vedges.begin();
01471          eit != vedges.end()&&!found_edge; eit++)
01472     {
01473       vtol_vertex_sptr v = (*eit)->other_endpoint(**vit);
01474       // Continue if:
01475       //  1)the vertex v has been used;
01476       //  2)v can't be found in bad_verts;
01477       //  3)v can't be found in edge_verts;
01478       //  4)(*eit) is already in the input edge set.
01479       if (v->get_user_flag(VSOL_FLAG1))
01480         continue; // 1)
01481       bool found_in_bad_verts = false;
01482       if (vcl_find (temp.begin(), temp.end(), v) != temp.end())
01483         found_in_bad_verts = true;
01484       // already iterating
01485       // in bad_verts, so use temp
01486       bool found_in_edge_verts = false;
01487       if (!found_in_bad_verts) // 2)
01488       {
01489         if (vcl_find(edge_verts.begin(), edge_verts.end(),v) != edge_verts.end())
01490         {
01491           found_in_edge_verts = true;
01492         }
01493       }
01494       if (!(found_in_bad_verts||found_in_edge_verts)) // 3)
01495         continue;
01496       vtol_edge_2d_sptr e = (*eit)->cast_to_edge_2d();
01497       if (vcl_find(edges.begin(), edges.end(), e) != edges.end())
01498         continue; // 4)
01499       // Found a connecting edge.
01500       edges.push_back((*eit)->cast_to_edge_2d());
01501       found_edge = true;
01502       v->set_user_flag(VSOL_FLAG1);
01503       (*vit)->set_user_flag(VSOL_FLAG1);
01504       repaired_verts.push_back(*vit);
01505     }
01506     all_ends_connected =
01507       all_ends_connected&&(*vit)->get_user_flag(VSOL_FLAG1);
01508   }
01509   for (vit = repaired_verts.begin();
01510        vit != repaired_verts.end(); vit++)
01511     bad_verts.erase(vit);
01512   return all_ends_connected;
01513 }
01514 
01515 //-------------------------------------------------------------------
01516 //:
01517 //    There can be some gaps in the region boundary due to missing
01518 //    edges caused by a high local density of vertices.  Take each
01519 //    un-attached vertex and look for a match in the failed edge insertion
01520 //    array. If an edge can be attached, do so.
01521 void gevd_edgel_regions::repair_failed_insertions(vcl_vector<vtol_edge_2d_sptr>& edges,
01522                                                   vcl_vector<vtol_vertex_sptr>& bad_verts)
01523 {
01524   vcl_vector<vtol_vertex_sptr> temp1, temp2;
01525   for (vcl_vector<vtol_vertex_sptr>::iterator vit = bad_verts.begin();
01526        vit != bad_verts.end(); vit++)
01527     for (vcl_vector<vtol_edge_2d_sptr>::iterator eit = failed_insertions_->begin();
01528          eit != failed_insertions_->end(); eit++)
01529       if ((*vit)==(*eit)->v1())
01530       {
01531         edges.push_back(*eit);
01532         temp1.push_back(*vit);
01533         temp2.push_back((*eit)->v2());
01534       }
01535       else if ((*vit)==(*eit)->v2())
01536       {
01537         edges.push_back(*eit);
01538         temp1.push_back(*vit);
01539         temp2.push_back((*eit)->v1());
01540       }
01541   for (vcl_vector<vtol_vertex_sptr>::iterator wit = temp1.begin();
01542        wit != temp1.end(); wit++)
01543     bad_verts.erase(wit);
01544 
01545   for (vcl_vector<vtol_vertex_sptr>::iterator vvit = temp2.begin();
01546        vvit != temp2.end(); vvit++)
01547     bad_verts.push_back(*vvit);
01548 }
01549 
01550 //-------------------------------------------------------------------
01551 //:
01552 //    After connected components have been generated pass over the
01553 //    array and assign region labels to the gevd_region_edge(s).
01554 //    As in ::UpdateConnectedNeighborhood, the algorithm uses a 2x2 neigborhood
01555 //    E.G.,
01556 //    ee But the purpose is to assign labels. No updating of the
01557 //    aa region_label_array_ is carried out.
01558 //
01559 //    Note that the 2x2 neighborhood is encoded as uchar = [ul|ur|ll|lr]
01560 //                                                          2  2  2  2  bits
01561 void gevd_edgel_regions::AssignEdgeLabels(unsigned int x, unsigned int y)
01562 {
01563   unsigned int ul = region_label_array_[y][x];
01564   unsigned int ur = region_label_array_[y][x+1];
01565   unsigned int& ll = region_label_array_[y+1][x];
01566   unsigned int& lr = region_label_array_[y+1][x+1];
01567   gevd_region_edge* rul = edge_boundary_array_[y][x];
01568   gevd_region_edge* rur = edge_boundary_array_[y][x+1];
01569   gevd_region_edge* rll = edge_boundary_array_[y+1][x];
01570   gevd_region_edge* rlr = edge_boundary_array_[y+1][x+1];
01571 
01572   unsigned char nhood = this->EncodeNeighborhood(ul, ur, ll, lr);
01573   switch (int(nhood))
01574   {
01575     case 170:
01576       // aa
01577       // aa
01578       return;
01579 
01580     case 169:
01581       // aa
01582       // ae
01583       rlr->Prop(rlr, ul);
01584       return;
01585 
01586     case 166:
01587       // aa
01588       // ea
01589       rll->Prop(rll, ul);
01590       return;
01591 
01592     case 165:
01593       // aa
01594       // ee
01595       rll->Prop(rll, ul);
01596       print_edge_colis(x, y, rll, rlr);
01597       return;
01598 
01599     case 154:
01600       // ae
01601       // aa
01602       rur->Prop(rur, ul);
01603       return;
01604 
01605     case 153:
01606       // ae
01607       // ae
01608       rlr->Prop(rur, ul);
01609       print_edge_colis(x, y, rur, rlr);
01610       return;
01611 
01612     case 150:
01613       // ae
01614       // ea
01615       rur->Prop(rll, ul);
01616       rur->Prop(rll, lr);
01617       print_edge_colis(x, y, rur, rll);
01618       return;
01619 
01620     case 149:
01621       // ae
01622       // ee
01623       rll->Prop(rll, ul);
01624       rur->Prop(rlr, ul);
01625       if (!(rlr->is_vertex()))
01626       {
01627         print_edge_colis(x, y, rur, rlr);
01628         print_edge_colis(x, y, rll, rur);
01629         print_edge_colis(x, y, rll, rlr);
01630       }
01631       return;
01632 
01633     case 106:
01634       // ea
01635       // aa
01636       rul->Prop(rul, ll);
01637       return;
01638 
01639     case 105:
01640       // ea
01641       // ae
01642       rlr->Prop(rul, ll);
01643       rlr->Prop(rul, ur);
01644       print_edge_colis(x, y, rul, rlr);
01645       return;
01646 
01647     case 102:
01648       // ea
01649       // ea
01650       rll->Prop(rul, ur);
01651       print_edge_colis(x, y, rul, rll);
01652       return;
01653 
01654     case 101:
01655       // ea
01656       // ee
01657       if (!(rll->is_vertex()))
01658       {
01659         print_edge_colis(x, y, rul, rll);
01660         print_edge_colis(x, y, rul, rlr);
01661         print_edge_colis(x, y, rll, rlr);
01662       }
01663       return;
01664 
01665     case 90:
01666       // ee
01667       // aa
01668       rul->Prop(rul,ll);
01669       print_edge_colis(x, y, rul, rur);
01670       return;
01671 
01672     case 89:
01673       // ee
01674       // ae
01675       rul->Prop(rul, ll);
01676       rlr->Prop(rur, ll);
01677       if (!(rur->is_vertex()))
01678       {
01679         print_edge_colis(x, y, rul, rur);
01680         print_edge_colis(x, y, rul, rlr);
01681         print_edge_colis(x, y, rur, rlr);
01682       }
01683       return;
01684 
01685     case 86:
01686       // ee
01687       // ea
01688       rul->Prop(rul, lr);
01689       if (!(rul->is_vertex()))
01690       {
01691         print_edge_colis(x, y, rul, rur);
01692         print_edge_colis(x, y, rul, rll);
01693         print_edge_colis(x, y, rur, rll);
01694       }
01695       return;
01696     case 85:
01697         // ee
01698         // ee
01699       if (!((rul->is_vertex())||(rur->is_vertex())||
01700           (rll->is_vertex())||(rlr->is_vertex())))
01701       {
01702         print_edge_colis(x, y, rul ,rur);
01703         print_edge_colis(x, y, rul ,rll);
01704         print_edge_colis(x, y, rul ,rlr);
01705         print_edge_colis(x, y, rur ,rll);
01706         print_edge_colis(x, y, rur ,rlr);
01707         print_edge_colis(x, y, rll ,rlr);
01708       }
01709       return;
01710     default:
01711       vcl_cout << "In gevd_edgel_regions::UpdateNeigborhood(..)"
01712                << "impossible pattern = " << (int)nhood << vcl_endl;
01713   }
01714 }
01715 
01716 //---------------------------------------------------------------------
01717 //: Scan the region_label_array_ and apply the region equivalence map.
01718 //    The result is that all equivalences are reconciled with the smallest
01719 //    labels.
01720 void gevd_edgel_regions::ApplyRegionEquivalence()
01721 {
01722   unsigned int x, y;
01723   for (y = yo_; y<=yend_; y++)
01724     for (x = xo_; x<=xend_; x++)
01725     {
01726       // Update the region label array
01727       unsigned int label = region_label_array_[Y(y)][X(x)];
01728       if (label<min_region_label_)
01729         continue;
01730       unsigned int base = this->BaseLabel(label);
01731       region_label_array_[Y(y)][X(x)] = base;
01732     }
01733 }
01734 
01735 //-------------------------------------------------------------------
01736 //: Bounds check on region_label_array_
01737 bool gevd_edgel_regions::out_of_bounds(unsigned int x, unsigned int y)
01738 {
01739   bool out = x>(xend_-xo_)||y>(yend_-yo_);
01740   return out;
01741 }
01742 
01743 //: Get the a region label for an edge used to construct the boundaries.
01744 //   A return corresponding to UNLABELED means the domain outside the ROI
01745 //   or nr is larger than the number of adjacent regions.
01746 unsigned int gevd_edgel_regions::GetLabel(vtol_edge_2d_sptr e, unsigned int nr)
01747 {
01748   vcl_map<int,gevd_region_edge *>::iterator reit = region_edges_.find(e->get_id());
01749   if ( reit == region_edges_.end())
01750     return UNLABELED;
01751   return reit->second->GetLabel(nr);
01752 }
01753 
01754 //--------------------------------------------------------------------
01755 //: Insert an Edge into the adjacency list for a region
01756 //
01757 void gevd_edgel_regions::insert_adjacency(unsigned int r, vtol_edge_2d_sptr e)
01758 {
01759   if (!e) return;
01760   //  e->Protect();
01761   vcl_map<unsigned int,vcl_vector<vtol_edge_2d_sptr> *>::iterator reit =region_edge_adjacency_.find(r);
01762   if (reit == region_edge_adjacency_.end())
01763   {
01764     vcl_vector<vtol_edge_2d_sptr>* array = new vcl_vector<vtol_edge_2d_sptr>;
01765     array->push_back(e);
01766     region_edge_adjacency_[r] = array;
01767   }
01768   else
01769     reit->second->push_back(e);
01770   //    region_edge_adjacency_.value()->push(e);
01771 }
01772 
01773 //------------------------------------------------------------------
01774 //: Get the edges adjacent to each region
01775 //
01776 void gevd_edgel_regions::CollectEdges()
01777 {
01778   for ( vcl_map<int, gevd_region_edge*>::iterator reit= region_edges_.begin();
01779         reit == region_edges_.end(); reit++)
01780   {
01781     gevd_region_edge* re = reit->second;
01782     vtol_edge_2d_sptr e = re->get_edge();
01783     if (verbose_)
01784       vcl_cout << "\nEdge:" << e << '(' << e->v1() <<  ' ' << e->v2() <<"):(";
01785     for (unsigned int i = 0; i<re->NumLabels(); i++)
01786     {
01787       unsigned int l = re->GetLabel(i);
01788       if (verbose_)
01789         vcl_cout << "l[" << i << "]:" << l << ' ';
01790       if (l!=0)
01791         insert_adjacency(l, e);
01792     }
01793     if (verbose_)
01794       vcl_cout << ")\n";
01795   }
01796 }
01797 
01798 //---------------------------------------------------------------------
01799 //: Trace through the topology network keeping regions on the left.
01800 //    At this point, we have a list of edges for each region. We will
01801 //    trace out the list and form OneCycle(s).  Then the set of OneCycle(s)
01802 //    will form the boundary of the face corresponding to the region.
01803 void gevd_edgel_regions::CollectFaceEdges()
01804 {
01805   vul_timer t;
01806   unsigned int i;
01807   vcl_cout<<"Constructing Face-Edges:";
01808 
01809   face_edge_index_ = new vcl_vector<vtol_edge_2d_sptr>*[max_region_label_];
01810   for (i=0; i<max_region_label_; i++)
01811     face_edge_index_[i] = NULL;
01812 
01813   for (i =min_region_label_; i<max_region_label_; i++)
01814   {
01815     vcl_map<unsigned int, vcl_vector<vtol_edge_2d_sptr>* >::iterator  reait;
01816     reait = region_edge_adjacency_.find(i);
01817     if (reait == region_edge_adjacency_.end())
01818       continue;
01819     vcl_vector<vtol_edge_2d_sptr>* edges = reait->second;
01820 
01821     int len = edges->size();
01822     if (!len)
01823       continue;
01824 
01825     this->remove_hairs(*edges);
01826     vcl_vector<vtol_vertex_sptr> bad_verts;
01827     // If the input edge list is corrupt, then attempt to fix it.
01828     if (this->corrupt_boundary(*edges, bad_verts))
01829     {
01830       this->repair_failed_insertions(*edges, bad_verts);
01831       if (!this->connect_ends(*edges, bad_verts))
01832       {
01833         if (verbose_)
01834         {
01835           vcl_cout << "Region [" << i << "] is corrupt\n"
01836                    << "Bad Vertices\n";
01837           for (vcl_vector<vtol_vertex_sptr>::iterator vit = bad_verts.begin();
01838                vit != bad_verts.end(); vit++)
01839             if (!(*vit)->get_user_flag(VSOL_FLAG1))
01840               vcl_cout << *(*vit);
01841           for (vcl_vector<vtol_edge_2d_sptr>::iterator eit = edges->begin();
01842                eit != edges->end(); eit++)
01843             vcl_cout << "\nEdge(\n" << *((*eit)->v1()) << *((*eit)->v2()) <<")\n";
01844         }
01845 #if 0
01846         if (debug_data_)
01847         {
01848           debug_data_->set_verts(bad_verts);
01849           debug_data_->set_edges(*edges);
01850         }
01851 #endif
01852       }
01853     }
01854     if (verbose_)
01855       vcl_cout << " Building Region [" << i << "]\n";
01856     len = edges->size();
01857 
01858     vcl_vector<vtol_edge_2d_sptr> EdgeSet;
01859     for (int j =0; j<len; j++)
01860     {
01861       vtol_edge_2d_sptr e = (*edges)[j];
01862       if (verbose_)
01863         vcl_cout << "Edge(" << e->v1() <<  ' ' << e->v2() << vcl_endl;
01864       EdgeSet.push_back ( e );
01865     }
01866     vcl_vector<vtol_edge_2d_sptr>* edge_list = new vcl_vector<vtol_edge_2d_sptr>;
01867     for (vcl_vector<vtol_edge_2d_sptr>::iterator esit = EdgeSet.begin();
01868          esit != EdgeSet.end() ; esit++)
01869       edge_list->push_back (*esit );
01870     face_edge_index_[i] = edge_list;
01871   }
01872 
01873   vcl_cout << "\nConstructed Face-Edges(" << max_region_label_ - min_region_label_
01874            << ") in " << t.real() << " msecs.\n";
01875 }
01876 
01877 //----------------------------------------------------------------
01878 //: Construct Face(s) from Edge(s) in the face_edge_index_ array.
01879 //    This method has been made virtual so that sub-classes of
01880 //    vtol_intensity_face can be constructed by sub-classes of gevd_edgel_regions.
01881 void gevd_edgel_regions::ConstructFaces()
01882 {
01883   vul_timer t;
01884   unsigned int i;
01885   vcl_cout<<"Constructing Faces:";
01886   // Initialize the intensity_face_index_
01887   intensity_face_index_ = new vtol_intensity_face_sptr[max_region_label_];
01888   for (i=0; i<max_region_label_; i++)
01889     intensity_face_index_[i] = NULL;
01890 
01891   for (i =min_region_label_; i<max_region_label_; i++)
01892   {
01893     // Retrieve the face boundary edges
01894     vcl_vector<vtol_edge_2d_sptr>* edge_list = face_edge_index_[i];
01895     if (!edge_list||!edge_list->size())
01896       continue;
01897     // Make a new vtol_intensity_face
01898     vtol_cycle_processor cp(*edge_list);
01899     vcl_vector<vtol_one_chain_sptr> one_chains;
01900     cp.nested_one_cycles(one_chains, 0.5);
01901 #if 0
01902     if (!one_chains.size()&&debug_data_)
01903     {
01904       debug_data_->set_edges(*edge_list);
01905       continue;
01906     }
01907 #endif
01908     vtol_intensity_face_sptr face = new vtol_intensity_face(one_chains);
01909     // Check if the Face has valid Edges, since the Face
01910     // constructor can fail
01911     // looks like an expensive call
01912     vcl_vector<vtol_edge_sptr> face_edges; face->edges(face_edges);
01913     if (face_edges.size())
01914     {
01915       faces_->push_back(face);
01916       //  face->Protect();
01917       intensity_face_index_[i] = face;
01918       //  face->Protect();
01919     }
01920     //      else
01921     //        face->UnProtect();
01922   }
01923   vcl_cout << "\nConstructed Faces(" << max_region_label_ - min_region_label_
01924            << ") in " << t.real() << " msecs.\n";
01925 }
01926 
01927 //--------------------------------------------------------------
01928 //: get a row from a BufferXY
01929 //
01930 void gevd_edgel_regions::get_buffer_row(unsigned int row)
01931 {
01932   if (!buf_source_)
01933     return;
01934   int x0 = (int)xo_, y0 = (int)row, xsize = (int)(xend_-xo_ + 1);
01935   for (int x = x0; x<xsize; x++)
01936   {
01937     switch (this->bytes_per_pix())
01938     {
01939      case 1:   // Grey scale image with one byte per pixel
01940       ubuf_[x]= bytePixel(buf_, x, y0);
01941       break;
01942      case 2:   // Grey scale image with an unsigned short per pixel
01943       sbuf_[x] = shortPixel(buf_, x, y0);
01944       break;
01945 
01946      default:
01947       vcl_cout<<"In gevd_edgel_rgions::get_row(): bytes/pixel not 1 or 2\n";
01948       return;
01949     }
01950   }
01951 }
01952 
01953 // ==== These routines were added to speed up the intensity face data fill ====
01954 
01955 //------------------------------------------------
01956 //: Get an image row
01957 void gevd_edgel_regions::get_image_row(unsigned int row)
01958 {
01959   if (!image_source_)
01960     return;
01961   int x0 = (int)xo_, y0 = (int)row, xsize = (int)(xend_-xo_ + 1);
01962 
01963   switch (this->bytes_per_pix())
01964   {
01965    case 1:     // Grey scale image with one byte per pixel
01966     image_->get_section(ubuf_, x0, y0, xsize, 1);
01967     break;
01968    case 2:     // Grey scale image with an unsigned short per pixel
01969     image_->get_section(sbuf_, x0, y0, xsize, 1);
01970     break;
01971 
01972    default:
01973     vcl_cout<<"In gevd_edgel_regions::get_row(): bytes/pixel not 1 or 2\n";
01974   }
01975 }
01976 
01977 //---------------------------------------------------------------
01978 //: Get the intensity of a single pixel
01979 unsigned short gevd_edgel_regions::get_intensity(unsigned int x)
01980 {
01981   unsigned short intensity = 0;
01982   switch (this->bytes_per_pix())
01983   {
01984    case 1:     // Grey scale image with one byte per pixel
01985     intensity = (unsigned short)ubuf_[X(x)];
01986     break;
01987    case 2:     // Grey scale image with an unsigned short per pixel
01988     intensity = sbuf_[X(x)];
01989     break;
01990    default:
01991     vcl_cout<<"In gevd_edgel_regions::get_intensity(): bytes/pixel not 1 or 2\n";
01992   }
01993   return intensity;
01994 }
01995 
01996 //---------------------------------------------------------------------
01997 //: Accumulate intensity statistics from each region and update the vtol_intensity_face parameters
01998 void gevd_edgel_regions::AccumulateMeans()
01999 {
02000   vul_timer t;
02001   unsigned int i;
02002   // Initialize the intensity face means
02003   for (i=min_region_label_; i<max_region_label_; i++)
02004     if (intensity_face_index_[i])
02005       intensity_face_index_[i]->ResetPixelData();
02006 
02007   int Npixels = 0;
02008   for (unsigned int y=yo_; y<=yend_; y++)
02009   {
02010     if (image_source_)
02011       this->get_image_row(y);
02012     if (buf_source_)
02013       this->get_buffer_row(y);
02014     for (unsigned int x=xo_; x<=xend_; x++)
02015     {
02016       unsigned int label = region_label_array_[Y(y)][X(x)];
02017       Npixels++;
02018       if (intensity_face_index_[label])
02019       {
02020         unsigned short intensity = this->get_intensity(x);
02021         float Ximg = float(x)+.5f, // coordinates are at the pixel center
02022               Yimg = float(y)+.5f;
02023         intensity_face_index_[label]->IncrementMeans(Ximg, Yimg, intensity);
02024       }
02025     }
02026   }
02027   int Nregions = max_region_label_ - min_region_label_;
02028   vcl_cout << "Accumulate Region Means(" << Nregions << ") in "
02029            << t.real() << " msecs.\n"
02030            << "Normalized Time = " << (10000.0*t.real())/Npixels << vcl_endl;
02031 }
02032 
02033 //---------------------------------------------------------------------
02034 //: Insert region pixels into the vtol_intensity_face arrays
02035 //
02036 void gevd_edgel_regions::AccumulateRegionData()
02037 {
02038   vul_timer t;
02039   // Initialize the intensity face pixel arrays
02040   for (unsigned int i = min_region_label_; i<max_region_label_; i++)
02041     if (intensity_face_index_[i])
02042       (intensity_face_index_[i])->InitPixelArrays();
02043   // Scan the image and insert intensities
02044   for (unsigned int y=yo_; y<=yend_; y++)
02045   {
02046     if (image_source_)
02047       this->get_image_row(y);
02048     if (buf_source_)
02049       this->get_buffer_row(y);
02050     for (unsigned int x=xo_; x<=xend_; x++)
02051     {
02052       unsigned int label = region_label_array_[Y(y)][X(x)];
02053       if (intensity_face_index_[label])
02054       {
02055         unsigned short intensity= this->get_intensity(x);
02056         // Set face pixel arrays
02057         vtol_intensity_face_sptr f = intensity_face_index_[label];
02058         float Ximg = float(x)+.5f;
02059         float Yimg = float(y)+.5f;
02060         f->InsertInPixelArrays(Ximg, Yimg, intensity);
02061       }
02062     }
02063   }
02064   vcl_cout << "Accumulate Region Data(" << max_region_label_ - min_region_label_
02065            << ") in " << t.real() << " msecs.\n";
02066 }
02067 
02068 //---------------------------------------------------------------------
02069 //:
02070 //    Do both a scatter matrix update and insertion into the region pixel
02071 //    arrays of each intensity face.  AccumulateScatterData is done first
02072 //    so that the number of pixels can be determined.
02073 //
02074 void gevd_edgel_regions::InsertFaceData()
02075 {
02076   this->AccumulateMeans();
02077   this->AccumulateRegionData();
02078 }