1 #include <iostream>
2 #include <fstream>
3 #include <deque>
4 #include <map>
5 #include <set>
6 #include <algorithm>
7 #include "sdet_sel_base.h"
8 
9 #include <cassert>
10 #ifdef _MSC_VER
11 #  include "vcl_msvc_warnings.h"
12 #endif
13 //#include <mbl/mbl_stats_1d.h>
14 
15 #include "sdet_edgemap.h"
16 // remove dependency on mul
17 #include "vnl/vnl_vector.h"
calc_mean_var(double & mean,double & var,const double * d,int n)18 static void calc_mean_var(double& mean, double& var,
19                           const double* d, int n){
20     double sum=0;
21     double sum2 = 0;
22     for (int i=0;i<n;++i)
23       {
24         sum+=d[i];
25         sum2+=d[i]*d[i];
26       }
27 
28     mean = sum/n;
29     var  = (sum2 - n*mean*mean)/(n-1);
30 }
calc_mean_var(double & mean,double & var,const vnl_vector<double> & d)31 static void calc_mean_var(double& mean, double& var,
32                           const vnl_vector<double>& d){
33   calc_mean_var(mean,var,d.data_block(),d.size());
34 }
35 //: Constructor
36 sdet_sel_base
sdet_sel_base(const sdet_edgemap_sptr & edgemap,sdet_curvelet_map & cvlet_map,sdet_edgel_link_graph & edge_link_graph,sdet_curve_fragment_graph & curve_frag_graph,sdet_curvelet_params cvlet_params)37 ::sdet_sel_base(const sdet_edgemap_sptr& edgemap,
38                 sdet_curvelet_map& cvlet_map,
39                 sdet_edgel_link_graph& edge_link_graph,
40                 sdet_curve_fragment_graph& curve_frag_graph,
41                 sdet_curvelet_params cvlet_params) :
42   edgemap_(edgemap),
43   curvelet_map_(cvlet_map),
44   edge_link_graph_(edge_link_graph),
45   curve_frag_graph_(curve_frag_graph),
46   nrows_(edgemap->height()),
47   ncols_(edgemap->width()),
48   app_usage_(0),
49   app_thresh_(2),
50   rad_(cvlet_params.rad_),
51   dtheta_(cvlet_params.dtheta_*vnl_math::pi/180),
52   dpos_(cvlet_params.dpos_),
53   badap_uncer_(cvlet_params.badap_uncer_),
54   token_len_(cvlet_params.token_len_),
55   max_k_(cvlet_params.max_k_),
56   max_gamma_(cvlet_params.max_gamma_),
57   nrad_((unsigned) std::ceil(rad_)+1),
58   gap_(cvlet_params.gap_),
59   maxN_(2*nrad_),
60   centered_(cvlet_params.centered_),
61   bidir_(cvlet_params.bidirectional_),
62   use_anchored_curvelets_(true),
63   min_deg_to_link_(4),
64   use_hybrid_(false),
65   DHT_mode_(true),
66   propagate_constraints(true)
67 {
68   //save the parameters in the curvelet map
69   curvelet_map_.set_edgemap(edgemap);
70   curvelet_map_.set_parameters(cvlet_params);
71 }
72 
73 //:destructor
74 sdet_sel_base
75 ::~sdet_sel_base()
76 = default;
77 
78 //********************************************************************//
79 // User Friendly functions
80 //********************************************************************//
81 
82 //: use the recommended sub-algorithms to extract final contour set (naive users should call this function)
83 void
84 sdet_sel_base
extract_image_contours()85 ::extract_image_contours()
86 {
87   //1) perform local edgel grouping
88   set_appearance_usage(0); //do not use
89   set_appearance_threshold(0.2);
90 
91   build_curvelets_greedy(2*nrad_, false, true, true); //greedy (depth first grouping)
92 
93   //2) form the link graph
94   use_anchored_curvelets_only();
95   construct_the_link_graph(4, 0);
96 
97   //extract contours
98   extract_regular_contours_from_the_link_graph();
99 
100   //extract_image_contours_from_the_link_graph(1);
101 
102 }
103 
104 //: group pairs of edgels into curvelets
105 void
106 sdet_sel_base
build_pairs()107 ::build_pairs()
108 {
109   std::cout << "Building pairs ...";
110   std::cout.flush();
111 
112   //std::ofstream outfp("pair_distribution.txt", std::ios::out);
113 
114   //form pairs from the edgels in the local neighborhood
115   for (unsigned i=0; i<edgemap_->edgels.size(); i++){
116     sdet_edgel* eA = edgemap_->edgels[i];
117 
118     //get the grid coordinates of this edgel
119     unsigned ii = sdet_round(eA->pt.x());
120     unsigned jj = sdet_round(eA->pt.y());
121 
122     int cnt = 0; //count the # of neighboring edgels
123 
124     //iterate over the cell neighborhoods around this edgel that contains the full edgel neighborhood
125     for (int xx=(int)ii-(int)nrad_; xx<=(int)(ii+nrad_) ; xx++){
126       for (int yy=(int)jj-(int)nrad_; yy<=(int)(jj+nrad_) ; yy++){
127 
128         if (xx<0 || xx>=(int)ncols_ || yy<0 || yy>=(int)nrows_)
129           continue;
130 
131         unsigned N = edgemap_->cell(xx, yy).size();
132         for (unsigned k=0; k<N; k++){
133           sdet_edgel* eB = edgemap_->cell(xx, yy)[k];
134           if (eB == eA) continue;
135 
136           cnt++;
137 
138           // form edgel pair eA->eB.
139           // there is no need to form eB->eA because this will be done by eB
140           form_an_edgel_pair(eA,eB);
141         }
142       }
143     }
144     // save the neighboring edge count
145     //outfp << cnt <<std::endl;
146   }
147 
148   //close file
149   //outfp.close();
150 
151   std::cout << "done!" << std::endl;
152 }
153 
154 
155 //: form curvelets around each edgel in a greedy fashion
156 void
157 sdet_sel_base
build_curvelets_greedy(unsigned max_size_to_group,bool use_flag,bool clear_existing,bool verbose)158 ::build_curvelets_greedy(unsigned max_size_to_group,bool use_flag, bool clear_existing, bool verbose)
159 {
160   if (verbose){
161     std::cout << "Building All Possible Curvelets (Greedy) ..." ;
162     std::cout.flush();
163   }
164 
165   if (clear_existing){
166     //clear the curvelet map
167     curvelet_map_.clear();
168 
169     //form a new curvelet map
170     curvelet_map_.resize(edgemap_->num_edgels());
171 
172     if (verbose){
173       std::cout << "curvelet map cleared..." ;
174       std::cout.flush();
175     }
176   }
177 
178   //store this parameter
179   maxN_ = max_size_to_group;
180 
181   if (centered_) {
182     if (bidir_) {
183       for (auto eA : edgemap_->edgels) {
184         // centered_ && bidir_
185         build_curvelets_greedy_for_edge(eA, max_size_to_group, use_flag, true, centered_, false); //first in the forward direction
186         build_curvelets_greedy_for_edge(eA, max_size_to_group, use_flag, false, centered_, false); //then in the other direction
187       }
188     } else {
189       for (auto eA : edgemap_->edgels) {
190         // centered_ && !bidir_
191         build_curvelets_greedy_for_edge(eA, max_size_to_group, use_flag, true, centered_, false); //first in the forward direction
192       }
193     }
194   } else {
195     if (bidir_) {
196       for (auto eA : edgemap_->edgels) {
197         build_curvelets_greedy_for_edge(eA, max_size_to_group, use_flag, true, centered_, true); //forward half
198         build_curvelets_greedy_for_edge(eA, max_size_to_group, use_flag, false, centered_, true); //backward half
199         // !centered_ && bidir_
200       }
201     } else {
202       for (auto eA : edgemap_->edgels) {
203         build_curvelets_greedy_for_edge(eA, max_size_to_group, use_flag, true, centered_, true); //forward half
204         build_curvelets_greedy_for_edge(eA, max_size_to_group, use_flag, true, centered_, false); //ENO style forward
205         // !centered_ && !bidir_
206       }
207     }
208   }
209 
210   if (verbose)
211     std::cout << "done!" << std::endl;
212 }
213 
214 
215 //: form the full curvelet map (curvelet map lists all the curvelets it participated in and not just the ones anchored to it)
216 void
217 sdet_sel_base
form_full_cvlet_map()218 ::form_full_cvlet_map()
219 {
220   // This method forms a curvelet map which is a mapping from each edgel to all the
221   // curvelets it participates in and not just the ones anchored to it
222 
223   for (unsigned i=0; i<edgemap_->edgels.size(); i++){
224     sdet_edgel* eA = edgemap_->edgels[i];
225 
226     //add all the curvelets anchored at this edgel to all the other edgels in it
227     auto cv_it = curvelet_map_.curvelets(i).begin();
228     for ( ; cv_it!=curvelet_map_.curvelets(i).end(); cv_it++){
229       sdet_curvelet* cvlet = (*cv_it);
230 
231       //only add the ones that are anchored to this edgel
232       if (cvlet->ref_edgel != eA)
233         continue;
234 
235       //add this curvelet to each of the edgels of the grouping
236       for (unsigned n=0; n<cvlet->edgel_chain.size(); n++){
237         sdet_edgel* eB = cvlet->edgel_chain[n];
238 
239         //make sure that there are no duplicates (this is not strictly necessary)
240         bool cvlet_exists = false; //reset flag
241 
242         //go over all the curvelets (not just anchored) formed by the current edgel
243         auto cv_it2 = curvelet_map_.curvelets(eB->id).begin();
244         for ( ; cv_it2!=curvelet_map_.curvelets(eB->id).end(); cv_it2++){
245           sdet_curvelet* cvlet2 = (*cv_it2);
246 
247           if (cvlet2==cvlet){
248             cvlet_exists=true;
249             break;
250           }
251 
252           if (cvlet2->edgel_chain.size() != cvlet->edgel_chain.size())
253             continue;
254 
255           bool exists = true;
256           for (unsigned k=0; k<cvlet2->edgel_chain.size(); k++)
257             exists = exists && (cvlet2->edgel_chain[k]==cvlet->edgel_chain[k]);
258 
259           //the flag will remain true only if all the edgels match
260           if (exists){
261             cvlet_exists= true;
262             break;
263           }
264         }
265 
266         if (!cvlet_exists)
267           curvelet_map_.curvelets(eB->id).push_back((*cv_it)); //insert this into the map
268 
269       }
270     }
271   }
272 
273 }
274 
275 //: check to see if curvelets are balanced
276 bool
277 sdet_sel_base
curvelet_is_balanced(sdet_edgel * ref_e,std::deque<sdet_edgel * > & edgel_chain)278 ::curvelet_is_balanced(sdet_edgel* ref_e, std::deque<sdet_edgel*> &edgel_chain)
279 {
280   //looks like this is one of the qualitites we need of an edgel grouping before it can qualify to be a curvelet
281 
282   //find out the # of edgels before and after the reference edgel
283   //also find out the length before and after the reference edgel
284   int num_before=0, num_after=0;
285   double Lm=0, Lp=0;
286 
287   bool before_ref = true;
288   for (unsigned i=0; i<edgel_chain.size()-1; i++){
289     if (before_ref) { Lm += vgl_distance(edgel_chain[i]->pt, edgel_chain[i+1]->pt); num_before++; }
290     else            { Lp += vgl_distance(edgel_chain[i]->pt, edgel_chain[i+1]->pt); num_after++; }
291 
292     if (edgel_chain[i+1]==ref_e)
293       before_ref = false;
294   }
295 
296   //simple measure of balance.
297   if (num_before<1 || num_after<1)
298     return false;
299   else
300     return true;
301 }
302 
303 void
304 sdet_sel_base
recompute_curvelet_quality()305 ::recompute_curvelet_quality()
306 {
307   for (unsigned i=0; i<edgemap_->edgels.size(); i++)
308   {
309     auto cv_it = curvelet_map_.curvelets(i).begin();
310     for ( ; cv_it!=curvelet_map_.curvelets(i).end(); cv_it++)
311       (*cv_it)->compute_properties(rad_, token_len_);
312   }
313 }
314 
315 //: prune the curvelets with gaps larger than the one specified
316 void
317 sdet_sel_base
prune_curvelets_by_gaps(double gap_threshold)318 ::prune_curvelets_by_gaps(double gap_threshold)
319 {
320   //go through the curvelet map and remove all the curvelets below threshold
321 
322   //1) first clear the link graph and form a new one
323   edge_link_graph_.clear();
324   edge_link_graph_.resize(edgemap_->num_edgels());
325 
326   //go over the curvelets in the curvelet map
327   std::vector<sdet_curvelet*> cvlets_to_del;
328   for (unsigned i=0; i<edgemap_->edgels.size(); i++)
329   {
330     auto cv_it = curvelet_map_.curvelets(i).begin();
331     for ( ; cv_it!=curvelet_map_.curvelets(i).end(); cv_it++){
332       sdet_curvelet* cvlet = (*cv_it);
333 
334       //determine largest gap
335       for (unsigned j=0; j<cvlet->edgel_chain.size()-1; j++){
336         if (vgl_distance(cvlet->edgel_chain[j]->pt, cvlet->edgel_chain[j+1]->pt)>gap_threshold){
337           cvlets_to_del.push_back(cvlet);
338           break;
339         }
340       }
341     }
342   }
343 
344   //now actually delete them
345   for (auto & i : cvlets_to_del)
346     curvelet_map_.remove_curvelet(i);
347   cvlets_to_del.clear();
348 }
349 
350 //: prune the curvelets with lengths (extent) smaller than the one specified
351 void
352 sdet_sel_base
prune_curvelets_by_length(double length_threshold)353 ::prune_curvelets_by_length(double length_threshold)
354 {
355   //go through the curvelet map and remove all the curvelets below threshold
356 
357   //1) first clear the link graph and form a new one
358   edge_link_graph_.clear();
359   edge_link_graph_.resize(edgemap_->num_edgels());
360 
361   //go over the curvelets in the curvelet map
362   std::vector<sdet_curvelet*> cvlets_to_del;
363   for (unsigned i=0; i<edgemap_->edgels.size(); i++)
364   {
365     auto cv_it = curvelet_map_.curvelets(i).begin();
366     for ( ; cv_it!=curvelet_map_.curvelets(i).end(); cv_it++){
367       sdet_curvelet* cvlet = (*cv_it);
368 
369       if (cvlet->length<length_threshold)
370         cvlets_to_del.push_back(cvlet);
371     }
372   }
373 
374   //now actually delete them
375   for (auto & i : cvlets_to_del)
376     curvelet_map_.remove_curvelet(i);
377   cvlets_to_del.clear();
378 }
379 
380 //: prune the curvelets that are below the quality threshold and hence considered spurious
381 void
382 sdet_sel_base
prune_the_curvelets(double quality_threshold)383 ::prune_the_curvelets(double quality_threshold)
384 {
385   //go through the curvelet map and remove all the curvelets below threshold
386 
387   //1) first clear the link graph and form a new one
388   edge_link_graph_.clear();
389   edge_link_graph_.resize(edgemap_->num_edgels());
390 
391   //go over the curvelets in the curvelet map
392   std::vector<sdet_curvelet*> cvlets_to_del;
393   for (unsigned i=0; i<edgemap_->edgels.size(); i++)
394   {
395     auto cv_it = curvelet_map_.curvelets(i).begin();
396     for ( ; cv_it!=curvelet_map_.curvelets(i).end(); cv_it++){
397       if ((*cv_it)->quality<quality_threshold)
398         cvlets_to_del.push_back(*cv_it);
399     }
400   }
401 
402   //now actually delete them
403   for (auto & i : cvlets_to_del)
404     curvelet_map_.remove_curvelet(i);
405   cvlets_to_del.clear();
406 }
407 
408 //: prne the curvelets that are not locally geometrically consistent (i.e., c1)
409 void
410 sdet_sel_base
prune_curvelets_by_c1_condition()411 ::prune_curvelets_by_c1_condition()
412 {
413   //Note: this is currently only meaningful for GENO style curvelets
414   //goal: to locally do a test of viability beyond the local neighborhood by looking for viability across
415   //two neighborhoods using the c1 test (or biarc condition)
416 
417   //1) first clear the link graph so that new one can be formed later
418   edge_link_graph_.clear();
419   edge_link_graph_.resize(edgemap_->num_edgels());
420 
421   //go over all the edgels and look at the curvelets on it
422   std::vector<sdet_curvelet*> cvlets_to_del;
423   for (unsigned i=0; i<edgemap_->edgels.size(); i++)
424   {
425     sdet_edgel* eA = edgemap_->edgels[i];
426 
427     //for each cvlet before the edgel, see if a c1 cvlet can be found after it
428     auto cv_it = curvelet_map_.curvelets(i).begin();
429     for ( ; cv_it!=curvelet_map_.curvelets(i).end(); cv_it++)
430     {
431       sdet_curvelet* cvlet1 = (*cv_it);
432       bool before = (cvlet1->edgel_chain.back()==eA);
433       bool c1_pair_found = false;
434       bool cvlet2_found = false;
435 
436       //go over all the cvlet after
437       auto cv_it2 = curvelet_map_.curvelets(i).begin();
438       for ( ; cv_it2!=curvelet_map_.curvelets(i).end(); cv_it2++)
439       {
440         sdet_curvelet* cvlet2 = (*cv_it2);
441         if (cvlet2 == cvlet1) continue;
442         cvlet2_found = true;
443 
444         //do the c1 test
445         if ( (before && cvlet2->edgel_chain.front()==eA) ||
446             (!before && cvlet2->edgel_chain.back()==eA) )
447           c1_pair_found = c1_pair_found || cvlet1->curve_model->is_C1_with(cvlet2->curve_model);
448       }
449 
450       if (cvlet2_found && !c1_pair_found) //mark for deletion
451         cvlets_to_del.push_back(cvlet1);
452     }
453   }
454 
455   //now actually delete them
456   for (auto & i : cvlets_to_del)
457     curvelet_map_.remove_curvelet(i);
458   cvlets_to_del.clear();
459 
460 }
461 
462 //: construct a simple link grpah by connectng edgels to all its neighbors
463 void
464 sdet_sel_base
construct_naive_link_graph(double proximity_threshold,double affinity_threshold)465 ::construct_naive_link_graph(double proximity_threshold, double affinity_threshold)
466 {
467   //1) clear the link graph and form a new one
468   edge_link_graph_.clear();
469   edge_link_graph_.resize(edgemap_->num_edgels());
470 
471   auto R = (unsigned) std::ceil(proximity_threshold);
472 
473   // 2a) go over all the curvelets and reset the used flags
474   for (unsigned i=0; i<edgemap_->edgels.size(); i++)
475   {
476     sdet_edgel* eA = edgemap_->edgels[i];
477 
478     //get the grid coordinates of this edgel
479     unsigned ii = sdet_round(eA->pt.x());
480     unsigned jj = sdet_round(eA->pt.y());
481 
482     // 2) iterate over the neighboring cells around this edgel
483     for (int xx=(int)ii-(int)R; xx<=(int)(ii+R) ; xx++){
484       for (int yy=(int)jj-(int)R; yy<=(int)(jj+R) ; yy++){
485 
486         if (xx<0 || xx>=(int)ncols_ || yy<0 || yy>=(int)nrows_)
487           continue;
488 
489         //for all the edgels in its neighborhood
490         for (auto eB : edgemap_->cell(xx, yy)){
491           if (eB == eA) continue;
492 
493           //form a link between eA and eB (if affinity is high)
494 
495           //compute pairwise affinity
496 
497           //determine the intrinsic parameters for this edgel pair
498           sdet_int_params params = sdet_get_intrinsic_params(eA->pt, eB->pt, eA->tangent, eB->tangent);
499 
500           double kk, gamma, len;
501           double k0_max_error, gamma_max_error, len_max_error; //other params (unimportant)
502           // read the ES solutions from the table and scale appropriately
503           bvgl_eulerspiral_lookup_table::instance()->look_up( params.t1, params.t2,
504                                                               &kk, &gamma, &len,
505                                                               &k0_max_error, &gamma_max_error, &len_max_error );
506           kk = kk/params.d; gamma= gamma/(params.d*params.d);
507 
508           //some energy function
509           double E = gamma*gamma*len;
510 
511           //threshold using a simple energy function
512           if (E<affinity_threshold)
513             edge_link_graph_.link(eA, eB, nullptr);
514         }
515       }
516     }
517   }
518 }
519 
520 //: form the link graph from the existing edgel groupings
521 // method = 0 : include all the curvelets
522 // method = 1 : curve model consistency
523 // method = 2 : reciprocal immediate links only
524 // method = 3 : immediate links only
525 void
526 sdet_sel_base
construct_the_link_graph(unsigned min_group_size,int method)527 ::construct_the_link_graph(unsigned min_group_size, int method)
528 {
529   //1) clear the link graph and form a new one
530   edge_link_graph_.clear();
531   edge_link_graph_.resize(edgemap_->num_edgels());
532   if (!use_anchored_curvelets_){
533     // First update the curvelet map to include all links
534     form_full_cvlet_map();
535   }
536 
537   // 2) now construct the link graph from the curvelet map
538   std::cout << "Constructing the Link Graph using (N >= " << min_group_size << ")..." ;
539 
540   // 2a) go over all the curvelets and reset the used flags
541   for (unsigned i=0; i<edgemap_->edgels.size(); i++)
542   {
543     //for all curvelets that are larger than the group size threshold
544     auto cv_it = curvelet_map_.curvelets(i).begin();
545     for ( ; cv_it!=curvelet_map_.curvelets(i).end(); cv_it++)
546       (*cv_it)->used = false; //reset this flag
547   }
548 
549   // 2b) go over all the curvelets above the min size and determine which links can be formed
550   for (unsigned i=0; i<edgemap_->edgels.size(); i++)
551   {
552     sdet_edgel* eA = edgemap_->edgels[i];
553 
554     //for all curvelets that are larger than the group size threshold
555     auto cv_it = curvelet_map_.curvelets(i).begin();
556     for ( ; cv_it!=curvelet_map_.curvelets(i).end(); cv_it++){
557       sdet_curvelet* cvlet = (*cv_it);
558       if (cvlet->order() < min_group_size) continue;
559 
560       //form all possible links from this curvelet
561       form_links_from_a_curvelet(eA, cvlet, min_group_size, method);
562     }
563   }
564   std::cout << "done!" << std::endl;
565 
566   ////3) prune duplicate curvelets (Assuming that once the curvelets are formed, they are independent)
567   //for (unsigned i=0; i<edge_link_graph_.cLinks.size(); i++){
568   //  //all child links of each edgel covers all the links
569   //  sdet_link_list_iter l_it = edge_link_graph_.cLinks[i].begin();
570   //  for (; l_it != edge_link_graph_.cLinks[i].end(); l_it++){
571   //    (*l_it)->prune_redundant_curvelets();
572   //  }
573   //}
574 
575   //4) after forming the link graph, determine the degree of overlap of the links in the graph
576   for (auto & cLink : edge_link_graph_.cLinks){
577     //all child links of each edgel covers all the links
578     auto l_it = cLink.begin();
579     for (; l_it != cLink.end(); l_it++){
580       (*l_it)->deg_overlap = count_degree_overlap((*l_it));
581     }
582   }
583 
584 }
585 
586 //: count the degree of overlap between pairs of curvelets at a link
587 int
588 sdet_sel_base
count_degree_overlap(sdet_link * link)589 ::count_degree_overlap(sdet_link* link)
590 {
591   int max_deg = 0;
592 
593   //go over all pairs of curvelets causing the link
594   auto c_it = link->curvelets.begin();
595   for (; c_it != link->curvelets.end(); c_it++){
596     auto c_it2 = c_it;
597     c_it2++;
598     for (; c_it2 != link->curvelets.end(); c_it2++)
599     {
600       unsigned k1=0, k2=0;
601 
602       //count the degree of overlap between these two curvelets
603       for (unsigned i=0; i<(*c_it)->edgel_chain.size(); i++){
604         if ((*c_it)->edgel_chain[i]==link->pe){
605           k1 = i;
606           break;
607         }
608       }
609 
610       for (unsigned i=0; i<(*c_it2)->edgel_chain.size(); i++){
611         if ((*c_it2)->edgel_chain[i]==link->pe){
612           k2 = i;
613           break;
614         }
615       }
616 
617       int deg = count_degree_overlap((*c_it), (*c_it2), k1, k2);
618       if (deg>max_deg)
619         max_deg = deg;
620     }
621   }
622   return max_deg;
623 }
624 
625 //: count the degree of overlap between two curvelets
626 int
627 sdet_sel_base
count_degree_overlap(sdet_curvelet * cvlet1,sdet_curvelet * cvlet2,unsigned k1,unsigned k2)628 ::count_degree_overlap(sdet_curvelet* cvlet1, sdet_curvelet* cvlet2, unsigned k1, unsigned k2)
629 {
630   //ks are the indices into the edgel chain of the cvlets
631   int cnt_overlap=0;
632 
633   //count the overlaps before the link
634   int kk1=k1-1;
635   int kk2=k2-1;
636   bool continuous = true;
637   for (; kk1>=0 && kk2>=0 && continuous; kk1--, kk2--){
638     if (cvlet1->edgel_chain[kk1]==cvlet2->edgel_chain[kk2])
639       cnt_overlap++;
640     else
641       continuous = false;
642   }
643 
644   //count the overlaps after the link
645   kk1=k1+2; kk2=k2+2;
646   continuous = true;
647   for (; kk1<(int)cvlet1->edgel_chain.size() && kk2<(int)cvlet2->edgel_chain.size() && continuous; kk1++, kk2++){
648     if (cvlet1->edgel_chain[kk1]==cvlet2->edgel_chain[kk2])
649       cnt_overlap++;
650     else
651       continuous = false;
652   }
653 
654   return cnt_overlap;
655 }
656 
657 //: form all appropriate links from a curvelet
form_links_from_a_curvelet(sdet_edgel * eA,sdet_curvelet * cvlet,unsigned min_group_size,int method)658 void sdet_sel_base::form_links_from_a_curvelet(sdet_edgel* eA, sdet_curvelet* cvlet, unsigned min_group_size, int method)
659 {
660   if (method ==0)
661   {
662     //Link all edgels in the group
663     //
664     // Explanation:
665     // if xyzAbcd then X-Y, Y-Z, Z-A, A-B, B-C and C-D
666 
667     //Amir: new feature
668     //      since some curvelets are constructed in the reverse direction and the link graph is a directed graph,
669     //      we ought to either make the link graph an undirected graph or add the links from the reverse curvelet in reverse
670       for (unsigned k=0; k<cvlet->edgel_chain.size()-1; k++)
671        edge_link_graph_.link(cvlet->edgel_chain[k], cvlet->edgel_chain[k+1], cvlet);
672     //all cvlets are used
673     cvlet->used = true;
674   }
675   else if (method==1)
676   {
677     //Link immediate edgels only (only the ones it's directly connected to)
678     //
679     // Explanation:
680     // if -zAb- then Z-A and A-B
681 
682     for (unsigned k=0; k<cvlet->edgel_chain.size(); k++){
683       if (k>0 && cvlet->edgel_chain[k-1]==eA) //the link after it (eA --> edgel_chain[k])
684         edge_link_graph_.link(eA, cvlet->edgel_chain[k], cvlet);
685 
686       if (k<cvlet->edgel_chain.size()-1 && cvlet->edgel_chain[k+1]==eA) //the link before it (edgel_chain[k] --> eA)
687         edge_link_graph_.link(cvlet->edgel_chain[k], eA, cvlet);
688     }
689 
690     //all cvlets are used
691     cvlet->used = true;
692   }
693   else if (method==2)
694   {
695     // Link immediate reciprocal edgels only
696     //
697     // Explanation: (caps mean anchored)
698     // (1)  -Ab- + -aB- = A-B
699 
700     for (unsigned k=0; k<cvlet->edgel_chain.size(); k++){
701       if (k>0 && cvlet->edgel_chain[k-1]==eA) //the link after it (eA --> edgel_chain[k])
702       {
703         if (link_is_reciprocal(eA, cvlet->edgel_chain[k], eA, min_group_size)){
704           edge_link_graph_.link(eA, cvlet->edgel_chain[k], cvlet);
705           cvlet->used = true;
706         }
707       }
708       if (k<cvlet->edgel_chain.size()-1 && cvlet->edgel_chain[k+1]==eA) //the link before it (edgel_chain[k] --> eA)
709       {
710         if (link_is_reciprocal(cvlet->edgel_chain[k], eA, eA, min_group_size)){
711           edge_link_graph_.link(cvlet->edgel_chain[k], eA, cvlet);
712           cvlet->used = true;
713         }
714       }
715     }
716   }
717   else if (method==3)
718   {
719     // Link immediate reciprocal links if they are supported
720     //
721     // Explanation: (caps mean anchored)
722     // (1)  -Abc- + -aBc- = A-B (if A is a terminal edgel)
723     // (2)  -zAb- + -zaB- = A-B (if B is a terminal edgel)
724     // (3)  -zAbc- + -zaBc- = A-B
725 
726     for (unsigned k=0; k<cvlet->edgel_chain.size(); k++){
727       sdet_edgel *eX=nullptr, *eY=nullptr;
728       if (k>0 && cvlet->edgel_chain[k-1]==eA) //the link after it (eA --> edgel_chain[k])
729       {
730         if (k>1) eX = cvlet->edgel_chain[k-2];
731         if (k<cvlet->edgel_chain.size()-1) eY=cvlet->edgel_chain[k+1];
732 
733         if (link_is_supported(eX, eA, cvlet->edgel_chain[k], eY, eA, min_group_size)){
734           edge_link_graph_.link(eA, cvlet->edgel_chain[k], cvlet);
735           cvlet->used = true;
736         }
737       }
738       if (k<cvlet->edgel_chain.size()-1 && cvlet->edgel_chain[k+1]==eA) //the link before it (edgel_chain[k] --> eA)
739       {
740         if (k>0) eX = cvlet->edgel_chain[k-1];
741         if (k<cvlet->edgel_chain.size()-2) eY=cvlet->edgel_chain[k+2];
742 
743         if (link_is_supported(eX, cvlet->edgel_chain[k], eA, eY, eA, min_group_size)){
744           edge_link_graph_.link(cvlet->edgel_chain[k], eA, cvlet);
745           cvlet->used = true;
746         }
747       }
748     }
749   }
750   else if (method==4)
751   {
752     // Put a triplet overlap condition
753     //
754     // Basic Idea:
755     //
756     //   Every edgel gets to pick its neighbors (before and after, in one shot)
757     //   But they have to be supported by the curvelets of the neighbors.
758     //
759     // Explanation: (caps mean anchored)
760     // -Abc- + -aBc- + abC- = A-B-C
761     //
762 
763     for (unsigned k=0; k<cvlet->edgel_chain.size(); k++)
764     {
765       sdet_edgel *eX=nullptr, *eY=nullptr;
766       if (k<cvlet->edgel_chain.size()-2 && cvlet->edgel_chain[k+1]==eA) //the link before it (edgel_chain[k] --> eA)
767       {
768         eX = cvlet->edgel_chain[k];
769         eY = cvlet->edgel_chain[k+2];
770 
771         if (triplet_is_supported(eX, eA, eY, min_group_size)){
772           edge_link_graph_.link(eX, eA, cvlet);
773           edge_link_graph_.link(eA, eY, cvlet);
774           cvlet->used = true;
775         }
776       }
777     }
778   }
779 
780 }
781 
782 //: check to see if link between two edges is reciprocal (i.e., x-A->b-y && p-a->B-q)
783 bool
784 sdet_sel_base
link_is_reciprocal(sdet_edgel * eA,sdet_edgel * eB,unsigned min_group_size)785 ::link_is_reciprocal(sdet_edgel* eA, sdet_edgel* eB, unsigned min_group_size)
786 {
787   bool link_found = false;
788 
789   //for all curvelets of eA that are larger than the group size threshold
790   auto cv_it = curvelet_map_.curvelets(eA->id).begin();
791   for ( ; cv_it!=curvelet_map_.curvelets(eA->id).end() && !link_found; cv_it++)
792   {
793     sdet_curvelet* cvlet = (*cv_it);
794 
795     if (cvlet->order()<min_group_size)
796       continue;
797 
798     //check if eA is directly connected to eB
799     for (unsigned k=0; k<cvlet->edgel_chain.size(); k++){
800       if (cvlet->edgel_chain[k]==eA && (k<cvlet->edgel_chain.size()-1 && cvlet->edgel_chain[k+1]==eB)){
801         link_found = true;
802         break;
803       }
804     }
805   }
806 
807   if (!link_found)
808     return false;
809 
810   //for all curvelets of eB that are larger than the group size threshold
811   link_found = false;
812   cv_it = curvelet_map_.curvelets(eB->id).begin();
813   for ( ; cv_it!=curvelet_map_.curvelets(eB->id).end() && !link_found; cv_it++)
814   {
815     sdet_curvelet* cvlet = (*cv_it);
816 
817     if (cvlet->order()<min_group_size)
818       continue;
819 
820     //check if eA is directly connected to eB
821     for (unsigned k=0; k<cvlet->edgel_chain.size(); k++){
822       if (cvlet->edgel_chain[k]==eB && (k>0 && cvlet->edgel_chain[k-1]==eA)){
823         link_found = true;
824         break;
825       }
826     }
827   }
828 
829   return link_found; //link found in both directions
830 }
831 
832 //: check to see if link between two edges is reciprocal (i.e., x-A-b-y && p-a-B-q)
833 bool
834 sdet_sel_base
link_is_reciprocal(sdet_edgel * eA,sdet_edgel * eB,sdet_edgel * ref_e,unsigned min_group_size)835 ::link_is_reciprocal(sdet_edgel* eA, sdet_edgel* eB, sdet_edgel* ref_e, unsigned min_group_size)
836 {
837   sdet_edgel *eC, *eN; //current edgel and neighboring edgel
838 
839   if (ref_e == eA) { eC = eA; eN = eB; }
840   else             { eC = eB; eN = eA; }
841 
842   //we know eC-->eN, now look for eN-->eC link
843 
844   //for all curvelets that are larger than the group size threshold
845   auto cv_it = curvelet_map_.curvelets(eN->id).begin();
846   for ( ; cv_it!=curvelet_map_.curvelets(eN->id).end(); cv_it++)
847   {
848     sdet_curvelet* cvlet = (*cv_it);
849 
850     if (cvlet->order()<min_group_size)
851       continue;
852 
853     //check if eN is directly connected to eC
854     for (unsigned k=0; k<cvlet->edgel_chain.size(); k++){
855       if (cvlet->edgel_chain[k]==eN && ((k>0 && cvlet->edgel_chain[k-1]==eC) ||
856                                         (k<cvlet->edgel_chain.size()-1 && cvlet->edgel_chain[k+1]==eC))
857          )
858       {
859         cvlet->used = true;
860         return true;
861       }
862     }
863   }
864 
865   return false;
866 }
867 
868 //: check to see if link is reciprocal and supported by other edgels  (i.e., x-A->b-y && x-a->B-y)
869 bool
870 sdet_sel_base
link_is_supported(sdet_edgel * eA,sdet_edgel * eB,unsigned min_group_size)871 ::link_is_supported(sdet_edgel* eA, sdet_edgel* eB, unsigned min_group_size)
872 {
873   bool link_found = false;
874 
875   //go over all curvelets of eA and find the ones that contain eB
876   auto cv_it = curvelet_map_.curvelets(eA->id).begin();
877   for ( ; cv_it!=curvelet_map_.curvelets(eA->id).end() && !link_found; cv_it++)
878   {
879     sdet_curvelet* cvlet = (*cv_it);
880 
881     if (cvlet->order()<min_group_size)
882       continue;
883 
884     for (unsigned k=0; k<cvlet->edgel_chain.size(); k++){
885       sdet_edgel *eX=nullptr, *eY=nullptr;
886       if (k<cvlet->edgel_chain.size()-1 && cvlet->edgel_chain[k]==eA && cvlet->edgel_chain[k+1]==eB)
887       {
888         if (k>0) eX = cvlet->edgel_chain[k-1];
889         if (k<cvlet->edgel_chain.size()-2) eY=cvlet->edgel_chain[k+2];
890 
891         link_found = link_is_supported(eX, eA, eB, eY, eA, min_group_size);
892 
893         if (link_found)
894           break;
895       }
896     }
897   }
898 
899   return link_found;
900 }
901 
902 
903 //: check to see if link is reciprocal and supported by other edgels  (i.e., x-A->b-y && x-a->B-y)
904 bool
905 sdet_sel_base
link_is_supported(sdet_edgel * eX,sdet_edgel * eA,sdet_edgel * eB,sdet_edgel * eY,sdet_edgel * ref_e,unsigned min_group_size)906 ::link_is_supported(sdet_edgel* eX, sdet_edgel* eA, sdet_edgel* eB, sdet_edgel* eY,
907                                        sdet_edgel* ref_e, unsigned min_group_size)
908 {
909   sdet_edgel *eC, *eN; //current edgel and neighboring edgel
910 
911   if (ref_e == eA) { eC = eA; eN = eB; }
912   else             { eC = eB; eN = eA; }
913 
914   // we know eC-->eN, now we need to verify that for those curvelets which have the eN-->eC link,
915   // they are supported by the same edgels (i.e., that eX-eC->eN-eY and eX-eC<-eN-eY both exist)
916 
917   //for all curvelets of eN that are larger than the group size threshold
918   auto cv_it = curvelet_map_.curvelets(eN->id).begin();
919   for ( ; cv_it!=curvelet_map_.curvelets(eN->id).end(); cv_it++)
920   {
921     sdet_curvelet* cvlet = (*cv_it);
922 
923     if (cvlet->order()<min_group_size)
924       continue;
925 
926     //check if eN is directly connected to eC
927     for (unsigned j=0; j<cvlet->edgel_chain.size(); j++)
928     {
929       //eN-eC <=> eA-eB
930       if (cvlet->edgel_chain[j]==eN && j<cvlet->edgel_chain.size()-1 && cvlet->edgel_chain[j+1]==eC)
931       {
932         assert (eA==eN && eB==eC); //just making sure
933         if (eX && eY && j>0 && cvlet->edgel_chain[j-1]==eX && j<cvlet->edgel_chain.size()-2 && cvlet->edgel_chain[j+2]==eY){
934           cvlet->used = true;
935           return true; //found eX-eA-eB-eY grouping
936         }
937 
938         //if ((!eY && eX && j>0 && cvlet->edgel_chain[j-1]==eX) ||                         //found eX-eA-eB grouping
939         //    (!eX && eY && j<cvlet->edgel_chain.size()-2 && cvlet->edgel_chain[j+2]==eY)) //found eA-eB-eY grouping
940         //  return true;
941       }
942       //eC-eN <=> eA-eB
943       if (cvlet->edgel_chain[j]==eN && j>0 && cvlet->edgel_chain[j-1]==eC)
944       {
945         assert (eA==eC && eB==eN); //just making sure
946         if (eX && eY && j>1 && cvlet->edgel_chain[j-2]==eX && j<cvlet->edgel_chain.size()-1 && cvlet->edgel_chain[j+1]==eY){
947           cvlet->used = true;
948           return true; //found eX-eA-eB-eY grouping
949         }
950 
951         //if ((!eY && eX && j>1 && cvlet->edgel_chain[j-2]==eX) ||                         //found eX-eA-eB grouping
952         //    (!eX && eY && j<cvlet->edgel_chain.size()-1 && cvlet->edgel_chain[j+1]==eY)) //found eA-eB-eY grouping
953         //  return true;
954       }
955     }
956   }
957 
958   return false; //this link is not supported by the same edgel groups
959 }
960 
961 //: check to see if this triplet is supported
962 bool
963 sdet_sel_base
triplet_is_supported(sdet_edgel * eX,sdet_edgel * eA,sdet_edgel * eY,unsigned min_group_size)964 ::triplet_is_supported(sdet_edgel* eX, sdet_edgel* eA, sdet_edgel* eY,
965                                           unsigned min_group_size)
966 {
967   //we know eX-->eA-->eY exists, we need to verify that -eX-eA-eY exists for eX and eY.
968   sdet_curvelet* cvlet1 = nullptr;
969   sdet_curvelet* cvlet2 = nullptr;
970 
971   bool cvlet_found = false;
972 
973   //for all curvelets of eX that are larger than the group size threshold
974   auto cv_it = curvelet_map_.curvelets(eX->id).begin();
975   for ( ; cv_it!=curvelet_map_.curvelets(eX->id).end() && !cvlet_found; cv_it++)
976   {
977     cvlet1 = (*cv_it);
978 
979     if (cvlet1->order()<min_group_size)
980       continue;
981 
982     //check if eX is directly connected to eA and eY
983     for (unsigned j=0; j<cvlet1->edgel_chain.size(); j++){
984       if (cvlet1->edgel_chain[j]==eX && j<cvlet1->edgel_chain.size()-2 && cvlet1->edgel_chain[j+1]==eA && cvlet1->edgel_chain[j+2]==eY)
985       {
986         cvlet_found =  true; //found eX-eA-eY grouping
987         break;
988       }
989     }
990   }
991 
992   if (!cvlet_found)
993     return false; // no supporting triplet found in eX
994 
995   //for all curvelets of eY that are larger than the group size threshold
996   cvlet_found = false; //reset flag
997   cv_it = curvelet_map_.curvelets(eY->id).begin();
998   for ( ; cv_it!=curvelet_map_.curvelets(eY->id).end() && !cvlet_found; cv_it++)
999   {
1000     cvlet2 = (*cv_it);
1001 
1002     if (cvlet2->order()<min_group_size)
1003       continue;
1004 
1005     //check if eY is directly connected to eX and eA
1006     for (unsigned j=0; j<cvlet2->edgel_chain.size(); j++){
1007       if (cvlet2->edgel_chain[j]==eX && j<cvlet2->edgel_chain.size()-2 && cvlet2->edgel_chain[j+1]==eA && cvlet2->edgel_chain[j+2]==eY)
1008       {
1009         cvlet_found =  true; //found eX-eA-eY grouping
1010         break;
1011       }
1012     }
1013   }
1014 
1015   if (cvlet_found){
1016     cvlet1->used = true;
1017     cvlet1->used = false;
1018   }
1019 
1020   return cvlet_found;
1021 }
1022 
1023 void
1024 sdet_sel_base
prune_the_link_graph()1025 ::prune_the_link_graph()
1026 {
1027   //prune the link graph of spurious links (ie links that cannot be extended)
1028   std::vector<sdet_link*> links_to_del;
1029   for (auto & cLink : edge_link_graph_.cLinks)
1030   {
1031     auto l_it = cLink.begin();
1032     for (;l_it!=cLink.end(); l_it++)
1033     {
1034       if (!link_valid(*l_it)) //invalid link
1035         links_to_del.push_back(*l_it);
1036     }
1037   }
1038 
1039   //now delete all these single links
1040   for (auto & i : links_to_del)
1041     edge_link_graph_.remove_link(i);
1042 
1043   links_to_del.clear();
1044 }
1045 
1046 //: make the link graph bidirectionally consistent
1047 void
1048 sdet_sel_base
make_link_graph_consistent()1049 ::make_link_graph_consistent()
1050 {
1051   //this ought to be an iterative algorithm
1052   bool LG_consistent = false;
1053   while (!LG_consistent)
1054   {
1055     std::vector<sdet_link*> links_to_del;
1056 
1057     // go over all the links of the link graph and determine if there is a counterpart to each of the links
1058     for (auto & cLink : edge_link_graph_.cLinks)
1059     {
1060       auto l_it = cLink.begin();
1061       for (;l_it!=cLink.end(); l_it++)
1062       {
1063         if (!link_bidirectional(*l_it)) //invalid link
1064           links_to_del.push_back(*l_it);
1065       }
1066     }
1067 
1068     LG_consistent = (links_to_del.size()==0);
1069 
1070     //delete the inconsistent links along with the curvelets causing them
1071     for (auto & j : links_to_del)
1072     {
1073       //Note: comment this part to visualize the links that are removed by this process
1074 
1075       //first remove the cvlets
1076       auto cv_it = j->curvelets.begin();
1077       for (; cv_it != j->curvelets.end(); cv_it++)
1078         curvelet_map_.remove_curvelet(*cv_it);
1079     }
1080 
1081     //reconstruct the link graph from the remainng curvelets
1082     construct_the_link_graph(0, 0); //minsize, method
1083   }
1084 }
1085 
1086 //: clear all contours
1087 void
1088 sdet_sel_base
clear_all_contours()1089 ::clear_all_contours()
1090 {
1091   //reset linked flags on the link graph
1092   edge_link_graph_.linked.assign(edgemap_->edgels.size(), false);
1093 
1094   //clear the curve fragment graph
1095   curve_frag_graph_.clear();
1096 
1097   //form a new contour fragment graph
1098   curve_frag_graph_.resize(edgemap_->num_edgels());
1099 }
1100 
1101 // Extract image contours from the link graph by
1102 // extracting regular contours in successive stages
1103 void
1104 sdet_sel_base
extract_image_contours_from_the_link_graph(unsigned num_link_iters)1105 ::extract_image_contours_from_the_link_graph(unsigned num_link_iters)
1106 {
1107   std::cout << "Extracting regular contours from the Link Graph..." ;
1108 
1109   //first remove any existing contours
1110   clear_all_contours();
1111 
1112   //find the max deg of overlap for all the links
1113   unsigned max_overlap = 0;
1114   for (auto & cLink : edge_link_graph_.cLinks){
1115     auto l_it = cLink.begin();
1116     for (;l_it!=cLink.end(); l_it++){
1117       if ((*l_it)->deg_overlap > (int)max_overlap)
1118         max_overlap = (*l_it)->deg_overlap;
1119     }
1120   }
1121 
1122   //clear the linked flags
1123   edge_link_graph_.clear_linked_flag();
1124 
1125   //now iterate over the range of overlaps to link contours
1126   //starting from the best overlaps
1127   sdet_edgel_link_graph link_graph_temp;
1128   link_graph_temp.linked.resize(edgemap_->edgels.size()); //create a common flag matrix for the iterations
1129 
1130   for (int i=max_overlap; (i>int(max_overlap-num_link_iters) && i>0); i--){
1131     min_deg_to_link_ = i;
1132 
1133     //form a partial link graph from the links that satisfy the min deg of overlap condition
1134     link_graph_temp.cLinks.clear();
1135     link_graph_temp.pLinks.clear();
1136     link_graph_temp.cLinks.resize(edgemap_->edgels.size());
1137     link_graph_temp.pLinks.resize(edgemap_->edgels.size());
1138 
1139     for (unsigned j=0; j<edge_link_graph_.cLinks.size(); j++){
1140       auto l_it = edge_link_graph_.cLinks[j].begin();
1141       for (;l_it!=edge_link_graph_.cLinks[j].end(); l_it++){
1142         if ((*l_it)->deg_overlap >= (int)min_deg_to_link_)
1143           link_graph_temp.cLinks[j].push_back(*l_it);
1144       }
1145     }
1146 
1147     for (unsigned j=0; j<edge_link_graph_.pLinks.size(); j++){
1148       auto l_it = edge_link_graph_.pLinks[j].begin();
1149       for (;l_it!=edge_link_graph_.pLinks[j].end(); l_it++){
1150         if ((*l_it)->deg_overlap >= (int)min_deg_to_link_)
1151           link_graph_temp.pLinks[j].push_back(*l_it);
1152       }
1153     }
1154 
1155     extract_one_chains_from_the_link_graph(link_graph_temp);
1156 
1157     //clear the temp links so that they are not deleted (hack)
1158     link_graph_temp.cLinks.clear();
1159     link_graph_temp.pLinks.clear();
1160 
1161     std::cout << i << "...";
1162   }
1163 
1164   //Now sew together any distinct but connected edgel chains
1165   //TODO: post_process_to_link_fragments();
1166 
1167   //remove any short segments
1168   //TODO: prune_contours(0.0, 4.0);
1169 
1170   std::cout << "done!" << std::endl;
1171 }
1172 
1173 
1174 //: extract the regular contours from the link graph
1175 void
1176 sdet_sel_base
extract_regular_contours_from_the_link_graph()1177 ::extract_regular_contours_from_the_link_graph()
1178 {
1179   //first remove any existing contours
1180   clear_all_contours();
1181 
1182   //clear the linked flags
1183   edge_link_graph_.clear_linked_flag();
1184 
1185   //exract one chains from the main link graph
1186   extract_one_chains_from_the_link_graph(edge_link_graph_);
1187 }
1188 
1189 //: extract the one chains from a given link graph (from the primary link grpah of ELG)
1190 void
1191 sdet_sel_base
extract_one_chains_from_the_link_graph(sdet_edgel_link_graph & ELG)1192 ::extract_one_chains_from_the_link_graph(sdet_edgel_link_graph& ELG)
1193 {
1194   //initialize the curve fragment map
1195   curve_frag_graph_.resize(edgemap_->edgels.size());
1196   double thres=gap_;
1197   //now look for edgel chains
1198   //Rules:
1199   //    (a) start from an edgel that is locally legal
1200   //    (b) trace in both directions until an illegal edgel is reached
1201   //    (c) prune out short chains
1202 
1203   for (auto first_edgel : edgemap_->edgels)
1204   {
1205     //if it's already linked, ignore
1206     if (ELG.linked[first_edgel->id])
1207       continue;
1208 
1209     // Check edgel to see if it is legal to start a chain here
1210     if (ELG.edgel_is_legal_first_edgel(first_edgel))
1211     {
1212       //start a chain from this edgel
1213       auto* chain = new sdet_edgel_chain();
1214 
1215       //add the first edgel to the chain
1216       chain->push_back(first_edgel);
1217       ELG.linked[first_edgel->id] = true; //mark it as linked
1218 
1219       //now start tracing FORWARD from its child
1220       sdet_edgel* eA = ELG.cLinks[first_edgel->id].front()->ce;
1221       sdet_edgel* eB;
1222       if(vgl_distance(first_edgel->pt,eA->pt)<thres)
1223       chain->push_back(eA);
1224 
1225       //trace FORWARD through the link graph until an illegal or terminal edgel is reached
1226       while (ELG.edgel_is_legal(eA))
1227       {
1228         // Mark the last edgel as linked.
1229 
1230         // Note:
1231         //   By doing this here, we can get the edgels at junctions to be added to the contour
1232         //   without marking them as linked. This means that other contours arriving at
1233         //   the junction can also claim the junction edgel as being on their chains.
1234         ELG.linked[eA->id] = true;
1235 
1236         //is this a terminal edgel?
1237         if (ELG.cLinks[eA->id].size()==0)
1238           break; //terminate chain
1239 
1240         //else advance to child node
1241         eB=eA;
1242         eA = ELG.cLinks[eA->id].front()->ce;
1243         if(vgl_distance(eB->pt,eA->pt)<thres)
1244         chain->push_back(eA);
1245         else break;
1246       }
1247 
1248       //Note: Junction edgels will still be marked as unlinked after the tracing is done!
1249 
1250       //now start tracing BACKWARD from the first edgel
1251 
1252       //first determine if this is a closed contour
1253       //with closed contours, the chain might already include the first edgel twice
1254       if (eA != first_edgel){
1255         //not a closed contour, start tracing
1256         eA = ELG.pLinks[first_edgel->id].front()->pe;
1257         if(vgl_distance(first_edgel->pt,eA->pt)<thres)
1258         chain->push_front(eA);
1259       }
1260 
1261       while (ELG.edgel_is_legal(eA))
1262       {
1263         // Mark the last edgel as linked.
1264         ELG.linked[eA->id] = true;
1265 
1266         //is this a terminal edge?
1267         if (ELG.pLinks[eA->id].size()==0)
1268           break; //terminate chain
1269 
1270         //else advance to parent node
1271         eB=eA;
1272         eA = ELG.pLinks[eA->id].front()->pe;
1273         if(vgl_distance(eB->pt,eA->pt)<thres)
1274         chain->push_front(eA);
1275         else break;
1276         }
1277 
1278       //save the current chain on the curve fragment graph
1279       if (chain->edgels.size()>2)
1280         curve_frag_graph_.insert_fragment(chain); //prune out the short ones
1281       else
1282         delete chain;
1283 
1284     }
1285   }
1286 }
1287 
1288 
1289 //: determine if this links from the link grpah is valid
1290 bool
1291 sdet_sel_base
link_valid(sdet_link * link)1292 ::link_valid(sdet_link* link)
1293 {
1294 
1295   //if (link->deg_overlap >= min_deg_to_link_)
1296   //  return true;
1297   //else
1298   //  return false;
1299 
1300   if (link->vote>1)
1301     return true;
1302   else {
1303     //return false; //simple pruning (dangerous: will remove good links at large gaps)
1304 
1305     //make sure that this link is locally supported by a curvelet, otherwise it's spurious
1306     //go over all the cvlets on this link and make sure that at least one of them is anchored on its parent
1307     auto cv_it = link->curvelets.begin();
1308     for (; cv_it != link->curvelets.end(); cv_it++)
1309     {
1310       sdet_curvelet* cvlet = (*cv_it);
1311 
1312       if (cvlet->ref_edgel == link->pe)
1313         return true;
1314     }
1315     return false;
1316   }
1317 }
1318 
1319 //: determine if this link is bidirectional
1320 bool
1321 sdet_sel_base
link_bidirectional(sdet_link * link)1322 ::link_bidirectional(sdet_link* link)
1323 {
1324   unsigned src_id = link->pe->id;
1325   unsigned tar_id = link->ce->id;
1326 
1327   //is there a link from the target to the source?
1328   auto l_it = edge_link_graph_.cLinks[tar_id].begin();
1329   for (;l_it!=edge_link_graph_.cLinks[tar_id].end(); l_it++)
1330   {
1331     if ((*l_it)->ce->id == (int)src_id)
1332       return true;
1333   }
1334 
1335   return false;
1336 }
1337 
1338 //: connect pieces of contours that are connected but separated
1339 void
1340 sdet_sel_base
post_process_to_link_contour_fragments()1341 ::post_process_to_link_contour_fragments()
1342 {
1343 
1344 }
1345 
1346 
1347 //***********************************************************************//
1348 // Hybrid methods
1349 //***********************************************************************//
1350 
1351 //: construct a mapping between edgel ids and curve ids
1352 void
1353 sdet_sel_base
compile_edge_to_contour_mapping()1354 ::compile_edge_to_contour_mapping()
1355 {
1356   //clear the mapping
1357   cId_.clear();
1358   cId_.resize(edgemap_->num_edgels());
1359 
1360   //now go over the CFG and create the mapping
1361   int cnt=1;
1362 
1363   auto f_it = curve_frag_graph_.frags.begin();
1364   for (; f_it != curve_frag_graph_.frags.end(); f_it++)
1365   {
1366     sdet_edgel_chain* chain = (*f_it);
1367 
1368     //go over the edgel chain and insert them into the mapping
1369     for (auto e : chain->edgels)
1370     {
1371       cId_[e->id] = cnt;
1372     }
1373 
1374     //update contour count
1375     cnt++;
1376   }
1377 
1378 }
1379 
1380 //: attempt to form curvelets from the traced contour fragments
1381 void
1382 sdet_sel_base
form_curvelets_from_contours(bool clear_existing)1383 ::form_curvelets_from_contours(bool clear_existing)
1384 {
1385   if (clear_existing)
1386   {
1387     curvelet_map_.clear();
1388 
1389     //form a new curvelet map
1390     curvelet_map_.resize(edgemap_->num_edgels());
1391   }
1392 
1393   auto f_it = curve_frag_graph_.frags.begin();
1394   for (; f_it != curve_frag_graph_.frags.end(); f_it++)
1395   {
1396     sdet_edgel_chain* chain = (*f_it);
1397 
1398     //go over the edgel chain and try to form curvelets using the edgels in the chain
1399     for (unsigned i=0; i<chain->edgels.size(); i++)
1400     {
1401       sdet_edgel* ref_e = chain->edgels[i];
1402 
1403       //Issue: how do we find out whether the ordering is forward/backward wrt the edge chain?
1404       bool rel_dir;
1405       if (i==0) rel_dir = sdet_dot(ref_e->tangent, sdet_vPointPoint(ref_e->pt, chain->edgels[i+1]->pt))>0;
1406       else      rel_dir = sdet_dot(ref_e->tangent, sdet_vPointPoint(chain->edgels[i-1]->pt, ref_e->pt))>0;
1407 
1408       if (centered_ && !bidir_) //form regular curvelets
1409       {
1410         //use a symmetric set around the ref of the desired size
1411         std::deque<sdet_edgel*> cvlet_chain;
1412 
1413         //backward direction
1414         for (unsigned j=1; j<2*nrad_; j++)
1415         {
1416           if (int(i)-int(j)<0) continue;
1417 
1418           sdet_edgel* e=chain->edgels[i-j];
1419           if (vgl_distance(ref_e->pt, e->pt)>rad_)
1420             break;
1421 
1422           cvlet_chain.push_front(e); //add it to the sub-chain
1423         }
1424 
1425         cvlet_chain.push_back(ref_e); //add the current edgel to the subchain
1426 
1427         //forward direction
1428         for (unsigned j=1; j<2*nrad_; j++)
1429         {
1430           if (i+j>=chain->edgels.size()) continue;
1431 
1432           sdet_edgel* e=chain->edgels[i+j];
1433           if (vgl_distance(ref_e->pt, e->pt)>rad_)
1434             break;
1435 
1436           cvlet_chain.push_back(e); //add it to the sub-chain
1437         }
1438 
1439         if (!rel_dir)
1440           std::reverse(cvlet_chain.begin(), cvlet_chain.end());
1441 
1442         //now form a curvelet from this subchain
1443         sdet_curvelet* cvlet = nullptr;
1444         if (cvlet_chain.size()>3)
1445           cvlet = form_an_edgel_grouping(ref_e, cvlet_chain, true, centered_, false);
1446 
1447         if (cvlet){
1448           curvelet_map_.add_curvelet(cvlet);
1449         }
1450       }
1451 
1452       if (!centered_ && !bidir_) //ENO style curvelets
1453       {
1454         //2 curvelets around the ref edgel
1455         std::deque<sdet_edgel*> cvlet_chainb, cvlet_chaina;
1456 
1457         //backward direction
1458         for (unsigned j=0; j<2*nrad_; j++)
1459         {
1460           if (int(i)-int(j)<0) continue;
1461 
1462           sdet_edgel* e=chain->edgels[i-j];
1463           if (vgl_distance(ref_e->pt, e->pt)>rad_)
1464             break;
1465 
1466           cvlet_chainb.push_front(e); //add it to the sub-chain
1467         }
1468 
1469         if (!rel_dir)
1470           std::reverse(cvlet_chainb.begin(), cvlet_chainb.end());
1471 
1472         //now form a curvelet from this subchain
1473         sdet_curvelet* cvletb = nullptr;
1474         if (cvlet_chainb.size()>3)
1475           cvletb = form_an_edgel_grouping(ref_e, cvlet_chainb);
1476 
1477         if (cvletb) curvelet_map_.add_curvelet(cvletb);
1478 
1479         //forward direction
1480         for (unsigned j=0; j<2*nrad_; j++)
1481         {
1482           if (i+j>=chain->edgels.size()) continue;
1483 
1484           sdet_edgel* e=chain->edgels[i+j];
1485           if (vgl_distance(ref_e->pt, e->pt)>rad_)
1486             break;
1487 
1488           cvlet_chaina.push_back(e); //add it to the sub-chain
1489         }
1490 
1491         if (!rel_dir)
1492           std::reverse(cvlet_chaina.begin(), cvlet_chaina.end());
1493 
1494         //now form a curvelet from this subchain
1495         sdet_curvelet* cvleta = nullptr;
1496         if (cvlet_chainb.size()>3)
1497           cvleta = form_an_edgel_grouping(ref_e, cvlet_chaina);
1498 
1499         if (cvleta) curvelet_map_.add_curvelet(cvleta);
1500 
1501       }
1502     }
1503   }
1504 
1505 }
1506 
1507 //: attempt to form curvelets from the traced contour fragments
1508 void
1509 sdet_sel_base
form_curvelets_from_contours(unsigned max_size_to_group)1510 ::form_curvelets_from_contours(unsigned max_size_to_group)
1511 {
1512   //form a new curvelet map
1513   curvelet_map_.resize(edgemap_->num_edgels());
1514 
1515   auto half_size = (unsigned) std::floor((max_size_to_group-1)/2.0);
1516 
1517   auto f_it = curve_frag_graph_.frags.begin();
1518   for (; f_it != curve_frag_graph_.frags.end(); f_it++)
1519   {
1520     sdet_edgel_chain* chain = (*f_it);
1521 
1522     if (chain->edgels.size()<max_size_to_group)
1523       continue;
1524 
1525     //go over the edgel chain and try to form curvelets using the edgels in the chain
1526     for (unsigned i=0; i<chain->edgels.size(); i++)
1527     {
1528       sdet_edgel* ref_e = chain->edgels[i];
1529 
1530       //Issue: how do we find out whether the ordering is forward/backward wrt the edge chain?
1531       bool rel_dir;
1532       if (i==0) rel_dir = sdet_dot(ref_e->tangent, sdet_vPointPoint(ref_e->pt, chain->edgels[i+1]->pt))>0;
1533       else      rel_dir = sdet_dot(ref_e->tangent, sdet_vPointPoint(chain->edgels[i-1]->pt, ref_e->pt))>0;
1534 
1535       //use different groups according to the nature of the grouping process
1536       if (centered_) //regular curvelet
1537       {
1538         //first in the forward direction
1539         //use a symmetric set around the ref of the desired size
1540         std::deque<sdet_edgel*> cvlet_chain;
1541         for (int j=(int)i-(int)half_size; j<(int)(i+half_size+1); j++){
1542           if (j>=0 && j<(int)chain->edgels.size())
1543             cvlet_chain.push_back(chain->edgels[j]);
1544         }
1545 
1546         sdet_curvelet* cvlet = form_an_edgel_grouping(ref_e, cvlet_chain, rel_dir, centered_, false);
1547         if (cvlet)
1548           curvelet_map_.add_curvelet(cvlet, rel_dir);
1549 
1550         if (bidir_){ //also in the other direction
1551           sdet_curvelet* cvlet2 = form_an_edgel_grouping(ref_e, cvlet_chain, !rel_dir, centered_, false);
1552           if (cvlet2)
1553             curvelet_map_.add_curvelet(cvlet2, !rel_dir);
1554         }
1555       }
1556       else {
1557         //form it as two separate one sided ones ones
1558 
1559         //forward half
1560         std::deque<sdet_edgel*> cvlet_chain;
1561         for (unsigned j=0; j<i+half_size+1; j++){
1562           if (j<chain->edgels.size())
1563             cvlet_chain.push_back(chain->edgels[j]);
1564         }
1565         sdet_curvelet* cvlet = form_an_edgel_grouping(ref_e, cvlet_chain, rel_dir, centered_, true);
1566         if (cvlet)
1567           curvelet_map_.add_curvelet(cvlet);
1568 
1569         if (bidir_)//other half in the other direction
1570         {
1571           std::deque<sdet_edgel*> cvlet_chain;
1572           for (int j=i-half_size; j<1; j++){
1573             if (j>=0 && j<(int)chain->edgels.size())
1574               cvlet_chain.push_back(chain->edgels[j]);
1575           }
1576           sdet_curvelet* cvlet = form_an_edgel_grouping(ref_e, cvlet_chain, !rel_dir, centered_, true);
1577           if (cvlet)
1578             curvelet_map_.add_curvelet(cvlet);
1579         }
1580         else { //other half in the same direction (ENO style)
1581           std::deque<sdet_edgel*> cvlet_chain;
1582           for (int j=i-half_size; j<1; j++){
1583             if (j>=0 && j<(int)chain->edgels.size())
1584               cvlet_chain.push_back(chain->edgels[j]);
1585           }
1586           sdet_curvelet* cvlet = form_an_edgel_grouping(ref_e, cvlet_chain, rel_dir, centered_, false);
1587           if (cvlet)
1588             curvelet_map_.add_curvelet(cvlet);
1589         }
1590       }
1591     }
1592   }
1593 }
1594 
1595 //: Break contours at places where curvelets cannot form
1596 void
1597 sdet_sel_base
post_process_to_break_contours()1598 ::post_process_to_break_contours()
1599 {
1600   //Assume that curvelets have been computed already and the link graph reflects all the links from the curvelets
1601 
1602   std::cout << "Breaking contours....";
1603 
1604   //container for all fragments to be deleted
1605   std::vector<sdet_edgel_chain*> frags_to_del;
1606 
1607   //container for all the new sub fragments
1608   std::vector<sdet_edgel_chain*> new_frags;
1609 
1610   //size of segment to ignore at the beginning and end of a contour
1611   unsigned max_size_to_group=7; //temp (should be passed in to this function)
1612   auto half_size = (unsigned) std::floor((max_size_to_group-1)/2.0);
1613 
1614   auto f_it = curve_frag_graph_.frags.begin();
1615   for (; f_it != curve_frag_graph_.frags.end(); f_it++)
1616   {
1617     sdet_edgel_chain* chain = (*f_it);
1618 
1619     if (chain->edgels.size()<max_size_to_group)
1620     {
1621       frags_to_del.push_back(chain);
1622       continue;
1623     }
1624 
1625     //Now trace through the curve fragment and verify that each edgel has a legal curve bundle
1626     //if not form sub chains
1627     sdet_edgel_chain* sub_chain = nullptr;
1628     bool needs_to_be_deleted = false;
1629     //bool first_frag = true;
1630     bool break_found = false;
1631     bool forming_sub_chain = false;
1632 
1633     for (unsigned j=half_size-1; j<chain->edgels.size()-half_size; j++)
1634     {
1635       bool cvlet_exists = curvelet_map_.curvelets(chain->edgels[j]->id).size()>0;
1636       needs_to_be_deleted = needs_to_be_deleted || !cvlet_exists;
1637 
1638       if (!break_found && !cvlet_exists)
1639         break_found = true;
1640 
1641       if (break_found && cvlet_exists) //create new sub chain from here
1642       {
1643         sub_chain = new sdet_edgel_chain();
1644         break_found = false;
1645         forming_sub_chain = true;
1646       }
1647 
1648       //grow or terminate current sub chain
1649       if (forming_sub_chain){
1650         //add edgel to the current sub chain
1651         sub_chain->edgels.push_back(chain->edgels[j]);
1652 
1653         if (!cvlet_exists)//terminate the sub chain
1654         {
1655           //add it to the fragment list
1656           new_frags.push_back(sub_chain);
1657           forming_sub_chain = false;
1658         }
1659       }
1660     }
1661 
1662     if (forming_sub_chain) //terminate the final sub chain
1663     {
1664       //now add it to the fragment list
1665       new_frags.push_back(sub_chain);
1666     }
1667 
1668     //delete the curve fragments that were broken
1669     if (needs_to_be_deleted)
1670       frags_to_del.push_back(chain); //mark for deletion
1671 
1672   }
1673 
1674   //First, delete all the fragments marked for deletion
1675   for (auto & j : frags_to_del)
1676     curve_frag_graph_.remove_fragment(j);
1677 
1678   //Finally, add all the new fragments to curve fragment graph
1679   for (auto & new_frag : new_frags)
1680   {
1681     if (new_frag->edgels.size()>2)
1682       curve_frag_graph_.insert_fragment(new_frag);
1683   }
1684 
1685   std::cout << "done." << std::endl;
1686 }
1687 
1688 //: evauate the qualities of curvelets using various functions
1689 void
1690 sdet_sel_base
evaluate_curvelet_quality(int method)1691 ::evaluate_curvelet_quality(int method)
1692 {
1693   //for each edgel, for each curvelet, compute quality using the specified method
1694   for (auto eA : edgemap_->edgels)
1695   {
1696     auto it = curvelet_map_.curvelets(eA->id).begin();
1697     for (; it != curvelet_map_.curvelets(eA->id).end(); it++){
1698       sdet_curvelet* cvlet = (*it);
1699 
1700       switch(method){
1701         case 0: //average distance between edgels
1702         {
1703           double L=0;
1704           for (unsigned i=0; i<cvlet->edgel_chain.size()-1; i++)
1705             L += vgl_distance(cvlet->edgel_chain[i]->pt, cvlet->edgel_chain[i+1]->pt);
1706 
1707           cvlet->quality = L/(cvlet->edgel_chain.size()-1);
1708           break;
1709         }
1710         case 1: //largest distance between edgels in the curvelet
1711         {
1712           double maxL = -1.0;
1713           for (unsigned i=0; i<cvlet->edgel_chain.size()-1; i++){
1714             double d = vgl_distance(cvlet->edgel_chain[i]->pt, cvlet->edgel_chain[i+1]->pt);
1715             if (d>maxL) maxL = d;
1716           }
1717           cvlet->quality = maxL;
1718           break;
1719         }
1720         case 3: //ratio between the largest distance and the total length
1721         {
1722           double maxL = -1.0;
1723           double L=0;
1724           for (unsigned i=0; i<cvlet->edgel_chain.size()-1; i++){
1725             double d = vgl_distance(cvlet->edgel_chain[i]->pt, cvlet->edgel_chain[i+1]->pt);
1726             L += d;
1727             if (d>maxL) maxL = d;
1728           }
1729 
1730           cvlet->quality = maxL/L;
1731           break;
1732         }
1733         case 4: //ratio/diff in length beween the polyline and the length of the curve fit
1734         {
1735           break;
1736         }
1737       }
1738 
1739 
1740     }
1741   }
1742 
1743 }
1744 
1745 //: method to look at the spread of differential estimates
1746 void
1747 sdet_sel_base
determine_accuracy_of_measurements()1748 ::determine_accuracy_of_measurements()
1749 {
1750   //determine # of curvelets
1751   int cvlet_cnt=0;
1752   for (unsigned i=0; i<edgemap_->edgels.size(); i++)
1753     cvlet_cnt += curvelet_map_.curvelets(i).size();
1754 
1755   //estimates
1756   double estimates[3], min_estimates[3], max_estimates[3];
1757   vnl_vector<double> theta_est(cvlet_cnt), k_est(cvlet_cnt), gamma_est(cvlet_cnt);
1758   vnl_vector<double> theta_error(cvlet_cnt), k_error(cvlet_cnt), gamma_error(cvlet_cnt);
1759 
1760   cvlet_cnt=0;
1761   //for each edgel, for each curvelet, get accuracy measurements from the curve_model
1762   for (unsigned i=0; i<edgemap_->edgels.size(); i++)
1763   {
1764     auto it = curvelet_map_.curvelets(i).begin();
1765     for (; it != curvelet_map_.curvelets(i).end(); it++){
1766       sdet_curvelet* cvlet = (*it);
1767 
1768       //get the measurements from the curvelets
1769       cvlet->curve_model->report_accuracy(estimates, min_estimates, max_estimates);
1770 
1771       theta_est(cvlet_cnt) = estimates[0];
1772       k_est(cvlet_cnt)     = estimates[1];
1773       gamma_est(cvlet_cnt) = estimates[2];
1774 
1775       theta_error(cvlet_cnt) = std::min(std::abs(estimates[0]-min_estimates[0]), std::abs(estimates[0]-max_estimates[0]));
1776       k_error(cvlet_cnt)     = std::min(std::abs(estimates[1]-min_estimates[1]), std::abs(estimates[1]-max_estimates[1]));
1777       gamma_error(cvlet_cnt) = std::min(std::abs(estimates[2]-min_estimates[2]), std::abs(estimates[2]-max_estimates[2]));
1778 
1779       cvlet_cnt++;
1780     }
1781   }
1782 
1783   double theta_mean, theta_std, theta_error_mean, theta_error_std;
1784   double k_mean, k_std, k_error_mean, k_error_std;
1785   double gamma_mean, gamma_std, gamma_error_mean, gamma_error_std;
1786 
1787   //calculate the meaan and variance of the measurements
1788   calc_mean_var(theta_mean, theta_std, theta_est);
1789   calc_mean_var(k_mean, k_std, k_est);
1790   calc_mean_var(gamma_mean, gamma_std, gamma_est);
1791 
1792   //calculate mean and variance of the errors
1793   calc_mean_var(theta_error_mean, theta_error_std, theta_error);
1794   calc_mean_var(k_error_mean, k_error_std, k_error);
1795   calc_mean_var(gamma_error_mean, gamma_error_std, gamma_error);
1796 
1797   std::cout << "======================================" << std::endl;
1798   std::cout << "Derivative estimate accuracy Report"    << std::endl;
1799   std::cout << "======================================" << std::endl;
1800   std::cout << "theta estimate (mean, std): (" << theta_mean << ", " << std::sqrt(theta_std) << ")" << std::endl;
1801   std::cout << "  k   estimate (mean, std): (" << k_mean << ", " << std::sqrt(k_std) << ")" << std::endl;
1802   std::cout << "gamma estimate (mean, std): (" << gamma_mean << ", " << std::sqrt(gamma_std) << ")" << std::endl;
1803 
1804   std::cout << "spread of theta estimate (mean, std): (" << theta_error_mean << ", " << std::sqrt(theta_error_std) << ")" << std::endl;
1805   std::cout << "spread of  k   estimate (mean, std): (" << k_error_mean << ", " << std::sqrt(k_error_std) << ")" << std::endl;
1806   std::cout << "spread of gamma estimate (mean, std): (" << gamma_error_mean << ", " << std::sqrt(gamma_error_std) << ")" << std::endl;
1807 
1808 }
1809 
1810 
1811 void
1812 sdet_sel_base
report_stats()1813 ::report_stats()
1814 {
1815   std::cout << "======================================" << std::endl;
1816   std::cout << "Edge Linking Summary\n";
1817   std::cout << "======================================" << std::endl;
1818   std::cout << "# of edgels:   " << edgemap_->edgels.size() << std::endl;
1819   std::cout << "Parameters: ";
1820   std::cout << "dx = " << dpos_ << ", dt = " << dtheta_ << std::endl;
1821   std::cout << "neighborhood radius = " << rad_ << ", maxN = " << maxN_ << std::endl;
1822 
1823   unsigned max_size = 0;
1824   //find maximum size of curvelet
1825   for (unsigned i=0; i<edgemap_->edgels.size(); i++){
1826     auto it = curvelet_map_.curvelets(i).begin();
1827     for (; it != curvelet_map_.curvelets(i).end(); it++){
1828       sdet_curvelet* cvlet = (*it);
1829 
1830       if (cvlet->order()>max_size)
1831         max_size = cvlet->order();
1832     }
1833   }
1834 
1835   //count the raw number of edgel groupings by size
1836   std::vector<int> cvlet_cnt(max_size+1, 0);
1837 
1838   //count the # of edgels that have a particular sized grouping
1839   std::vector<int> cvlet_edgel_cnt(max_size+1, 0);
1840 
1841   //count the # of edgels that have a curvelets of a certain size or lower
1842   std::vector<int> min_cvlet_edgel_cnt(max_size+1, 0);
1843 
1844   //count the # of curvelets that are consistent with their neighbors (criteria 1)
1845   std::vector<int> consistent_cvlet_cnt(max_size+1, 0);
1846 
1847   //count the # of edgels that have consistent curvelets of a particular size
1848   std::vector<int> consistent_cvlet_edgel_cnt(max_size+1, 0);
1849 
1850   //count the # of edgels that have consistent curvelets of a particular size or lower
1851   std::vector<int> min_consistent_cvlet_edgel_cnt(max_size+1, 0);
1852 
1853   for (auto eA : edgemap_->edgels)
1854   {
1855     //keep track of the various sized curvelets formed by this edgel
1856     std::vector<bool> size_exists(max_size+1, false);
1857     std::vector<bool> consistent_size_exists(max_size+1, false);
1858 
1859     //for each edgel go over all the curvelets it forms
1860     auto it = curvelet_map_.curvelets(eA->id).begin();
1861     for (; it != curvelet_map_.curvelets(eA->id).end(); it++)
1862     {
1863       sdet_curvelet* cvlet = (*it);
1864 
1865       //increment the raw cvlet counter for the current size
1866       cvlet_cnt[cvlet->order()]++;
1867 
1868       //make a note of the size of this curvelet
1869       size_exists[cvlet->order()] = true;
1870 
1871       //check to see if this curvelet is consistent with its neighbors
1872       //This requires a parameter of which neighboring curvelets to consider to judge consistency
1873       //so use the same sized neighbors as itself
1874       bool cvlet_has_consistent_neighbor = false;
1875       for (unsigned k=0; k<cvlet->edgel_chain.size(); k++){
1876         if (k>0 && cvlet->edgel_chain[k-1]==eA) //the link after it (eA --> edgel_chain[k])
1877         {
1878           if (link_is_reciprocal(eA, cvlet->edgel_chain[k], eA, cvlet->order()))
1879             cvlet_has_consistent_neighbor = true;
1880         }
1881         if (k<cvlet->edgel_chain.size()-1 && cvlet->edgel_chain[k+1]==eA) //the link before it (edgel_chain[k] --> eA)
1882         {
1883           if (link_is_reciprocal(cvlet->edgel_chain[k], eA, eA, cvlet->order()))
1884             cvlet_has_consistent_neighbor = true;
1885         }
1886       }
1887 
1888       if (cvlet_has_consistent_neighbor){
1889         consistent_cvlet_cnt[cvlet->order()]++;
1890         consistent_size_exists[cvlet->order()] = true;
1891       }
1892     }
1893 
1894     //now update the cvlet_edgel_cnt with the various sized curvelets that this edgel had formed
1895     for (unsigned j=3; j<=max_size; j++)
1896     {
1897       if (size_exists[j]) cvlet_edgel_cnt[j]++;
1898 
1899       bool larger = false;
1900       for (unsigned k=j+1; k<=max_size; k++)
1901         larger = larger || size_exists[k];
1902 
1903       //this is the largest curvelet that this edgel has
1904       if (!larger)  min_cvlet_edgel_cnt[j]++;
1905 
1906       //repeat for consistent curvelets only
1907       if (consistent_size_exists[j]) consistent_cvlet_edgel_cnt[j]++;
1908 
1909       larger = false;
1910       for (unsigned k=j+1; k<=max_size; k++)
1911         larger = larger || consistent_size_exists[k];
1912 
1913       //this is the largest curvelet that this edgel has
1914       if (!larger)  min_consistent_cvlet_edgel_cnt[j]++;
1915     }
1916   }
1917 
1918   //report
1919   std::cout << "==========================================================================================================" << std::endl;
1920   std::cout << "| cvlet size | raw # cvlet | % of edgels | % of edgels with no other larger curvelets | # of consistent cvlets | % of edgels with consistent curvelets |" << std::endl;
1921   for (unsigned i=3; i<=max_size; i++){
1922     std::cout << i << " " << cvlet_cnt[i] << " " << cvlet_edgel_cnt[i]*100.0/edgemap_->edgels.size() << " " << min_cvlet_edgel_cnt[i]*100.0/edgemap_->edgels.size() << " " ;
1923     std::cout <<  consistent_cvlet_cnt[i] << " " << consistent_cvlet_edgel_cnt[i]*100.0/edgemap_->edgels.size() << " " << min_consistent_cvlet_edgel_cnt[i]*100.0/edgemap_->edgels.size() << std::endl;
1924   }
1925 
1926   std::cout << std::endl;
1927   std::cout << "# of image curves: " << curve_frag_graph_.frags.size() << std::endl;
1928   std::cout << "======================================" << std::endl;
1929 }
1930 
1931 // Moved sel_base member functions from sdet_sel_base_CFTG_algo to here
1932 // to keep all together
1933 
1934 //********************************************************************//
1935 // Functions for constructing hypothesis trees and
1936 // tracing between contour end points.
1937 //********************************************************************//
1938 
1939 
1940 #define SM_TH 0.6
1941 
1942 #define Theta_1 0.6
1943 #define Theta_2 0.0
1944 #define Strength_Diff1 2.0
1945 #define Strength_Diff2 4.0
1946 
1947 sdet_EHT*
1948 sdet_sel_base
construct_hyp_tree(sdet_edgel * edge)1949 ::construct_hyp_tree(sdet_edgel* edge)
1950 {
1951   if (edge_link_graph_.cLinks.size()==0)
1952     {
1953     std::cout << "No Link Graph !" <<std::endl;
1954     return nullptr;
1955     }
1956 
1957 
1958  //construct 2 HTs: one in the forward direction and one in the reverse direction ????  by yuliang no forword
1959 //Modify: for each node, consider all the child links and parent links(exact the one linking parent node), as its child node
1960   std::queue<sdet_EHT_node*> BFS_queue;
1961 
1962   //forward HT
1963   auto* HTF = new sdet_EHT();
1964 
1965   auto* root1 = new sdet_EHT_node(edge);
1966   HTF->root = root1;
1967   BFS_queue.push(root1);
1968 
1969   int depth = 0; // comment by Yuliang, this is not the depth of the tree, but number of nodes actually
1970 
1971   //How far do we wanna go (if we don't hit a node)?
1972   while (!BFS_queue.empty() && std::log10(double(depth))<3)
1973   {
1974     sdet_EHT_node* cur_node = BFS_queue.front();
1975     BFS_queue.pop();
1976 
1977     //are we at a CFG node? if we are we don't need to go any further
1978     if (cur_node!= root1 &&
1979         (curve_frag_graph_.pFrags[cur_node->e->id].size()>0 ||
1980          curve_frag_graph_.cFrags[cur_node->e->id].size()>0))
1981       continue;
1982 
1983     //also if we hit an edgel that is already linked no need to go further (this might ensure planarity)
1984     if (edge_link_graph_.linked[cur_node->e->id])
1985       continue;
1986 
1987     //propagate this node
1988     auto lit = edge_link_graph_.cLinks[cur_node->e->id].begin();
1989     for (; lit != edge_link_graph_.cLinks[cur_node->e->id].end(); lit++)
1990     {
1991       if (edge_link_graph_.linked[(*lit)->ce->id]) //don't go tracing in linked contours
1992         continue;
1993 
1994       if (cur_node->parent) {
1995         //make a simple consistency check
1996         double dx1 = cur_node->e->pt.x() - cur_node->parent->e->pt.x();
1997         double dy1 = cur_node->e->pt.y() - cur_node->parent->e->pt.y();
1998         double dx2 = (*lit)->ce->pt.x() - cur_node->e->pt.x();
1999         double dy2 = (*lit)->ce->pt.y() - cur_node->e->pt.y();
2000 
2001 
2002         if (((dx1*dx2 + dy1*dy2)/std::sqrt(dx1*dx1+dy1*dy1)/std::sqrt(dx2*dx2+dy2*dy2))<SM_TH) //not consistent, but with lower TH to keep more Hypothesis by Yuliang ////////// Cosine Formula
2003           continue;
2004       }
2005 
2006       //else extend the tree to this edgel
2007       auto* new_node = new sdet_EHT_node((*lit)->ce);
2008 
2009       cur_node->add_child(new_node);
2010       BFS_queue.push(new_node);
2011       depth++;
2012     }
2013     // by Yuliang
2014     // explore in pLinks
2015     lit = edge_link_graph_.pLinks[cur_node->e->id].begin();
2016     for (; lit != edge_link_graph_.pLinks[cur_node->e->id].end(); lit++)
2017     {
2018       if (edge_link_graph_.linked[(*lit)->pe->id]) //don't go tracing in linked contours
2019         continue;
2020       if (cur_node->parent) {
2021           if((*lit)->pe->id == cur_node->parent->e->id)// if this parent link the same from parent node, don't trace
2022         continue;
2023         //make a simple consistency check
2024         double dx1 = cur_node->e->pt.x() - cur_node->parent->e->pt.x();
2025         double dy1 = cur_node->e->pt.y() - cur_node->parent->e->pt.y();
2026         double dx2 = (*lit)->pe->pt.x() - cur_node->e->pt.x();
2027         double dy2 = (*lit)->pe->pt.y() - cur_node->e->pt.y();
2028 
2029         if (((dx1*dx2 + dy1*dy2)/std::sqrt(dx1*dx1+dy1*dy1)/std::sqrt(dx2*dx2+dy2*dy2))<SM_TH) //not consistent, but with lower TH to keep more Hypothesis by Yuliang
2030           continue;
2031       }
2032 
2033       //else extend the tree to this edgel
2034       auto* new_node = new sdet_EHT_node((*lit)->pe);
2035 
2036       cur_node->add_child(new_node);
2037       BFS_queue.push(new_node);
2038       depth++;
2039     }
2040   }
2041 
2042   //empty the bfs queue
2043   while (!BFS_queue.empty())
2044     BFS_queue.pop();
2045 
2046   return HTF;
2047 }
2048 
2049 //: construct all possible EHTs from the terminal nodes and find legal contour paths
2050 void
2051 sdet_sel_base
construct_all_path_from_EHTs()2052 ::construct_all_path_from_EHTs()
2053 {
2054   // modify by Yuliang, use a local filter for contours size 3 and 4 to prune some, and merge some continuous regular contours first
2055   regular_contour_filter();
2056   //go over the contour fragment graph and form an EHT from every terminal node
2057   //validate each of the paths in the EHT
2058 
2059   std::vector<sdet_edgel_chain*> new_frags;
2060 
2061   //going over the edgemap instead so that an EHT only starts once from a node when there are two
2062   //contour fragments terminating there
2063   for (unsigned i=0; i<edgemap_->edgels.size(); i++)
2064   {
2065     sdet_edgel* eA = edgemap_->edgels[i];
2066 
2067     if (curve_frag_graph_.pFrags[i].size()==0 &&
2068         curve_frag_graph_.cFrags[i].size()==0)
2069       continue; //no terminal nodes here
2070 
2071     //1) Terminal node found, construct an EHT from here
2072     sdet_EHT* EHT1 = construct_hyp_tree(eA);
2073 
2074     //2) traverse each path and determine its validity
2075     if (EHT1)
2076     {
2077       //traverse the EHT and test all the paths
2078       sdet_EHT::path_iterator pit = EHT1->path_begin();
2079       for (; pit != EHT1->path_end(); pit++){
2080         std::vector<sdet_edgel*>& edgel_chain = pit.get_cur_path();
2081 
2082     sdet_edgel* le = edgel_chain.back();
2083 
2084         if (curve_frag_graph_.pFrags[le->id].size()==0 && curve_frag_graph_.cFrags[le->id].size()==0)
2085         {
2086           //not a valid termination node
2087           //delete the node associated  with this path ( it will delete the entire path, by definition)
2088           EHT1->delete_subtree(pit);
2089           continue;
2090         }
2091 
2092         //test this path to see if it is valid
2093         if (!is_EHT_path_legal(edgel_chain)){
2094           EHT1->delete_subtree(pit);
2095           continue;
2096         }
2097 
2098         //copy this chain
2099         auto* new_chain = new sdet_edgel_chain();
2100         new_chain->append(edgel_chain);
2101         new_chain->temp = true; //make sure that the new frags are initialized with temp flags
2102 
2103         curve_frag_graph_.CFTG.insert_fragment(new_chain);
2104         //now that its added delete the apth
2105         EHT1->delete_subtree(pit);
2106       }
2107 
2108       //finally delete the EHT
2109       delete EHT1;
2110     }
2111   }
2112   std::cout<<"Finish constructing all hypothesis trees"<<std::endl;
2113   ////Now add all the new curve fragments into the CFG (as tentative fragments)
2114   //for (unsigned i=0; i<new_frags.size(); i++)
2115   //  curve_frag_graph_.insert_fragment(new_frags[i]);
2116 }
2117 
2118 //: perform a geometric consistency check to determine whether a given temp path is valid
2119 bool
2120 sdet_sel_base
is_EHT_path_legal(std::vector<sdet_edgel * > & edgel_chain)2121 ::is_EHT_path_legal(std::vector<sdet_edgel*>& edgel_chain)
2122 {
2123   //what makes a path legal?
2124 
2125   // Modified by Yuliang, before (a), (b), if path only have < 3 edgels, prune out direct link over 3 pixels
2126   if(edgel_chain.size()<3)
2127   {
2128       sdet_edgel* eS = edgel_chain.front();
2129       sdet_edgel* eE = edgel_chain.back();
2130       double dx1 = eE->pt.x() - eS->pt.x();
2131       double dy1 = eE->pt.y() - eS->pt.y();
2132       double dist= std::sqrt(dx1*dx1+dy1*dy1);
2133       if(dist>5)
2134         return false;
2135    }
2136 
2137   // by Yuliang, construct two lists of end nodes from other Curve Fragments end poits linking the end points of the path
2138   std::vector<sdet_edgel*> S_link_end_nodes, E_link_end_nodes;
2139 
2140   // (a) if a c1 polyarc bundle can form within it
2141   // (b) if it is c1 compatible with the end points
2142 
2143   //For now, just check for...
2144 
2145   //1) continuity consistency at the end points
2146   //1a) at the start point
2147   sdet_edgel* eS = edgel_chain.front();
2148   sdet_edgel* e2 = edgel_chain[1];
2149   double dx1 = e2->pt.x() - eS->pt.x();
2150   double dy1 = e2->pt.y() - eS->pt.y();
2151   bool cons = false;
2152 
2153 
2154   //is this at a start or an end of an unambiguous chain?
2155   auto pcit = curve_frag_graph_.pFrags[eS->id].begin();
2156   for ( ; pcit != curve_frag_graph_.pFrags[eS->id].end(); pcit++)
2157   {
2158     sdet_edgel* pe = (*pcit)->edgels[(*pcit)->edgels.size()-2];
2159     S_link_end_nodes.push_back((*pcit)->edgels.front());
2160 
2161     //make a simple consistency check for child Frags
2162     double dx2 = eS->pt.x() - pe->pt.x();
2163     double dy2 = eS->pt.y() - pe->pt.y();
2164 
2165     cons = cons || ((dx1*dx2 + dy1*dy2)/std::sqrt(dx1*dx1+dy1*dy1)/std::sqrt(dx2*dx2+dy2*dy2))>0;
2166   }
2167   auto ccit = curve_frag_graph_.cFrags[eS->id].begin();
2168   for ( ; ccit != curve_frag_graph_.cFrags[eS->id].end(); ccit++)
2169   {
2170     sdet_edgel* ce = (*ccit)->edgels[1];
2171     S_link_end_nodes.push_back((*ccit)->edgels.back());
2172 
2173     //make a simple consistency check for parent Frags
2174     double dx2 = eS->pt.x() - ce->pt.x();
2175     double dy2 = eS->pt.y() - ce->pt.y();
2176 
2177     cons = cons || ((dx1*dx2 + dy1*dy2)/std::sqrt(dx1*dx1+dy1*dy1)/std::sqrt(dx2*dx2+dy2*dy2))>0;
2178   }
2179   if (!cons) return false; //no good at the start point
2180 
2181   //1b) at the end point
2182   sdet_edgel* eE = edgel_chain.back();
2183   e2 = edgel_chain[edgel_chain.size()-2];
2184   dx1 = eE->pt.x() - e2->pt.x();
2185   dy1 = eE->pt.y() - e2->pt.y();
2186   cons = false;
2187 
2188   //is this at a start or an end of an unambiguous chain?
2189   pcit = curve_frag_graph_.pFrags[eE->id].begin();
2190   for ( ; pcit != curve_frag_graph_.pFrags[eE->id].end(); pcit++)
2191   {
2192     sdet_edgel* pe = (*pcit)->edgels[(*pcit)->edgels.size()-2];
2193     E_link_end_nodes.push_back((*pcit)->edgels.front());
2194 
2195     //make a simple consistency check
2196     double dx2 = pe->pt.x() - eE->pt.x();
2197     double dy2 = pe->pt.y() - eE->pt.y();
2198 
2199     cons = cons || ((dx1*dx2 + dy1*dy2)/std::sqrt(dx1*dx1+dy1*dy1)/std::sqrt(dx2*dx2+dy2*dy2))>0;
2200   }
2201   ccit = curve_frag_graph_.cFrags[eE->id].begin();
2202   for ( ; ccit != curve_frag_graph_.cFrags[eE->id].end(); ccit++)
2203   {
2204     sdet_edgel* ce = (*ccit)->edgels[1];
2205     E_link_end_nodes.push_back((*ccit)->edgels.back());
2206 
2207     //make a simple consistency check
2208     double dx2 = ce->pt.x() - eE->pt.x();
2209     double dy2 = ce->pt.y() - eE->pt.y();
2210 
2211     cons = cons || ((dx1*dx2 + dy1*dy2)/std::sqrt(dx1*dx1+dy1*dy1)/std::sqrt(dx2*dx2+dy2*dy2))>0;
2212   }
2213   if (!cons) return false; //no good at the end point
2214 
2215   //2) By Yuliang, use the two lists, check if it is a path between which unambiguous contours linked
2216   for (auto S_l_e : S_link_end_nodes)
2217     {
2218     if(S_l_e == eE)
2219       return false;
2220     for (auto E_l_e : E_link_end_nodes)
2221       {
2222       if(E_l_e == eS)
2223         return false;
2224       // the case two connected contours filling the path
2225       if(E_l_e== S_l_e)
2226         return false;
2227       }
2228     }
2229 
2230   // comment by Yuliang, in most cases, it is no need, because of short paths.
2231   //fit_polyarc_to_chain(&edgel_chain);
2232   return true;
2233 }
2234 
2235 //: New Quality Metric by Naman Kumar :: compute a path metric based on the Gap, Orientation, Strength and Size of the chain
2236 double
2237 sdet_sel_base
compute_path_metric2(std::vector<sdet_edgel * > & Pchain,std::vector<sdet_edgel * > & Tchain,std::vector<sdet_edgel * > & Cchain)2238 ::compute_path_metric2(std::vector<sdet_edgel*>& Pchain,
2239                        std::vector<sdet_edgel*>& Tchain,
2240                        std::vector<sdet_edgel*>& Cchain)
2241 {
2242   double cost = 0.0;double ds=0;double dt=0;
2243 
2244   //construct an edgel chain out of all three chains
2245   std::vector<sdet_edgel*> chain;
2246   if (Pchain.size())
2247     for (auto i : Pchain) chain.push_back(i);
2248   if (Tchain.size())
2249     for (auto i : Tchain) chain.push_back(i);
2250   if (Cchain.size())
2251     for (auto i : Cchain) chain.push_back(i);
2252 
2253   //now compute the metric
2254   sdet_edgel *eA=nullptr, *eP=nullptr;
2255   double dsp = 0, thp = 0, total_ds =0.0, a=0.0,s1=0,s2=0,s=0,size=chain.size();
2256   for (unsigned i=1; i<chain.size(); i++)
2257   {
2258     eA = chain[i];
2259     eP = chain[i-1];
2260     s1=(eA)->strength;
2261     s2=(eP)->strength;
2262     s=std::fabs(s1-s2);
2263     //compute ds
2264     ds = vgl_distance(eA->pt, eP->pt);
2265     if(ds>1.0) a=2.0; else a=1.0;
2266     total_ds += ds;
2267     //compute dtheta
2268     double thc = sdet_vPointPoint(eP->pt, eA->pt);
2269     dt = std::fabs(thc-thp);
2270     dt = (dt>vnl_math::pi)? 2*vnl_math::pi-dt : dt;
2271     cost += std::pow((s+dt + a*ds)/size, 2.0);
2272     thp = thc;//save the current vector for the next iteration
2273   }
2274   return cost;
2275 }
2276 
2277 
link_cost_less(sdet_CFTG_link * link1,sdet_CFTG_link * link2)2278 bool link_cost_less(sdet_CFTG_link* link1, sdet_CFTG_link* link2)
2279 {return link1->cost < link2->cost;}
2280 
2281 
2282 //: disambiguate the CFG, basically to produce a disjoint set
disambiguate_the_CFTG()2283 void sdet_sel_base::disambiguate_the_CFTG()
2284 {
2285   //At the moment, I cannot verify that the CFTG is topologically sound (i.e., a planar graph)
2286   //so within this limit, the goal is to break the links at junctions
2287 
2288   //Alternatively, it is possible to splice the two contours and mark the connection with the others as a junction
2289   //these others might be pruned off at a postprocessing stage if desired
2290 
2291   //Note: the temp flag on the contours distinguish it from the unambiguous contours
2292 
2293   //A) disambiguate the links first : Only keep the best path
2294   //   Note: remember to search in both directions
2295 
2296   //go over all the links of the CFTG
2297   std::vector<sdet_edgel*> dummy_chain;
2298 
2299   auto l_it = curve_frag_graph_.CFTG.Links.begin();
2300   for (; l_it != curve_frag_graph_.CFTG.Links.end(); l_it++)
2301   {
2302     sdet_CFTG_link* cur_Link = (*l_it);
2303 
2304 
2305     //is this an ambiguous link?
2306     if (cur_Link->cCFs.size()>1)
2307     {
2308       //needs disambiguation
2309       double min_cost = 10000;
2310       sdet_edgel_chain* best_chain = nullptr;
2311     auto f_it = cur_Link->cCFs.begin();
2312     for(; f_it != cur_Link->cCFs.end(); f_it++)
2313       {
2314         sdet_edgel_chain* edgel_chain = (*f_it);
2315         std::vector<sdet_edgel*> chain(edgel_chain->edgels.begin(), edgel_chain->edgels.end());
2316 
2317         double path_cost = compute_path_metric2(dummy_chain, chain, dummy_chain);
2318         if (path_cost < min_cost){
2319           min_cost = path_cost;
2320           best_chain = edgel_chain;
2321         }
2322 
2323       }
2324 
2325       //remove all except the best chain
2326       if (best_chain){
2327         auto f_it = cur_Link->cCFs.begin();
2328         for(; f_it != cur_Link->cCFs.end(); f_it++)
2329           if ((*f_it) != best_chain)
2330             delete (*f_it);
2331 
2332         cur_Link->cCFs.clear();
2333         cur_Link->cCFs.push_back(best_chain);
2334         cur_Link->cost = min_cost;
2335 }
2336     }
2337     else { //just comptue cost for this path
2338 
2339       sdet_edgel_chain* edgel_chain = cur_Link->cCFs.front();
2340       std::vector<sdet_edgel*> chain(edgel_chain->edgels.begin(), edgel_chain->edgels.end());
2341       cur_Link->cost = compute_path_metric2(dummy_chain, chain, dummy_chain);
2342     }
2343   }
2344   //B) disambiguate between duplicates (A->B vs B->A)
2345   l_it = curve_frag_graph_.CFTG.Links.begin();
2346   for (; l_it != curve_frag_graph_.CFTG.Links.end(); l_it++)
2347   {
2348     sdet_CFTG_link* cur_Link = (*l_it);
2349 
2350     if (cur_Link->cCFs.size()==0)
2351       continue;
2352 
2353     //look for the link from the other direction
2354     auto l_it2 = curve_frag_graph_.CFTG.cLinks[cur_Link->eE->id].begin();
2355     for (; l_it2 != curve_frag_graph_.CFTG.cLinks[cur_Link->eE->id].end(); l_it2++){
2356       if ((*l_it2)->eE == cur_Link->eS){
2357         //duplicate found
2358 
2359         if ((*l_it2)->cCFs.size()==0)
2360           continue;
2361 
2362         sdet_edgel_chain* edgel_chain1 = cur_Link->cCFs.front();
2363         sdet_edgel_chain* edgel_chain2 = (*l_it2)->cCFs.front();
2364 
2365         std::vector<sdet_edgel*> chain1(edgel_chain1->edgels.begin(), edgel_chain1->edgels.end());
2366         std::vector<sdet_edgel*> chain2(edgel_chain2->edgels.begin(), edgel_chain2->edgels.end());
2367 
2368         double path_cost1 = compute_path_metric2(dummy_chain, chain1, dummy_chain);
2369         double path_cost2 = compute_path_metric2(dummy_chain, chain2, dummy_chain);
2370 
2371         if (path_cost1<path_cost2){
2372           //keep current link and delete the other
2373           delete edgel_chain2;
2374           (*l_it2)->cCFs.clear();
2375           (*l_it2)->cost = 1000;
2376         }
2377         else{
2378           delete edgel_chain1;
2379           cur_Link->cCFs.clear();
2380           cur_Link->cost = 1000;
2381         }
2382       }
2383     }
2384   }
2385 
2386   //C) Gradient descent to prune bifurcations from the CFTG
2387 
2388   //go over list of Links and find any with degree > 1
2389   //these need to be disambiguated (gradient descent)
2390   std::list<sdet_CFTG_link*> GD_list;
2391 
2392   //populate the map
2393   l_it = curve_frag_graph_.CFTG.Links.begin();
2394   for (; l_it != curve_frag_graph_.CFTG.Links.end(); l_it++)
2395   {
2396     //compute degree at each end
2397     int deg_S = curve_frag_graph_.CFTG.cLinks[(*l_it)->eS->id].size() + curve_frag_graph_.CFTG.pLinks[(*l_it)->eS->id].size();
2398     int deg_E = curve_frag_graph_.CFTG.cLinks[(*l_it)->eE->id].size() + curve_frag_graph_.CFTG.pLinks[(*l_it)->eE->id].size();
2399 
2400     if (deg_S>1){
2401       GD_list.push_back(*l_it);
2402       continue;
2403     }
2404 
2405     if (deg_E>1){
2406       GD_list.push_back(*l_it);
2407       continue;
2408     }
2409 
2410   }
2411 
2412 
2413   //sort the cost list
2414   GD_list.sort(link_cost_less);
2415 
2416   //gradient descent
2417   while (GD_list.size()>0)
2418   {
2419     sdet_CFTG_link* cur_Link = GD_list.front();
2420     GD_list.pop_front();
2421 
2422     //now remove the other links connected to the end points of this link
2423     //clinks from eS
2424     std::vector<sdet_CFTG_link*> links_to_del;
2425     l_it = curve_frag_graph_.CFTG.cLinks[cur_Link->eS->id].begin();
2426     for (; l_it != curve_frag_graph_.CFTG.cLinks[cur_Link->eS->id].end(); l_it++){
2427 
2428       if ((*l_it) != cur_Link)
2429     links_to_del.push_back((*l_it));
2430     }
2431 
2432     //by yuliang, also consider plinks from eS
2433     l_it = curve_frag_graph_.CFTG.pLinks[cur_Link->eS->id].begin();
2434     for (; l_it != curve_frag_graph_.CFTG.pLinks[cur_Link->eS->id].end(); l_it++){
2435 
2436       if ((*l_it) != cur_Link)
2437         links_to_del.push_back((*l_it));
2438     }
2439 
2440     for (auto & j : links_to_del){
2441       GD_list.remove(j);//also remove it from the GD list
2442       curve_frag_graph_.CFTG.remove_link(j);
2443     }
2444     links_to_del.clear();
2445 
2446     //plinks from eE
2447     l_it = curve_frag_graph_.CFTG.pLinks[cur_Link->eE->id].begin();
2448     for (; l_it != curve_frag_graph_.CFTG.pLinks[cur_Link->eE->id].end(); l_it++){
2449 
2450       if ((*l_it) != cur_Link)
2451         links_to_del.push_back((*l_it));
2452     }
2453 
2454     //by yuliang, also consider clinks from eE
2455     l_it = curve_frag_graph_.CFTG.cLinks[cur_Link->eE->id].begin();
2456     for (; l_it != curve_frag_graph_.CFTG.cLinks[cur_Link->eE->id].end(); l_it++){
2457 
2458       if ((*l_it) != cur_Link)
2459         links_to_del.push_back((*l_it));
2460     }
2461 
2462     for (auto & j : links_to_del){
2463       GD_list.remove(j);//also remove it from the GD list
2464       curve_frag_graph_.CFTG.remove_link(j);
2465     }
2466     links_to_del.clear();
2467   }
2468 
2469   //D) Add it all back to the CFG (clear the CFTG in the process)
2470   l_it = curve_frag_graph_.CFTG.Links.begin();
2471   for (; l_it != curve_frag_graph_.CFTG.Links.end(); l_it++)
2472   {
2473     if ((*l_it)->cCFs.size()==1)
2474       curve_frag_graph_.insert_fragment((*l_it)->cCFs.front());
2475   }
2476   curve_frag_graph_.CFTG.clear();
2477   curve_frag_graph_.CFTG.resize(edgemap_->edgels.size());
2478    std::cout<<"Finish disambiguating the CFTG"<<std::endl;
2479 }
2480 
2481 // Following part by Yuliang Guo.
2482 static bool is_continue (const sdet_edgel_chain *c1, const sdet_edgel_chain *c2); // test genenal/local continuity
2483 
is_longer(const sdet_edgel_chain * c1,const sdet_edgel_chain * c2)2484 static bool is_longer (const sdet_edgel_chain *c1, const sdet_edgel_chain *c2){ // whether contour 1 is longer
2485     if (c1->edgels.size()>c2->edgels.size()){
2486         return true;
2487     }
2488     return false;
2489 
2490 }
2491 
2492 static double get_continuity (const sdet_edgel_chain *c1, const sdet_edgel_chain *c2);
2493 //: correct the CFG topology to produce a disjoint set
2494 
2495 
correct_CFG_topology()2496 void sdet_sel_base::correct_CFG_topology()
2497 {
2498   //D) Final T-junction type disambiguation can be done on the CFG
2499   // Basically, go over all the nodes of the CFG and operate on the ones with degree>2
2500   // also merge all segments that are adjacent
2501 
2502   // going over the edgemap instead so that a node is visited only once and so that I
2503   // don't have to deal with iterator issues
2504 
2505   for (unsigned int i=0; i<edgemap_->edgels.size(); ++i)
2506   {
2507     sdet_edgel_chain *c1=nullptr, *c2=nullptr;
2508 
2509     int deg = curve_frag_graph_.pFrags[i].size()+ curve_frag_graph_.cFrags[i].size();
2510     if (deg<2)
2511       continue; //nodes
2512 
2513     if (deg==2){ //degree 2 segments will trigger a splice
2514 
2515       //standard operation: extract them from the graph, reorder them, either merge or put them back
2516 
2517       //segments need to meet continuity criteria (simple one for now)
2518       if (curve_frag_graph_.pFrags[i].size()>1){
2519         auto fit = curve_frag_graph_.pFrags[i].begin();
2520         c1 =  (*fit); fit++;
2521         c2 =  (*fit);
2522 
2523         curve_frag_graph_.extract_fragment(c1);
2524         curve_frag_graph_.extract_fragment(c2);
2525 
2526         //reverse the sequence of edgels
2527         std::reverse(c2->edgels.begin(), c2->edgels.end());
2528         curve_frag_graph_.insert_fragment(c1);
2529         curve_frag_graph_.insert_fragment(c2);
2530       }
2531       else if (curve_frag_graph_.pFrags[i].size()==1){
2532         c1 =  curve_frag_graph_.pFrags[i].front();
2533         c2 =  curve_frag_graph_.cFrags[i].front();
2534     //for the closed contour case
2535     if(c1==c2)
2536         continue;
2537       }
2538       else {
2539         auto fit = curve_frag_graph_.cFrags[i].begin();
2540         c1 =  (*fit); fit++;
2541         c2 =  (*fit);
2542 
2543         //add the second one to the first one and delete it from the graph
2544         curve_frag_graph_.extract_fragment(c1);
2545         curve_frag_graph_.extract_fragment(c2);
2546 
2547         //reverse the sequence of edgels
2548         std::reverse(c1->edgels.begin(), c1->edgels.end());
2549         curve_frag_graph_.insert_fragment(c1);
2550         curve_frag_graph_.insert_fragment(c2);
2551       }
2552 
2553       if (is_continue(c1,c2)){ //if two contours are generally/local continue based on a frag
2554         //merge the two contours
2555             curve_frag_graph_.extract_fragment(c1);
2556         curve_frag_graph_.extract_fragment(c2);
2557         c1->append(c2->edgels);
2558         curve_frag_graph_.insert_fragment(c1);
2559     //when it makes a closed contour, just count as the child frag rather than parent frag
2560         if(c1->edgels.front()==c1->edgels.back())
2561         curve_frag_graph_.pFrags[c1->edgels.front()->id].remove(c1);
2562         delete c2;
2563       }
2564      }
2565   }
2566 
2567   // deal with junction with another loop after dealing with deg 2
2568 
2569   for (unsigned i=0; i<edgemap_->edgels.size(); i++)
2570   {
2571     sdet_edgel_chain *c1=nullptr, *c2=nullptr;
2572     sdet_edgel* eA = edgemap_->edgels[i];
2573 
2574     int deg = curve_frag_graph_.pFrags[i].size()+ curve_frag_graph_.cFrags[i].size();
2575     //degree 3 is a junction (T-junction or Y-junction)
2576     if (deg>2) //  Make length of contour as the first priority
2577     {
2578         //goal is to see if any two will produce smooth continuation
2579     sdet_edgel_chain_list node_frags;
2580         if(curve_frag_graph_.pFrags[i].size()!=0){
2581         auto p_fit = curve_frag_graph_.pFrags[i].begin();
2582             for(;p_fit!=curve_frag_graph_.pFrags[i].end();p_fit++)
2583         {
2584             node_frags.push_back(*p_fit);
2585         }
2586     }
2587 
2588         if(curve_frag_graph_.cFrags[i].size()!=0){
2589         auto c_fit = curve_frag_graph_.cFrags[i].begin();
2590             for(;c_fit!=curve_frag_graph_.cFrags[i].end();c_fit++)
2591         {
2592             node_frags.push_back(*c_fit);
2593         }
2594     }
2595 
2596     node_frags.sort(is_longer); //sort all the pfrags and cfrags in length
2597 
2598         //compare each pair to decide merge or not
2599         auto fit_1=node_frags.begin();
2600     for (;fit_1!=--node_frags.end();){
2601         c1= *fit_1;
2602 
2603         if(c1->edgels.back()!= eA){
2604             curve_frag_graph_.extract_fragment(c1);
2605             std::reverse(c1->edgels.begin(), c1->edgels.end());
2606             curve_frag_graph_.insert_fragment(c1);
2607         }
2608         fit_1++;
2609         auto fit_2 = fit_1, max_fit = fit_1;
2610         double max_SM = 0;
2611         for (;fit_2!=node_frags.end();fit_2++){
2612             c2=*fit_2;
2613             if(c2->edgels.back()== eA){
2614                 curve_frag_graph_.extract_fragment(c2);
2615                 std::reverse(c2->edgels.begin(), c2->edgels.end());
2616                 curve_frag_graph_.insert_fragment(c2);
2617             }
2618 
2619             double SM_0 = get_continuity(c1,c2);
2620             if(SM_0>max_SM){
2621                 max_SM = SM_0;
2622                 max_fit = fit_2;
2623             }
2624         }
2625         if(max_SM>=0.9){
2626             c2=*max_fit;
2627             curve_frag_graph_.extract_fragment(c1);
2628             curve_frag_graph_.extract_fragment(c2);
2629             c1->append(c2->edgels);
2630             curve_frag_graph_.insert_fragment(c1);
2631             break;
2632         }
2633 
2634         //if(fit_2!=node_frags.end())
2635         //    break;
2636         }
2637     }
2638   }
2639     // use the filter to prun out local problems again
2640     regular_contour_filter();
2641     std::cout<<"Finish correcting the CFG topology"<<std::endl;
2642 }
2643 
2644 //20th June, 2012:: New Merging of Contours Decision Making by Naman Kumar,function to test whether two contours are continuous
is_continue(const sdet_edgel_chain * c1,const sdet_edgel_chain * c2)2645 static bool is_continue (const sdet_edgel_chain *c1, const sdet_edgel_chain *c2)
2646 {
2647          sdet_edgel* e1;sdet_edgel* e4;
2648         sdet_edgel* e2 = c1->edgels.back();
2649         sdet_edgel* e3 = c2->edgels.front();
2650         double dx1=0,dy1=0,dy2=0,dx2=0,s1=0,s2=0,s=0,SM_1=0;
2651         int j=0;
2652         for(int i=c1->edgels.size()-2;i>=0;i--)
2653         {
2654                 e1 = c1->edgels[i];
2655                     j++;
2656                     if(j==c2->edgels.size()) break;
2657                 e4 = c2->edgels[j];
2658                 dx1 = e2->pt.x()-e1->pt.x();
2659                 dy1 = e2->pt.y()-e1->pt.y();
2660                 dx2 = e4->pt.x()-e3->pt.x();
2661                 dy2 = e4->pt.y()-e3->pt.y();
2662                 s1+=(e1)->strength;
2663                 s2+=(e4)->strength;
2664                 s=std::fabs((s1-s2)/j);
2665                 SM_1 = (dx1*dx2 + dy1*dy2)/std::sqrt(dx1*dx1+dy1*dy1)/std::sqrt(dx2*dx2+dy2*dy2);
2666                 if(SM_1>=Theta_1 || s<=Strength_Diff1) return true;
2667                 else if(SM_1<Theta_2 || s>Strength_Diff2) return false;
2668                 else continue;
2669         }
2670             return false;
2671 }
2672 
get_continuity(const sdet_edgel_chain * c1,const sdet_edgel_chain * c2)2673 static double get_continuity (const sdet_edgel_chain *c1, const sdet_edgel_chain *c2)
2674 {
2675         // using the median global continuity
2676         sdet_edgel* e1=nullptr;
2677         sdet_edgel* e2=nullptr;
2678         sdet_edgel* e3=nullptr;
2679         sdet_edgel* e4=nullptr;
2680         if(c1->edgels.size()>=5){
2681             e1 = c1->edgels[c1->edgels.size()-5];
2682             e2 = c1->edgels.back();
2683         }
2684         else{
2685             e1 = c1->edgels.front();
2686             e2 = c1->edgels.back();
2687         }
2688         if(c2->edgels.size()>=5){
2689             e3 = c2->edgels.front();
2690             e4 = c2->edgels[4];
2691         }
2692         else{
2693             e3 = c2->edgels.front();
2694             e4 = c2->edgels.back();
2695         }
2696         double dx1 = e2->pt.x()-e1->pt.x();
2697         double dy1 = e2->pt.y()-e1->pt.y();
2698         double dx2 = e4->pt.x()-e3->pt.x();
2699         double dy2 = e4->pt.y()-e3->pt.y();
2700         return (dx1*dx2 + dy1*dy2)/std::sqrt(dx1*dx1+dy1*dy1)/std::sqrt(dx2*dx2+dy2*dy2);
2701 }
2702 
share_same_ends(sdet_edgel_chain * c1,sdet_edgel_chain * c2)2703 static bool share_same_ends(sdet_edgel_chain *c1, sdet_edgel_chain *c2)
2704 {
2705     if((c1->edgels.front()==c2->edgels.front()&&c1->edgels.back()==c2->edgels.back())
2706         || (c1->edgels.front()==c2->edgels.back()&&c1->edgels.back()==c2->edgels.front()))
2707         return true;
2708     return false;
2709 }
2710 
2711 
2712 
regular_contour_filter()2713 void sdet_sel_base::regular_contour_filter(){
2714 // first, deal with contours with length 3, which cause a lot of local problems
2715     sdet_edgel_chain_list Size_3_chain_list;
2716     auto fit = curve_frag_graph_.frags.begin();
2717     for(;fit!=curve_frag_graph_.frags.end();fit++)
2718     {
2719         sdet_edgel_chain *c1=*fit;
2720     // (a) for size 4 frags, git rid of the small closed triangle
2721     if(c1->edgels.size()==4 && (c1->edgels.front()==c1->edgels.back()))
2722     {
2723         c1->edgels.pop_back();
2724         curve_frag_graph_.pFrags[c1->edgels.back()->id].push_back(c1);
2725     }
2726     // push size 3 frags's pointer into a seperate list to same computation for next step
2727     if(c1->edgels.size()==3)
2728         Size_3_chain_list.push_back(c1);
2729     }
2730 
2731 
2732     auto fit_1 = Size_3_chain_list.begin();
2733     while(fit_1!=Size_3_chain_list.end())
2734     {
2735         // (b) change 3 edgels sharp path to be a direct line link
2736     sdet_edgel_chain *c1=*fit_1;
2737     double dx1 = c1->edgels[1]->pt.x() - c1->edgels.front()->pt.x();
2738     double dy1 = c1->edgels[1]->pt.y() - c1->edgels.front()->pt.y();
2739     double dx2 = c1->edgels.back()->pt.x() - c1->edgels[1]->pt.x();
2740     double dy2 = c1->edgels.back()->pt.y() - c1->edgels[1]->pt.y();
2741     double SM = (dx1*dx2 + dy1*dy2)/std::sqrt(dx1*dx1+dy1*dy1)/std::sqrt(dx2*dx2+dy2*dy2);
2742     double length = std::sqrt(dx1*dx1+dy1*dy1) + std::sqrt(dx2*dx2+dy2*dy2);
2743     if(length>10)// only consider local problems
2744         continue;
2745     if(SM<=0)
2746     {
2747         auto eit = c1->edgels.begin();
2748         eit++;
2749         c1->edgels.erase(eit);
2750     }
2751     // (c) if two frags share same end nodes, change them into one direct line link
2752     auto fit_2 = ++fit_1;
2753     while(fit_2!=Size_3_chain_list.end())
2754     {
2755         sdet_edgel_chain *c2=*fit_2;
2756         if(share_same_ends(c1, c2))
2757         {
2758             // check if c1 is modifid in (b), if no, change it to a direct line link
2759             if(c1->edgels.size()==3)
2760             {
2761                 auto eit = c1->edgels.begin();
2762                 eit++;
2763                 c1->edgels.erase(eit);
2764             }
2765             // remove c2 from CFG
2766             curve_frag_graph_.extract_fragment(c2);
2767             // only deal with one frag has same ends, if there are more, leave for iterations afterward
2768             break;
2769         }
2770         fit_2++;
2771     }
2772     }
2773 }
2774 
2775 
2776 //New construction of Hypothesis Tree by Naman Kumar
Construct_Hypothesis_Tree()2777 void sdet_sel_base::Construct_Hypothesis_Tree()
2778 {
2779   regular_contour_filter();
2780   int n1=0;
2781   std::vector<sdet_edgel*> new_chain0,new_chain2,new_chain3,new_chain6,new_chain33;
2782   auto* new_chain1=new sdet_edgel_chain();
2783   auto* new_chain4=new sdet_edgel_chain();
2784   double gap_thres=gap_;
2785   std::cout << "Construction of Hypothesis Tree is in Progress!! " << std::endl;
2786   // Calculating number of edges with degree as 1
2787   for (auto eA1 : edgemap_->edgels)
2788     {
2789     new_chain0.push_back(eA1);
2790     if ((curve_frag_graph_.pFrags[eA1->id].size() + curve_frag_graph_.cFrags[eA1->id].size()) ==1)
2791       new_chain1->edgels.push_back(eA1);
2792     else new_chain2.push_back(eA1);
2793     }
2794 
2795     //Calculating number of edges which are part of the contours and which are unused
2796     auto fit = curve_frag_graph_.frags.begin();
2797     for (; fit!=curve_frag_graph_.frags.end(); ++fit)
2798       {
2799       sdet_edgel_chain *test1=*fit;
2800       for (auto edgel : test1->edgels)
2801         {
2802         new_chain3.push_back(edgel);new_chain33.push_back(edgel);
2803         }
2804       }
2805 
2806       for (auto & i : new_chain0)
2807         {
2808         for (auto & j : new_chain3)
2809           {
2810           if(i!=j) continue;
2811           else
2812             {
2813             n1=5;
2814             break;
2815             }
2816           }
2817           if (n1==0)
2818             {
2819             new_chain4->edgels.push_back(i);
2820             }
2821           else
2822             {
2823             n1=0;
2824             continue;
2825             }
2826         }
2827         //Constucting the tree from end of an unambiguous chain and extending it till the end of edge chain
2828       double cost2=10.0, d1=0.0,dx=0.0,dy=0.0,cost=1000.0,costc=0.0;
2829       int m1=0,m2=0,m3=0,m4=0,m5=0,m7=0,m8=0,m9=0;
2830       sdet_edgel* ce=nullptr;sdet_edgel* pe=nullptr;sdet_edgel* ed=nullptr;sdet_edgel* imp=nullptr;sdet_edgel* im=nullptr;
2831       auto *c11=new sdet_edgel_chain();
2832       auto* xx=new sdet_edgel_chain();
2833       auto* end=new sdet_edgel_chain();
2834       while(new_chain1->edgels.size()>0)
2835         {
2836         a: ;
2837         if (0 == new_chain1->edgels.size()) break;
2838         ed=new_chain1->edgels[0];
2839         new_chain1->edgels.pop_front();
2840         for (auto & edgel : end->edgels)
2841           {
2842           if (ed==edgel) goto a;
2843           else continue;
2844           }
2845           auto* new_chain5 = new sdet_edgel_chain();
2846           new_chain5->edgels.push_back(ed);xx->edgels.push_back(ed);
2847           m4=0;m7=0;
2848           double dis=0, distance=0;
2849           //Forming the tree from the edge
2850           while (true)
2851             {
2852             auto eit1=new_chain4->edgels.begin();
2853             auto eit2=new_chain4->edgels.begin();
2854             if (m4==0)
2855               {
2856               if (1 == curve_frag_graph_.cFrags[ed->id].size())
2857                 {
2858                 auto ccit = curve_frag_graph_.cFrags[ed->id].begin();
2859                 ce = (*ccit)->edgels[1];c11=*ccit;pe=ce;m7=1;
2860                 for (unsigned int j=1; j<c11->edgels.size(); ++j)
2861                   {
2862                   dis=vgl_distance(c11->edgels[j]->pt,c11->edgels[j-1]->pt);
2863                   if (dis>distance) distance=dis;
2864                   }
2865                 distance=distance + 0.25;
2866                 if (distance <=1) gap_=1;
2867                 else if (distance <gap_thres) gap_=distance;
2868                 else gap_=gap_thres;
2869                 }
2870               else if (1 == curve_frag_graph_.pFrags[ed->id].size())
2871                 {
2872                 auto pcit = curve_frag_graph_.pFrags[ed->id].begin();
2873                 ce = (*pcit)->edgels[(*pcit)->edgels.size()-2];
2874                 c11=*pcit;
2875                 pe=ce;
2876                 m7=2;
2877                 for (unsigned int j=1; j<c11->edgels.size(); ++j)
2878                    {
2879                    dis=vgl_distance(c11->edgels[j]->pt,c11->edgels[j-1]->pt);
2880                    if (dis>distance) distance=dis;
2881                    }
2882                 distance=distance + 0.25;
2883                 if (distance <=1) gap_=1;
2884                 else if (distance <gap_thres) gap_=distance;
2885                 else gap_=gap_thres;
2886                 }
2887               m4=1;
2888               }
2889               // Used later
2890               if (m7==2)
2891                 {
2892                 m8=c11->edgels.size()-5;
2893                 if (m8<0) m8=0;
2894                 m9=c11->edgels.size();
2895                 }
2896               else if(m7==1)
2897                 {
2898                 m8=0;
2899                 m9=5;
2900                 if (m9>static_cast<int>(c11->edgels.size()))
2901                   m9=c11->edgels.size();
2902                 }
2903               // Finding the closest unused edge
2904               cost=10000.0;
2905               double cost1=gap_;
2906               for (auto & edgel : new_chain4->edgels)
2907                 {
2908                 d1= vgl_distance(ed->pt,edgel->pt);
2909                 //Checking Localization, Orientation,etc..
2910                 if (d1<cost1)
2911                   {
2912                   std::vector<sdet_edgel*> dummy_chain;
2913                   auto* edgel_chain = new sdet_edgel_chain();
2914                   for (auto i : new_chain5->edgels)
2915                     edgel_chain->edgels.push_back(i);
2916                   edgel_chain->edgels.push_back(edgel);
2917                   std::vector<sdet_edgel*> chain(edgel_chain->edgels.begin(),edgel_chain->edgels.end());
2918                   costc = compute_path_metric2(dummy_chain, chain, dummy_chain);
2919                   if (costc<cost)
2920                     {
2921                     double d8=vgl_distance(edgel->pt,ce->pt);
2922                     double d9=vgl_distance(edgel->pt,ed->pt);
2923                     double d0=vgl_distance(edgel->pt,pe->pt);
2924                     double dx1 = ce->pt.x() - ed->pt.x();
2925                     double dy1 = ce->pt.y() - ed->pt.y();
2926                     double dx2 = ed->pt.x() - edgel->pt.x();
2927                     double dy2 = ed->pt.y() - edgel->pt.y();
2928                     double angle=((dx1*dx2 + dy1*dy2)/std::sqrt(dx1*dx1+dy1*dy1)/std::sqrt(dx2*dx2+dy2*dy2));
2929                     if (d0<d9)
2930                       {
2931                       ++eit1;
2932                       continue;
2933                       }
2934                     if (d8<d9 || angle<0)
2935                       {
2936                       ++eit1;
2937                       continue;
2938                       }
2939                     imp=edgel;
2940                     cost=costc;
2941                     m1=1;
2942                     eit2=eit1;
2943                     }
2944                   }
2945                 else if (d1<cost2 && d1>1)
2946                   {
2947                   cost2=d1;
2948                   }
2949                 ++eit1;
2950                 }
2951 
2952               m3=0;m5=0;
2953               double cost3=gap_;
2954               // Finding the closest edge which is part of a fragment
2955               for (auto & t : new_chain3)
2956                 {
2957                 if (t==ed || t==ce) continue;
2958                 d1 = vgl_distance(ed->pt,t->pt);
2959                 if (d1<=cost3)
2960                   {
2961                   //Dont consider the previous 5 edges present in parent/child fragment of the starting edge
2962                   for (int c=m8;c<m9;c++)
2963                     {
2964                     if (t==c11->edgels[c]) goto z;
2965                     else continue;
2966                     }
2967                   //Dont use the edge which is part of the same tree again
2968                   for (auto & edgel : new_chain5->edgels)
2969                     {
2970                     if (t==edgel) goto z;
2971                     else continue;
2972                     }
2973                   im=t;
2974                   cost3=d1;m5=1;
2975                   dx=vgl_distance(im->pt,ce->pt);
2976                   dy=vgl_distance(im->pt,ed->pt);
2977                   }
2978                 z: ;
2979                 }
2980               if (dx>dy && m5==1)
2981                 {
2982                 m3=5;
2983                 m1=1;
2984                 imp=im;
2985                 }
2986               if (m1==1)
2987                 {
2988                 m2=1;
2989                 m1=0;
2990                 ce=ed;
2991                 ed=imp;
2992                 xx->edgels.push_back(imp);
2993                 new_chain5->edgels.push_back(imp);
2994                 if (m3==0)
2995                   {
2996                   new_chain4->edgels.erase(eit2);
2997                   new_chain3.push_back(imp);
2998                   new_chain33.push_back(imp);
2999                   }
3000                 if (m3!=0)
3001                   {
3002                   break;
3003                   }
3004                 }
3005               else if (cost2>1) break;
3006             }
3007           //No double contours within the same 2 end points.
3008           if (m2==1)
3009             {
3010             if (c11->edgels.front()==c11->edgels.back()) continue;
3011             }
3012           //Add the tree
3013           new_chain5->temp = true;
3014           curve_frag_graph_.CFTG.insert_fragment(new_chain5);
3015           end->edgels.push_back(new_chain5->edgels.back());
3016 
3017         }
3018         sdet_edgel* edge1=nullptr;
3019         sdet_edgel* edge2=nullptr;
3020         auto *chain1=new sdet_edgel_chain();
3021         std::list<sdet_CFTG_link*> GD_list;
3022         double p1=1.0;
3023         int p2=0,p3=0,p16=0;
3024         auto l_it = curve_frag_graph_.CFTG.Links.begin();
3025         for (; l_it != curve_frag_graph_.CFTG.Links.end(); ++l_it)
3026           GD_list.push_back(*l_it);
3027         while (GD_list.size()>0)
3028           {
3029           sdet_CFTG_link* cur_Link = GD_list.front();
3030           GD_list.pop_front();
3031           auto f_it = cur_Link->cCFs.begin();
3032           sdet_edgel_chain* new_chain5=(*f_it);
3033           sdet_edgel* edge3=new_chain5->edgels.front();
3034           gap_=1;
3035           for (unsigned int i=0; i<new_chain5->edgels.size(); ++i)
3036             {
3037             p1=gap_;
3038             auto eit5=new_chain4->edgels.begin();
3039             auto eit6=new_chain4->edgels.begin();
3040             for (auto & edgel : new_chain4->edgels)
3041               {
3042               double p4=vgl_distance(new_chain5->edgels[i]->pt,edgel->pt);
3043               if (p4<p1)
3044                 {
3045                 edge1=edgel;
3046                 p1=p4;
3047                 p2=1;
3048                 eit6=eit5;
3049                 ++eit5;
3050                 }
3051               else
3052                 {
3053                 ++eit5;
3054                 continue;
3055                 }
3056               }
3057             if (p2==1)
3058               {
3059               new_chain4->edgels.erase(eit6);
3060               sdet_edgel* edge4=nullptr;p2=0;double p5=gap_;
3061               for (auto & edgel : new_chain5->edgels)
3062                 {
3063                 double p6=vgl_distance(edge1->pt,edgel->pt);
3064                 if (p6<p5)
3065                   {
3066                   edge2=edgel;
3067                   p5=p6;
3068                   }
3069                 else continue;
3070                 }
3071                 auto *new_chain6a = new sdet_edgel_chain();
3072                 new_chain6a->edgels.push_back(edge2); new_chain6a->edgels.push_back(edge1);
3073                 int p7=0,p8=0,p9=0;
3074                 if (curve_frag_graph_.cFrags[edge3->id].size()>=1)
3075                   {
3076                   auto ccit = curve_frag_graph_.cFrags[edge3->id].begin();
3077                   chain1=(*ccit);
3078                   p7=1;
3079                   }
3080                 else if (curve_frag_graph_.pFrags[edge3->id].size()>=1)
3081                   {
3082                   auto pcit = curve_frag_graph_.pFrags[edge3->id].begin();
3083                   chain1=(*pcit);
3084                   p7=2;
3085                   }
3086                 if (p7==2)
3087                   {
3088                   p8=chain1->edgels.size()-5;
3089                   if (p8<0) p8=0;
3090                   p9=chain1->edgels.size();
3091                   }
3092                 else if (p7==1)
3093                   {
3094                   p8=0;
3095                   p9=5;
3096                   if (p9>static_cast<int>(chain1->edgels.size())) p9=chain1->edgels.size();
3097                   }
3098                 while (true)
3099                   {
3100                   double p10=gap_,p11=0.0;
3101                   auto eit3=new_chain4->edgels.begin();auto eit4=new_chain4->edgels.begin();
3102                   for (auto & edgel : new_chain4->edgels)
3103                     {
3104                     p11= vgl_distance(edge1->pt,edgel->pt);
3105                     if (p11<p10)
3106                       {
3107                       double d8=vgl_distance(edgel->pt,edge2->pt);
3108                       double d9=vgl_distance(edgel->pt,edge1->pt);
3109                       double dx1 = edge1->pt.x() - edge2->pt.x(), dy1 = edge1->pt.y() - edge2->pt.y();
3110                       double dx2=edgel->pt.x()-edge1->pt.x();
3111                       double dy2=edgel->pt.y()-edge1->pt.y();
3112                       if (d8<d9 || ((dx1*dx2 + dy1*dy2)/std::sqrt(dx1*dx1+dy1*dy1)/std::sqrt(dx2*dx2+dy2*dy2))<0.4)
3113                         {
3114                         ++eit3;
3115                         continue;
3116                         }
3117                       p10=p11;edge4=edgel;eit4=eit3;p2=1;
3118                       }
3119                     ++eit3;
3120                     }
3121                     double p12=gap_,p13=0,p14=0.0,p15=0.0;p16=0;sdet_edgel* edge5=nullptr;
3122                     for (auto & t : new_chain3)
3123                       {
3124                       if (t==edge1) continue;
3125                       p13= vgl_distance(edge1->pt,t->pt);
3126                       if (p13<=p12)
3127                         {
3128                         for (int c=p8; c<p9; ++c)
3129                           {
3130                           if (t==chain1->edgels[c])
3131                             goto jump;
3132                           else continue;
3133                           }
3134                         for (auto & edgel : new_chain5->edgels)
3135                           {
3136                           if (t==edgel) goto jump;
3137                           else continue;
3138                           }
3139                         for (auto & edgel : new_chain6a->edgels)
3140                           {
3141                           if (t==edgel) goto jump;
3142                           else continue;
3143                           }
3144                         edge5=t;p12=p13;p14=vgl_distance(edge5->pt,edge2->pt);
3145                         p15=vgl_distance(edge5->pt,edge1->pt);
3146                         p16=1;
3147                         }
3148                         jump: ;
3149                       }
3150                     if (p14>p15 && p16==1)
3151                       {
3152                       edge4=edge5;
3153                       p2=1;
3154                       }
3155                     if (p2==1)
3156                       {
3157                       new_chain6a->edgels.push_back(edge4);p3=1;p2=0;
3158                       if (p16==0)
3159                         {
3160                         new_chain4->edgels.erase(eit4);
3161                         new_chain3.push_back(edge4);
3162                         edge2=edge1;
3163                         edge1=edge4;
3164                         }
3165                       else break;
3166                       }
3167                     else break;
3168                   }
3169                 double p17=0,p18=0,p21=0;
3170                 if (p3==1 && new_chain6a->edgels.size()>5)
3171                   {
3172                   sdet_edgel* edge6=new_chain6a->edgels[new_chain6a->edgels.size()/2];
3173                   for (auto & i : new_chain33)
3174                     {
3175                     p18=vgl_distance(edge6->pt,i->pt);
3176                     if (p18<1) p21=10;
3177                     if (p21==10)
3178                       {
3179                       p17=1;
3180                       break;
3181                       }
3182                     }
3183                   if (p17==0)
3184                     {
3185                     new_chain6a->temp = true;
3186                     curve_frag_graph_.CFTG.insert_fragment(new_chain6a);
3187                     }
3188                   p2=0;
3189                   p3=0;
3190                   }
3191               }
3192             }
3193           }
3194           std::cout << "Hypothesis Tree Constructed!!" << std::endl;
3195 }
3196 
3197 // New Disambiguation Process by Naman Kumar
Disambiguation()3198 void sdet_sel_base::Disambiguation()
3199 {
3200         std::cout << "Disambiguating the Hypothesis Tree!!" << std::endl;
3201         auto l_it = curve_frag_graph_.CFTG.Links.begin();
3202         for (; l_it != curve_frag_graph_.CFTG.Links.end(); l_it++)
3203         {
3204                 double cost=0.0;
3205                 int deg_S = curve_frag_graph_.CFTG.cLinks[(*l_it)->eS->id].size() + curve_frag_graph_.CFTG.pLinks[(*l_it)->eS->id].size();
3206                 sdet_CFTG_link* cur_Link = (*l_it);
3207                 //Calculating Cost
3208                 std::vector<sdet_edgel*> dummy_chain;
3209                 sdet_edgel_chain* edgel_chain = cur_Link->cCFs.front();
3210                 std::vector<sdet_edgel*> chain(edgel_chain->edgels.begin(),edgel_chain->edgels.end());
3211                  cost = compute_path_metric2(dummy_chain, chain, dummy_chain);
3212                 //Degree=1
3213                 if(deg_S==1) {curve_frag_graph_.insert_fragment((*l_it)->cCFs.front()); continue;}
3214                 //Degree>1
3215                 // To fill small gaps in closed contours
3216                 if((curve_frag_graph_.pFrags[edgel_chain->edgels.front()->id].size()+curve_frag_graph_.cFrags[edgel_chain->edgels.front()->id].size())==1                            &&(curve_frag_graph_.pFrags[edgel_chain->edgels.back()->id].size()+curve_frag_graph_.cFrags[edgel_chain->edgels.back()->id].size())==1                         && edgel_chain->edgels.size()==2) curve_frag_graph_.insert_fragment(edgel_chain);
3217                 if(cost<1.0 && edgel_chain->edgels.size()>2) curve_frag_graph_.insert_fragment(edgel_chain);
3218         }
3219         //clear the graph
3220         curve_frag_graph_.CFTG.clear();
3221         curve_frag_graph_.CFTG.resize(edgemap_->edgels.size());
3222 }
3223 
3224 // By Naman Kumar: a minor function just to prune some extra small part of contours
Post_Process()3225 void sdet_sel_base::Post_Process()
3226 {
3227 
3228         auto* new_chain= new sdet_edgel_chain();
3229         for (auto eA1 : edgemap_->edgels)
3230             {
3231                 if ((curve_frag_graph_.pFrags[eA1->id].size() + curve_frag_graph_.cFrags[eA1->id].size()) ==1) new_chain->edgels.push_back(eA1);
3232             }
3233             for (auto edge : new_chain->edgels)
3234               {
3235               sdet_edgel* edge2=nullptr;auto* chain= new sdet_edgel_chain();sdet_edgel* edge3=nullptr;
3236               int n=0,number=0,diff=0;
3237               if (curve_frag_graph_.cFrags[edge->id].size()==1)
3238                 {
3239                 n=1;
3240                 auto ccit = curve_frag_graph_.cFrags[edge->id].begin();
3241                 chain=*ccit;
3242                 edge2 = chain->edgels[1];
3243                 if (chain->edgels.size()>2)
3244                   {
3245                   number=1;
3246                   edge3=chain->edgels[2];
3247                   }
3248                 diff=1;
3249                 }
3250               else if(curve_frag_graph_.pFrags[edge->id].size()==1)
3251                 {
3252                 n=1;auto pcit = curve_frag_graph_.pFrags[edge->id].begin();chain=*pcit;
3253                 edge2 = chain->edgels[chain->edgels.size()-2];
3254                 if (chain->edgels.size()>2)
3255                   {
3256                   number=1;
3257                   edge3=chain->edgels[chain->edgels.size()-3];
3258                   }
3259                 diff=2;
3260                 }
3261                 auto fit = curve_frag_graph_.frags.begin();
3262                 for (;fit!=curve_frag_graph_.frags.end();++fit)
3263                   {
3264                   sdet_edgel_chain *test1=*fit;
3265                   if (test1==chain) continue;
3266                   for (auto & edgel : test1->edgels)
3267                     {
3268                     if (edge==edgel) goto end;
3269                     }
3270                   }
3271                 if (n==1 && chain->edgels.size()>1 && ((curve_frag_graph_.pFrags[edge2->id].size() + curve_frag_graph_.cFrags[edge2->id].size()) >=1))
3272                   {
3273                   curve_frag_graph_.extract_fragment(chain);
3274                   if (diff==1)
3275                     chain->edgels.pop_front();
3276                   else if (diff==2)
3277                     chain->edgels.pop_back();
3278                   curve_frag_graph_.insert_fragment(chain);
3279                   }
3280                 else if(number==1 && chain->edgels.size()>1 && ((curve_frag_graph_.pFrags[edge3->id].size()+curve_frag_graph_.cFrags[edge3->id].size()) >=1))
3281                   {
3282                   curve_frag_graph_.extract_fragment(chain);
3283                   if (diff==1)
3284                     {
3285                     chain->edgels.pop_front();
3286                     chain->edgels.pop_front();
3287                     }
3288                   else if (diff==2)
3289                     {
3290                     chain->edgels.pop_back();
3291                     chain->edgels.pop_back();
3292                     }
3293                   curve_frag_graph_.insert_fragment(chain);
3294                   }
3295                 end: ;
3296               }
3297 }
3298