Skip to content

Commit cbbecea

Browse files
author
Yann N.
committed
Add grid-based decimation followed by triangulation in BA
This greatly speeds-up BA, with no noticeable change in quality. Also reduces memory usage (smaller BAs) On helenenschacht (https://github.com/OpenDroneMap/odm_data_helenenschacht/tree/main) : BEFORE : 75 seconds Average Reprojection Error (normalized / pixels / angular)0.22 / 0.74 / 0.00015 Average Track Length 2.62 images Average Track Length (> 2)4.17 images AFTER : 35 seconds Average Reprojection Error (normalized / pixels / angular)0.22 / 0.74 / 0.00015 Average Track Length 2.62 images Average Track Length (> 2) 4.17 images On ziegeleipark (https://github.com/zivillian/odm_ziegeleipark/tree/master) BEFORE : stopped after 12 hours AFTER : 7575 seconds
1 parent de4da7c commit cbbecea

File tree

4 files changed

+170
-21
lines changed

4 files changed

+170
-21
lines changed

opensfm/config.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,10 @@ class OpenSfMConfig:
292292
local_bundle_min_common_points: int = 20
293293
# Max number of shots to optimize during local bundle adjustment
294294
local_bundle_max_shots: int = 30
295+
# Number of grid division for seleccting tracks in local bundle adjustment
296+
local_bundle_grid: int = 8
297+
# Number of grid division for selecting tracks in final bundle adjustment
298+
final_bundle_grid: int = 32
295299

296300
# Save reconstructions at every iteration
297301
save_partial_reconstructions: bool = False

opensfm/reconstruction.py

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ def _get_camera_from_bundle(
5151

5252
def log_bundle_stats(bundle_type: str, bundle_report: Dict[str, Any]) -> None:
5353
times = bundle_report["wall_times"]
54-
time_secs = times["run"] + times["setup"] + times["teardown"]
54+
time_secs = times["run"] + times["setup"] + times["teardown"] + times["triangulate"]
5555
num_images, num_points, num_reprojections = (
5656
bundle_report["num_images"],
5757
bundle_report["num_points"],
@@ -71,6 +71,7 @@ def bundle(
7171
camera_priors: Dict[str, pygeometry.Camera],
7272
rig_camera_priors: Dict[str, pymap.RigCamera],
7373
gcp: Optional[List[pymap.GroundControlPoint]],
74+
grid_size: int,
7475
config: Dict[str, Any],
7576
) -> Dict[str, Any]:
7677
"""Bundle adjust a reconstruction."""
@@ -79,6 +80,7 @@ def bundle(
7980
dict(camera_priors),
8081
dict(rig_camera_priors),
8182
gcp if gcp is not None else [],
83+
grid_size,
8284
config,
8385
)
8486
log_bundle_stats("GLOBAL", report)
@@ -109,6 +111,7 @@ def bundle_local(
109111
camera_priors: Dict[str, pygeometry.Camera],
110112
rig_camera_priors: Dict[str, pymap.RigCamera],
111113
gcp: Optional[List[pymap.GroundControlPoint]],
114+
grid_size: int,
112115
central_shot_id: str,
113116
config: Dict[str, Any],
114117
) -> Tuple[Dict[str, Any], List[int]]:
@@ -119,6 +122,7 @@ def bundle_local(
119122
dict(rig_camera_priors),
120123
gcp if gcp is not None else [],
121124
central_shot_id,
125+
grid_size,
122126
config,
123127
)
124128
log_bundle_stats("LOCAL", report)
@@ -1509,7 +1513,7 @@ def grow_reconstruction(
15091513
paint_reconstruction(data, tracks_manager, reconstruction)
15101514
align_reconstruction(reconstruction, gcp, config)
15111515

1512-
bundle(reconstruction, camera_priors, rig_camera_priors, None, config)
1516+
bundle(reconstruction, camera_priors, rig_camera_priors, None, -1, config)
15131517
remove_outliers(reconstruction, config)
15141518
paint_reconstruction(data, tracks_manager, reconstruction)
15151519

@@ -1522,6 +1526,10 @@ def grow_reconstruction(
15221526
list(reconstruction.points.keys()),
15231527
)
15241528

1529+
local_ba_radius = config["local_bundle_radius"]
1530+
local_ba_grid = config["local_bundle_grid"]
1531+
final_bundle_grid = config["final_bundle_grid"]
1532+
15251533
while True:
15261534
if config["save_partial_reconstructions"]:
15271535
paint_reconstruction(data, tracks_manager, reconstruction)
@@ -1579,12 +1587,12 @@ def grow_reconstruction(
15791587
logger.info("Re-triangulating")
15801588
align_reconstruction(reconstruction, gcp, config)
15811589
b1rep = bundle(
1582-
reconstruction, camera_priors, rig_camera_priors, None, config
1590+
reconstruction, camera_priors, rig_camera_priors, None, local_ba_grid, config
15831591
)
15841592
rrep = retriangulate(tracks_manager, reconstruction, config)
15851593
resection_candidates.update(reconstruction)
15861594
b2rep = bundle(
1587-
reconstruction, camera_priors, rig_camera_priors, None, config
1595+
reconstruction, camera_priors, rig_camera_priors, None, local_ba_grid, config
15881596
)
15891597
resection_candidates.remove(*remove_outliers(reconstruction, config))
15901598
step["bundle"] = b1rep
@@ -1595,17 +1603,18 @@ def grow_reconstruction(
15951603
elif should_bundle.should():
15961604
align_reconstruction(reconstruction, gcp, config)
15971605
brep = bundle(
1598-
reconstruction, camera_priors, rig_camera_priors, None, config
1606+
reconstruction, camera_priors, rig_camera_priors, None, local_ba_grid, config
15991607
)
16001608
resection_candidates.remove(*remove_outliers(reconstruction, config))
16011609
step["bundle"] = brep
16021610
should_bundle.done()
1603-
elif config["local_bundle_radius"] > 0:
1611+
elif local_ba_radius > 0:
16041612
bundled_points, brep = bundle_local(
16051613
reconstruction,
16061614
camera_priors,
16071615
rig_camera_priors,
16081616
None,
1617+
local_ba_grid,
16091618
image,
16101619
config,
16111620
)
@@ -1627,7 +1636,7 @@ def grow_reconstruction(
16271636
overidden_config["bundle_compensate_gps_bias"] = False
16281637
config = overidden_config
16291638

1630-
bundle(reconstruction, camera_priors, rig_camera_priors, gcp, config)
1639+
bundle(reconstruction, camera_priors, rig_camera_priors, gcp, final_bundle_grid, config)
16311640
resection_candidates.remove(*remove_outliers(reconstruction, config))
16321641
paint_reconstruction(data, tracks_manager, reconstruction)
16331642
return reconstruction, report

opensfm/src/sfm/ba_helpers.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class BAHelpers {
1818
const std::unordered_map<map::RigCameraId, map::RigCamera>&
1919
rig_camera_priors,
2020
const AlignedVector<map::GroundControlPoint>& gcp,
21+
int grid_size,
2122
const py::dict& config);
2223

2324
static py::tuple BundleLocal(
@@ -26,7 +27,9 @@ class BAHelpers {
2627
const std::unordered_map<map::RigCameraId, map::RigCamera>&
2728
rig_camera_priors,
2829
const AlignedVector<map::GroundControlPoint>& gcp,
29-
const map::ShotId& central_shot_id, const py::dict& config);
30+
const map::ShotId& central_shot_id,
31+
int grid_size,
32+
const py::dict& config);
3033

3134
static py::dict BundleShotPoses(
3235
map::Map& map, const std::unordered_set<map::ShotId>& shot_ids,
@@ -57,6 +60,11 @@ class BAHelpers {
5760
const AlignedVector<map::GroundControlPoint>& gcp,
5861
const py::dict& config);
5962

63+
static std::unordered_set<map::TrackId> SelectTracksGrid(
64+
map::Map& map,
65+
const std::unordered_set<map::ShotId>& shot_ids,
66+
size_t grid_size);
67+
6068
private:
6169
static std::unordered_set<map::Shot*> DirectShotNeighbors(
6270
map::Map& map, const std::unordered_set<map::Shot*>& shot_ids,

0 commit comments

Comments
 (0)