| 472 | } // namespace |
| 473 | |
| 474 | bool MergeReconstructions(const double max_reproj_error, |
| 475 | const Reconstruction& src_reconstruction, |
| 476 | Reconstruction& tgt_reconstruction) { |
| 477 | Sim3d tgt_from_src; |
| 478 | if (!AlignReconstructionsViaReprojections(src_reconstruction, |
| 479 | tgt_reconstruction, |
| 480 | /*min_inlier_observations=*/0.3, |
| 481 | max_reproj_error, |
| 482 | &tgt_from_src)) { |
| 483 | return false; |
| 484 | } |
| 485 | |
| 486 | // Find common and missing images in the two reconstructions. |
| 487 | std::unordered_set<image_t> common_image_ids; |
| 488 | common_image_ids.reserve(src_reconstruction.NumRegImages()); |
| 489 | std::unordered_set<image_t> missing_image_ids; |
| 490 | missing_image_ids.reserve(src_reconstruction.NumRegImages()); |
| 491 | for (const image_t image_id : src_reconstruction.RegImageIds()) { |
| 492 | if (tgt_reconstruction.ExistsImage(image_id)) { |
| 493 | common_image_ids.insert(image_id); |
| 494 | } else { |
| 495 | missing_image_ids.insert(image_id); |
| 496 | } |
| 497 | } |
| 498 | |
| 499 | // Register the missing images in this src_reconstruction. |
| 500 | for (const auto image_id : missing_image_ids) { |
| 501 | CopyRegisteredImage( |
| 502 | image_id, tgt_from_src, src_reconstruction, tgt_reconstruction); |
| 503 | } |
| 504 | |
| 505 | // Merge the two point clouds using the following two rules: |
| 506 | // - copy points to this src_reconstruction with non-conflicting tracks, |
| 507 | // i.e. points that do not have an already triangulated observation |
| 508 | // in this src_reconstruction. |
| 509 | // - merge tracks that are unambiguous, i.e. only merge points in the two |
| 510 | // reconstructions if they have a one-to-one mapping. |
| 511 | // Note that in both cases no cheirality or reprojection test is performed. |
| 512 | |
| 513 | for (const auto& [_, point3D] : src_reconstruction.Points3D()) { |
| 514 | Track new_track; |
| 515 | Track old_track; |
| 516 | std::unordered_set<point3D_t> old_point3D_ids; |
| 517 | for (const auto& track_el : point3D.track.Elements()) { |
| 518 | if (common_image_ids.count(track_el.image_id) > 0) { |
| 519 | const auto& point2D = tgt_reconstruction.Image(track_el.image_id) |
| 520 | .Point2D(track_el.point2D_idx); |
| 521 | if (point2D.HasPoint3D()) { |
| 522 | old_track.AddElement(track_el); |
| 523 | old_point3D_ids.insert(point2D.point3D_id); |
| 524 | } else { |
| 525 | new_track.AddElement(track_el); |
| 526 | } |
| 527 | } else if (missing_image_ids.count(track_el.image_id) > 0) { |
| 528 | tgt_reconstruction.Image(track_el.image_id) |
| 529 | .ResetPoint3DForPoint2D(track_el.point2D_idx); |
| 530 | new_track.AddElement(track_el); |
| 531 | } |