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