Handle non-trivial frames in bundle adjustment#3214
Conversation
…camera rays (#3159) This is the first in a series of PRs to support cameras with >180deg FOV (including spherical cameras). This PR should result in no behavioral change other than changes up to numerical precision.
Currently, if we manage to initialize from one pair but get stuck after a few images and none of the other pairs satisfy the initialization thresholds, then we never try to initialize from a relaxed set of thresholds anymore for the remaining images, even though there is a high chance to succeed. In addition, we unnecessarily tried the same pairs redundantly for the same initialization constraints. This should result in more complete reconstruction results and faster initialization.
…#3167) This was a big confusion. I added some comments to explain why the fix in #3155 was correct. In the end its because that in COLMAP we use the left convention, while in GTSAM and its reference paper here https://arxiv.org/pdf/1812.01537 the right convention was employed. This is also in preparation for another PR on propagating relative pose covariance in COLMAP (with left convention) with cross-pose correlation available. This will encode the fact that the close image has lower relative pose covariance and does not get affected by Gauge ambiguity.
I found that some of my collaborators aren't aware of the pre-built Docker image. I think it would be helpful to mention it somewhere on the documentation's installation page.
A/B comparison against main branch. Changes mostly up to numerical noise
except for "meadow" as the usual outlier.
```
I20250217 19:45:49.373275 1782301 compare.py:main:58] Results A - B:
=====scenes===== ======AUC @ X deg (%)====== ===images=== =components=
0.5 1.0 5.0 10.0 reg all num largest
==============================eth3d=dslr==============================
botanical_garden -0.03 -0.02 -0.00 -0.00 0 0 0 0
boulders -0.01 -0.00 -0.00 -0.00 0 0 0 0
bridge 0.00 0.00 0.00 0.00 0 0 0 0
courtyard 0.01 0.00 0.00 0.00 0 0 0 0
delivery_area 0.00 0.00 0.00 0.00 0 0 0 0
door -0.00 -0.00 -0.00 -0.00 0 0 0 0
electro -0.03 -0.00 0.00 0.00 0 0 0 0
exhibition_hall 0.01 -0.02 -0.00 -0.00 0 0 0 0
facade -0.01 -0.01 -0.00 -0.00 0 0 0 0
kicker -0.04 -0.02 -0.00 -0.00 0 0 0 0
lecture_room 0.00 -0.00 -0.00 -0.00 0 0 0 0
living_room 0.03 0.02 0.00 0.00 0 0 0 0
lounge -0.03 -0.01 -0.00 -0.00 0 0 0 0
meadow -3.93 -2.52 -0.50 -0.25 0 0 0 0
observatory 0.00 0.00 0.00 0.00 0 0 0 0
office -0.03 -0.03 -0.01 -0.01 0 0 0 0
old_computer -0.68 -0.35 -0.08 -0.04 0 0 0 0
pipes 1.50 0.95 0.19 0.09 0 0 0 0
playground -0.03 -0.02 -0.00 -0.00 0 0 0 0
relief 0.03 0.02 0.00 0.00 0 0 0 0
relief_2 -0.00 -0.00 -0.00 -0.00 0 0 0 0
statue 0.00 0.00 0.00 0.00 0 0 0 0
terrace -0.04 -0.02 -0.00 -0.00 0 0 0 0
terrace_2 -0.00 -0.00 -0.00 -0.00 0 0 0 0
terrains 0.00 0.00 -0.00 -0.00 0 0 0 0
----------------------------------------------------------------------
overall -0.06 -0.03 -0.01 -0.00 0 0 0 0
----------------------------------------------------------------------
average -0.13 -0.08 -0.02 -0.01 0 0 0 0
```
…face (#3170) Now the name is too long. Creating this PR to initiate the thread. --------- Co-authored-by: Johannes Schönberger <jsch@demuc.de>
Towards supporting spherical / large FOV cameras for which a different logic will have to be implemented than for perspective projection models. The logic is now specialized and localized within the camera model and the user just knows about valid or invalid projections. This can also be used to more robustly deal with numerical issues in distortion computation (as we have for some of the fisheye models). The next PRs will do the equivalent for CamFromImg to return camera rays rather than image points as well as remove redundant "HasPointPositiveDepth/Cheirality" checks. --------- Co-authored-by: Paul-Edouard Sarlin <15985472+sarlinpe@users.noreply.github.com>
We got hit by the partial python version for the pycolmap CI build again: https://github.com/colmap/colmap/actions/runs/13519440475/job/37775195384 And I just realized that we are always building 3.8 rather than 3.12 on all the pycolmap ci build for pull requests. Was this intended? As it does not align with the comment here: https://github.com/colmap/colmap/blob/main/.github/workflows/build-pycolmap.yml#L35
…ser/jsch/reconstruction-io-frames
| // Do the bundle adjustment only if there is any connected images. | ||
| if (local_bundle.size() > 0) { | ||
| BundleAdjustmentConfig ba_config; | ||
| ba_config.FixGauge(BundleAdjustmentGauge::THREE_POINTS); |
There was a problem hiding this comment.
This can result in different behaviors, as it was two cameras before rather than three points?
There was a problem hiding this comment.
Actually, maybe the Gauge fixing is often not needed in local bundle adjustment as we mostly have some fixed 3D points in the problem.
There was a problem hiding this comment.
It'll behave differently but I think it should be overall superior to the previous behavior. As you correctly point out, the previous behavior actually lead to an over-constraining of the Gauge, because typically there would already be a lot of constant points at the "boundary" of the local bundle.
There was a problem hiding this comment.
I'll evaluate the impact on the ETH3D benchmark.
There was a problem hiding this comment.
@B1ueber2y A/B comparison against main branch. Seems to be in the order of random noise.
I20250317 21:43:15.483952 807426 compare.py:main:56] Results A:
=====scenes===== ======AUC @ X deg (%)====== ===images=== =components=
0.5 1.0 5.0 10.0 reg all num largest
==============================eth3d=dslr==============================
botanical_garden 74.22 82.46 89.21 90.06 30 30 1 30
boulders 73.02 81.69 89.00 89.96 26 26 1 26
bridge 76.18 83.42 89.40 90.16 110 110 1 110
courtyard 65.30 77.45 88.19 89.55 38 38 1 38
delivery_area 65.17 70.05 73.98 74.47 40 44 1 40
door 79.23 84.38 89.60 90.26 7 7 1 7
electro 62.24 68.09 73.70 74.45 41 45 1 41
exhibition_hall 13.99 18.07 22.28 22.93 68 68 1 68
facade 74.79 82.63 89.25 90.08 76 76 1 76
kicker 69.11 76.75 83.34 84.19 30 31 1 30
lecture_room 62.49 74.69 87.36 89.14 23 23 2 23
living_room 65.91 77.34 87.95 89.43 65 65 1 65
lounge 23.17 26.74 29.59 29.95 6 10 1 6
meadow 61.53 69.76 85.62 88.27 15 15 2 15
observatory 28.58 35.66 42.12 42.95 27 27 2 14
office 30.44 39.03 49.82 51.48 20 26 1 20
old_computer 27.59 35.69 43.52 44.57 54 54 1 54
pipes 68.92 79.56 88.64 89.77 14 14 1 14
playground 53.13 58.50 62.98 63.56 32 38 2 32
relief 42.13 43.65 44.86 45.01 31 31 2 18
relief_2 43.28 45.56 47.43 47.66 31 31 2 20
statue 88.55 89.73 90.67 90.79 11 11 1 11
terrace 73.03 81.77 89.08 90.00 23 23 1 23
terrace_2 74.70 82.20 89.07 89.99 13 13 1 13
terrains 62.79 76.34 87.85 89.38 42 42 1 42
----------------------------------------------------------------------
overall 59.67 67.19 73.92 74.81 873 898 31 836
----------------------------------------------------------------------
average 58.38 65.65 72.58 73.52 35 36 1 33
I20250317 21:43:15.484521 807426 compare.py:main:57] Results B:
=====scenes===== ======AUC @ X deg (%)====== ===images=== =components=
0.5 1.0 5.0 10.0 reg all num largest
==============================eth3d=dslr==============================
botanical_garden 74.18 82.44 89.21 90.06 30 30 1 30
boulders 72.95 81.65 89.00 89.95 26 26 1 26
bridge 76.15 83.41 89.40 90.16 110 110 1 110
courtyard 64.30 76.84 88.05 89.48 38 38 1 38
delivery_area 65.16 70.05 73.97 74.47 40 44 1 40
door 79.19 84.33 89.59 90.25 7 7 1 7
electro 62.21 68.07 73.69 74.45 41 45 1 41
exhibition_hall 19.59 29.21 39.18 40.71 68 68 2 68
facade 74.79 82.63 89.25 90.08 76 76 1 76
kicker 67.86 76.11 83.21 84.13 30 31 1 30
lecture_room 62.60 74.76 87.38 89.15 23 23 2 23
living_room 66.02 77.41 87.97 89.44 65 65 1 65
lounge 23.13 26.72 29.59 29.94 6 10 1 6
meadow 63.10 70.82 85.83 88.37 15 15 2 15
observatory 28.26 35.49 42.08 42.93 27 27 2 14
office 31.56 41.25 54.49 56.61 21 26 1 21
old_computer 28.01 35.87 43.56 44.59 54 54 1 54
pipes 68.21 79.20 88.57 89.74 14 14 1 14
playground 53.33 58.59 63.00 63.57 32 38 2 32
relief 42.18 43.67 44.86 45.01 31 31 2 18
relief_2 43.42 45.62 47.44 47.67 31 31 2 20
statue 88.59 89.75 90.68 90.79 11 11 1 11
terrace 75.57 83.17 89.36 90.14 23 23 1 23
terrace_2 74.56 82.13 89.05 89.98 13 13 1 13
terrains 62.99 76.46 87.88 89.39 42 42 1 42
----------------------------------------------------------------------
overall 60.26 68.36 75.69 76.68 874 898 32 837
----------------------------------------------------------------------
average 58.72 66.23 73.45 74.44 35 36 1 33
I20250317 21:43:15.484681 807426 compare.py:main:58] Results A - B:
=====scenes===== ======AUC @ X deg (%)====== ===images=== =components=
0.5 1.0 5.0 10.0 reg all num largest
==============================eth3d=dslr==============================
botanical_garden 0.05 0.02 0.00 0.00 0 0 0 0
boulders 0.07 0.03 0.01 0.00 0 0 0 0
bridge 0.02 0.01 0.00 0.00 0 0 0 0
courtyard 1.00 0.62 0.14 0.07 0 0 0 0
delivery_area 0.01 0.01 0.00 0.00 0 0 0 0
door 0.04 0.06 0.01 0.01 0 0 0 0
electro 0.02 0.02 0.00 0.00 0 0 0 0
exhibition_hall -5.61 -11.14 -16.90 -17.78 0 0 -1 0
facade 0.00 0.00 0.00 0.00 0 0 0 0
kicker 1.25 0.63 0.13 0.06 0 0 0 0
lecture_room -0.11 -0.07 -0.02 -0.01 0 0 0 0
living_room -0.11 -0.08 -0.02 -0.01 0 0 0 0
lounge 0.04 0.02 0.00 0.00 0 0 0 0
meadow -1.57 -1.06 -0.21 -0.10 0 0 0 0
observatory 0.32 0.18 0.04 0.02 0 0 0 0
office -1.12 -2.23 -4.67 -5.13 -1 0 0 -1
old_computer -0.42 -0.19 -0.04 -0.02 0 0 0 0
pipes 0.71 0.37 0.07 0.04 0 0 0 0
playground -0.19 -0.10 -0.02 -0.01 0 0 0 0
relief -0.04 -0.02 -0.00 -0.00 0 0 0 0
relief_2 -0.14 -0.05 -0.01 -0.01 0 0 0 0
statue -0.04 -0.02 -0.00 -0.00 0 0 0 0
terrace -2.54 -1.40 -0.28 -0.14 0 0 0 0
terrace_2 0.13 0.07 0.01 0.01 0 0 0 0
terrains -0.20 -0.11 -0.02 -0.01 0 0 0 0
----------------------------------------------------------------------
overall -0.60 -1.16 -1.77 -1.87 -1 0 -1 -1
----------------------------------------------------------------------
average -0.34 -0.58 -0.87 -0.92 0 0 0 0
There was a problem hiding this comment.
Thinking again on it, do we really need to fix the Gauge for the local bundle adjustment? Now we fix three points which can be potentially already constrained by the boundary points in the local BA. This will lead to noise at point fixing.
Also, fixing three points is more likely to introduce noise than fixing two cameras (6 + 1) as it fixed more degrees of freedom (3x3 = 9) than needed, where the three points are very likely starting at a quite noisy initialization.
There was a problem hiding this comment.
If you look at the implementation, it only fixes three points, if not already three other points have been fixed (that have rank 3). In practice, this will basically never fix additional points unless the local bundle is equivalent to the global bundle.
There was a problem hiding this comment.
I see. I missed that. Great then!
There was a problem hiding this comment.
If we wanted to be extra safe, we could fix two cameras when the local bundle contains all images in the beginning? WDYT?
There was a problem hiding this comment.
Yes but I guess it probably does not matter practically though.
IMO it might be already safe to just drop the Gauge in local bundle. I believe it may not affect much the performance there. In my experience even without Gauge fixing in global bundle it generally produces marginal difference (as long as we dont hit numerical issues).
No description provided.