contrib/brl/bseg/sdet/sdet_contour.cxx

Go to the documentation of this file.
00001 // This is brl/bseg/sdet/sdet_contour.cxx
00002 #include "sdet_contour.h"
00003 //:
00004 // \file
00005 #include <vcl_iostream.h>
00006 #include <vcl_cstdlib.h>   // for vcl_abs(int) and vcl_qsort()
00007 #include <vcl_vector.h>
00008 #include <vcl_cmath.h>
00009 #include <vcl_algorithm.h> // for vcl_max()
00010 #include <vul/vul_timer.h>
00011 #include <vxl_config.h>
00012 #include <vnl/vnl_math.h> // for sqrt2
00013 #include <vdgl/vdgl_digital_curve_sptr.h>
00014 #include <vdgl/vdgl_digital_curve.h>
00015 #include <vdgl/vdgl_edgel_chain_sptr.h>
00016 #include <vdgl/vdgl_edgel_chain.h>
00017 #include <vdgl/vdgl_interpolator.h>
00018 #include <vdgl/vdgl_interpolator_linear.h>
00019 #include <vtol/vtol_vertex_2d.h>
00020 #include <vtol/vtol_edge_2d.h>
00021 #include <btol/btol_vertex_algs.h>
00022 #include <btol/btol_edge_algs.h>
00023 #include <bdgl/bdgl_curve_algs.h>
00024 #include <gevd/gevd_bufferxy.h>
00025 #include <gevd/gevd_pixel.h>
00026 
00027 #ifdef DEBUG
00028  bool sdet_contour::talkative_ = true;
00029  bool sdet_contour::debug_ = true;      // Print extensive debug messages
00030 #else
00031  bool sdet_contour::talkative_ = false; // By default contour is not silent.
00032  bool sdet_contour::debug_ = false;
00033 #endif
00034 
00035 const int INVALID = -1;
00036 
00037 // Use 8 directions, with 45 degree angle in between them.
00038 
00039 const vxl_byte TWOPI = 8, /* FULLPI = 4, */ HALFPI = 2 /* , QUARTERPI = 1 */;
00040 //const vxl_byte DIR0 = 8, DIR1 = 9, DIR2 = 10, DIR3 = 11;
00041 const int DIS[] = { 1, 1, 0,-1,-1,-1, 0, 1, // 8-connected neighbors
00042                     1, 1, 0,-1,-1,-1, 0, 1, // wrapped by 2PI to
00043                     1, 1, 0,-1,-1,-1, 0, 1};// avoid modulo operations.
00044 const int DJS[] = { 0, 1, 1, 1, 0,-1,-1,-1,
00045                     0, 1, 1, 1, 0,-1,-1,-1,
00046                     0, 1, 1, 1, 0,-1,-1,-1};
00047 
00048 //const int RDS[] = {0,-1, 1,-2, 2,-3, 3,-4, 4,-5, 5}; // radial search
00049 const int RIS[] = { 1, 0,-1, 0, // spiral search for 4/8-connected
00050                     1,-1,-1, 1, // neighbors
00051                     2, 0,-2, 0,
00052                     2, 1,-1,-2,
00053                     -2,-1, 1, 2,
00054                     2,-2,-2, 2,
00055                     3, 0,-3, 0,
00056                     3, 1,-1,-3,
00057                     -3,-1, 1, 3,
00058                     3, 2,-2,-3,
00059                     -3,-2, 2, 3,
00060                     4, 0,-4, 0};
00061 const int RJS[] = { 0, 1, 0,-1, // rotate CW, increasing radius
00062                     1, 1,-1,-1,
00063                     0, 2, 0,-2,
00064                     1, 2, 2, 1,
00065                     -1,-2,-2,-1,
00066                     2, 2,-2,-2,
00067                     0, 3, 0,-3,
00068                     1, 3, 3, 1,
00069                     -1,-3,-3,-1,
00070                     2, 3, 3, 2,
00071                     -2,-3,-3,-2,
00072                     0, 4, 0,-4};
00073 const int RNS[] = { 4, 8, 12, 20, 24, 28, 36, 44, 48}; // at distinct r
00074 const float RGS[] = { 1.f, 1.414213f, 2.f, 2.236067f, 2.828427f, // values of gap
00075                       3.f, 3.162277f, 3.605551f, 4.f};
00076 
00077 // - win32 - moved to here for MSVC++
00078 const int MINLENGTH = 3;        // minimum number of pixels for a chain
00079 const int FRAME = 4;            // border of image
00080 
00081 //: A container to support sorting of edge lengths
00082 // Will result in descending order according to length
00083 struct sdet_contour_edge
00084 {
00085   sdet_contour_edge () {}
00086 
00087   void set_edge(vtol_edge_2d_sptr const& e) {e_ = e;}
00088   vtol_edge_2d_sptr edge() {return e_;}
00089 
00090   double length() {return e_->curve()->length();}
00091 
00092  private:
00093   vtol_edge_2d_sptr e_;
00094 };
00095 
00096 //The sort compare function
00097 static int compare(sdet_contour_edge*  ea,
00098                    sdet_contour_edge*  eb)
00099 {
00100   if (ea->length() < eb->length())
00101     return +1;
00102   return -1;
00103 }
00104 
00105 //: Save parameters and create workspace for detecting contours.
00106 // Each contour must have at least 1 pixel above min_strength,
00107 // and its number of internal pixels must be above min_length.
00108 // This is a heuristic hysteresis scheme that prunes weak or short
00109 // isolated chains.
00110 // To join a weaker contour to a stronger contour, a junction must
00111 // have a change in response above min_jump on the stronger contour.
00112 // This way, only strong junctions are detected.
00113 sdet_contour::sdet_contour(float min_strength, int min_length,
00114                            float min_jump, float max_gap_in)
00115   : minStrength(min_strength), minLength(min_length),
00116     minJump(min_jump), maxSpiral(0),
00117     edgeMap(), vertexMap()
00118 {
00119   if (minStrength < 0)
00120   {
00121     vcl_cerr << "sdet_contour::sdet_contour -- negative min_strength: "
00122              << minStrength << ". Reset to 0.\n";
00123     minStrength = 0;
00124   }
00125   if (minLength < MINLENGTH)
00126   {
00127     vcl_cerr << "sdet_contour::sdet_contour -- too small min_length: "
00128              << minLength << ". Reset to " << MINLENGTH << ".\n";
00129     minLength = MINLENGTH;
00130   }
00131   if (minJump < 0)
00132   {
00133     vcl_cerr << "sdet_contour::sdet_contour -- negative min_jump: "
00134              << minJump << ". Reset to 0.\n";
00135     minJump = 0;
00136   }
00137   if (minJump > minStrength)
00138   {
00139     vcl_cerr << "sdet_contour::sdet_contour -- too large min_jump: "
00140              << min_jump << ". Reset to " << minStrength << ".\n";
00141     minJump = minStrength;
00142   }
00143   if (max_gap_in < 1)
00144   {
00145     vcl_cerr << "sdet_contour::sdet_contour -- too small max_gap: "
00146              << max_gap_in << ". Reset to 1.\n";
00147     max_gap_in = 1;
00148   }
00149   if (max_gap_in > FRAME)
00150   {
00151     vcl_cerr << "sdet_contour::sdet_contour -- too large max_gap: "
00152              << max_gap_in << ". Reset to " << FRAME << vcl_endl;
00153     max_gap_in = FRAME;
00154   }
00155   max_gap = max_gap_in;
00156   for (int i = 0; i < 9; i++)   // find number of neighbors to search
00157     if (max_gap <= RGS[i])      // for given gap radius
00158       maxSpiral= i+1;
00159 }
00160 
00161 
00162 //: Free space allocated for detecting contours.
00163 sdet_contour::~sdet_contour()
00164 {
00165   delete edgeMap;               // space shared by LinkJunction/Chain
00166   delete vertexMap;
00167 }
00168 
00169 
00170 //: Find network of linked edges and vertices, from 8-connected edge elements.
00171 // The contours must be less than 2 pixel wide,
00172 // for example found from non maximum suppression.
00173 // Isolated edgels and short segments are erased.
00174 bool
00175 sdet_contour::FindNetwork(gevd_bufferxy& edgels, bool junctionp,
00176                           const int njunction,
00177                           const int* junctionx, const int* junctiony,
00178                           vcl_vector<vtol_edge_2d_sptr>*& edges,
00179                           vcl_vector<vtol_vertex_2d_sptr >*& vertices)
00180 {
00181   // make sure that if no edges are found that edges and vertices
00182   // get values, to avoid seg faults, WAH
00183   if (!edges)
00184     edges = new vcl_vector<vtol_edge_2d_sptr>;
00185   else
00186     edges->clear();
00187   if (!vertices)
00188     vertices = new vcl_vector<vtol_vertex_2d_sptr >;
00189   else
00190     vertices->clear();
00191 
00192 
00193   if (this->talkative_)
00194     vcl_cout << "*** Link edge elements into connected edges/vertices.\n";
00195 
00196   // 1. Setup lookup maps based on (x,y) integer location.
00197   vertexMap = new vbl_array_2d<vtol_vertex_2d_sptr>(edgels.GetSizeX(), edgels.GetSizeY());
00198   vertexMap->fill(NULL);
00199   edgeMap = new vbl_array_2d<vtol_edge_2d_sptr>(edgels.GetSizeX(), edgels.GetSizeY());
00200   edgeMap->fill(NULL);
00201 
00202   // 2. Collect 4/8-connected pixels into chains
00203   int n; // = vcl_max(10*njunction, // preallocated size from junctions or
00204   //       edgels.GetSizeX()*edgels.GetSizeY()/100); // image size
00205   vcl_vector<vtol_edge_2d_sptr> *edges2 = new vcl_vector<vtol_edge_2d_sptr>;
00206   n = this->FindChains(edgels, // link pixels into chains
00207                        njunction, // also use junction pixels
00208                        junctionx, junctiony,
00209                        *edges2);
00210   if (!n)
00211     return false;               // empty network
00212   if (junctionp) {
00213     // 3. Sort chains longest first.
00214     if (edges2->size() < 10000)     // don't sort if too many edges
00215     {
00216       sdet_contour_edge* edge_array = new sdet_contour_edge[edges2->size()];
00217       int i =0;
00218       for (vcl_vector<vtol_edge_2d_sptr>::iterator eit = edges2->begin();
00219            eit != edges2->end(); eit++,i++)
00220       {
00221         edge_array[i].set_edge(*eit);
00222       }
00223       vcl_qsort(edge_array, i, sizeof(sdet_contour_edge) ,
00224                 (int (*)(const void *, const void *))&compare);
00225       edges2->clear();
00226       for (int j = 0; j<i; j++)
00227         edges2->push_back(edge_array[j].edge());
00228       delete [] edge_array;
00229     }
00230 
00231     // renumber with order in array
00232     for (unsigned int i= 0; i< edges2->size(); i++)
00233       (*edges2)[i]->set_id(i);
00234 
00235 
00236     // 4. Split/Merge chains from touching end points
00237     vcl_vector<vtol_vertex_2d_sptr > vertices2;
00238 
00239     this->FindJunctions(edgels, // break/merge at junctions of
00240                         *edges2, vertices2); // distinct chains
00241     for (unsigned int i=0; i< vertices2.size(); i++)
00242       vertices->push_back( vertices2[i]);
00243   }
00244 
00245   // 5. Copy back results into global lists
00246   for (unsigned int i= 0; i< edges2->size(); i++)
00247     edges->push_back( (*edges2)[i]);
00248 
00249   //eliminate memory leaks
00250   edges2->clear();
00251   delete edges2;
00252 
00253   return true;
00254 }
00255 
00256 
00257 //: Return TRUE if pixel is a local maximum, and so is right on top of contour.
00258 static bool
00259 on_contour(const gevd_bufferxy& edgels, const int i, const int j)
00260 {
00261   double pix = (1 + vnl_math::sqrt2) * floatPixel(edgels, i, j); // fuzzy threshold
00262   for (vxl_byte dir = 0; dir < TWOPI; dir += HALFPI) // 4-connected only
00263     if (floatPixel(edgels, i+DIS[dir], j+DJS[dir]) > pix)
00264       return false;             // should choose neighbor instead
00265   return true;
00266 }
00267 
00268 
00269 //: Delete pixel from contour, and save its location in xloc/yloc.
00270 static void
00271 RecordPixel(int i, int j, gevd_bufferxy& edgels,
00272             vcl_vector<int>& iloc, vcl_vector<int>& jloc)
00273 {
00274   //JLM
00275   // This doesn't work if we record the same pixel twice
00276   //  floatPixel(edgels, i, j) = -floatPixel(edgels, i, j); // flip sign
00277   //  The following asserts that a pixel has been used and subsequent
00278   //  applications of RecordPixel cannot undo the used state.
00279   floatPixel(edgels, i, j) = -1;
00280   iloc.push_back(i), jloc.push_back(j);
00281 #ifdef DEBUG
00282   if (sdet_contour::debug_)
00283     vcl_cout << "Recording (" << i << ' ' << j << ")\n";
00284 #endif
00285 }
00286 
00287 //:
00288 // Delete the last pixel added to iloc and jloc
00289 //
00290 void
00291 ErasePixel(vcl_vector<int>& xloc, vcl_vector<int>& yloc)
00292 {
00293   vcl_vector<int>::iterator xit = xloc.end();
00294   vcl_vector<int>::iterator yit = yloc.end();
00295   xloc.erase(xit-1);
00296   yloc.erase(yit-1);
00297 }
00298 
00299 
00300 //:
00301 // Find next best pixel on contour, searching for strongest response,
00302 // and favoring 4-connected over 8-connected.
00303 // Return 0, if no pixel is found, or direction in range [2*pi, 4*pi).
00304 static int
00305 NextPixel(int& i, int& j, const gevd_bufferxy& edgels)
00306 {
00307   float maxpix = 0, npix;
00308   int maxdir = 0, dir;
00309   for (dir = 0; dir < TWOPI; dir += HALFPI) // 4-connected first
00310     if ((npix = floatPixel(edgels, i+DIS[dir], j+DJS[dir])) > maxpix)
00311     {
00312       maxpix = npix;
00313       maxdir = dir+TWOPI;
00314     }
00315   if (!maxdir)
00316   {
00317     for (dir = 1; dir < TWOPI; dir += HALFPI) // 8-connected next
00318       if ((npix = floatPixel(edgels, i+DIS[dir], j+DJS[dir])) > maxpix)
00319       {
00320         maxpix = npix;
00321         maxdir = dir+TWOPI;
00322       }
00323   }
00324   if (maxdir)                   // update next strongest pixel
00325     i += DIS[maxdir], j += DJS[maxdir];
00326   return maxdir;
00327 }
00328 
00329 
00330 //:
00331 // Find next best pixel on contour, searching for strongest response,
00332 // and favoring 4-connected over 8-connected.
00333 // Return 0, if no pixel is found, or direction in range [2*pi, 4*pi).
00334 static int
00335 next_pixel(int& i, int& j, const vbl_array_2d<vtol_vertex_2d_sptr>& vertexMap)
00336 {
00337   int maxdir = 0, dir;
00338   for (dir = 0; dir < TWOPI; dir += HALFPI) // 4-connected first
00339     if (vertexMap.get(i+DIS[dir], j+DJS[dir]))
00340     {
00341       maxdir = dir+TWOPI;
00342       break;
00343     }
00344   if (!maxdir)
00345   {
00346     for (dir = 1; dir < TWOPI; dir += HALFPI) // 8-connected next
00347       if (vertexMap.get(i+DIS[dir], j+DJS[dir]))
00348       {
00349         maxdir = dir+TWOPI;
00350         break;
00351       }
00352   }
00353   if (maxdir)                   // update next strongest pixel
00354     i += DIS[maxdir], j += DJS[maxdir];
00355   return maxdir;
00356 }
00357 
00358 
00359 //:
00360 // Trace and collect pixels on thin contours, stronger pixels first,
00361 // and favoring 4-connected over 8-connected. Thinning is not used,
00362 // and so will avoid errors because of square grid tessellation.
00363 // A chain can not cross itself. It can only touch itself or another
00364 // chain, in which case a junction will be found later.
00365 // The pixels of a chain include the 2 end points.
00366 // End points and junctions are created in sdet_contour::FindJunctions.
00367 // Return the number of chains found.  Protected.
00368 int
00369 sdet_contour::FindChains(gevd_bufferxy& edgels, const int njunction,
00370                          const int* junctionx, const int* junctiony,
00371                          vcl_vector<vtol_edge_2d_sptr>& edges)
00372 {
00373   vul_timer t;
00374 
00375   // 1. Save away detected junctions from extending at end points of
00376   // contours, without linking these contours up. This avoids random
00377   // order in the traversal of the contours.
00378   vtol_vertex_2d_sptr mark = new vtol_vertex_2d;      // dummy non zero pointer
00379   for (int k = 0; k < njunction; k++)
00380     vertexMap->put(junctionx[k], junctiony[k], mark);
00381 
00382   // 2. Trace elongated & thinned chains, stronger pixels first.
00383   // Virtual border of image should be inserted last.
00384   const int rmax = FRAME;
00385   const int xmax = edgels.GetSizeX()-rmax-1;
00386   const int ymax = edgels.GetSizeY()-rmax-1;
00387   vcl_vector<int> xloc(xmax+ymax), yloc(xmax+ymax); // work space for
00388 
00389   for (int j = rmax; j <= ymax; j++)
00390     for (int i = rmax; i <= xmax; i++)
00391     {
00392       // 2.0. Start from better pixels above noise+hysteresis
00393       if (floatPixel(edgels, i, j) > minStrength &&
00394           on_contour(edgels, i, j))    // right on the contour
00395       {
00396         int x = i, y = j;
00397 
00398         // 2.1. Prune isolated pixels
00399         if (!NextPixel(x, y, edgels))  // prune isolated pixels
00400         {
00401           floatPixel(edgels, i, j) = 0;
00402           continue;
00403         }
00404         // 2.2. Start collecting first 3 pixels
00405         xloc.clear(), yloc.clear(); // collect pixels on contour
00406         RecordPixel(i, j, edgels, xloc, yloc);  // first pixel
00407         int ii = x, jj = y;
00408         RecordPixel(ii, jj, edgels, xloc, yloc); // second pixel
00409         if (NextPixel(x, y, edgels))
00410           RecordPixel(x, y, edgels, xloc, yloc); // third pixel
00411         else {                  // reach end point
00412           x = i, y = j;         // revert back to start pt
00413           if (NextPixel(x, y, edgels)) { // reverse collection
00414             xloc.clear(), yloc.clear();
00415             RecordPixel(ii, jj, edgels, xloc, yloc); // second pixel
00416             RecordPixel(i, j, edgels, xloc, yloc); // first pixel
00417             RecordPixel(x, y, edgels, xloc, yloc); // third pixel
00418             ii = i, jj = j;
00419           } else  {             // reach other end point
00420             floatPixel(edgels, i, j) = 0; // prune isolated pixel-pairs
00421             floatPixel(edgels, ii, jj) = 0;
00422             continue;
00423           }
00424         }
00425 
00426         // 2.3. Watch out for zig-zag at 2nd pixel, from LR-TD scans
00427         //Check to see if the contour doubles back on itself
00428         //if so, eliminate the middle pixel causing the jag
00429         int dprod = (x - ii)*(ii - xloc[0]) + (y - jj)*(jj - yloc[0]);
00430         if (dprod < 0)
00431         {
00432           if (sdet_contour::debug_)
00433             vcl_cout << "dps(" << xloc[0] << ' ' << yloc[0] << ")(" << xloc[1]
00434                      << ' ' << yloc[1] << ")(" << x << ' ' << y << ")= "
00435                      << dprod << '\n' << vcl_flush;
00436           //Replace the 2nd pixel in the chain with x-y
00437           ErasePixel(xloc, yloc);
00438           ErasePixel(xloc, yloc);
00439           RecordPixel(x, y, edgels, xloc, yloc);
00440         }
00441         // 2.4. Collect both directions & extension points if 1-chain
00442         // trace along first dir, 4-connected and stronger first
00443         // Scanning forward --->
00444         int niii = ii, njjj = jj;//the i-2 pixel
00445         int nii = x, njj=y;
00446         while (NextPixel(x, y, edgels))
00447         {
00448           //Check to see if the contour doubles back on itself
00449           //if so, eliminate the middle pixel causing the jag
00450           dprod = (x - nii)*(nii - niii) + (y - njj)*(njj - njjj);
00451           if (dprod < 0)
00452           {
00453             if (sdet_contour::debug_)
00454               vcl_cout << "dpf(" << niii << ' ' << njjj << ")(" << nii << ' '
00455                        << njj << ")(" << x << ' ' << y << ")= " << dprod
00456                        << '\n' << vcl_flush;
00457             //Erase the last pixel and replace it with (x, y)
00458             ErasePixel(xloc,  yloc);
00459             RecordPixel(x, y,edgels, xloc, yloc);
00460           }
00461           else
00462             RecordPixel(x, y, edgels, xloc, yloc);
00463           niii = nii; njjj = njj;
00464           nii = x; njj = y;
00465         }
00466         // disjoint first/last pixel
00467         // so must be an open chain with different end points
00468         if (vcl_abs(xloc[0]-x) > 1 ||
00469             vcl_abs(yloc[0]-y) > 1)
00470         {
00471           // include a vertex location if
00472           // there was one detected at the end of the chain
00473           if (next_pixel(x, y, *vertexMap))
00474             xloc.push_back(x), yloc.push_back(y);
00475 
00476           // start again from first pixel
00477 
00478           x = xloc[0], y = yloc[0];
00479 
00480           //reversing the vectors, xloc and yloc
00481           vcl_vector<int> xloctemp( xloc.size()), yloctemp( yloc.size());
00482           for (unsigned int iii=0; iii< xloc.size(); iii++)
00483             xloctemp[iii]= xloc[xloc.size()-1-iii];
00484           for (unsigned int jjj=0; jjj< yloc.size(); jjj++)
00485             yloctemp[jjj]= yloc[yloc.size()-1-jjj];
00486 
00487           //now copy the reversed vector back into xloc, yloc.
00488           for (unsigned int jk=0; jk<xloc.size(); jk++)
00489             xloc[jk]=xloctemp[jk];
00490           for (unsigned int jk=0; jk<yloc.size(); jk++)
00491             yloc[jk]=yloctemp[jk];
00492 
00493           // Scanning backwards from the first point <----
00494           int il = xloc.size();
00495           nii = xloc[il-1];
00496           njj = yloc[il-1];
00497           niii = xloc[il-2];
00498           njjj = yloc[il-2];
00499           while (NextPixel(x, y, edgels)) // trace along other dir
00500           {
00501             //Check to see if the contour doubles back on itself
00502             //if so, eliminate the middle pixel causing the jag
00503             dprod = (x - nii)*(nii - niii)+(y - njj)*(njj - njjj);
00504             if (dprod < 0)
00505             {
00506               if (sdet_contour::debug_)
00507                 vcl_cout << "dpr(" << niii << ' ' << njjj << ")(" << nii << ' '
00508                          << njj << ")(" << x << ' ' << y << ")= " << dprod
00509                          << '\n' << vcl_flush;
00510               //Erase the last pixel and replace it with (x, y)
00511               ErasePixel(xloc, yloc);
00512               RecordPixel(x, y, edgels, xloc, yloc);
00513             }
00514             else
00515               RecordPixel(x, y, edgels, xloc, yloc);
00516             niii = nii; njjj = njj;
00517             nii = x; njj = y;
00518           }
00519           // add in an edgel for the junction at the end
00520           // if it exists.
00521           if (next_pixel(x, y, *vertexMap))
00522             xloc.push_back(x), yloc.push_back(y); // detected junctions
00523         }
00524         int len = xloc.size();
00525         // 2.5. Check for isolated contours that are too short
00526         if (len < minLength) {  // zero or too few internal pixels
00527           for (int k = 0; k < len; k++) // zero or too few internal pixels
00528             floatPixel(edgels, xloc[k], yloc[k]) = 0; // prune short chains
00529           continue;
00530         }
00531 
00532         // 2.6. Create topological network of chains, touching,
00533         //      possibly ending at same junction, but never
00534         //      crossing one another
00535         vtol_edge_2d_sptr edge = new vtol_edge_2d();
00536         vdgl_edgel_chain_sptr ec = new vdgl_edgel_chain;
00537         vdgl_interpolator_sptr it = new vdgl_interpolator_linear(ec);
00538         vdgl_digital_curve_sptr dc = new vdgl_digital_curve(it);
00539 
00540         for (int k=0; k< len; k++)
00541         {
00542           x= xloc[k];
00543           y= yloc[k];
00544           ec->add_edgel( vdgl_edgel( x, y));
00545           edgeMap->put(x, y, edge);
00546         }
00547         edge->set_curve(*dc->cast_to_curve());
00548         LookupTableInsert(edges, edge);
00549       }
00550     }
00551   // 3. Restore cache to original state
00552   //    Placeholder vertices had been added to
00553   //    flag junctions but will be replaced with
00554   //    actual vertices in a later step
00555   for (int k = 0; k < njunction; k++)  // clear all void*/float labels
00556     vertexMap->put(junctionx[k], junctiony[k],NULL);
00557   for (int j = rmax; j <= ymax; j++)
00558     for (int i = rmax; i <= xmax; i++)
00559       if (floatPixel(edgels, i, j) < 0) // undo marks placed by RecordPixel
00560         floatPixel(edgels, i, j) = - floatPixel(edgels, i, j);
00561 
00562   if (talkative_)
00563     vcl_cout << "Find " << edges.size()
00564              << " chains/cycles, with pixels > " << minLength
00565              << " and strength > " << minStrength
00566              << ", in " << t.real() << " msecs.\n";
00567 
00568   return edges.size();  // number of chains found so far
00569 }
00570 
00571 
00572 //:
00573 // The inputs are: endv, edgels, maxSpiral, and edgeMap.
00574 // The outputs are: index, weaker and stronger.
00575 // endv is a vertex corresponding to a dangling end of an edge.
00576 // i.) If the end vertex is bounding more than one edge, the routine
00577 //     returns false.
00578 // ii.) Otherwise a spiral search is carried out around the end with a radius
00579 // given by maxSpiral.  Some of the nearby points on the edge connected to endv,
00580 // are erased so that they are not found in the search.
00581 // iii.) The edgel with maximum strength is found.  If there is none, the
00582 //       routine returns false.
00583 // iv.) The edge containing the found edgel is called "stronger" and the
00584 //      the location on that edge where the edgel was found is "index"
00585 bool sdet_contour:: DetectJunction(vtol_vertex_2d_sptr const& endv, int& index,
00586                                    vtol_edge_2d_sptr& weaker,
00587                                    vtol_edge_2d_sptr& stronger,
00588                                    const int maxSpiral,
00589                                    const gevd_bufferxy& edgels)
00590 {
00591   // 0. Must be an end point of a dangling 1-chain
00592   if (endv->numsup() > 1)         // avoid junction and 1-cycle
00593     return false;
00594   vcl_vector<vtol_edge_sptr> edges; endv->edges(edges);
00595   weaker = edges[0]->cast_to_edge_2d();      // dangling edge must be a weaker contour
00596   vdgl_digital_curve_sptr dc = weaker->curve()->cast_to_vdgl_digital_curve();
00597 
00598   const int len = dc->get_interpolator()->get_edgel_chain()->size();
00599 
00600   // 1. Mark off pixels at end pt to find junction of a contour to itself
00601   //Erase the edge pointers for rfuzz positions in the edgeMap corresponding
00602   //to the last rfuzz edgels in the weaker edge.  It looks like "labels"
00603   //caches the old edge pointers
00604   const int rfuzz = vcl_min(len, 3*MINLENGTH);
00605   vtol_edge_2d_sptr* labels = new vtol_edge_2d_sptr[rfuzz];
00606   //make sure the "end" of the edge corresponds to the correct end of the
00607   //edgel chain, i.e. "endv" might be either v1 or v2 -- the first or last
00608   //point on the edgel chain.
00609   if (endv == weaker->v1()->cast_to_vertex_2d())    //erase the first part
00610     for (int r = 0; r < rfuzz; r++)
00611     {
00612       vdgl_edgel edgel= dc->get_interpolator()->get_edgel_chain()->edgel( r);
00613       labels[r] = edgeMap->get( int(edgel.get_x()), int(edgel.get_y()));
00614       edgeMap->put(int(edgel.get_x()), int(edgel.get_y()), NULL);
00615     }
00616   else //erase the last part
00617     for (int r = 0; r < rfuzz; r++)
00618     {
00619       vdgl_edgel edgel= dc->get_interpolator()->get_edgel_chain()->edgel(len-1-r);
00620       labels[r] = edgeMap->get( int( edgel.get_x()), int( edgel.get_y()));
00621       edgeMap->put(int(edgel.get_x()), int(edgel.get_y()), NULL);
00622     }
00623 
00624   // 2. Find another stronger contour touched by this end point < gap.
00625   //Sprial around the end location, increasing the radius
00626   //searching for the strongest edge strength on some other chain
00627   //It can't be near the end of the weaker chain nearby since we
00628   //erased the pixels corresponding to it.
00629   stronger = NULL;              // contour can join with itself
00630   int jx = int(endv->x()), jy = int(endv->y());
00631   for (int l = 0, n = 0; l < maxSpiral; l++)    // increasing radius of spiral
00632   {
00633     float maxpix = 0; int maxn = 0;     // strongest strength at this radius
00634     for (; n < RNS[l]; n++)
00635     {
00636       int x = jx+RIS[n], y = jy+RJS[n];
00637       if (edgeMap->get(x, y) && // find another contour or itself
00638           floatPixel(edgels, x, y) > maxpix)
00639       {
00640         maxpix = floatPixel(edgels, x, y);
00641         maxn = n;               // better neighbor
00642       }
00643     }
00644     if (maxpix) {               // location of junction on contour
00645       stronger = edgeMap->get(jx+RIS[maxn], jy+RJS[maxn]);
00646       jx += RIS[maxn], jy += RJS[maxn];
00647       break;
00648     }
00649   }
00650   // restore edgeMap around end point (undo step 1)
00651   if (endv == weaker->v1()->cast_to_vertex_2d())
00652     for (int r=0; r< rfuzz; r++)
00653     {
00654       vdgl_edgel edge= dc->get_interpolator()->get_edgel_chain()->edgel(r);
00655       edgeMap->put(int( edge.get_x()), int( edge.get_y()), labels[r]);
00656     }
00657   else
00658     for (int r=0; r< rfuzz; r++)
00659     {
00660       vdgl_edgel edgel= dc->get_interpolator()->get_edgel_chain()->edgel(len-1-r);
00661       edgeMap->put(int( edgel.get_x()), int( edgel.get_y()),labels[r]);
00662     }
00663   delete [] labels;
00664 
00665   if (!stronger)                // do not find any edge in search region
00666     return false;
00667 
00668   // 3. Find index location of junction on this contour
00669   // We have found an edgel on a "stronger" edge at location maxn on the
00670   // search spiral, i.e. at jx and jy.
00671   index = int(INVALID);
00672   vdgl_digital_curve_sptr dc2 =(stronger->curve()->cast_to_vdgl_digital_curve());
00673   vdgl_edgel_chain_sptr ec = dc2->get_interpolator()->get_edgel_chain();
00674   index = bdgl_curve_algs::closest_point(ec, jx, jy);
00675   //
00676   //If we are within s pixels of either end then don't bother to split the
00677   //edge unless the stronger curve is a cycle without a vertex
00678   //In the case of a cycle there is no real origin to be used as
00679   //a junction later during merging tests
00680   const int s = 3;
00681   if ((index<=s || index+s+1 > (int)ec->size())&&
00682       stronger->v1()&&stronger->v2())
00683     return false;
00684   if (sdet_contour::debug_)
00685     vcl_cout << "Closest index to (" << endv->x() << ' '
00686              << endv->y() << ") is " << index
00687              << " corresponding to " << ec->edgel(index)
00688              << "size = " << ec->size() << vcl_endl;
00689 
00690   return true;
00691 }
00692 
00693 //: Move a junction to lie on the intersecting digital curve
00694 //  Refine the intersection position to double precision
00695 bool sdet_contour::move_junction(vtol_vertex_2d_sptr const& junction,
00696                                  int& index,
00697                                  vdgl_digital_curve_sptr const & dc)
00698 {
00699   if (!junction)
00700     return false;
00701   int jx = int(junction->x()), jy = int(junction->y());
00702   vertexMap->put(jx, jy, NULL); // erase old location
00703   //get new location
00704   vdgl_edgel_chain_sptr ec = dc->get_interpolator()->get_edgel_chain();
00705   jx = int((*ec)[index].x());
00706   jy = int((*ec)[index].y());
00707   //move the junction
00708   junction->set_x(jx), junction->set_y(jy); // update new vertex location
00709 
00710   //fill out the arrays
00711   vertexMap->put(jx, jy, junction);
00712   edgeMap->put(jx, jy, NULL);
00713   return true;
00714 }
00715 
00716 //:
00717 // when a vertex position is moved, an edge's edgel chain must potentially
00718 // be replaced.  old_x and old_y is the original end position.
00719 // It is possible that the vertex can move up to 4 pixels.  The new
00720 // position is the location of v.
00721 // Edgels are added from the end of the old digital_curve to the new
00722 // vertex position.
00723 void sdet_contour::update_edgel_chain(vtol_edge_2d_sptr const& edge,
00724                                       const int old_x, const int old_y,
00725                                       vtol_vertex_2d_sptr& v)
00726 {
00727   if (!edge||!v)
00728   {
00729     vcl_cout << "In update_edgel_chain - null inputs\n";
00730     return;
00731   }
00732   //The new vertex position
00733   double x = v->x(), y = v->y();
00734   //Access the old edgel chain
00735   vdgl_digital_curve_sptr dc_old= edge->curve()->cast_to_vdgl_digital_curve();
00736   vdgl_edgel_chain_sptr ec_old= dc_old->get_interpolator()->get_edgel_chain();
00737   int N = ec_old->size();
00738   //Create a new digital curve
00739   vdgl_edgel_chain_sptr  ec = new vdgl_edgel_chain;
00740   vdgl_interpolator_sptr it = new vdgl_interpolator_linear(ec);
00741   vsol_curve_2d_sptr dc = new vdgl_digital_curve(it);
00742 
00743   // Cases
00744   // A. The edge is a cycle
00745   if (edge->v1()==edge->v2())
00746   {
00747     vcl_cout << "Cycle case not implemented\n";
00748     return;
00749   }
00750   // B. The edge is open
00751   // Determine which end of the digital curve is closest to v
00752   //  int end_index = bdgl_curve_algs::closest_end(ec_old, x, y);
00753   //  if (end_index == 0)
00754   if (v==edge->v1()->cast_to_vertex_2d())
00755   {    //index = 0
00756     //vcl_cout << "update at v1\n";
00757     //start the chain with the new vertex location
00758     vdgl_edgel ed(x, y, bdgl_curve_algs::synthetic);//mark as synthetic edgel
00759 
00760     ec->add_edgel(ed);
00761 
00762     //add in a linear segment to reach old location
00763     int npix =
00764       bdgl_curve_algs::add_straight_edgels(ec, old_x, old_y,
00765                                            sdet_contour::debug_);
00766 
00767     if (!npix)
00768       return;//nothing was needed
00769 
00770     //mark the edge map at the new edgel locations
00771     for (int i=1; i<npix; i++)
00772       edgeMap->put(int((*ec)[i].x()),int((*ec)[i].y()),edge);
00773 
00774     //fill out the rest of the edgel chain
00775     for (int index = 0; index<N; index++)
00776       ec->add_edgel((*ec_old)[index]);
00777 
00778     //replace the curve on the edge
00779     edge->set_curve(*dc);
00780     return;
00781   }
00782 
00783   if (v==edge->v2()->cast_to_vertex_2d())
00784   {
00785     //vcl_cout << "update at v2\n";
00786     //copy the chain
00787     for (int index = 0; index<N; index++)
00788       ec->add_edgel((*ec_old)[index]);
00789 
00790     //Add in a linear segment to reach to new vertex location
00791     //from old vertex location, (*ec_old)[N-1].
00792     int npix =
00793       bdgl_curve_algs::add_straight_edgels(ec, x, y,
00794                                            sdet_contour::debug_);
00795 
00796     if (!npix)
00797       return;//nothing was needed
00798     //mark the edge map at the new locations
00799     for (int i=N; i<N+npix; i++)
00800       edgeMap->put(int((*ec)[i].x()),int((*ec)[i].y()),edge);
00801 
00802     //replace the curve on the edge
00803     edge->set_curve(*dc);
00804     return;
00805   }
00806 }
00807 
00808 void fill_cycle_gap(vdgl_edgel_chain_sptr const & ec)
00809 {
00810   if (!ec)
00811     return;
00812   int x0 = int((*ec)[0].x()), y0 = int((*ec)[0].y());
00813   bdgl_curve_algs::add_straight_edgels(ec, x0, y0,
00814                                        sdet_contour::debug_);
00815 }
00816 
00817 #if 0 // unused local function
00818 static bool
00819 ConfirmJunctionOnCycle(int index, float threshold,
00820                        vtol_edge_2d& cycle, const gevd_bufferxy& edgels)
00821 {
00822   if (sdet_contour::debug_)
00823     vcl_cerr << "ConfirmJunctionOnCycle() not run: returning 'TRUE'\n";
00824 
00825 #if 1 // JLM
00826   return true;
00827 #else
00828   vdgl_digital_curve_sptr dc = cycle.curve()->cast_to_vdgl_digital_curve();
00829   const int len = dc->get_interpolator()->get_edgel_chain()->size();
00830   const int wrap = 10*len;      // for positive index
00831   const int radius = 3;         // gap < 3, around junction pixel
00832 
00833   for (int n = index-radius; n <= index+radius; n++)
00834   {
00835     int nm = (n-1+wrap)%len;    // modulo operations to wrap at borders
00836     int np = (n+1+wrap)%len;
00837 
00838     vdgl_edgel edgel_m= dc->get_interpolator()->get_edgel_chain()->edgel( nm);
00839     vdgl_edgel edgel_p= dc->get_interpolator()->get_edgel_chain()->edgel( np);
00840 
00841     if (vcl_fabs(floatPixel(edgels, int( edgel_p.x()), int( edgel_p.y())) -
00842                  floatPixel(edgels, int( edgel_m.x()), int( edgel_m.y())))
00843         > threshold)
00844       return true;
00845   }
00846   return false;
00847 #endif // 1
00848 }
00849 #endif // 0
00850 
00851 //:
00852 // Break the cycle at given index, and create new cycle from/to
00853 // and not including index pixel.
00854 //
00855 //           stronger (no vertex initially)
00856 //         ------------
00857 //         |          |
00858 //         |          |
00859 // 0-------0 junction |
00860 //         |          |
00861 //         |          |
00862 //         ------------
00863 //             split -  the new edge
00864 //
00865 void sdet_contour::BreakCycle(vtol_vertex_2d_sptr const& junction,
00866                               int& index, vtol_edge_2d_sptr const& stronger,
00867                               vtol_edge_2d_sptr & split)
00868 {
00869   //Get the old curve
00870   vdgl_digital_curve_sptr old_dc =
00871     (stronger->curve()->cast_to_vdgl_digital_curve());
00872   vdgl_edgel_chain_sptr old_ec = old_dc->get_interpolator()->get_edgel_chain();
00873   const int N = old_ec->size();
00874 
00875   // 1. Move location of junction
00876   move_junction(junction, index, old_dc);
00877 
00878   // 2. Create a new edge (a cycle)
00879   split = new vtol_edge_2d();
00880 
00881   //  The new curve
00882   vdgl_edgel_chain* es = new vdgl_edgel_chain;
00883   vdgl_interpolator* it =
00884     new vdgl_interpolator_linear(vdgl_edgel_chain_sptr(es));
00885   vdgl_digital_curve *ds =
00886     new vdgl_digital_curve( vdgl_interpolator_sptr( it));
00887   split->set_curve(*ds);
00888 
00889   //insert edgels from index to N-1
00890   //starting at v1()
00891   for (int k = index; k <N; k++)
00892   {
00893     es->add_edgel((*old_ec)[k]);
00894     int x = int((*old_ec)[k].x()), y = int((*old_ec)[k].y());
00895     edgeMap->put(x, y, split);
00896     if (sdet_contour::debug_)
00897       vcl_cout << "BreakCycle: edge1 edgel at (" << x << ' ' << y << ")\n";
00898   }
00899   //insert edgels from 0 to and including index
00900   for (int k = 0; k <= index; k++)
00901   {
00902     es->add_edgel((*old_ec)[k]);
00903     int x = int((*old_ec)[k].x()), y = int((*old_ec)[k].y());
00904     edgeMap->put(x, y, split);
00905     if (sdet_contour::debug_)
00906       vcl_cout << "BreakCycle: edge1 edgel at (" << x << ' ' << y << ")\n";
00907   }
00908 
00909   split->set_v1(junction->cast_to_vertex());
00910   split->set_v2(junction->cast_to_vertex());
00911   int x = int(junction->x());
00912   int y = int(junction->y());
00913   vertexMap->put(x, y, junction);
00914   //stronger is no longer of interest to v1 and v2.
00915   //  btol_edge_algs::unlink_all_inferiors_twoway(stronger); done in lookup tab
00916 }
00917 
00918 #if 0 // unused local function
00919 //: Confirm there is a strong jump in response near a junction.
00920 // The location of this jump is however inaccurate, and so junctions
00921 // can not be localized accurately along the stronger chain.
00922 static bool
00923 ConfirmJunctionOnChain(int index, float threshold,
00924                        vtol_edge_2d& chain, const gevd_bufferxy& edgels)
00925 {
00926   if (sdet_contour::debug_)
00927     vcl_cerr << "ConfirmJunctionOnChain() not run: returning 'TRUE'\n";
00928 
00929 #if 1 // JLM
00930   return true;
00931 #else
00932   vdgl_digital_curve_sptr dc = chain.curve()->cast_to_vdgl_digital_curve();
00933   const int len = dc->get_interpolator()->get_edgel_chain()->size()-1;
00934 
00935   if (len < 2*MINLENGTH-1) // will merge vertices instead of
00936     return false;          // breaking up chains
00937 
00938   const int fuzz = MINLENGTH-1; // from min length of broken chains
00939   const int radius = 3;         // gap < 3, around junction pixel
00940   //search a neighborhood around index on the input chain
00941   //for long chains this amounts to index+-radius
00942   for (int n = vcl_max(index-radius, fuzz); n <= vcl_min(index+radius,len-1-fuzz); n++)
00943   {
00944     //for each point in the neighborhood of index
00945     //get edgels on each side
00946     vdgl_edgel cp1= dc->get_interpolator()->get_edgel_chain()->edgel(n+1);
00947     vdgl_edgel cm1= dc->get_interpolator()->get_edgel_chain()->edgel(n-1);
00948     //if there is a location where the difference is above
00949     // a threshold then the junction can be formed.
00950     if (vcl_fabs(floatPixel(edgels, int(cp1.x()), int(cp1.y())) -
00951                  floatPixel(edgels, int(cm1.x()), int(cm1.y())))
00952         > threshold)
00953     {
00954       return true;
00955     }
00956   }
00957   return false;
00958 #endif // 1
00959 }
00960 #endif // 0
00961 
00962 vtol_vertex_2d_sptr get_vertex_at_index(vtol_edge_2d_sptr& e, int index)
00963 {
00964   vdgl_digital_curve_sptr dc = e->curve()->cast_to_vdgl_digital_curve();
00965   if (!dc)
00966     return 0;
00967   vdgl_edgel ed = dc->get_interpolator()->get_edgel_chain()->edgel( index);
00968   vtol_vertex_2d_sptr v = new vtol_vertex_2d(ed.x(), ed.y());
00969   return v;
00970 }
00971 
00972 bool find_vertex(vtol_vertex_2d_sptr& v,
00973                  vcl_vector<vtol_vertex_2d_sptr>& vertices)
00974 {
00975   for (vcl_vector<vtol_vertex_2d_sptr>::iterator vit = vertices.begin();
00976        vit != vertices.end(); vit++)
00977     if ((*vit)==v)
00978       return true;
00979   return false;
00980 }
00981 
00982 bool find_edge(vtol_edge_2d_sptr& e,
00983                vcl_vector<vtol_edge_2d_sptr>& edges)
00984 {
00985   for (vcl_vector<vtol_edge_2d_sptr>::iterator eit = edges.begin();
00986        eit != edges.end(); eit++)
00987     if ((*eit)==e)
00988       return true;
00989   return false;
00990 }
00991 
00992 void print_edge_lookup_table(vcl_vector<vtol_edge_2d_sptr>& edges)
00993 {
00994   int ei=0;
00995   for (vcl_vector<vtol_edge_2d_sptr>::iterator eit = edges.begin();
00996        eit != edges.end(); eit++, ei++)
00997   {
00998     if (!*eit)
00999     {
01000       vcl_cout << "edge[" << ei << "]= null\n";
01001       continue;
01002     }
01003     vcl_cout<< "edge["<< ei << "]= " << **eit
01004             << *((*eit)->v1()->cast_to_vertex_2d())
01005             << ' ' << *((*eit)->v2()->cast_to_vertex_2d()) << '\n';
01006   }
01007 }
01008 
01009 //: Break the edge at given index, and create two subchains from it.
01010 //
01011 //               junction
01012 //  0---------------o----------------------0
01013 //                index                  nedgels-1
01014 //       edge1                edge2
01015 //
01016 //
01017 void sdet_contour::BreakChain(vtol_vertex_2d_sptr const& junction,
01018                               int& index,
01019                               vtol_edge_2d_sptr const& stronger,
01020                               vtol_edge_2d_sptr& longer,
01021                               vtol_edge_2d_sptr& shorter)
01022 {
01023   vdgl_digital_curve_sptr dc = stronger->curve()->cast_to_vdgl_digital_curve();
01024 
01025   const int N = dc->get_interpolator()->get_edgel_chain()->size();
01026 
01027   // 1. Move the location of junction to lie on stronger's digital_curve
01028   move_junction(junction, index, dc);
01029 
01030   // 2. Create first subchain up to and including junction pixel.
01031   vtol_edge_2d_sptr edge1 = new vtol_edge_2d();
01032   vdgl_edgel_chain *ec= new vdgl_edgel_chain;
01033   vdgl_interpolator *it= new vdgl_interpolator_linear( ec);
01034   vdgl_digital_curve *dc1 = new vdgl_digital_curve( it);
01035   edge1->set_curve(*dc1);
01036 
01037   //insert the edgels in first subchain, edge1
01038   // include index in edge 1
01039   vdgl_edgel_chain_sptr cxy= dc->get_interpolator()->get_edgel_chain();
01040   vdgl_edgel_chain *cxy1= ec;
01041   for (int k = 0; k <= index; k++)
01042   {
01043     cxy1->add_edgel( (*cxy)[k] );
01044     (*cxy1)[k] = (*cxy)[k];
01045     int x = int((*cxy1)[k].x()), y = int((*cxy1)[k].y());
01046     edgeMap->put(x , y,  edge1);
01047     if (sdet_contour::debug_)
01048       vcl_cout << "BreakChain: edge1 edgel at (" << x << ' ' << y << ")\n";
01049   }
01050 
01051   //set the vertices of edge 1
01052   // have to get rid of stronger from the list of superiors of v1
01053   edge1->set_v1(stronger->v1()->cast_to_vertex());
01054 
01055   // junction keeps its original superiors, + edge1
01056   edge1->set_v2(junction->cast_to_vertex());
01057 
01058   //mark vertex and edge arrays for edge 1
01059   int x11 = int(edge1->v1()->cast_to_vertex_2d()->x());
01060   int y11 = int(edge1->v1()->cast_to_vertex_2d()->y());
01061   int x12 = int(edge1->v2()->cast_to_vertex_2d()->x());
01062   int y12 = int(edge1->v2()->cast_to_vertex_2d()->y());
01063   edgeMap->put(x11, y11, NULL);
01064   edgeMap->put(x12, y12, NULL);
01065   vertexMap->put(x11, y11, edge1->v1()->cast_to_vertex_2d());
01066   vertexMap->put(x12, y12, edge1->v2()->cast_to_vertex_2d());
01067 
01068   // 3. Create second subchain from and including junction pixel.
01069   vtol_edge_2d_sptr edge2 = new vtol_edge_2d();    // create second subchain
01070   vdgl_edgel_chain *ec2= new vdgl_edgel_chain;
01071   vdgl_interpolator *it2= new vdgl_interpolator_linear( ec2);
01072   vdgl_digital_curve *dc2= new vdgl_digital_curve( it2);
01073   edge2->set_curve(*dc2);
01074 
01075   //insert the edgels into edge2
01076   //start at index since that edgel will be v1 of edge2
01077   vdgl_edgel_chain *cxy2= ec2;
01078   for (int k = index; k < N; k++)
01079   {
01080     cxy2->add_edgel((*cxy)[k]);
01081     int x = int((*cxy)[k].x()), y = int((*cxy)[k].y());
01082     edgeMap->put( x, y, edge2);
01083     if (sdet_contour::debug_)
01084       vcl_cout << "BreakChain: edge2 edgel at (" << x << ' ' << y << ")\n";
01085   }
01086 
01087   // have to remove stronger from superiors of v2
01088   edge2->set_v2(stronger->v2()->cast_to_vertex());
01089   // junction keeps the orginal superiors + edge2
01090   edge2->set_v1(junction->cast_to_vertex());
01091 
01092   //mark vertex and edge arrays for edge 2
01093   int x21 = int(edge2->v1()->cast_to_vertex_2d()->x());
01094   int y21 = int(edge2->v1()->cast_to_vertex_2d()->y());
01095   int x22 = int(edge2->v2()->cast_to_vertex_2d()->x());
01096   int y22 = int(edge2->v2()->cast_to_vertex_2d()->y());
01097   edgeMap->put(x21, y21, NULL);
01098   edgeMap->put(x22, y22, NULL);
01099   vertexMap->put(x21, y21, edge2->v1()->cast_to_vertex_2d());
01100   vertexMap->put(x22, y22, edge2->v2()->cast_to_vertex_2d());
01101 
01102   //Here is where we get rid of the stale superior (stronger) of v1 and v2
01103 
01104   //  btol_edge_algs::unlink_all_inferiors_twoway(stronger);
01105   // done in lookup table
01106   if (cxy1->size() >= cxy2->size())  // sort longer/shorter chains
01107     longer = edge1, shorter = edge2;
01108   else
01109     longer = edge2, shorter = edge1;
01110 }
01111 
01112 
01113 //: Break the chain at given index, and create a loop.
01114 // This case occurs when the junction is caused by a chain touching itself
01115 //
01116 //      straight     junction
01117 //  0-------------------0--------
01118 //                      |       |  curled
01119 //                      |       |
01120 //                      ---------
01121 void
01122 sdet_contour::LoopChain(vtol_vertex_2d_sptr const& junction, int& index,
01123                         vtol_edge_2d_sptr const& chain,
01124                         vtol_edge_2d_sptr& straight,
01125                         vtol_edge_2d_sptr& curled)
01126 {
01127   vdgl_digital_curve_sptr dc = chain->curve()->cast_to_vdgl_digital_curve();
01128   vdgl_edgel_chain_sptr cxy= dc->get_interpolator()->get_edgel_chain();
01129   const int N = cxy->size();
01130 
01131   // 1. Move location of junction
01132   int old_x = int(junction->x()), old_y = int(junction->y());
01133   move_junction(junction, index, dc);
01134 
01135   // 2. Find straight/curled chains
01136   straight = new vtol_edge_2d(), curled = new vtol_edge_2d();
01137 
01138   //
01139   // The touching end of chain is v1 so
01140   // first subchain is curled and forms a cycle
01141   //         v1 index    v2
01142   //   -------0----------0
01143   //  |       x
01144   //  |       | potential gap
01145   //   --------
01146   //    curled
01147   if (junction == chain->v1()->cast_to_vertex_2d())
01148   {
01149     vdgl_edgel_chain *ec= new vdgl_edgel_chain;
01150     vdgl_interpolator *it= new vdgl_interpolator_linear( ec);
01151     vdgl_digital_curve *c= new vdgl_digital_curve( it);
01152     curled->set_curve(*c);
01153     vdgl_edgel_chain *xy= ec;
01154 
01155     //fill in potential gap starting at index
01156     if (!(int(junction->x())==old_x&&int(junction->y())==old_y))
01157     {
01158       //add an edgel at index
01159       ec->add_edgel(vdgl_edgel((*cxy)[index].x(), (*cxy)[index].y()));
01160 
01161       //add in a linear segment to reach old v1's position
01162       int npix =
01163         bdgl_curve_algs::add_straight_edgels(ec, old_x, old_y,
01164                                              sdet_contour::debug_);
01165 
01166       //mark the edge map at the new edgel locations
01167       for (int i=1; i<npix; i++)
01168         edgeMap->put(int((*xy)[i].x()),int((*xy)[i].y()),curled);
01169     }
01170     //include index as other endpoint of curled
01171     for (int k = 0; k <= index; k++)
01172     {
01173       xy->add_edgel( (*cxy)[k] );
01174       edgeMap->put( int((*cxy)[k].x()), int((*cxy)[k].y()), curled);
01175     }
01176     //same v1 and v2 since curled is a cycle
01177     curled->set_v1(junction->cast_to_vertex());
01178     curled->set_v2(junction->cast_to_vertex());
01179     int x = int(junction->x()), y = int(junction->y());
01180     edgeMap->put(x, y, NULL);
01181     vertexMap->put(x, y, junction);
01182     //
01183     //define the straight section (ends in v2)
01184     //
01185     ec= new vdgl_edgel_chain;
01186     it= new vdgl_interpolator_linear( ec);
01187     c = new vdgl_digital_curve( it);    // second subchain is straight
01188     straight->set_curve(*c);
01189     xy= ec;
01190     //start at index
01191     for (int k = index; k < N; k++)
01192     {
01193       xy->add_edgel( (*cxy)[k] );
01194       edgeMap->put( int((*cxy)[k].x()), int((*cxy)[k].y()), straight);
01195     }
01196     //set vertices of new straight section
01197     straight->set_v1(junction->cast_to_vertex());
01198     straight->set_v2(chain->v2());
01199 
01200     //fill out maps
01201     x = int(straight->v2()->cast_to_vertex_2d()->x());
01202     y = int(straight->v2()->cast_to_vertex_2d()->y());
01203     edgeMap->put(x, y, NULL);
01204     vertexMap->put(x, y, straight->v2()->cast_to_vertex_2d());
01205   }
01206   else // The first subchain is straight, second is curled
01207   {
01208     //
01209     // v1         v2 index
01210     //  0-----------0--------
01211     //   potential  x        |
01212     //      gap     |        |
01213     //               --------
01214     //                 curled
01215     vdgl_edgel_chain *ec= new vdgl_edgel_chain;
01216     vdgl_interpolator *it= new vdgl_interpolator_linear( ec);
01217     vdgl_digital_curve *c= new vdgl_digital_curve( it);
01218     straight->set_curve(*c);
01219     vdgl_edgel_chain *xy= ec;
01220     //include index in the straight section
01221     for (int k = 0; k <=index; k++)
01222     {
01223       xy->add_edgel( (*cxy)[k] );
01224       edgeMap->put( int((*cxy)[k].x()), int((*cxy)[k].y()), straight);
01225     }
01226 
01227     //set the vertices of straight
01228     straight->set_v1(chain->v1());
01229     straight->set_v2(junction->cast_to_vertex());
01230 
01231     //fill out the maps
01232     int x = int(straight->v1()->cast_to_vertex_2d()->x());
01233     int y = int(straight->v1()->cast_to_vertex_2d()->y());
01234     edgeMap->put(x, y, NULL);
01235     vertexMap->put(x, y, straight->v1()->cast_to_vertex_2d());
01236 
01237     //construct the curled section
01238     ec= new vdgl_edgel_chain;
01239     it= new vdgl_interpolator_linear( ec);
01240     c = new vdgl_digital_curve( it);    // second subchain is curled
01241     curled->set_curve(*c);
01242     xy = ec;
01243 
01244     int nc = 0;//length of curled section up to gap
01245     // start at index
01246     for (int k = index; k < N; k++, nc++)
01247     {
01248       xy->add_edgel( (*cxy)[k] );
01249       edgeMap->put( int((*cxy)[k].x()), int((*cxy)[k].y()), curled);
01250     }
01251 
01252     //fill in potential gap starting at v2
01253     if (!(int(junction->x())==old_x&&int(junction->y())==old_y))
01254     {
01255       //add in a linear segment to reach new junction position
01256       int new_x = int(junction->x()), new_y = int(junction->y());
01257       int npix =
01258         bdgl_curve_algs::add_straight_edgels(ec, new_x, new_y,
01259                                              sdet_contour::debug_);
01260       //mark the edge map at the new edgel locations
01261       for (int i=0; i<npix; i++)
01262         edgeMap->put(int((*xy)[nc+i].x()),int((*xy)[nc+i].y()),curled);
01263     }
01264 
01265     // set the vertices of curled
01266     curled->set_v1(junction->cast_to_vertex());
01267     curled->set_v2(junction->cast_to_vertex());
01268 
01269     //fill out the maps
01270     x = int(junction->x());
01271     y = int(junction->y());
01272     edgeMap->put(x, y, NULL);
01273     vertexMap->put(x, y, junction);
01274   }
01275   //done in lookup table
01276   //btol_edge_algs::unlink_all_inferiors_twoway(chain);
01277 }
01278 
01279 //: Determine if a vertex is in the border strip.
01280 //  The strip supports the edge detection kernel
01281 //
01282 bool sdet_contour::near_border(vtol_vertex_2d_sptr const&  v)
01283 {
01284   const int xmin = FRAME;
01285   const int ymin = FRAME;
01286   const int xmax = vertexMap->rows()-FRAME-1;
01287   const int ymax = vertexMap->columns()-FRAME-1;
01288   int x = int(v->x()), y = int(v->y());
01289   return x<=xmin||x>=xmax||y<=ymin||y>=ymax;
01290 }
01291 
01292 //:
01293 // Detect touching another junction or end point,
01294 // from an end point of a dangling chain by
01295 // searching in a spiral pattern.
01296 // Find the neighboring vertex with the largest number of
01297 // incident edges.
01298 //
01299 vtol_vertex_2d_sptr
01300 sdet_contour::DetectTouch(vtol_vertex_2d_sptr const& endv,
01301                           const int maxSpiral)
01302 {
01303   const int jx = int(endv->x()), jy = int(endv->y());
01304   for (int l = 0, n = 0; l < maxSpiral; l++)    // increasing radius of spiral
01305   {
01306     int bx=0, by=0;
01307     vtol_vertex_2d_sptr  best_neighbor = NULL;  // prefer junction over endpt
01308     int max_edges = 0;             // max number of edges
01309     for (; n < RNS[l]; n++)    // 4- then 8-connected
01310     {
01311       int x = jx+RIS[n], y = jy+RJS[n];
01312       vtol_vertex_2d_sptr nbr = vertexMap->get(x, y);
01313       int nedges = 0;
01314       if (nbr)
01315         nedges = nbr->numsup();
01316       if (nedges > max_edges)
01317       {
01318         max_edges = nedges;    // number of edges connected to it
01319         best_neighbor = nbr;   // better neighbor
01320         bx = x; by = y; //best detected location, for debug purposes
01321       }
01322     }
01323     if (sdet_contour::debug_)
01324       vcl_cout << "(bx,by) = (" << bx << ' ' << by << ")\n";
01325     if (max_edges)
01326       return best_neighbor;
01327   }
01328   return NULL;
01329 }
01330 
01331 //: If there is only one edge connected to v then return it, otherwise return null
01332 //
01333 vtol_edge_2d_sptr
01334 DanglingEdge(vtol_vertex_2d_sptr const& v)
01335 {
01336   vcl_vector<vtol_edge_sptr> segs; v->edges(segs);
01337   if (segs.size()==1)
01338     return segs[0]->cast_to_edge_2d();
01339   else
01340     return 0;
01341 }
01342 
01343 
01344 //: Merge 2 end points of a same chain creating a cycle
01345 //
01346 //       endpt
01347 //         o------------------
01348 //         o----             |
01349 //      other   \            |
01350 //               ------------
01351 //
01352 //  The removed vertex is the either endpt or other, depending
01353 //  on the direction of the edge
01354 //
01355 bool
01356 sdet_contour::MergeEndPtsOfChain(vtol_vertex_2d_sptr const& endpt,
01357                                  vtol_vertex_2d_sptr const& other,
01358                                  vtol_vertex_2d_sptr& removed_vert)
01359 {
01360   if (sdet_contour::debug_)
01361     vcl_cout << " Merging end points of same edge " << *endpt << ' '
01362              << *other << '\n';
01363 
01364   vcl_vector<vtol_edge_sptr> edges; endpt->edges(edges);
01365   // dangling edge terminating at endpt
01366   vtol_edge_2d_sptr edge = edges[0]->cast_to_edge_2d();
01367   vdgl_digital_curve_sptr dc = edge->curve()->cast_to_vdgl_digital_curve();
01368   vdgl_edgel_chain_sptr cxy= dc->get_interpolator()->get_edgel_chain();
01369   int N = cxy->size();
01370 
01371   //replace the old edge
01372   //
01373   // need to consider 2 combinations
01374   //          endpt               other         removed_vert
01375   //             0-------------------0
01376   //  case a     v2                 v1             endpt
01377   //  case b     v1                 v2             other
01378 
01379   while (true)
01380   {
01381     //case self_a: v2 corresponds to endpt
01382     //add edgels to reach other
01383     if (edge->v2()->cast_to_vertex_2d() == endpt)
01384     {
01385       //Fill in edges across the gap endpt->other
01386       double xe = other->x();
01387       double ye = other->y();
01388       int nedgls =
01389         bdgl_curve_algs::add_straight_edgels(cxy, xe, ye,
01390                                              sdet_contour::debug_);
01391       for (int i = N; i<N+nedgls; i++)
01392         edgeMap->put( int((*cxy)[i].x()), int((*cxy)[i].y()), edge);
01393       edge->set_v2(other->cast_to_vertex());
01394       removed_vert = endpt;
01395       vertexMap->put(int(endpt->x()), int(endpt->y()), NULL);
01396       break;
01397     }
01398 
01399     //case jb, v1 corresponds to endpt
01400     if (edge->v1()->cast_to_vertex_2d() == endpt)
01401     {
01402       //Fill in edges across the gap other->endpt
01403       double xe = endpt->x();
01404       double ye = endpt->y();
01405       int nedgls =
01406         bdgl_curve_algs::add_straight_edgels(cxy, xe, ye,
01407                                              sdet_contour::debug_);
01408       for (int i = N; i<N+nedgls; i++)
01409         edgeMap->put( int((*cxy)[i].x()), int((*cxy)[i].y()), edge);
01410       edge->set_v2(endpt->cast_to_vertex());
01411       removed_vert = other;
01412       vertexMap->put(int(other->x()), int(other->y()), NULL);
01413       break;
01414     }
01415   }
01416   return true;
01417 }
01418 
01419 
01420 //:
01421 //  Merge two different chains by inserting a link from end1 to end2
01422 //  end1 and end2 are touching according to the predicate DetectTouch
01423 //  end1 and end2 are each incident to a single, different edge
01424 //
01425 //        shorter   gap         longer
01426 //    0-------------o  o----------------------0
01427 //              end1    end2
01428 //
01429 void
01430 sdet_contour::MergeEndPtTouchingEndPt(vtol_vertex_2d_sptr const& end1,
01431                                       vtol_vertex_2d_sptr const& end2,
01432                                       vtol_edge_2d_sptr& merge,
01433                                       vtol_edge_2d_sptr& longer,
01434                                       vtol_edge_2d_sptr& shorter)
01435 {
01436   // 1. Retrieve the dangling edges/chains
01437 
01438   // The single edge connected to end1
01439   vcl_vector<vtol_edge_sptr> edges; end1->edges(edges);
01440   vtol_edge_2d_sptr edge1 = edges[0]->cast_to_edge_2d();
01441 
01442   // The single edge connected to end2
01443   end2->edges(edges);
01444   vtol_edge_2d_sptr edge2 = edges[0]->cast_to_edge_2d();
01445 
01446   // 2. Create merged edge/chain
01447   vdgl_digital_curve_sptr dc1 = edge1->curve()->cast_to_vdgl_digital_curve();
01448   const int l1 = dc1->get_interpolator()->get_edgel_chain()->size();
01449   vdgl_digital_curve_sptr dc2 = edge2->curve()->cast_to_vdgl_digital_curve();
01450   const int l2 = dc2->get_interpolator()->get_edgel_chain()->size();
01451 
01452   //edgel chain for edge1
01453   vdgl_edgel_chain_sptr cxy1= dc1->get_interpolator()->get_edgel_chain();
01454 
01455   //edgel chain for edge2
01456   vdgl_edgel_chain_sptr cxy2= dc2->get_interpolator()->get_edgel_chain();
01457 
01458   //The new edge
01459   merge = new vtol_edge_2d();
01460   vdgl_edgel_chain *ec = new vdgl_edgel_chain;
01461   vdgl_interpolator *it = new vdgl_interpolator_linear( ec);
01462   vdgl_digital_curve *dc = new vdgl_digital_curve(it);
01463 
01464   merge->set_curve(*dc);
01465   //
01466   // need to consider 4 combinations
01467   //                   dc1         end1  end2     dc2
01468   //             0-------------------0    0----------------------0
01469   //  case a     v1                 v2    -                      -
01470   //  case b     v2                 v1    -                      -
01471   //  case c     -                  -     v1                    v2
01472   //  case d     -                  -     v2                    v1
01473   //
01474   //debug
01475 
01476   if (sdet_contour::debug_)
01477   {
01478     vcl_cout << "end1 " << *end1 << '\n'
01479              << "end2 " << *end2 << '\n'
01480              << "edge1-v1 " << *(edge1->v1())
01481              << "  edge1-v2 " << *(edge1->v2()) << '\n'
01482              << "edge2-v1 " << *(edge2->v1())
01483              << "  edge2-v2 " << *(edge2->v2()) << '\n'
01484              << " (*cxy1)[0] ="<< (*cxy1)[0] << '\n'
01485              << " (*cxy1)[l1-1] =" <<(*cxy1)[l1-1] << '\n'
01486 
01487              << " (*cxy2)[0] = "<<(*cxy2)[0] << '\n'
01488              << " (*cxy1)[l2-1] =" << (*cxy2)[l2-1] << '\n';
01489   }
01490 
01491   vdgl_edgel_chain *cxy= ec;    // new edgel chain
01492 
01493   //Fill in edgels up to end1
01494   while (true)
01495   {
01496     //case a: v2 corresponds to end1
01497     if (edge1->v2()->cast_to_vertex_2d() == end1)
01498     {
01499       if (sdet_contour::debug_)
01500         vcl_cout << "Case a\n";
01501       for (int i = 0; i < l1; i++)
01502       {
01503         cxy->add_edgel( (*cxy1)[i] );
01504         if (sdet_contour::debug_)
01505           vcl_cout << "merge edgel " << (*cxy1)[i] << '\n';
01506       }
01507       merge->set_v1(edge1->v1());
01508       break;
01509     }
01510     //case b, v1 corresponds to end1, reverse the original edge1 chain
01511     if (edge1->v1()->cast_to_vertex_2d() == end1)
01512     {
01513       if (sdet_contour::debug_)
01514         vcl_cout << "Case b\n";
01515       for (int i = l1-1; i >= 0; --i)
01516       {
01517         cxy->add_edgel((*cxy1)[i]);
01518         if (sdet_contour::debug_)
01519           vcl_cout << "merge edgel " << (*cxy1)[i] << '\n';
01520       }
01521       merge->set_v1(edge1->v2());
01522       break;
01523     }
01524   }
01525   //
01526   //Fill in edges across the gap end1->end2
01527   double xe = end2->cast_to_vertex_2d()->x();
01528   double ye = end2->cast_to_vertex_2d()->y();
01529   bdgl_curve_algs::add_straight_edgels(cxy, xe, ye,
01530                                        sdet_contour::debug_);
01531   //note that end1 is now accounted for in the merged chain
01532 
01533   while (true)
01534   {
01535     //case c: v1 corresponds to end2
01536     if (edge2->v1()->cast_to_vertex_2d() == end2)
01537     {
01538       if (sdet_contour::debug_)
01539         vcl_cout << "Case c\n";
01540       for (int i = 1; i < l2; i++)//don't need edge2->v1() i=1
01541       {
01542         cxy->add_edgel( (*cxy2)[i] );
01543         if (sdet_contour::debug_)
01544           vcl_cout << "merge edgel " << (*cxy2)[i] << '\n';
01545       }
01546       merge->set_v2(edge2->v2());
01547       break;
01548     }
01549     //case d: v2 corresponds to end2, reverse the chain
01550     if (edge2->v2()->cast_to_vertex_2d() == end2)
01551     {
01552       if (sdet_contour::debug_)
01553         vcl_cout << "Case d\n";
01554       for (int i = l2-2; i >= 0; i--)// don't need edge2->v2() i = l2-2
01555       {
01556         cxy->add_edgel( (*cxy2)[i] );
01557         if (sdet_contour::debug_)
01558           vcl_cout << "merge edgel " << (*cxy2)[i] << '\n';
01559       }
01560       merge->set_v2(edge2->v1());
01561       break;
01562     }
01563   }
01564 
01565   // 3. Update global maps
01566   vertexMap->put(int(end1->x()), int(end1->y()), NULL);
01567   vertexMap->put(int(end2->x()), int(end2->y()), NULL);
01568   const int last = cxy->size()-1;
01569   for (int k = 1; k < last; k++)
01570     edgeMap->put( int((*cxy)[k].x()), int((*cxy)[k].y()), merge);
01571   if (edgeMap->get( int((*cxy)[0].x()), int((*cxy)[0].y())))
01572     edgeMap->put( int((*cxy)[0].x()), int((*cxy)[0].y()), merge);
01573   if (edgeMap->get( int((*cxy)[last].x()), int((*cxy)[last].y())))
01574     edgeMap->put( int((*cxy)[last].x()), int((*cxy)[last].y()), merge);
01575 
01576   if (l1 >= l2)                 // sort out length of deleted subchains
01577     longer = edge1, shorter = edge2;
01578   else
01579     longer = edge2, shorter = edge1;
01580   if (sdet_contour::debug_)
01581   {
01582     vcl_cout << "longer " << *(longer->v1()->cast_to_vertex_2d())
01583              << ' ' << *(longer->v2()->cast_to_vertex_2d()) << '\n'
01584              << "shorter " << *(shorter->v1()->cast_to_vertex_2d())
01585              << ' ' << *(shorter->v2()->cast_to_vertex_2d()) << '\n';
01586   }
01587 }
01588 
01589 
01590 //: Merge an isolated end point into a nearby junction.
01591 //
01592 //                     ------------
01593 //                    |            |
01594 //             endpt  |            |         O
01595 //    0-----------o   0 junction   0         |
01596 //                    |                      |
01597 //                     ----------------------
01598 //
01599 bool sdet_contour::
01600 MergeEndPtTouchingJunction(vtol_vertex_2d_sptr const& endpt,
01601                            vtol_vertex_2d_sptr const& junction,
01602                            vtol_edge_2d_sptr& old_edge,
01603                            vtol_edge_2d_sptr& new_edge)
01604 {
01605   if (sdet_contour::debug_)
01606     vcl_cout << "Merge at Junction e" << *endpt<< " j"  << *junction << '\n';
01607   vcl_vector<vtol_edge_sptr> edges; endpt->edges(edges);
01608   // dangling edge terminating at end pt
01609   old_edge = edges[0]->cast_to_edge_2d();
01610   vdgl_digital_curve_sptr old_dc = old_edge->curve()->cast_to_vdgl_digital_curve();
01611   vdgl_edgel_chain_sptr old_cxy= old_dc->get_interpolator()->get_edgel_chain();
01612   int N = old_cxy->size();
01613 
01614   new_edge = new vtol_edge_2d();
01615   vdgl_edgel_chain *cxy = new vdgl_edgel_chain;
01616   vdgl_interpolator *it = new vdgl_interpolator_linear(cxy);
01617   vdgl_digital_curve *dc = new vdgl_digital_curve(it);
01618   new_edge->set_curve(*dc);
01619 
01620   int xs, ys;
01621   //replace the old edge
01622   while (true)
01623   {
01624     //case ja: v2 corresponds to endpt
01625     //copy edgels up to v2
01626     if (old_edge->v2()->cast_to_vertex_2d() == endpt)
01627     {
01628       if (sdet_contour::debug_)
01629         vcl_cout << "Case ja\n";
01630       for (int i = 0; i+1 < N; ++i)
01631       {
01632         cxy->add_edgel( (*old_cxy)[i] );
01633         if (sdet_contour::debug_)
01634           vcl_cout << "junction edgel " << (*old_cxy)[i] << '\n';
01635         edgeMap->put( int((*old_cxy)[i].x()),
01636                       int((*old_cxy)[i].y()), new_edge);
01637       }
01638       //set v1 to old v1
01639       new_edge->set_v1(old_edge->v1());
01640       xs = int(old_edge->v1()->cast_to_vertex_2d()->x());
01641       ys = int(old_edge->v1()->cast_to_vertex_2d()->y());
01642       vertexMap->put(xs, ys, new_edge->v1()->cast_to_vertex_2d());
01643       edgeMap->put(xs, ys, NULL);
01644       break;
01645     }
01646     //case jb, v1 corresponds to endpt
01647     //must reverse the original edge1 chain
01648     if (old_edge->v1()->cast_to_vertex_2d() == endpt)
01649     {
01650       if (sdet_contour::debug_)
01651         vcl_cout << "Case jb\n";
01652       for (int i = N-1; i >=0; --i)
01653       {
01654         cxy->add_edgel((*old_cxy)[i]);
01655         if (sdet_contour::debug_)
01656           vcl_cout << "junction edgel " << (*old_cxy)[i] << '\n';
01657         edgeMap->put( int((*old_cxy)[i].x()),
01658                       int((*old_cxy)[i].y()), new_edge);
01659       }
01660 
01661       //set new v1 to old v2
01662       new_edge->set_v1(old_edge->v2());
01663       xs = int(old_edge->v2()->cast_to_vertex_2d()->x());
01664       ys = int(old_edge->v2()->cast_to_vertex_2d()->y());
01665       vertexMap->put(xs, ys, new_edge->v1()->cast_to_vertex_2d());
01666       edgeMap->put(xs, ys, NULL);
01667       break;
01668     }
01669   }
01670   //At this point we have copied the old edge up to the gap at endpt
01671   //the new edge has v2 at the position of endpt.
01672   //Now we add edgels to reach the junction
01673   double xe = junction->cast_to_vertex_2d()->x();
01674   double ye = junction->cast_to_vertex_2d()->y();
01675   int nedgls =
01676     bdgl_curve_algs::add_straight_edgels(cxy, xe, ye,
01677                                          sdet_contour::debug_);
01678 
01679   //Check for self-intersection
01680   //Intersections in a 3x3 window around the
01681   //final point (xs, ys) do not count since
01682   //there are intrinsically collisions near the vertex
01683   bool self_intersects = false;//JLM added -1 need to check!
01684   for (int i = N; i<(N+nedgls-1)&&!self_intersects; i++)
01685   {
01686     int x = int((*cxy)[i].x()), y = int((*cxy)[i].y());
01687 #define WARN(x,y) vcl_cerr << "Warning: edgel "<<i<<" is at ("<<x<<','<<y\
01688                            <<") which is outside of edge map of size "\
01689                            <<edgeMap->rows()<<'x'<<edgeMap->cols()<<'\n'
01690     if (x < 0) { WARN(x,y); x = 0; }
01691     if (y < 0) { WARN(x,y); y = 0; }
01692     if (x >= int(edgeMap->rows())) { WARN(x,y); x = edgeMap->rows()-1; }
01693     if (y >= int(edgeMap->cols())) { WARN(x,y); y = edgeMap->cols()-1; }
01694 #undef WARN
01695 
01696     if (sdet_contour::debug_)
01697       vcl_cout << " intersecting (" << i << ")(" << vnl_math_abs(x-xe)
01698                << ' ' << vnl_math_abs(y-ye) << ")\n";
01699 
01700     self_intersects = self_intersects ||
01701       ((edgeMap->get(x, y)==new_edge)&&
01702        ((vnl_math_abs(x-xe)>1)||(vnl_math_abs(y-ye)>1)));
01703 
01704     if (!self_intersects)
01705       edgeMap->put(x, y,new_edge);
01706   }
01707 
01708   if (sdet_contour::debug_&&self_intersects)
01709     vcl_cout << "merge endpoint touching junction - self-intersection\n";
01710 
01711   if (self_intersects)
01712     return false;
01713 
01714   //set v2 of the new edge to be the junction
01715   new_edge->set_v2(junction->cast_to_vertex());
01716   int x = int(junction->x()), y = int(junction->y());
01717   vertexMap->put(x, y, junction);
01718   vertexMap->put(int(endpt->x()), int(endpt->y()), NULL);
01719 
01720   edgeMap->put(x, y, NULL);
01721 
01722   return true;
01723 }
01724 
01725 
01726 //:
01727 // Find junctions from end points touching at an interior point
01728 // of a chain, with detectable jump in filter response.
01729 // Localize these junctions on the stronger contour to pixel accuracy,
01730 // and break stronger chain into subchains.
01731 // Also merge end points touching another end point or junction.
01732 // Return the number of end points and junctions bounding
01733 // all chains/cycles detected in sdet_contour::FindChains.
01734 // Deletion/insertion to the network must be done completely,
01735 // so that the connectivity links are updated.  Protected.
01736 int
01737 sdet_contour::FindJunctions(gevd_bufferxy& edgels,
01738                             vcl_vector<vtol_edge_2d_sptr>& edges,
01739                             vcl_vector<vtol_vertex_2d_sptr >& vertices)
01740 {
01741   vul_timer t;
01742 
01743   if (!edges.size())
01744   {
01745     vcl_cerr << "sdet_contour::FindChains must precede sdet_contour::FindJunctions.\n";
01746     return 0;
01747   }
01748   // 1. Create vertices at the end of edges (digital_curve geometry)
01749   const float connect_fuzz = 2;
01750 
01751   for (unsigned int i=0; i< edges.size(); i++)
01752   {
01753     vtol_edge_2d_sptr edge = edges[i];
01754     vdgl_digital_curve_sptr dc = edge->curve()->cast_to_vdgl_digital_curve();
01755     vdgl_edgel_chain_sptr cxy= dc->get_interpolator()->get_edgel_chain();
01756     //the index of the last edgel in the curve
01757     const int last = cxy->size()-1;
01758     //the edge might be a closed cycle
01759     // test for disjoint first/last pixel
01760     if (vcl_fabs((*cxy)[0].x()-(*cxy)[last].x()) > connect_fuzz ||
01761         vcl_fabs((*cxy)[0].y()-(*cxy)[last].y()) > connect_fuzz)
01762     { // so not closed cycle
01763       int x = int((*cxy)[0].x()), y = int((*cxy)[0].y());
01764       vtol_vertex_2d_sptr v1 = vertexMap->get(x, y);
01765       //see if there is a vertex for v1 at x,y
01766       if (!v1)
01767       {
01768         // If not, add a new vertex, for v1
01769         // 1st point in chain
01770         v1 = new vtol_vertex_2d((*cxy)[0].x(), (*cxy)[0].y());
01771         vertexMap->put(x, y, v1);
01772         LookupTableInsert(vertices, v1);
01773       }
01774       else//othewise erase the edgel at x,y
01775       {
01776         edgeMap->put( x, y, NULL); // erase junction point
01777       }
01778 
01779       edge->set_v1(v1->cast_to_vertex());         // link both directions v-e
01780       if (sdet_contour::debug_)
01781         vcl_cout << "adding vertex (" << x << ' ' << y
01782                  << ")(" << v1->numsup() << ")\n";
01783       x = int((*cxy)[last].x()), y = int((*cxy)[last].y());
01784 
01785       vtol_vertex_2d_sptr v2 = vertexMap->get(x, y);
01786       //see if there is a vertex for v2 at x,y
01787       if (!v2)
01788       {
01789         // If not, add a new vertex, for v2
01790         // last point in chain
01791         v2 = new vtol_vertex_2d((*cxy)[last].x(), (*cxy)[last].y());
01792         vertexMap->put(x, y, v2);
01793         LookupTableInsert(vertices, v2);
01794       }
01795       else//othewise erase the edgel at x,y
01796       {
01797         edgeMap->put( x, y, NULL); // erase junction point
01798       }
01799 
01800       edge->set_v2(v2->cast_to_vertex());  // link both directions v-e
01801       if (sdet_contour::debug_)
01802         vcl_cout << "adding vertex (" << x << ' ' << y
01803                  << ")(" << v2->numsup() << ")\n";
01804     }
01805     else // is a closed cycle but with a potential gap of connect_fuzz
01806       fill_cycle_gap(cxy);
01807   }
01808   //
01809   // At this point, all edges have vertices defined at the endpoints
01810   // of the digital curve except for 1-edge cycles
01811   //
01812   // 2. Localize a junction, when an end point of a dangling contour
01813   // touches another contour or itself at an interior point.
01814   //
01815   // If the end vertex does form a junction, e.g. with DetectJunction
01816   // then the digital_curve "weaker" must also be updated
01817   //
01818   int jcycle = 0, jchain = 0;   // number of junctions with cycle/chain
01819   for (unsigned int i=0; i< vertices.size(); i++)
01820   {
01821     //continue; //JLM no junctions
01822     vtol_vertex_2d_sptr  endv = vertices[i];
01823     vtol_edge_2d_sptr weaker = NULL, stronger = NULL;
01824     int index; // location on stronger contour
01825     if (DetectJunction(endv, index, weaker, stronger, maxSpiral, edgels))
01826     {
01827       if (sdet_contour::debug_)
01828         vcl_cout << "detected junction near (" << endv->x() <<' '<< endv->y()
01829                  << ")\n";
01830 
01831       int old_x = int(endv->x()), old_y = int(endv->y());//before end moves
01832 
01833       //If v1 is NULL then the edge is a cycle
01834 
01835       if (!stronger->v1())
01836       {
01837         // cycle is now split at junction
01838         vtol_edge_2d_sptr split = NULL;
01839         BreakCycle(endv, index, stronger, split);
01840         LookupTableReplace(edges, stronger, split);
01841 
01842         //Replace the mutated weaker digital curve
01843         //since the endpoint may have moved
01844         update_edgel_chain(weaker, old_x, old_y, endv);
01845 
01846         if (sdet_contour::debug_) {
01847           vcl_cout << "new position on cycle (" << endv->x() << ' '
01848                    << endv->y() << ")\n";
01849         }
01850         jcycle++;             // remove original edge
01851       }
01852       else if (weaker == stronger)                  // touch itself or another 1-chain
01853       {
01854         vtol_edge_2d_sptr straight = NULL, curled = NULL;
01855         // break own chain and make a loop
01856         // edgel chain gaps are updated internally
01857         LoopChain(endv, index, stronger, straight, curled);
01858 
01859         LookupTableReplace(edges, stronger, straight);
01860         LookupTableInsert(edges, curled);
01861 
01862         if (sdet_contour::debug_)
01863           vcl_cout << "new position on loop chain (" << endv->x()
01864                    << ' ' << endv->y()<< ")\n";
01865         jchain++;
01866       }
01867       else
01868       {
01869         vtol_edge_2d_sptr longer = NULL, shorter = NULL;
01870         BreakChain(endv, index, stronger,longer, shorter);
01871         LookupTableReplace(edges, stronger, longer);
01872         LookupTableInsert(edges, shorter);
01873 
01874         //Replace the mutated weaker digital curve
01875         //since the endpoint may have moved
01876         update_edgel_chain(weaker, old_x, old_y, endv);
01877         if (sdet_contour::debug_)
01878           vcl_cout << "old position on chain (" << old_x
01879                    << ' ' << old_y
01880                    << ")  new position on chain (" << endv->x()
01881                    << ' ' << endv->y()<< ")(" << endv->numsup() <<")\n";
01882 
01883         jchain++;
01884       }
01885     }
01886   }
01887 
01888   if (talkative_)
01889     vcl_cout << "Find junctions with "
01890              << jcycle << " cycles and " << jchain << " chains, with jump > "
01891              << minJump << " and maxSpiral " << maxSpiral << vcl_endl;
01892   // 3. Merge touching end points, into a larger junction/chain.
01893   int dendpt = 0, dchain = 0;   // number of deleted endpt/chain
01894 
01895   for (unsigned int i=0; i< vertices.size(); i++)
01896   {
01897     //continue; //JLM no merge
01898     // search from dangling end pt only
01899     vtol_vertex_2d_sptr  end1 = vertices[i];
01900 
01901     // skip deleted vertices, i.e., !end
01902     // and only consider end point of dangling 1-chain
01903     // but not within border strip
01904     if (end1 && end1->numsup() == 1 && !near_border(end1))
01905     {
01906       if (sdet_contour::debug_)
01907         vcl_cout << "merge target end1(" << end1->x() << ' '
01908                  << end1->y() << ")\n";
01909       // find another vertex nearby
01910       vtol_vertex_2d_sptr  end2 = DetectTouch(end1, maxSpiral);
01911       if (end2)
01912       {
01913         //Case a. The other end point has only one edge
01914         if (end2->numsup() == 1)
01915         {
01916           vtol_edge_2d_sptr seg = DanglingEdge(end1);
01917           //Case a1. The edge on the other endpoint is the same as seg
01918           if (seg == DanglingEdge(end2))
01919           {
01920             vtol_vertex_2d_sptr removed_vert = NULL;
01921             if (MergeEndPtsOfChain(end1, end2, removed_vert))
01922             {
01923               LookupTableRemove(vertices, removed_vert);
01924               if (sdet_contour::debug_)
01925                 vcl_cout << "cycle endpt1=" << *end1 << vcl_endl
01926                          << "cycle endpt2=" << *end2 << vcl_endl;
01927               dendpt++;
01928             }
01929           }
01930           else
01931           {
01932             //Case a2. The edge on the other endpoint is different from seg
01933             if (sdet_contour::debug_)
01934               vcl_cout << "endpt1=" << *end1 << vcl_endl
01935                        << "endpt2=" << *end2 << vcl_endl;
01936 
01937             vtol_edge_2d_sptr merge=NULL, longer=NULL, shorter=NULL;
01938             // merge 2 different edges
01939             MergeEndPtTouchingEndPt(end1, end2,
01940                                     merge, longer, shorter);
01941             if (sdet_contour::debug_)
01942               vcl_cout << "merge=" << *merge << vcl_endl
01943                        << "longer=" << *longer << vcl_endl
01944                        << "shorter=" << *shorter << vcl_endl
01945                        << "merge.v1=" << *merge->v1() << vcl_endl
01946                        << "merge.v2=" << *merge->v2() << vcl_endl;
01947 
01948             LookupTableReplace(edges, longer, merge);
01949             LookupTableRemove(edges, shorter);
01950             LookupTableRemove(vertices, end1);
01951             LookupTableRemove(vertices, end2);
01952             dendpt += 2, dchain += 1;
01953           }
01954         }
01955         else
01956         {
01957           //Case b. The other junction has more than 2 edges
01958           if (sdet_contour::debug_)
01959             vcl_cout << "junction endpt1=" << *end1 << vcl_endl
01960                      << "junction endpt2=" << *end2 << vcl_endl;
01961           vtol_edge_2d_sptr old_edge=NULL, new_edge=NULL;
01962           if (MergeEndPtTouchingJunction(end1, end2, old_edge, new_edge))
01963           {
01964             LookupTableReplace(edges, old_edge, new_edge);
01965             LookupTableRemove(vertices, end1);
01966             dendpt++;
01967           }
01968         }
01969       } //end if (end2->numsup()==1)
01970     } //end if (end2)
01971   }
01972 
01973   if (sdet_contour::debug_)
01974     vcl_cout << "Merge and delete " << dendpt
01975              << " end points and " << dchain << " edges\n";
01976   if (dchain)                   // eliminate holes in global arrays
01977     LookupTableCompress(edges);
01978   if (dendpt)
01979     LookupTableCompress(vertices);
01980 
01981   // 4. Insert virtual junction for isolated 1-cycles
01982   int ncycle = 0;
01983   for (unsigned int i=0; i< edges.size(); i++)
01984   {
01985     //continue; //JLM no virtual junctions
01986     vtol_edge_2d_sptr edge = edges[i];
01987     if (!edge->v1())    // vertices not created from 1.
01988     {
01989       vdgl_digital_curve_sptr dc = edge->curve()->cast_to_vdgl_digital_curve();
01990       vdgl_edgel_chain_sptr cxy= dc->get_interpolator()->get_edgel_chain();
01991 
01992       const int last = cxy->size()-1;
01993       vtol_vertex_2d_sptr  v =
01994         new vtol_vertex_2d(((*cxy)[0].x()+(*cxy)[last].x())/2,
01995                            ((*cxy)[0].y()+(*cxy)[last].y())/2);
01996       edge->set_v1(v->cast_to_vertex()); edge->set_v2(v->cast_to_vertex());
01997       vertexMap->put(int(v->x()), int(v->y()), v);
01998       LookupTableInsert(vertices, v);
01999       ncycle++;
02000     }
02001   }
02002   if (sdet_contour::debug_)
02003     vcl_cout << "Create " << ncycle
02004              << " virtual end points for isolated cycles.\n";
02005 
02006   if (talkative_)
02007     vcl_cout << "All junctions found in " << t.real() << " msecs.\n";
02008 
02009   return vertices.size();
02010 }
02011 
02012 
02013 //: Insert subpixel accuracy into the pixels on the edges/vertices.
02014 // Truncating float locations with int(xy) should map to the original
02015 // pixel locations. No interpolation is done at junctions of 3 or more
02016 // contours, so a junction can have location error up to 1-2 pixel,
02017 // tangential to the strong contour.
02018 void
02019 sdet_contour::SubPixelAccuracy(vcl_vector<vtol_edge_2d_sptr>& edges,
02020                                vcl_vector<vtol_vertex_2d_sptr >& vertices,
02021                                const gevd_bufferxy& locationx,
02022                                const gevd_bufferxy& locationy)
02023 {
02024   //return;//JLM no subpixel
02025   vul_timer t;
02026   if (talkative_)
02027     vcl_cout << "Insert subpixel accuracy into edges/vertices";
02028 
02029   // 1. Subpixel accuracy for end points
02030   for (unsigned int i=0; i< vertices.size(); i++)
02031   {
02032     vtol_vertex_2d_sptr  vert = vertices[i];
02033     int x = int(vert->x()), y = int(vert->y());
02034     vert->set_x(x + floatPixel(locationx, x, y));
02035     vert->set_y(y + floatPixel(locationy, x, y));
02036   }
02037 
02038   // 2. Subpixel accuracy for chain pixels
02039   for (unsigned int i=0; i< edges.size(); i++)
02040   {
02041     vtol_edge_2d_sptr edge = edges[i];
02042     if (!edge) continue;
02043     vdgl_digital_curve_sptr dc = edge->curve()->cast_to_vdgl_digital_curve();
02044     if (!dc) continue;
02045     if (!dc->get_interpolator()) continue;
02046     vdgl_edgel_chain_sptr cxy= dc->get_interpolator()->get_edgel_chain();
02047     if (!cxy) continue;
02048 
02049     for (unsigned int k = 0; k < cxy->size(); ++k)
02050     {
02051       // if ((*cxy)[k].get_grad()<0)
02052       int x = int((*cxy)[k].x()), y = int((*cxy)[k].y());
02053       double tempx= (*cxy)[k].x()+ floatPixel( locationx, x, y);
02054       double tempy= (*cxy)[k].y()+ floatPixel( locationy, x, y);
02055       (*cxy)[k].set_x( tempx);
02056       (*cxy)[k].set_y( tempy);
02057     }
02058   }
02059 
02060   // 3. Thin zig-zags on the contours? Zig-zags happen at
02061   // the 2 end points because of extension, or inside the contour
02062   // because of 4/8-connected tracing through noisy chain pixels,
02063   // and large shifts for subpixel locations.
02064   // Implement only if experiments prove zig-zags are excessive
02065 
02066   if (talkative_)
02067     vcl_cout << ", in " << t.real() << " msecs.\n";
02068 }
02069 
02070 
02071 //:
02072 //  Generate an Edge with a vdgl_digital_curve representing a straight line
02073 //  between the specified vertices.
02074 vtol_edge_2d_sptr DigitalEdge(vtol_vertex_2d_sptr const& vs,
02075                               vtol_vertex_2d_sptr const& ve)
02076 {
02077   vsol_curve_2d_sptr dc= new vdgl_digital_curve(vs->point(), ve->point());
02078   return new vtol_edge_2d(vs, ve, dc);
02079 }
02080 
02081 
02082 //:
02083 // Insert virtual edges and vertices to enforce closure
02084 // of the regions beyond the rectangular image border.
02085 // The location of the border is at 3 pixels away from the
02086 // real image border, because of kernel radius in convolution
02087 // and non maximum suppression. Virtual border of image should be
02088 // inserted after sdet_contour::FindChains() and sdet_contour::FindJunctions().
02089 //
02090 // JLM - February 1999  Modified this routine extensively to
02091 // move the border to the actual image ROI bounds.  Chain endpoints
02092 // are extended to intersect with the border.  These changes were
02093 // made to support region segmentation from edgels.
02094 void
02095 sdet_contour::InsertBorder(vcl_vector<vtol_edge_2d_sptr>& edges,
02096                            vcl_vector<vtol_vertex_2d_sptr >& vertices)
02097 {
02098   //return;//JLM no borders
02099   vul_timer t;
02100   bool merge = true;//merge close vertices
02101   //1. Save Edges along the border
02102   vcl_vector<vtol_vertex_2d_sptr > xmin_verts;
02103   vcl_vector<vtol_vertex_2d_sptr > xmax_verts;
02104   vcl_vector<vtol_vertex_2d_sptr > ymin_verts;
02105   vcl_vector<vtol_vertex_2d_sptr > ymax_verts;
02106 
02107   if (talkative_)
02108     vcl_cout << "Insert virtual border to enforce closure";
02109 
02110   // 2. Create 4 corners vertices
02111   const int rmax = FRAME;       // border of image
02112   const int xmax = vertexMap->rows()-rmax-1;
02113   const int ymax = vertexMap->columns()-rmax-1;
02114   int cx[] = {rmax, xmax, rmax, xmax}; // coordinates of 4 corners
02115   int cy[] = {rmax, ymax, ymax, rmax};
02116   int d;
02117   // 3. Collect Vertices along each border
02118   //3.0 Generate Corner Vertices
02119   vtol_vertex_2d_sptr  V00 = new vtol_vertex_2d(rmax, rmax);
02120   vtol_vertex_2d_sptr  V01 = new vtol_vertex_2d(rmax, ymax);
02121   vtol_vertex_2d_sptr  V10 = new vtol_vertex_2d(xmax, rmax);
02122   vtol_vertex_2d_sptr  V11 = new vtol_vertex_2d(xmax, ymax);
02123   xmin_verts.push_back(V00);
02124   xmax_verts.push_back(V10);
02125   ymin_verts.push_back(V00);
02126   ymax_verts.push_back(V01);
02127   // 3.1 ymin, ymax edges
02128   for (d = 0; d < 2; d++)
02129   {
02130     int x, y = cy[d];
02131     for (x = rmax; x<=xmax; x++)
02132     {
02133       vtol_vertex_2d_sptr  v = vertexMap->get(x, y);
02134       if (v)
02135         vertexMap->put(x, y, NULL);
02136       else continue;
02137       if (d)
02138         ymax_verts.push_back(v);
02139       else
02140         ymin_verts.push_back(v);
02141     }
02142   }
02143   // 3.2 xmin, xmax edges
02144   for (d = 0; d < 2; d++)
02145   {
02146     int x = cx[d], y;
02147     for (y = rmax; y<=ymax; y++)
02148     {
02149       vtol_vertex_2d_sptr  v = vertexMap->get(x, y);
02150       if (v)
02151         vertexMap->put(x, y, NULL);
02152       else continue;
02153       if (d)
02154         xmax_verts.push_back(v);
02155       else
02156         xmin_verts.push_back(v);
02157     }
02158   }
02159 
02160   xmin_verts.push_back(V01);
02161   xmax_verts.push_back(V11);
02162   ymin_verts.push_back(V10);
02163   ymax_verts.push_back(V11);
02164 
02165   // 4. Merge vertices
02166   // 4.1  along ymin and ymax
02167   for (d = 0; d < 2; d++)
02168   {
02169     vcl_vector<vtol_vertex_2d_sptr >* verts = &ymin_verts;
02170     if (d)
02171       verts = &ymax_verts;
02172     int len = (*verts).size();
02173     if (len<3) continue;
02174     //potential merge at xmin
02175     vtol_vertex_2d_sptr  pre_v = (*verts)[0];
02176     vtol_vertex_2d_sptr  v = (*verts)[1];
02177     int x = int(v->x());
02178     int pre_x = int(pre_v->x());
02179     if (merge&&(x-pre_x)<3)
02180     {
02181       vtol_vertex_sptr pv = pre_v->cast_to_vertex(),
02182         vv = v->cast_to_vertex();
02183       btol_vertex_algs::merge_superiors(pv, vv);
02184 
02185       for (vcl_vector<vtol_vertex_2d_sptr >::iterator it= verts->begin();
02186            it!= verts->end(); ++it)
02187       {
02188         if (*it == v)
02189         {
02190           verts->erase( it);
02191           break;
02192         }
02193       }
02194       for (vcl_vector<vtol_vertex_2d_sptr >::iterator it= vertices.begin();
02195            it!= vertices.end(); ++it)
02196       {
02197         if (*it == v)
02198         {
02199           vertices.erase( it);
02200           break;
02201         }
02202       }
02203       len--;
02204     }
02205     //potential merge at xmax
02206     pre_v = (*verts)[len-2];
02207     v = (*verts)[len-1];
02208     pre_x = int(pre_v->x());
02209     if (merge&&(xmax+rmax-pre_x)<3)
02210     {
02211       vtol_vertex_sptr pv = pre_v->cast_to_vertex(),
02212         vv = v->cast_to_vertex();
02213       btol_vertex_algs::merge_superiors(pv, vv);
02214 
02215       for (vcl_vector<vtol_vertex_2d_sptr >::iterator it= verts->begin();
02216            it!= verts->end(); ++it)
02217       {
02218         if (*it == pre_v)
02219         {
02220           verts->erase( it);
02221           break;
02222         }
02223       }
02224       for (vcl_vector<vtol_vertex_2d_sptr >::iterator it= vertices.begin();
02225            it!= vertices.end(); ++it)
02226       {
02227         if (*it == pre_v)
02228         {
02229           vertices.erase( it);
02230           break;
02231         }
02232       }
02233       len--;
02234     }
02235   }
02236 
02237   // 4.2  along xmin and xmax
02238   for (d = 0; d < 2; d++)
02239   {
02240     vcl_vector<vtol_vertex_2d_sptr >* verts = &xmin_verts;
02241     if (d)
02242       verts = &xmax_verts;
02243     int len = (*verts).size();
02244     if (len<3) continue;
02245     //potential merge at ymin
02246     vtol_vertex_2d_sptr  pre_v = (*verts)[0];
02247     vtol_vertex_2d_sptr  v = (*verts)[1];
02248 
02249     int y = int(v->y()), pre_y = int(pre_v->y());
02250     if (merge&&(y-pre_y)<3)
02251     {
02252       vtol_vertex_sptr pv = pre_v->cast_to_vertex(),
02253         vv = v->cast_to_vertex();
02254       btol_vertex_algs::merge_superiors(pv, vv);
02255       for (vcl_vector<vtol_vertex_2d_sptr >::iterator it= verts->begin();
02256            it!= verts->end(); ++it)
02257       {
02258         if (*it == v)
02259         {
02260           verts->erase( it);
02261           break;
02262         }
02263       }
02264       for (vcl_vector<vtol_vertex_2d_sptr >::iterator it= vertices.begin();
02265            it!= vertices.end(); ++it)
02266       {
02267         if (*it == v)
02268         {
02269           vertices.erase( it);
02270           break;
02271         }
02272       }
02273       len--;
02274     }
02275     //potential merge at ymax
02276     pre_v = (*verts)[len-2];
02277     v = (*verts)[len-1];
02278     pre_y = int(pre_v->y());
02279     if (merge&&(ymax+rmax-pre_y)<3)
02280     {
02281       vtol_vertex_sptr pv = pre_v->cast_to_vertex(),
02282         vv = v->cast_to_vertex();
02283       btol_vertex_algs::merge_superiors(pv, vv);
02284       for (vcl_vector<vtol_vertex_2d_sptr >::iterator it= verts->begin();
02285            it!= verts->end(); ++it)
02286       {
02287         if (*it == pre_v)
02288         {
02289           verts->erase( it);
02290           break;
02291         }
02292       }
02293       for (vcl_vector<vtol_vertex_2d_sptr >::iterator it= vertices.begin();
02294            it!= vertices.end(); ++it)
02295       {
02296         if (*it == pre_v)
02297         {
02298           vertices.erase( it);
02299           break;
02300         }
02301       }
02302       len--;
02303     }
02304   }
02305 
02306   // 5. Move the vertices to the bounds of the ROI
02307   float xmi = 0, xmx = float(xmax + rmax);
02308   float ymi = 0, ymx = float(ymax + rmax);
02309   for (unsigned int iv=1; iv+1<xmin_verts.size(); ++iv)
02310   {
02311     vtol_vertex_2d_sptr  v = xmin_verts[iv];
02312     if (!v) continue;
02313     vtol_vertex_2d_sptr  vp = new vtol_vertex_2d(xmi, v->y());
02314     vertices.push_back(vp);// vp->Protect();
02315     xmin_verts[iv] = vp;
02316 
02317     vtol_edge_2d_sptr e = DigitalEdge(v, vp);
02318     edges.push_back(e);//  e->Protect();
02319   }
02320 
02321   for (unsigned int iv=1; iv+1<xmax_verts.size(); ++iv)
02322   {
02323     vtol_vertex_2d_sptr v = xmax_verts[iv];
02324     if (!v) continue;
02325     vtol_vertex_2d_sptr  vp = new vtol_vertex_2d( xmx, v->y());
02326     vertices.push_back(vp); // vp->Protect();
02327     xmax_verts[iv] = vp;
02328     vtol_edge_2d_sptr e = DigitalEdge(v, vp);
02329     edges.push_back(e); // e->Protect();
02330   }
02331   for (unsigned int iv=1; iv+1<ymin_verts.size(); ++iv)
02332   {
02333     vtol_vertex_2d_sptr  v = ymin_verts[iv];
02334     if (!v) continue;
02335     vtol_vertex_2d_sptr  vp = new vtol_vertex_2d(v->x(), ymi);
02336     vertices.push_back(vp); // vp->Protect();
02337     ymin_verts[iv] = vp;
02338     vtol_edge_2d_sptr e = DigitalEdge(v, vp);
02339     edges.push_back(e); // e->Protect();
02340   }
02341   for (unsigned int iv=1; iv+1<ymax_verts.size(); ++iv)
02342   {
02343     vtol_vertex_2d_sptr  v = ymax_verts[iv];
02344     if (!v) continue;
02345     vtol_vertex_2d_sptr  vp = new vtol_vertex_2d( v->x(), ymx);
02346     vertices.push_back(vp); // vp->Protect();
02347     ymax_verts[iv] = vp;
02348     vtol_edge_2d_sptr e = DigitalEdge(v, vp);
02349     edges.push_back(e); // e->Protect();
02350   }
02351   V00->set_x(0);  V00->set_y(0); vertices.push_back(V00);
02352   V01->set_x(0);  V01->set_y(ymax+rmax); vertices.push_back(V01);
02353   V10->set_x(xmax+rmax);  V10->set_y(0); vertices.push_back(V10);
02354   V11->set_x(xmax+rmax);  V11->set_y(ymax+rmax); vertices.push_back(V11);
02355 
02356   //6. Now we have properly placed vertices.  Next we scan and generate
02357   //edges. along the border.
02358   //6.1 along ymin and ymax
02359   for (d = 0; d < 2; ++d)
02360   {
02361     vcl_vector<vtol_vertex_2d_sptr >* verts = &ymin_verts;
02362     if (d)
02363       verts = &ymax_verts;
02364     unsigned int len = (*verts).size();
02365     if (len<2)
02366     {
02367       vcl_cout <<"In sdet_contour::InsertBorder() - too few vertices\n";
02368       return;
02369     }
02370     for (unsigned int i=0; i+1<len; ++i)
02371     {
02372       vtol_vertex_2d_sptr  v = (*verts)[i];
02373       vtol_vertex_2d_sptr  vp = (*verts)[i+1];
02374       vtol_edge_2d_sptr e = DigitalEdge(v, vp);
02375       edges.push_back(e); // e->Protect();
02376     }
02377   }
02378   //6.2 along xmin and xmax
02379   for (d = 0; d < 2; ++d)
02380   {
02381     vcl_vector<vtol_vertex_2d_sptr >* verts = &xmin_verts;
02382     if (d)
02383       verts = &xmax_verts;
02384     unsigned int len = (*verts).size();
02385     if (len<2)
02386     {
02387       vcl_cout <<"In sdet_contour::InsertBorder() - too few vertices\n";
02388       return;
02389     }
02390     for (unsigned int i = 0; i+1<len; ++i)
02391     {
02392       vtol_vertex_2d_sptr  v = (*verts)[i];
02393       vtol_vertex_2d_sptr  vp = (*verts)[i+1];
02394       vtol_edge_2d_sptr e = DigitalEdge(v, vp);
02395       edges.push_back(e); // e->Protect();
02396     }
02397   }
02398 
02399   if (talkative_)
02400     vcl_cout << ", in " << t.real() << " msecs.\n";
02401 }
02402 
02403 
02404 //:
02405 // Convolve array elements with [1 0 1]/2, replacing
02406 // center pixel by average of 2 neighbors.
02407 // This will make the spacing between pixels almost equal
02408 // and prune away small zig-zags.
02409 void
02410 EqualizeElements(double* elmts, int n, double v1, double v2)
02411 {
02412   double p0 = elmts[0], p1 = elmts[1], p2 = elmts[2]; // setup pipeline
02413   elmts[0] = (v1 + p1) / 2;     // touching first vertex
02414   for (int i = 1; i+2 < n; ++i)
02415   {
02416     elmts[i] = (p0 + p2)/2;
02417     p0 = p1; p1 = p2; p2 = elmts[i+2]; // faster with circular list
02418   }
02419   if (n>1) elmts[n-2] = (p0 + p2)/2;   // last convolution
02420   if (n>0) elmts[n-1] = (p1 + v2)/2;   // touching second vertex
02421 }
02422 
02423 
02424 //:
02425 // Make the spacing of the chain pixels nearly equal by
02426 // smoothing their locations with the average filter  [1 0 1]/2.
02427 // This will reduce square grid tessellation artifacts, and
02428 // lead to more accurate estimation of the tangent direction,
02429 // and local curvature angle, from finite differences in location.
02430 // It is also useful to avoid weight artifacts in curve fitting
02431 // caused by the periodic clustering of pixels along the chain.
02432 // Truncating the float locations with int() will no longer map
02433 // to the original pixels of the discrete chains.
02434 void
02435 sdet_contour::EqualizeSpacing(vcl_vector<vtol_edge_2d_sptr>& chains)
02436 {
02437   vul_timer t;
02438 
02439   if (talkative_)
02440     vcl_cout << "Equalize the spacing between pixels in chains\n";
02441 
02442   for (unsigned int i= 0; i< chains.size(); ++i)
02443   {
02444     vtol_edge_2d_sptr e = chains[i];
02445     vdgl_digital_curve_sptr dc = e->curve()->cast_to_vdgl_digital_curve();
02446     const int len = dc->get_interpolator()->get_edgel_chain()->size();
02447     if (len > 2*MINLENGTH)
02448     {   // not necessary for short chains
02449       vtol_vertex_sptr v1 = e->v1(), v2 = e->v2();
02450 
02451       vcl_vector<double> cx(len);
02452       vcl_vector<double> cy(len);
02453 
02454       for (int qq=0; qq<len; ++qq)
02455       {
02456         vdgl_edgel e= dc->get_interpolator()->get_edgel_chain()->edgel( qq);
02457         cx[qq]= e.x();
02458         cy[qq]= e.y();
02459       }
02460 
02461       EqualizeElements(&cx[0], len, v1->cast_to_vertex_2d()->x(), v2->cast_to_vertex_2d()->x());
02462       EqualizeElements(&cy[0], len, v1->cast_to_vertex_2d()->y(), v2->cast_to_vertex_2d()->y());
02463 
02464       for (int qq=0; qq<len; ++qq)
02465       {
02466         vdgl_edgel e( cx[qq], cy[qq]);
02467         dc->get_interpolator()->get_edgel_chain()->set_edgel( qq, e);
02468       }
02469     }
02470   }
02471   if (talkative_)
02472     vcl_cout << ", in " << t.real() << " msecs.\n";
02473 }
02474 
02475 
02476 //: Translate all the pixels in the edges and vertices by (tx, ty).
02477 // If the image is extracted from an ROI, a translation of
02478 // (roi->GetOrigX(), roi->GetOrigY()) must be done to have
02479 // coordinates in the reference frame of the original image.
02480 // Add 0.5 if you want to display location at center of pixel
02481 // instead of upper-left corner.
02482 void
02483 sdet_contour::Translate(vcl_vector<vtol_edge_2d_sptr>& edges, // translate loc to center
02484                         vcl_vector<vtol_vertex_2d_sptr >& vertices,
02485                         float tx, float ty)
02486 {
02487   vul_timer t;
02488 
02489   if (talkative_)
02490     vcl_cout << "Translate edges/vertices\n";
02491 
02492   for (unsigned int i=0; i< vertices.size(); ++i)
02493   {
02494     vtol_vertex_2d_sptr  vert = vertices[i];
02495     vert->set_x(vert->x() + tx);
02496     vert->set_y(vert->y() + ty);
02497   }
02498   for (unsigned int i=0; i< edges.size(); ++i)
02499   {
02500     vtol_edge_2d_sptr edge = edges[i];
02501     vdgl_digital_curve_sptr dc = edge->curve()->cast_to_vdgl_digital_curve();
02502 
02503     vdgl_edgel_chain_sptr cxy= dc->get_interpolator()->get_edgel_chain();
02504     for (unsigned int k = 0; k < cxy->size(); ++k)
02505     {
02506       vdgl_edgel e= (*cxy)[k];
02507 
02508       e.set_x( e.x()+tx);
02509       e.set_y( e.y()+ty);
02510 
02511       cxy->set_edgel( k, e);
02512     }
02513   }
02514 
02515   if (talkative_)
02516     vcl_cout << ", in " << t.real() << " msecs.\n";
02517 }
02518 
02519 
02520 //:
02521 // Remove and delete all elements in global lists, and set
02522 // the global lists to NULL. Remove all digital chains of edges.
02523 // Edges and vertices are removed with UnProtect().
02524 void
02525 sdet_contour::ClearNetwork(vcl_vector<vtol_edge_2d_sptr>*& edges,
02526                            vcl_vector<vtol_vertex_2d_sptr >*& vertices)
02527 {
02528   delete edges; edges = NULL;
02529   delete vertices; vertices = NULL;
02530 }
02531 
02532 
02533 //:
02534 // Set the orientation at each edgel on all digital curves to a continuous
02535 // orientation value, which is consistent with C. Rothwell's EdgeDetector.
02536 // That is theta = (180/M_PI)*atan2(dI/dy, dI/dx)
02537 //
02538 void
02539 sdet_contour::SetEdgelData(gevd_bufferxy& grad_mag, gevd_bufferxy& angle, vcl_vector<vtol_edge_2d_sptr>& edges)
02540 {
02541   for (unsigned int i=0; i< edges.size(); ++i)
02542   {
02543     vtol_edge_2d_sptr e = edges[i];
02544     vdgl_digital_curve_sptr dc= e->curve()->cast_to_vdgl_digital_curve();
02545 
02546     if (dc)
02547     {
02548       vdgl_edgel_chain_sptr xypos= dc->get_interpolator()->get_edgel_chain();
02549 
02550       int len = xypos->size();
02551 
02552       for (int i = 0; i < len; ++i)
02553       {
02554         int ix = int((*xypos)[i].x());
02555         int iy = int((*xypos)[i].y());
02556 
02557         // Debugging : RIH
02558         // Routine crashes with iy < 0.
02559         if (iy < 0 || ix < 0 ||
02560             ix >= grad_mag.GetSizeX() ||
02561             iy >= grad_mag.GetSizeY())
02562         {
02563           vcl_cerr << "***********  ERROR  : (ix, iy) = ("
02564                    << ix << ", " << iy << ")\n";
02565           if (ix < 0) ix = 0;
02566           if (iy < 0) iy = 0;
02567           if (ix >= grad_mag.GetSizeX()) ix = grad_mag.GetSizeX()-1;
02568           if (iy >= grad_mag.GetSizeY()) iy = grad_mag.GetSizeY()-1;
02569         }
02570 
02571         (*xypos)[i].set_grad( floatPixel( grad_mag, ix, iy));
02572         (*xypos)[i].set_theta( floatPixel( angle, ix, iy));
02573 #if 0
02574         gr[i] = floatPixel(grad_mag, ix, iy);
02575         th[i] = floatPixel(angle, ix, iy);
02576 #endif
02577       }
02578     }
02579   }
02580 }
02581 
02582 
02583 //:
02584 // Insert topology object in 2-way lookup table,
02585 // using Id and dynamic array. Protect it in the network.
02586 void
02587 sdet_contour::LookupTableInsert(vcl_vector<vtol_edge_2d_sptr>& set,
02588                                 vtol_edge_2d_sptr elmt)
02589 {
02590   elmt->set_id(set.size());     // index in global array
02591   set.push_back(elmt);          // push_back at end of array
02592 }
02593 
02594 
02595 //: As above for vertices.
02596 void
02597 sdet_contour::LookupTableInsert(vcl_vector<vtol_vertex_2d_sptr >& set,
02598                                 vtol_vertex_2d_sptr  elmt)
02599 {
02600   elmt->set_id(set.size());     // index in global array
02601   set.push_back(elmt);          // push at end of array
02602 }
02603 
02604 
02605 //: Replace deleted by inserted in 2-way lookup table.
02606 // Also remove object from the network.
02607 void
02608 sdet_contour::LookupTableReplace(vcl_vector<vtol_edge_2d_sptr>& set,
02609                                  vtol_edge_2d_sptr deleted, vtol_edge_2d_sptr inserted)
02610 {
02611   const int i = deleted->get_id();
02612   inserted->set_id(i);
02613   set[i] = inserted;            // replace in global array
02614   btol_edge_algs::unlink_all_inferiors_twoway(deleted);
02615 }
02616 
02617 
02618 //: As above for vertices.
02619 void
02620 sdet_contour::LookupTableReplace(vcl_vector<vtol_vertex_2d_sptr >& set,
02621                                  vtol_vertex_2d_sptr  deleted, vtol_vertex_2d_sptr  inserted)
02622 {
02623   const int i = deleted->get_id();
02624   inserted->set_id(i);
02625   set[i] = inserted;            // replace in global array
02626 }
02627 
02628 
02629 //: Remove topology object from 2-way lookup table leaving an empty hole.
02630 // Also remove object from the network.
02631 void
02632 sdet_contour::LookupTableRemove(vcl_vector<vtol_edge_2d_sptr>& set,
02633                                 vtol_edge_2d_sptr elmt)
02634 {
02635   btol_edge_algs::unlink_all_inferiors_twoway(elmt);
02636   set[elmt->get_id()] = NULL;   // remove from global array
02637 }
02638 
02639 
02640 //: As above for vertices.
02641 void
02642 sdet_contour::LookupTableRemove(vcl_vector<vtol_vertex_2d_sptr >& set,
02643                                 vtol_vertex_2d_sptr  elmt)
02644 {
02645   set[elmt->get_id()] = NULL;   // remove from global array
02646 }
02647 
02648 
02649 //: Eliminate empty holes in the lookup table.
02650 void
02651 sdet_contour::LookupTableCompress(vcl_vector<vtol_edge_2d_sptr>& set)
02652 {
02653   vcl_vector<vtol_edge_2d_sptr> temp;
02654   //eliminate null edges
02655   for (vcl_vector<vtol_edge_2d_sptr>::iterator eit = set.begin();
02656        eit != set.end(); eit++)
02657     if (*eit)
02658       temp.push_back(*eit);
02659   int i = 0;
02660   set.clear();
02661   for (vcl_vector<vtol_edge_2d_sptr>::iterator eit = temp.begin();
02662        eit != temp.end(); eit++, i++)
02663   {
02664     (*eit)->set_id(i);
02665     set.push_back(*eit);
02666   }
02667 }
02668 
02669 //: As above for vertices.
02670 void
02671 sdet_contour::LookupTableCompress(vcl_vector<vtol_vertex_2d_sptr>& set)
02672 {
02673   vcl_vector<vtol_vertex_2d_sptr> temp;
02674   //eliminate null edges
02675   for (vcl_vector<vtol_vertex_2d_sptr>::iterator vit = set.begin();
02676        vit != set.end(); vit++)
02677     if (*vit)
02678       temp.push_back(*vit);
02679   int i = 0;
02680   set.clear();
02681   for (vcl_vector<vtol_vertex_2d_sptr>::iterator vit = temp.begin();
02682        vit != temp.end(); vit++, i++)
02683   {
02684     (*vit)->set_id(i);
02685     set.push_back(*vit);
02686   }
02687 }

Generated on Mon Mar 8 05:33:14 2010 for contrib/brl/bseg/sdet by  doxygen 1.5.1