contrib/gel/gevd/gevd_clean_edgels.cxx
Go to the documentation of this file.
00001 // This is gel/gevd/gevd_clean_edgels.cxx
00002 #include "gevd_clean_edgels.h"
00003 //:
00004 // \file
00005 
00006 #include <vcl_iostream.h>
00007 #include <vcl_vector.h>
00008 #include <vcl_algorithm.h> // for vcl_find()
00009 #include <vul/vul_timer.h>
00010 #include <vgl/vgl_point_2d.h>
00011 #include <vsol/vsol_point_2d.h>
00012 #include <vdgl/vdgl_digital_curve_sptr.h>
00013 #include <vdgl/vdgl_digital_curve.h>
00014 #include <vdgl/vdgl_edgel_chain_sptr.h>
00015 #include <vdgl/vdgl_edgel_chain.h>
00016 #include <vdgl/vdgl_interpolator_sptr.h>
00017 #include <vdgl/vdgl_interpolator.h>
00018 #include <vdgl/vdgl_interpolator_linear.h>
00019 #include <vtol/vtol_edge.h>
00020 #include <vtol/vtol_edge_2d.h>
00021 
00022 static bool verbose = false;
00023 
00024 //:
00025 // \todo not yet implemented
00026 static bool near_equal(vdgl_digital_curve_sptr /*dc1*/, vdgl_digital_curve_sptr /*dc2*/, float /*tolerance*/)
00027 {
00028   vcl_cerr << __FILE__ << ": near_equal(dc1,dc2) not yet implemented\n";
00029   return false; // TODO
00030 #if 0
00031   if (!(dc1&&dc2))
00032     return false;
00033   bool similar=true;
00034   double n1 = dc1->length(), n2 = dc2->length(), ns;
00035   //Curves should be similar in length
00036   if (vcl_fabs(n1-n2)>tolerance)
00037     return false;
00038 
00039   //Get the shortest curve to probe with
00040   vdgl_digital_curve_sptr dcs = NULL, dcl = NULL; //s for short, l for long
00041   if (n1>n2) { dcs = dc2; dcl = dc1; ns = n2; }
00042   else       { dcs = dc1; dcl = dc2; ns = n1; }
00043 
00044   //Scan the sort curve and get the distance from each edgel
00045   //to the longer curve.
00046   for (int i = 0; i<ns; i++)
00047   {
00048     vnl_vector<float> ps(X[i], Y[i], 0.0);
00049     float d = dcl->DistanceFrom(ps);
00050     if (d>tolerance) // A single distance violation means they aren't similar
00051     { similar = false; break; }
00052   }
00053   return similar;
00054 #endif
00055 }
00056 
00057 
00058 void gevd_clean_edgels::print_protection()
00059 {
00060 #ifdef DEBUG
00061   vcl_cout << "Protection Values: ";
00062   for (EdgelGroup::iterator egit = out_edgels_->begin();
00063        egit != out_edgels_->end(); ++egit)
00064     vcl_cout << (*egit)->GetProtection() << ' ';
00065   vcl_cout << vcl_endl << vcl_endl;
00066 #endif
00067 }
00068 
00069 
00070 //:Default Constructor
00071 gevd_clean_edgels::gevd_clean_edgels()
00072 {
00073   out_edgels_ = NULL;
00074 }
00075 
00076 
00077 //:Default Destructor
00078 gevd_clean_edgels::~gevd_clean_edgels()
00079 {
00080 }
00081 
00082 
00083 //: The main process method.  The input edgel group is filtered to remove bridges and short edges.
00084 void gevd_clean_edgels::DoCleanEdgelChains(vcl_vector<vtol_edge_2d_sptr>& in_edgels,
00085                                            vcl_vector<vtol_edge_2d_sptr>& out_edgels, int steps)
00086 {
00087   vul_timer t;
00088   out_edgels_= &out_edgels;
00089   out_edgels_->clear();
00090   //Copy the input edges to the output
00091   for (vcl_vector<vtol_edge_2d_sptr>::iterator egit = in_edgels.begin();
00092        egit != in_edgels.end(); ++egit)
00093     out_edgels_->push_back(*egit);
00094   if (steps > 0)
00095     this->JumpGaps();
00096   if (steps > 1)
00097     this->DeleteShortEdges();
00098   if (steps > 2)
00099     this->FixDefficientEdgels();
00100   if (steps > 3)
00101     this->RemoveBridges();
00102   if (steps > 4)
00103     this->RemoveJaggies();
00104   if (steps > 5)
00105     this->RemoveLoops();
00106   vcl_cout << "Total Clean Time(" << out_edgels_->size() << ") in " << t.real() << " msecs.\n";
00107 }
00108 
00109 
00110 //: Merge edges which have all edgels within a given tolerance
00111 //
00112 void gevd_clean_edgels::detect_similar_edges(vcl_vector<vtol_edge_2d_sptr >& common_edges,
00113                                              float tolerance,
00114                                              vcl_vector<vtol_edge_2d_sptr >& deleted_edges)
00115 {
00116   vcl_vector<vtol_edge_2d_sptr > temp;
00117   for (vcl_vector<vtol_edge_2d_sptr >::iterator e1it = common_edges.begin();
00118        e1it != common_edges.end(); ++e1it)
00119   {
00120     vtol_edge_2d_sptr e1 = (*e1it);
00121     vdgl_digital_curve_sptr dc1 = e1->curve()->cast_to_vdgl_digital_curve();
00122     if (!dc1) continue;
00123     vcl_vector<vtol_edge_2d_sptr >::iterator e2it = e1it;
00124     for (e2it++; e2it != common_edges.end(); ++e2it)
00125     {
00126       vtol_edge_2d_sptr e2 = (*e2it);
00127       vdgl_digital_curve_sptr dc2 = e2->curve()->cast_to_vdgl_digital_curve();
00128       if (near_equal(dc1, dc2, tolerance))
00129         temp.push_back(e2);
00130     }
00131   }
00132   for (vcl_vector<vtol_edge_2d_sptr >::iterator eit = temp.begin();
00133        eit != temp.end(); ++eit)
00134   {
00135     vtol_edge_2d_sptr e = (*eit);
00136     // e->unlink_all_inferiors(); // -tpk-
00137     deleted_edges.push_back(e);
00138   }
00139 }
00140 
00141 
00142 //: Find similar edges between v1 and some other vertex v and remove them.
00143 //  In this case, similar means all edgels of the similar edges lie within a given pixel tolerance
00144 //  from each other.
00145 void gevd_clean_edgels::remove_similar_edges(vtol_vertex_2d*& v1, vcl_vector<vtol_edge_2d_sptr >& deleted_edges)
00146 {
00147   float tol = 3.0f;
00148   vcl_vector<vtol_edge_sptr> v1_edges; v1->edges(v1_edges);
00149   vcl_vector<vtol_vertex_2d_sptr> opposite_v1_verts;
00150   // Find all the vertices opposite from v1
00151   for (vcl_vector<vtol_edge_sptr>::iterator eit = v1_edges.begin();
00152        eit != v1_edges.end(); ++eit)
00153   {
00154     vtol_vertex_2d_sptr v11 = (*eit)->v1()->cast_to_vertex_2d(),
00155                         v12 = (*eit)->v2()->cast_to_vertex_2d();
00156     if (v11==v1)
00157       {opposite_v1_verts.push_back(v12); continue;}
00158     if (v12==v1)
00159       {opposite_v1_verts.push_back(v11); continue;}
00160     vcl_cout << "In gevd_clean_edgels::remove_similar_edges(..) shouldn't happen\n";
00161   }
00162   //Then get the opposite vertices, v, with more than one edge between v1 and v
00163   //For these edges merge them into a common edge if they are too close
00164   for (vcl_vector<vtol_vertex_2d_sptr>::iterator vit= opposite_v1_verts.begin();
00165        vit != opposite_v1_verts.end(); ++vit)
00166   {
00167     vcl_vector<vtol_edge_2d_sptr > intersection;
00168     this->edge_exists(v1, (*vit), intersection);
00169     if (intersection.size()>1)
00170       this->detect_similar_edges(intersection, tol, deleted_edges);
00171   }
00172 }
00173 
00174 
00175 //: Find if an edge already exists between the given vertices
00176 bool gevd_clean_edgels::edge_exists(vtol_vertex_2d_sptr v1, vtol_vertex_2d_sptr v2, vcl_vector<vtol_edge_2d_sptr >& intersection)
00177 {
00178   bool found = false;
00179   intersection.clear();
00180 
00181   vcl_vector<vtol_edge_sptr> edges; v1->edges(edges);
00182 
00183   for (vcl_vector<vtol_edge_sptr>::iterator eit = edges.begin();
00184        eit != edges.end(); ++eit)
00185   {
00186     vtol_edge_2d* e = (*eit)->cast_to_edge_2d();
00187     if (!e) continue;
00188     if ( (e->v1()->cast_to_vertex_2d() == v1 && e->v2()->cast_to_vertex_2d() == v2) ||
00189          (e->v1()->cast_to_vertex_2d() == v2 && e->v2()->cast_to_vertex_2d() == v1) )
00190     {
00191       intersection.push_back(e);
00192       found = true;
00193     }
00194   }
00195   return found;
00196 }
00197 
00198 
00199 //: Remove edges which are already connected to the given vertex.
00200 void gevd_clean_edgels::remove_connected_edges(vtol_vertex_2d* v, vcl_vector<vtol_edge_2d_sptr >& edges)
00201 {
00202   vcl_vector<vtol_edge_2d_sptr > tmp;
00203   for (vcl_vector<vtol_edge_2d_sptr >::iterator eit = edges.begin();
00204        eit != edges.end(); ++eit)
00205   {
00206     vtol_edge_2d_sptr e = (*eit);
00207     if (e->v1() != v && e->v2() != v)
00208       tmp.push_back(e);
00209   }
00210   edges = tmp;
00211 }
00212 
00213 
00214 //: Find the closest vertex within a given radius on a given edge
00215 //  If one of the edge vertices is within the radius, then choose it.
00216 //  Otherwise return a vertex which lies on, and interior to, the edge.
00217 //  Original compared end vertex distances to radius, now with actual
00218 //  jump span - JLM Sept. 99
00219 bool gevd_clean_edgels::closest_vertex(vtol_edge_2d_sptr e, vsol_point_2d_sptr p, float radius, vtol_vertex_2d_sptr& v)
00220 {
00221   vdgl_digital_curve_sptr dc = e->curve()->cast_to_vdgl_digital_curve();
00222   if (!dc) { v = NULL; return false; }
00223   vsol_point_2d_sptr sp = new vsol_point_2d(*p);
00224   vsol_point_2d_sptr pc = dc->get_interpolator()->closest_point_on_curve( sp );
00225   double span_sq = p->distance(pc);
00226   if (radius < span_sq)
00227     vcl_cerr << __FILE__ << ": closest_vertex(): Warning: ignoring radius="
00228              << radius << " since span=" << span_sq << " is larger\n";
00229 
00230   vtol_vertex_2d_sptr v1 = e->v1()->cast_to_vertex_2d(), v2 = e->v2()->cast_to_vertex_2d();
00231   double d1 = v1->point()->distance(p);
00232   double d2 = v2->point()->distance(p);
00233   if (d1<d2)
00234   {
00235     if (d1<=span_sq)
00236     {
00237       v = v1;
00238       return true;
00239     }
00240   }
00241   else
00242   {
00243   if (d2<=span_sq)
00244   {
00245     v = v2;
00246     return true;
00247   }
00248   }
00249   v = new vtol_vertex_2d(*pc);
00250   return false;
00251 }
00252 
00253 
00254 //: Split an edge at a vertex which is assumed geometrically to lie on the edge.
00255 bool gevd_clean_edgels::split_edge(vtol_edge_2d_sptr e, vtol_vertex_2d_sptr new_v,
00256                                    vtol_edge_2d_sptr & e1, vtol_edge_2d_sptr & e2)
00257 {
00258   if (!e||!new_v)
00259   {
00260     vcl_cout << "In gevd_clean_edgels::split_edge(..) null edge or vertex\n";
00261     return false;
00262   }
00263   vdgl_digital_curve_sptr dc = e->curve()->cast_to_vdgl_digital_curve();
00264   if (!dc)
00265   {
00266     vcl_cout << "In gevd_clean_edgels::split_edge(..) no digital curve\n";
00267     return false;
00268   }
00269 
00270   // Find the proper index
00271   int index = -1;
00272   double min_distance = 10e5;
00273   for (unsigned int i=0; i< dc->get_interpolator()->get_edgel_chain()->size(); ++i)
00274   {
00275     vgl_point_2d<double> curve_point = dc->get_interpolator()->get_edgel_chain()->edgel(i).get_pt();
00276     double d = new_v->point()->distance(vsol_point_2d(curve_point));
00277     if (d < min_distance)
00278     {
00279       index = i;
00280       min_distance = d;
00281     }
00282   }
00283 
00284   vdgl_edgel_chain_sptr cxy= dc->get_interpolator()->get_edgel_chain();
00285 
00286   // 2. Create first subchain up to and including junction pixel.
00287   vtol_edge_2d_sptr edge1 = new vtol_edge_2d();    // create subchains, broken at junction.
00288   vdgl_edgel_chain_sptr ec= new vdgl_edgel_chain;
00289   vdgl_interpolator_sptr it= new vdgl_interpolator_linear( ec);
00290   vdgl_digital_curve_sptr dc1 = new vdgl_digital_curve( it);
00291   edge1->set_curve(*dc1);
00292   vdgl_edgel_chain_sptr cxy1= ec;
00293 
00294   for (int k = 0; k < index; k++)
00295     cxy1->add_edgel( (*cxy)[k] );
00296 
00297   vtol_vertex_2d * v1 = e->v1()->cast_to_vertex_2d();
00298 
00299   edge1->set_v1(v1);            // link both directions v-e
00300   edge1->set_v2(new_v->cast_to_vertex());     // unlink when stronger.UnProtect()
00301 
00302   // Create second subchain from and including junction pixel.
00303   vtol_edge_2d_sptr edge2 = new vtol_edge_2d();    // create second subchain
00304   vdgl_edgel_chain *ec2= new vdgl_edgel_chain;
00305   vdgl_interpolator *it2= new vdgl_interpolator_linear( ec2);
00306   vdgl_digital_curve_sptr dc2= new vdgl_digital_curve( it2);
00307   edge2->set_curve(*dc2);
00308   vdgl_edgel_chain *cxy2= ec2;
00309 
00310   for (unsigned int k = index; k < dc->get_interpolator()->get_edgel_chain()->size(); ++k)
00311     cxy2->add_edgel( cxy->edgel( k ));
00312 
00313   vtol_vertex_sptr v2 = e->v2()->cast_to_vertex();
00314 
00315   edge2->set_v1(new_v->cast_to_vertex());     // link both directions v-e
00316   edge2->set_v2(v2.ptr());            // unlink when stronger.UnProtect()
00317 
00318 
00319 #if 0
00320   if (!dc->Split(*(new_v->GetLocation()), dc1, dc2))
00321   {
00322     e1 = NULL; e2 = NULL;
00323     return false;
00324   }
00325   vtol_vertex_2d_sptr v1 = e->v1()->cast_to_vertex_2d(),
00326                       v2 = e->v2()->cast_to_vertex_2d();
00327   e1 = new vtol_edge_2d(v1, new_v); e2 = new vtol_edge_2d(new_v, v2);
00328   e1->set_curve(dc1) ; e2->set_curve(dc2);
00329 #else
00330   e1 = edge1;
00331   e2 = edge2;
00332 #endif
00333   return true;
00334 }
00335 
00336 
00337 //: Jump gaps by finding the nearest edge to a vertex which is not incident on the vertex.
00338 //  If some point on the digital curve of edge is within a radius of the vertex, then jump across.
00339 //
00340 void gevd_clean_edgels::JumpGaps()
00341 {
00342   vul_timer t;
00343   float radius = 5.0f;
00344   //  float radius = 5.0; Feb 08, 2001 - used in recent DDB exp
00345   //  float radius = 6.0;
00346   //All the vertices of the initial segmentation
00347   vcl_vector<vtol_vertex_2d*> verts;
00348   vcl_vector<vtol_edge_2d_sptr >::iterator eit;
00349   for (eit = out_edgels_->begin(); eit != out_edgels_->end(); ++eit)
00350   {
00351     verts.push_back( (*eit)->v1()->cast_to_vertex_2d() );
00352     verts.push_back( (*eit)->v2()->cast_to_vertex_2d() );
00353   }
00354   //Iterate over the vertices and find nearby edgel chains
00355   for (vcl_vector<vtol_vertex_2d*>::iterator vit = verts.begin();
00356        vit != verts.end(); ++vit)
00357   {
00358     vtol_vertex_2d* v = (*vit);
00359     vsol_point_2d_sptr p = v->point();
00360     //Get the edges within the radius of the vertex
00361     vcl_vector<vtol_edge_2d_sptr > near_edges;
00362 
00363     // out_edgels_->EdgesWithinRadius(*p, radius, near_edges);
00364     // Find edges within the given radius
00365     for (eit = out_edgels_->begin(); eit != out_edgels_->end(); ++eit)
00366     {
00367       vdgl_digital_curve_sptr dc = (*eit)->curve()->cast_to_vdgl_digital_curve();
00368       if (dc && radius > dc->get_interpolator()->distance_curve_to_point(p))
00369         near_edges.push_back( *eit );
00370     }
00371 
00372     if (verbose) vcl_cout << "Found: " << near_edges.size() << " near edges, ";
00373     //Get rid of edges already connected to the vertex
00374 
00375     this->remove_connected_edges(v, near_edges);
00376     if (verbose) vcl_cout << "There were " << near_edges.size() << " after connected removal\n";
00377     //Now iterate over the nearby edges and try to connect
00378     //We assume that the edges all have digital curves
00379           int nnn = 1;
00380     for (eit = near_edges.begin(); eit != near_edges.end() && nnn == 1; ++eit)
00381     {
00382       ///      nnn=0;
00383       vtol_edge_2d_sptr  e = (*eit);
00384       vtol_vertex_2d_sptr new_v = NULL;
00385       //If end_vertex is true, then one of the vertices of e is
00386       //within the given radius
00387       bool end_vertex = this->closest_vertex(e, p, radius, new_v);
00388       if (!new_v) continue; // should always have a new_v
00389       if (!end_vertex)
00390       {
00391         //The new vertex is interior to e,
00392         //so we have to split the edge
00393         vtol_edge_2d_sptr e1=NULL, e2=NULL;
00394         if (verbose) vcl_cout << "Splitting " << e->v1()->cast_to_vertex() << e->v2()->cast_to_vertex() << vcl_endl;
00395         if (!this->split_edge(e, new_v, e1, e2))
00396           continue;
00397         if (verbose) vcl_cout << "It Split, new is: " << *new_v << vcl_endl;
00398         out_edgels_->push_back(e1);
00399         out_edgels_->push_back(e2);
00400         vcl_vector<vtol_edge_2d_sptr >::iterator f;
00401         //e->unlink(); -tpk-
00402         f = vcl_find(out_edgels_->begin(), out_edgels_->end(), e);
00403         if (f != out_edgels_->end())
00404         {
00405           if (verbose) vcl_cout <<"getting rid of old edge\n";
00406           out_edgels_->erase(f);
00407         }
00408       }
00409       //Check if an edge already exists
00410       vcl_vector<vtol_edge_2d_sptr > intersection;//Contains the duplicate edge(s)
00411       if (this->edge_exists(v, new_v, intersection))
00412         {
00413         continue;
00414         }
00415       //Now add the new edge which fills the gap
00416       if (verbose) vcl_cout << "Adding a gap jumping edgel from " << *v << " to " << *new_v << vcl_endl;
00417       vtol_edge_2d_sptr new_edge = new vtol_edge_2d(v, new_v);
00418       // vdgl_digital_curve_sptr dc = new vdgl_digital_curve(v->point(),new_v->point());
00419       vdgl_edgel_chain* new_chain = new vdgl_edgel_chain();
00420       new_chain->add_edgel(vdgl_edgel(v->point()->x(), v->point()->y()));
00421       new_chain->add_edgel(vdgl_edgel(new_v->point()->x(), new_v->point()->y()));
00422       vdgl_digital_curve_sptr dc = new vdgl_digital_curve(new vdgl_interpolator_linear(new_chain));
00423       // dc->set_p0(vsol_point_2d_sptr(new vsol_point_2d(v)));
00424       new_edge->set_curve(*dc);
00425       out_edgels_->push_back(new_edge);
00426     }
00427   }
00428   // delete verts;
00429   vcl_cout << "JumpGaps(" << out_edgels_->size() << ") in " << t.real() << " msecs.\n";
00430 }
00431 
00432 
00433 //: Remove all edges which are shorter than two pixels.
00434 //     That is, e.V1() and e.v2().ptr() are closer than three pixels along both image
00435 //     axes, and no edgel in the vtol_edge_2d is farther than two pixels from vertices.
00436 //     The edge is removed and replaced by a single vertex at the
00437 //     average location.
00438 void gevd_clean_edgels::DeleteShortEdges()
00439 {
00440   int d_remove=2;
00441   int d_close = 1;
00442   vul_timer t;
00443   int N_total=0, N_close=0;
00444   vcl_vector<vtol_edge_2d_sptr > deleted_edges;
00445   int edgelcount = 0;
00446   for (vcl_vector<vtol_edge_2d_sptr >::iterator egit = out_edgels_->begin();
00447        egit != out_edgels_->end(); egit++, ++N_total)
00448   {
00449     if ( (edgelcount % 100) == 0 )
00450       vcl_cout << "Edgels: " << edgelcount << '/' << out_edgels_->size() << vcl_endl;
00451     edgelcount++;
00452     vtol_edge_2d_sptr e = (vtol_edge_2d_sptr )(*egit);
00453     vtol_vertex_2d* v1 = e->v1()->cast_to_vertex_2d();
00454     vtol_vertex_2d* v2 = e->v2()->cast_to_vertex_2d();
00455     double fx1 = v1->x(), fy1 = v1->y();
00456     double fx2 = v2->x(), fy2 = v2->y();
00457     int x1 = int(fx1), y1 = int(fy1);
00458     int x2 = int(fx2), y2 = int(fy2);
00459     int dx = x2-x1; if (dx < 0) dx = -dx; // dx = vcl_abs(x2-x1);
00460     int dy = y2-y1; if (dy < 0) dy = -dy; // dy = vcl_abs(y2-y1);
00461     //First, are the vertices too close?
00462     if (dx<d_remove && dy<d_remove)
00463     {
00464       N_close++;
00465       //If so, then check if all edgels in the EdgelChain are
00466       // too close, i.e, within 2 pixels of both vertices
00467       vdgl_digital_curve_sptr dc = e->curve()->cast_to_vdgl_digital_curve();
00468       vdgl_edgel_chain_sptr chain = dc->get_interpolator()->get_edgel_chain();
00469       int n_edgels = chain->size();
00470       bool all_close = true;
00471       for (int t = 0; (t<n_edgels)&&all_close; t++)
00472       {
00473         int xe = int(chain->edgel(t).x());
00474         int ye = int(chain->edgel(t).y());
00475         dx = xe-x1; if (dx < 0) dx = -dx; // dx = vcl_abs(xe-x1);
00476         dy = ye-y1; if (dy < 0) dy = -dy; // dy = vcl_abs(ye-y1);
00477         bool far_from_v1 = (dx>d_close||dy>d_close);
00478         dx = xe-x2; if (dx < 0) dx = -dx; // dx = vcl_abs(xe-x2);
00479         dy = ye-y2; if (dy < 0) dy = -dy; // dy = vcl_abs(ye-y2);
00480         bool far_from_v2 = (dx>d_close||dy>d_close);
00481         if (far_from_v1&&far_from_v2)
00482           all_close = false;
00483       }
00484 
00485       //They are all too close so, get rid of the edge
00486       if (all_close)
00487       {
00488         // e->unlink_all_inferiors_twoway(e);
00489         // e->unlink_all_inferiors();
00490         // v1->merge_references(v2);
00491         v1->set_x((fx1+fx2)/2);//This could cause missing edgels
00492         v1->set_y((fy1+fy2)/2);
00493         this->remove_similar_edges(v1, deleted_edges);
00494         //We remove e last since it may already
00495         //have been removed by remove_similar_edges
00496         deleted_edges.push_back(e);
00497       }
00498     }
00499   }
00500   for (vcl_vector<vtol_edge_2d_sptr >::iterator eit = deleted_edges.begin();
00501        eit != deleted_edges.end(); ++eit)
00502   {
00503     vcl_vector<vtol_edge_2d_sptr >::iterator f;
00504     // (*eit)->unlink();
00505     f = vcl_find(out_edgels_->begin(), out_edgels_->end(), *eit);
00506     if (f != out_edgels_->end())
00507       out_edgels_->erase( f );
00508   }
00509 
00510   vcl_cout << "Delete Short Edges(" << out_edgels_->size() << ") in " << t.real() << " msecs.\n"
00511            << "Ntotal = " << N_total << "  Nclose =  " << N_close << vcl_endl;
00512 }
00513 
00514 
00515 //: A bridge is an edge or a sequence of edges which is not closed.
00516 //    In this approach, a set of vertices with order one (one incident edge) is
00517 //    found and the associated edges are deleted.  The process is repeated
00518 //    until no more vertices of order one are found.
00519 void gevd_clean_edgels::RemoveBridges()
00520 {
00521   vul_timer t;
00522   bool order_one = true;
00523   vcl_vector<vtol_vertex_2d*> v_one;
00524   while (order_one)
00525   {
00526     //Get the current set of vertices
00527     // vcl_vector<vtol_vertex_2d*>* verts = Vertices(out_edgels_);
00528     vcl_vector<vtol_vertex_2d*> verts;
00529     vcl_vector<vtol_edge_2d_sptr >::iterator eit;
00530     for (eit = out_edgels_->begin(); eit != out_edgels_->end(); ++eit)
00531     {
00532       verts.push_back( (*eit)->v1()->cast_to_vertex_2d() );
00533       verts.push_back( (*eit)->v2()->cast_to_vertex_2d() );
00534     }
00535     v_one.clear();
00536     //Collect all the vertices of order one which are not self-loops.
00537     for (vcl_vector<vtol_vertex_2d*>::iterator vit = verts.begin();
00538          vit != verts.end(); ++vit)
00539     {
00540       vtol_vertex_2d* v = *vit;
00541       vcl_vector<vtol_edge_sptr> edges; v->edges(edges);
00542       if (edges.size()==1)
00543       {
00544         vtol_edge_sptr e = edges[0];
00545         if (e->v1()!=e->v2())
00546           v_one.push_back(v);
00547       }
00548     }
00549     //The main termination condition, i.e., no order one vertices
00550     if (v_one.size()==0)
00551     {
00552       order_one=false;
00553       continue;
00554     }
00555     //Remove the Edge(s) attached to order zero vertices
00556     for (vcl_vector<vtol_vertex_2d*>::iterator v1 = v_one.begin();
00557          v1 != v_one.end(); ++v1)
00558     {
00559       vcl_vector<vtol_edge_sptr> v_edges; (*v1)->edges(v_edges);
00560       int order = v_edges.size();
00561       if (order<1 )
00562       {
00563         //We can leave isolated vertices in v_one
00564         //but they will go away on the next sweep
00565         continue;
00566       }
00567       vtol_edge_sptr ep = v_edges[0];
00568       if (!ep)
00569       {
00570         vcl_cout << "In gevd_clean_edgels::RemoveBridges() - null edge\n";
00571         order_one = false;
00572         continue;
00573       }
00574       vtol_edge_2d_sptr e = ep->cast_to_edge_2d();
00575       if (!e)
00576       {
00577         vcl_cout << "In gevd_clean_edgels::RemoveBridges() - edge is not an edge_2d\n";
00578         order_one = false;
00579         continue;
00580       }
00581       // e->unlink_all_inferiors_twoway(e);
00582       // e->unlink_all_inferiors();
00583       vcl_vector<vtol_edge_2d_sptr >::iterator f;
00584       vcl_cout << "Removing from output edgels: " << e << vcl_endl;
00585       // e->unlink();
00586       f = vcl_find(out_edgels_->begin(), out_edgels_->end(), e);
00587       if (f != out_edgels_->end())
00588       {
00589         out_edgels_->erase(f);
00590       }
00591     }
00592   }
00593   vcl_cout << "Remove Bridges(" << out_edgels_->size() << ") in " << t.real() << " msecs.\n";
00594 }
00595 
00596 
00597 //:
00598 //  Check if the number of edgels is <=2.  If so, replace the
00599 //  vdgl_digital_curve_sptr with one formed from a straight line between the endpoints.
00600 void gevd_clean_edgels::FixDefficientEdgels()
00601 {
00602   vul_timer t;
00603   for (vcl_vector<vtol_edge_2d_sptr >::iterator egit = out_edgels_->begin();
00604        egit!=out_edgels_->end(); ++egit)
00605   {
00606     bool fix_it = false;
00607     vtol_edge_2d_sptr e = (vtol_edge_2d_sptr )(*egit);
00608     vdgl_digital_curve_sptr dc = e->curve()->cast_to_vdgl_digital_curve();
00609     fix_it = fix_it || !dc;
00610     int n_edgels = dc->get_interpolator()->get_edgel_chain()->size();
00611     fix_it = fix_it || n_edgels<=2;
00612     if (fix_it)
00613     {
00614       vtol_vertex_2d_sptr v1 = e->v1()->cast_to_vertex_2d();
00615       vtol_vertex_2d_sptr v2 = e->v2()->cast_to_vertex_2d();
00616       vsol_point_2d_sptr p1 = v1->point();
00617       vsol_point_2d_sptr p2 = v2->point();
00618       // vdgl_digital_curve_sptr dc = new vdgl_digital_curve(p1, p2);
00619       vdgl_edgel_chain_sptr chain = new vdgl_edgel_chain();
00620       // chain->set_p0(p1);
00621       // chain->set_p1(p2);
00622       chain->add_edgel(vdgl_edgel(p1->x(), p1->y()));
00623       chain->add_edgel(vdgl_edgel(p2->x(), p2->y()));
00624       vdgl_digital_curve_sptr dc = new vdgl_digital_curve(new vdgl_interpolator_linear(chain));
00625       e->set_curve(*dc);
00626     }
00627   }
00628   vcl_cout << "Fix Defficient Edgels(" << out_edgels_->size() << ") in " << t.real() << " msecs.\n";
00629 }
00630 
00631 
00632 //:
00633 //    The VD edgedetector produces wild jaggies in the contour
00634 //    from time to time.  This function "smooths' the digital
00635 //    chains by removing sharp adjacent excursions.
00636 void gevd_clean_edgels::RemoveJaggies()
00637 {
00638   vul_timer t;
00639   for (vcl_vector<vtol_edge_2d_sptr >::iterator egit = out_edgels_->begin();
00640        egit!=out_edgels_->end(); ++egit)
00641   {
00642     vtol_edge_2d_sptr e = (vtol_edge_2d_sptr )(*egit);
00643     vtol_vertex_2d_sptr v1 = e->v1()->cast_to_vertex_2d();
00644     vtol_vertex_2d_sptr v2 = e->v2()->cast_to_vertex_2d();
00645     double x1 = v1->x(), y1 = v1->y();
00646     double x2 = v2->x(), y2 = v2->y();
00647     vdgl_digital_curve_sptr dc = e->curve()->cast_to_vdgl_digital_curve();
00648     vdgl_edgel_chain_sptr chain = dc->get_interpolator()->get_edgel_chain();
00649     int n_edgels = chain->size();
00650     int n1 = n_edgels-1;
00651     double xo = chain->edgel(0).x(), yo = chain->edgel(0).y();
00652     // dc->GetX(0), yo = dc->GetY(0);
00653     // float xn = dc->GetX(n1), yn = dc->GetY(n1);
00654     double xn = chain->edgel(n1).x(), yn = chain->edgel(n1).y();
00655     double d1o = (x1-xo)*(x1-xo) + (y1-yo)*(y1-yo);
00656     double d1n = (x1-xn)*(x1-xn) + (y1-yn)*(y1-yn);
00657     if (d1o<d1n)//The expected case
00658     {
00659       // dc->SetX(x1, 0); dc->SetY(y1, 0);
00660       chain->edgel(0).set_x(x1);
00661       chain->edgel(0).set_y(y1);
00662       // dc->SetX(x2, n1); dc->SetY(y2, n1);
00663       chain->edgel(n1).set_x(x2);
00664       chain->edgel(n1).set_y(y2);
00665     }
00666     else
00667     {
00668       // dc->SetX(x2, 0); dc->SetY(y2, 0);
00669       chain->edgel(0).set_x(x2);
00670       chain->edgel(0).set_y(y2);
00671       // dc->SetX(x1, n1); dc->SetY(y1, n1);
00672       chain->edgel(n1).set_x(x1);
00673       chain->edgel(n1).set_y(y1);
00674     }
00675   }
00676   vcl_cout << "Remove Jaggies(" << out_edgels_->size() << ") in " << t.real() << " msecs.\n";
00677 }
00678 
00679 
00680 //: Removal of edges can also produce loops.  Short loops should be removed.
00681 void gevd_clean_edgels::RemoveLoops()
00682 {
00683   vul_timer t;
00684   float min_loop_length = 4.0f;  //6 is normally used in Clean
00685   vcl_vector<vtol_edge_2d_sptr > removed_edges;
00686   for (vcl_vector<vtol_edge_2d_sptr >::iterator egit = out_edgels_->begin();
00687        egit!=out_edgels_->end(); ++egit)
00688   {
00689     vtol_edge_2d_sptr e = (vtol_edge_2d_sptr )(*egit);
00690     vtol_vertex_2d_sptr v1 = e->v1()->cast_to_vertex_2d();
00691     vtol_vertex_2d_sptr v2 = e->v2()->cast_to_vertex_2d();
00692     if (*v1==*v2)//We have a loop
00693     {
00694       vdgl_digital_curve_sptr c = e->curve()->cast_to_vdgl_digital_curve();
00695       double len = c->length();
00696       if (verbose) vcl_cout << "In Remove Loops: "<< v1 << " L = " << len << vcl_endl;
00697       if (len<min_loop_length)
00698       {
00699         // e->unlink_all_inferiors_twoway(e);
00700         // e->unlink_all_inferiors();
00701         removed_edges.push_back(e);
00702       }
00703     }
00704   }
00705 
00706   for (vcl_vector<vtol_edge_2d_sptr >::iterator eit = removed_edges.begin();
00707        eit != removed_edges.end(); ++eit)
00708   {
00709     vcl_vector<vtol_edge_2d_sptr>::iterator f = vcl_find(out_edgels_->begin(), out_edgels_->end(), *eit);
00710     if (f != out_edgels_->end())
00711       out_edgels_->erase(f);
00712   }
00713 
00714   vcl_cout << "Remove Loops(" << out_edgels_->size() << ") in " << t.real() << " msecs.\n";
00715 }