Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose a bundle_adjustment function #146

Merged
merged 5 commits into from
Sep 19, 2023

Conversation

blurgyy
Copy link
Contributor

@blurgyy blurgyy commented Jun 15, 2023

This commit exposes a bundle_adjustment function that has a similar functionality to the command line utility colmap bundle_adjuster. One use case it enables is to allow one use pycolmap to run bundle adjustment after sparse reconstruction to refine the principal point, as jointly refining the principal point1 during sparse reconstruction would make sparse reconstruction on some scenes to fail.

Note that not all available members of ceres::Solver::Options are exposed in this change, but only the ones modified by BundleAdjustmentOptions in colmap2. Besides, the registered CeresSolverOptions uses py::module_local() to avoid conflicts with downstream libraries.

Example usage

from pathlib import Path

import pycolmap

sparse_reconstruction_directory = Path("sparse/0")  # or just `... = "sparse/0"`

ba_opts = {
  "refine_principal_point": True,
  "solver_options": {
    "max_num_iterations": 256,
  },
}

pycolmap.bundle_adjustment(
  input_path=sparse_reconstruction_directory,
  output_path=sparse_reconstruction_directory,
  options=ba_opts,
)

Known problem

Though creating a pycolmap.BundleAdjustmentOptions object with a nested dict works as expected, i.e., the following examples work well:

import pycolmap

ba_opts = pycolmap.BundleAdjustmentOptions({
  "refine_principal_point": True,
  "solver_options": {
    "max_num_iterations": 256,
  },
})
print(ba_opts.todict())  # runs successfully with user-specified option values

ba_opts = pycolmap.BundleAdjustmentOptions({
  refine_principal_point=True,
  solver_options={"max_num_iterations": 256},
})
print(ba_opts.todict())  # runs successfully with user-specified option values

it gives an error while trying to create a
pycolmap.BundleAdjustmentOptions object with its solver_options set to a pycolmap.CeresSolverOptions object, i.e. the following gives an error:

import pycolmap

solver_options = pycolmap.CeresSolverOptions(max_num_iterations=256)
print(solver_options.todict())  # runs successfully with user-specified option values

ba_opts = pycolmap.BundleAdjustmentOptions({
  "refine_principal_point": True,
  "solver_options": solver_options
})  # RuntimeError: instance allocation failed: new instance has no pybind11-registered base types

The "new instance" mentioned in the RuntimeError message probably points to the CeresSolverOptions added in this commit, but I'm not sure about a way to solve this at the moment, plus, as reported above, using dicts to specify the option values works properly and works around this error.

Footnotes

  1. https://colmap.github.io/faq.html#frequently-asked-questions

  2. https://github.com/colmap/colmap/blob/3.8/src/optim/bundle_adjustment.h#L81-L89

blurgyy and others added 5 commits June 15, 2023 16:48
This commit exposes a `bundle_adjustment` function that has a similar
functionality to the command line utility `colmap bundle_adjuster`.  One
use case it enables is to allow one use pycolmap to run bundle
adjustment after sparse reconstruction to refine the principal point, as
jointly refining the principal point[^principal_point_refinement] during
sparse reconstruction would make sparse reconstruction on some scenes to
fail.

Note that not all available members of `ceres::Solver::Options` are
exposed in this change, but only the ones modified by
`BundleAdjustmentOptions` in colmap[^modified_solver_options].  Besides,
the registered `CeresSolverOptions` uses `py::module_local()` to avoid
conflicts with downstream libraries.

Example usage
=============

```python
from pathlib import Path

import pycolmap

sparse_reconstruction_directory = Path("sparse/0")  # or just `... = "sparse/0"`

ba_opts = {
  "refine_principal_point": True,
  "solver_options": {
    "max_num_iterations": 256,
  },
}

pycolmap.bundle_adjustment(
  input_path=sparse_reconstruction_directory,
  output_path=sparse_reconstruction_directory,
  options=ba_opts,
)
```

Known problem
=============

Though creating a `pycolmap.BundleAdjustmentOptions` object with a
nested `dict` works as expected, i.e., the following examples work well:

```python
import pycolmap

ba_opts = pycolmap.BundleAdjustmentOptions({
  "refine_principal_point": True,
  "solver_options": {
    "max_num_iterations": 256,
  },
})
print(ba_opts.todict())  # runs successfully with user-specified option values

ba_opts = pycolmap.BundleAdjustmentOptions({
  refine_principal_point=True,
  solver_options={"max_num_iterations": 256},
})
print(ba_opts.todict())  # runs successfully with user-specified option values
```

it gives an error while trying to create a
`pycolmap.BundleAdjustmentOptions` object with its `solver_options` set
to a `pycolmap.CeresSolverOptions` object, i.e. the following gives an
error:

```python
import pycolmap

solver_options = pycolmap.CeresSolverOptions(max_num_iterations=256)
print(solver_options.todict())  # runs successfully with user-specified option values

ba_opts = pycolmap.BundleAdjustmentOptions({
  "refine_principal_point": True,
  "solver_options": solver_options
})  # RuntimeError: instance allocation failed: new instance has no pybind11-registered base types
```

The "new instance" mentioned in the RuntimeError message probably points
to the `CeresSolverOptions` added in this commit, but I'm not sure about
a way to solve this at the moment, plus, as reported above, using
`dict`s to specify the option values works properly and works around
this error.

[^principal_point_refinement]: <https://colmap.github.io/faq.html#frequently-asked-questions>
[^modified_solver_options]: <https://github.com/colmap/colmap/blob/3.8/src/optim/bundle_adjustment.h#L81-L89>

Signed-off-by: Gaoyang Zhang <gy@blurgy.xyz>
@sarlinpe
Copy link
Collaborator

Thanks! This is most likely a limitation of make_dataclass, we will look into it.

@sarlinpe sarlinpe merged commit 97484c0 into colmap:master Sep 19, 2023
5 checks passed
@blurgyy blurgyy deleted the expose-bundle-adjustment-function branch September 21, 2023 11:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants