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