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