8000 Customized python interface for bundle adjustment by B1ueber2y · Pull Request #2509 · colmap/colmap · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Customized python interface for bundle adjustment #2509

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

Merged
merged 47 commits into from
May 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
9bc9e20
remove unused teardown for raw bundle adjustment. add some getters.
B1ueber2y Apr 8, 2024
9e72fb0
remove unused line.
B1ueber2y Apr 8, 2024
ad5dccb
restructure bundle adjustment.
B1ueber2y Apr 8, 2024
3f5ec5c
add return value (ceres::Problem) for SetUpProblem.
B1ueber2y Apr 8, 2024
e702175
fix format.
B1ueber2y Apr 8, 2024
31227c2
bind bundle adjustment draft.
B1ueber2y Apr 9, 2024
0361bb7
update. fix local ba.
B1ueber2y Apr 9, 2024
09b5b1f
revert.
B1ueber2y Apr 9, 2024
9c4b850
update pybind to v2.12. fix py::bind_map.
B1ueber2y Apr 9, 2024
e54a158
move the make_opaque for Point3DMap to reconstruction.cc to fix recon…
B1ueber2y Apr 9, 2024
26f61b6
add reconstruction bindings for accessing members directly by id.
B1ueber2y Apr 9, 2024
b6dde46
fix format.
B1ueber2y Apr 9, 2024
8daee6b
minor. 8000
B1ueber2y Apr 11, 2024
962a776
useless fix.
B1ueber2y Apr 11, 2024
9d80081
push debug code.
B1ueber2y Apr 11, 2024
78ccc9b
fix format.
B1ueber2y Apr 11, 2024
dab7fb6
Merge branch 'dev' into features/custom_ba
B1ueber2y Apr 18, 2024
5a128a1
Merge branch 'fix/reconstruction_points3D' into features/custom_ba
B1ueber2y Apr 18, 2024
c4793d9
merge with main.
B1ueber2y Apr 18, 2024
7f168a6
update.
B1ueber2y Apr 20, 2024
209d100
Merge branch 'dev' into features/custom_ba
B1ueber2y Apr 20, 2024
07c676a
update.
B1ueber2y Apr 20, 2024
49020ca
fix formatting.
B1ueber2y Apr 20, 2024
8740cde
update.
B1ueber2y Apr 20, 2024
e4505d6
add minor comment.
B1ueber2y Apr 20, 2024
2276cb7
minor
B1ueber2y Apr 20, 2024
1f8ee80
minor.
B1ueber2y Apr 20, 2024
87dbc11
update.
B1ueber2y Apr 22, 2024
134931c
merge with main.
B1ueber2y Apr 24, 2024
1f7f584
update.
B1ueber2y Apr 24, 2024
214c22f
update,
B1ueber2y Apr 24, 2024
d610896
update. fix performance.
B1ueber2y Apr 24, 2024
517d91e
fixed.
B1ueber2y Apr 24, 2024
58fc7c2
minor.
B1ueber2y Apr 24, 2024
4f0b199
fix formatting.
B1ueber2y Apr 24, 2024
a4012a3
add keep_alive to hold the life of loss.
B1ueber2y Apr 24, 2024
4f020ce
fix formatting.
B1ueber2y Apr 24, 2024
21debe0
Merge branch 'main' into features/custom_ba
B1ueber2y Apr 28, 2024
3e85da7
some updates on syntax.
B1ueber2y Apr 28, 2024
ee810cb
fix formatting.
B1ueber2y Apr 28, 2024
67f61f5
make problem_ a shared pointer rather than unique.
B1ueber2y Apr 28, 2024
2762e59
update.
B1ueber2y Apr 28, 2024
3133c41
change const ref to value for shared_ptr return type
B1ueber2y Apr 28, 2024
edfb040
remove the binding of ceres options from pycolmap.
B1ueber2y Apr 28, 2024
9378633
add minor comments for pyceres.
B1ueber2y Apr 29, 2024
e71d297
minor. add pyceres comments to the head of BA python file
B1ueber2y Apr 29, 2024
5226714
minor + add ceres version string.
B1ueber2y May 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
429 changes: 429 additions & 0 deletions pycolmap/custom_bundle_adjustment.py

Large diffs are not rendered by default.

14 changes: 10 additions & 4 deletions pycolmap/custom_incremental_mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

import pycolmap
from pycolmap import logging
import custom_bundle_adjustment


def extract_colors(image_path, image_id, reconstruction):
Expand All @@ -30,7 +31,9 @@ def write_snapshot(reconstruction, snapshot_path):

def iterative_global_refinement(options, mapper_options, mapper):
logging.info("Retriangulation and Global bundle adjustment")
mapper.iterative_global_refinement(
# The following is equivalent to mapper.iterative_global_refinement(...)
custom_bundle_adjustment.iterative_global_refinement(
mapper,
options.ba_global_max_refinements,
options.ba_global_max_refinement_change,
mapper_options,
Expand Down Expand Up @@ -70,8 +73,9 @@ def initialize_reconstruction(
mapper_options, two_view_geometry, *init_pair
)
logging.info("Global bundle adjustment")
mapper.adjust_global_bundle(
mapper_options, options.get_global_bundle_adjustment()
# The following is equivalent to: mapper.adjust_global_bundle(...)
custom_bundle_adjustment.adjust_global_bundle(
mapper, mapper_options, options.get_global_bundle_adjustment()
)
reconstruction.normalize()
mapper.filter_points(mapper_options)
Expand Down Expand Up @@ -144,7 +148,9 @@ def reconstruct_sub_model(controller, mapper, mapper_options, reconstruction):
break
if reg_next_success:
mapper.triangulate_image(options.get_triangulation(), next_image_id)
mapper.iterative_local_refinement(
# The following is equivalent to mapper.iterative_local_refinement(...)
custom_bundle_adjustment.iterative_local_refinement(
mapper,
options.ba_local_max_refinements,
options.ba_local_max_refinement_change,
mapper_options,
Expand Down
197 changes: 97 additions & 100 deletions src/colmap/estimators/bundle_adjustment.cc
5D39
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,11 @@ bool BundleAdjustmentConfig::HasConstantCamPositions(
constant_cam_positions_.end();
}

const std::unordered_set<camera_t> BundleAdjustmentConfig::ConstantIntrinsics()
const {
return constant_intrinsics_;
}

const std::unordered_set<image_t>& BundleAdjustmentConfig::Images() const {
return image_ids_;
}
Expand All @@ -208,6 +213,11 @@ const std::unordered_set<point3D_t>& BundleAdjustmentConfig::ConstantPoints()
return constant_point3D_ids_;
}

const std::unordered_set<image_t>& BundleAdjustmentConfig::ConstantCamPoses()
const {
return constant_cam_poses_;
}

const std::vector<int>& BundleAdjustmentConfig::ConstantCamPositions(
const image_t image_id) const {
return constant_cam_positions_.at(image_id);
Expand Down Expand Up @@ -256,22 +266,68 @@ BundleAdjuster::BundleAdjuster(const BundleAdjustmentOptions& options,
}

bool BundleAdjuster::Solve(Reconstruction* reconstruction) {
THROW_CHECK_NOTNULL(reconstruction);
THROW_CHECK(!problem_) << "Cannot use the same BundleAdjuster multiple times";

ceres::Problem::Options problem_options;
problem_options.loss_function_ownership = ceres::DO_NOT_TAKE_OWNERSHIP;
problem_ = std::make_unique<ceres::Problem>(problem_options);

const auto loss_function =
std::unique_ptr<ceres::LossFunction>(options_.CreateLossFunction());
SetUp(reconstruction, loss_function.get());
SetUpProblem(reconstruction, loss_function.get());

if (problem_->NumResiduals() == 0) {
return false;
}

ceres::Solver::Options solver_options = options_.solver_options;
ceres::Solver::Options solver_options =
SetUpSolverOptions(*problem_, options_.solver_options);

ceres::Solve(solver_options, problem_.get(), &summary_);

if (options_.print_summary || VLOG_IS_ON(1)) {
PrintSolverSummary(summary_, "Bundle adjustment report");
}

return true;
}

const BundleAdjustmentOptions& BundleAdjuster::Options() const {
return options_;
}

const BundleAdjustmentConfig& BundleAdjuster::Config() const { return config_; }

std::shared_ptr<ceres::Problem> BundleAdjuster::Problem() { return problem_; }

const ceres::Solver::Summary& BundleAdjuster::Summary() const {
return summary_;
}

void BundleAdjuster::SetUpProblem(Reconstruction* reconstruction,
ceres::LossFunction* loss_function) {
THROW_CHECK_NOTNULL(reconstruction);

// Initialize an empty problem
ceres::Problem::Options problem_options;
problem_options.loss_function_ownership = ceres::DO_NOT_TAKE_OWNERSHIP;
problem_ = std::make_shared<ceres::Problem>(problem_options);

// Set up problem
// Warning: AddPointsToProblem assumes that AddImageToProblem is called first.
// Do not change order of instructions!
for (const image_t image_id : config_.Images()) {
AddImageToProblem(image_id, reconstruction, loss_function);
}
for (const auto point3D_id : config_.VariablePoints()) {
AddPointToProblem(point3D_id, reconstruction, loss_function);
}
for (const auto point3D_id : config_.ConstantPoints()) {
AddPointToProblem(point3D_id, reconstruction, loss_function);
}

ParameterizeCameras(reconstruction);
ParameterizePoints(reconstruction);
}

ceres::Solver::Options BundleAdjuster::SetUpSolverOptions(
const ceres::Problem& problem,
const ceres::Solver::Options& input_solver_options) const {
ceres::Solver::Options solver_options = input_solver_options;
const bool has_sparse =
solver_options.sparse_linear_algebra_library_type != ceres::NO_SPARSE;

Expand All @@ -288,8 +344,7 @@ bool BundleAdjuster::Solve(Reconstruction* reconstruction) {
solver_options.preconditioner_type = ceres::SCHUR_JACOBI;
}

if (problem_->NumResiduals() <
options_.min_num_residuals_for_multi_threading) {
if (problem.NumResiduals() < options_.min_num_residuals_for_multi_threading) {
solver_options.num_threads = 1;
#if CERES_VERSION_MAJOR < 2
solver_options.num_linear_solver_threads = 1;
Expand All @@ -305,42 +360,7 @@ bool BundleAdjuster::Solve(Reconstruction* reconstruction) {

std::string solver_error;
THROW_CHECK(solver_options.IsValid(&solver_error)) << solver_error;

ceres::Solve(solver_options, problem_.get(), &summary_);

if (options_.print_summary || VLOG_IS_ON(1)) {
PrintSolverSummary(summary_, "Bundle adjustment report");
}

TearDown(reconstruction);

return true;
}

const ceres::Solver::Summary& BundleAdjuster::Summary() const {
return summary_;
}

void BundleAdjuster::SetUp(Reconstruction* reconstruction,
ceres::LossFunction* loss_function) {
// Warning: AddPointsToProblem assumes that AddImageToProblem is called first.
// Do not change order of instructions!
for (const image_t image_id : config_.Images()) {
AddImageToProblem(image_id, reconstruction, loss_function);
}
for (const auto point3D_id : config_.VariablePoints()) {
AddPointToProblem(point3D_id, reconstruction, loss_function);
}
for (const auto point3D_id : config_.ConstantPoints()) {
AddPointToProblem(point3D_id, reconstruction, loss_function);
}

ParameterizeCameras(reconstruction);
ParameterizePoints(reconstruction);
}

void BundleAdjuster::TearDown(Reconstruction*) {
// Nothing to do
return solver_options;
}

void BundleAdjuster::AddImageToProblem(const image_t image_id,
Expand Down Expand Up @@ -516,9 +536,35 @@ RigBundleAdjuster::RigBundleAdjuster(const BundleAdjustmentOptions& options,

bool RigBundleAdjuster::Solve(Reconstruction* reconstruction,
std::vector<CameraRig>* camera_rigs) {
const auto loss_function =
std::unique_ptr<ceres::LossFunction>(options_.CreateLossFunction());
SetUpProblem(reconstruction, camera_rigs, loss_function.get());

if (problem_->NumResiduals() == 0) {
return false;
}

ceres::Solver::Options solver_options =
SetUpSolverOptions(*problem_, options_.solver_options);

ceres::Solve(solver_options, problem_.get(), &summary_);

if (options_.print_summary || VLOG_IS_ON(1)) {
PrintSolverSummary(summary_, "Rig Bundle adjustment report");
}

TearDown(reconstruction, *camera_rigs);

return true;
}

void RigBundleAdjuster::SetUpProblem(Reconstruction* reconstruction,
std::vector<CameraRig>* camera_rigs,
ceres::LossFunction* loss_function) {
THROW_CHECK_NOTNULL(reconstruction);
THROW_CHECK_NOTNULL(camera_rigs);
THROW_CHECK(!problem_) << "Cannot use the same BundleAdjuster multiple times";
THROW_CHECK(!problem_)
<< "Cannot set up problem from the same BundleAdjuster multiple times";

// Check the validity of the provided camera rigs.
std::unordered_set<camera_t> rig_camera_ids;
Expand All @@ -539,61 +585,12 @@ bool RigBundleAdjuster::Solve(Reconstruction* reconstruction,
}
}

problem_ = std::make_unique<ceres::Problem>();

// Initialize an empty problem
ceres::Problem::Options problem_options;
problem_options.loss_function_ownership = ceres::DO_NOT_TAKE_OWNERSHIP;
problem_ = std::make_unique<ceres::Problem>(problem_options);

const auto loss_function =
std::unique_ptr<ceres::LossFunction>(options_.CreateLossFunction());
SetUp(reconstruction, camera_rigs, loss_function.get());

if (problem_->NumResiduals() == 0) {
return false;
}

ceres::Solver::Options solver_options = options_.solver_options;
const bool has_sparse =
solver_options.sparse_linear_algebra_library_type != ceres::NO_SPARSE;

// Empirical choice.
const size_t kMaxNumImagesDirectDenseSolver = 50;
const size_t kMaxNumImagesDirectSparseSolver = 1000;
const size_t num_images = config_.NumImages();
if (num_images <= kMaxNumImagesDirectDenseSolver) {
solver_options.linear_solver_type = ceres::DENSE_SCHUR;
} else if (num_images <= kMaxNumImagesDirectSparseSolver && has_sparse) {
solver_options.linear_solver_type = ceres::SPARSE_SCHUR;
} else { // Indirect sparse (preconditioned CG) solver.
solver_options.linear_solver_type = ceres::ITERATIVE_SCHUR;
solver_options.preconditioner_type = ceres::SCHUR_JACOBI;
}

solver_options.num_threads =
GetEffectiveNumThreads(solver_options.num_threads);
#if CERES_VERSION_MAJOR < 2
solver_options.num_linear_solver_threads =
GetEffectiveNumThreads(solver_options.num_linear_solver_threads);
#endif // CERES_VERSION_MAJOR

std::string solver_error;
THROW_CHECK(solver_options.IsValid(&solver_error)) << solver_error;

ceres::Solve(solver_options, problem_.get(), &summary_);

if (options_.print_summary || VLOG_IS_ON(1)) {
PrintSolverSummary(summary_, "Rig Bundle adjustment report");
}

TearDown(reconstruction, *camera_rigs);

return true;
}
problem_ = std::make_shared<ceres::Problem>(problem_options);

void RigBundleAdjuster::SetUp(Reconstruction* reconstruction,
std::vector<CameraRig>* camera_rigs,
ceres::LossFunction* loss_function) {
// Set up problem
ComputeCameraRigPoses(*reconstruction, *camera_rigs);

for (const image_t image_id : config_.Images()) {
Expand Down
31 changes: 21 additions & 10 deletions src/colmap/estimators/bundle_adjustment.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,11 @@ class BundleAdjustmentConfig {
void RemoveConstantPoint(point3D_t point3D_id);

// Access configuration data.
const std::unordered_set<camera_t> ConstantIntrinsics() const;
const std::unordered_set<image_t>& Images() const;
const std::unordered_set<point3D_t>& VariablePoints() const;
const std::unordered_set<point3D_t>& ConstantPoints() const;
const std::unordered_set<image_t>& ConstantCamPoses() const;
const std::vector<int>& ConstantCamPositions(image_t image_id) const;

private:
Expand All @@ -170,14 +172,22 @@ class BundleAdjuster {

bool Solve(Reconstruction* reconstruction);

// Get the Ceres solver summary for the last call to `Solve`.
// Set up the problem
void SetUpProblem(Reconstruction* reconstruction,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to pass the reconstruction to the constructor such that it doesn't need to be provided as argument most of its member functions? I can't see any use case where we need to use a different reconstruction between function calls. Maybe for future PRs @ahojnnes

ceres::LossFunction* loss_function);
ceres::Solver::Options SetUpSolverOptions(
const ceres::Problem& problem,
const ceres::Solver::Options& input_solver_options) const;

// Getter functions below
const BundleAdjustmentOptions& Options() const;
const BundleAdjustmentConfig& Config() const;
// Get the Ceres problem after the last call to "set_up"
std::shared_ptr<ceres::Problem> Problem();
// Get the Ceres solver summary after the last call to `Solve`.
const ceres::Solver::Summary& Summary() const;

private:
void SetUp(Reconstruction* reconstruction,
ceres::LossFunction* loss_function);
void TearDown(Reconstruction* reconstruction);

void AddImageToProblem(image_t image_id,
Reconstruction* reconstruction,
ceres::LossFunction* loss_function);
Expand All @@ -192,7 +202,7 @@ class BundleAdjuster {

const BundleAdjustmentOptions options_;
BundleAdjustmentConfig config_;
std::unique_ptr<ceres::Problem> problem_;
std::shared_ptr<ceres::Problem> problem_;
ceres::Solver::Summary summary_;
std::unordered_set<camera_t> camera_ids_;
std::unordered_map<point3D_t, size_t> point3D_num_observations_;
Expand All @@ -219,13 +229,14 @@ class RigBundleAdjuster : public BundleAdjuster {
bool Solve(Reconstruction* reconstruction,
std::vector<CameraRig>* camera_rigs);

private:
void SetUp(Reconstruction* reconstruction,
std::vector<CameraRig>* camera_rigs,
ceres::LossFunction* loss_function);
void SetUpProblem(Reconstruction* reconstruction,
std::vector<CameraRig>* camera_rigs,
ceres::LossFunction* loss_function);

void TearDown(Reconstruction* reconstruction,
const std::vector<CameraRig>& camera_rigs);

private:
void AddImageToProblem(image_t image_id,
Reconstruction* reconstruction,
std::vector<CameraRig>* camera_rigs,
Expand Down
Loading
0