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