8000 Compute residuals with threadpool for model_merger by clementinboittiaux · Pull Request #3401 · colmap/colmap · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Compute residuals with threadpool for model_merger #3401

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

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
170 changes: 105 additions & 65 deletions src/colmap/estimators/alignment.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "colmap/optim/loransac.h"
#include "colmap/scene/projection.h"
#include "colmap/util/logging.h"
#include "colmap/util/threading.h"

#include <unordered_map>

Expand All @@ -49,10 +50,12 @@ struct ReconstructionAlignmentEstimator {

ReconstructionAlignmentEstimator(double max_reproj_error,
const Reconstruction* src_reconstruction,
const Reconstruction* tgt_reconstruction)
const Reconstruction* tgt_reconstruction,
ThreadPool* thread_pool = nullptr)
: max_squared_reproj_error_(max_reproj_error * max_reproj_error),
src_reconstruction_(src_reconstruction),
tgt_reconstruction_(tgt_reconstruction) {
tgt_reconstruction_(tgt_reconstruction),
thread_pool_(thread_pool) {
THROW_CHECK_GE(max_reproj_error, 0);
THROW_CHECK_NOTNULL(src_reconstruction_);
THROW_CHECK_NOTNULL(tgt_reconstruction_);
Expand Down Expand Up @@ -106,78 +109,108 @@ struct ReconstructionAlignmentEstimator {
for (size_t i = 0; i < src_images.size(); ++i) {
const Image& src_image = *src_images[i];
const Image& tgt_image = *tgt_images[i];

THROW_CHECK_EQ(src_image.ImageId(), tgt_image.ImageId());

const Camera& src_camera = *src_image.CameraPtr();
const Camera& tgt_camera = *tgt_image.CameraPtr();

const Eigen::Matrix3x4d src_cam_from_world =
src_image.CamFromWorld().ToMatrix();
const Eigen::Matrix3x4d tgt_cam_from_world =
tgt_image.CamFromWorld().ToMatrix();

THROW_CHECK_EQ(src_image.NumPoints2D(), tgt_image.NumPoints2D());
}

size_t num_inliers = 0;
size_t num_common_points = 0;

for (point2D_t point2D_idx = 0; point2D_idx < src_image.NumPoints2D();
++point2D_idx) {
// Check if both images have a 3D point.

const auto& src_point2D = src_image.Point2D(point2D_idx);
if (!src_point2D.HasPoint3D()) {
continue;
}
if (thread_pool_ && src_images.size() > 10) {
for (size_t i = 0; i < src_images.size(); ++i) {
thread_pool_->AddTask([this,
i,
&src_images,
&tgt_images,
&tgt_from_src,
&src_from_tgt,
residuals]() {
ComputeImageResidual(
i, src_images, tgt_images, tgt_from_src, src_from_tgt, residuals);
});
}
thread_pool_->Wait();
} else {
for (size_t i = 0; i < src_images.size(); ++i) {
ComputeImageResidual(
i, src_images, tgt_images, tgt_from_src, src_from_tgt, residuals);
}
}
}

const auto& tgt_point2D = tgt_image.Point2D(point2D_idx);
if (!tgt_point2D.HasPoint3D()) {
continue;
}
private:
void ComputeImageResidual(size_t i,
const std::vector<X_t>& src_images,
const std::vector<Y_t>& tgt_images,
const M_t& tgt_from_src,
const M_t& src_from_tgt,
std::vector<double>* residuals) const {
const Image& src_image = *src_images[i];
const Image& tgt_image = *tgt_images[i];

const Camera& src_camera = *src_image.CameraPtr();
const Camera& tgt_camera = *tgt_image.CameraPtr();

const Eigen::Matrix3x4d src_cam_from_world =
src_image.CamFromWorld().ToMatrix();
const Eigen::Matrix3x4d tgt_cam_from_world =
tgt_image.CamFromWorld().ToMatrix();

size_t num_inliers = 0;
size_t num_common_points = 0;

for (point2D_t point2D_idx = 0; point2D_idx < src_image.NumPoints2D();
++point2D_idx) {
// Check if both images have a 3D point.

const auto& src_point2D = src_image.Point2D(point2D_idx);
if (!src_point2D.HasPoint3D()) {
continue;
}

num_common_points += 1;

const Eigen::Vector3d src_point_in_tgt =
tgt_from_src *
src_reconstruction_->Point3D(src_point2D.point3D_id).xyz;
if (CalculateSquaredReprojectionError(tgt_point2D.xy,
src_point_in_tgt,
tgt_cam_from_world,
tgt_camera) >
max_squared_reproj_error_) {
continue;
}
const auto& tgt_point2D = tgt_image.Point2D(point2D_idx);
if (!tgt_point2D.HasPoint3D()) {
continue;
}

const Eigen::Vector3d tgt_point_in_src =
src_from_tgt *
tgt_reconstruction_->Point3D(tgt_point2D.point3D_id).xyz;
if (CalculateSquaredReprojectionError(src_point2D.xy,
tgt_point_in_src,
src_cam_from_world,
src_camera) >
max_squared_reproj_error_) {
continue;
}
num_common_points += 1;

num_inliers += 1;
const Eigen::Vector3d src_point_in_tgt =
tgt_from_src *
src_reconstruction_->Point3D(src_point2D.point3D_id).xyz;
if (CalculateSquaredReprojectionError(tgt_point2D.xy,
src_point_in_tgt,
tgt_cam_from_world,
tgt_camera) >
max_squared_reproj_error_) {
continue;
}

if (num_common_points == 0) {
(*residuals)[i] = 1.0;
} else {
const double negative_inlier_ratio =
1.0 - static_cast<double>(num_inliers) /
static_cast<double>(num_common_points);
(*residuals)[i] = negative_inlier_ratio * negative_inlier_ratio;
const Eigen::Vector3d tgt_point_in_src =
src_from_tgt *
tgt_reconstruction_->Point3D(tgt_point2D.point3D_id).xyz;
if (CalculateSquaredReprojectionError(src_point2D.xy,
tgt_point_in_src,
src_cam_from_world,
src_camera) >
max_squared_reproj_error_) {
continue;
}

num_inliers += 1;
}

if (num_common_points == 0) {
(*residuals)[i] = 1.0;
} else {
const double negative_inlier_ratio =
1.0 - static_cast<double>(num_inliers) /
static_cast<double>(num_common_points);
(*residuals)[i] = negative_inlier_ratio * negative_inlier_ratio;
}
}

private:
double max_squared_reproj_error_;
const Reconstruction* src_reconstruction_;
const Reconstruction* tgt_reconstruction_;
ThreadPool* thread_pool_;
};

} // namespace
Expand Down Expand Up @@ -273,7 +306,8 @@ bool AlignReconstructionsViaReprojections(
const Reconstruction& tgt_reconstruction,
const double min_inlier_observations,
const double max_reproj_error,
Sim3d* tgt_from_src) {
Sim3d* tgt_from_src,
ThreadPool* thread_pool) {
THROW_CHECK_GE(min_inlier_observations, 0.0);
THROW_CHECK_LE(min_inlier_observations, 1.0);

Expand All @@ -283,10 +317,14 @@ bool AlignReconstructionsViaReprojections(

LORANSAC<ReconstructionAlignmentEstimator, ReconstructionAlignmentEstimator>
ransac(ransac_options,
ReconstructionAlignmentEstimator(
max_reproj_error, &src_reconstruction, &tgt_reconstruction),
ReconstructionAlignmentEstimator(
max_reproj_error, &src_reconstruction, &tgt_reconstruction));
ReconstructionAlignmentEstimator(max_reproj_error,
&src_reconstruction,
&tgt_reconstruction,
thread_pool),
ReconstructionAlignmentEstimator(max_reproj_error,
&src_reconstruction,
&tgt_reconstruction,
thread_pool));

const std::vector<std::pair<image_t, image_t>> common_image_ids =
src_reconstruction.FindCommonRegImageIds(tgt_reconstruction);
Expand Down Expand Up @@ -462,13 +500,15 @@ void CopyRegisteredImage(image_t image_id,

bool MergeReconstructions(const double max_reproj_error,
const Reconstruction& src_reconstruction,
Reconstruction& tgt_reconstruction) {
Reconstruction& tgt_reconstruction,
ThreadPool* thread_pool) {
Sim3d tgt_from_src;
if (!AlignReconstructionsViaReprojections(src_reconstruction,
tgt_reconstruction,
/*min_inlier_observations=*/0.3,
max_reproj_error,
&tgt_from_src)) {
&tgt_from_src,
thread_pool)) {
return false;
}

Expand Down
8 changes: 6 additions & 2 deletions src/colmap/estimators/alignment.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@

namespace colmap {

class ThreadPool;

// Robustly align reconstruction to given image locations (projection centers).
bool AlignReconstructionToLocations(
const Reconstruction& src_reconstruction,
Expand Down Expand Up @@ -62,7 +64,8 @@ bool AlignReconstructionsViaReprojections(
const Reconstruction& tgt_reconstruction,
double min_inlier_observations,
double max_reproj_error,
Sim3d* tgt_from_src);
Sim3d* tgt_from_src,
ThreadPool* thread_pool = nullptr);

// Robustly compute alignment between reconstructions by finding images that
// are registered in both reconstructions. The alignment is then estimated
Expand Down Expand Up @@ -99,6 +102,7 @@ std::vector<ImageAlignmentError> ComputeImageAlignmentError(
// points3D into the target using the alignment. Returns false on failure.
bool MergeReconstructions(double max_reproj_error,
const Reconstruction& src_reconstruction,
Reconstruction& tgt_reconstruction);
Reconstruction& tgt_reconstruction,
ThreadPool* thread_pool = nullptr);

} // namespace colmap
7 changes: 6 additions & 1 deletion src/colmap/exe/model.cc
Original file line number Diff line number Diff line change
Expand Up @@ -725,14 +725,19 @@ int RunModelMerger(int argc, char** argv) {
std::string input_path2;
std::string output_path;
double max_reproj_error = 64.0;
int num_threads = -1;

OptionManager options;
options.AddRequiredOption("input_path1", &input_path1);
options.AddRequiredOption("input_path2", &input_path2);
options.AddRequiredOption("output_path", &output_path);
options.AddDefaultOption("max_reproj_error", &max_reproj_error);
options.AddDefaultOption("num_threads", &num_threads);
options.Parse(argc, argv);

const int num_effective_threads = GetEffectiveNumThreads(num_threads);
ThreadPool thread_pool(num_effective_threads);

Reconstruction reconstruction1;
reconstruction1.Read(input_path1);
PrintHeading2("Reconstruction 1");
Expand All @@ -747,7 +752,7 @@ int RunModelMerger(int argc, char** argv) {

PrintHeading2("Merging reconstructions");
if (MergeAndFilterReconstructions(
max_reproj_error, reconstruction1, reconstruction2)) {
max_reproj_error, reconstruction1, reconstruction2, &thread_pool)) {
LOG(INFO) << "=> Merge succeeded";
PrintHeading2("Merged reconstruction");
LOG(INFO) << StringPrintf("Images: %d", reconstruction2.NumRegImages());
Expand Down
9 changes: 6 additions & 3 deletions src/colmap/sfm/observation_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,12 @@ namespace colmap {

bool MergeAndFilterReconstructions(const double max_reproj_error,
const Reconstruction& src_reconstruction,
Reconstruction& tgt_reconstruction) {
if (!MergeReconstructions(
max_reproj_error, src_reconstruction, tgt_reconstruction)) {
Reconstruction& tgt_reconstruction,
ThreadPool* thread_pool) {
if (!MergeReconstructions(max_reproj_error,
src_reconstruction,
tgt_reconstruction,
thread_pool)) {
return false;
}
ObservationManager(tgt_reconstruction)
Expand Down
5 changes: 4 additions & 1 deletion src/colmap/sfm/observation_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,12 @@

namespace colmap {

class ThreadPool;

bool MergeAndFilterReconstructions(double max_reproj_error,
const Reconstruction& src_reconstruction,
Reconstruction& tgt_reconstruction);
Reconstruction& tgt_reconstruction,
ThreadPool* thread_pool = nullptr);

class ObservationManager {
public:
Expand Down
0