Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members

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 #endif
00062 
00063 //: Print the region label array
00064 void sdet_edgel_regions::print_region_array()
00065 {
00066   vcl_cout << vcl_endl << vcl_endl;
00067   for (unsigned int y = 0; y<ys_; y++)
00068   {
00069     for (unsigned int x = 0; x<xs_; x++)
00070       if (region_label_array_[y][x]==EDGE
00071           //&&edge_boundary_array_[Y(y)][X(x)]->IsVertex()
00072          )
00073         vcl_cout << '*';
00074       else
00075         vcl_cout << region_label_array_[y][x] << ' ';
00076     vcl_cout << vcl_endl;
00077   }
00078   vcl_cout << vcl_endl << vcl_endl;
00079 }
00080 
00081 //: Print the contents of the forward equivalence index
00082 void sdet_edgel_regions::print_region_equivalence()
00083 {
00084   vcl_cout << "\nLabel Equivalence:\n"
00085            << "------------------\n";
00086   vcl_map<unsigned int, vcl_vector<unsigned int>*>::iterator rpf_iterator;
00087   for (rpf_iterator= region_pairs_forward_.begin();
00088        rpf_iterator!=region_pairs_forward_.end(); rpf_iterator++)
00089   {
00090     vcl_cout << (*rpf_iterator).first << " == ";
00091     vcl_vector<unsigned int>* labels = (*rpf_iterator).second;
00092     if (labels)
00093     {
00094       for (vcl_vector<unsigned int>::iterator lit = labels->begin();
00095            lit != labels->end(); lit++)
00096         vcl_cout << *lit << ' ';
00097       vcl_cout << vcl_endl;
00098     }
00099   }
00100   vcl_cout << vcl_endl;
00101 }
00102 
00103 //: Print the contents of the reverse equivalence index
00104 void sdet_edgel_regions::print_reverse_region_equivalence()
00105 {
00106   vcl_cout << "\nReverse Label Equivalence:\n"
00107            << "--------------------------\n";
00108   vcl_map<unsigned int, vcl_vector<unsigned int>*>::iterator rpf_iterator;
00109   for (rpf_iterator= region_pairs_reverse_.begin();
00110        rpf_iterator!=region_pairs_reverse_.end(); rpf_iterator++)
00111   {
00112     vcl_cout << (*rpf_iterator).first << " == ";
00113     vcl_vector<unsigned int>* labels = (*rpf_iterator).second;
00114     if (labels)
00115     {
00116       for (vcl_vector<unsigned int>::iterator lit = labels->begin();
00117            lit != labels->end(); lit++)
00118         vcl_cout << *lit << ' ';
00119       vcl_cout << vcl_endl;
00120     }
00121   }
00122   vcl_cout << vcl_endl;
00123 }
00124 
00125 //: Print the reduced equivalence relation
00126 void sdet_edgel_regions::print_base_equivalence()
00127 {
00128   vcl_cout << "\nBase Label Equivalence:\n"
00129            << "-----------------------\n";
00130 
00131   for (unsigned int i = min_region_label_; i<max_region_label_; i++)
00132     vcl_cout << i << " == " << this->BaseLabel(i) << vcl_endl;
00133 }
00134 
00135 //: Print the fitted intensity data for all faces
00136 void sdet_edgel_regions::print_intensity_data()
00137 {
00138   for (vcl_vector<vtol_intensity_face_sptr>::iterator fit =faces_->begin();
00139        fit != faces_->end(); fit++)
00140   {
00141     vtol_intensity_face_sptr const & f = *fit;
00142     vcl_cout << "IntFaceAt(" << f->Xo() << ' ' << f->Yo() << "):\n";
00143     //      f->PrintFit();
00144   }
00145 }
00146 
00147 //--------------------------------------------------------------
00148 //: The region array can be offset from the corner of the ROI.
00149 //  This method transforms from the ROI coordinate
00150 //  system to the region label array coordinate system.
00151 unsigned int sdet_edgel_regions::X(unsigned int x)
00152 {
00153   return x-xo_;
00154 }
00155 
00156 //: The region array can be offset from the corner of the ROI.
00157 //  This method transforms from the ROI coordinate
00158 //  system to the region label array coordinate system.
00159 unsigned int sdet_edgel_regions::Y(unsigned int y)
00160 {
00161   return y-yo_;
00162 }
00163 
00164 //---------------------------------------------------------
00165 //: Transforms the image x coordinate to the array coordinate with a scale factor
00166 float sdet_edgel_regions::Xf(float x)
00167 {
00168   float xu = (x-xo_)*s_;
00169   return xu;
00170 }
00171 
00172 //---------------------------------------------------------
00173 //:
00174 float sdet_edgel_regions::Yf(float y)
00175 {
00176   float yu = (y-yo_)*s_;
00177   return yu;
00178 }
00179 
00180 //----------------------------------------------------------
00181 // Default constructor
00182 sdet_edgel_regions::sdet_edgel_regions(int array_scale,bool verbose,
00183                                        bool debug)
00184 {
00185   debug_ = debug;
00186   verbose_ = verbose;
00187   s_ = array_scale; //Some boundaries can approach less than 1/2 pixel proximity
00188 #ifdef DEBUG
00189   debug_data_ = debug_ ? new topo_debug_data : 0;
00190 #endif
00191   image_source_ = false;
00192   buf_source_ = false;
00193   buf_ = NULL;
00194   xo_=0;
00195   yo_=0;
00196   xend_ = 0;
00197   yend_ = 0;
00198   xs_ = 0;
00199   ys_ = 0;
00200   min_region_label_ = LABEL;
00201   max_region_label_ = LABEL;
00202   faces_ = new vcl_vector<vtol_intensity_face_sptr>;
00203   face_edge_index_ = NULL;
00204   intensity_face_index_ = NULL;
00205   failed_insertions_ = new vcl_vector<vtol_edge_2d_sptr>;
00206   ubuf_ = NULL;
00207   sbuf_ = NULL;
00208 }
00209 
00210 //----------------------------------------------------------
00211 // Default destructor
00212 sdet_edgel_regions::~sdet_edgel_regions()
00213 {
00214   if (face_edge_index_)
00215   {
00216     for (unsigned int i = 0; i<max_region_label_; i++)
00217       delete face_edge_index_[i];
00218     delete [] face_edge_index_;
00219   }
00220   delete failed_insertions_;
00221   delete [] ubuf_;
00222   delete [] sbuf_;
00223   //fix leaks
00224   delete faces_;
00225   delete [] intensity_face_index_;
00226 
00227   for (vcl_map<unsigned int, vcl_vector<vtol_edge_2d_sptr>* >::iterator
00228        mit = region_edge_adjacency_.begin();
00229        mit != region_edge_adjacency_.end(); mit++)
00230   {
00231     if ((*mit).second)
00232       (*mit).second->clear();
00233     delete (*mit).second;
00234   }
00235 
00236   for (vcl_map<unsigned int, vcl_vector<unsigned int>* >::iterator
00237        mit = equivalence_set_.begin(); mit != equivalence_set_.end(); mit++)
00238     delete (*mit).second;
00239 
00240   for (vcl_map<unsigned int, vcl_vector<unsigned int>* >::iterator
00241        mit = region_pairs_reverse_.begin();
00242        mit != region_pairs_reverse_.end(); mit++)
00243     delete (*mit).second;
00244 
00245   for (vcl_map<unsigned int, vcl_vector<unsigned int>* >::iterator
00246        mit = region_pairs_forward_.begin();
00247        mit != region_pairs_forward_.end(); mit++)
00248     delete (*mit).second;
00249 }
00250 
00251 bool sdet_edgel_regions::compute_edgel_regions(gevd_bufferxy* buf,
00252                                                vcl_vector<vtol_edge_2d_sptr>& sgrp,
00253                                                vcl_vector<vtol_intensity_face_sptr>& faces)
00254 {
00255   buf_ = buf;
00256   buf_source_=true;
00257   image_source_=false;
00258   return compute_edgel_regions(sgrp, faces);
00259 }
00260 
00261 //-----------------------------------------------------------------
00262 //: The key process loop.
00263 //  Carries out the steps:
00264 //  - Connected components
00265 //  - Edge-label assignment
00266 //  - Collect region boundaries
00267 //  - Construct vtol_intensity_faces
00268 //  - Calculate intensity fit
00269 bool sdet_edgel_regions::
00270 compute_edgel_regions(vil1_image const& image,
00271                       vcl_vector<vtol_edge_2d_sptr>& sgrp,
00272                       vcl_vector<vtol_intensity_face_sptr>& faces)
00273 {
00274 #if 0
00275   image_ = image;
00276   buf_ = NULL;
00277   image_source_=true;
00278   buf_source_ = false;
00279 #endif
00280   //change to uniform use of bufferxy for ease of interfacing to different
00281   //image types
00282   image_ = 0;
00283   image_source_=false;
00284   buf_source_ = false;
00285   buf_ = new gevd_bufferxy(image);
00286   if(buf_)
00287     buf_source_ = true;
00288   else
00289     return false;
00290   return compute_edgel_regions(sgrp, faces);
00291 }
00292 bool sdet_edgel_regions::
00293 compute_edgel_regions(vil_image_resource_sptr const& image,
00294                       vcl_vector<vtol_edge_2d_sptr>& sgrp,
00295                       vcl_vector<vtol_intensity_face_sptr>& faces)
00296 {
00297 #if 0
00298   image_ = image;
00299   buf_ = NULL;
00300   image_source_=true;
00301   buf_source_ = false;
00302 #endif
00303   //change to uniform use of bufferxy for ease of interfacing to different
00304   //image types
00305   image_ = 0;
00306   image_source_=false;
00307   buf_source_ = false;
00308   buf_ = new gevd_bufferxy(image);
00309   if(buf_)
00310     buf_source_ = true;
00311   else
00312     return false;
00313   return compute_edgel_regions(sgrp, faces);
00314 }
00315 
00316 bool sdet_edgel_regions::
00317 compute_edgel_regions(vcl_vector<vtol_edge_2d_sptr>& sgrp,
00318                       vcl_vector<vtol_intensity_face_sptr>& faces)
00319 {
00320 #ifdef DEBUG
00321   if (debug_data_)
00322   {
00323     debug_data_->clear();
00324     if (buf_source_)
00325       debug_data_->set_buf(buf_);
00326   }
00327 #endif
00328   vul_timer t;
00329   if (!sgrp.size())
00330     return false;
00331 
00332   //Set up the region label array with edge boundaries
00333   this->InitRegionArray(sgrp);
00334   if (debug_)
00335     this->print_region_array();
00336 
00337   unsigned int y, x;
00338   //Propagate connected components
00339   // the -1 accounts for the 2x2 label classification neighborhood
00340   for (y=0; y<ys_-1; y++)
00341     for (x=0; x<xs_-1; x++)
00342       this->UpdateConnectedNeighborhood(x,y);
00343 
00344   if (debug_)
00345     this->print_region_array();
00346   //Resolve region label equivalence
00347   if (debug_)
00348   {
00349     this->print_region_equivalence();
00350     this->print_reverse_region_equivalence();
00351   }
00352   this->GrowEquivalenceClasses();
00353   this->PropagateEquivalence();
00354   if (debug_)
00355     this->print_base_equivalence();
00356   this->ApplyRegionEquivalence();
00357   if (debug_)
00358     vcl_cout << "After Label Equivalence\n";
00359   if (debug_)
00360     this->print_region_array();
00361 
00362   //Associate Edge(s) with region labels (-1?)JLM
00363   for (y=0; y<ys_-1; y++)
00364     for (x=0; x<xs_-1; x++)
00365       this->AssignEdgeLabels(x, y);
00366 
00367   //Collect Edge(s) bounding each region
00368   this->CollectEdges();
00369   if (verbose_)
00370     vcl_cout << "Propagate Regions and Collect Edges("
00371              <<  max_region_label_-min_region_label_ << ") in "
00372              << t.real() << " msecs.\n"<< vcl_flush;
00373 
00374   //Collect Face-Edge associations
00375   this->CollectFaceEdges();
00376 
00377   //Construct vtol_intensity_faces
00378   this->ConstructFaces();
00379   if (!faces_||!faces_->size())
00380     return false;
00381 
00382   //Collect intensity data for each region
00383   this->InsertFaceData();
00384 
00385   if (debug_)
00386     this->print_intensity_data();
00387   //Output the result
00388   faces.clear();
00389   for (vcl_vector<vtol_intensity_face_sptr>::iterator fit = faces_->begin();
00390        fit != faces_->end(); fit++)
00391     faces.push_back(*fit);
00392 
00393   if (verbose_)
00394   vcl_cout << "Compute Edgel Regions Total(" << faces_->size() << ") in "
00395            << t.real() << " msecs.\n"<< vcl_flush;
00396   return true;
00397 }
00398 
00399 
00400 //----------------------------------------------------------
00401 //: assign equivalence of region label b to region label a
00402 //
00403 bool sdet_edgel_regions::InsertRegionEquivalence(unsigned int label_b,
00404                                                  unsigned int label_a)
00405 {
00406   bool result = true;
00407   result = result && this->add_to_forward(label_b, label_a);
00408   result = result && this->add_to_reverse(label_a, label_b);
00409   return result;
00410 }
00411 
00412 //--------------------------------------------------------------
00413 //: Get the most basic label equivalent to a given label.
00414 //  If the label_map_ is not defined, this function uses the
00415 //  forward label hash table.  Otherwise 0 is returned.
00416 unsigned int sdet_edgel_regions::BaseLabel(unsigned int label)
00417 {
00418   vcl_map<unsigned int, unsigned int >::iterator lmtest;
00419   lmtest = label_map_.find(label);
00420   if ( lmtest != label_map_.end() )
00421     return lmtest->second;
00422   else
00423     return 0;
00424 }
00425 
00426 //------------------------------------------------------------
00427 //: Return label image (255/0) indicating edgels.
00428 //  Paint the edgels into the region label array and then
00429 //  output an image where the value is 255 if the pixel is an
00430 //  edge, 0 otherwise
00431 vil1_image sdet_edgel_regions::GetEdgeImage(vcl_vector<vtol_edge_2d_sptr>& sg)
00432 {
00433   if (!this->InitRegionArray(sg)) return NULL;
00434   unsigned char no_edge = 0, edge = 255;
00435 
00436   vil1_memory_image_of<vxl_byte> image(xs_,ys_);
00437 
00438   for (unsigned int y = 0; y<ys_; y++)
00439     for (unsigned int x = 0; x<xs_; x++)
00440       if (region_label_array_[y][x] == EDGE)
00441         image[y][x] = edge;
00442       else
00443         image[y][x] = no_edge;
00444   return image;
00445 }
00446 
00447 //-----------------------------------------------------------
00448 //: Populate the label_map_ to reflect the equivalences between labels.
00449 void sdet_edgel_regions::PropagateEquivalence()
00450 {
00451   vcl_map<unsigned int, vcl_vector<unsigned int>* >::iterator  esi;
00452 
00453   for (esi = equivalence_set_.begin(); esi != equivalence_set_.end(); esi++)
00454   {
00455     unsigned int base = esi->first;
00456     vcl_vector<unsigned int>* labels = esi->second;
00457     if (!labels) continue;
00458     int len = labels->size();
00459     if (!len) continue;
00460     for (int i = 0; i<len; i++)
00461       label_map_[(*labels)[i]] = base;
00462   }
00463   for (unsigned int i = min_region_label_; i<max_region_label_; i++)
00464     if (label_map_.find(i) == label_map_.end())
00465       label_map_[i] = i;
00466 }
00467 
00468 //---------------------------------------------------------------------
00469 //: Find the set of labels equivalent to label from a given hash table and merge into equivalence_set_.
00470 //  cur_label is the equivalence set being formed. label is the table key of equivalences
00471 //  to be merged. The labels equivalent to label are in the input map, tab.
00472 bool sdet_edgel_regions::
00473 merge_equivalence(vcl_map<unsigned int, vcl_vector<unsigned int>* >& tab,
00474                   unsigned int cur_label,
00475                   unsigned int label)
00476 {
00477   vcl_map<unsigned int, vcl_vector<unsigned int>* >::iterator hashi;
00478   //If we can't find the label in tab then there are no equivalences to be merged
00479   hashi = tab.find(label);
00480   if (hashi == tab.end()) {
00481     return false;
00482   }
00483   //We did find label, and labels is a set of equivalent labels
00484   vcl_vector<unsigned int>* labels = hashi->second;
00485 
00486   //If the set is empty then nothing to do
00487   int len = labels->size();
00488   if (!len) {
00489     return false;
00490   }
00491 
00492   //The set of labels equivalent to cur_label
00493   vcl_vector<unsigned int>* array;
00494 
00495   hashi = equivalence_set_.find(cur_label);
00496   if ( hashi == equivalence_set_.end())
00497   {
00498     //We didn't find any equivalent labels for cur_label so we initialize a new one
00499     //and insert it into equivalence_set
00500     array = new vcl_vector<unsigned int>;
00501     equivalence_set_[cur_label] = array;
00502   }
00503   else
00504   {
00505     //otherwise there is already a growing set of equivalent labels
00506     array = hashi->second;
00507   }
00508 
00509   //We look through the set of labels found in map for label
00510   for (int i = 0; i<len; i++)
00511   {
00512     unsigned int l = (*labels)[i];
00513     bool found = false;
00514     //see if l is in the current set of equivalent labels for cur_label
00515     for (unsigned int j=0 ; j < array->size() ; j++)
00516     {
00517       if ((*array)[j] == l) found = true;
00518     }
00519     //If label l is not already there then add it
00520     if (!found)
00521     {
00522       array->push_back(l);
00523     }
00524   }
00525 
00526   return true;
00527 }
00528 
00529 //----------------------------------------------------------------
00530 //: Find the next label not accounted for in the current equivalence set.
00531 //  The set of labels is searched to find a label larger than label, but
00532 //  not in the set, labels.
00533 bool sdet_edgel_regions::get_next_label(vcl_vector<unsigned int>* labels,
00534                                         unsigned int& label)
00535 {
00536   //If the set labels is null then
00537   //just return the next larger label (if less than max_region_label_)
00538   unsigned int tmp = label+1;
00539   if (!labels)
00540     if (tmp<max_region_label_)
00541     {
00542       label = tmp;
00543       return true;
00544     }
00545 
00546   //The set is not empty, so search for a label not found in the
00547   //set.
00548 
00549   for (unsigned int i = tmp; i<max_region_label_; i++)
00550   {
00551     //if we don't find i we can use it as the new label
00552     if (vcl_find(labels->begin(), labels->end(), i) == labels->end())
00553     {
00554       label = i;
00555       return true;
00556     }
00557   }
00558   return false;
00559 }
00560 
00561 //----------------------------------------------------------------
00562 //: Form equivalence classes by transitive closure on each label.
00563 //  The resulting label equivalence is stored in the map, equivalence_set_.
00564 //
00565 //  The idea is to add labels to the current equivalence set, cur_set,
00566 //  from either forward or reverse equivalence classes until no
00567 //  new equivalences can be found.  The current equivalence class,
00568 //  cur_set, is repeatedly scanned when new labels are added to pick up
00569 //  new equivalence groups.  Old equivalence entries are removed from
00570 //  forward and reverse forward and reverse equivalence maps as they
00571 //  are used.  When the cur_set is completely closed, i.e. no new labels
00572 //  can be added, then a new label not in cur_set is used to
00573 //  seed a new equivalence class.
00574 //
00575 void sdet_edgel_regions::GrowEquivalenceClasses()
00576 {
00577   if ((max_region_label_-min_region_label_) < 2)
00578     return;
00579   //start with the minimum label
00580   unsigned int cur_label = min_region_label_;
00581   //the iterator for equivalence_set_
00582   vcl_map<unsigned int, vcl_vector<unsigned int>* >::iterator mei;
00583   while (true)
00584   {
00585     bool merging = true;
00586     vcl_vector<unsigned int>* cur_set = NULL;
00587     unsigned int i = cur_label;
00588     int len = 0;
00589     int old_len;
00590     while (merging)
00591     {
00592       old_len = len;
00593       merging = false;
00594 
00595       //find label equivalence in the forward map
00596       bool find_forward =
00597         this->merge_equivalence(region_pairs_forward_, cur_label, i);
00598       if (find_forward)
00599       {
00600         delete region_pairs_forward_[i];//memory leak otherwise
00601         region_pairs_forward_.erase(i);//remove hits from the forward map
00602       }
00603       //find label equivalence in the reverse map
00604       bool find_reverse =
00605         this->merge_equivalence(region_pairs_reverse_, cur_label, i);
00606       if (find_reverse)
00607       {
00608         delete region_pairs_reverse_[i];//memory leak otherwise
00609         region_pairs_reverse_.erase(i);//remove hits from the reverse map
00610       }
00611       //At this point we may have established or added to the equivalence set
00612       //for cur_label stored in equivalence_set[cur_label]
00613       //we check if we have
00614       mei = equivalence_set_.find(cur_label);
00615       if (mei == equivalence_set_.end()) continue;
00616       //If we don't find cur_label, it means that we couldn't find label i
00617       //in either region_pairs_forward or region_pairs_reverse, so we need
00618       //to get a new i.
00619 
00620       //We did find a growing equivalence set, cur_set, but it might be null
00621       //or empty
00622       cur_set = equivalence_set_[cur_label];
00623       if (!cur_set) continue;
00624       len = cur_set->size();
00625       if (!len) continue;
00626 
00627       //Now we check cur_set has actually been extended.
00628       //If it has we have to sort the labels so that we can find
00629       //the next larger label in cur_set easily
00630       if (len > old_len)
00631       {
00632         i = cur_label;
00633         vbl_qsort_ascending(*cur_set);//vcl_sort didn't seem to work!
00634       }
00635 
00636       //Get the next larger label from cur_set
00637       //so that we can insert its equivalent labels
00638       for (int j = 0; j<len&&!merging; j++)
00639         if ((*cur_set)[j]>i)
00640         {
00641           i = (*cur_set)[j];
00642           merging = true;
00643         }
00644       //If we reach here with merging = false then we have finished the
00645       //current equivalence class
00646     }
00647     //Find the next largest label that isn't in cur_set to seed the
00648     //next equivalence class
00649     if (!get_next_label(cur_set, cur_label)) return;
00650   }
00651 }
00652 
00653 //------------------------------------------------------------
00654 //: Check if the vtol_edge list sg (spatial group) contains edge(s) - NYI
00655 bool sdet_edgel_regions::GroupContainsEdges(vcl_vector<vtol_edge_2d_sptr>& /* sg */)
00656 {
00657 #if 0
00658   CoolString type(sg.GetSpatialGroupName());
00659   return type == CoolString("EdgelGroup") ||
00660     type == CoolString("FittedEdgeGroup");
00661 #endif
00662   return true; // TODO
00663 }
00664 
00665 
00666 //----------------------------------------------------------
00667 //: A utility for inserting an edgel into the region_label_array_.
00668 //  An edgel and a previous edgel in the chain are used to interpolate
00669 //  intermediate edgels to take account of pixel quantization
00670 bool sdet_edgel_regions::insert_edgel(float pre_x, float pre_y,
00671                                       float xedgel, float yedgel,
00672                                       sdet_region_edge_sptr const& re)
00673 {
00674   //Transform image pixel coordinates to array coordinates
00675   float pre_xf = Xf(pre_x), pre_yf = Yf(pre_y),
00676     xedgelf = Xf(xedgel), yedgelf = Yf(yedgel);
00677 
00678   float xf, yf;
00679   unsigned int xinterp, yinterp;
00680 
00681   bool edge_insert = false;
00682   bool init = true, done = false;
00683   while (bdgl_curve_algs::line_gen(pre_xf, pre_yf, xedgelf, yedgelf,
00684                                    init, done, xf, yf))
00685   {
00686     xinterp = (unsigned int)xf;
00687     yinterp = (unsigned int)yf;
00688     if (out_of_bounds(xinterp, yinterp))
00689     {
00690       vcl_cout << "In sdet_edgel_regions::insert_edgel - out of bounds "
00691                << "at array(" << xinterp << ' ' << yinterp << ")\n";
00692       continue;
00693     }
00694 
00695     region_label_array_[yinterp][xinterp] = EDGE;
00696 
00697     if (!re) continue;
00698     sdet_region_edge_sptr const& old_re =
00699       edge_boundary_array_[yinterp][xinterp];
00700     if (old_re&&old_re->get_edge())
00701     {
00702       edge_boundary_array_[yinterp][xinterp] = re;
00703       edge_insert = true;
00704     }
00705     if (!old_re)
00706     {
00707       edge_boundary_array_[yinterp][xinterp] = re;
00708       edge_insert = true;
00709     }
00710   }
00711   return edge_insert;
00712 }
00713 
00714 int sdet_edgel_regions::bytes_per_pix()
00715 {
00716   int bypp = 1;
00717   if (image_source_)
00718   {
00719     int bytes_per_comp = (image_.bits_per_component()+7)/8;
00720     bypp = image_.components() * bytes_per_comp;
00721   }
00722   if (buf_source_)
00723     bypp = buf_->GetBytesPixel();
00724   return bypp;
00725 }
00726 
00727 //-----------------------------------------------------------
00728 //: Initialize the region label array.
00729 //  There are three types of region label symbols:
00730 //  - UNLABELED - no label has yet been assigned,
00731 //  - EDGE, the existence of an edgel boundary pixel.
00732 //  - An unsigned integer which represents an existing region label.
00733 
00734 bool sdet_edgel_regions::InitRegionArray(vcl_vector< vtol_edge_2d_sptr>& sg)
00735 {
00736   if (!this->GroupContainsEdges(sg))
00737     return false;
00738   vsol_box_2d b = btol_edge_algs::bounding_box(sg);
00739   //Get the bounds for the arrays from the input edges
00740   xo_ = (unsigned int)b.get_min_x();
00741   yo_ = (unsigned int)b.get_min_y();
00742 
00743   xend_ = (unsigned int)b.get_max_x();
00744   yend_ = (unsigned int)b.get_max_y();
00745 
00746   xs_ = (this->GetXSize()-1)*s_+1;
00747   ys_ = (this->GetYSize()-1)*s_+1;
00748 
00749   //JLM debug
00750   vcl_cout << "bounding box(" << xo_ << ' ' << yo_ << ' ' << xs_ << ' ' << ys_
00751            << ")\n";
00752 
00753   //Construct the edge and label arrays
00754   edge_boundary_array_ = vbl_array_2d<sdet_region_edge_sptr>(ys_, xs_);
00755 
00756   region_label_array_ = vbl_array_2d<unsigned int>(ys_, xs_);
00757 
00758   //initialize
00759   region_label_array_.fill(UNLABELED);
00760   edge_boundary_array_.fill(NULL);
00761 
00762   switch (this->bytes_per_pix())
00763   {
00764    case 1:     // Grey scale image with one byte per pixel
00765     delete[] ubuf_; ubuf_ = new unsigned char[this->GetXSize()];
00766     break;
00767    case 2:     // Grey scale image with an unsigned short per pixel
00768     delete[] sbuf_; sbuf_ = new unsigned short[this->GetXSize()];
00769     break;
00770    default:
00771     vcl_cout<<"In vtol_intensity_face::get_intensity(): "
00772             << "bytes/pixel not 1 or 2\n";
00773   }
00774 
00775   //Initialize the buffers
00776   if (ubuf_)
00777     for (int x = 0; x<this->GetXSize(); ++x)
00778       ubuf_[x] = 0;
00779 
00780   if (sbuf_)
00781     for (int x = 0; x<this->GetXSize(); ++x)
00782       sbuf_[x] = 0;
00783 
00784   //Insert edgels into arrays.
00785   int counter=0;
00786   for (vcl_vector<vtol_edge_2d_sptr >::iterator sgit = sg.begin();
00787        sgit != sg.end(); sgit++)
00788   {
00789     vtol_edge_2d_sptr e = (*sgit);
00790     if (!e)
00791       continue;
00792     e->set_id(counter++);
00793     vdgl_digital_curve* dc = e->curve()->cast_to_vdgl_digital_curve();
00794     if (!dc)
00795       continue;
00796 
00797     //The sdet_region_edge enables the link between a region label and
00798     //an Edge from the input segmentation
00799     sdet_region_edge_sptr const & re = new sdet_region_edge(e);
00800     region_edges_[e->get_id()] = re;
00801 
00802     vdgl_edgel_chain_sptr xy= dc->get_interpolator()->get_edgel_chain();
00803 
00804     int n_edgels = xy->size();
00805 
00806     //Insert the vertices at the ends of the edge
00807     //If there is a gap between the vertex locations and the
00808     //nearest edgels, the insert_edgel function will generate
00809     //edge insertions to prevent any gaps in the region boundary
00810     //There shouldn't be DigitalCurve(s) with this defect but it
00811     //does seem to occur.
00812     sdet_region_edge_sptr const& vre = new sdet_region_edge(NULL);
00813     float pex1, pey1, pex2, pey2;
00814     if (n_edgels>0)
00815     {
00816       pex1 = float((*xy)[0].x()); pex2 = float((*xy)[n_edgels-1].x());
00817       pey1 = float((*xy)[0].y()); pey2 = float((*xy)[n_edgels-1].y());
00818       this->insert_edgel(pex1, pey1,
00819                          float(e->v1()->cast_to_vertex_2d()->x()),
00820                          float(e->v1()->cast_to_vertex_2d()->y()),
00821                          vre);
00822       this->insert_edgel(pex2, pey2,
00823                          float(e->v2()->cast_to_vertex_2d()->x()),
00824                          float(e->v2()->cast_to_vertex_2d()->y()),
00825                          vre);
00826     }
00827     else
00828     {
00829       pex1 = float(e->v1()->cast_to_vertex_2d()->x());
00830       pey1 = float(e->v1()->cast_to_vertex_2d()->y());
00831       pex2 = float(e->v2()->cast_to_vertex_2d()->x());
00832       pey2 = float(e->v2()->cast_to_vertex_2d()->y());
00833       this->insert_edgel(pex1, pey1, pex1, pey1, vre);
00834       this->insert_edgel(pex1, pey1, pex2, pey2, vre);
00835     }
00836 
00837     //Insert the edgels between the vertices
00838     //An edgel cannot be inserted on top of an existing vertex
00839     //insertion.  A vertex is distinguished by having a NULL Edge.
00840     //That is, for vertices it is ambiguous what Edge instance
00841     //exists at that location. Edge insertion fails if no edgels
00842     //of the Edge can be sucessfully inserted.
00843     bool edge_insert = false;
00844     for (int k =0; k < n_edgels; k++)
00845     {
00846       bool inserted = this->insert_edgel(pex1, pey1,
00847                                          float((*xy)[k].x()),
00848                                          float((*xy)[k].y()), re);
00849       edge_insert = edge_insert || inserted;
00850       pex1 = float((*xy)[k].x());
00851       pey1 = float((*xy)[k].y());
00852     }
00853     if (!edge_insert)
00854     {
00855       vcl_cout << "Edge Insert Failed for (" << e->v1() << ' '
00856                << e->v2() << ")N: "<< n_edgels << vcl_endl;
00857       failed_insertions_->push_back(e);
00858     }
00859   }
00860   return true;
00861 }
00862 
00863 //---------------------------------------------------------------
00864 //: Get code for a given label.
00865 unsigned char sdet_edgel_regions::label_code(unsigned int label)
00866 {
00867   unsigned char result;
00868   if (label<min_region_label_)
00869     result = label;
00870   else
00871     result = LABEL;
00872   return result;
00873 }
00874 
00875 //----------------------------------------------------------------
00876 //: Add a new pair to the forward equivalence list.
00877 //    That is, a ==> b. Note that there can be multiple equivalences which are
00878 //    stored in a vcl_vector
00879 bool sdet_edgel_regions::add_to_forward(unsigned int key, unsigned int value)
00880 {
00881   bool result = true;
00882   vcl_map<unsigned int, vcl_vector<unsigned int>* >::iterator rpfi;
00883   rpfi = region_pairs_forward_.find(key);
00884 
00885   if (rpfi !=region_pairs_forward_.end())
00886   {
00887     vcl_vector<unsigned int> * vec = region_pairs_forward_[key];
00888     bool found = false;
00889     for (unsigned int i =0 ; i < vec->size() ; i++)
00890     {
00891       if ((*vec)[i] == value)
00892         found = true;
00893     }
00894     if (!found)
00895     {
00896       vec->push_back(value);
00897     }
00898   }
00899   else
00900   {
00901     vcl_vector<unsigned int>* larray = new vcl_vector<unsigned int>;
00902     larray->push_back(value);
00903     region_pairs_forward_[key]=larray;
00904   }
00905   return result;
00906 }
00907 
00908 //----------------------------------------------------------------
00909 //: Add a new pair to the reverse equivalence list.
00910 //  That is, b==>a. Note that there can be multiple equivalences which are
00911 //  stored in a vcl_vector
00912 bool sdet_edgel_regions::add_to_reverse(unsigned int key, unsigned int value)
00913 {
00914   bool result = true;
00915   vcl_map<unsigned int, vcl_vector<unsigned int>* >::iterator rpfi;
00916   rpfi = region_pairs_reverse_.find(key);
00917 
00918   if (rpfi !=region_pairs_reverse_.end())
00919   {
00920     vcl_vector<unsigned int> * vec = region_pairs_reverse_[key];
00921     bool found = false;
00922     for (unsigned int i =0 ; i < vec->size() ; i++)
00923     {
00924       if ((*vec)[i] == value)
00925         found = true;
00926     }
00927     if (!found)
00928     {
00929       vec->push_back(value);
00930     }
00931   }
00932   else
00933   {
00934     vcl_vector<unsigned int>* larray = new vcl_vector<unsigned int>;
00935     larray->push_back(value);
00936     region_pairs_reverse_[key]=larray;
00937   }
00938   return result;
00939 }
00940 
00941 //-------------------------------------------------------------------
00942 //: Encode a 2x2 neighborhood with the state of the region array for a given location.
00943 //  \verbatim
00944 //    The Neighborhood    The states are:
00945 //         ul ur          UNLABELED, EDGE, LABEL
00946 //         ll lr              0       1      2
00947 //  \endverbatim
00948 //  The encoding maps the 2x2 pattern to an unsigned char.  The layout
00949 //  of the uchar is:  [ul|ur|ll|lr] with 2 bits for the state of each position.
00950 unsigned char
00951 sdet_edgel_regions::EncodeNeighborhood(unsigned int ul, unsigned int ur,
00952                                        unsigned int ll, unsigned int lr)
00953 {
00954   unsigned char nhood = 0;
00955 
00956   unsigned char nul = label_code(ul);
00957   nul = nul<<6;
00958   nhood |= nul;
00959 
00960   unsigned char nur = label_code(ur);
00961   nur = nur<<4;
00962   nhood |= nur;
00963 
00964   unsigned char nll = label_code(ll);
00965   nll = nll << 2;
00966   nhood |= nll;
00967 
00968   unsigned char nlr = label_code(lr);
00969   nhood |= nlr;
00970 
00971   return nhood;
00972 }
00973 
00974 //----------------------------------------------------------------------
00975 //: This is the fundamental assignment of label equivalence
00976 void sdet_edgel_regions::insert_equivalence(unsigned int ll, unsigned int ur, unsigned int& lr)
00977 {
00978   if (ll!=ur)//Is a=b?
00979   {//No. We want the smallest label to be the equivalence base
00980     //Also we don't want to loose earlier equivalences
00981     unsigned int smaller_label, larger_label;
00982     //Get the ordering right
00983     if (ll>ur) { smaller_label = ur; larger_label = ll; }
00984     else       { smaller_label = ll; larger_label = ur; }
00985     this->add_to_forward(larger_label, smaller_label);
00986     this->add_to_reverse(smaller_label, larger_label);
00987     lr = smaller_label;
00988   }
00989   else //yes, a=b the simple case
00990     lr = ur;
00991 }
00992 
00993 //-------------------------------------------------------------------
00994 //: Propagate connected components.
00995 //  Uses an unsigned char encoding
00996 //  a 2x2 neighborhood to propagate region labels. For example:
00997 //  \verbatim
00998 //  aa ->   aa
00999 //  xx ->   aa
01000 //  \endverbatim
01001 //  Here the lower two labels are set to the upper label.
01002 //  This method operates directly on the region_label_array_.
01003 //
01004 //  Note that the 2x2 neighborhood is encoded as uchar = [ul|ur|ll|lr]
01005 //                                                          2  2  2  2  bits
01006 void sdet_edgel_regions::UpdateConnectedNeighborhood(unsigned int x, unsigned int y)
01007 {
01008   unsigned int &ul = region_label_array_[y][x];
01009   unsigned int &ur = region_label_array_[y][x+1];
01010   unsigned int &ll = region_label_array_[y+1][x];
01011   unsigned int &lr = region_label_array_[y+1][x+1];
01012 
01013   unsigned char nhood = this->EncodeNeighborhood(ul, ur, ll, lr);
01014   switch (int(nhood))
01015   {
01016    case 0:
01017     //xx xx
01018     //xx xx
01019     return;
01020    case 1:
01021     //xx xx
01022     //xe xe
01023     return;
01024    case 5:
01025     //xx xx
01026     //ee ee
01027     return;
01028    case 17:
01029     //xe xe
01030     //xe xe
01031     return;
01032    case 20:
01033     //xe xe
01034     //ex ea
01035     lr = max_region_label_++;
01036     return;
01037    case 21:
01038     //xe xe
01039     //ee ee
01040     return;
01041    case 22:
01042     //xe xe
01043     //ea ea
01044     return;
01045    case 68:
01046     //ex ex
01047     //ex ex
01048     return;
01049    case 72:
01050     //ex ex
01051     //ax ax
01052     return;
01053    case 133:
01054     //ax aa
01055     //ee ee
01056     return;
01057    case 136:
01058     //ax ax
01059     //ax ax
01060     return;
01061    case 160:
01062     //aa aa
01063     //xx aa
01064     ll = ul;
01065     lr = ul;
01066     return;
01067    case 161:
01068     //aa aa
01069     //xe ae
01070     ll = ul;
01071     return;
01072    case 168:
01073     //aa aa
01074     //ax aa
01075     insert_equivalence(ll, ur, lr);
01076     return;
01077    case 169:
01078     //aa aa
01079     //ae ae
01080     return;
01081    case 164:
01082     //aa aa
01083     //ex ea
01084     lr = ul;
01085     return;
01086    case 165:
01087     //aa aa
01088     //ee ee
01089     return;
01090    case 144:
01091     //ae ae
01092     //xx aa
01093     ll = ul;
01094     lr = ul;
01095     return;
01096    case 145:
01097     //ae ae
01098     //xe ae
01099     ll = ul;
01100     return;
01101    case 152:
01102     //ae ae
01103     //ax aa
01104     lr = ul;
01105     return;
01106    case 153:
01107     //ae ae
01108     //ae ae
01109     return;
01110    case 148:
01111     //ae ae
01112     //ex eb
01113     lr = max_region_label_++;
01114     return;
01115    case 149:
01116     //ae ae
01117     //ee ee
01118     return;
01119    case 96:
01120     //ea ea
01121     //xx aa
01122     ll = ur;
01123     lr = ur;
01124     return;
01125    case 97:
01126     //ea ea
01127     //xe be
01128     ll = max_region_label_++;
01129     return;
01130    case 104:
01131     //ea ea
01132     //bx aa
01133     insert_equivalence(ll, ur, lr);
01134     return;
01135    case 105:
01136     //ea ea
01137     //ae ae
01138     return;
01139    case 100:
01140     //ea ea
01141     //ex ea
01142     lr = ur;
01143     return;
01144    case 101:
01145     //ea ea
01146     //ee ee
01147     return;
01148    case 80:
01149     //ee ee
01150     //xx bb
01151     ll = max_region_label_++;
01152     lr = ll;
01153     return;
01154    case 81:
01155     //ee ee
01156     //xe be
01157     ll = max_region_label_++;
01158     return;
01159    case 88:
01160     //ee ee
01161     //ax aa
01162     lr = ll;
01163     return;
01164    case 89:
01165     //ee ee
01166     //ae ae
01167     return;
01168    case 84:
01169     //ee ee
01170     //ex eb
01171     lr = max_region_label_++;
01172     return;
01173    case 85:
01174     //ee ee
01175     //ee ee
01176     return;
01177    default:
01178     vcl_cout << "In sdet_edgel_regions::UpdateNeigborhood(..)"
01179              << "impossible pattern(" << x << ' ' << y << ") = " << (int)nhood << '\n'
01180              << int(label_code(ul)) << ' ' << int(label_code(ur)) << '\n'
01181              << int(label_code(ll)) << ' ' << int(label_code(lr)) << "\n\n";
01182   }
01183 }
01184 
01185 static bool reg_edges_neq(sdet_region_edge_sptr