1 #include <algorithm>
2 #include <cmath>
3 #include <fstream>
4 #include <iostream>
5 #include <set>
6 #include <sstream>
7
8 #include "acal_match_graph.h"
9 #include "vul/vul_file.h"
10
11
12 // --------------------
13 // match_vertex
14 // --------------------
15
16 // edge ids connected to vertex
17 std::vector<size_t>
edge_ids() const18 match_vertex::edge_ids() const
19 {
20 std::vector<size_t> ids;
21 for (auto edge : edges_) {
22 ids.push_back(edge->id_);
23 }
24 return ids;
25 }
26
27
28 // equality operator
29 bool
operator ==(match_vertex const & other) const30 match_vertex::operator==(match_vertex const& other) const
31 {
32 return this->cam_id_ == other.cam_id_ &&
33 this->edge_ids() == other.edge_ids();
34 }
35
36
37 // streaming operator
38 std::ostream&
operator <<(std::ostream & os,match_vertex const & vertex)39 operator<<(std::ostream& os, match_vertex const& vertex)
40 {
41 os << "vertex " << vertex.cam_id_ << " with edges [";
42
43 std::string separator;
44 for (auto edge_id : vertex.edge_ids()) {
45 os << separator << edge_id;
46 separator = ",";
47 }
48 os << "]";
49
50 return os;
51 }
52
53
54 // --------------------
55 // match_edge
56 // --------------------
57
58 // vertex ids connected to edge
59 std::vector<size_t>
vertex_ids() const60 match_edge::vertex_ids() const
61 {
62 std::vector<size_t> ids = {v0_->cam_id_, v1_->cam_id_};
63 return ids;
64 }
65
66
67 // equality operator
68 bool
operator ==(match_edge const & other) const69 match_edge::operator==(match_edge const& other) const
70 {
71 return this->id_ == other.id_ &&
72 this->vertex_ids() == other.vertex_ids() &&
73 this->matches_ == other.matches_;
74 }
75
76
77 // streaming operator
78 std::ostream&
operator <<(std::ostream & os,match_edge const & edge)79 operator<<(std::ostream& os, match_edge const& edge)
80 {
81 os << "edge " << edge.id_ << " connecting vertices ["
82 << edge.v0_->cam_id_ << "," << edge.v1_->cam_id_
83 << "] with " << edge.matches_.size() << " matches";
84 return os;
85 }
86
87
88 // --------------------
89 // acal_match_graph
90 // --------------------
91
acal_match_graph(std::map<size_t,std::map<size_t,std::vector<acal_match_pair>>> const & incidence_matrix)92 acal_match_graph::acal_match_graph(
93 std::map<size_t, std::map<size_t, std::vector<acal_match_pair> > > const& incidence_matrix)
94 {
95 bool success = this->load_incidence_matrix(incidence_matrix);
96 }
97
98
99 bool
load_incidence_matrix(std::map<size_t,std::map<size_t,std::vector<acal_match_pair>>> const & incidence_matrix)100 acal_match_graph::load_incidence_matrix(
101 // cam id i cam id j matches (i, j)
102 std::map<size_t, std::map<size_t, std::vector<acal_match_pair> > > const& incidence_matrix)
103 {
104 // construct vertices
105 for (std::map<size_t, std::map<size_t, std::vector<acal_match_pair> > >::const_iterator iit = incidence_matrix.begin();
106 iit != incidence_matrix.end(); ++iit) {
107 size_t i = iit->first;
108 if (!match_vertices_[i]) {
109 match_vertices_[i] = std::make_shared<match_vertex>(i);
110 }
111 const std::map<size_t, std::vector<acal_match_pair> >& temp = iit->second;
112 for (std::map<size_t, std::vector<acal_match_pair> >::const_iterator jit = temp.begin();
113 jit != temp.end(); ++jit) {
114 size_t j = jit->first;
115 if (!match_vertices_[j]) {
116 match_vertices_[j] = std::make_shared<match_vertex>(j);
117 }
118 }
119 }
120
121 // construct edges
122 size_t edge_id = 0;
123 for (std::map<size_t, std::map<size_t, std::vector<acal_match_pair> > >::const_iterator iit = incidence_matrix.begin();
124 iit != incidence_matrix.end(); ++iit) {
125 size_t i = iit->first;
126 std::shared_ptr<match_vertex> v0 = match_vertices_[i];
127 const std::map<size_t, std::vector<acal_match_pair> >& temp = iit->second;
128 for (std::map<size_t, std::vector<acal_match_pair> >::const_iterator jit = temp.begin();
129 jit != temp.end(); ++jit) {
130 size_t j = jit->first;
131 const std::vector<acal_match_pair>& matches = jit->second;
132 if (matches.size() == 0)
133 continue;
134 std::shared_ptr<match_vertex> v1 = match_vertices_[j];
135 match_edges_.push_back(std::make_shared<match_edge>(v0, v1, matches, edge_id));
136 edge_id++;
137 }
138 }
139
140 return true;
141 }
142
143
144 bool
load_from_fmatches(std::string const & fmatches_path)145 acal_match_graph::load_from_fmatches(std::string const& fmatches_path)
146 {
147 std::map<size_t, std::map<size_t, std::vector<acal_match_pair> > > fmatches;
148 std::map<size_t, std::string> image_paths;
149 bool good = acal_f_utils::read_f_matches(fmatches_path, fmatches, image_paths);
150 if (!good)
151 return false;
152
153 if (!this->load_incidence_matrix(fmatches))
154 return false;
155
156 image_paths_ = image_paths;
157 return true;
158 }
159
160
161 bool
load_affine_cams(std::string const & affine_cam_path)162 acal_match_graph::load_affine_cams(std::string const& affine_cam_path)
163 {
164 return acal_f_utils::read_affine_cameras(affine_cam_path, all_acams_);
165 }
166
167
168 void
clear_vertex_marks()169 acal_match_graph::clear_vertex_marks()
170 {
171 for (std::map<size_t, std::shared_ptr<match_vertex> >::iterator vit = match_vertices_.begin();
172 vit != match_vertices_.end(); ++vit)
173 (*vit).second->mark_ = false;
174 }
175
176
177 std::vector<std::shared_ptr<match_vertex> >
adjacent_verts(std::shared_ptr<match_vertex> const & v)178 acal_match_graph::adjacent_verts(std::shared_ptr<match_vertex> const& v)
179 {
180 std::vector<std::shared_ptr<match_vertex> > ret;
181 for (std::vector<match_edge*>::iterator eit = v->edges_.begin();
182 eit != v->edges_.end(); ++eit) {
183
184 if ((*eit)->v0_ != v)
185 ret.push_back((*eit)->v0_);
186
187 if ((*eit)->v1_ != v)
188 ret.push_back((*eit)->v1_);
189 }
190 return ret;
191 }
192
193
194 void
visit(std::shared_ptr<match_vertex> & v,std::vector<std::shared_ptr<match_vertex>> & comp)195 acal_match_graph::visit(
196 std::shared_ptr<match_vertex>& v,
197 std::vector<std::shared_ptr<match_vertex> >& comp)
198 {
199 v->mark_ = true;
200 comp.push_back(v);
201 std::vector<std::shared_ptr<match_vertex> > adj_verts = adjacent_verts(v);
202 for (std::vector<std::shared_ptr<match_vertex> >::iterator vit = adj_verts.begin();
203 vit != adj_verts.end(); ++vit) {
204 if ((*vit)->mark_)
205 continue;
206 visit(*vit,comp);
207 }
208 }
209
210
211 void
find_connected_components()212 acal_match_graph::find_connected_components()
213 {
214 this->clear_vertex_marks();
215 for (std::map<size_t, std::shared_ptr<match_vertex> >::iterator vit = match_vertices_.begin();
216 vit != match_vertices_.end(); ++vit) {
217 if ((*vit).second->mark_)
218 continue;
219 std::vector<std::shared_ptr<match_vertex> > comp;
220 visit((*vit).second, comp);
221 if (comp.size())
222 conn_comps_.push_back(comp);
223 }
224 }
225
226
227 void
set_intersect_match_edge(std::shared_ptr<match_vertex> const & focus_vert,match_edge * e,std::vector<acal_corr> & focus_corrs,std::map<size_t,std::vector<acal_corr>> & other_corrs)228 acal_match_graph::set_intersect_match_edge(
229 std::shared_ptr<match_vertex> const& focus_vert,
230 match_edge* e,
231 std::vector<acal_corr>& focus_corrs,
232 std::map<size_t, std::vector<acal_corr> >& other_corrs)
233 {
234 size_t fid = focus_vert->cam_id_; // focus cam id
235 size_t oid = -1; //other cam id
236 std::shared_ptr<match_vertex> v0 = e->v0_, v1 = e->v1_; //edge verts
237 size_t nm = e->matches_.size();
238 if (nm == 0)
239 return; //e has no matches - shouldn't happen
240
241 // initialization step for first call
242 if (focus_corrs.size() == 0 && other_corrs.size() == 0) {
243 focus_corrs.resize(nm);
244 if (v0->cam_id_ == fid) { // is v0 the focus vertex?
245 oid = v1->cam_id_;
246 other_corrs[oid].resize(nm);
247 for (size_t m = 0; m<nm; ++m) { // idx1, uv1 are focus corrs
248 const acal_match_pair& pr = e->matches_[m];
249 focus_corrs[m] = pr.corr1_;
250 other_corrs[oid][m] = pr.corr2_;
251 }
252 } else { // v1 is the focus vertex
253 oid = v0->cam_id_;
254 other_corrs[oid].resize(nm);
255 for (size_t m = 0; m<nm; ++m) { // idx2, uv2 are focus corrs
256 const acal_match_pair& pr = e->matches_[m];
257 focus_corrs[m] = pr.corr2_;
258 other_corrs[oid][m] = pr.corr1_;
259 }
260 }
261 return;
262 }
263
264 // intersect correspondences of e with current correspondence sets
265 std::vector<acal_corr> inter_focus_corrs; //focus corrs after intersection
266 std::map<size_t, std::vector<acal_corr> > inter_other_corrs; //other camera corrs after intersection
267 if (v0->cam_id_ == fid) { // idx1, uv1 are assigned to focus
268 oid = v1->cam_id_;
269 for (size_t m = 0; m<nm; ++m) {
270 const acal_match_pair& pr = e->matches_[m];
271 size_t idf = pr.corr1_.id_, ido = pr.corr2_.id_;
272
273 bool found = false; // find idf in focus_corrs
274 for (std::vector<acal_corr>::iterator fit = focus_corrs.begin();
275 fit != focus_corrs.end()&&!found; ++fit)
276 found = (*fit).id_ == idf;
277
278 if (found) {
279 inter_focus_corrs.push_back(pr.corr1_);
280 inter_other_corrs[oid].push_back(pr.corr2_);
281 }
282 }
283 } else { // idx2, uv2 are assigned to focus
284 oid = v0->cam_id_;
285 for (size_t m = 0; m<nm; ++m) {
286 const acal_match_pair& pr = e->matches_[m];
287 size_t idf = pr.corr2_.id_, ido = pr.corr1_.id_;
288
289 bool found = false; // find idf in focus_corrs
290 for (std::vector<acal_corr>::iterator fit = focus_corrs.begin();
291 fit != focus_corrs.end()&&!found; ++fit)
292 found = (*fit).id_ == idf;
293
294 if (found) {
295 inter_focus_corrs.push_back(pr.corr2_);
296 inter_other_corrs[oid].push_back(pr.corr1_);
297 }
298 }
299 }
300
301 // other cam, oid, is up to date but need to remove correspondences from other cams
302 size_t nif = inter_focus_corrs.size();
303 for (std::map<size_t, std::vector<acal_corr > >::iterator cit = other_corrs.begin();
304 cit != other_corrs.end(); ++cit) {
305 size_t ocam_id = cit->first;
306 std::vector<acal_corr> pruned_other_corrs;
307 const std::vector<acal_corr>& cur_ocorrs = cit->second;
308 size_t noc = cur_ocorrs.size();
309
310 std::vector<acal_corr> otemp;
311
312 size_t nf = focus_corrs.size();
313 size_t nco = cur_ocorrs.size();
314 if (nf != nco) {
315 std::cout << "Mismatch in correspondences - fatal" << std::endl;
316 focus_corrs.clear();
317 other_corrs.clear();
318 return;
319 }
320 // search through original focus corrs to find vector index of
321 // the other image corr in the set of other correspondences before intersection
322 for (size_t f = 0; f<nif; ++f) {
323 const acal_corr& ifc = inter_focus_corrs[f];
324 size_t fidx = ifc.id_;
325 bool found = false;
326 size_t found_j = -1;
327 for (size_t j = 0; j<nf&&!found; ++j) {
328 found = focus_corrs[j].id_ == fidx;
329 found_j = j;
330 }
331 if (found)
332 pruned_other_corrs.push_back(cur_ocorrs[found_j]);
333 }
334 other_corrs[ocam_id] = pruned_other_corrs;
335 }
336 other_corrs[oid] = inter_other_corrs[oid];
337 focus_corrs = inter_focus_corrs;
338 }
339
340
341 bool
find_joint_tracks(std::shared_ptr<match_vertex> const & focus_vert,std::vector<std::map<size_t,vgl_point_2d<double>>> & joint_tracks,size_t min_n_tracks)342 acal_match_graph::find_joint_tracks(
343 std::shared_ptr<match_vertex> const& focus_vert,
344 // track cam_id correspondence
345 std::vector< std::map<size_t, vgl_point_2d<double> > >& joint_tracks,
346 size_t min_n_tracks)
347 {
348
349 // tracks for focus vert
350 std::vector<acal_corr> focus_corrs;
351 // other cam id tracks on other cam
352 std::map<size_t, std::vector<acal_corr> > other_corrs;
353
354 size_t fid = focus_vert->cam_id_;
355
356 for (std::vector<match_edge*>::iterator eit = focus_vert->edges_.begin();
357 eit != focus_vert->edges_.end(); ++eit) {
358 // temporary cache in case intersection produces no tracks
359 std::vector<acal_corr> tempf = focus_corrs;
360 std::map<size_t, std::vector<acal_corr> > tempo = other_corrs;
361
362 // intersect matches of *eit with current set of tracks
363 set_intersect_match_edge(focus_vert, *eit, tempf, tempo);
364
365 // if min number of tracks survive update the current intersection set
366 // otherwise skip the edge
367 if (tempf.size() >= min_n_tracks) {
368 focus_corrs = tempf;
369 other_corrs = tempo;
370 }
371 }
372 // check for failure
373 size_t nf = focus_corrs.size();
374 if (nf < min_n_tracks)
375 return false;
376
377 // convert to form suitable for ray intersection (track form) to construct 3-d points
378 joint_tracks.resize(nf);
379 size_t t = 0;
380 for (std::vector<acal_corr >::iterator fit = focus_corrs.begin();
381 fit != focus_corrs.end(); ++fit, t++)
382 joint_tracks[t][fid] = (*fit).pt_;
383
384 for (std::map<size_t, std::vector<acal_corr> >::iterator oit = other_corrs.begin();
385 oit != other_corrs.end(); ++oit) {
386 size_t cid = oit->first;
387 const std::vector<acal_corr>& ocorrs = oit->second;
388 if (ocorrs.size() != nf) {
389 std::cout << "inconsistent number of correspondences" << std::endl;
390 return false;
391 }
392 t = 0;
393 for (; t<nf; ++t)
394 joint_tracks[t][cid] = ocorrs[t].pt_;
395 }
396 return true;
397 }
398
399
400 void
compute_focus_tracks()401 acal_match_graph::compute_focus_tracks()
402 {
403 size_t nc = conn_comps_.size();
404 focus_track_metric_.resize(nc, 0.0);
405
406 size_t V = 0;
407 for (size_t c = 0; c < nc; ++c) {
408 V += conn_comps_[c].size();
409 }
410
411 for (size_t c = 0; c < nc; ++c) {
412 size_t nv = conn_comps_[c].size();
413 if (nv == 0) {
414 continue;
415 }
416 double metric = 0.0;
417 // focus cam id track cam_id correspondence location
418 std::map<size_t, std::vector< std::map<size_t, vgl_point_2d<double> > > > c_tracks;
419 for (size_t i = 0; i < nv; ++i) {
420 std::shared_ptr<match_vertex> focus_v = conn_comps_[c][i];
421 if (!focus_v)
422 continue;
423
424 // track cam_id correspondence location
425 std::vector< std::map<size_t, vgl_point_2d<double> > > joint_tracks;
426 if (!find_joint_tracks(focus_v, joint_tracks, params_.min_n_tracks_))
427 continue;
428 size_t ntrks = joint_tracks.size();
429 if (ntrks == 0) {
430 metric = -10.0;
431 continue;
432 }
433 size_t n_connected_cams = joint_tracks[0].size();
434 if (n_connected_cams < params_.min_n_cams_)
435 continue;
436 // update metric
437 metric += static_cast<double>((n_connected_cams - 2) * (n_connected_cams - 2) * ntrks);
438 c_tracks[focus_v->cam_id_] = joint_tracks;
439 }
440 focus_track_metric_[c] = metric * (static_cast<double>(nv) / V);
441 focus_tracks_[c] = c_tracks;
442 }
443 }
444
445
446 void
compute_match_trees()447 acal_match_graph::compute_match_trees()
448 {
449 size_t nc = conn_comps_.size();
450 // iterate over all the connected components
451 for (size_t c = 0; c < nc; ++c) {
452 size_t nv = conn_comps_[c].size();
453 if (nv == 0)
454 continue;
455 // iterate over all vertices in connected component c
456 for (size_t v = 0; v<nv; ++v) {
457 std::shared_ptr<match_vertex> f_vert = conn_comps_[c][v];
458 size_t fidx = f_vert->cam_id_;
459 auto mt_ptr = std::make_shared<acal_match_tree>(fidx);
460 std::map<size_t, std::shared_ptr<match_vertex> > active_verts;
461 active_verts[fidx] = f_vert;
462 std::set<size_t> used_verts; // vertices already explored for a given focus vertex
463 std::set<match_edge*> used_edges;// graph edges already explored for a given focus vertex
464 bool first = true;
465 // construct the match tree from all reachable vertices
466 // from f_vert in connected component c
467 while (active_verts.size() > 0) {
468 size_t aidx = (active_verts.begin())->first;
469 // has active vertex aidx already been explored?
470 std::set<size_t>::iterator uit;
471 uit = std::find(used_verts.begin(), used_verts.end(), aidx);
472 if (uit != used_verts.end()) {
473 active_verts.erase(*uit);
474 continue;
475 }
476 // no, so try to extend the tree
477 used_verts.insert(aidx);
478 std::shared_ptr<match_vertex> a_vert = (active_verts.begin())->second;
479 std::vector<match_edge*>& edges = a_vert->edges_;
480 size_t ne = edges.size();
481 // iterate over the graph edges for the active vertex
482 for (size_t e = 0; e<ne; ++e) {
483 match_edge* edge = edges[e];
484 // has the edge already been explored?
485 std::set<match_edge*>::iterator eit;
486 eit = std::find(used_edges.begin(), used_edges.end(), edge);
487 if (eit != used_edges.end())
488 continue;
489 // no so try to extend the tree
490 used_edges.insert(edge);
491 size_t id0 = edge->v0_->cam_id_;
492 size_t id1 = edge->v1_->cam_id_;
493 std::vector<acal_match_pair> match_pairs = edge->matches_;
494 size_t parent_id = id0, child_id = id1;
495 if (id1 == aidx) {
496 parent_id = id1; child_id = id0;
497 acal_match_utils::reverse(match_pairs);
498 }
499 // try to add the child to a node of the current tree
500 if (mt_ptr->add_child_node(parent_id, child_id, match_pairs))
501 if (id1 == aidx) // if success then add child node as an active vertex
502 active_verts[id0] = edge->v0_;
503 else
504 active_verts[id1] = edge->v1_;
505 }// end vert edges
506 active_verts.erase(aidx);
507 } // end active verts
508 mt_ptr->update_tree_size();
509 match_trees_[c][fidx] = mt_ptr;
510 }// end focus v
511 } // end conn-comp
512 }
513
514
515 bool
valid_tree(std::shared_ptr<acal_match_tree> const & mtree)516 acal_match_graph::valid_tree(std::shared_ptr<acal_match_tree> const& mtree)
517 {
518 // valid trees must have at least 2 nodes
519 if (mtree->size() < 2)
520 return false;
521
522 std::vector< std::map<size_t, vgl_point_2d<double> > > tracks = mtree->tracks();
523 std::map<size_t, std::map<size_t, vgl_point_2d<double> > > proj_tracks;
524 std::map<size_t, vpgl_affine_camera<double> > tree_acams;
525 std::vector<size_t> tree_cam_ids = mtree->cam_ids();
526
527 for (std::vector<size_t>::iterator cit = tree_cam_ids.begin();
528 cit != tree_cam_ids.end(); ++cit)
529 {
530 if (all_acams_.count(*cit) == 0) {
531 std::cout << "affine camera " << *cit << " not in match graph - fatal" << std::endl;
532 return false;
533 }
534 tree_acams[*cit] = all_acams_[*cit];
535 }
536
537 std::map<size_t, vgl_point_3d<double> > inter_pts;
538 if (! acal_f_utils::intersect_tracks_with_3d(tree_acams, tracks, inter_pts, proj_tracks))
539 return false;
540
541 double max_proj_error = 0.0;
542 size_t max_track = -1, max_cam_id = -1;
543 for (std::map<size_t, std::map<size_t, vgl_point_2d<double> > >::iterator pit = proj_tracks.begin();
544 pit != proj_tracks.end(); ++pit)
545 {
546 size_t tidx = pit->first; //track index
547 std::map<size_t, vgl_point_2d<double> > temp = pit->second;
548 for (std::map<size_t, vgl_point_2d<double> >::iterator cit = temp.begin();
549 cit != temp.end(); ++cit)
550 {
551 size_t cam_id = cit->first;
552 vgl_point_2d<double>& pt = tracks[tidx][cam_id];
553 vgl_point_2d<double>& proj_pt = cit->second;
554 double proj_error = (pt-proj_pt).length();
555 if (proj_error > max_proj_error) {
556 max_proj_error = proj_error;
557 max_track = tidx;
558 max_cam_id = cam_id;
559 }
560 }
561 }
562
563 //std::cout << max_proj_error << ' ';
564 if (max_proj_error > params_.max_uncal_proj_error_) {
565 //std::cout << max_proj_error << " error exceeds limit for cam " << max_cam_id << " on track " << max_track << std::endl;
566 bad_track_camera_ids_[max_cam_id]++;
567 return false;
568 }
569 return true;
570 }
571
572
573 void
print_bad_camera_ids()574 acal_match_graph::print_bad_camera_ids()
575 {
576 std::cout << "cameras that have excessive projection error in a track" << std::endl;
577 for(std::map<size_t, size_t>::iterator bit = bad_track_camera_ids_.begin();
578 bit != bad_track_camera_ids_.end(); ++bit) {
579 size_t nbad = bit->second;
580 if (nbad == 0) continue;
581 std::cout << "cam id " << bit->first << " number of tracks invalidated " << bit->second << std::endl;
582 }
583 }
584
585
586 void
validate_match_trees_and_set_metric()587 acal_match_graph::validate_match_trees_and_set_metric()
588 {
589 size_t ncc = conn_comps_.size();
590 match_tree_metric_.clear();
591 match_tree_metric_.resize(ncc, 0);
592
593 for (size_t cc = 0; cc<ncc; ++cc)
594 {
595 std::map<size_t, std::shared_ptr<acal_match_tree> >& mtrees = match_trees_[cc];
596 std::map<size_t, std::shared_ptr<acal_match_tree> > temp, repaired_trees;
597 size_t n_trees = mtrees.size();
598 if (n_trees==0) {
599 std::cout << "no match trees for connected component " << cc << std::endl;
600 continue;
601 }
602
603 // initialize bad camera map
604 for (std::map<size_t, std::shared_ptr<acal_match_tree> >::iterator trit = mtrees.begin();
605 trit != mtrees.end(); ++trit)
606 {
607 std::vector<size_t> cam_ids = trit->second->cam_ids();
608 for(size_t i = 0; i<cam_ids.size(); ++i)
609 bad_track_camera_ids_[cam_ids[i]] = 0;//initialize bad in track count to 0
610 }
611
612 for (std::map<size_t, std::shared_ptr<acal_match_tree> >::iterator trit = mtrees.begin();
613 trit != mtrees.end(); ++trit)
614 {
615 if (valid_tree(trit->second))//updates bad track camera count
616 temp[trit->first] = trit->second;
617 }
618
619 // no valid match trees
620 if (temp.empty())
621 {
622 std::cout << "all match trees failed for connected component " << cc
623 << " listing cams with excessive projection error" << std::endl;
624 std::vector<size_t> bad_ids;
625 for (std::map<size_t, size_t>::iterator bit = bad_track_camera_ids_.begin();
626 bit != bad_track_camera_ids_.end(); ++bit)
627 {
628 size_t nbad = bit->second;
629 if (nbad > 0) {
630 bad_ids.push_back(bit->first);
631 std::cout << "cam id " << bit->first << ", n_bad " << nbad
632 << ", n_trees " << n_trees << std::endl;
633 }
634 }
635
636 std::cout << "remove bad cameras from match trees and retry to find valid trees" << std::endl;
637 std::map<size_t, std::shared_ptr<acal_match_tree> > repaired_trees;
638 for(std::map<size_t, std::shared_ptr<acal_match_tree> >::iterator mit = mtrees.begin();
639 mit != mtrees.end(); ++mit)
640 {
641 size_t fid = mit->first;
642 if (bad_track_camera_ids_[fid] > 0) // skip entire tree if root is bad
643 continue;
644 std::shared_ptr<acal_match_tree> repaired(new acal_match_tree(*(mit->second), bad_ids));
645 repaired_trees[mit->first] = repaired;
646 }
647
648 // initialize bad camera map
649 bad_track_camera_ids_.clear();
650 for (std::map<size_t, std::shared_ptr<acal_match_tree> >::iterator trit = repaired_trees.begin();
651 trit != repaired_trees.end(); ++trit)
652 {
653 std::vector<size_t> cam_ids = trit->second->cam_ids();
654 for(size_t i = 0; i<cam_ids.size(); ++i)
655 bad_track_camera_ids_[cam_ids[i]] = 0;//initialize bad in track count to 0
656 }
657
658 for (std::map<size_t, std::shared_ptr<acal_match_tree> >::iterator trit = repaired_trees.begin();
659 trit != repaired_trees.end(); ++trit)
660 {
661 if (valid_tree(trit->second))//updates bad track camera count
662 temp[trit->first] = trit->second;
663 }
664 }
665
666 if (temp.size() > 0)
667 {
668 match_trees_[cc] = temp;
669 std::shared_ptr<acal_match_tree> best_tree = this->largest_tree(cc);
670 if (!best_tree) {
671 match_tree_metric_[cc] = 0;
672 } else {
673 match_tree_metric_[cc] = best_tree->size();
674 }
675 }
676 }
677 }
678
679
680 // the predicate that orders based on number of cameras in the tree
681 static bool
tree_size_greater(std::pair<size_t,std::shared_ptr<acal_match_tree>> const a,std::pair<size_t,std::shared_ptr<acal_match_tree>> const b)682 tree_size_greater(std::pair<size_t, std::shared_ptr<acal_match_tree> > const a,
683 std::pair<size_t, std::shared_ptr<acal_match_tree> > const b)
684 {
685 return a.second->n_ > b.second->n_;
686 }
687
688
689 // sort the trees on number of cameras and return the first tree in the sorted list
690 std::shared_ptr<acal_match_tree>
largest_tree(size_t conn_comp_index)691 acal_match_graph::largest_tree(size_t conn_comp_index)
692 {
693 if (conn_comp_index == -1)
694 return std::shared_ptr<acal_match_tree>();
695 std::map<size_t, std::shared_ptr<acal_match_tree> > & mtrees = match_trees_[conn_comp_index];
696 if (mtrees.size()==0) {
697 std::cout << "no match trees for connected component " << conn_comp_index << std::endl;
698 return std::shared_ptr<acal_match_tree>();
699 }
700 std::vector<std::pair<size_t, std::shared_ptr<acal_match_tree> > > trees;
701 for (std::map<size_t, std::shared_ptr<acal_match_tree> >::iterator mit = mtrees.begin();
702 mit != mtrees.end(); ++mit) {
703 std::pair<size_t, std::shared_ptr<acal_match_tree> > pr(mit->first, mit->second);
704 trees.push_back(pr);
705 }
706 std::sort(trees.begin(), trees.end(), tree_size_greater);
707 return trees[0].second;
708 }
709
710
711 void
print_connected_components()712 acal_match_graph::print_connected_components()
713 {
714 size_t nc = conn_comps_.size();
715 for (size_t c =0; c<nc; ++c) {
716 std::cout << "\nconnected component " << c <<
717 "\n( ";
718 size_t nv = conn_comps_[c].size();
719 for (size_t i = 0; i<nv; ++i)
720 std::cout << conn_comps_[c][i]->cam_id_ << ' ';
721 std::cout << ")" << std::endl;
722 for (size_t i = 0; i<nv; ++i) {
723 std::string img_path = image_paths_[conn_comps_[c][i]->cam_id_];
724 std::string img_name = vul_file::strip_directory(img_path);
725 img_name = vul_file::strip_extension(img_name);
726 std::cout << conn_comps_[c][i]->cam_id_ << ' ' << img_name << std::endl;
727 }
728 std::cout << std::endl;
729 }
730 }
731
732
733 void
print_n_tracks_for_conn_comp()734 acal_match_graph::print_n_tracks_for_conn_comp()
735 {
736 size_t nc = conn_comps_.size();
737 for (size_t c =0; c<nc; ++c) {
738 std::cout << "\nconnected component " << c << std::endl;
739 size_t nv = conn_comps_[c].size();
740 for (size_t i = 0; i<nv; ++i) {
741 const std::shared_ptr<match_vertex>& v = conn_comps_[c][i];
742 std::cout << "vertex " << v->cam_id_ << "\n( ";
743 for (std::vector<match_edge*>::iterator eit = v->edges_.begin();
744 eit != v->edges_.end(); ++eit)
745 std::cout << (*eit)->v0_->cam_id_ << ":" << (*eit)->v1_->cam_id_ << ' ' << (*eit)->matches_.size() << ' ';
746 std::cout << " )" << std::endl;
747 }
748 }
749 }
750
751
752 void
print_focus_tracks()753 acal_match_graph::print_focus_tracks()
754 {
755 std::cout << "\n======focus vertex tracks=======" << std::endl;
756 // conn comp focus vert tracks cam id track point
757 for (std::map<size_t, std::map<size_t, std::vector< std::map<size_t, vgl_point_2d<double> > > > >::iterator cit = focus_tracks_.begin();
758 cit != focus_tracks_.end(); ++cit) {
759 size_t cc = cit->first;
760 std::cout << "\nconnected component " << cc << std::endl;
761 const std::map<size_t, std::vector< std::map<size_t, vgl_point_2d<double> > > >& ftemp = cit->second;
762 for (std::map<size_t, std::vector< std::map<size_t, vgl_point_2d<double> > > >::const_iterator fit = ftemp.begin();
763 fit != ftemp.end(); ++fit) {
764 size_t focus_id = fit->first;
765 std::cout << "----- focus camera id " << focus_id << std::endl;
766 const std::vector< std::map<size_t, vgl_point_2d<double> > >& tr_temp = fit->second;
767 size_t t = 0;
768 for (std::vector< std::map<size_t, vgl_point_2d<double> > >::const_iterator trit = tr_temp.begin();
769 trit != tr_temp.end(); ++trit, ++t) {
770 std::cout << " track " << t << std::endl;
771 const std::map<size_t, vgl_point_2d<double> >& tcorrs = *trit;
772 for (std::map<size_t, vgl_point_2d<double> >::const_iterator cmpit = tcorrs.begin();
773 cmpit != tcorrs.end(); ++cmpit) {
774 std::cout << " " << cmpit->first << ' ' << cmpit->second.x() << ' ' << cmpit->second.y() << std::endl;
775 }
776 }
777 }
778 std::cout << std::endl;
779 }
780 }
781
782
783 void
adjust_affine_cams(std::map<size_t,vgl_vector_2d<double>> & cam_translations)784 acal_match_graph::adjust_affine_cams(std::map<size_t, vgl_vector_2d<double> >& cam_translations)
785 {
786 for (std::map<size_t, vgl_vector_2d<double> >::iterator cit = cam_translations.begin();
787 cit != cam_translations.end(); ++cit) {
788 size_t cidx = cit->first;
789 if (!all_acams_.count(cidx))
790 continue;
791 vpgl_affine_camera<double>& acam = all_acams_[cidx];
792 vnl_matrix_fixed<double, 3, 4> m = acam.get_matrix();
793 m[0][3] += cit->second.x(); m[1][3] += cit->second.y();
794 acam.set_matrix(m);
795 }
796 }
797
798
799 bool
save_graph_dot_format(std::string const & path)800 acal_match_graph::save_graph_dot_format(std::string const& path)
801 {
802 std::ofstream ostr(path.c_str());
803 if (!ostr) {
804 std::cout << "Can't open " << path << " to write dot file" << std::endl;
805 return false;
806 }
807 ostr << "graph" << std::endl;
808 ostr << "graphN {" << std::endl;
809
810 size_t ne = match_edges_.size();
811 if (!ne) {
812 std::cout << "no edges in graph" << std::endl;
813 return false;
814 }
815 size_t ncc = conn_comps_.size();
816 std::vector<std::vector<std::string> > ccomp(ncc);
817 for (size_t i =0; i<ne; ++i) {
818 std::shared_ptr<match_edge> e = match_edges_[i];
819 if (!e)
820 continue;
821 size_t n_matches = e->matches_.size();
822 size_t v0_id = e->v0_->cam_id_;
823 size_t v1_id = e->v1_->cam_id_;
824 std::stringstream ss;
825 ss << v0_id << "--"<< v1_id << " [ label = \" " << n_matches << "\" ];";
826 size_t cc = -1;
827 for (size_t c = 0; c<ncc; ++c) {
828 bool found = false;
829 for (std::vector<std::shared_ptr<match_vertex> >::iterator vit = conn_comps_[c].begin();
830 vit != conn_comps_[c].end()&&!found; ++vit)
831 if ((*vit)->cam_id_ == v0_id ||(*vit)->cam_id_ == v1_id) {
832 found = true;
833 cc = c;
834 }
835 if (!found)
836 continue;
837 }
838 if (cc == -1) {
839 std::cout << "edge(" << v0_id << ' ' << v1_id << ") not found in any connected component" << std::endl;
840 return false;
841 }
842 ccomp[cc].push_back(ss.str());
843 }
844
845 for (size_t c = 0; c<ncc; ++c) {
846 std::stringstream scc;
847 // note, a subgraph id must begin with cluster
848 scc << "subgraph cluster_cc" << c << " { label = \"conn comp " << c << " m = " << focus_track_metric_[c]<< "\";";
849 ostr << scc.str() << std::endl;
850 for (size_t s = 0; s<ccomp[c].size();++s)
851 ostr << ccomp[c][s] << std::endl;
852 ostr << "}" << std::endl;
853 }
854 ostr << "}" << std::endl;
855 ostr.close();
856 return true;
857 }
858
859
860 bool
save_focus_graphs_dot_format(size_t ccomp_index,std::string const & path)861 acal_match_graph::save_focus_graphs_dot_format(size_t ccomp_index, std::string const& path)
862 {
863 std::ofstream ostr(path.c_str());
864 if (!ostr) {
865 std::cout << "Can't open " << path << " to write dot file" << std::endl;
866 return false;
867 }
868 ostr << "graph" << std::endl;
869 ostr << "graphN {" << std::endl;
870
871 std::map<size_t, std::vector< std::map<size_t, vgl_point_2d<double> > > >& ftrk = focus_tracks_[ccomp_index];
872 if (ftrk.size()==0) {
873 std::cout << "no focus tracks for connected component " << ccomp_index << std::endl;
874 return false;
875 }
876 for (std::map<size_t, std::vector< std::map<size_t, vgl_point_2d<double> > > >::iterator fit = ftrk.begin();
877 fit != ftrk.end(); ++fit) {
878 size_t cidx = fit->first;
879 std::vector< std::map<size_t, vgl_point_2d<double> > >& trks = fit->second;
880 size_t ntrk = trks.size();
881 if (ntrk == 0)
882 continue;
883 std::map<size_t, vgl_point_2d<double> >& trk = trks[0];
884 std::stringstream ss;
885 ss << " subgraph cluster" << cidx << " {\n label = \"focus vert id " << cidx << "\";";
886 ostr << ss.str() << std::endl;
887 for (std::map<size_t, vgl_point_2d<double> >::iterator cit = trk.begin();
888 cit != trk.end(); ++cit) {
889 if (cit->first == cidx)
890 continue;
891 std::stringstream css;
892 css << " " << cidx << "--" << cit->first<<"." << cidx << " [ label = \" " << ntrk << "\" ];";
893 ostr << css.str() << std::endl;
894 }
895 ostr << " }" << std::endl;
896 }
897 ostr << "}" << std::endl;
898 ostr.close();
899 return true;
900 }
901
902
903 bool
save_match_trees_dot_format(size_t ccomp_index,std::string const & path,size_t num_trees)904 acal_match_graph::save_match_trees_dot_format(size_t ccomp_index, std::string const& path, size_t num_trees)
905 {
906 std::ofstream ostr(path.c_str());
907 if (!ostr) {
908 std::cout << "Can't open " << path << " to write dot file" << std::endl;
909 return false;
910 }
911 ostr << "graph" << std::endl;
912 ostr << "graphN {" << std::endl;
913
914 std::map<size_t, std::shared_ptr<acal_match_tree> > & mtrees = match_trees_[ccomp_index];
915 if (mtrees.size()==0) {
916 std::cout << "no focus trees for connected component " << ccomp_index << std::endl;
917 return false;
918 }
919 std::vector<std::pair<size_t, std::shared_ptr<acal_match_tree> > > trees;
920 for (std::map<size_t, std::shared_ptr<acal_match_tree> >::iterator mit = mtrees.begin();
921 mit != mtrees.end(); ++mit) {
922 std::pair<size_t, std::shared_ptr<acal_match_tree> > pr(mit->first, mit->second);
923 trees.push_back(pr);
924 }
925 std::sort(trees.begin(), trees.end(), tree_size_greater);
926 size_t n = 0;
927 size_t nt = trees.size();
928 for (size_t i = 0; i<nt&&n<=num_trees; ++i, ++n) {
929 size_t cidx = trees[i].first;
930 std::shared_ptr<acal_match_tree> mt_ptr = trees[i].second;
931 size_t nn = 0;
932 mt_ptr->n_nodes(mt_ptr->root_, nn);
933 std::cout << "n_nodes " << nn << std::endl;
934 std::stringstream ss;
935 ss << " subgraph cluster" << cidx << " {\n label = \"focus vert id " << cidx << "\";";
936 ostr << ss.str() << std::endl;
937 mt_ptr->write_dot(ostr, mt_ptr->root_, mt_ptr->root_->cam_id_);
938 ostr << " }" << std::endl;
939 }
940 ostr << "}" << std::endl;
941 ostr.close();
942 return true;
943 }
944
945
946 std::map<size_t, std::string>
image_names()947 acal_match_graph::image_names()
948 {
949 std::map<size_t, std::string> ret;
950 for (std::map<size_t, std::string>::iterator sit = image_paths_.begin();
951 sit != image_paths_.end(); ++sit) {
952 size_t iit = sit->first;
953 std::string path = sit->second;
954 std::string temp = vul_file::strip_directory(path);
955 temp = vul_file::strip_extension(temp);
956 ret[iit] = temp;
957 }
958 return ret;
959 }
960
961
962 std::vector<std::shared_ptr<acal_match_tree> >
trees(size_t conn_comp_index)963 acal_match_graph::trees(size_t conn_comp_index)
964 {
965 std::vector<std::shared_ptr<acal_match_tree> > ret;
966 // focus cam id tree
967 std::map<size_t, std::shared_ptr<acal_match_tree> > trees = match_trees_[conn_comp_index];
968
969 for (std::map<size_t, std::shared_ptr<acal_match_tree> >::iterator mit = trees.begin();
970 mit != trees.end(); ++mit)
971 ret.push_back(mit->second);
972 return ret;
973 }
974
975
976 // equality for iterable (std::vector, std::map) of std::shared_ptr
977 // requires special handling to compare dereferenced shared_ptr content
978 // std::equal pattern from https://stackoverflow.com/a/8473603
979 template<typename T>
980 bool
is_equal(std::vector<T> const & lhs,std::vector<T> const & rhs)981 is_equal(std::vector<T> const& lhs, std::vector<T> const& rhs)
982 {
983 auto pred = [] (decltype(*lhs.begin()) a, decltype(a) b)
984 { return is_equal(a, b); };
985
986 return lhs.size() == rhs.size() &&
987 std::equal(lhs.begin(), lhs.end(), rhs.begin(), pred);
988 }
989
990 template<typename K, typename T>
991 bool
is_equal(std::map<K,T> const & lhs,std::map<K,T> const & rhs)992 is_equal(std::map<K, T> const& lhs, std::map<K, T> const& rhs)
993 {
994 auto pred = [] (decltype(*lhs.begin()) a, decltype(a) b)
995 { return a.first == b.first && is_equal(a.second, b.second); };
996
997 return lhs.size() == rhs.size() &&
998 std::equal(lhs.begin(), lhs.end(), rhs.begin(), pred);
999 }
1000
1001 template<typename T>
1002 bool
is_equal(std::shared_ptr<T> const & lhs,std::shared_ptr<T> const & rhs)1003 is_equal(std::shared_ptr<T> const& lhs, std::shared_ptr<T> const& rhs)
1004 {
1005 return *lhs == *rhs;
1006 }
1007
1008
1009 // equality operator
1010 bool
operator ==(acal_match_graph const & other) const1011 acal_match_graph::operator==(acal_match_graph const& other) const
1012 {
1013 return this->params_ == other.params_
1014 && this->image_paths_ == other.image_paths_
1015 && this->all_acams_ == other.all_acams_
1016 && is_equal(this->match_vertices_, other.match_vertices_)
1017 && is_equal(this->match_edges_, other.match_edges_)
1018 && is_equal(this->conn_comps_, other.conn_comps_)
1019 && this->focus_tracks_ == other.focus_tracks_
1020 && this->focus_track_metric_ == other.focus_track_metric_
1021 && is_equal(this->match_trees_, other.match_trees_)
1022 && this->match_tree_metric_ == other.match_tree_metric_;
1023 }
1024
1025