ceres-solver-v2
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .gitattributes +6 -0
- colmap/bin/colmap +3 -0
- colmap/include/colmap/base/camera.h +211 -0
- colmap/include/colmap/base/camera_database.h +58 -0
- colmap/include/colmap/base/camera_models.h +1533 -0
- colmap/include/colmap/base/camera_rig.h +128 -0
- colmap/include/colmap/base/correspondence_graph.h +206 -0
- colmap/include/colmap/base/cost_functions.h +301 -0
- colmap/include/colmap/base/database.h +394 -0
- colmap/include/colmap/base/database_cache.h +151 -0
- colmap/include/colmap/base/essential_matrix.h +160 -0
- colmap/include/colmap/base/gps.h +89 -0
- colmap/include/colmap/base/graph_cut.h +209 -0
- colmap/include/colmap/base/homography_matrix.h +111 -0
- colmap/include/colmap/base/image.h +364 -0
- colmap/include/colmap/base/image_reader.h +133 -0
- colmap/include/colmap/base/line.h +66 -0
- colmap/include/colmap/base/point2d.h +98 -0
- colmap/include/colmap/base/point3d.h +140 -0
- colmap/include/colmap/base/polynomial.h +101 -0
- colmap/include/colmap/base/pose.h +230 -0
- colmap/include/colmap/base/projection.h +167 -0
- colmap/include/colmap/base/reconstruction.h +651 -0
- colmap/include/colmap/base/reconstruction_manager.h +81 -0
- colmap/include/colmap/base/scene_clustering.h +100 -0
- colmap/include/colmap/base/similarity_transform.h +121 -0
- colmap/include/colmap/base/track.h +139 -0
- colmap/include/colmap/base/triangulation.h +118 -0
- colmap/include/colmap/base/undistortion.h +234 -0
- colmap/include/colmap/base/visibility_pyramid.h +104 -0
- colmap/include/colmap/base/warp.h +80 -0
- colmap/include/colmap/controllers/automatic_reconstruction.h +123 -0
- colmap/include/colmap/controllers/bundle_adjustment.h +56 -0
- colmap/include/colmap/controllers/hierarchical_mapper.h +82 -0
- colmap/include/colmap/controllers/incremental_mapper.h +199 -0
- colmap/include/colmap/estimators/absolute_pose.h +182 -0
- colmap/include/colmap/estimators/affine_transform.h +65 -0
- colmap/include/colmap/estimators/coordinate_frame.h +88 -0
- colmap/include/colmap/estimators/essential_matrix.h +127 -0
- colmap/include/colmap/estimators/essential_matrix_coeffs.h +206 -0
- colmap/include/colmap/estimators/essential_matrix_poly.h +0 -0
- colmap/include/colmap/estimators/euclidean_transform.h +56 -0
- colmap/include/colmap/estimators/fundamental_matrix.h +129 -0
- colmap/include/colmap/estimators/generalized_absolute_pose.h +100 -0
- colmap/include/colmap/estimators/generalized_absolute_pose_coeffs.h +44 -0
- colmap/include/colmap/estimators/generalized_relative_pose.h +94 -0
- colmap/include/colmap/estimators/homography_matrix.h +83 -0
- colmap/include/colmap/estimators/pose.h +234 -0
- colmap/include/colmap/estimators/similarity_transform.h +138 -0
- colmap/include/colmap/estimators/translation_transform.h +120 -0
.gitattributes
CHANGED
|
@@ -43,3 +43,9 @@ src/exe/CMakeFiles/colmap_exe.dir/vocab_tree.cc.o filter=lfs diff=lfs merge=lfs
|
|
| 43 |
src/exe/colmap filter=lfs diff=lfs merge=lfs -text
|
| 44 |
src/libcolmap.a filter=lfs diff=lfs merge=lfs -text
|
| 45 |
src/libcolmap_cuda.a filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 43 |
src/exe/colmap filter=lfs diff=lfs merge=lfs -text
|
| 44 |
src/libcolmap.a filter=lfs diff=lfs merge=lfs -text
|
| 45 |
src/libcolmap_cuda.a filter=lfs diff=lfs merge=lfs -text
|
| 46 |
+
colmap/bin/colmap filter=lfs diff=lfs merge=lfs -text
|
| 47 |
+
colmap/lib/libcolmap.a filter=lfs diff=lfs merge=lfs -text
|
| 48 |
+
colmap/lib/libcolmap_cuda.a filter=lfs diff=lfs merge=lfs -text
|
| 49 |
+
colmap/lib/libpba.a filter=lfs diff=lfs merge=lfs -text
|
| 50 |
+
colmap/lib/libpoisson_recon.a filter=lfs diff=lfs merge=lfs -text
|
| 51 |
+
colmap/lib/libsift_gpu.a filter=lfs diff=lfs merge=lfs -text
|
colmap/bin/colmap
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:9efc313d53067e8a32ff66555e20318dc8382bd06ccc9ea769440f20da5d74be
|
| 3 |
+
size 31933416
|
colmap/include/colmap/base/camera.h
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_BASE_CAMERA_H_
|
| 33 |
+
#define COLMAP_SRC_BASE_CAMERA_H_
|
| 34 |
+
|
| 35 |
+
#include <vector>
|
| 36 |
+
|
| 37 |
+
#include "util/types.h"
|
| 38 |
+
|
| 39 |
+
namespace colmap {
|
| 40 |
+
|
| 41 |
+
// Camera class that holds the intrinsic parameters. Cameras may be shared
|
| 42 |
+
// between multiple images, e.g., if the same "physical" camera took multiple
|
| 43 |
+
// pictures with the exact same lens and intrinsics (focal length, etc.).
|
| 44 |
+
// This class has a specific distortion model defined by a camera model class.
|
| 45 |
+
class Camera {
|
| 46 |
+
public:
|
| 47 |
+
Camera();
|
| 48 |
+
|
| 49 |
+
// Access the unique identifier of the camera.
|
| 50 |
+
inline camera_t CameraId() const;
|
| 51 |
+
inline void SetCameraId(const camera_t camera_id);
|
| 52 |
+
|
| 53 |
+
// Access the camera model.
|
| 54 |
+
inline int ModelId() const;
|
| 55 |
+
std::string ModelName() const;
|
| 56 |
+
void SetModelId(const int model_id);
|
| 57 |
+
void SetModelIdFromName(const std::string& model_name);
|
| 58 |
+
|
| 59 |
+
// Access dimensions of the camera sensor.
|
| 60 |
+
inline size_t Width() const;
|
| 61 |
+
inline size_t Height() const;
|
| 62 |
+
inline void SetWidth(const size_t width);
|
| 63 |
+
inline void SetHeight(const size_t height);
|
| 64 |
+
|
| 65 |
+
// Access focal length parameters.
|
| 66 |
+
double MeanFocalLength() const;
|
| 67 |
+
double FocalLength() const;
|
| 68 |
+
double FocalLengthX() const;
|
| 69 |
+
double FocalLengthY() const;
|
| 70 |
+
void SetFocalLength(const double focal_length);
|
| 71 |
+
void SetFocalLengthX(const double focal_length_x);
|
| 72 |
+
void SetFocalLengthY(const double focal_length_y);
|
| 73 |
+
|
| 74 |
+
// Check if camera has prior focal length.
|
| 75 |
+
inline bool HasPriorFocalLength() const;
|
| 76 |
+
inline void SetPriorFocalLength(const bool prior);
|
| 77 |
+
|
| 78 |
+
// Access principal point parameters. Only works if there are two
|
| 79 |
+
// principal point parameters.
|
| 80 |
+
double PrincipalPointX() const;
|
| 81 |
+
double PrincipalPointY() const;
|
| 82 |
+
void SetPrincipalPointX(const double ppx);
|
| 83 |
+
void SetPrincipalPointY(const double ppy);
|
| 84 |
+
|
| 85 |
+
// Get the indices of the parameter groups in the parameter vector.
|
| 86 |
+
const std::vector<size_t>& FocalLengthIdxs() const;
|
| 87 |
+
const std::vector<size_t>& PrincipalPointIdxs() const;
|
| 88 |
+
const std::vector<size_t>& ExtraParamsIdxs() const;
|
| 89 |
+
|
| 90 |
+
// Get intrinsic calibration matrix composed from focal length and principal
|
| 91 |
+
// point parameters, excluding distortion parameters.
|
| 92 |
+
Eigen::Matrix3d CalibrationMatrix() const;
|
| 93 |
+
|
| 94 |
+
// Get human-readable information about the parameter vector ordering.
|
| 95 |
+
std::string ParamsInfo() const;
|
| 96 |
+
|
| 97 |
+
// Access the raw parameter vector.
|
| 98 |
+
inline size_t NumParams() const;
|
| 99 |
+
inline const std::vector<double>& Params() const;
|
| 100 |
+
inline std::vector<double>& Params();
|
| 101 |
+
inline double Params(const size_t idx) const;
|
| 102 |
+
inline double& Params(const size_t idx);
|
| 103 |
+
inline const double* ParamsData() const;
|
| 104 |
+
inline double* ParamsData();
|
| 105 |
+
inline void SetParams(const std::vector<double>& params);
|
| 106 |
+
|
| 107 |
+
// Concatenate parameters as comma-separated list.
|
| 108 |
+
std::string ParamsToString() const;
|
| 109 |
+
|
| 110 |
+
// Set camera parameters from comma-separated list.
|
| 111 |
+
bool SetParamsFromString(const std::string& string);
|
| 112 |
+
|
| 113 |
+
// Check whether parameters are valid, i.e. the parameter vector has
|
| 114 |
+
// the correct dimensions that match the specified camera model.
|
| 115 |
+
bool VerifyParams() const;
|
| 116 |
+
|
| 117 |
+
// Check whether camera is already undistorted
|
| 118 |
+
bool IsUndistorted() const;
|
| 119 |
+
|
| 120 |
+
// Check whether camera has bogus parameters.
|
| 121 |
+
bool HasBogusParams(const double min_focal_length_ratio,
|
| 122 |
+
const double max_focal_length_ratio,
|
| 123 |
+
const double max_extra_param) const;
|
| 124 |
+
|
| 125 |
+
// Initialize parameters for given camera model and focal length, and set
|
| 126 |
+
// the principal point to be the image center.
|
| 127 |
+
void InitializeWithId(const int model_id, const double focal_length,
|
| 128 |
+
const size_t width, const size_t height);
|
| 129 |
+
void InitializeWithName(const std::string& model_name,
|
| 130 |
+
const double focal_length, const size_t width,
|
| 131 |
+
const size_t height);
|
| 132 |
+
|
| 133 |
+
// Project point in image plane to world / infinity.
|
| 134 |
+
Eigen::Vector2d ImageToWorld(const Eigen::Vector2d& image_point) const;
|
| 135 |
+
|
| 136 |
+
// Convert pixel threshold in image plane to world space.
|
| 137 |
+
double ImageToWorldThreshold(const double threshold) const;
|
| 138 |
+
|
| 139 |
+
// Project point from world / infinity to image plane.
|
| 140 |
+
Eigen::Vector2d WorldToImage(const Eigen::Vector2d& world_point) const;
|
| 141 |
+
|
| 142 |
+
// Rescale camera dimensions and accordingly the focal length and
|
| 143 |
+
// and the principal point.
|
| 144 |
+
void Rescale(const double scale);
|
| 145 |
+
void Rescale(const size_t width, const size_t height);
|
| 146 |
+
|
| 147 |
+
private:
|
| 148 |
+
// The unique identifier of the camera. If the identifier is not specified
|
| 149 |
+
// it is set to `kInvalidCameraId`.
|
| 150 |
+
camera_t camera_id_;
|
| 151 |
+
|
| 152 |
+
// The identifier of the camera model. If the camera model is not specified
|
| 153 |
+
// the identifier is `kInvalidCameraModelId`.
|
| 154 |
+
int model_id_;
|
| 155 |
+
|
| 156 |
+
// The dimensions of the image, 0 if not initialized.
|
| 157 |
+
size_t width_;
|
| 158 |
+
size_t height_;
|
| 159 |
+
|
| 160 |
+
// The focal length, principal point, and extra parameters. If the camera
|
| 161 |
+
// model is not specified, this vector is empty.
|
| 162 |
+
std::vector<double> params_;
|
| 163 |
+
|
| 164 |
+
// Whether there is a safe prior for the focal length,
|
| 165 |
+
// e.g. manually provided or extracted from EXIF
|
| 166 |
+
bool prior_focal_length_;
|
| 167 |
+
};
|
| 168 |
+
|
| 169 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 170 |
+
// Implementation
|
| 171 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 172 |
+
|
| 173 |
+
camera_t Camera::CameraId() const { return camera_id_; }
|
| 174 |
+
|
| 175 |
+
void Camera::SetCameraId(const camera_t camera_id) { camera_id_ = camera_id; }
|
| 176 |
+
|
| 177 |
+
int Camera::ModelId() const { return model_id_; }
|
| 178 |
+
|
| 179 |
+
size_t Camera::Width() const { return width_; }
|
| 180 |
+
|
| 181 |
+
size_t Camera::Height() const { return height_; }
|
| 182 |
+
|
| 183 |
+
void Camera::SetWidth(const size_t width) { width_ = width; }
|
| 184 |
+
|
| 185 |
+
void Camera::SetHeight(const size_t height) { height_ = height; }
|
| 186 |
+
|
| 187 |
+
bool Camera::HasPriorFocalLength() const { return prior_focal_length_; }
|
| 188 |
+
|
| 189 |
+
void Camera::SetPriorFocalLength(const bool prior) {
|
| 190 |
+
prior_focal_length_ = prior;
|
| 191 |
+
}
|
| 192 |
+
|
| 193 |
+
size_t Camera::NumParams() const { return params_.size(); }
|
| 194 |
+
|
| 195 |
+
const std::vector<double>& Camera::Params() const { return params_; }
|
| 196 |
+
|
| 197 |
+
std::vector<double>& Camera::Params() { return params_; }
|
| 198 |
+
|
| 199 |
+
double Camera::Params(const size_t idx) const { return params_[idx]; }
|
| 200 |
+
|
| 201 |
+
double& Camera::Params(const size_t idx) { return params_[idx]; }
|
| 202 |
+
|
| 203 |
+
const double* Camera::ParamsData() const { return params_.data(); }
|
| 204 |
+
|
| 205 |
+
double* Camera::ParamsData() { return params_.data(); }
|
| 206 |
+
|
| 207 |
+
void Camera::SetParams(const std::vector<double>& params) { params_ = params; }
|
| 208 |
+
|
| 209 |
+
} // namespace colmap
|
| 210 |
+
|
| 211 |
+
#endif // COLMAP_SRC_BASE_CAMERA_H_
|
colmap/include/colmap/base/camera_database.h
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_BASE_CAMERA_DATABASE_H_
|
| 33 |
+
#define COLMAP_SRC_BASE_CAMERA_DATABASE_H_
|
| 34 |
+
|
| 35 |
+
#include <string>
|
| 36 |
+
|
| 37 |
+
#include "util/camera_specs.h"
|
| 38 |
+
|
| 39 |
+
namespace colmap {
|
| 40 |
+
|
| 41 |
+
// Database that contains sensor widths for many cameras, which is useful
|
| 42 |
+
// to automatically extract the focal length if EXIF information is incomplete.
|
| 43 |
+
class CameraDatabase {
|
| 44 |
+
public:
|
| 45 |
+
CameraDatabase();
|
| 46 |
+
|
| 47 |
+
size_t NumEntries() const { return specs_.size(); }
|
| 48 |
+
|
| 49 |
+
bool QuerySensorWidth(const std::string& make, const std::string& model,
|
| 50 |
+
double* sensor_width);
|
| 51 |
+
|
| 52 |
+
private:
|
| 53 |
+
static const camera_specs_t specs_;
|
| 54 |
+
};
|
| 55 |
+
|
| 56 |
+
} // namespace colmap
|
| 57 |
+
|
| 58 |
+
#endif // COLMAP_SRC_BASE_CAMERA_DATABASE_H_
|
colmap/include/colmap/base/camera_models.h
ADDED
|
@@ -0,0 +1,1533 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_BASE_CAMERA_MODELS_H_
|
| 33 |
+
#define COLMAP_SRC_BASE_CAMERA_MODELS_H_
|
| 34 |
+
|
| 35 |
+
#include <cfloat>
|
| 36 |
+
#include <string>
|
| 37 |
+
#include <vector>
|
| 38 |
+
|
| 39 |
+
#include <Eigen/Core>
|
| 40 |
+
#include <Eigen/Dense>
|
| 41 |
+
|
| 42 |
+
#include <ceres/ceres.h>
|
| 43 |
+
|
| 44 |
+
namespace colmap {
|
| 45 |
+
|
| 46 |
+
// This file defines several different camera models and arbitrary new camera
|
| 47 |
+
// models can be added by the following steps:
|
| 48 |
+
//
|
| 49 |
+
// 1. Add a new struct in this file which implements all the necessary methods.
|
| 50 |
+
// 2. Define an unique model_name and model_id for the camera model.
|
| 51 |
+
// 3. Add camera model to `CAMERA_MODEL_CASES` macro in this file.
|
| 52 |
+
// 4. Add new template specialization of test case for camera model to
|
| 53 |
+
// `camera_models_test.cc`.
|
| 54 |
+
//
|
| 55 |
+
// A camera model can have three different types of camera parameters: focal
|
| 56 |
+
// length, principal point, extra parameters (distortion parameters). The
|
| 57 |
+
// parameter array is split into different groups, so that we can enable or
|
| 58 |
+
// disable the refinement of the individual groups during bundle adjustment. It
|
| 59 |
+
// is up to the camera model to access the parameters correctly (it is free to
|
| 60 |
+
// do so in an arbitrary manner) - the parameters are not accessed from outside.
|
| 61 |
+
//
|
| 62 |
+
// A camera model must have the following methods:
|
| 63 |
+
//
|
| 64 |
+
// - `WorldToImage`: transform normalized camera coordinates to image
|
| 65 |
+
// coordinates (the inverse of `ImageToWorld`). Assumes that the world
|
| 66 |
+
// coordinates are given as (u, v, 1).
|
| 67 |
+
// - `ImageToWorld`: transform image coordinates to normalized camera
|
| 68 |
+
// coordinates (the inverse of `WorldToImage`). Produces world coordinates
|
| 69 |
+
// as (u, v, 1).
|
| 70 |
+
// - `ImageToWorldThreshold`: transform a threshold given in pixels to
|
| 71 |
+
// normalized units (e.g. useful for reprojection error thresholds).
|
| 72 |
+
//
|
| 73 |
+
// Whenever you specify the camera parameters in a list, they must appear
|
| 74 |
+
// exactly in the order as they are accessed in the defined model struct.
|
| 75 |
+
//
|
| 76 |
+
// The camera models follow the convention that the upper left image corner has
|
| 77 |
+
// the coordinate (0, 0), the lower right corner (width, height), i.e. that
|
| 78 |
+
// the upper left pixel center has coordinate (0.5, 0.5) and the lower right
|
| 79 |
+
// pixel center has the coordinate (width - 0.5, height - 0.5).
|
| 80 |
+
|
| 81 |
+
static const int kInvalidCameraModelId = -1;
|
| 82 |
+
|
| 83 |
+
#ifndef CAMERA_MODEL_DEFINITIONS
|
| 84 |
+
#define CAMERA_MODEL_DEFINITIONS(model_id_value, model_name_value, \
|
| 85 |
+
num_params_value) \
|
| 86 |
+
static const int kModelId = model_id_value; \
|
| 87 |
+
static const size_t kNumParams = num_params_value; \
|
| 88 |
+
static const int model_id; \
|
| 89 |
+
static const std::string model_name; \
|
| 90 |
+
static const size_t num_params; \
|
| 91 |
+
static const std::string params_info; \
|
| 92 |
+
static const std::vector<size_t> focal_length_idxs; \
|
| 93 |
+
static const std::vector<size_t> principal_point_idxs; \
|
| 94 |
+
static const std::vector<size_t> extra_params_idxs; \
|
| 95 |
+
\
|
| 96 |
+
static inline int InitializeModelId() { return model_id_value; }; \
|
| 97 |
+
static inline std::string InitializeModelName() { \
|
| 98 |
+
return model_name_value; \
|
| 99 |
+
}; \
|
| 100 |
+
static inline size_t InitializeNumParams() { return num_params_value; }; \
|
| 101 |
+
static inline std::string InitializeParamsInfo(); \
|
| 102 |
+
static inline std::vector<size_t> InitializeFocalLengthIdxs(); \
|
| 103 |
+
static inline std::vector<size_t> InitializePrincipalPointIdxs(); \
|
| 104 |
+
static inline std::vector<size_t> InitializeExtraParamsIdxs(); \
|
| 105 |
+
static inline std::vector<double> InitializeParams( \
|
| 106 |
+
const double focal_length, const size_t width, const size_t height); \
|
| 107 |
+
\
|
| 108 |
+
template <typename T> \
|
| 109 |
+
static void WorldToImage(const T* params, const T u, const T v, T* x, T* y); \
|
| 110 |
+
template <typename T> \
|
| 111 |
+
static void ImageToWorld(const T* params, const T x, const T y, T* u, T* v); \
|
| 112 |
+
template <typename T> \
|
| 113 |
+
static void Distortion(const T* extra_params, const T u, const T v, T* du, \
|
| 114 |
+
T* dv);
|
| 115 |
+
#endif
|
| 116 |
+
|
| 117 |
+
#ifndef CAMERA_MODEL_CASES
|
| 118 |
+
#define CAMERA_MODEL_CASES \
|
| 119 |
+
CAMERA_MODEL_CASE(SimplePinholeCameraModel) \
|
| 120 |
+
CAMERA_MODEL_CASE(PinholeCameraModel) \
|
| 121 |
+
CAMERA_MODEL_CASE(SimpleRadialCameraModel) \
|
| 122 |
+
CAMERA_MODEL_CASE(SimpleRadialFisheyeCameraModel) \
|
| 123 |
+
CAMERA_MODEL_CASE(RadialCameraModel) \
|
| 124 |
+
CAMERA_MODEL_CASE(RadialFisheyeCameraModel) \
|
| 125 |
+
CAMERA_MODEL_CASE(OpenCVCameraModel) \
|
| 126 |
+
CAMERA_MODEL_CASE(OpenCVFisheyeCameraModel) \
|
| 127 |
+
CAMERA_MODEL_CASE(FullOpenCVCameraModel) \
|
| 128 |
+
CAMERA_MODEL_CASE(FOVCameraModel) \
|
| 129 |
+
CAMERA_MODEL_CASE(ThinPrismFisheyeCameraModel)
|
| 130 |
+
#endif
|
| 131 |
+
|
| 132 |
+
#ifndef CAMERA_MODEL_SWITCH_CASES
|
| 133 |
+
#define CAMERA_MODEL_SWITCH_CASES \
|
| 134 |
+
CAMERA_MODEL_CASES \
|
| 135 |
+
default: \
|
| 136 |
+
CAMERA_MODEL_DOES_NOT_EXIST_EXCEPTION \
|
| 137 |
+
break;
|
| 138 |
+
#endif
|
| 139 |
+
|
| 140 |
+
#define CAMERA_MODEL_DOES_NOT_EXIST_EXCEPTION \
|
| 141 |
+
throw std::domain_error("Camera model does not exist");
|
| 142 |
+
|
| 143 |
+
// The "Curiously Recurring Template Pattern" (CRTP) is used here, so that we
|
| 144 |
+
// can reuse some shared functionality between all camera models -
|
| 145 |
+
// defined in the BaseCameraModel.
|
| 146 |
+
template <typename CameraModel>
|
| 147 |
+
struct BaseCameraModel {
|
| 148 |
+
template <typename T>
|
| 149 |
+
static inline bool HasBogusParams(const std::vector<T>& params,
|
| 150 |
+
const size_t width, const size_t height,
|
| 151 |
+
const T min_focal_length_ratio,
|
| 152 |
+
const T max_focal_length_ratio,
|
| 153 |
+
const T max_extra_param);
|
| 154 |
+
|
| 155 |
+
template <typename T>
|
| 156 |
+
static inline bool HasBogusFocalLength(const std::vector<T>& params,
|
| 157 |
+
const size_t width,
|
| 158 |
+
const size_t height,
|
| 159 |
+
const T min_focal_length_ratio,
|
| 160 |
+
const T max_focal_length_ratio);
|
| 161 |
+
|
| 162 |
+
template <typename T>
|
| 163 |
+
static inline bool HasBogusPrincipalPoint(const std::vector<T>& params,
|
| 164 |
+
const size_t width,
|
| 165 |
+
const size_t height);
|
| 166 |
+
|
| 167 |
+
template <typename T>
|
| 168 |
+
static inline bool HasBogusExtraParams(const std::vector<T>& params,
|
| 169 |
+
const T max_extra_param);
|
| 170 |
+
|
| 171 |
+
template <typename T>
|
| 172 |
+
static inline T ImageToWorldThreshold(const T* params, const T threshold);
|
| 173 |
+
|
| 174 |
+
template <typename T>
|
| 175 |
+
static inline void IterativeUndistortion(const T* params, T* u, T* v);
|
| 176 |
+
};
|
| 177 |
+
|
| 178 |
+
// Simple Pinhole camera model.
|
| 179 |
+
//
|
| 180 |
+
// No Distortion is assumed. Only focal length and principal point is modeled.
|
| 181 |
+
//
|
| 182 |
+
// Parameter list is expected in the following order:
|
| 183 |
+
//
|
| 184 |
+
// f, cx, cy
|
| 185 |
+
//
|
| 186 |
+
// See https://en.wikipedia.org/wiki/Pinhole_camera_model
|
| 187 |
+
struct SimplePinholeCameraModel
|
| 188 |
+
: public BaseCameraModel<SimplePinholeCameraModel> {
|
| 189 |
+
CAMERA_MODEL_DEFINITIONS(0, "SIMPLE_PINHOLE", 3)
|
| 190 |
+
};
|
| 191 |
+
|
| 192 |
+
// Pinhole camera model.
|
| 193 |
+
//
|
| 194 |
+
// No Distortion is assumed. Only focal length and principal point is modeled.
|
| 195 |
+
//
|
| 196 |
+
// Parameter list is expected in the following order:
|
| 197 |
+
//
|
| 198 |
+
// fx, fy, cx, cy
|
| 199 |
+
//
|
| 200 |
+
// See https://en.wikipedia.org/wiki/Pinhole_camera_model
|
| 201 |
+
struct PinholeCameraModel : public BaseCameraModel<PinholeCameraModel> {
|
| 202 |
+
CAMERA_MODEL_DEFINITIONS(1, "PINHOLE", 4)
|
| 203 |
+
};
|
| 204 |
+
|
| 205 |
+
// Simple camera model with one focal length and one radial distortion
|
| 206 |
+
// parameter.
|
| 207 |
+
//
|
| 208 |
+
// This model is similar to the camera model that VisualSfM uses with the
|
| 209 |
+
// difference that the distortion here is applied to the projections and
|
| 210 |
+
// not to the measurements.
|
| 211 |
+
//
|
| 212 |
+
// Parameter list is expected in the following order:
|
| 213 |
+
//
|
| 214 |
+
// f, cx, cy, k
|
| 215 |
+
//
|
| 216 |
+
struct SimpleRadialCameraModel
|
| 217 |
+
: public BaseCameraModel<SimpleRadialCameraModel> {
|
| 218 |
+
CAMERA_MODEL_DEFINITIONS(2, "SIMPLE_RADIAL", 4)
|
| 219 |
+
};
|
| 220 |
+
|
| 221 |
+
// Simple camera model with one focal length and two radial distortion
|
| 222 |
+
// parameters.
|
| 223 |
+
//
|
| 224 |
+
// This model is equivalent to the camera model that Bundler uses
|
| 225 |
+
// (except for an inverse z-axis in the camera coordinate system).
|
| 226 |
+
//
|
| 227 |
+
// Parameter list is expected in the following order:
|
| 228 |
+
//
|
| 229 |
+
// f, cx, cy, k1, k2
|
| 230 |
+
//
|
| 231 |
+
struct RadialCameraModel : public BaseCameraModel<RadialCameraModel> {
|
| 232 |
+
CAMERA_MODEL_DEFINITIONS(3, "RADIAL", 5)
|
| 233 |
+
};
|
| 234 |
+
|
| 235 |
+
// OpenCV camera model.
|
| 236 |
+
//
|
| 237 |
+
// Based on the pinhole camera model. Additionally models radial and
|
| 238 |
+
// tangential distortion (up to 2nd degree of coefficients). Not suitable for
|
| 239 |
+
// large radial distortions of fish-eye cameras.
|
| 240 |
+
//
|
| 241 |
+
// Parameter list is expected in the following order:
|
| 242 |
+
//
|
| 243 |
+
// fx, fy, cx, cy, k1, k2, p1, p2
|
| 244 |
+
//
|
| 245 |
+
// See
|
| 246 |
+
// http://docs.opencv.org/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html
|
| 247 |
+
struct OpenCVCameraModel : public BaseCameraModel<OpenCVCameraModel> {
|
| 248 |
+
CAMERA_MODEL_DEFINITIONS(4, "OPENCV", 8)
|
| 249 |
+
};
|
| 250 |
+
|
| 251 |
+
// OpenCV fish-eye camera model.
|
| 252 |
+
//
|
| 253 |
+
// Based on the pinhole camera model. Additionally models radial and
|
| 254 |
+
// tangential Distortion (up to 2nd degree of coefficients). Suitable for
|
| 255 |
+
// large radial distortions of fish-eye cameras.
|
| 256 |
+
//
|
| 257 |
+
// Parameter list is expected in the following order:
|
| 258 |
+
//
|
| 259 |
+
// fx, fy, cx, cy, k1, k2, k3, k4
|
| 260 |
+
//
|
| 261 |
+
// See
|
| 262 |
+
// http://docs.opencv.org/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html
|
| 263 |
+
struct OpenCVFisheyeCameraModel
|
| 264 |
+
: public BaseCameraModel<OpenCVFisheyeCameraModel> {
|
| 265 |
+
CAMERA_MODEL_DEFINITIONS(5, "OPENCV_FISHEYE", 8)
|
| 266 |
+
};
|
| 267 |
+
|
| 268 |
+
// Full OpenCV camera model.
|
| 269 |
+
//
|
| 270 |
+
// Based on the pinhole camera model. Additionally models radial and
|
| 271 |
+
// tangential Distortion.
|
| 272 |
+
//
|
| 273 |
+
// Parameter list is expected in the following order:
|
| 274 |
+
//
|
| 275 |
+
// fx, fy, cx, cy, k1, k2, p1, p2, k3, k4, k5, k6
|
| 276 |
+
//
|
| 277 |
+
// See
|
| 278 |
+
// http://docs.opencv.org/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html
|
| 279 |
+
struct FullOpenCVCameraModel : public BaseCameraModel<FullOpenCVCameraModel> {
|
| 280 |
+
CAMERA_MODEL_DEFINITIONS(6, "FULL_OPENCV", 12)
|
| 281 |
+
};
|
| 282 |
+
|
| 283 |
+
// FOV camera model.
|
| 284 |
+
//
|
| 285 |
+
// Based on the pinhole camera model. Additionally models radial distortion.
|
| 286 |
+
// This model is for example used by Project Tango for its equidistant
|
| 287 |
+
// calibration type.
|
| 288 |
+
//
|
| 289 |
+
// Parameter list is expected in the following order:
|
| 290 |
+
//
|
| 291 |
+
// fx, fy, cx, cy, omega
|
| 292 |
+
//
|
| 293 |
+
// See:
|
| 294 |
+
// Frederic Devernay, Olivier Faugeras. Straight lines have to be straight:
|
| 295 |
+
// Automatic calibration and removal of distortion from scenes of structured
|
| 296 |
+
// environments. Machine vision and applications, 2001.
|
| 297 |
+
struct FOVCameraModel : public BaseCameraModel<FOVCameraModel> {
|
| 298 |
+
CAMERA_MODEL_DEFINITIONS(7, "FOV", 5)
|
| 299 |
+
|
| 300 |
+
template <typename T>
|
| 301 |
+
static void Undistortion(const T* extra_params, const T u, const T v, T* du,
|
| 302 |
+
T* dv);
|
| 303 |
+
};
|
| 304 |
+
|
| 305 |
+
// Simple camera model with one focal length and one radial distortion
|
| 306 |
+
// parameter, suitable for fish-eye cameras.
|
| 307 |
+
//
|
| 308 |
+
// This model is equivalent to the OpenCVFisheyeCameraModel but has only one
|
| 309 |
+
// radial distortion coefficient.
|
| 310 |
+
//
|
| 311 |
+
// Parameter list is expected in the following order:
|
| 312 |
+
//
|
| 313 |
+
// f, cx, cy, k
|
| 314 |
+
//
|
| 315 |
+
struct SimpleRadialFisheyeCameraModel
|
| 316 |
+
: public BaseCameraModel<SimpleRadialFisheyeCameraModel> {
|
| 317 |
+
CAMERA_MODEL_DEFINITIONS(8, "SIMPLE_RADIAL_FISHEYE", 4)
|
| 318 |
+
};
|
| 319 |
+
|
| 320 |
+
// Simple camera model with one focal length and two radial distortion
|
| 321 |
+
// parameters, suitable for fish-eye cameras.
|
| 322 |
+
//
|
| 323 |
+
// This model is equivalent to the OpenCVFisheyeCameraModel but has only two
|
| 324 |
+
// radial distortion coefficients.
|
| 325 |
+
//
|
| 326 |
+
// Parameter list is expected in the following order:
|
| 327 |
+
//
|
| 328 |
+
// f, cx, cy, k1, k2
|
| 329 |
+
//
|
| 330 |
+
struct RadialFisheyeCameraModel
|
| 331 |
+
: public BaseCameraModel<RadialFisheyeCameraModel> {
|
| 332 |
+
CAMERA_MODEL_DEFINITIONS(9, "RADIAL_FISHEYE", 5)
|
| 333 |
+
};
|
| 334 |
+
|
| 335 |
+
// Camera model with radial and tangential distortion coefficients and
|
| 336 |
+
// additional coefficients accounting for thin-prism distortion.
|
| 337 |
+
//
|
| 338 |
+
// This camera model is described in
|
| 339 |
+
//
|
| 340 |
+
// "Camera Calibration with Distortion Models and Accuracy Evaluation",
|
| 341 |
+
// J Weng et al., TPAMI, 1992.
|
| 342 |
+
//
|
| 343 |
+
// Parameter list is expected in the following order:
|
| 344 |
+
//
|
| 345 |
+
// fx, fy, cx, cy, k1, k2, p1, p2, k3, k4, sx1, sy1
|
| 346 |
+
//
|
| 347 |
+
struct ThinPrismFisheyeCameraModel
|
| 348 |
+
: public BaseCameraModel<ThinPrismFisheyeCameraModel> {
|
| 349 |
+
CAMERA_MODEL_DEFINITIONS(10, "THIN_PRISM_FISHEYE", 12)
|
| 350 |
+
};
|
| 351 |
+
|
| 352 |
+
// Check whether camera model with given name or identifier exists.
|
| 353 |
+
bool ExistsCameraModelWithName(const std::string& model_name);
|
| 354 |
+
bool ExistsCameraModelWithId(const int model_id);
|
| 355 |
+
|
| 356 |
+
// Convert camera name to unique camera model identifier.
|
| 357 |
+
//
|
| 358 |
+
// @param name Unique name of camera model.
|
| 359 |
+
//
|
| 360 |
+
// @return Unique identifier of camera model.
|
| 361 |
+
int CameraModelNameToId(const std::string& model_name);
|
| 362 |
+
|
| 363 |
+
// Convert camera model identifier to unique camera model name.
|
| 364 |
+
//
|
| 365 |
+
// @param model_id Unique identifier of camera model.
|
| 366 |
+
//
|
| 367 |
+
// @return Unique name of camera model.
|
| 368 |
+
std::string CameraModelIdToName(const int model_id);
|
| 369 |
+
|
| 370 |
+
// Initialize camera parameters using given image properties.
|
| 371 |
+
//
|
| 372 |
+
// Initializes all focal length parameters to the same given focal length and
|
| 373 |
+
// sets the principal point to the image center.
|
| 374 |
+
//
|
| 375 |
+
// @param model_id Unique identifier of camera model.
|
| 376 |
+
// @param focal_length Focal length, equal for all focal length parameters.
|
| 377 |
+
// @param width Sensor width of the camera.
|
| 378 |
+
// @param height Sensor height of the camera.
|
| 379 |
+
std::vector<double> CameraModelInitializeParams(const int model_id,
|
| 380 |
+
const double focal_length,
|
| 381 |
+
const size_t width,
|
| 382 |
+
const size_t height);
|
| 383 |
+
|
| 384 |
+
// Get human-readable information about the parameter vector order.
|
| 385 |
+
//
|
| 386 |
+
// @param model_id Unique identifier of camera model.
|
| 387 |
+
std::string CameraModelParamsInfo(const int model_id);
|
| 388 |
+
|
| 389 |
+
// Get the indices of the parameter groups in the parameter vector.
|
| 390 |
+
//
|
| 391 |
+
// @param model_id Unique identifier of camera model.
|
| 392 |
+
const std::vector<size_t>& CameraModelFocalLengthIdxs(const int model_id);
|
| 393 |
+
const std::vector<size_t>& CameraModelPrincipalPointIdxs(const int model_id);
|
| 394 |
+
const std::vector<size_t>& CameraModelExtraParamsIdxs(const int model_id);
|
| 395 |
+
|
| 396 |
+
// Get the total number of parameters of a camera model.
|
| 397 |
+
size_t CameraModelNumParams(const int model_id);
|
| 398 |
+
|
| 399 |
+
// Check whether parameters are valid, i.e. the parameter vector has
|
| 400 |
+
// the correct dimensions that match the specified camera model.
|
| 401 |
+
//
|
| 402 |
+
// @param model_id Unique identifier of camera model.
|
| 403 |
+
// @param params Array of camera parameters.
|
| 404 |
+
bool CameraModelVerifyParams(const int model_id,
|
| 405 |
+
const std::vector<double>& params);
|
| 406 |
+
|
| 407 |
+
// Check whether camera has bogus parameters.
|
| 408 |
+
//
|
| 409 |
+
// @param model_id Unique identifier of camera model.
|
| 410 |
+
// @param params Array of camera parameters.
|
| 411 |
+
// @param width Sensor width of the camera.
|
| 412 |
+
// @param height Sensor height of the camera.
|
| 413 |
+
// @param min_focal_length_ratio Minimum ratio of focal length over
|
| 414 |
+
// maximum sensor dimension.
|
| 415 |
+
// @param min_focal_length_ratio Maximum ratio of focal length over
|
| 416 |
+
// maximum sensor dimension.
|
| 417 |
+
// @param max_extra_param Maximum magnitude of each extra parameter.
|
| 418 |
+
bool CameraModelHasBogusParams(const int model_id,
|
| 419 |
+
const std::vector<double>& params,
|
| 420 |
+
const size_t width, const size_t height,
|
| 421 |
+
const double min_focal_length_ratio,
|
| 422 |
+
const double max_focal_length_ratio,
|
| 423 |
+
const double max_extra_param);
|
| 424 |
+
|
| 425 |
+
// Transform world coordinates in camera coordinate system to image coordinates.
|
| 426 |
+
//
|
| 427 |
+
// This is the inverse of `CameraModelImageToWorld`.
|
| 428 |
+
//
|
| 429 |
+
// @param model_id Unique model_id of camera model as defined in
|
| 430 |
+
// `CAMERA_MODEL_NAME_TO_CODE`.
|
| 431 |
+
// @param params Array of camera parameters.
|
| 432 |
+
// @param u, v Coordinates in camera system as (u, v, 1).
|
| 433 |
+
// @param x, y Output image coordinates in pixels.
|
| 434 |
+
inline void CameraModelWorldToImage(const int model_id,
|
| 435 |
+
const std::vector<double>& params,
|
| 436 |
+
const double u, const double v, double* x,
|
| 437 |
+
double* y);
|
| 438 |
+
|
| 439 |
+
// Transform image coordinates to world coordinates in camera coordinate system.
|
| 440 |
+
//
|
| 441 |
+
// This is the inverse of `CameraModelWorldToImage`.
|
| 442 |
+
//
|
| 443 |
+
// @param model_id Unique identifier of camera model.
|
| 444 |
+
// @param params Array of camera parameters.
|
| 445 |
+
// @param x, y Image coordinates in pixels.
|
| 446 |
+
// @param v, u Output Coordinates in camera system as (u, v, 1).
|
| 447 |
+
inline void CameraModelImageToWorld(const int model_id,
|
| 448 |
+
const std::vector<double>& params,
|
| 449 |
+
const double x, const double y, double* u,
|
| 450 |
+
double* v);
|
| 451 |
+
|
| 452 |
+
// Convert pixel threshold in image plane to world space by dividing
|
| 453 |
+
// the threshold through the mean focal length.
|
| 454 |
+
//
|
| 455 |
+
// @param model_id Unique identifier of camera model.
|
| 456 |
+
// @param params Array of camera parameters.
|
| 457 |
+
// @param threshold Image space threshold in pixels.
|
| 458 |
+
//
|
| 459 |
+
// @ return World space threshold.
|
| 460 |
+
inline double CameraModelImageToWorldThreshold(
|
| 461 |
+
const int model_id, const std::vector<double>& params,
|
| 462 |
+
const double threshold);
|
| 463 |
+
|
| 464 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 465 |
+
// Implementation
|
| 466 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 467 |
+
|
| 468 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 469 |
+
// BaseCameraModel
|
| 470 |
+
|
| 471 |
+
template <typename CameraModel>
|
| 472 |
+
template <typename T>
|
| 473 |
+
bool BaseCameraModel<CameraModel>::HasBogusParams(
|
| 474 |
+
const std::vector<T>& params, const size_t width, const size_t height,
|
| 475 |
+
const T min_focal_length_ratio, const T max_focal_length_ratio,
|
| 476 |
+
const T max_extra_param) {
|
| 477 |
+
if (HasBogusPrincipalPoint(params, width, height)) {
|
| 478 |
+
return true;
|
| 479 |
+
}
|
| 480 |
+
|
| 481 |
+
if (HasBogusFocalLength(params, width, height, min_focal_length_ratio,
|
| 482 |
+
max_focal_length_ratio)) {
|
| 483 |
+
return true;
|
| 484 |
+
}
|
| 485 |
+
|
| 486 |
+
if (HasBogusExtraParams(params, max_extra_param)) {
|
| 487 |
+
return true;
|
| 488 |
+
}
|
| 489 |
+
|
| 490 |
+
return false;
|
| 491 |
+
}
|
| 492 |
+
|
| 493 |
+
template <typename CameraModel>
|
| 494 |
+
template <typename T>
|
| 495 |
+
bool BaseCameraModel<CameraModel>::HasBogusFocalLength(
|
| 496 |
+
const std::vector<T>& params, const size_t width, const size_t height,
|
| 497 |
+
const T min_focal_length_ratio, const T max_focal_length_ratio) {
|
| 498 |
+
const size_t max_size = std::max(width, height);
|
| 499 |
+
|
| 500 |
+
for (const auto& idx : CameraModel::focal_length_idxs) {
|
| 501 |
+
const T focal_length_ratio = params[idx] / max_size;
|
| 502 |
+
if (focal_length_ratio < min_focal_length_ratio ||
|
| 503 |
+
focal_length_ratio > max_focal_length_ratio) {
|
| 504 |
+
return true;
|
| 505 |
+
}
|
| 506 |
+
}
|
| 507 |
+
|
| 508 |
+
return false;
|
| 509 |
+
}
|
| 510 |
+
|
| 511 |
+
template <typename CameraModel>
|
| 512 |
+
template <typename T>
|
| 513 |
+
bool BaseCameraModel<CameraModel>::HasBogusPrincipalPoint(
|
| 514 |
+
const std::vector<T>& params, const size_t width, const size_t height) {
|
| 515 |
+
const T cx = params[CameraModel::principal_point_idxs[0]];
|
| 516 |
+
const T cy = params[CameraModel::principal_point_idxs[1]];
|
| 517 |
+
return cx < 0 || cx > width || cy < 0 || cy > height;
|
| 518 |
+
}
|
| 519 |
+
|
| 520 |
+
template <typename CameraModel>
|
| 521 |
+
template <typename T>
|
| 522 |
+
bool BaseCameraModel<CameraModel>::HasBogusExtraParams(
|
| 523 |
+
const std::vector<T>& params, const T max_extra_param) {
|
| 524 |
+
for (const auto& idx : CameraModel::extra_params_idxs) {
|
| 525 |
+
if (std::abs(params[idx]) > max_extra_param) {
|
| 526 |
+
return true;
|
| 527 |
+
}
|
| 528 |
+
}
|
| 529 |
+
|
| 530 |
+
return false;
|
| 531 |
+
}
|
| 532 |
+
|
| 533 |
+
template <typename CameraModel>
|
| 534 |
+
template <typename T>
|
| 535 |
+
T BaseCameraModel<CameraModel>::ImageToWorldThreshold(const T* params,
|
| 536 |
+
const T threshold) {
|
| 537 |
+
T mean_focal_length = 0;
|
| 538 |
+
for (const auto& idx : CameraModel::focal_length_idxs) {
|
| 539 |
+
mean_focal_length += params[idx];
|
| 540 |
+
}
|
| 541 |
+
mean_focal_length /= CameraModel::focal_length_idxs.size();
|
| 542 |
+
return threshold / mean_focal_length;
|
| 543 |
+
}
|
| 544 |
+
|
| 545 |
+
template <typename CameraModel>
|
| 546 |
+
template <typename T>
|
| 547 |
+
void BaseCameraModel<CameraModel>::IterativeUndistortion(const T* params, T* u,
|
| 548 |
+
T* v) {
|
| 549 |
+
// Parameters for Newton iteration using numerical differentiation with
|
| 550 |
+
// central differences, 100 iterations should be enough even for complex
|
| 551 |
+
// camera models with higher order terms.
|
| 552 |
+
const size_t kNumIterations = 100;
|
| 553 |
+
const double kMaxStepNorm = 1e-10;
|
| 554 |
+
const double kRelStepSize = 1e-6;
|
| 555 |
+
|
| 556 |
+
Eigen::Matrix2d J;
|
| 557 |
+
const Eigen::Vector2d x0(*u, *v);
|
| 558 |
+
Eigen::Vector2d x(*u, *v);
|
| 559 |
+
Eigen::Vector2d dx;
|
| 560 |
+
Eigen::Vector2d dx_0b;
|
| 561 |
+
Eigen::Vector2d dx_0f;
|
| 562 |
+
Eigen::Vector2d dx_1b;
|
| 563 |
+
Eigen::Vector2d dx_1f;
|
| 564 |
+
|
| 565 |
+
for (size_t i = 0; i < kNumIterations; ++i) {
|
| 566 |
+
const double step0 = std::max(std::numeric_limits<double>::epsilon(),
|
| 567 |
+
std::abs(kRelStepSize * x(0)));
|
| 568 |
+
const double step1 = std::max(std::numeric_limits<double>::epsilon(),
|
| 569 |
+
std::abs(kRelStepSize * x(1)));
|
| 570 |
+
CameraModel::Distortion(params, x(0), x(1), &dx(0), &dx(1));
|
| 571 |
+
CameraModel::Distortion(params, x(0) - step0, x(1), &dx_0b(0), &dx_0b(1));
|
| 572 |
+
CameraModel::Distortion(params, x(0) + step0, x(1), &dx_0f(0), &dx_0f(1));
|
| 573 |
+
CameraModel::Distortion(params, x(0), x(1) - step1, &dx_1b(0), &dx_1b(1));
|
| 574 |
+
CameraModel::Distortion(params, x(0), x(1) + step1, &dx_1f(0), &dx_1f(1));
|
| 575 |
+
J(0, 0) = 1 + (dx_0f(0) - dx_0b(0)) / (2 * step0);
|
| 576 |
+
J(0, 1) = (dx_1f(0) - dx_1b(0)) / (2 * step1);
|
| 577 |
+
J(1, 0) = (dx_0f(1) - dx_0b(1)) / (2 * step0);
|
| 578 |
+
J(1, 1) = 1 + (dx_1f(1) - dx_1b(1)) / (2 * step1);
|
| 579 |
+
const Eigen::Vector2d step_x = J.inverse() * (x + dx - x0);
|
| 580 |
+
x -= step_x;
|
| 581 |
+
if (step_x.squaredNorm() < kMaxStepNorm) {
|
| 582 |
+
break;
|
| 583 |
+
}
|
| 584 |
+
}
|
| 585 |
+
|
| 586 |
+
*u = x(0);
|
| 587 |
+
*v = x(1);
|
| 588 |
+
}
|
| 589 |
+
|
| 590 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 591 |
+
// SimplePinholeCameraModel
|
| 592 |
+
|
| 593 |
+
std::string SimplePinholeCameraModel::InitializeParamsInfo() {
|
| 594 |
+
return "f, cx, cy";
|
| 595 |
+
}
|
| 596 |
+
|
| 597 |
+
std::vector<size_t> SimplePinholeCameraModel::InitializeFocalLengthIdxs() {
|
| 598 |
+
return {0};
|
| 599 |
+
}
|
| 600 |
+
|
| 601 |
+
std::vector<size_t> SimplePinholeCameraModel::InitializePrincipalPointIdxs() {
|
| 602 |
+
return {1, 2};
|
| 603 |
+
}
|
| 604 |
+
|
| 605 |
+
std::vector<size_t> SimplePinholeCameraModel::InitializeExtraParamsIdxs() {
|
| 606 |
+
return {};
|
| 607 |
+
}
|
| 608 |
+
|
| 609 |
+
std::vector<double> SimplePinholeCameraModel::InitializeParams(
|
| 610 |
+
const double focal_length, const size_t width, const size_t height) {
|
| 611 |
+
return {focal_length, width / 2.0, height / 2.0};
|
| 612 |
+
}
|
| 613 |
+
|
| 614 |
+
template <typename T>
|
| 615 |
+
void SimplePinholeCameraModel::WorldToImage(const T* params, const T u,
|
| 616 |
+
const T v, T* x, T* y) {
|
| 617 |
+
const T f = params[0];
|
| 618 |
+
const T c1 = params[1];
|
| 619 |
+
const T c2 = params[2];
|
| 620 |
+
|
| 621 |
+
// No Distortion
|
| 622 |
+
|
| 623 |
+
// Transform to image coordinates
|
| 624 |
+
*x = f * u + c1;
|
| 625 |
+
*y = f * v + c2;
|
| 626 |
+
}
|
| 627 |
+
|
| 628 |
+
template <typename T>
|
| 629 |
+
void SimplePinholeCameraModel::ImageToWorld(const T* params, const T x,
|
| 630 |
+
const T y, T* u, T* v) {
|
| 631 |
+
const T f = params[0];
|
| 632 |
+
const T c1 = params[1];
|
| 633 |
+
const T c2 = params[2];
|
| 634 |
+
|
| 635 |
+
*u = (x - c1) / f;
|
| 636 |
+
*v = (y - c2) / f;
|
| 637 |
+
}
|
| 638 |
+
|
| 639 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 640 |
+
// PinholeCameraModel
|
| 641 |
+
|
| 642 |
+
std::string PinholeCameraModel::InitializeParamsInfo() {
|
| 643 |
+
return "fx, fy, cx, cy";
|
| 644 |
+
}
|
| 645 |
+
|
| 646 |
+
std::vector<size_t> PinholeCameraModel::InitializeFocalLengthIdxs() {
|
| 647 |
+
return {0, 1};
|
| 648 |
+
}
|
| 649 |
+
|
| 650 |
+
std::vector<size_t> PinholeCameraModel::InitializePrincipalPointIdxs() {
|
| 651 |
+
return {2, 3};
|
| 652 |
+
}
|
| 653 |
+
|
| 654 |
+
std::vector<size_t> PinholeCameraModel::InitializeExtraParamsIdxs() {
|
| 655 |
+
return {};
|
| 656 |
+
}
|
| 657 |
+
|
| 658 |
+
std::vector<double> PinholeCameraModel::InitializeParams(
|
| 659 |
+
const double focal_length, const size_t width, const size_t height) {
|
| 660 |
+
return {focal_length, focal_length, width / 2.0, height / 2.0};
|
| 661 |
+
}
|
| 662 |
+
|
| 663 |
+
template <typename T>
|
| 664 |
+
void PinholeCameraModel::WorldToImage(const T* params, const T u, const T v,
|
| 665 |
+
T* x, T* y) {
|
| 666 |
+
const T f1 = params[0];
|
| 667 |
+
const T f2 = params[1];
|
| 668 |
+
const T c1 = params[2];
|
| 669 |
+
const T c2 = params[3];
|
| 670 |
+
|
| 671 |
+
// No Distortion
|
| 672 |
+
|
| 673 |
+
// Transform to image coordinates
|
| 674 |
+
*x = f1 * u + c1;
|
| 675 |
+
*y = f2 * v + c2;
|
| 676 |
+
}
|
| 677 |
+
|
| 678 |
+
template <typename T>
|
| 679 |
+
void PinholeCameraModel::ImageToWorld(const T* params, const T x, const T y,
|
| 680 |
+
T* u, T* v) {
|
| 681 |
+
const T f1 = params[0];
|
| 682 |
+
const T f2 = params[1];
|
| 683 |
+
const T c1 = params[2];
|
| 684 |
+
const T c2 = params[3];
|
| 685 |
+
|
| 686 |
+
*u = (x - c1) / f1;
|
| 687 |
+
*v = (y - c2) / f2;
|
| 688 |
+
}
|
| 689 |
+
|
| 690 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 691 |
+
// SimpleRadialCameraModel
|
| 692 |
+
|
| 693 |
+
std::string SimpleRadialCameraModel::InitializeParamsInfo() {
|
| 694 |
+
return "f, cx, cy, k";
|
| 695 |
+
}
|
| 696 |
+
|
| 697 |
+
std::vector<size_t> SimpleRadialCameraModel::InitializeFocalLengthIdxs() {
|
| 698 |
+
return {0};
|
| 699 |
+
}
|
| 700 |
+
|
| 701 |
+
std::vector<size_t> SimpleRadialCameraModel::InitializePrincipalPointIdxs() {
|
| 702 |
+
return {1, 2};
|
| 703 |
+
}
|
| 704 |
+
|
| 705 |
+
std::vector<size_t> SimpleRadialCameraModel::InitializeExtraParamsIdxs() {
|
| 706 |
+
return {3};
|
| 707 |
+
}
|
| 708 |
+
|
| 709 |
+
std::vector<double> SimpleRadialCameraModel::InitializeParams(
|
| 710 |
+
const double focal_length, const size_t width, const size_t height) {
|
| 711 |
+
return {focal_length, width / 2.0, height / 2.0, 0};
|
| 712 |
+
}
|
| 713 |
+
|
| 714 |
+
template <typename T>
|
| 715 |
+
void SimpleRadialCameraModel::WorldToImage(const T* params, const T u,
|
| 716 |
+
const T v, T* x, T* y) {
|
| 717 |
+
const T f = params[0];
|
| 718 |
+
const T c1 = params[1];
|
| 719 |
+
const T c2 = params[2];
|
| 720 |
+
|
| 721 |
+
// Distortion
|
| 722 |
+
T du, dv;
|
| 723 |
+
Distortion(¶ms[3], u, v, &du, &dv);
|
| 724 |
+
*x = u + du;
|
| 725 |
+
*y = v + dv;
|
| 726 |
+
|
| 727 |
+
// Transform to image coordinates
|
| 728 |
+
*x = f * *x + c1;
|
| 729 |
+
*y = f * *y + c2;
|
| 730 |
+
}
|
| 731 |
+
|
| 732 |
+
template <typename T>
|
| 733 |
+
void SimpleRadialCameraModel::ImageToWorld(const T* params, const T x,
|
| 734 |
+
const T y, T* u, T* v) {
|
| 735 |
+
const T f = params[0];
|
| 736 |
+
const T c1 = params[1];
|
| 737 |
+
const T c2 = params[2];
|
| 738 |
+
|
| 739 |
+
// Lift points to normalized plane
|
| 740 |
+
*u = (x - c1) / f;
|
| 741 |
+
*v = (y - c2) / f;
|
| 742 |
+
|
| 743 |
+
IterativeUndistortion(¶ms[3], u, v);
|
| 744 |
+
}
|
| 745 |
+
|
| 746 |
+
template <typename T>
|
| 747 |
+
void SimpleRadialCameraModel::Distortion(const T* extra_params, const T u,
|
| 748 |
+
const T v, T* du, T* dv) {
|
| 749 |
+
const T k = extra_params[0];
|
| 750 |
+
|
| 751 |
+
const T u2 = u * u;
|
| 752 |
+
const T v2 = v * v;
|
| 753 |
+
const T r2 = u2 + v2;
|
| 754 |
+
const T radial = k * r2;
|
| 755 |
+
*du = u * radial;
|
| 756 |
+
*dv = v * radial;
|
| 757 |
+
}
|
| 758 |
+
|
| 759 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 760 |
+
// RadialCameraModel
|
| 761 |
+
|
| 762 |
+
std::string RadialCameraModel::InitializeParamsInfo() {
|
| 763 |
+
return "f, cx, cy, k1, k2";
|
| 764 |
+
}
|
| 765 |
+
|
| 766 |
+
std::vector<size_t> RadialCameraModel::InitializeFocalLengthIdxs() {
|
| 767 |
+
return {0};
|
| 768 |
+
}
|
| 769 |
+
|
| 770 |
+
std::vector<size_t> RadialCameraModel::InitializePrincipalPointIdxs() {
|
| 771 |
+
return {1, 2};
|
| 772 |
+
}
|
| 773 |
+
|
| 774 |
+
std::vector<size_t> RadialCameraModel::InitializeExtraParamsIdxs() {
|
| 775 |
+
return {3, 4};
|
| 776 |
+
}
|
| 777 |
+
|
| 778 |
+
std::vector<double> RadialCameraModel::InitializeParams(
|
| 779 |
+
const double focal_length, const size_t width, const size_t height) {
|
| 780 |
+
return {focal_length, width / 2.0, height / 2.0, 0, 0};
|
| 781 |
+
}
|
| 782 |
+
|
| 783 |
+
template <typename T>
|
| 784 |
+
void RadialCameraModel::WorldToImage(const T* params, const T u, const T v,
|
| 785 |
+
T* x, T* y) {
|
| 786 |
+
const T f = params[0];
|
| 787 |
+
const T c1 = params[1];
|
| 788 |
+
const T c2 = params[2];
|
| 789 |
+
|
| 790 |
+
// Distortion
|
| 791 |
+
T du, dv;
|
| 792 |
+
Distortion(¶ms[3], u, v, &du, &dv);
|
| 793 |
+
*x = u + du;
|
| 794 |
+
*y = v + dv;
|
| 795 |
+
|
| 796 |
+
// Transform to image coordinates
|
| 797 |
+
*x = f * *x + c1;
|
| 798 |
+
*y = f * *y + c2;
|
| 799 |
+
}
|
| 800 |
+
|
| 801 |
+
template <typename T>
|
| 802 |
+
void RadialCameraModel::ImageToWorld(const T* params, const T x, const T y,
|
| 803 |
+
T* u, T* v) {
|
| 804 |
+
const T f = params[0];
|
| 805 |
+
const T c1 = params[1];
|
| 806 |
+
const T c2 = params[2];
|
| 807 |
+
|
| 808 |
+
// Lift points to normalized plane
|
| 809 |
+
*u = (x - c1) / f;
|
| 810 |
+
*v = (y - c2) / f;
|
| 811 |
+
|
| 812 |
+
IterativeUndistortion(¶ms[3], u, v);
|
| 813 |
+
}
|
| 814 |
+
|
| 815 |
+
template <typename T>
|
| 816 |
+
void RadialCameraModel::Distortion(const T* extra_params, const T u, const T v,
|
| 817 |
+
T* du, T* dv) {
|
| 818 |
+
const T k1 = extra_params[0];
|
| 819 |
+
const T k2 = extra_params[1];
|
| 820 |
+
|
| 821 |
+
const T u2 = u * u;
|
| 822 |
+
const T v2 = v * v;
|
| 823 |
+
const T r2 = u2 + v2;
|
| 824 |
+
const T radial = k1 * r2 + k2 * r2 * r2;
|
| 825 |
+
*du = u * radial;
|
| 826 |
+
*dv = v * radial;
|
| 827 |
+
}
|
| 828 |
+
|
| 829 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 830 |
+
// OpenCVCameraModel
|
| 831 |
+
|
| 832 |
+
std::string OpenCVCameraModel::InitializeParamsInfo() {
|
| 833 |
+
return "fx, fy, cx, cy, k1, k2, p1, p2";
|
| 834 |
+
}
|
| 835 |
+
|
| 836 |
+
std::vector<size_t> OpenCVCameraModel::InitializeFocalLengthIdxs() {
|
| 837 |
+
return {0, 1};
|
| 838 |
+
}
|
| 839 |
+
|
| 840 |
+
std::vector<size_t> OpenCVCameraModel::InitializePrincipalPointIdxs() {
|
| 841 |
+
return {2, 3};
|
| 842 |
+
}
|
| 843 |
+
|
| 844 |
+
std::vector<size_t> OpenCVCameraModel::InitializeExtraParamsIdxs() {
|
| 845 |
+
return {4, 5, 6, 7};
|
| 846 |
+
}
|
| 847 |
+
|
| 848 |
+
std::vector<double> OpenCVCameraModel::InitializeParams(
|
| 849 |
+
const double focal_length, const size_t width, const size_t height) {
|
| 850 |
+
return {focal_length, focal_length, width / 2.0, height / 2.0, 0, 0, 0, 0};
|
| 851 |
+
}
|
| 852 |
+
|
| 853 |
+
template <typename T>
|
| 854 |
+
void OpenCVCameraModel::WorldToImage(const T* params, const T u, const T v,
|
| 855 |
+
T* x, T* y) {
|
| 856 |
+
const T f1 = params[0];
|
| 857 |
+
const T f2 = params[1];
|
| 858 |
+
const T c1 = params[2];
|
| 859 |
+
const T c2 = params[3];
|
| 860 |
+
|
| 861 |
+
// Distortion
|
| 862 |
+
T du, dv;
|
| 863 |
+
Distortion(¶ms[4], u, v, &du, &dv);
|
| 864 |
+
*x = u + du;
|
| 865 |
+
*y = v + dv;
|
| 866 |
+
|
| 867 |
+
// Transform to image coordinates
|
| 868 |
+
*x = f1 * *x + c1;
|
| 869 |
+
*y = f2 * *y + c2;
|
| 870 |
+
}
|
| 871 |
+
|
| 872 |
+
template <typename T>
|
| 873 |
+
void OpenCVCameraModel::ImageToWorld(const T* params, const T x, const T y,
|
| 874 |
+
T* u, T* v) {
|
| 875 |
+
const T f1 = params[0];
|
| 876 |
+
const T f2 = params[1];
|
| 877 |
+
const T c1 = params[2];
|
| 878 |
+
const T c2 = params[3];
|
| 879 |
+
|
| 880 |
+
// Lift points to normalized plane
|
| 881 |
+
*u = (x - c1) / f1;
|
| 882 |
+
*v = (y - c2) / f2;
|
| 883 |
+
|
| 884 |
+
IterativeUndistortion(¶ms[4], u, v);
|
| 885 |
+
}
|
| 886 |
+
|
| 887 |
+
template <typename T>
|
| 888 |
+
void OpenCVCameraModel::Distortion(const T* extra_params, const T u, const T v,
|
| 889 |
+
T* du, T* dv) {
|
| 890 |
+
const T k1 = extra_params[0];
|
| 891 |
+
const T k2 = extra_params[1];
|
| 892 |
+
const T p1 = extra_params[2];
|
| 893 |
+
const T p2 = extra_params[3];
|
| 894 |
+
|
| 895 |
+
const T u2 = u * u;
|
| 896 |
+
const T uv = u * v;
|
| 897 |
+
const T v2 = v * v;
|
| 898 |
+
const T r2 = u2 + v2;
|
| 899 |
+
const T radial = k1 * r2 + k2 * r2 * r2;
|
| 900 |
+
*du = u * radial + T(2) * p1 * uv + p2 * (r2 + T(2) * u2);
|
| 901 |
+
*dv = v * radial + T(2) * p2 * uv + p1 * (r2 + T(2) * v2);
|
| 902 |
+
}
|
| 903 |
+
|
| 904 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 905 |
+
// OpenCVFisheyeCameraModel
|
| 906 |
+
|
| 907 |
+
std::string OpenCVFisheyeCameraModel::InitializeParamsInfo() {
|
| 908 |
+
return "fx, fy, cx, cy, k1, k2, k3, k4";
|
| 909 |
+
}
|
| 910 |
+
|
| 911 |
+
std::vector<size_t> OpenCVFisheyeCameraModel::InitializeFocalLengthIdxs() {
|
| 912 |
+
return {0, 1};
|
| 913 |
+
}
|
| 914 |
+
|
| 915 |
+
std::vector<size_t> OpenCVFisheyeCameraModel::InitializePrincipalPointIdxs() {
|
| 916 |
+
return {2, 3};
|
| 917 |
+
}
|
| 918 |
+
|
| 919 |
+
std::vector<size_t> OpenCVFisheyeCameraModel::InitializeExtraParamsIdxs() {
|
| 920 |
+
return {4, 5, 6, 7};
|
| 921 |
+
}
|
| 922 |
+
|
| 923 |
+
std::vector<double> OpenCVFisheyeCameraModel::InitializeParams(
|
| 924 |
+
const double focal_length, const size_t width, const size_t height) {
|
| 925 |
+
return {focal_length, focal_length, width / 2.0, height / 2.0, 0, 0, 0, 0};
|
| 926 |
+
}
|
| 927 |
+
|
| 928 |
+
template <typename T>
|
| 929 |
+
void OpenCVFisheyeCameraModel::WorldToImage(const T* params, const T u,
|
| 930 |
+
const T v, T* x, T* y) {
|
| 931 |
+
const T f1 = params[0];
|
| 932 |
+
const T f2 = params[1];
|
| 933 |
+
const T c1 = params[2];
|
| 934 |
+
const T c2 = params[3];
|
| 935 |
+
|
| 936 |
+
// Distortion
|
| 937 |
+
T du, dv;
|
| 938 |
+
Distortion(¶ms[4], u, v, &du, &dv);
|
| 939 |
+
*x = u + du;
|
| 940 |
+
*y = v + dv;
|
| 941 |
+
|
| 942 |
+
// Transform to image coordinates
|
| 943 |
+
*x = f1 * *x + c1;
|
| 944 |
+
*y = f2 * *y + c2;
|
| 945 |
+
}
|
| 946 |
+
|
| 947 |
+
template <typename T>
|
| 948 |
+
void OpenCVFisheyeCameraModel::ImageToWorld(const T* params, const T x,
|
| 949 |
+
const T y, T* u, T* v) {
|
| 950 |
+
const T f1 = params[0];
|
| 951 |
+
const T f2 = params[1];
|
| 952 |
+
const T c1 = params[2];
|
| 953 |
+
const T c2 = params[3];
|
| 954 |
+
|
| 955 |
+
// Lift points to normalized plane
|
| 956 |
+
*u = (x - c1) / f1;
|
| 957 |
+
*v = (y - c2) / f2;
|
| 958 |
+
|
| 959 |
+
IterativeUndistortion(¶ms[4], u, v);
|
| 960 |
+
}
|
| 961 |
+
|
| 962 |
+
template <typename T>
|
| 963 |
+
void OpenCVFisheyeCameraModel::Distortion(const T* extra_params, const T u,
|
| 964 |
+
const T v, T* du, T* dv) {
|
| 965 |
+
const T k1 = extra_params[0];
|
| 966 |
+
const T k2 = extra_params[1];
|
| 967 |
+
const T k3 = extra_params[2];
|
| 968 |
+
const T k4 = extra_params[3];
|
| 969 |
+
|
| 970 |
+
const T r = ceres::sqrt(u * u + v * v);
|
| 971 |
+
|
| 972 |
+
if (r > T(std::numeric_limits<double>::epsilon())) {
|
| 973 |
+
const T theta = ceres::atan(r);
|
| 974 |
+
const T theta2 = theta * theta;
|
| 975 |
+
const T theta4 = theta2 * theta2;
|
| 976 |
+
const T theta6 = theta4 * theta2;
|
| 977 |
+
const T theta8 = theta4 * theta4;
|
| 978 |
+
const T thetad =
|
| 979 |
+
theta * (T(1) + k1 * theta2 + k2 * theta4 + k3 * theta6 + k4 * theta8);
|
| 980 |
+
*du = u * thetad / r - u;
|
| 981 |
+
*dv = v * thetad / r - v;
|
| 982 |
+
} else {
|
| 983 |
+
*du = T(0);
|
| 984 |
+
*dv = T(0);
|
| 985 |
+
}
|
| 986 |
+
}
|
| 987 |
+
|
| 988 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 989 |
+
// FullOpenCVCameraModel
|
| 990 |
+
|
| 991 |
+
std::string FullOpenCVCameraModel::InitializeParamsInfo() {
|
| 992 |
+
return "fx, fy, cx, cy, k1, k2, p1, p2, k3, k4, k5, k6";
|
| 993 |
+
}
|
| 994 |
+
|
| 995 |
+
std::vector<size_t> FullOpenCVCameraModel::InitializeFocalLengthIdxs() {
|
| 996 |
+
return {0, 1};
|
| 997 |
+
}
|
| 998 |
+
|
| 999 |
+
std::vector<size_t> FullOpenCVCameraModel::InitializePrincipalPointIdxs() {
|
| 1000 |
+
return {2, 3};
|
| 1001 |
+
}
|
| 1002 |
+
|
| 1003 |
+
std::vector<size_t> FullOpenCVCameraModel::InitializeExtraParamsIdxs() {
|
| 1004 |
+
return {4, 5, 6, 7, 8, 9, 10, 11};
|
| 1005 |
+
}
|
| 1006 |
+
|
| 1007 |
+
std::vector<double> FullOpenCVCameraModel::InitializeParams(
|
| 1008 |
+
const double focal_length, const size_t width, const size_t height) {
|
| 1009 |
+
return {focal_length,
|
| 1010 |
+
focal_length,
|
| 1011 |
+
width / 2.0,
|
| 1012 |
+
height / 2.0,
|
| 1013 |
+
0,
|
| 1014 |
+
0,
|
| 1015 |
+
0,
|
| 1016 |
+
0,
|
| 1017 |
+
0,
|
| 1018 |
+
0,
|
| 1019 |
+
0,
|
| 1020 |
+
0};
|
| 1021 |
+
}
|
| 1022 |
+
|
| 1023 |
+
template <typename T>
|
| 1024 |
+
void FullOpenCVCameraModel::WorldToImage(const T* params, const T u, const T v,
|
| 1025 |
+
T* x, T* y) {
|
| 1026 |
+
const T f1 = params[0];
|
| 1027 |
+
const T f2 = params[1];
|
| 1028 |
+
const T c1 = params[2];
|
| 1029 |
+
const T c2 = params[3];
|
| 1030 |
+
|
| 1031 |
+
// Distortion
|
| 1032 |
+
T du, dv;
|
| 1033 |
+
Distortion(¶ms[4], u, v, &du, &dv);
|
| 1034 |
+
*x = u + du;
|
| 1035 |
+
*y = v + dv;
|
| 1036 |
+
|
| 1037 |
+
// Transform to image coordinates
|
| 1038 |
+
*x = f1 * *x + c1;
|
| 1039 |
+
*y = f2 * *y + c2;
|
| 1040 |
+
}
|
| 1041 |
+
|
| 1042 |
+
template <typename T>
|
| 1043 |
+
void FullOpenCVCameraModel::ImageToWorld(const T* params, const T x, const T y,
|
| 1044 |
+
T* u, T* v) {
|
| 1045 |
+
const T f1 = params[0];
|
| 1046 |
+
const T f2 = params[1];
|
| 1047 |
+
const T c1 = params[2];
|
| 1048 |
+
const T c2 = params[3];
|
| 1049 |
+
|
| 1050 |
+
// Lift points to normalized plane
|
| 1051 |
+
*u = (x - c1) / f1;
|
| 1052 |
+
*v = (y - c2) / f2;
|
| 1053 |
+
|
| 1054 |
+
IterativeUndistortion(¶ms[4], u, v);
|
| 1055 |
+
}
|
| 1056 |
+
|
| 1057 |
+
template <typename T>
|
| 1058 |
+
void FullOpenCVCameraModel::Distortion(const T* extra_params, const T u,
|
| 1059 |
+
const T v, T* du, T* dv) {
|
| 1060 |
+
const T k1 = extra_params[0];
|
| 1061 |
+
const T k2 = extra_params[1];
|
| 1062 |
+
const T p1 = extra_params[2];
|
| 1063 |
+
const T p2 = extra_params[3];
|
| 1064 |
+
const T k3 = extra_params[4];
|
| 1065 |
+
const T k4 = extra_params[5];
|
| 1066 |
+
const T k5 = extra_params[6];
|
| 1067 |
+
const T k6 = extra_params[7];
|
| 1068 |
+
|
| 1069 |
+
const T u2 = u * u;
|
| 1070 |
+
const T uv = u * v;
|
| 1071 |
+
const T v2 = v * v;
|
| 1072 |
+
const T r2 = u2 + v2;
|
| 1073 |
+
const T r4 = r2 * r2;
|
| 1074 |
+
const T r6 = r4 * r2;
|
| 1075 |
+
const T radial = (T(1) + k1 * r2 + k2 * r4 + k3 * r6) /
|
| 1076 |
+
(T(1) + k4 * r2 + k5 * r4 + k6 * r6);
|
| 1077 |
+
*du = u * radial + T(2) * p1 * uv + p2 * (r2 + T(2) * u2) - u;
|
| 1078 |
+
*dv = v * radial + T(2) * p2 * uv + p1 * (r2 + T(2) * v2) - v;
|
| 1079 |
+
}
|
| 1080 |
+
|
| 1081 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 1082 |
+
// FOVCameraModel
|
| 1083 |
+
|
| 1084 |
+
std::string FOVCameraModel::InitializeParamsInfo() {
|
| 1085 |
+
return "fx, fy, cx, cy, omega";
|
| 1086 |
+
}
|
| 1087 |
+
|
| 1088 |
+
std::vector<size_t> FOVCameraModel::InitializeFocalLengthIdxs() {
|
| 1089 |
+
return {0, 1};
|
| 1090 |
+
}
|
| 1091 |
+
|
| 1092 |
+
std::vector<size_t> FOVCameraModel::InitializePrincipalPointIdxs() {
|
| 1093 |
+
return {2, 3};
|
| 1094 |
+
}
|
| 1095 |
+
|
| 1096 |
+
std::vector<size_t> FOVCameraModel::InitializeExtraParamsIdxs() { return {4}; }
|
| 1097 |
+
|
| 1098 |
+
std::vector<double> FOVCameraModel::InitializeParams(const double focal_length,
|
| 1099 |
+
const size_t width,
|
| 1100 |
+
const size_t height) {
|
| 1101 |
+
return {focal_length, focal_length, width / 2.0, height / 2.0, 1e-2};
|
| 1102 |
+
}
|
| 1103 |
+
|
| 1104 |
+
template <typename T>
|
| 1105 |
+
void FOVCameraModel::WorldToImage(const T* params, const T u, const T v, T* x,
|
| 1106 |
+
T* y) {
|
| 1107 |
+
const T f1 = params[0];
|
| 1108 |
+
const T f2 = params[1];
|
| 1109 |
+
const T c1 = params[2];
|
| 1110 |
+
const T c2 = params[3];
|
| 1111 |
+
|
| 1112 |
+
// Distortion
|
| 1113 |
+
Distortion(¶ms[4], u, v, x, y);
|
| 1114 |
+
|
| 1115 |
+
// Transform to image coordinates
|
| 1116 |
+
*x = f1 * *x + c1;
|
| 1117 |
+
*y = f2 * *y + c2;
|
| 1118 |
+
}
|
| 1119 |
+
|
| 1120 |
+
template <typename T>
|
| 1121 |
+
void FOVCameraModel::ImageToWorld(const T* params, const T x, const T y, T* u,
|
| 1122 |
+
T* v) {
|
| 1123 |
+
const T f1 = params[0];
|
| 1124 |
+
const T f2 = params[1];
|
| 1125 |
+
const T c1 = params[2];
|
| 1126 |
+
const T c2 = params[3];
|
| 1127 |
+
|
| 1128 |
+
// Lift points to normalized plane
|
| 1129 |
+
const T uu = (x - c1) / f1;
|
| 1130 |
+
const T vv = (y - c2) / f2;
|
| 1131 |
+
|
| 1132 |
+
// Undistortion
|
| 1133 |
+
Undistortion(¶ms[4], uu, vv, u, v);
|
| 1134 |
+
}
|
| 1135 |
+
|
| 1136 |
+
template <typename T>
|
| 1137 |
+
void FOVCameraModel::Distortion(const T* extra_params, const T u, const T v,
|
| 1138 |
+
T* du, T* dv) {
|
| 1139 |
+
const T omega = extra_params[0];
|
| 1140 |
+
|
| 1141 |
+
// Chosen arbitrarily.
|
| 1142 |
+
const T kEpsilon = T(1e-4);
|
| 1143 |
+
|
| 1144 |
+
const T radius2 = u * u + v * v;
|
| 1145 |
+
const T omega2 = omega * omega;
|
| 1146 |
+
|
| 1147 |
+
T factor;
|
| 1148 |
+
if (omega2 < kEpsilon) {
|
| 1149 |
+
// Derivation of this case with Matlab:
|
| 1150 |
+
// syms radius omega;
|
| 1151 |
+
// factor(radius) = atan(radius * 2 * tan(omega / 2)) / ...
|
| 1152 |
+
// (radius * omega);
|
| 1153 |
+
// simplify(taylor(factor, omega, 'order', 3))
|
| 1154 |
+
factor = (omega2 * radius2) / T(3) - omega2 / T(12) + T(1);
|
| 1155 |
+
} else if (radius2 < kEpsilon) {
|
| 1156 |
+
// Derivation of this case with Matlab:
|
| 1157 |
+
// syms radius omega;
|
| 1158 |
+
// factor(radius) = atan(radius * 2 * tan(omega / 2)) / ...
|
| 1159 |
+
// (radius * omega);
|
| 1160 |
+
// simplify(taylor(factor, radius, 'order', 3))
|
| 1161 |
+
const T tan_half_omega = ceres::tan(omega / T(2));
|
| 1162 |
+
factor = (T(-2) * tan_half_omega *
|
| 1163 |
+
(T(4) * radius2 * tan_half_omega * tan_half_omega - T(3))) /
|
| 1164 |
+
(T(3) * omega);
|
| 1165 |
+
} else {
|
| 1166 |
+
const T radius = ceres::sqrt(radius2);
|
| 1167 |
+
const T numerator = ceres::atan(radius * T(2) * ceres::tan(omega / T(2)));
|
| 1168 |
+
factor = numerator / (radius * omega);
|
| 1169 |
+
}
|
| 1170 |
+
|
| 1171 |
+
*du = u * factor;
|
| 1172 |
+
*dv = v * factor;
|
| 1173 |
+
}
|
| 1174 |
+
|
| 1175 |
+
template <typename T>
|
| 1176 |
+
void FOVCameraModel::Undistortion(const T* extra_params, const T u, const T v,
|
| 1177 |
+
T* du, T* dv) {
|
| 1178 |
+
T omega = extra_params[0];
|
| 1179 |
+
|
| 1180 |
+
// Chosen arbitrarily.
|
| 1181 |
+
const T kEpsilon = T(1e-4);
|
| 1182 |
+
|
| 1183 |
+
const T radius2 = u * u + v * v;
|
| 1184 |
+
const T omega2 = omega * omega;
|
| 1185 |
+
|
| 1186 |
+
T factor;
|
| 1187 |
+
if (omega2 < kEpsilon) {
|
| 1188 |
+
// Derivation of this case with Matlab:
|
| 1189 |
+
// syms radius omega;
|
| 1190 |
+
// factor(radius) = tan(radius * omega) / ...
|
| 1191 |
+
// (radius * 2*tan(omega/2));
|
| 1192 |
+
// simplify(taylor(factor, omega, 'order', 3))
|
| 1193 |
+
factor = (omega2 * radius2) / T(3) - omega2 / T(12) + T(1);
|
| 1194 |
+
} else if (radius2 < kEpsilon) {
|
| 1195 |
+
// Derivation of this case with Matlab:
|
| 1196 |
+
// syms radius omega;
|
| 1197 |
+
// factor(radius) = tan(radius * omega) / ...
|
| 1198 |
+
// (radius * 2*tan(omega/2));
|
| 1199 |
+
// simplify(taylor(factor, radius, 'order', 3))
|
| 1200 |
+
factor = (omega * (omega * omega * radius2 + T(3))) /
|
| 1201 |
+
(T(6) * ceres::tan(omega / T(2)));
|
| 1202 |
+
} else {
|
| 1203 |
+
const T radius = ceres::sqrt(radius2);
|
| 1204 |
+
const T numerator = ceres::tan(radius * omega);
|
| 1205 |
+
factor = numerator / (radius * T(2) * ceres::tan(omega / T(2)));
|
| 1206 |
+
}
|
| 1207 |
+
|
| 1208 |
+
*du = u * factor;
|
| 1209 |
+
*dv = v * factor;
|
| 1210 |
+
}
|
| 1211 |
+
|
| 1212 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 1213 |
+
// SimpleRadialFisheyeCameraModel
|
| 1214 |
+
|
| 1215 |
+
std::string SimpleRadialFisheyeCameraModel::InitializeParamsInfo() {
|
| 1216 |
+
return "f, cx, cy, k";
|
| 1217 |
+
}
|
| 1218 |
+
|
| 1219 |
+
std::vector<size_t>
|
| 1220 |
+
SimpleRadialFisheyeCameraModel::InitializeFocalLengthIdxs() {
|
| 1221 |
+
return {0};
|
| 1222 |
+
}
|
| 1223 |
+
|
| 1224 |
+
std::vector<size_t>
|
| 1225 |
+
SimpleRadialFisheyeCameraModel::InitializePrincipalPointIdxs() {
|
| 1226 |
+
return {1, 2};
|
| 1227 |
+
}
|
| 1228 |
+
|
| 1229 |
+
std::vector<size_t>
|
| 1230 |
+
SimpleRadialFisheyeCameraModel::InitializeExtraParamsIdxs() {
|
| 1231 |
+
return {3};
|
| 1232 |
+
}
|
| 1233 |
+
|
| 1234 |
+
std::vector<double> SimpleRadialFisheyeCameraModel::InitializeParams(
|
| 1235 |
+
const double focal_length, const size_t width, const size_t height) {
|
| 1236 |
+
return {focal_length, width / 2.0, height / 2.0, 0};
|
| 1237 |
+
}
|
| 1238 |
+
|
| 1239 |
+
template <typename T>
|
| 1240 |
+
void SimpleRadialFisheyeCameraModel::WorldToImage(const T* params, const T u,
|
| 1241 |
+
const T v, T* x, T* y) {
|
| 1242 |
+
const T f = params[0];
|
| 1243 |
+
const T c1 = params[1];
|
| 1244 |
+
const T c2 = params[2];
|
| 1245 |
+
|
| 1246 |
+
// Distortion
|
| 1247 |
+
T du, dv;
|
| 1248 |
+
Distortion(¶ms[3], u, v, &du, &dv);
|
| 1249 |
+
*x = u + du;
|
| 1250 |
+
*y = v + dv;
|
| 1251 |
+
|
| 1252 |
+
// Transform to image coordinates
|
| 1253 |
+
*x = f * *x + c1;
|
| 1254 |
+
*y = f * *y + c2;
|
| 1255 |
+
}
|
| 1256 |
+
|
| 1257 |
+
template <typename T>
|
| 1258 |
+
void SimpleRadialFisheyeCameraModel::ImageToWorld(const T* params, const T x,
|
| 1259 |
+
const T y, T* u, T* v) {
|
| 1260 |
+
const T f = params[0];
|
| 1261 |
+
const T c1 = params[1];
|
| 1262 |
+
const T c2 = params[2];
|
| 1263 |
+
|
| 1264 |
+
// Lift points to normalized plane
|
| 1265 |
+
*u = (x - c1) / f;
|
| 1266 |
+
*v = (y - c2) / f;
|
| 1267 |
+
|
| 1268 |
+
IterativeUndistortion(¶ms[3], u, v);
|
| 1269 |
+
}
|
| 1270 |
+
|
| 1271 |
+
template <typename T>
|
| 1272 |
+
void SimpleRadialFisheyeCameraModel::Distortion(const T* extra_params,
|
| 1273 |
+
const T u, const T v, T* du,
|
| 1274 |
+
T* dv) {
|
| 1275 |
+
const T k = extra_params[0];
|
| 1276 |
+
|
| 1277 |
+
const T r = ceres::sqrt(u * u + v * v);
|
| 1278 |
+
|
| 1279 |
+
if (r > T(std::numeric_limits<double>::epsilon())) {
|
| 1280 |
+
const T theta = ceres::atan(r);
|
| 1281 |
+
const T theta2 = theta * theta;
|
| 1282 |
+
const T thetad = theta * (T(1) + k * theta2);
|
| 1283 |
+
*du = u * thetad / r - u;
|
| 1284 |
+
*dv = v * thetad / r - v;
|
| 1285 |
+
} else {
|
| 1286 |
+
*du = T(0);
|
| 1287 |
+
*dv = T(0);
|
| 1288 |
+
}
|
| 1289 |
+
}
|
| 1290 |
+
|
| 1291 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 1292 |
+
// RadialFisheyeCameraModel
|
| 1293 |
+
|
| 1294 |
+
std::string RadialFisheyeCameraModel::InitializeParamsInfo() {
|
| 1295 |
+
return "f, cx, cy, k1, k2";
|
| 1296 |
+
}
|
| 1297 |
+
|
| 1298 |
+
std::vector<size_t> RadialFisheyeCameraModel::InitializeFocalLengthIdxs() {
|
| 1299 |
+
return {0};
|
| 1300 |
+
}
|
| 1301 |
+
|
| 1302 |
+
std::vector<size_t> RadialFisheyeCameraModel::InitializePrincipalPointIdxs() {
|
| 1303 |
+
return {1, 2};
|
| 1304 |
+
}
|
| 1305 |
+
|
| 1306 |
+
std::vector<size_t> RadialFisheyeCameraModel::InitializeExtraParamsIdxs() {
|
| 1307 |
+
return {3, 4};
|
| 1308 |
+
}
|
| 1309 |
+
|
| 1310 |
+
std::vector<double> RadialFisheyeCameraModel::InitializeParams(
|
| 1311 |
+
const double focal_length, const size_t width, const size_t height) {
|
| 1312 |
+
return {focal_length, width / 2.0, height / 2.0, 0, 0};
|
| 1313 |
+
}
|
| 1314 |
+
|
| 1315 |
+
template <typename T>
|
| 1316 |
+
void RadialFisheyeCameraModel::WorldToImage(const T* params, const T u,
|
| 1317 |
+
const T v, T* x, T* y) {
|
| 1318 |
+
const T f = params[0];
|
| 1319 |
+
const T c1 = params[1];
|
| 1320 |
+
const T c2 = params[2];
|
| 1321 |
+
|
| 1322 |
+
// Distortion
|
| 1323 |
+
T du, dv;
|
| 1324 |
+
Distortion(¶ms[3], u, v, &du, &dv);
|
| 1325 |
+
*x = u + du;
|
| 1326 |
+
*y = v + dv;
|
| 1327 |
+
|
| 1328 |
+
// Transform to image coordinates
|
| 1329 |
+
*x = f * *x + c1;
|
| 1330 |
+
*y = f * *y + c2;
|
| 1331 |
+
}
|
| 1332 |
+
|
| 1333 |
+
template <typename T>
|
| 1334 |
+
void RadialFisheyeCameraModel::ImageToWorld(const T* params, const T x,
|
| 1335 |
+
const T y, T* u, T* v) {
|
| 1336 |
+
const T f = params[0];
|
| 1337 |
+
const T c1 = params[1];
|
| 1338 |
+
const T c2 = params[2];
|
| 1339 |
+
|
| 1340 |
+
// Lift points to normalized plane
|
| 1341 |
+
*u = (x - c1) / f;
|
| 1342 |
+
*v = (y - c2) / f;
|
| 1343 |
+
|
| 1344 |
+
IterativeUndistortion(¶ms[3], u, v);
|
| 1345 |
+
}
|
| 1346 |
+
|
| 1347 |
+
template <typename T>
|
| 1348 |
+
void RadialFisheyeCameraModel::Distortion(const T* extra_params, const T u,
|
| 1349 |
+
const T v, T* du, T* dv) {
|
| 1350 |
+
const T k1 = extra_params[0];
|
| 1351 |
+
const T k2 = extra_params[1];
|
| 1352 |
+
|
| 1353 |
+
const T r = ceres::sqrt(u * u + v * v);
|
| 1354 |
+
|
| 1355 |
+
if (r > T(std::numeric_limits<double>::epsilon())) {
|
| 1356 |
+
const T theta = ceres::atan(r);
|
| 1357 |
+
const T theta2 = theta * theta;
|
| 1358 |
+
const T theta4 = theta2 * theta2;
|
| 1359 |
+
const T thetad = theta * (T(1) + k1 * theta2 + k2 * theta4);
|
| 1360 |
+
*du = u * thetad / r - u;
|
| 1361 |
+
*dv = v * thetad / r - v;
|
| 1362 |
+
} else {
|
| 1363 |
+
*du = T(0);
|
| 1364 |
+
*dv = T(0);
|
| 1365 |
+
}
|
| 1366 |
+
}
|
| 1367 |
+
|
| 1368 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 1369 |
+
// ThinPrismFisheyeCameraModel
|
| 1370 |
+
|
| 1371 |
+
std::string ThinPrismFisheyeCameraModel::InitializeParamsInfo() {
|
| 1372 |
+
return "fx, fy, cx, cy, k1, k2, p1, p2, k3, k4, sx1, sy1";
|
| 1373 |
+
}
|
| 1374 |
+
|
| 1375 |
+
std::vector<size_t> ThinPrismFisheyeCameraModel::InitializeFocalLengthIdxs() {
|
| 1376 |
+
return {0, 1};
|
| 1377 |
+
}
|
| 1378 |
+
|
| 1379 |
+
std::vector<size_t>
|
| 1380 |
+
ThinPrismFisheyeCameraModel::InitializePrincipalPointIdxs() {
|
| 1381 |
+
return {2, 3};
|
| 1382 |
+
}
|
| 1383 |
+
|
| 1384 |
+
std::vector<size_t> ThinPrismFisheyeCameraModel::InitializeExtraParamsIdxs() {
|
| 1385 |
+
return {4, 5, 6, 7, 8, 9, 10, 11};
|
| 1386 |
+
}
|
| 1387 |
+
|
| 1388 |
+
std::vector<double> ThinPrismFisheyeCameraModel::InitializeParams(
|
| 1389 |
+
const double focal_length, const size_t width, const size_t height) {
|
| 1390 |
+
return {focal_length,
|
| 1391 |
+
focal_length,
|
| 1392 |
+
width / 2.0,
|
| 1393 |
+
height / 2.0,
|
| 1394 |
+
0,
|
| 1395 |
+
0,
|
| 1396 |
+
0,
|
| 1397 |
+
0,
|
| 1398 |
+
0,
|
| 1399 |
+
0,
|
| 1400 |
+
0,
|
| 1401 |
+
0};
|
| 1402 |
+
}
|
| 1403 |
+
|
| 1404 |
+
template <typename T>
|
| 1405 |
+
void ThinPrismFisheyeCameraModel::WorldToImage(const T* params, const T u,
|
| 1406 |
+
const T v, T* x, T* y) {
|
| 1407 |
+
const T f1 = params[0];
|
| 1408 |
+
const T f2 = params[1];
|
| 1409 |
+
const T c1 = params[2];
|
| 1410 |
+
const T c2 = params[3];
|
| 1411 |
+
|
| 1412 |
+
const T r = ceres::sqrt(u * u + v * v);
|
| 1413 |
+
|
| 1414 |
+
T uu, vv;
|
| 1415 |
+
if (r > T(std::numeric_limits<double>::epsilon())) {
|
| 1416 |
+
const T theta = ceres::atan(r);
|
| 1417 |
+
uu = theta * u / r;
|
| 1418 |
+
vv = theta * v / r;
|
| 1419 |
+
} else {
|
| 1420 |
+
uu = u;
|
| 1421 |
+
vv = v;
|
| 1422 |
+
}
|
| 1423 |
+
|
| 1424 |
+
// Distortion
|
| 1425 |
+
T du, dv;
|
| 1426 |
+
Distortion(¶ms[4], uu, vv, &du, &dv);
|
| 1427 |
+
*x = uu + du;
|
| 1428 |
+
*y = vv + dv;
|
| 1429 |
+
|
| 1430 |
+
// Transform to image coordinates
|
| 1431 |
+
*x = f1 * *x + c1;
|
| 1432 |
+
*y = f2 * *y + c2;
|
| 1433 |
+
}
|
| 1434 |
+
|
| 1435 |
+
template <typename T>
|
| 1436 |
+
void ThinPrismFisheyeCameraModel::ImageToWorld(const T* params, const T x,
|
| 1437 |
+
const T y, T* u, T* v) {
|
| 1438 |
+
const T f1 = params[0];
|
| 1439 |
+
const T f2 = params[1];
|
| 1440 |
+
const T c1 = params[2];
|
| 1441 |
+
const T c2 = params[3];
|
| 1442 |
+
|
| 1443 |
+
// Lift points to normalized plane
|
| 1444 |
+
*u = (x - c1) / f1;
|
| 1445 |
+
*v = (y - c2) / f2;
|
| 1446 |
+
|
| 1447 |
+
IterativeUndistortion(¶ms[4], u, v);
|
| 1448 |
+
|
| 1449 |
+
const T theta = ceres::sqrt(*u * *u + *v * *v);
|
| 1450 |
+
const T theta_cos_theta = theta * ceres::cos(theta);
|
| 1451 |
+
if (theta_cos_theta > T(std::numeric_limits<double>::epsilon())) {
|
| 1452 |
+
const T scale = ceres::sin(theta) / theta_cos_theta;
|
| 1453 |
+
*u *= scale;
|
| 1454 |
+
*v *= scale;
|
| 1455 |
+
}
|
| 1456 |
+
}
|
| 1457 |
+
|
| 1458 |
+
template <typename T>
|
| 1459 |
+
void ThinPrismFisheyeCameraModel::Distortion(const T* extra_params, const T u,
|
| 1460 |
+
const T v, T* du, T* dv) {
|
| 1461 |
+
const T k1 = extra_params[0];
|
| 1462 |
+
const T k2 = extra_params[1];
|
| 1463 |
+
const T p1 = extra_params[2];
|
| 1464 |
+
const T p2 = extra_params[3];
|
| 1465 |
+
const T k3 = extra_params[4];
|
| 1466 |
+
const T k4 = extra_params[5];
|
| 1467 |
+
const T sx1 = extra_params[6];
|
| 1468 |
+
const T sy1 = extra_params[7];
|
| 1469 |
+
|
| 1470 |
+
const T u2 = u * u;
|
| 1471 |
+
const T uv = u * v;
|
| 1472 |
+
const T v2 = v * v;
|
| 1473 |
+
const T r2 = u2 + v2;
|
| 1474 |
+
const T r4 = r2 * r2;
|
| 1475 |
+
const T r6 = r4 * r2;
|
| 1476 |
+
const T r8 = r6 * r2;
|
| 1477 |
+
const T radial = k1 * r2 + k2 * r4 + k3 * r6 + k4 * r8;
|
| 1478 |
+
*du = u * radial + T(2) * p1 * uv + p2 * (r2 + T(2) * u2) + sx1 * r2;
|
| 1479 |
+
*dv = v * radial + T(2) * p2 * uv + p1 * (r2 + T(2) * v2) + sy1 * r2;
|
| 1480 |
+
}
|
| 1481 |
+
|
| 1482 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 1483 |
+
|
| 1484 |
+
void CameraModelWorldToImage(const int model_id,
|
| 1485 |
+
const std::vector<double>& params, const double u,
|
| 1486 |
+
const double v, double* x, double* y) {
|
| 1487 |
+
switch (model_id) {
|
| 1488 |
+
#define CAMERA_MODEL_CASE(CameraModel) \
|
| 1489 |
+
case CameraModel::kModelId: \
|
| 1490 |
+
CameraModel::WorldToImage(params.data(), u, v, x, y); \
|
| 1491 |
+
break;
|
| 1492 |
+
|
| 1493 |
+
CAMERA_MODEL_SWITCH_CASES
|
| 1494 |
+
|
| 1495 |
+
#undef CAMERA_MODEL_CASE
|
| 1496 |
+
}
|
| 1497 |
+
}
|
| 1498 |
+
|
| 1499 |
+
void CameraModelImageToWorld(const int model_id,
|
| 1500 |
+
const std::vector<double>& params, const double x,
|
| 1501 |
+
const double y, double* u, double* v) {
|
| 1502 |
+
switch (model_id) {
|
| 1503 |
+
#define CAMERA_MODEL_CASE(CameraModel) \
|
| 1504 |
+
case CameraModel::kModelId: \
|
| 1505 |
+
CameraModel::ImageToWorld(params.data(), x, y, u, v); \
|
| 1506 |
+
break;
|
| 1507 |
+
|
| 1508 |
+
CAMERA_MODEL_SWITCH_CASES
|
| 1509 |
+
|
| 1510 |
+
#undef CAMERA_MODEL_CASE
|
| 1511 |
+
}
|
| 1512 |
+
}
|
| 1513 |
+
|
| 1514 |
+
double CameraModelImageToWorldThreshold(const int model_id,
|
| 1515 |
+
const std::vector<double>& params,
|
| 1516 |
+
const double threshold) {
|
| 1517 |
+
switch (model_id) {
|
| 1518 |
+
#define CAMERA_MODEL_CASE(CameraModel) \
|
| 1519 |
+
case CameraModel::kModelId: \
|
| 1520 |
+
return CameraModel::ImageToWorldThreshold(params.data(), threshold); \
|
| 1521 |
+
break;
|
| 1522 |
+
|
| 1523 |
+
CAMERA_MODEL_SWITCH_CASES
|
| 1524 |
+
|
| 1525 |
+
#undef CAMERA_MODEL_CASE
|
| 1526 |
+
}
|
| 1527 |
+
|
| 1528 |
+
return -1;
|
| 1529 |
+
}
|
| 1530 |
+
|
| 1531 |
+
} // namespace colmap
|
| 1532 |
+
|
| 1533 |
+
#endif // COLMAP_SRC_BASE_CAMERA_MODELS_H_
|
colmap/include/colmap/base/camera_rig.h
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_BASE_CAMERA_RIG_H_
|
| 33 |
+
#define COLMAP_SRC_BASE_CAMERA_RIG_H_
|
| 34 |
+
|
| 35 |
+
#include <unordered_map>
|
| 36 |
+
#include <vector>
|
| 37 |
+
|
| 38 |
+
#include "base/camera.h"
|
| 39 |
+
#include "base/pose.h"
|
| 40 |
+
#include "base/reconstruction.h"
|
| 41 |
+
#include "util/alignment.h"
|
| 42 |
+
#include "util/types.h"
|
| 43 |
+
|
| 44 |
+
namespace colmap {
|
| 45 |
+
|
| 46 |
+
// This class holds information about the relative configuration of camera rigs.
|
| 47 |
+
// Camera rigs are composed of multiple cameras with a rigid relative extrinsic
|
| 48 |
+
// configuration over multiple snapshots. Snapshots are defined as the
|
| 49 |
+
// collection of images captured simultaneously by all cameras in the rig.
|
| 50 |
+
class CameraRig {
|
| 51 |
+
public:
|
| 52 |
+
CameraRig();
|
| 53 |
+
|
| 54 |
+
// The number of cameras in the rig.
|
| 55 |
+
size_t NumCameras() const;
|
| 56 |
+
|
| 57 |
+
// The number of snapshots captured by this rig.
|
| 58 |
+
size_t NumSnapshots() const;
|
| 59 |
+
|
| 60 |
+
// Check whether the given camera is part of the rig.
|
| 61 |
+
bool HasCamera(const camera_t camera_id) const;
|
| 62 |
+
|
| 63 |
+
// Access the reference camera.
|
| 64 |
+
camera_t RefCameraId() const;
|
| 65 |
+
void SetRefCameraId(const camera_t camera_id);
|
| 66 |
+
|
| 67 |
+
// Get the identifiers of the cameras in the rig.
|
| 68 |
+
std::vector<camera_t> GetCameraIds() const;
|
| 69 |
+
|
| 70 |
+
// Get the snapshots of the camera rig.
|
| 71 |
+
const std::vector<std::vector<image_t>>& Snapshots() const;
|
| 72 |
+
|
| 73 |
+
// Add a new camera to the rig. The relative pose may contain dummy values and
|
| 74 |
+
// can then be computed automatically from a given reconstruction using the
|
| 75 |
+
// method `ComputeRelativePoses`.
|
| 76 |
+
void AddCamera(const camera_t camera_id, const Eigen::Vector4d& rel_qvec,
|
| 77 |
+
const Eigen::Vector3d& rel_tvec);
|
| 78 |
+
|
| 79 |
+
// Add the images of a single snapshot to rig. A snapshot consists of the
|
| 80 |
+
// captured images of all cameras of the rig. All images of a snapshot share
|
| 81 |
+
// the same global camera rig pose, i.e. all images in the camera rig are
|
| 82 |
+
// captured simultaneously.
|
| 83 |
+
void AddSnapshot(const std::vector<image_t>& image_ids);
|
| 84 |
+
|
| 85 |
+
// Check whether the camera rig setup is valid.
|
| 86 |
+
void Check(const Reconstruction& reconstruction) const;
|
| 87 |
+
|
| 88 |
+
// Get the relative poses of the cameras in the rig.
|
| 89 |
+
Eigen::Vector4d& RelativeQvec(const camera_t camera_id);
|
| 90 |
+
const Eigen::Vector4d& RelativeQvec(const camera_t camera_id) const;
|
| 91 |
+
Eigen::Vector3d& RelativeTvec(const camera_t camera_id);
|
| 92 |
+
const Eigen::Vector3d& RelativeTvec(const camera_t camera_id) const;
|
| 93 |
+
|
| 94 |
+
// Compute the scaling factor from the reconstruction to the camera rig
|
| 95 |
+
// dimensions by averaging over the distances between the projection centers.
|
| 96 |
+
// Note that this assumes that there is at least one camera pair in the rig
|
| 97 |
+
// with non-zero baseline, otherwise the function returns NaN.
|
| 98 |
+
double ComputeScale(const Reconstruction& reconstruction) const;
|
| 99 |
+
|
| 100 |
+
// Compute the relative poses in the rig from the reconstruction by averaging
|
| 101 |
+
// the relative poses over all snapshots. The pose of the reference camera
|
| 102 |
+
// will be the identity transformation. This assumes that the camera rig has
|
| 103 |
+
// snapshots that are registered in the reconstruction.
|
| 104 |
+
bool ComputeRelativePoses(const Reconstruction& reconstruction);
|
| 105 |
+
|
| 106 |
+
// Compute the absolute camera pose of the rig. The absolute camera pose of
|
| 107 |
+
// the rig is computed as the average of all relative camera poses in the rig
|
| 108 |
+
// and their corresponding image poses in the reconstruction.
|
| 109 |
+
void ComputeAbsolutePose(const size_t snapshot_idx,
|
| 110 |
+
const Reconstruction& reconstruction,
|
| 111 |
+
Eigen::Vector4d* abs_qvec,
|
| 112 |
+
Eigen::Vector3d* abs_tvec) const;
|
| 113 |
+
|
| 114 |
+
private:
|
| 115 |
+
struct RigCamera {
|
| 116 |
+
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
| 117 |
+
Eigen::Vector4d rel_qvec = ComposeIdentityQuaternion();
|
| 118 |
+
Eigen::Vector3d rel_tvec = Eigen::Vector3d(0, 0, 0);
|
| 119 |
+
};
|
| 120 |
+
|
| 121 |
+
camera_t ref_camera_id_ = kInvalidCameraId;
|
| 122 |
+
EIGEN_STL_UMAP(camera_t, RigCamera) rig_cameras_;
|
| 123 |
+
std::vector<std::vector<image_t>> snapshots_;
|
| 124 |
+
};
|
| 125 |
+
|
| 126 |
+
} // namespace colmap
|
| 127 |
+
|
| 128 |
+
#endif // COLMAP_SRC_BASE_CAMERA_RIG_H_
|
colmap/include/colmap/base/correspondence_graph.h
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_BASE_CORRESPONDENCE_GRAPH_H_
|
| 33 |
+
#define COLMAP_SRC_BASE_CORRESPONDENCE_GRAPH_H_
|
| 34 |
+
|
| 35 |
+
#include <unordered_map>
|
| 36 |
+
#include <vector>
|
| 37 |
+
|
| 38 |
+
#include "base/database.h"
|
| 39 |
+
#include "util/types.h"
|
| 40 |
+
|
| 41 |
+
namespace colmap {
|
| 42 |
+
|
| 43 |
+
// Scene graph represents the graph of image to image and feature to feature
|
| 44 |
+
// correspondences of a dataset. It should be accessed from the DatabaseCache.
|
| 45 |
+
class CorrespondenceGraph {
|
| 46 |
+
public:
|
| 47 |
+
struct Correspondence {
|
| 48 |
+
Correspondence()
|
| 49 |
+
: image_id(kInvalidImageId), point2D_idx(kInvalidPoint2DIdx) {}
|
| 50 |
+
Correspondence(const image_t image_id, const point2D_t point2D_idx)
|
| 51 |
+
: image_id(image_id), point2D_idx(point2D_idx) {}
|
| 52 |
+
|
| 53 |
+
// The identifier of the corresponding image.
|
| 54 |
+
image_t image_id;
|
| 55 |
+
|
| 56 |
+
// The index of the corresponding point in the corresponding image.
|
| 57 |
+
point2D_t point2D_idx;
|
| 58 |
+
};
|
| 59 |
+
|
| 60 |
+
CorrespondenceGraph();
|
| 61 |
+
|
| 62 |
+
// Number of added images.
|
| 63 |
+
inline size_t NumImages() const;
|
| 64 |
+
|
| 65 |
+
// Number of added images.
|
| 66 |
+
inline size_t NumImagePairs() const;
|
| 67 |
+
|
| 68 |
+
// Check whether image exists.
|
| 69 |
+
inline bool ExistsImage(const image_t image_id) const;
|
| 70 |
+
|
| 71 |
+
// Get the number of observations in an image. An observation is an image
|
| 72 |
+
// point that has at least one correspondence.
|
| 73 |
+
inline point2D_t NumObservationsForImage(const image_t image_id) const;
|
| 74 |
+
|
| 75 |
+
// Get the number of correspondences per image.
|
| 76 |
+
inline point2D_t NumCorrespondencesForImage(const image_t image_id) const;
|
| 77 |
+
|
| 78 |
+
// Get the number of correspondences between a pair of images.
|
| 79 |
+
inline point2D_t NumCorrespondencesBetweenImages(
|
| 80 |
+
const image_t image_id1, const image_t image_id2) const;
|
| 81 |
+
|
| 82 |
+
// Get the number of correspondences between all images.
|
| 83 |
+
std::unordered_map<image_pair_t, point2D_t> NumCorrespondencesBetweenImages()
|
| 84 |
+
const;
|
| 85 |
+
|
| 86 |
+
// Finalize the database manager.
|
| 87 |
+
//
|
| 88 |
+
// - Calculates the number of observations per image by counting the number
|
| 89 |
+
// of image points that have at least one correspondence.
|
| 90 |
+
// - Deletes images without observations, as they are useless for SfM.
|
| 91 |
+
// - Shrinks the correspondence vectors to their size to save memory.
|
| 92 |
+
void Finalize();
|
| 93 |
+
|
| 94 |
+
// Add new image to the correspondence graph.
|
| 95 |
+
void AddImage(const image_t image_id, const size_t num_points2D);
|
| 96 |
+
|
| 97 |
+
// Add correspondences between images. This function ignores invalid
|
| 98 |
+
// correspondences where the point indices are out of bounds or duplicate
|
| 99 |
+
// correspondences between the same image points. Whenever either of the two
|
| 100 |
+
// cases occur this function prints a warning to the standard output.
|
| 101 |
+
void AddCorrespondences(const image_t image_id1, const image_t image_id2,
|
| 102 |
+
const FeatureMatches& matches);
|
| 103 |
+
|
| 104 |
+
// Find the correspondence of an image observation to all other images.
|
| 105 |
+
inline const std::vector<Correspondence>& FindCorrespondences(
|
| 106 |
+
const image_t image_id, const point2D_t point2D_idx) const;
|
| 107 |
+
|
| 108 |
+
// Find correspondences to the given observation.
|
| 109 |
+
//
|
| 110 |
+
// Transitively collects correspondences to the given observation by first
|
| 111 |
+
// finding correspondences to the given observation, then looking for
|
| 112 |
+
// correspondences to the collected correspondences in the first step, and so
|
| 113 |
+
// forth until the transitivity is exhausted or no more correspondences are
|
| 114 |
+
// found. The returned list does not contain duplicates and contains
|
| 115 |
+
// the given observation.
|
| 116 |
+
void FindTransitiveCorrespondences(
|
| 117 |
+
const image_t image_id, const point2D_t point2D_idx,
|
| 118 |
+
const size_t transitivity,
|
| 119 |
+
std::vector<Correspondence>* found_corrs) const;
|
| 120 |
+
|
| 121 |
+
// Find all correspondences between two images.
|
| 122 |
+
FeatureMatches FindCorrespondencesBetweenImages(
|
| 123 |
+
const image_t image_id1, const image_t image_id2) const;
|
| 124 |
+
|
| 125 |
+
// Check whether the image point has correspondences.
|
| 126 |
+
inline bool HasCorrespondences(const image_t image_id,
|
| 127 |
+
const point2D_t point2D_idx) const;
|
| 128 |
+
|
| 129 |
+
// Check whether the given observation is part of a two-view track, i.e.
|
| 130 |
+
// it only has one correspondence and that correspondence has the given
|
| 131 |
+
// observation as its only correspondence.
|
| 132 |
+
bool IsTwoViewObservation(const image_t image_id,
|
| 133 |
+
const point2D_t point2D_idx) const;
|
| 134 |
+
|
| 135 |
+
private:
|
| 136 |
+
struct Image {
|
| 137 |
+
// Number of 2D points with at least one correspondence to another image.
|
| 138 |
+
point2D_t num_observations = 0;
|
| 139 |
+
|
| 140 |
+
// Total number of correspondences to other images. This measure is useful
|
| 141 |
+
// to find a good initial pair, that is connected to many images.
|
| 142 |
+
point2D_t num_correspondences = 0;
|
| 143 |
+
|
| 144 |
+
// Correspondences to other images per image point.
|
| 145 |
+
std::vector<std::vector<Correspondence>> corrs;
|
| 146 |
+
};
|
| 147 |
+
|
| 148 |
+
struct ImagePair {
|
| 149 |
+
// The number of correspondences between pairs of images.
|
| 150 |
+
point2D_t num_correspondences = 0;
|
| 151 |
+
};
|
| 152 |
+
|
| 153 |
+
EIGEN_STL_UMAP(image_t, Image) images_;
|
| 154 |
+
std::unordered_map<image_pair_t, ImagePair> image_pairs_;
|
| 155 |
+
};
|
| 156 |
+
|
| 157 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 158 |
+
// Implementation
|
| 159 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 160 |
+
|
| 161 |
+
size_t CorrespondenceGraph::NumImages() const { return images_.size(); }
|
| 162 |
+
|
| 163 |
+
size_t CorrespondenceGraph::NumImagePairs() const {
|
| 164 |
+
return image_pairs_.size();
|
| 165 |
+
}
|
| 166 |
+
|
| 167 |
+
bool CorrespondenceGraph::ExistsImage(const image_t image_id) const {
|
| 168 |
+
return images_.find(image_id) != images_.end();
|
| 169 |
+
}
|
| 170 |
+
|
| 171 |
+
point2D_t CorrespondenceGraph::NumObservationsForImage(
|
| 172 |
+
const image_t image_id) const {
|
| 173 |
+
return images_.at(image_id).num_observations;
|
| 174 |
+
}
|
| 175 |
+
|
| 176 |
+
point2D_t CorrespondenceGraph::NumCorrespondencesForImage(
|
| 177 |
+
const image_t image_id) const {
|
| 178 |
+
return images_.at(image_id).num_correspondences;
|
| 179 |
+
}
|
| 180 |
+
|
| 181 |
+
point2D_t CorrespondenceGraph::NumCorrespondencesBetweenImages(
|
| 182 |
+
const image_t image_id1, const image_t image_id2) const {
|
| 183 |
+
const image_pair_t pair_id =
|
| 184 |
+
Database::ImagePairToPairId(image_id1, image_id2);
|
| 185 |
+
const auto it = image_pairs_.find(pair_id);
|
| 186 |
+
if (it == image_pairs_.end()) {
|
| 187 |
+
return 0;
|
| 188 |
+
} else {
|
| 189 |
+
return static_cast<point2D_t>(it->second.num_correspondences);
|
| 190 |
+
}
|
| 191 |
+
}
|
| 192 |
+
|
| 193 |
+
const std::vector<CorrespondenceGraph::Correspondence>&
|
| 194 |
+
CorrespondenceGraph::FindCorrespondences(const image_t image_id,
|
| 195 |
+
const point2D_t point2D_idx) const {
|
| 196 |
+
return images_.at(image_id).corrs.at(point2D_idx);
|
| 197 |
+
}
|
| 198 |
+
|
| 199 |
+
bool CorrespondenceGraph::HasCorrespondences(
|
| 200 |
+
const image_t image_id, const point2D_t point2D_idx) const {
|
| 201 |
+
return !images_.at(image_id).corrs.at(point2D_idx).empty();
|
| 202 |
+
}
|
| 203 |
+
|
| 204 |
+
} // namespace colmap
|
| 205 |
+
|
| 206 |
+
#endif // COLMAP_SRC_BASE_CORRESPONDENCE_GRAPH_H_
|
colmap/include/colmap/base/cost_functions.h
ADDED
|
@@ -0,0 +1,301 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_BASE_COST_FUNCTIONS_H_
|
| 33 |
+
#define COLMAP_SRC_BASE_COST_FUNCTIONS_H_
|
| 34 |
+
|
| 35 |
+
#include <Eigen/Core>
|
| 36 |
+
|
| 37 |
+
#include <ceres/ceres.h>
|
| 38 |
+
#include <ceres/rotation.h>
|
| 39 |
+
|
| 40 |
+
namespace colmap {
|
| 41 |
+
|
| 42 |
+
// Standard bundle adjustment cost function for variable
|
| 43 |
+
// camera pose and calibration and point parameters.
|
| 44 |
+
template <typename CameraModel>
|
| 45 |
+
class BundleAdjustmentCostFunction {
|
| 46 |
+
public:
|
| 47 |
+
explicit BundleAdjustmentCostFunction(const Eigen::Vector2d& point2D)
|
| 48 |
+
: observed_x_(point2D(0)), observed_y_(point2D(1)) {}
|
| 49 |
+
|
| 50 |
+
static ceres::CostFunction* Create(const Eigen::Vector2d& point2D) {
|
| 51 |
+
return (new ceres::AutoDiffCostFunction<
|
| 52 |
+
BundleAdjustmentCostFunction<CameraModel>, 2, 4, 3, 3,
|
| 53 |
+
CameraModel::kNumParams>(
|
| 54 |
+
new BundleAdjustmentCostFunction(point2D)));
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
template <typename T>
|
| 58 |
+
bool operator()(const T* const qvec, const T* const tvec,
|
| 59 |
+
const T* const point3D, const T* const camera_params,
|
| 60 |
+
T* residuals) const {
|
| 61 |
+
// Rotate and translate.
|
| 62 |
+
T projection[3];
|
| 63 |
+
ceres::UnitQuaternionRotatePoint(qvec, point3D, projection);
|
| 64 |
+
projection[0] += tvec[0];
|
| 65 |
+
projection[1] += tvec[1];
|
| 66 |
+
projection[2] += tvec[2];
|
| 67 |
+
|
| 68 |
+
// Project to image plane.
|
| 69 |
+
projection[0] /= projection[2];
|
| 70 |
+
projection[1] /= projection[2];
|
| 71 |
+
|
| 72 |
+
// Distort and transform to pixel space.
|
| 73 |
+
CameraModel::WorldToImage(camera_params, projection[0], projection[1],
|
| 74 |
+
&residuals[0], &residuals[1]);
|
| 75 |
+
|
| 76 |
+
// Re-projection error.
|
| 77 |
+
residuals[0] -= T(observed_x_);
|
| 78 |
+
residuals[1] -= T(observed_y_);
|
| 79 |
+
|
| 80 |
+
return true;
|
| 81 |
+
}
|
| 82 |
+
|
| 83 |
+
private:
|
| 84 |
+
const double observed_x_;
|
| 85 |
+
const double observed_y_;
|
| 86 |
+
};
|
| 87 |
+
|
| 88 |
+
// Bundle adjustment cost function for variable
|
| 89 |
+
// camera calibration and point parameters, and fixed camera pose.
|
| 90 |
+
template <typename CameraModel>
|
| 91 |
+
class BundleAdjustmentConstantPoseCostFunction {
|
| 92 |
+
public:
|
| 93 |
+
BundleAdjustmentConstantPoseCostFunction(const Eigen::Vector4d& qvec,
|
| 94 |
+
const Eigen::Vector3d& tvec,
|
| 95 |
+
const Eigen::Vector2d& point2D)
|
| 96 |
+
: qw_(qvec(0)),
|
| 97 |
+
qx_(qvec(1)),
|
| 98 |
+
qy_(qvec(2)),
|
| 99 |
+
qz_(qvec(3)),
|
| 100 |
+
tx_(tvec(0)),
|
| 101 |
+
ty_(tvec(1)),
|
| 102 |
+
tz_(tvec(2)),
|
| 103 |
+
observed_x_(point2D(0)),
|
| 104 |
+
observed_y_(point2D(1)) {}
|
| 105 |
+
|
| 106 |
+
static ceres::CostFunction* Create(const Eigen::Vector4d& qvec,
|
| 107 |
+
const Eigen::Vector3d& tvec,
|
| 108 |
+
const Eigen::Vector2d& point2D) {
|
| 109 |
+
return (new ceres::AutoDiffCostFunction<
|
| 110 |
+
BundleAdjustmentConstantPoseCostFunction<CameraModel>, 2, 3,
|
| 111 |
+
CameraModel::kNumParams>(
|
| 112 |
+
new BundleAdjustmentConstantPoseCostFunction(qvec, tvec, point2D)));
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
template <typename T>
|
| 116 |
+
bool operator()(const T* const point3D, const T* const camera_params,
|
| 117 |
+
T* residuals) const {
|
| 118 |
+
const T qvec[4] = {T(qw_), T(qx_), T(qy_), T(qz_)};
|
| 119 |
+
|
| 120 |
+
// Rotate and translate.
|
| 121 |
+
T projection[3];
|
| 122 |
+
ceres::UnitQuaternionRotatePoint(qvec, point3D, projection);
|
| 123 |
+
projection[0] += T(tx_);
|
| 124 |
+
projection[1] += T(ty_);
|
| 125 |
+
projection[2] += T(tz_);
|
| 126 |
+
|
| 127 |
+
// Project to image plane.
|
| 128 |
+
projection[0] /= projection[2];
|
| 129 |
+
projection[1] /= projection[2];
|
| 130 |
+
|
| 131 |
+
// Distort and transform to pixel space.
|
| 132 |
+
CameraModel::WorldToImage(camera_params, projection[0], projection[1],
|
| 133 |
+
&residuals[0], &residuals[1]);
|
| 134 |
+
|
| 135 |
+
// Re-projection error.
|
| 136 |
+
residuals[0] -= T(observed_x_);
|
| 137 |
+
residuals[1] -= T(observed_y_);
|
| 138 |
+
|
| 139 |
+
return true;
|
| 140 |
+
}
|
| 141 |
+
|
| 142 |
+
private:
|
| 143 |
+
const double qw_;
|
| 144 |
+
const double qx_;
|
| 145 |
+
const double qy_;
|
| 146 |
+
const double qz_;
|
| 147 |
+
const double tx_;
|
| 148 |
+
const double ty_;
|
| 149 |
+
const double tz_;
|
| 150 |
+
const double observed_x_;
|
| 151 |
+
const double observed_y_;
|
| 152 |
+
};
|
| 153 |
+
|
| 154 |
+
// Rig bundle adjustment cost function for variable camera pose and calibration
|
| 155 |
+
// and point parameters. Different from the standard bundle adjustment function,
|
| 156 |
+
// this cost function is suitable for camera rigs with consistent relative poses
|
| 157 |
+
// of the cameras within the rig. The cost function first projects points into
|
| 158 |
+
// the local system of the camera rig and then into the local system of the
|
| 159 |
+
// camera within the rig.
|
| 160 |
+
template <typename CameraModel>
|
| 161 |
+
class RigBundleAdjustmentCostFunction {
|
| 162 |
+
public:
|
| 163 |
+
explicit RigBundleAdjustmentCostFunction(const Eigen::Vector2d& point2D)
|
| 164 |
+
: observed_x_(point2D(0)), observed_y_(point2D(1)) {}
|
| 165 |
+
|
| 166 |
+
static ceres::CostFunction* Create(const Eigen::Vector2d& point2D) {
|
| 167 |
+
return (new ceres::AutoDiffCostFunction<
|
| 168 |
+
RigBundleAdjustmentCostFunction<CameraModel>, 2, 4, 3, 4, 3, 3,
|
| 169 |
+
CameraModel::kNumParams>(
|
| 170 |
+
new RigBundleAdjustmentCostFunction(point2D)));
|
| 171 |
+
}
|
| 172 |
+
|
| 173 |
+
template <typename T>
|
| 174 |
+
bool operator()(const T* const rig_qvec, const T* const rig_tvec,
|
| 175 |
+
const T* const rel_qvec, const T* const rel_tvec,
|
| 176 |
+
const T* const point3D, const T* const camera_params,
|
| 177 |
+
T* residuals) const {
|
| 178 |
+
// Concatenate rotations.
|
| 179 |
+
T qvec[4];
|
| 180 |
+
ceres::QuaternionProduct(rel_qvec, rig_qvec, qvec);
|
| 181 |
+
|
| 182 |
+
// Concatenate translations.
|
| 183 |
+
T tvec[3];
|
| 184 |
+
ceres::UnitQuaternionRotatePoint(rel_qvec, rig_tvec, tvec);
|
| 185 |
+
tvec[0] += rel_tvec[0];
|
| 186 |
+
tvec[1] += rel_tvec[1];
|
| 187 |
+
tvec[2] += rel_tvec[2];
|
| 188 |
+
|
| 189 |
+
// Rotate and translate.
|
| 190 |
+
T projection[3];
|
| 191 |
+
ceres::UnitQuaternionRotatePoint(qvec, point3D, projection);
|
| 192 |
+
projection[0] += tvec[0];
|
| 193 |
+
projection[1] += tvec[1];
|
| 194 |
+
projection[2] += tvec[2];
|
| 195 |
+
|
| 196 |
+
// Project to image plane.
|
| 197 |
+
projection[0] /= projection[2];
|
| 198 |
+
projection[1] /= projection[2];
|
| 199 |
+
|
| 200 |
+
// Distort and transform to pixel space.
|
| 201 |
+
CameraModel::WorldToImage(camera_params, projection[0], projection[1],
|
| 202 |
+
&residuals[0], &residuals[1]);
|
| 203 |
+
|
| 204 |
+
// Re-projection error.
|
| 205 |
+
residuals[0] -= T(observed_x_);
|
| 206 |
+
residuals[1] -= T(observed_y_);
|
| 207 |
+
|
| 208 |
+
return true;
|
| 209 |
+
}
|
| 210 |
+
|
| 211 |
+
private:
|
| 212 |
+
const double observed_x_;
|
| 213 |
+
const double observed_y_;
|
| 214 |
+
};
|
| 215 |
+
|
| 216 |
+
// Cost function for refining two-view geometry based on the Sampson-Error.
|
| 217 |
+
//
|
| 218 |
+
// First pose is assumed to be located at the origin with 0 rotation. Second
|
| 219 |
+
// pose is assumed to be on the unit sphere around the first pose, i.e. the
|
| 220 |
+
// pose of the second camera is parameterized by a 3D rotation and a
|
| 221 |
+
// 3D translation with unit norm. `tvec` is therefore over-parameterized as is
|
| 222 |
+
// and should be down-projected using `SphereManifold`.
|
| 223 |
+
class RelativePoseCostFunction {
|
| 224 |
+
public:
|
| 225 |
+
RelativePoseCostFunction(const Eigen::Vector2d& x1, const Eigen::Vector2d& x2)
|
| 226 |
+
: x1_(x1(0)), y1_(x1(1)), x2_(x2(0)), y2_(x2(1)) {}
|
| 227 |
+
|
| 228 |
+
static ceres::CostFunction* Create(const Eigen::Vector2d& x1,
|
| 229 |
+
const Eigen::Vector2d& x2) {
|
| 230 |
+
return (new ceres::AutoDiffCostFunction<RelativePoseCostFunction, 1, 4, 3>(
|
| 231 |
+
new RelativePoseCostFunction(x1, x2)));
|
| 232 |
+
}
|
| 233 |
+
|
| 234 |
+
template <typename T>
|
| 235 |
+
bool operator()(const T* const qvec, const T* const tvec,
|
| 236 |
+
T* residuals) const {
|
| 237 |
+
Eigen::Matrix<T, 3, 3, Eigen::RowMajor> R;
|
| 238 |
+
ceres::QuaternionToRotation(qvec, R.data());
|
| 239 |
+
|
| 240 |
+
// Matrix representation of the cross product t x R.
|
| 241 |
+
Eigen::Matrix<T, 3, 3> t_x;
|
| 242 |
+
t_x << T(0), -tvec[2], tvec[1], tvec[2], T(0), -tvec[0], -tvec[1], tvec[0],
|
| 243 |
+
T(0);
|
| 244 |
+
|
| 245 |
+
// Essential matrix.
|
| 246 |
+
const Eigen::Matrix<T, 3, 3> E = t_x * R;
|
| 247 |
+
|
| 248 |
+
// Homogeneous image coordinates.
|
| 249 |
+
const Eigen::Matrix<T, 3, 1> x1_h(T(x1_), T(y1_), T(1));
|
| 250 |
+
const Eigen::Matrix<T, 3, 1> x2_h(T(x2_), T(y2_), T(1));
|
| 251 |
+
|
| 252 |
+
// Squared sampson error.
|
| 253 |
+
const Eigen::Matrix<T, 3, 1> Ex1 = E * x1_h;
|
| 254 |
+
const Eigen::Matrix<T, 3, 1> Etx2 = E.transpose() * x2_h;
|
| 255 |
+
const T x2tEx1 = x2_h.transpose() * Ex1;
|
| 256 |
+
residuals[0] = x2tEx1 * x2tEx1 /
|
| 257 |
+
(Ex1(0) * Ex1(0) + Ex1(1) * Ex1(1) + Etx2(0) * Etx2(0) +
|
| 258 |
+
Etx2(1) * Etx2(1));
|
| 259 |
+
|
| 260 |
+
return true;
|
| 261 |
+
}
|
| 262 |
+
|
| 263 |
+
private:
|
| 264 |
+
const double x1_;
|
| 265 |
+
const double y1_;
|
| 266 |
+
const double x2_;
|
| 267 |
+
const double y2_;
|
| 268 |
+
};
|
| 269 |
+
|
| 270 |
+
inline void SetQuaternionManifold(ceres::Problem* problem, double* qvec) {
|
| 271 |
+
#if CERES_VERSION_MAJOR >= 2 && CERES_VERSION_MINOR >= 1
|
| 272 |
+
problem->SetManifold(qvec, new ceres::QuaternionManifold);
|
| 273 |
+
#else
|
| 274 |
+
problem->SetParameterization(qvec, new ceres::QuaternionParameterization);
|
| 275 |
+
#endif
|
| 276 |
+
}
|
| 277 |
+
|
| 278 |
+
inline void SetSubsetManifold(int size, const std::vector<int>& constant_params,
|
| 279 |
+
ceres::Problem* problem, double* params) {
|
| 280 |
+
#if CERES_VERSION_MAJOR >= 2 && CERES_VERSION_MINOR >= 1
|
| 281 |
+
problem->SetManifold(params,
|
| 282 |
+
new ceres::SubsetManifold(size, constant_params));
|
| 283 |
+
#else
|
| 284 |
+
problem->SetParameterization(
|
| 285 |
+
params, new ceres::SubsetParameterization(size, constant_params));
|
| 286 |
+
#endif
|
| 287 |
+
}
|
| 288 |
+
|
| 289 |
+
template <int size>
|
| 290 |
+
inline void SetSphereManifold(ceres::Problem* problem, double* params) {
|
| 291 |
+
#if CERES_VERSION_MAJOR >= 2 && CERES_VERSION_MINOR >= 1
|
| 292 |
+
problem->SetManifold(params, new ceres::SphereManifold<size>);
|
| 293 |
+
#else
|
| 294 |
+
problem->SetParameterization(
|
| 295 |
+
params, new ceres::HomogeneousVectorParameterization(size));
|
| 296 |
+
#endif
|
| 297 |
+
}
|
| 298 |
+
|
| 299 |
+
} // namespace colmap
|
| 300 |
+
|
| 301 |
+
#endif // COLMAP_SRC_BASE_COST_FUNCTIONS_H_
|
colmap/include/colmap/base/database.h
ADDED
|
@@ -0,0 +1,394 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_BASE_DATABASE_H_
|
| 33 |
+
#define COLMAP_SRC_BASE_DATABASE_H_
|
| 34 |
+
|
| 35 |
+
#include <mutex>
|
| 36 |
+
#include <unordered_map>
|
| 37 |
+
#include <vector>
|
| 38 |
+
|
| 39 |
+
#include <Eigen/Core>
|
| 40 |
+
#include <sqlite3.h>
|
| 41 |
+
|
| 42 |
+
#include "base/camera.h"
|
| 43 |
+
#include "base/image.h"
|
| 44 |
+
#include "estimators/two_view_geometry.h"
|
| 45 |
+
#include "feature/types.h"
|
| 46 |
+
#include "util/types.h"
|
| 47 |
+
|
| 48 |
+
namespace colmap {
|
| 49 |
+
|
| 50 |
+
// Database class to read and write images, features, cameras, matches, etc.
|
| 51 |
+
// from a SQLite database. The class is not thread-safe and must not be accessed
|
| 52 |
+
// concurrently. The class is optimized for single-thread speed and for optimal
|
| 53 |
+
// performance, wrap multiple method calls inside a leading `BeginTransaction`
|
| 54 |
+
// and trailing `EndTransaction`.
|
| 55 |
+
class Database {
|
| 56 |
+
public:
|
| 57 |
+
const static int kSchemaVersion = 1;
|
| 58 |
+
|
| 59 |
+
// The maximum number of images, that can be stored in the database.
|
| 60 |
+
// This limitation arises due to the fact, that we generate unique IDs for
|
| 61 |
+
// image pairs manually. Note: do not change this to
|
| 62 |
+
// another type than `size_t`.
|
| 63 |
+
const static size_t kMaxNumImages;
|
| 64 |
+
|
| 65 |
+
Database();
|
| 66 |
+
explicit Database(const std::string& path);
|
| 67 |
+
~Database();
|
| 68 |
+
|
| 69 |
+
// Open and close database. The same database should not be opened
|
| 70 |
+
// concurrently in multiple threads or processes.
|
| 71 |
+
void Open(const std::string& path);
|
| 72 |
+
void Close();
|
| 73 |
+
|
| 74 |
+
// Check if entry already exists in database. For image pairs, the order of
|
| 75 |
+
// `image_id1` and `image_id2` does not matter.
|
| 76 |
+
bool ExistsCamera(const camera_t camera_id) const;
|
| 77 |
+
bool ExistsImage(const image_t image_id) const;
|
| 78 |
+
bool ExistsImageWithName(std::string name) const;
|
| 79 |
+
bool ExistsKeypoints(const image_t image_id) const;
|
| 80 |
+
bool ExistsDescriptors(const image_t image_id) const;
|
| 81 |
+
bool ExistsMatches(const image_t image_id1, const image_t image_id2) const;
|
| 82 |
+
bool ExistsInlierMatches(const image_t image_id1,
|
| 83 |
+
const image_t image_id2) const;
|
| 84 |
+
|
| 85 |
+
// Number of rows in `cameras` table.
|
| 86 |
+
size_t NumCameras() const;
|
| 87 |
+
|
| 88 |
+
// Number of rows in `images` table.
|
| 89 |
+
size_t NumImages() const;
|
| 90 |
+
|
| 91 |
+
// Sum of `rows` column in `keypoints` table, i.e. number of total keypoints.
|
| 92 |
+
size_t NumKeypoints() const;
|
| 93 |
+
|
| 94 |
+
// The number of keypoints for the image with most features.
|
| 95 |
+
size_t MaxNumKeypoints() const;
|
| 96 |
+
|
| 97 |
+
// Number of descriptors for specific image.
|
| 98 |
+
size_t NumKeypointsForImage(const image_t image_id) const;
|
| 99 |
+
|
| 100 |
+
// Sum of `rows` column in `descriptors` table,
|
| 101 |
+
// i.e. number of total descriptors.
|
| 102 |
+
size_t NumDescriptors() const;
|
| 103 |
+
|
| 104 |
+
// The number of descriptors for the image with most features.
|
| 105 |
+
size_t MaxNumDescriptors() const;
|
| 106 |
+
|
| 107 |
+
// Number of descriptors for specific image.
|
| 108 |
+
size_t NumDescriptorsForImage(const image_t image_id) const;
|
| 109 |
+
|
| 110 |
+
// Sum of `rows` column in `matches` table, i.e. number of total matches.
|
| 111 |
+
size_t NumMatches() const;
|
| 112 |
+
|
| 113 |
+
// Sum of `rows` column in `two_view_geometries` table,
|
| 114 |
+
// i.e. number of total inlier matches.
|
| 115 |
+
size_t NumInlierMatches() const;
|
| 116 |
+
|
| 117 |
+
// Number of rows in `matches` table.
|
| 118 |
+
size_t NumMatchedImagePairs() const;
|
| 119 |
+
|
| 120 |
+
// Number of rows in `two_view_geometries` table.
|
| 121 |
+
size_t NumVerifiedImagePairs() const;
|
| 122 |
+
|
| 123 |
+
// Each image pair is assigned an unique ID in the `matches` and
|
| 124 |
+
// `two_view_geometries` table. We intentionally avoid to store the pairs in a
|
| 125 |
+
// separate table by using e.g. AUTOINCREMENT, since the overhead of querying
|
| 126 |
+
// the unique pair ID is significant.
|
| 127 |
+
inline static image_pair_t ImagePairToPairId(const image_t image_id1,
|
| 128 |
+
const image_t image_id2);
|
| 129 |
+
|
| 130 |
+
inline static void PairIdToImagePair(const image_pair_t pair_id,
|
| 131 |
+
image_t* image_id1, image_t* image_id2);
|
| 132 |
+
|
| 133 |
+
// Return true if image pairs should be swapped. Used to enforce a specific
|
| 134 |
+
// image order to generate unique image pair identifiers independent of the
|
| 135 |
+
// order in which the image identifiers are used.
|
| 136 |
+
inline static bool SwapImagePair(const image_t image_id1,
|
| 137 |
+
const image_t image_id2);
|
| 138 |
+
|
| 139 |
+
// Read an existing entry in the database. The user is responsible for making
|
| 140 |
+
// sure that the entry actually exists. For image pairs, the order of
|
| 141 |
+
// `image_id1` and `image_id2` does not matter.
|
| 142 |
+
Camera ReadCamera(const camera_t camera_id) const;
|
| 143 |
+
std::vector<Camera> ReadAllCameras() const;
|
| 144 |
+
|
| 145 |
+
Image ReadImage(const image_t image_id) const;
|
| 146 |
+
Image ReadImageWithName(const std::string& name) const;
|
| 147 |
+
std::vector<Image> ReadAllImages() const;
|
| 148 |
+
|
| 149 |
+
FeatureKeypoints ReadKeypoints(const image_t image_id) const;
|
| 150 |
+
FeatureDescriptors ReadDescriptors(const image_t image_id) const;
|
| 151 |
+
|
| 152 |
+
FeatureMatches ReadMatches(const image_t image_id1,
|
| 153 |
+
const image_t image_id2) const;
|
| 154 |
+
std::vector<std::pair<image_pair_t, FeatureMatches>> ReadAllMatches() const;
|
| 155 |
+
|
| 156 |
+
TwoViewGeometry ReadTwoViewGeometry(const image_t image_id1,
|
| 157 |
+
const image_t image_id2) const;
|
| 158 |
+
void ReadTwoViewGeometries(
|
| 159 |
+
std::vector<image_pair_t>* image_pair_ids,
|
| 160 |
+
std::vector<TwoViewGeometry>* two_view_geometries) const;
|
| 161 |
+
|
| 162 |
+
// Read all image pairs that have an entry in the `NumVerifiedImagePairs`
|
| 163 |
+
// table with at least one inlier match and their number of inlier matches.
|
| 164 |
+
void ReadTwoViewGeometryNumInliers(
|
| 165 |
+
std::vector<std::pair<image_t, image_t>>* image_pairs,
|
| 166 |
+
std::vector<int>* num_inliers) const;
|
| 167 |
+
|
| 168 |
+
// Add new camera and return its database identifier. If `use_camera_id`
|
| 169 |
+
// is false a new identifier is automatically generated.
|
| 170 |
+
camera_t WriteCamera(const Camera& camera,
|
| 171 |
+
const bool use_camera_id = false) const;
|
| 172 |
+
|
| 173 |
+
// Add new image and return its database identifier. If `use_image_id`
|
| 174 |
+
// is false a new identifier is automatically generated.
|
| 175 |
+
image_t WriteImage(const Image& image, const bool use_image_id = false) const;
|
| 176 |
+
|
| 177 |
+
// Write a new entry in the database. The user is responsible for making sure
|
| 178 |
+
// that the entry does not yet exist. For image pairs, the order of
|
| 179 |
+
// `image_id1` and `image_id2` does not matter.
|
| 180 |
+
void WriteKeypoints(const image_t image_id,
|
| 181 |
+
const FeatureKeypoints& keypoints) const;
|
| 182 |
+
void WriteDescriptors(const image_t image_id,
|
| 183 |
+
const FeatureDescriptors& descriptors) const;
|
| 184 |
+
void WriteMatches(const image_t image_id1, const image_t image_id2,
|
| 185 |
+
const FeatureMatches& matches) const;
|
| 186 |
+
void WriteTwoViewGeometry(const image_t image_id1, const image_t image_id2,
|
| 187 |
+
const TwoViewGeometry& two_view_geometry) const;
|
| 188 |
+
|
| 189 |
+
// Update an existing camera in the database. The user is responsible for
|
| 190 |
+
// making sure that the entry already exists.
|
| 191 |
+
void UpdateCamera(const Camera& camera) const;
|
| 192 |
+
|
| 193 |
+
// Update an existing image in the database. The user is responsible for
|
| 194 |
+
// making sure that the entry already exists.
|
| 195 |
+
void UpdateImage(const Image& image) const;
|
| 196 |
+
|
| 197 |
+
// Delete matches of an image pair.
|
| 198 |
+
void DeleteMatches(const image_t image_id1, const image_t image_id2) const;
|
| 199 |
+
|
| 200 |
+
// Delete inlier matches of an image pair.
|
| 201 |
+
void DeleteInlierMatches(const image_t image_id1,
|
| 202 |
+
const image_t image_id2) const;
|
| 203 |
+
|
| 204 |
+
// Clear all database tables
|
| 205 |
+
void ClearAllTables() const;
|
| 206 |
+
|
| 207 |
+
// Clear the entire cameras table
|
| 208 |
+
void ClearCameras() const;
|
| 209 |
+
|
| 210 |
+
// Clear the entire images, keypoints, and descriptors tables
|
| 211 |
+
void ClearImages() const;
|
| 212 |
+
|
| 213 |
+
// Clear the entire descriptors table
|
| 214 |
+
void ClearDescriptors() const;
|
| 215 |
+
|
| 216 |
+
// Clear the entire keypoints table
|
| 217 |
+
void ClearKeypoints() const;
|
| 218 |
+
|
| 219 |
+
// Clear the entire matches table.
|
| 220 |
+
void ClearMatches() const;
|
| 221 |
+
|
| 222 |
+
// Clear the entire inlier matches table.
|
| 223 |
+
void ClearTwoViewGeometries() const;
|
| 224 |
+
|
| 225 |
+
// Merge two databases into a single, new database.
|
| 226 |
+
static void Merge(const Database& database1, const Database& database2,
|
| 227 |
+
Database* merged_database);
|
| 228 |
+
|
| 229 |
+
private:
|
| 230 |
+
friend class DatabaseTransaction;
|
| 231 |
+
|
| 232 |
+
// Combine multiple queries into one transaction by wrapping a code section
|
| 233 |
+
// into a `BeginTransaction` and `EndTransaction`. You can create a scoped
|
| 234 |
+
// transaction with `DatabaseTransaction` that ends when the transaction
|
| 235 |
+
// object is destructed. Combining queries results in faster transaction time
|
| 236 |
+
// due to reduced locking of the database etc.
|
| 237 |
+
void BeginTransaction() const;
|
| 238 |
+
void EndTransaction() const;
|
| 239 |
+
|
| 240 |
+
// Prepare SQL statements once at construction of the database, and reuse
|
| 241 |
+
// the statements for multiple queries by resetting their states.
|
| 242 |
+
void PrepareSQLStatements();
|
| 243 |
+
void FinalizeSQLStatements();
|
| 244 |
+
|
| 245 |
+
// Create database tables, if not existing, called when opening a database.
|
| 246 |
+
void CreateTables() const;
|
| 247 |
+
void CreateCameraTable() const;
|
| 248 |
+
void CreateImageTable() const;
|
| 249 |
+
void CreateKeypointsTable() const;
|
| 250 |
+
void CreateDescriptorsTable() const;
|
| 251 |
+
void CreateMatchesTable() const;
|
| 252 |
+
void CreateTwoViewGeometriesTable() const;
|
| 253 |
+
|
| 254 |
+
void UpdateSchema() const;
|
| 255 |
+
|
| 256 |
+
bool ExistsTable(const std::string& table_name) const;
|
| 257 |
+
bool ExistsColumn(const std::string& table_name,
|
| 258 |
+
const std::string& column_name) const;
|
| 259 |
+
|
| 260 |
+
bool ExistsRowId(sqlite3_stmt* sql_stmt, const sqlite3_int64 row_id) const;
|
| 261 |
+
bool ExistsRowString(sqlite3_stmt* sql_stmt,
|
| 262 |
+
const std::string& row_entry) const;
|
| 263 |
+
|
| 264 |
+
size_t CountRows(const std::string& table) const;
|
| 265 |
+
size_t CountRowsForEntry(sqlite3_stmt* sql_stmt,
|
| 266 |
+
const sqlite3_int64 row_id) const;
|
| 267 |
+
size_t SumColumn(const std::string& column, const std::string& table) const;
|
| 268 |
+
size_t MaxColumn(const std::string& column, const std::string& table) const;
|
| 269 |
+
|
| 270 |
+
sqlite3* database_ = nullptr;
|
| 271 |
+
|
| 272 |
+
// Check if elements got removed from the database to only apply
|
| 273 |
+
// the VACUUM command in such case
|
| 274 |
+
mutable bool database_cleared_ = false;
|
| 275 |
+
|
| 276 |
+
// Ensure that only one database object at a time updates the schema of a
|
| 277 |
+
// database. Since the schema is updated every time a database is opened, this
|
| 278 |
+
// is to ensure that there are no race conditions ("database locked" error
|
| 279 |
+
// messages) when the user actually only intends to read from the database,
|
| 280 |
+
// which requires to open it.
|
| 281 |
+
static std::mutex update_schema_mutex_;
|
| 282 |
+
|
| 283 |
+
// Used to ensure that only one transaction is active at the same time.
|
| 284 |
+
std::mutex transaction_mutex_;
|
| 285 |
+
|
| 286 |
+
// A collection of all `sqlite3_stmt` objects for deletion in the destructor.
|
| 287 |
+
std::vector<sqlite3_stmt*> sql_stmts_;
|
| 288 |
+
|
| 289 |
+
// num_*
|
| 290 |
+
sqlite3_stmt* sql_stmt_num_keypoints_ = nullptr;
|
| 291 |
+
sqlite3_stmt* sql_stmt_num_descriptors_ = nullptr;
|
| 292 |
+
|
| 293 |
+
// exists_*
|
| 294 |
+
sqlite3_stmt* sql_stmt_exists_camera_ = nullptr;
|
| 295 |
+
sqlite3_stmt* sql_stmt_exists_image_id_ = nullptr;
|
| 296 |
+
sqlite3_stmt* sql_stmt_exists_image_name_ = nullptr;
|
| 297 |
+
sqlite3_stmt* sql_stmt_exists_keypoints_ = nullptr;
|
| 298 |
+
sqlite3_stmt* sql_stmt_exists_descriptors_ = nullptr;
|
| 299 |
+
sqlite3_stmt* sql_stmt_exists_matches_ = nullptr;
|
| 300 |
+
sqlite3_stmt* sql_stmt_exists_two_view_geometry_ = nullptr;
|
| 301 |
+
|
| 302 |
+
// add_*
|
| 303 |
+
sqlite3_stmt* sql_stmt_add_camera_ = nullptr;
|
| 304 |
+
sqlite3_stmt* sql_stmt_add_image_ = nullptr;
|
| 305 |
+
|
| 306 |
+
// update_*
|
| 307 |
+
sqlite3_stmt* sql_stmt_update_camera_ = nullptr;
|
| 308 |
+
sqlite3_stmt* sql_stmt_update_image_ = nullptr;
|
| 309 |
+
|
| 310 |
+
// read_*
|
| 311 |
+
sqlite3_stmt* sql_stmt_read_camera_ = nullptr;
|
| 312 |
+
sqlite3_stmt* sql_stmt_read_cameras_ = nullptr;
|
| 313 |
+
sqlite3_stmt* sql_stmt_read_image_id_ = nullptr;
|
| 314 |
+
sqlite3_stmt* sql_stmt_read_image_name_ = nullptr;
|
| 315 |
+
sqlite3_stmt* sql_stmt_read_images_ = nullptr;
|
| 316 |
+
sqlite3_stmt* sql_stmt_read_keypoints_ = nullptr;
|
| 317 |
+
sqlite3_stmt* sql_stmt_read_descriptors_ = nullptr;
|
| 318 |
+
sqlite3_stmt* sql_stmt_read_matches_ = nullptr;
|
| 319 |
+
sqlite3_stmt* sql_stmt_read_matches_all_ = nullptr;
|
| 320 |
+
sqlite3_stmt* sql_stmt_read_two_view_geometry_ = nullptr;
|
| 321 |
+
sqlite3_stmt* sql_stmt_read_two_view_geometries_ = nullptr;
|
| 322 |
+
sqlite3_stmt* sql_stmt_read_two_view_geometry_num_inliers_ = nullptr;
|
| 323 |
+
|
| 324 |
+
// write_*
|
| 325 |
+
sqlite3_stmt* sql_stmt_write_keypoints_ = nullptr;
|
| 326 |
+
sqlite3_stmt* sql_stmt_write_descriptors_ = nullptr;
|
| 327 |
+
sqlite3_stmt* sql_stmt_write_matches_ = nullptr;
|
| 328 |
+
sqlite3_stmt* sql_stmt_write_two_view_geometry_ = nullptr;
|
| 329 |
+
|
| 330 |
+
// delete_*
|
| 331 |
+
sqlite3_stmt* sql_stmt_delete_matches_ = nullptr;
|
| 332 |
+
sqlite3_stmt* sql_stmt_delete_two_view_geometry_ = nullptr;
|
| 333 |
+
|
| 334 |
+
// clear_*
|
| 335 |
+
sqlite3_stmt* sql_stmt_clear_cameras_ = nullptr;
|
| 336 |
+
sqlite3_stmt* sql_stmt_clear_images_ = nullptr;
|
| 337 |
+
sqlite3_stmt* sql_stmt_clear_descriptors_ = nullptr;
|
| 338 |
+
sqlite3_stmt* sql_stmt_clear_keypoints_ = nullptr;
|
| 339 |
+
sqlite3_stmt* sql_stmt_clear_matches_ = nullptr;
|
| 340 |
+
sqlite3_stmt* sql_stmt_clear_two_view_geometries_ = nullptr;
|
| 341 |
+
};
|
| 342 |
+
|
| 343 |
+
// This class automatically manages the scope of a database transaction by
|
| 344 |
+
// calling `BeginTransaction` and `EndTransaction` during construction and
|
| 345 |
+
// destruction, respectively.
|
| 346 |
+
class DatabaseTransaction {
|
| 347 |
+
public:
|
| 348 |
+
explicit DatabaseTransaction(Database* database);
|
| 349 |
+
~DatabaseTransaction();
|
| 350 |
+
|
| 351 |
+
private:
|
| 352 |
+
NON_COPYABLE(DatabaseTransaction)
|
| 353 |
+
NON_MOVABLE(DatabaseTransaction)
|
| 354 |
+
Database* database_;
|
| 355 |
+
std::unique_lock<std::mutex> database_lock_;
|
| 356 |
+
};
|
| 357 |
+
|
| 358 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 359 |
+
// Implementation
|
| 360 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 361 |
+
|
| 362 |
+
image_pair_t Database::ImagePairToPairId(const image_t image_id1,
|
| 363 |
+
const image_t image_id2) {
|
| 364 |
+
CHECK_GE(image_id1, 0);
|
| 365 |
+
CHECK_GE(image_id2, 0);
|
| 366 |
+
CHECK_LT(image_id1, kMaxNumImages);
|
| 367 |
+
CHECK_LT(image_id2, kMaxNumImages);
|
| 368 |
+
if (SwapImagePair(image_id1, image_id2)) {
|
| 369 |
+
return static_cast<image_pair_t>(kMaxNumImages) * image_id2 + image_id1;
|
| 370 |
+
} else {
|
| 371 |
+
return static_cast<image_pair_t>(kMaxNumImages) * image_id1 + image_id2;
|
| 372 |
+
}
|
| 373 |
+
}
|
| 374 |
+
|
| 375 |
+
void Database::PairIdToImagePair(const image_pair_t pair_id, image_t* image_id1,
|
| 376 |
+
image_t* image_id2) {
|
| 377 |
+
*image_id2 = static_cast<image_t>(pair_id % kMaxNumImages);
|
| 378 |
+
*image_id1 = static_cast<image_t>((pair_id - *image_id2) / kMaxNumImages);
|
| 379 |
+
CHECK_GE(*image_id1, 0);
|
| 380 |
+
CHECK_GE(*image_id2, 0);
|
| 381 |
+
CHECK_LT(*image_id1, kMaxNumImages);
|
| 382 |
+
CHECK_LT(*image_id2, kMaxNumImages);
|
| 383 |
+
}
|
| 384 |
+
|
| 385 |
+
// Return true if image pairs should be swapped. Used to enforce a specific
|
| 386 |
+
// image order to generate unique image pair identifiers independent of the
|
| 387 |
+
// order in which the image identifiers are used.
|
| 388 |
+
bool Database::SwapImagePair(const image_t image_id1, const image_t image_id2) {
|
| 389 |
+
return image_id1 > image_id2;
|
| 390 |
+
}
|
| 391 |
+
|
| 392 |
+
} // namespace colmap
|
| 393 |
+
|
| 394 |
+
#endif // COLMAP_SRC_BASE_DATABASE_H_
|
colmap/include/colmap/base/database_cache.h
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_BASE_DATABASE_CACHE_H_
|
| 33 |
+
#define COLMAP_SRC_BASE_DATABASE_CACHE_H_
|
| 34 |
+
|
| 35 |
+
#include <string>
|
| 36 |
+
#include <unordered_map>
|
| 37 |
+
#include <unordered_set>
|
| 38 |
+
#include <vector>
|
| 39 |
+
|
| 40 |
+
#include <Eigen/Core>
|
| 41 |
+
|
| 42 |
+
#include "base/camera.h"
|
| 43 |
+
#include "base/camera_models.h"
|
| 44 |
+
#include "base/correspondence_graph.h"
|
| 45 |
+
#include "base/database.h"
|
| 46 |
+
#include "base/image.h"
|
| 47 |
+
#include "util/alignment.h"
|
| 48 |
+
#include "util/types.h"
|
| 49 |
+
|
| 50 |
+
namespace colmap {
|
| 51 |
+
|
| 52 |
+
// A class that caches the contents of the database in memory, used to quickly
|
| 53 |
+
// create new reconstruction instances when multiple models are reconstructed.
|
| 54 |
+
class DatabaseCache {
|
| 55 |
+
public:
|
| 56 |
+
DatabaseCache();
|
| 57 |
+
|
| 58 |
+
// Get number of objects.
|
| 59 |
+
inline size_t NumCameras() const;
|
| 60 |
+
inline size_t NumImages() const;
|
| 61 |
+
|
| 62 |
+
// Get specific objects.
|
| 63 |
+
inline class Camera& Camera(const camera_t camera_id);
|
| 64 |
+
inline const class Camera& Camera(const camera_t camera_id) const;
|
| 65 |
+
inline class Image& Image(const image_t image_id);
|
| 66 |
+
inline const class Image& Image(const image_t image_id) const;
|
| 67 |
+
|
| 68 |
+
// Get all objects.
|
| 69 |
+
inline const EIGEN_STL_UMAP(camera_t, class Camera) & Cameras() const;
|
| 70 |
+
inline const EIGEN_STL_UMAP(image_t, class Image) & Images() const;
|
| 71 |
+
|
| 72 |
+
// Check whether specific object exists.
|
| 73 |
+
inline bool ExistsCamera(const camera_t camera_id) const;
|
| 74 |
+
inline bool ExistsImage(const image_t image_id) const;
|
| 75 |
+
|
| 76 |
+
// Get reference to correspondence graph.
|
| 77 |
+
inline const class CorrespondenceGraph& CorrespondenceGraph() const;
|
| 78 |
+
|
| 79 |
+
// Manually add data to cache.
|
| 80 |
+
void AddCamera(class Camera camera);
|
| 81 |
+
void AddImage(class Image image);
|
| 82 |
+
|
| 83 |
+
// Load cameras, images, features, and matches from database.
|
| 84 |
+
//
|
| 85 |
+
// @param database Source database from which to load data.
|
| 86 |
+
// @param min_num_matches Only load image pairs with a minimum number
|
| 87 |
+
// of matches.
|
| 88 |
+
// @param ignore_watermarks Whether to ignore watermark image pairs.
|
| 89 |
+
// @param image_names Whether to use only load the data for a subset
|
| 90 |
+
// of the images. All images are used if empty.
|
| 91 |
+
void Load(const Database& database, const size_t min_num_matches,
|
| 92 |
+
const bool ignore_watermarks,
|
| 93 |
+
const std::unordered_set<std::string>& image_names);
|
| 94 |
+
|
| 95 |
+
// Find specific image by name. Note that this uses linear search.
|
| 96 |
+
const class Image* FindImageWithName(const std::string& name) const;
|
| 97 |
+
|
| 98 |
+
private:
|
| 99 |
+
class CorrespondenceGraph correspondence_graph_;
|
| 100 |
+
|
| 101 |
+
EIGEN_STL_UMAP(camera_t, class Camera) cameras_;
|
| 102 |
+
EIGEN_STL_UMAP(image_t, class Image) images_;
|
| 103 |
+
};
|
| 104 |
+
|
| 105 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 106 |
+
// Implementation
|
| 107 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 108 |
+
|
| 109 |
+
size_t DatabaseCache::NumCameras() const { return cameras_.size(); }
|
| 110 |
+
size_t DatabaseCache::NumImages() const { return images_.size(); }
|
| 111 |
+
|
| 112 |
+
class Camera& DatabaseCache::Camera(const camera_t camera_id) {
|
| 113 |
+
return cameras_.at(camera_id);
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
const class Camera& DatabaseCache::Camera(const camera_t camera_id) const {
|
| 117 |
+
return cameras_.at(camera_id);
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
class Image& DatabaseCache::Image(const image_t image_id) {
|
| 121 |
+
return images_.at(image_id);
|
| 122 |
+
}
|
| 123 |
+
|
| 124 |
+
const class Image& DatabaseCache::Image(const image_t image_id) const {
|
| 125 |
+
return images_.at(image_id);
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
+
const EIGEN_STL_UMAP(camera_t, class Camera) & DatabaseCache::Cameras() const {
|
| 129 |
+
return cameras_;
|
| 130 |
+
}
|
| 131 |
+
|
| 132 |
+
const EIGEN_STL_UMAP(image_t, class Image) & DatabaseCache::Images() const {
|
| 133 |
+
return images_;
|
| 134 |
+
}
|
| 135 |
+
|
| 136 |
+
bool DatabaseCache::ExistsCamera(const camera_t camera_id) const {
|
| 137 |
+
return cameras_.find(camera_id) != cameras_.end();
|
| 138 |
+
}
|
| 139 |
+
|
| 140 |
+
bool DatabaseCache::ExistsImage(const image_t image_id) const {
|
| 141 |
+
return images_.find(image_id) != images_.end();
|
| 142 |
+
}
|
| 143 |
+
|
| 144 |
+
inline const class CorrespondenceGraph& DatabaseCache::CorrespondenceGraph()
|
| 145 |
+
const {
|
| 146 |
+
return correspondence_graph_;
|
| 147 |
+
}
|
| 148 |
+
|
| 149 |
+
} // namespace colmap
|
| 150 |
+
|
| 151 |
+
#endif // COLMAP_SRC_BASE_DATABASE_CACHE_H_
|
colmap/include/colmap/base/essential_matrix.h
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_BASE_ESSENTIAL_MATRIX_H_
|
| 33 |
+
#define COLMAP_SRC_BASE_ESSENTIAL_MATRIX_H_
|
| 34 |
+
|
| 35 |
+
#include <vector>
|
| 36 |
+
|
| 37 |
+
#include <Eigen/Core>
|
| 38 |
+
|
| 39 |
+
#include <ceres/ceres.h>
|
| 40 |
+
|
| 41 |
+
#include "util/alignment.h"
|
| 42 |
+
#include "util/types.h"
|
| 43 |
+
|
| 44 |
+
namespace colmap {
|
| 45 |
+
|
| 46 |
+
// Decompose an essential matrix into the possible rotations and translations.
|
| 47 |
+
//
|
| 48 |
+
// The first pose is assumed to be P = [I | 0] and the set of four other
|
| 49 |
+
// possible second poses are defined as: {[R1 | t], [R2 | t],
|
| 50 |
+
// [R1 | -t], [R2 | -t]}
|
| 51 |
+
//
|
| 52 |
+
// @param E 3x3 essential matrix.
|
| 53 |
+
// @param R1 First possible 3x3 rotation matrix.
|
| 54 |
+
// @param R2 Second possible 3x3 rotation matrix.
|
| 55 |
+
// @param t 3x1 possible translation vector (also -t possible).
|
| 56 |
+
void DecomposeEssentialMatrix(const Eigen::Matrix3d& E, Eigen::Matrix3d* R1,
|
| 57 |
+
Eigen::Matrix3d* R2, Eigen::Vector3d* t);
|
| 58 |
+
|
| 59 |
+
// Recover the most probable pose from the given essential matrix.
|
| 60 |
+
//
|
| 61 |
+
// The pose of the first image is assumed to be P = [I | 0].
|
| 62 |
+
//
|
| 63 |
+
// @param E 3x3 essential matrix.
|
| 64 |
+
// @param points1 First set of corresponding points.
|
| 65 |
+
// @param points2 Second set of corresponding points.
|
| 66 |
+
// @param inlier_mask Only points with `true` in the inlier mask are
|
| 67 |
+
// considered in the cheirality test. Size of the
|
| 68 |
+
// inlier mask must match the number of points N.
|
| 69 |
+
// @param R Most probable 3x3 rotation matrix.
|
| 70 |
+
// @param t Most probable 3x1 translation vector.
|
| 71 |
+
// @param points3D Triangulated 3D points infront of camera.
|
| 72 |
+
void PoseFromEssentialMatrix(const Eigen::Matrix3d& E,
|
| 73 |
+
const std::vector<Eigen::Vector2d>& points1,
|
| 74 |
+
const std::vector<Eigen::Vector2d>& points2,
|
| 75 |
+
Eigen::Matrix3d* R, Eigen::Vector3d* t,
|
| 76 |
+
std::vector<Eigen::Vector3d>* points3D);
|
| 77 |
+
|
| 78 |
+
// Compose essential matrix from relative camera poses.
|
| 79 |
+
//
|
| 80 |
+
// Assumes that first camera pose has projection matrix P = [I | 0], and
|
| 81 |
+
// pose of second camera is given as transformation from world to camera system.
|
| 82 |
+
//
|
| 83 |
+
// @param R 3x3 rotation matrix.
|
| 84 |
+
// @param t 3x1 translation vector.
|
| 85 |
+
//
|
| 86 |
+
// @return 3x3 essential matrix.
|
| 87 |
+
Eigen::Matrix3d EssentialMatrixFromPose(const Eigen::Matrix3d& R,
|
| 88 |
+
const Eigen::Vector3d& t);
|
| 89 |
+
|
| 90 |
+
// Compose essential matrix from two absolute camera poses.
|
| 91 |
+
//
|
| 92 |
+
// @param proj_matrix1 3x4 projection matrix.
|
| 93 |
+
// @param proj_matrix2 3x4 projection matrix.
|
| 94 |
+
//
|
| 95 |
+
// @return 3x3 essential matrix.
|
| 96 |
+
Eigen::Matrix3d EssentialMatrixFromAbsolutePoses(
|
| 97 |
+
const Eigen::Matrix3x4d& proj_matrix1,
|
| 98 |
+
const Eigen::Matrix3x4d& proj_matrix2);
|
| 99 |
+
|
| 100 |
+
// Find optimal image points, such that:
|
| 101 |
+
//
|
| 102 |
+
// optimal_point1^t * E * optimal_point2 = 0
|
| 103 |
+
//
|
| 104 |
+
// as described in:
|
| 105 |
+
//
|
| 106 |
+
// Lindstrom, P., "Triangulation made easy",
|
| 107 |
+
// Computer Vision and Pattern Recognition (CVPR),
|
| 108 |
+
// 2010 IEEE Conference on , vol., no., pp.1554,1561, 13-18 June 2010
|
| 109 |
+
//
|
| 110 |
+
// @param E Essential or fundamental matrix.
|
| 111 |
+
// @param point1 Corresponding 2D point in first image.
|
| 112 |
+
// @param point2 Corresponding 2D point in second image.
|
| 113 |
+
// @param optimal_point1 Estimated optimal image point in the first image.
|
| 114 |
+
// @param optimal_point2 Estimated optimal image point in the second image.
|
| 115 |
+
void FindOptimalImageObservations(const Eigen::Matrix3d& E,
|
| 116 |
+
const Eigen::Vector2d& point1,
|
| 117 |
+
const Eigen::Vector2d& point2,
|
| 118 |
+
Eigen::Vector2d* optimal_point1,
|
| 119 |
+
Eigen::Vector2d* optimal_point2);
|
| 120 |
+
|
| 121 |
+
// Compute the location of the epipole in homogeneous coordinates.
|
| 122 |
+
//
|
| 123 |
+
// @param E 3x3 essential matrix.
|
| 124 |
+
// @param left_image If true, epipole in left image is computed,
|
| 125 |
+
// else in right image.
|
| 126 |
+
//
|
| 127 |
+
// @return Epipole in homogeneous coordinates.
|
| 128 |
+
Eigen::Vector3d EpipoleFromEssentialMatrix(const Eigen::Matrix3d& E,
|
| 129 |
+
const bool left_image);
|
| 130 |
+
|
| 131 |
+
// Invert the essential matrix, i.e. if the essential matrix E describes the
|
| 132 |
+
// transformation from camera A to B, the inverted essential matrix E' describes
|
| 133 |
+
// the transformation from camera B to A.
|
| 134 |
+
//
|
| 135 |
+
// @param E 3x3 essential matrix.
|
| 136 |
+
//
|
| 137 |
+
// @return Inverted essential matrix.
|
| 138 |
+
Eigen::Matrix3d InvertEssentialMatrix(const Eigen::Matrix3d& matrix);
|
| 139 |
+
|
| 140 |
+
// Refine essential matrix.
|
| 141 |
+
//
|
| 142 |
+
// Decomposes the essential matrix into rotation and translation components
|
| 143 |
+
// and refines the relative pose using the function `RefineRelativePose`.
|
| 144 |
+
//
|
| 145 |
+
// @param E 3x3 essential matrix.
|
| 146 |
+
// @param points1 First set of corresponding points.
|
| 147 |
+
// @param points2 Second set of corresponding points.
|
| 148 |
+
// @param inlier_mask Inlier mask for corresponding points.
|
| 149 |
+
// @param options Solver options.
|
| 150 |
+
//
|
| 151 |
+
// @return Flag indicating if solution is usable.
|
| 152 |
+
bool RefineEssentialMatrix(const ceres::Solver::Options& options,
|
| 153 |
+
const std::vector<Eigen::Vector2d>& points1,
|
| 154 |
+
const std::vector<Eigen::Vector2d>& points2,
|
| 155 |
+
const std::vector<char>& inlier_mask,
|
| 156 |
+
Eigen::Matrix3d* E);
|
| 157 |
+
|
| 158 |
+
} // namespace colmap
|
| 159 |
+
|
| 160 |
+
#endif // COLMAP_SRC_BASE_ESSENTIAL_MATRIX_H_
|
colmap/include/colmap/base/gps.h
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_BASE_GPS_H_
|
| 33 |
+
#define COLMAP_SRC_BASE_GPS_H_
|
| 34 |
+
|
| 35 |
+
#include <vector>
|
| 36 |
+
|
| 37 |
+
#include <Eigen/Core>
|
| 38 |
+
|
| 39 |
+
#include "util/alignment.h"
|
| 40 |
+
#include "util/types.h"
|
| 41 |
+
|
| 42 |
+
namespace colmap {
|
| 43 |
+
|
| 44 |
+
// Transform ellipsoidal GPS coordinates to Cartesian GPS coordinate
|
| 45 |
+
// representation and vice versa.
|
| 46 |
+
class GPSTransform {
|
| 47 |
+
public:
|
| 48 |
+
enum ELLIPSOID { GRS80, WGS84 };
|
| 49 |
+
|
| 50 |
+
explicit GPSTransform(const int ellipsoid = GRS80);
|
| 51 |
+
|
| 52 |
+
std::vector<Eigen::Vector3d> EllToXYZ(
|
| 53 |
+
const std::vector<Eigen::Vector3d>& ell) const;
|
| 54 |
+
|
| 55 |
+
std::vector<Eigen::Vector3d> XYZToEll(
|
| 56 |
+
const std::vector<Eigen::Vector3d>& xyz) const;
|
| 57 |
+
|
| 58 |
+
// Convert GPS (lat / lon / alt) to ENU coords. with lat0 and lon0
|
| 59 |
+
// defining the origin of the ENU frame
|
| 60 |
+
std::vector<Eigen::Vector3d> EllToENU(const std::vector<Eigen::Vector3d>& ell,
|
| 61 |
+
const double lat0,
|
| 62 |
+
const double lon0) const;
|
| 63 |
+
|
| 64 |
+
std::vector<Eigen::Vector3d> XYZToENU(const std::vector<Eigen::Vector3d>& xyz,
|
| 65 |
+
const double lat0,
|
| 66 |
+
const double lon0) const;
|
| 67 |
+
|
| 68 |
+
std::vector<Eigen::Vector3d> ENUToEll(const std::vector<Eigen::Vector3d>& enu,
|
| 69 |
+
const double lat0, const double lon0,
|
| 70 |
+
const double alt0) const;
|
| 71 |
+
|
| 72 |
+
std::vector<Eigen::Vector3d> ENUToXYZ(const std::vector<Eigen::Vector3d>& enu,
|
| 73 |
+
const double lat0, const double lon0,
|
| 74 |
+
const double alt0) const;
|
| 75 |
+
|
| 76 |
+
private:
|
| 77 |
+
// Semimajor axis.
|
| 78 |
+
double a_;
|
| 79 |
+
// Semiminor axis.
|
| 80 |
+
double b_;
|
| 81 |
+
// Flattening.
|
| 82 |
+
double f_;
|
| 83 |
+
// Numerical eccentricity.
|
| 84 |
+
double e2_;
|
| 85 |
+
};
|
| 86 |
+
|
| 87 |
+
} // namespace colmap
|
| 88 |
+
|
| 89 |
+
#endif // COLMAP_SRC_BASE_GPS_H_
|
colmap/include/colmap/base/graph_cut.h
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_BASE_GRAPH_CUT_H_
|
| 33 |
+
#define COLMAP_SRC_BASE_GRAPH_CUT_H_
|
| 34 |
+
|
| 35 |
+
#include <unordered_map>
|
| 36 |
+
#include <vector>
|
| 37 |
+
|
| 38 |
+
#include <boost/graph/adjacency_list.hpp>
|
| 39 |
+
#include <boost/graph/boykov_kolmogorov_max_flow.hpp>
|
| 40 |
+
#include <boost/graph/graph_traits.hpp>
|
| 41 |
+
#include <boost/graph/one_bit_color_map.hpp>
|
| 42 |
+
|
| 43 |
+
#include "util/logging.h"
|
| 44 |
+
|
| 45 |
+
namespace colmap {
|
| 46 |
+
|
| 47 |
+
// Compute the min-cut of a undirected graph using the Stoer Wagner algorithm.
|
| 48 |
+
void ComputeMinGraphCutStoerWagner(
|
| 49 |
+
const std::vector<std::pair<int, int>>& edges,
|
| 50 |
+
const std::vector<int>& weights, int* cut_weight,
|
| 51 |
+
std::vector<char>* cut_labels);
|
| 52 |
+
|
| 53 |
+
// Compute the normalized min-cut of an undirected graph using Metis.
|
| 54 |
+
// Partitions the graph into clusters and returns the cluster labels per vertex.
|
| 55 |
+
std::unordered_map<int, int> ComputeNormalizedMinGraphCut(
|
| 56 |
+
const std::vector<std::pair<int, int>>& edges,
|
| 57 |
+
const std::vector<int>& weights, const int num_parts);
|
| 58 |
+
|
| 59 |
+
// Compute the minimum graph cut of a directed S-T graph using the
|
| 60 |
+
// Boykov-Kolmogorov max-flow min-cut algorithm, as descibed in:
|
| 61 |
+
// "An Experimental Comparison of Min-Cut/Max-Flow Algorithms for Energy
|
| 62 |
+
// Minimization in Vision". Yuri Boykov and Vladimir Kolmogorov. PAMI, 2004.
|
| 63 |
+
template <typename node_t, typename value_t>
|
| 64 |
+
class MinSTGraphCut {
|
| 65 |
+
public:
|
| 66 |
+
typedef boost::adjacency_list_traits<boost::vecS, boost::vecS,
|
| 67 |
+
boost::directedS>
|
| 68 |
+
graph_traits_t;
|
| 69 |
+
typedef graph_traits_t::edge_descriptor edge_descriptor_t;
|
| 70 |
+
typedef graph_traits_t::vertices_size_type vertices_size_t;
|
| 71 |
+
|
| 72 |
+
struct Edge {
|
| 73 |
+
value_t capacity;
|
| 74 |
+
value_t residual;
|
| 75 |
+
edge_descriptor_t reverse;
|
| 76 |
+
};
|
| 77 |
+
|
| 78 |
+
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS,
|
| 79 |
+
size_t, Edge>
|
| 80 |
+
graph_t;
|
| 81 |
+
|
| 82 |
+
MinSTGraphCut(const size_t num_nodes);
|
| 83 |
+
|
| 84 |
+
// Count the number of nodes and edges in the graph.
|
| 85 |
+
size_t NumNodes() const;
|
| 86 |
+
size_t NumEdges() const;
|
| 87 |
+
|
| 88 |
+
// Add node to the graph.
|
| 89 |
+
void AddNode(const node_t node_idx, const value_t source_capacity,
|
| 90 |
+
const value_t sink_capacity);
|
| 91 |
+
|
| 92 |
+
// Add edge to the graph.
|
| 93 |
+
void AddEdge(const node_t node_idx1, const node_t node_idx2,
|
| 94 |
+
const value_t capacity, const value_t reverse_capacity);
|
| 95 |
+
|
| 96 |
+
// Compute the min-cut using the max-flow algorithm. Returns the flow.
|
| 97 |
+
value_t Compute();
|
| 98 |
+
|
| 99 |
+
// Check whether node is connected to source or sink after computing the cut.
|
| 100 |
+
bool IsConnectedToSource(const node_t node_idx) const;
|
| 101 |
+
bool IsConnectedToSink(const node_t node_idx) const;
|
| 102 |
+
|
| 103 |
+
private:
|
| 104 |
+
const node_t S_node_;
|
| 105 |
+
const node_t T_node_;
|
| 106 |
+
graph_t graph_;
|
| 107 |
+
std::vector<boost::default_color_type> colors_;
|
| 108 |
+
};
|
| 109 |
+
|
| 110 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 111 |
+
// Implementation
|
| 112 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 113 |
+
|
| 114 |
+
template <typename node_t, typename value_t>
|
| 115 |
+
MinSTGraphCut<node_t, value_t>::MinSTGraphCut(const size_t num_nodes)
|
| 116 |
+
: S_node_(num_nodes), T_node_(num_nodes + 1), graph_(num_nodes + 2) {}
|
| 117 |
+
|
| 118 |
+
template <typename node_t, typename value_t>
|
| 119 |
+
size_t MinSTGraphCut<node_t, value_t>::NumNodes() const {
|
| 120 |
+
return boost::num_vertices(graph_) - 2;
|
| 121 |
+
}
|
| 122 |
+
|
| 123 |
+
template <typename node_t, typename value_t>
|
| 124 |
+
size_t MinSTGraphCut<node_t, value_t>::NumEdges() const {
|
| 125 |
+
return boost::num_edges(graph_);
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
+
template <typename node_t, typename value_t>
|
| 129 |
+
void MinSTGraphCut<node_t, value_t>::AddNode(const node_t node_idx,
|
| 130 |
+
const value_t source_capacity,
|
| 131 |
+
const value_t sink_capacity) {
|
| 132 |
+
CHECK_GE(node_idx, 0);
|
| 133 |
+
CHECK_LE(node_idx, boost::num_vertices(graph_));
|
| 134 |
+
CHECK_GE(source_capacity, 0);
|
| 135 |
+
CHECK_GE(sink_capacity, 0);
|
| 136 |
+
|
| 137 |
+
if (source_capacity > 0) {
|
| 138 |
+
const edge_descriptor_t edge =
|
| 139 |
+
boost::add_edge(S_node_, node_idx, graph_).first;
|
| 140 |
+
const edge_descriptor_t edge_reverse =
|
| 141 |
+
boost::add_edge(node_idx, S_node_, graph_).first;
|
| 142 |
+
graph_[edge].capacity = source_capacity;
|
| 143 |
+
graph_[edge].reverse = edge_reverse;
|
| 144 |
+
graph_[edge_reverse].reverse = edge;
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
+
if (sink_capacity > 0) {
|
| 148 |
+
const edge_descriptor_t edge =
|
| 149 |
+
boost::add_edge(node_idx, T_node_, graph_).first;
|
| 150 |
+
const edge_descriptor_t edge_reverse =
|
| 151 |
+
boost::add_edge(T_node_, node_idx, graph_).first;
|
| 152 |
+
graph_[edge].capacity = sink_capacity;
|
| 153 |
+
graph_[edge].reverse = edge_reverse;
|
| 154 |
+
graph_[edge_reverse].reverse = edge;
|
| 155 |
+
}
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
template <typename node_t, typename value_t>
|
| 159 |
+
void MinSTGraphCut<node_t, value_t>::AddEdge(const node_t node_idx1,
|
| 160 |
+
const node_t node_idx2,
|
| 161 |
+
const value_t capacity,
|
| 162 |
+
const value_t reverse_capacity) {
|
| 163 |
+
CHECK_GE(node_idx1, 0);
|
| 164 |
+
CHECK_LE(node_idx1, boost::num_vertices(graph_));
|
| 165 |
+
CHECK_GE(node_idx2, 0);
|
| 166 |
+
CHECK_LE(node_idx2, boost::num_vertices(graph_));
|
| 167 |
+
CHECK_GE(capacity, 0);
|
| 168 |
+
CHECK_GE(reverse_capacity, 0);
|
| 169 |
+
|
| 170 |
+
const edge_descriptor_t edge =
|
| 171 |
+
boost::add_edge(node_idx1, node_idx2, graph_).first;
|
| 172 |
+
const edge_descriptor_t edge_reverse =
|
| 173 |
+
boost::add_edge(node_idx2, node_idx1, graph_).first;
|
| 174 |
+
graph_[edge].capacity = capacity;
|
| 175 |
+
graph_[edge_reverse].capacity = reverse_capacity;
|
| 176 |
+
graph_[edge].reverse = edge_reverse;
|
| 177 |
+
graph_[edge_reverse].reverse = edge;
|
| 178 |
+
}
|
| 179 |
+
|
| 180 |
+
template <typename node_t, typename value_t>
|
| 181 |
+
value_t MinSTGraphCut<node_t, value_t>::Compute() {
|
| 182 |
+
const vertices_size_t num_vertices = boost::num_vertices(graph_);
|
| 183 |
+
|
| 184 |
+
colors_.resize(num_vertices);
|
| 185 |
+
std::vector<edge_descriptor_t> predecessors(num_vertices);
|
| 186 |
+
std::vector<vertices_size_t> distances(num_vertices);
|
| 187 |
+
|
| 188 |
+
return boost::boykov_kolmogorov_max_flow(
|
| 189 |
+
graph_, boost::get(&Edge::capacity, graph_),
|
| 190 |
+
boost::get(&Edge::residual, graph_), boost::get(&Edge::reverse, graph_),
|
| 191 |
+
predecessors.data(), colors_.data(), distances.data(),
|
| 192 |
+
boost::get(boost::vertex_index, graph_), S_node_, T_node_);
|
| 193 |
+
}
|
| 194 |
+
|
| 195 |
+
template <typename node_t, typename value_t>
|
| 196 |
+
bool MinSTGraphCut<node_t, value_t>::IsConnectedToSource(
|
| 197 |
+
const node_t node_idx) const {
|
| 198 |
+
return colors_.at(node_idx) != boost::white_color;
|
| 199 |
+
}
|
| 200 |
+
|
| 201 |
+
template <typename node_t, typename value_t>
|
| 202 |
+
bool MinSTGraphCut<node_t, value_t>::IsConnectedToSink(
|
| 203 |
+
const node_t node_idx) const {
|
| 204 |
+
return colors_.at(node_idx) == boost::white_color;
|
| 205 |
+
}
|
| 206 |
+
|
| 207 |
+
} // namespace colmap
|
| 208 |
+
|
| 209 |
+
#endif // COLMAP_SRC_BASE_GRAPH_CUT_H_
|
colmap/include/colmap/base/homography_matrix.h
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_BASE_HOMOGRAPHY_MATRIX_UTILS_H_
|
| 33 |
+
#define COLMAP_SRC_BASE_HOMOGRAPHY_MATRIX_UTILS_H_
|
| 34 |
+
|
| 35 |
+
#include <vector>
|
| 36 |
+
|
| 37 |
+
#include <Eigen/Core>
|
| 38 |
+
|
| 39 |
+
#include "util/alignment.h"
|
| 40 |
+
#include "util/types.h"
|
| 41 |
+
|
| 42 |
+
namespace colmap {
|
| 43 |
+
|
| 44 |
+
// Decompose an homography matrix into the possible rotations, translations,
|
| 45 |
+
// and plane normal vectors, according to:
|
| 46 |
+
//
|
| 47 |
+
// Malis, Ezio, and Manuel Vargas. "Deeper understanding of the homography
|
| 48 |
+
// decomposition for vision-based control." (2007): 90.
|
| 49 |
+
//
|
| 50 |
+
// The first pose is assumed to be P = [I | 0]. Note that the homography is
|
| 51 |
+
// plane-induced if `R.size() == t.size() == n.size() == 4`. If `R.size() ==
|
| 52 |
+
// t.size() == n.size() == 1` the homography is pure-rotational.
|
| 53 |
+
//
|
| 54 |
+
// @param H 3x3 homography matrix.
|
| 55 |
+
// @param K 3x3 calibration matrix.
|
| 56 |
+
// @param R Possible 3x3 rotation matrices.
|
| 57 |
+
// @param t Possible translation vectors.
|
| 58 |
+
// @param n Possible normal vectors.
|
| 59 |
+
void DecomposeHomographyMatrix(const Eigen::Matrix3d& H,
|
| 60 |
+
const Eigen::Matrix3d& K1,
|
| 61 |
+
const Eigen::Matrix3d& K2,
|
| 62 |
+
std::vector<Eigen::Matrix3d>* R,
|
| 63 |
+
std::vector<Eigen::Vector3d>* t,
|
| 64 |
+
std::vector<Eigen::Vector3d>* n);
|
| 65 |
+
|
| 66 |
+
// Recover the most probable pose from the given homography matrix.
|
| 67 |
+
//
|
| 68 |
+
// The pose of the first image is assumed to be P = [I | 0].
|
| 69 |
+
//
|
| 70 |
+
// @param H 3x3 homography matrix.
|
| 71 |
+
// @param K1 3x3 calibration matrix of first camera.
|
| 72 |
+
// @param K2 3x3 calibration matrix of second camera.
|
| 73 |
+
// @param points1 First set of corresponding points.
|
| 74 |
+
// @param points2 Second set of corresponding points.
|
| 75 |
+
// @param inlier_mask Only points with `true` in the inlier mask are
|
| 76 |
+
// considered in the cheirality test. Size of the
|
| 77 |
+
// inlier mask must match the number of points N.
|
| 78 |
+
// @param R Most probable 3x3 rotation matrix.
|
| 79 |
+
// @param t Most probable 3x1 translation vector.
|
| 80 |
+
// @param n Most probable 3x1 normal vector.
|
| 81 |
+
// @param points3D Triangulated 3D points infront of camera
|
| 82 |
+
// (only if homography is not pure-rotational).
|
| 83 |
+
void PoseFromHomographyMatrix(const Eigen::Matrix3d& H,
|
| 84 |
+
const Eigen::Matrix3d& K1,
|
| 85 |
+
const Eigen::Matrix3d& K2,
|
| 86 |
+
const std::vector<Eigen::Vector2d>& points1,
|
| 87 |
+
const std::vector<Eigen::Vector2d>& points2,
|
| 88 |
+
Eigen::Matrix3d* R, Eigen::Vector3d* t,
|
| 89 |
+
Eigen::Vector3d* n,
|
| 90 |
+
std::vector<Eigen::Vector3d>* points3D);
|
| 91 |
+
|
| 92 |
+
// Compose homography matrix from relative pose.
|
| 93 |
+
//
|
| 94 |
+
// @param K1 3x3 calibration matrix of first camera.
|
| 95 |
+
// @param K2 3x3 calibration matrix of second camera.
|
| 96 |
+
// @param R Most probable 3x3 rotation matrix.
|
| 97 |
+
// @param t Most probable 3x1 translation vector.
|
| 98 |
+
// @param n Most probable 3x1 normal vector.
|
| 99 |
+
// @param d Orthogonal distance from plane.
|
| 100 |
+
//
|
| 101 |
+
// @return 3x3 homography matrix.
|
| 102 |
+
Eigen::Matrix3d HomographyMatrixFromPose(const Eigen::Matrix3d& K1,
|
| 103 |
+
const Eigen::Matrix3d& K2,
|
| 104 |
+
const Eigen::Matrix3d& R,
|
| 105 |
+
const Eigen::Vector3d& t,
|
| 106 |
+
const Eigen::Vector3d& n,
|
| 107 |
+
const double d);
|
| 108 |
+
|
| 109 |
+
} // namespace colmap
|
| 110 |
+
|
| 111 |
+
#endif // COLMAP_SRC_BASE_HOMOGRAPHY_MATRIX_UTILS_H_
|
colmap/include/colmap/base/image.h
ADDED
|
@@ -0,0 +1,364 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_BASE_IMAGE_H_
|
| 33 |
+
#define COLMAP_SRC_BASE_IMAGE_H_
|
| 34 |
+
|
| 35 |
+
#include <string>
|
| 36 |
+
#include <vector>
|
| 37 |
+
|
| 38 |
+
#include <Eigen/Core>
|
| 39 |
+
|
| 40 |
+
#include "base/camera.h"
|
| 41 |
+
#include "base/point2d.h"
|
| 42 |
+
#include "base/visibility_pyramid.h"
|
| 43 |
+
#include "util/alignment.h"
|
| 44 |
+
#include "util/logging.h"
|
| 45 |
+
#include "util/math.h"
|
| 46 |
+
#include "util/types.h"
|
| 47 |
+
|
| 48 |
+
namespace colmap {
|
| 49 |
+
|
| 50 |
+
// Class that holds information about an image. An image is the product of one
|
| 51 |
+
// camera shot at a certain location (parameterized as the pose). An image may
|
| 52 |
+
// share a camera with multiple other images, if its intrinsics are the same.
|
| 53 |
+
class Image {
|
| 54 |
+
public:
|
| 55 |
+
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
| 56 |
+
|
| 57 |
+
Image();
|
| 58 |
+
|
| 59 |
+
// Setup / tear down the image and necessary internal data structures before
|
| 60 |
+
// and after being used in reconstruction.
|
| 61 |
+
void SetUp(const Camera& camera);
|
| 62 |
+
void TearDown();
|
| 63 |
+
|
| 64 |
+
// Access the unique identifier of the image.
|
| 65 |
+
inline image_t ImageId() const;
|
| 66 |
+
inline void SetImageId(const image_t image_id);
|
| 67 |
+
|
| 68 |
+
// Access the name of the image.
|
| 69 |
+
inline const std::string& Name() const;
|
| 70 |
+
inline std::string& Name();
|
| 71 |
+
inline void SetName(const std::string& name);
|
| 72 |
+
|
| 73 |
+
// Access the unique identifier of the camera. Note that multiple images
|
| 74 |
+
// might share the same camera.
|
| 75 |
+
inline camera_t CameraId() const;
|
| 76 |
+
inline void SetCameraId(const camera_t camera_id);
|
| 77 |
+
// Check whether identifier of camera has been set.
|
| 78 |
+
inline bool HasCamera() const;
|
| 79 |
+
|
| 80 |
+
// Check if image is registered.
|
| 81 |
+
inline bool IsRegistered() const;
|
| 82 |
+
inline void SetRegistered(const bool registered);
|
| 83 |
+
|
| 84 |
+
// Get the number of image points.
|
| 85 |
+
inline point2D_t NumPoints2D() const;
|
| 86 |
+
|
| 87 |
+
// Get the number of triangulations, i.e. the number of points that
|
| 88 |
+
// are part of a 3D point track.
|
| 89 |
+
inline point2D_t NumPoints3D() const;
|
| 90 |
+
|
| 91 |
+
// Get the number of observations, i.e. the number of image points that
|
| 92 |
+
// have at least one correspondence to another image.
|
| 93 |
+
inline point2D_t NumObservations() const;
|
| 94 |
+
inline void SetNumObservations(const point2D_t num_observations);
|
| 95 |
+
|
| 96 |
+
// Get the number of correspondences for all image points.
|
| 97 |
+
inline point2D_t NumCorrespondences() const;
|
| 98 |
+
inline void SetNumCorrespondences(const point2D_t num_observations);
|
| 99 |
+
|
| 100 |
+
// Get the number of observations that see a triangulated point, i.e. the
|
| 101 |
+
// number of image points that have at least one correspondence to a
|
| 102 |
+
// triangulated point in another image.
|
| 103 |
+
inline point2D_t NumVisiblePoints3D() const;
|
| 104 |
+
|
| 105 |
+
// Get the score of triangulated observations. In contrast to
|
| 106 |
+
// `NumVisiblePoints3D`, this score also captures the distribution
|
| 107 |
+
// of triangulated observations in the image. This is useful to select
|
| 108 |
+
// the next best image in incremental reconstruction, because a more
|
| 109 |
+
// uniform distribution of observations results in more robust registration.
|
| 110 |
+
inline size_t Point3DVisibilityScore() const;
|
| 111 |
+
|
| 112 |
+
// Access quaternion vector as (qw, qx, qy, qz) specifying the rotation of the
|
| 113 |
+
// pose which is defined as the transformation from world to image space.
|
| 114 |
+
inline const Eigen::Vector4d& Qvec() const;
|
| 115 |
+
inline Eigen::Vector4d& Qvec();
|
| 116 |
+
inline double Qvec(const size_t idx) const;
|
| 117 |
+
inline double& Qvec(const size_t idx);
|
| 118 |
+
inline void SetQvec(const Eigen::Vector4d& qvec);
|
| 119 |
+
|
| 120 |
+
// Quaternion prior, e.g. given by EXIF gyroscope tag.
|
| 121 |
+
inline const Eigen::Vector4d& QvecPrior() const;
|
| 122 |
+
inline Eigen::Vector4d& QvecPrior();
|
| 123 |
+
inline double QvecPrior(const size_t idx) const;
|
| 124 |
+
inline double& QvecPrior(const size_t idx);
|
| 125 |
+
inline bool HasQvecPrior() const;
|
| 126 |
+
inline void SetQvecPrior(const Eigen::Vector4d& qvec);
|
| 127 |
+
|
| 128 |
+
// Access translation vector as (tx, ty, tz) specifying the translation of the
|
| 129 |
+
// pose which is defined as the transformation from world to image space.
|
| 130 |
+
inline const Eigen::Vector3d& Tvec() const;
|
| 131 |
+
inline Eigen::Vector3d& Tvec();
|
| 132 |
+
inline double Tvec(const size_t idx) const;
|
| 133 |
+
inline double& Tvec(const size_t idx);
|
| 134 |
+
inline void SetTvec(const Eigen::Vector3d& tvec);
|
| 135 |
+
|
| 136 |
+
// Translation prior, e.g. given by EXIF GPS tag.
|
| 137 |
+
inline const Eigen::Vector3d& TvecPrior() const;
|
| 138 |
+
inline Eigen::Vector3d& TvecPrior();
|
| 139 |
+
inline double TvecPrior(const size_t idx) const;
|
| 140 |
+
inline double& TvecPrior(const size_t idx);
|
| 141 |
+
inline bool HasTvecPrior() const;
|
| 142 |
+
inline void SetTvecPrior(const Eigen::Vector3d& tvec);
|
| 143 |
+
|
| 144 |
+
// Access the coordinates of image points.
|
| 145 |
+
inline const class Point2D& Point2D(const point2D_t point2D_idx) const;
|
| 146 |
+
inline class Point2D& Point2D(const point2D_t point2D_idx);
|
| 147 |
+
inline const std::vector<class Point2D>& Points2D() const;
|
| 148 |
+
void SetPoints2D(const std::vector<Eigen::Vector2d>& points);
|
| 149 |
+
void SetPoints2D(const std::vector<class Point2D>& points);
|
| 150 |
+
|
| 151 |
+
// Set the point as triangulated, i.e. it is part of a 3D point track.
|
| 152 |
+
void SetPoint3DForPoint2D(const point2D_t point2D_idx,
|
| 153 |
+
const point3D_t point3D_id);
|
| 154 |
+
|
| 155 |
+
// Set the point as not triangulated, i.e. it is not part of a 3D point track.
|
| 156 |
+
void ResetPoint3DForPoint2D(const point2D_t point2D_idx);
|
| 157 |
+
|
| 158 |
+
// Check whether an image point has a correspondence to an image point in
|
| 159 |
+
// another image that has a 3D point.
|
| 160 |
+
inline bool IsPoint3DVisible(const point2D_t point2D_idx) const;
|
| 161 |
+
|
| 162 |
+
// Check whether one of the image points is part of the 3D point track.
|
| 163 |
+
bool HasPoint3D(const point3D_t point3D_id) const;
|
| 164 |
+
|
| 165 |
+
// Indicate that another image has a point that is triangulated and has
|
| 166 |
+
// a correspondence to this image point. Note that this must only be called
|
| 167 |
+
// after calling `SetUp`.
|
| 168 |
+
void IncrementCorrespondenceHasPoint3D(const point2D_t point2D_idx);
|
| 169 |
+
|
| 170 |
+
// Indicate that another image has a point that is not triangulated any more
|
| 171 |
+
// and has a correspondence to this image point. This assumes that
|
| 172 |
+
// `IncrementCorrespondenceHasPoint3D` was called for the same image point
|
| 173 |
+
// and correspondence before. Note that this must only be called
|
| 174 |
+
// after calling `SetUp`.
|
| 175 |
+
void DecrementCorrespondenceHasPoint3D(const point2D_t point2D_idx);
|
| 176 |
+
|
| 177 |
+
// Normalize the quaternion vector.
|
| 178 |
+
void NormalizeQvec();
|
| 179 |
+
|
| 180 |
+
// Compose the projection matrix from world to image space.
|
| 181 |
+
Eigen::Matrix3x4d ProjectionMatrix() const;
|
| 182 |
+
|
| 183 |
+
// Compose the inverse projection matrix from image to world space
|
| 184 |
+
Eigen::Matrix3x4d InverseProjectionMatrix() const;
|
| 185 |
+
|
| 186 |
+
// Compose rotation matrix from quaternion vector.
|
| 187 |
+
Eigen::Matrix3d RotationMatrix() const;
|
| 188 |
+
|
| 189 |
+
// Extract the projection center in world space.
|
| 190 |
+
Eigen::Vector3d ProjectionCenter() const;
|
| 191 |
+
|
| 192 |
+
// Extract the viewing direction of the image.
|
| 193 |
+
Eigen::Vector3d ViewingDirection() const;
|
| 194 |
+
|
| 195 |
+
// The number of levels in the 3D point multi-resolution visibility pyramid.
|
| 196 |
+
static const int kNumPoint3DVisibilityPyramidLevels;
|
| 197 |
+
|
| 198 |
+
private:
|
| 199 |
+
// Identifier of the image, if not specified `kInvalidImageId`.
|
| 200 |
+
image_t image_id_;
|
| 201 |
+
|
| 202 |
+
// The name of the image, i.e. the relative path.
|
| 203 |
+
std::string name_;
|
| 204 |
+
|
| 205 |
+
// The identifier of the associated camera. Note that multiple images might
|
| 206 |
+
// share the same camera. If not specified `kInvalidCameraId`.
|
| 207 |
+
camera_t camera_id_;
|
| 208 |
+
|
| 209 |
+
// Whether the image is successfully registered in the reconstruction.
|
| 210 |
+
bool registered_;
|
| 211 |
+
|
| 212 |
+
// The number of 3D points the image observes, i.e. the sum of its `points2D`
|
| 213 |
+
// where `point3D_id != kInvalidPoint3DId`.
|
| 214 |
+
point2D_t num_points3D_;
|
| 215 |
+
|
| 216 |
+
// The number of image points that have at least one correspondence to
|
| 217 |
+
// another image.
|
| 218 |
+
point2D_t num_observations_;
|
| 219 |
+
|
| 220 |
+
// The sum of correspondences per image point.
|
| 221 |
+
point2D_t num_correspondences_;
|
| 222 |
+
|
| 223 |
+
// The number of 2D points, which have at least one corresponding 2D point in
|
| 224 |
+
// another image that is part of a 3D point track, i.e. the sum of `points2D`
|
| 225 |
+
// where `num_tris > 0`.
|
| 226 |
+
point2D_t num_visible_points3D_;
|
| 227 |
+
|
| 228 |
+
// The pose of the image, defined as the transformation from world to image.
|
| 229 |
+
Eigen::Vector4d qvec_;
|
| 230 |
+
Eigen::Vector3d tvec_;
|
| 231 |
+
|
| 232 |
+
// The pose prior of the image, e.g. extracted from EXIF tags.
|
| 233 |
+
Eigen::Vector4d qvec_prior_;
|
| 234 |
+
Eigen::Vector3d tvec_prior_;
|
| 235 |
+
|
| 236 |
+
// All image points, including points that are not part of a 3D point track.
|
| 237 |
+
std::vector<class Point2D> points2D_;
|
| 238 |
+
|
| 239 |
+
// Per image point, the number of correspondences that have a 3D point.
|
| 240 |
+
std::vector<point2D_t> num_correspondences_have_point3D_;
|
| 241 |
+
|
| 242 |
+
// Data structure to compute the distribution of triangulated correspondences
|
| 243 |
+
// in the image. Note that this structure is only usable after `SetUp`.
|
| 244 |
+
VisibilityPyramid point3D_visibility_pyramid_;
|
| 245 |
+
};
|
| 246 |
+
|
| 247 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 248 |
+
// Implementation
|
| 249 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 250 |
+
|
| 251 |
+
image_t Image::ImageId() const { return image_id_; }
|
| 252 |
+
|
| 253 |
+
void Image::SetImageId(const image_t image_id) { image_id_ = image_id; }
|
| 254 |
+
|
| 255 |
+
const std::string& Image::Name() const { return name_; }
|
| 256 |
+
|
| 257 |
+
std::string& Image::Name() { return name_; }
|
| 258 |
+
|
| 259 |
+
void Image::SetName(const std::string& name) { name_ = name; }
|
| 260 |
+
|
| 261 |
+
inline camera_t Image::CameraId() const { return camera_id_; }
|
| 262 |
+
|
| 263 |
+
inline void Image::SetCameraId(const camera_t camera_id) {
|
| 264 |
+
CHECK_NE(camera_id, kInvalidCameraId);
|
| 265 |
+
camera_id_ = camera_id;
|
| 266 |
+
}
|
| 267 |
+
|
| 268 |
+
inline bool Image::HasCamera() const { return camera_id_ != kInvalidCameraId; }
|
| 269 |
+
|
| 270 |
+
bool Image::IsRegistered() const { return registered_; }
|
| 271 |
+
|
| 272 |
+
void Image::SetRegistered(const bool registered) { registered_ = registered; }
|
| 273 |
+
|
| 274 |
+
point2D_t Image::NumPoints2D() const {
|
| 275 |
+
return static_cast<point2D_t>(points2D_.size());
|
| 276 |
+
}
|
| 277 |
+
|
| 278 |
+
point2D_t Image::NumPoints3D() const { return num_points3D_; }
|
| 279 |
+
|
| 280 |
+
point2D_t Image::NumObservations() const { return num_observations_; }
|
| 281 |
+
|
| 282 |
+
void Image::SetNumObservations(const point2D_t num_observations) {
|
| 283 |
+
num_observations_ = num_observations;
|
| 284 |
+
}
|
| 285 |
+
|
| 286 |
+
point2D_t Image::NumCorrespondences() const { return num_correspondences_; }
|
| 287 |
+
|
| 288 |
+
void Image::SetNumCorrespondences(const point2D_t num_correspondences) {
|
| 289 |
+
num_correspondences_ = num_correspondences;
|
| 290 |
+
}
|
| 291 |
+
|
| 292 |
+
point2D_t Image::NumVisiblePoints3D() const { return num_visible_points3D_; }
|
| 293 |
+
|
| 294 |
+
size_t Image::Point3DVisibilityScore() const {
|
| 295 |
+
return point3D_visibility_pyramid_.Score();
|
| 296 |
+
}
|
| 297 |
+
|
| 298 |
+
const Eigen::Vector4d& Image::Qvec() const { return qvec_; }
|
| 299 |
+
|
| 300 |
+
Eigen::Vector4d& Image::Qvec() { return qvec_; }
|
| 301 |
+
|
| 302 |
+
inline double Image::Qvec(const size_t idx) const { return qvec_(idx); }
|
| 303 |
+
|
| 304 |
+
inline double& Image::Qvec(const size_t idx) { return qvec_(idx); }
|
| 305 |
+
|
| 306 |
+
void Image::SetQvec(const Eigen::Vector4d& qvec) { qvec_ = qvec; }
|
| 307 |
+
|
| 308 |
+
const Eigen::Vector4d& Image::QvecPrior() const { return qvec_prior_; }
|
| 309 |
+
|
| 310 |
+
Eigen::Vector4d& Image::QvecPrior() { return qvec_prior_; }
|
| 311 |
+
|
| 312 |
+
inline double Image::QvecPrior(const size_t idx) const {
|
| 313 |
+
return qvec_prior_(idx);
|
| 314 |
+
}
|
| 315 |
+
|
| 316 |
+
inline double& Image::QvecPrior(const size_t idx) { return qvec_prior_(idx); }
|
| 317 |
+
|
| 318 |
+
inline bool Image::HasQvecPrior() const { return !IsNaN(qvec_prior_.sum()); }
|
| 319 |
+
|
| 320 |
+
void Image::SetQvecPrior(const Eigen::Vector4d& qvec) { qvec_prior_ = qvec; }
|
| 321 |
+
|
| 322 |
+
const Eigen::Vector3d& Image::Tvec() const { return tvec_; }
|
| 323 |
+
|
| 324 |
+
Eigen::Vector3d& Image::Tvec() { return tvec_; }
|
| 325 |
+
|
| 326 |
+
inline double Image::Tvec(const size_t idx) const { return tvec_(idx); }
|
| 327 |
+
|
| 328 |
+
inline double& Image::Tvec(const size_t idx) { return tvec_(idx); }
|
| 329 |
+
|
| 330 |
+
void Image::SetTvec(const Eigen::Vector3d& tvec) { tvec_ = tvec; }
|
| 331 |
+
|
| 332 |
+
const Eigen::Vector3d& Image::TvecPrior() const { return tvec_prior_; }
|
| 333 |
+
|
| 334 |
+
Eigen::Vector3d& Image::TvecPrior() { return tvec_prior_; }
|
| 335 |
+
|
| 336 |
+
inline double Image::TvecPrior(const size_t idx) const {
|
| 337 |
+
return tvec_prior_(idx);
|
| 338 |
+
}
|
| 339 |
+
|
| 340 |
+
inline double& Image::TvecPrior(const size_t idx) { return tvec_prior_(idx); }
|
| 341 |
+
|
| 342 |
+
inline bool Image::HasTvecPrior() const { return !IsNaN(tvec_prior_.sum()); }
|
| 343 |
+
|
| 344 |
+
void Image::SetTvecPrior(const Eigen::Vector3d& tvec) { tvec_prior_ = tvec; }
|
| 345 |
+
|
| 346 |
+
const class Point2D& Image::Point2D(const point2D_t point2D_idx) const {
|
| 347 |
+
return points2D_.at(point2D_idx);
|
| 348 |
+
}
|
| 349 |
+
|
| 350 |
+
class Point2D& Image::Point2D(const point2D_t point2D_idx) {
|
| 351 |
+
return points2D_.at(point2D_idx);
|
| 352 |
+
}
|
| 353 |
+
|
| 354 |
+
const std::vector<class Point2D>& Image::Points2D() const { return points2D_; }
|
| 355 |
+
|
| 356 |
+
bool Image::IsPoint3DVisible(const point2D_t point2D_idx) const {
|
| 357 |
+
return num_correspondences_have_point3D_.at(point2D_idx) > 0;
|
| 358 |
+
}
|
| 359 |
+
|
| 360 |
+
} // namespace colmap
|
| 361 |
+
|
| 362 |
+
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION_CUSTOM(colmap::Image)
|
| 363 |
+
|
| 364 |
+
#endif // COLMAP_SRC_BASE_IMAGE_H_
|
colmap/include/colmap/base/image_reader.h
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_BASE_IMAGE_READER_H_
|
| 33 |
+
#define COLMAP_SRC_BASE_IMAGE_READER_H_
|
| 34 |
+
|
| 35 |
+
#include <unordered_set>
|
| 36 |
+
|
| 37 |
+
#include "base/database.h"
|
| 38 |
+
#include "util/bitmap.h"
|
| 39 |
+
#include "util/threading.h"
|
| 40 |
+
|
| 41 |
+
namespace colmap {
|
| 42 |
+
|
| 43 |
+
struct ImageReaderOptions {
|
| 44 |
+
// Path to database in which to store the extracted data.
|
| 45 |
+
std::string database_path = "";
|
| 46 |
+
|
| 47 |
+
// Root path to folder which contains the images.
|
| 48 |
+
std::string image_path = "";
|
| 49 |
+
|
| 50 |
+
// Optional root path to folder which contains image masks. For a given image,
|
| 51 |
+
// the corresponding mask must have the same sub-path below this root as the
|
| 52 |
+
// image has below image_path. The filename must be equal, aside from the
|
| 53 |
+
// added extension .png. For example, for an image image_path/abc/012.jpg, the
|
| 54 |
+
// mask would be mask_path/abc/012.jpg.png. No features will be extracted in
|
| 55 |
+
// regions where the mask image is black (pixel intensity value 0 in
|
| 56 |
+
// grayscale).
|
| 57 |
+
std::string mask_path = "";
|
| 58 |
+
|
| 59 |
+
// Optional list of images to read. The list must contain the relative path
|
| 60 |
+
// of the images with respect to the image_path.
|
| 61 |
+
std::vector<std::string> image_list;
|
| 62 |
+
|
| 63 |
+
// Name of the camera model.
|
| 64 |
+
std::string camera_model = "SIMPLE_RADIAL";
|
| 65 |
+
|
| 66 |
+
// Whether to use the same camera for all images.
|
| 67 |
+
bool single_camera = false;
|
| 68 |
+
|
| 69 |
+
// Whether to use the same camera for all images in the same sub-folder.
|
| 70 |
+
bool single_camera_per_folder = false;
|
| 71 |
+
|
| 72 |
+
// Whether to use a different camera for each image.
|
| 73 |
+
bool single_camera_per_image = false;
|
| 74 |
+
|
| 75 |
+
// Whether to explicitly use an existing camera for all images. Note that in
|
| 76 |
+
// this case the specified camera model and parameters are ignored.
|
| 77 |
+
int existing_camera_id = kInvalidCameraId;
|
| 78 |
+
|
| 79 |
+
// Manual specification of camera parameters. If empty, camera parameters
|
| 80 |
+
// will be extracted from EXIF, i.e. principal point and focal length.
|
| 81 |
+
std::string camera_params = "";
|
| 82 |
+
|
| 83 |
+
// If camera parameters are not specified manually and the image does not
|
| 84 |
+
// have focal length EXIF information, the focal length is set to the
|
| 85 |
+
// value `default_focal_length_factor * max(width, height)`.
|
| 86 |
+
double default_focal_length_factor = 1.2;
|
| 87 |
+
|
| 88 |
+
// Optional path to an image file specifying a mask for all images. No
|
| 89 |
+
// features will be extracted in regions where the mask is black (pixel
|
| 90 |
+
// intensity value 0 in grayscale).
|
| 91 |
+
std::string camera_mask_path = "";
|
| 92 |
+
|
| 93 |
+
bool Check() const;
|
| 94 |
+
};
|
| 95 |
+
|
| 96 |
+
// Recursively iterate over the images in a directory. Skips an image if it
|
| 97 |
+
// already exists in the database. Extracts the camera intrinsics from EXIF and
|
| 98 |
+
// writes the camera information to the database.
|
| 99 |
+
class ImageReader {
|
| 100 |
+
public:
|
| 101 |
+
enum class Status {
|
| 102 |
+
FAILURE,
|
| 103 |
+
SUCCESS,
|
| 104 |
+
IMAGE_EXISTS,
|
| 105 |
+
BITMAP_ERROR,
|
| 106 |
+
CAMERA_SINGLE_DIM_ERROR,
|
| 107 |
+
CAMERA_EXIST_DIM_ERROR,
|
| 108 |
+
CAMERA_PARAM_ERROR
|
| 109 |
+
};
|
| 110 |
+
|
| 111 |
+
ImageReader(const ImageReaderOptions& options, Database* database);
|
| 112 |
+
|
| 113 |
+
Status Next(Camera* camera, Image* image, Bitmap* bitmap, Bitmap* mask);
|
| 114 |
+
size_t NextIndex() const;
|
| 115 |
+
size_t NumImages() const;
|
| 116 |
+
|
| 117 |
+
private:
|
| 118 |
+
// Image reader options.
|
| 119 |
+
ImageReaderOptions options_;
|
| 120 |
+
Database* database_;
|
| 121 |
+
// Index of previously processed image.
|
| 122 |
+
size_t image_index_;
|
| 123 |
+
// Previously processed camera.
|
| 124 |
+
Camera prev_camera_;
|
| 125 |
+
std::unordered_map<std::string, camera_t> camera_model_to_id_;
|
| 126 |
+
// Names of image sub-folders.
|
| 127 |
+
std::string prev_image_folder_;
|
| 128 |
+
std::unordered_set<std::string> image_folders_;
|
| 129 |
+
};
|
| 130 |
+
|
| 131 |
+
} // namespace colmap
|
| 132 |
+
|
| 133 |
+
#endif // COLMAP_SRC_BASE_IMAGE_READER_H_
|
colmap/include/colmap/base/line.h
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_BASE_LINE_H_
|
| 33 |
+
#define COLMAP_SRC_BASE_LINE_H_
|
| 34 |
+
|
| 35 |
+
#include <Eigen/Core>
|
| 36 |
+
|
| 37 |
+
#include "util/alignment.h"
|
| 38 |
+
#include "util/bitmap.h"
|
| 39 |
+
|
| 40 |
+
namespace colmap {
|
| 41 |
+
|
| 42 |
+
struct LineSegment {
|
| 43 |
+
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
| 44 |
+
Eigen::Vector2d start;
|
| 45 |
+
Eigen::Vector2d end;
|
| 46 |
+
};
|
| 47 |
+
|
| 48 |
+
enum class LineSegmentOrientation {
|
| 49 |
+
HORIZONTAL = 1,
|
| 50 |
+
VERTICAL = -1,
|
| 51 |
+
UNDEFINED = 0,
|
| 52 |
+
};
|
| 53 |
+
|
| 54 |
+
// Detect line segments in the given bitmap image.
|
| 55 |
+
std::vector<LineSegment> DetectLineSegments(const Bitmap& bitmap,
|
| 56 |
+
const double min_length = 3);
|
| 57 |
+
|
| 58 |
+
// Classify line segments into horizontal/vertical.
|
| 59 |
+
std::vector<LineSegmentOrientation> ClassifyLineSegmentOrientations(
|
| 60 |
+
const std::vector<LineSegment>& segments, const double tolerance = 0.25);
|
| 61 |
+
|
| 62 |
+
} // namespace colmap
|
| 63 |
+
|
| 64 |
+
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION_CUSTOM(colmap::LineSegment)
|
| 65 |
+
|
| 66 |
+
#endif // COLMAP_SRC_BASE_LINE_H_
|
colmap/include/colmap/base/point2d.h
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_BASE_POINT2D_H_
|
| 33 |
+
#define COLMAP_SRC_BASE_POINT2D_H_
|
| 34 |
+
|
| 35 |
+
#include <Eigen/Core>
|
| 36 |
+
|
| 37 |
+
#include "util/alignment.h"
|
| 38 |
+
#include "util/types.h"
|
| 39 |
+
|
| 40 |
+
namespace colmap {
|
| 41 |
+
|
| 42 |
+
// 2D point class corresponds to a feature in an image. It may or may not have a
|
| 43 |
+
// corresponding 3D point if it is part of a triangulated track.
|
| 44 |
+
class Point2D {
|
| 45 |
+
public:
|
| 46 |
+
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
| 47 |
+
|
| 48 |
+
Point2D();
|
| 49 |
+
|
| 50 |
+
// The coordinate in image space in pixels.
|
| 51 |
+
inline const Eigen::Vector2d& XY() const;
|
| 52 |
+
inline Eigen::Vector2d& XY();
|
| 53 |
+
inline double X() const;
|
| 54 |
+
inline double Y() const;
|
| 55 |
+
inline void SetXY(const Eigen::Vector2d& xy);
|
| 56 |
+
|
| 57 |
+
// The identifier of the observed 3D point. If the image point does not
|
| 58 |
+
// observe a 3D point, the identifier is `kInvalidPoint3Did`.
|
| 59 |
+
inline point3D_t Point3DId() const;
|
| 60 |
+
inline bool HasPoint3D() const;
|
| 61 |
+
inline void SetPoint3DId(const point3D_t point3D_id);
|
| 62 |
+
|
| 63 |
+
private:
|
| 64 |
+
// The image coordinates in pixels, starting at upper left corner with 0.
|
| 65 |
+
Eigen::Vector2d xy_;
|
| 66 |
+
|
| 67 |
+
// The identifier of the 3D point. If the 2D point is not part of a 3D point
|
| 68 |
+
// track the identifier is `kInvalidPoint3DId` and `HasPoint3D() = false`.
|
| 69 |
+
point3D_t point3D_id_;
|
| 70 |
+
};
|
| 71 |
+
|
| 72 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 73 |
+
// Implementation
|
| 74 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 75 |
+
|
| 76 |
+
const Eigen::Vector2d& Point2D::XY() const { return xy_; }
|
| 77 |
+
|
| 78 |
+
Eigen::Vector2d& Point2D::XY() { return xy_; }
|
| 79 |
+
|
| 80 |
+
double Point2D::X() const { return xy_.x(); }
|
| 81 |
+
|
| 82 |
+
double Point2D::Y() const { return xy_.y(); }
|
| 83 |
+
|
| 84 |
+
void Point2D::SetXY(const Eigen::Vector2d& xy) { xy_ = xy; }
|
| 85 |
+
|
| 86 |
+
point3D_t Point2D::Point3DId() const { return point3D_id_; }
|
| 87 |
+
|
| 88 |
+
bool Point2D::HasPoint3D() const { return point3D_id_ != kInvalidPoint3DId; }
|
| 89 |
+
|
| 90 |
+
void Point2D::SetPoint3DId(const point3D_t point3D_id) {
|
| 91 |
+
point3D_id_ = point3D_id;
|
| 92 |
+
}
|
| 93 |
+
|
| 94 |
+
} // namespace colmap
|
| 95 |
+
|
| 96 |
+
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION_CUSTOM(colmap::Point2D)
|
| 97 |
+
|
| 98 |
+
#endif // COLMAP_SRC_BASE_POINT2D_H_
|
colmap/include/colmap/base/point3d.h
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_BASE_POINT3D_H_
|
| 33 |
+
#define COLMAP_SRC_BASE_POINT3D_H_
|
| 34 |
+
|
| 35 |
+
#include <vector>
|
| 36 |
+
|
| 37 |
+
#include <Eigen/Core>
|
| 38 |
+
|
| 39 |
+
#include "base/track.h"
|
| 40 |
+
#include "util/logging.h"
|
| 41 |
+
#include "util/types.h"
|
| 42 |
+
|
| 43 |
+
namespace colmap {
|
| 44 |
+
|
| 45 |
+
// 3D point class that holds information about triangulated 2D points.
|
| 46 |
+
class Point3D {
|
| 47 |
+
public:
|
| 48 |
+
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
| 49 |
+
|
| 50 |
+
Point3D();
|
| 51 |
+
|
| 52 |
+
// The point coordinate in world space.
|
| 53 |
+
inline const Eigen::Vector3d& XYZ() const;
|
| 54 |
+
inline Eigen::Vector3d& XYZ();
|
| 55 |
+
inline double XYZ(const size_t idx) const;
|
| 56 |
+
inline double& XYZ(const size_t idx);
|
| 57 |
+
inline double X() const;
|
| 58 |
+
inline double Y() const;
|
| 59 |
+
inline double Z() const;
|
| 60 |
+
inline void SetXYZ(const Eigen::Vector3d& xyz);
|
| 61 |
+
|
| 62 |
+
// The RGB color of the point.
|
| 63 |
+
inline const Eigen::Vector3ub& Color() const;
|
| 64 |
+
inline Eigen::Vector3ub& Color();
|
| 65 |
+
inline uint8_t Color(const size_t idx) const;
|
| 66 |
+
inline uint8_t& Color(const size_t idx);
|
| 67 |
+
inline void SetColor(const Eigen::Vector3ub& color);
|
| 68 |
+
|
| 69 |
+
// The mean reprojection error in image space.
|
| 70 |
+
inline double Error() const;
|
| 71 |
+
inline bool HasError() const;
|
| 72 |
+
inline void SetError(const double error);
|
| 73 |
+
|
| 74 |
+
inline const class Track& Track() const;
|
| 75 |
+
inline class Track& Track();
|
| 76 |
+
inline void SetTrack(class Track track);
|
| 77 |
+
|
| 78 |
+
private:
|
| 79 |
+
// The 3D position of the point.
|
| 80 |
+
Eigen::Vector3d xyz_;
|
| 81 |
+
|
| 82 |
+
// The color of the point in the range [0, 255].
|
| 83 |
+
Eigen::Vector3ub color_;
|
| 84 |
+
|
| 85 |
+
// The mean reprojection error in pixels.
|
| 86 |
+
double error_;
|
| 87 |
+
|
| 88 |
+
// The track of the point as a list of image observations.
|
| 89 |
+
class Track track_;
|
| 90 |
+
};
|
| 91 |
+
|
| 92 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 93 |
+
// Implementation
|
| 94 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 95 |
+
|
| 96 |
+
const Eigen::Vector3d& Point3D::XYZ() const { return xyz_; }
|
| 97 |
+
|
| 98 |
+
Eigen::Vector3d& Point3D::XYZ() { return xyz_; }
|
| 99 |
+
|
| 100 |
+
double Point3D::XYZ(const size_t idx) const { return xyz_(idx); }
|
| 101 |
+
|
| 102 |
+
double& Point3D::XYZ(const size_t idx) { return xyz_(idx); }
|
| 103 |
+
|
| 104 |
+
double Point3D::X() const { return xyz_.x(); }
|
| 105 |
+
|
| 106 |
+
double Point3D::Y() const { return xyz_.y(); }
|
| 107 |
+
|
| 108 |
+
double Point3D::Z() const { return xyz_.z(); }
|
| 109 |
+
|
| 110 |
+
void Point3D::SetXYZ(const Eigen::Vector3d& xyz) { xyz_ = xyz; }
|
| 111 |
+
|
| 112 |
+
const Eigen::Vector3ub& Point3D::Color() const { return color_; }
|
| 113 |
+
|
| 114 |
+
Eigen::Vector3ub& Point3D::Color() { return color_; }
|
| 115 |
+
|
| 116 |
+
uint8_t Point3D::Color(const size_t idx) const { return color_(idx); }
|
| 117 |
+
|
| 118 |
+
uint8_t& Point3D::Color(const size_t idx) { return color_(idx); }
|
| 119 |
+
|
| 120 |
+
void Point3D::SetColor(const Eigen::Vector3ub& color) { color_ = color; }
|
| 121 |
+
|
| 122 |
+
double Point3D::Error() const { return error_; }
|
| 123 |
+
|
| 124 |
+
bool Point3D::HasError() const { return error_ != -1.0; }
|
| 125 |
+
|
| 126 |
+
void Point3D::SetError(const double error) { error_ = error; }
|
| 127 |
+
|
| 128 |
+
const class Track& Point3D::Track() const { return track_; }
|
| 129 |
+
|
| 130 |
+
class Track& Point3D::Track() {
|
| 131 |
+
return track_;
|
| 132 |
+
}
|
| 133 |
+
|
| 134 |
+
void Point3D::SetTrack(class Track track) { track_ = std::move(track); }
|
| 135 |
+
|
| 136 |
+
} // namespace colmap
|
| 137 |
+
|
| 138 |
+
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION_CUSTOM(colmap::Point3D)
|
| 139 |
+
|
| 140 |
+
#endif // COLMAP_SRC_BASE_POINT3D_H_
|
colmap/include/colmap/base/polynomial.h
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_BASE_POLYNOMIAL_H_
|
| 33 |
+
#define COLMAP_SRC_BASE_POLYNOMIAL_H_
|
| 34 |
+
|
| 35 |
+
#include <Eigen/Core>
|
| 36 |
+
|
| 37 |
+
namespace colmap {
|
| 38 |
+
|
| 39 |
+
// All polynomials are assumed to be the form:
|
| 40 |
+
//
|
| 41 |
+
// sum_{i=0}^N polynomial(i) x^{N-i}.
|
| 42 |
+
//
|
| 43 |
+
// and are given by a vector of coefficients of size N + 1.
|
| 44 |
+
//
|
| 45 |
+
// The implementation is based on COLMAP's old polynomial functionality and is
|
| 46 |
+
// inspired by Ceres-Solver's/Theia's implementation to support complex
|
| 47 |
+
// polynomials. The companion matrix implementation is based on NumPy.
|
| 48 |
+
|
| 49 |
+
// Evaluate the polynomial for the given coefficients at x using the Horner
|
| 50 |
+
// scheme. This function is templated such that the polynomial may be evaluated
|
| 51 |
+
// at real and/or imaginary points.
|
| 52 |
+
template <typename T>
|
| 53 |
+
T EvaluatePolynomial(const Eigen::VectorXd& coeffs, const T& x);
|
| 54 |
+
|
| 55 |
+
// Find the root of polynomials of the form: a * x + b = 0.
|
| 56 |
+
// The real and/or imaginary variable may be NULL if the output is not needed.
|
| 57 |
+
bool FindLinearPolynomialRoots(const Eigen::VectorXd& coeffs,
|
| 58 |
+
Eigen::VectorXd* real, Eigen::VectorXd* imag);
|
| 59 |
+
|
| 60 |
+
// Find the roots of polynomials of the form: a * x^2 + b * x + c = 0.
|
| 61 |
+
// The real and/or imaginary variable may be NULL if the output is not needed.
|
| 62 |
+
bool FindQuadraticPolynomialRoots(const Eigen::VectorXd& coeffs,
|
| 63 |
+
Eigen::VectorXd* real, Eigen::VectorXd* imag);
|
| 64 |
+
|
| 65 |
+
// Find the roots of a polynomial using the Durand-Kerner method, based on:
|
| 66 |
+
//
|
| 67 |
+
// https://en.wikipedia.org/wiki/Durand%E2%80%93Kerner_method
|
| 68 |
+
//
|
| 69 |
+
// The Durand-Kerner is comparatively fast but often unstable/inaccurate.
|
| 70 |
+
// The real and/or imaginary variable may be NULL if the output is not needed.
|
| 71 |
+
bool FindPolynomialRootsDurandKerner(const Eigen::VectorXd& coeffs,
|
| 72 |
+
Eigen::VectorXd* real,
|
| 73 |
+
Eigen::VectorXd* imag);
|
| 74 |
+
|
| 75 |
+
// Find the roots of a polynomial using the companion matrix method, based on:
|
| 76 |
+
//
|
| 77 |
+
// R. A. Horn & C. R. Johnson, Matrix Analysis. Cambridge,
|
| 78 |
+
// UK: Cambridge University Press, 1999, pp. 146-7.
|
| 79 |
+
//
|
| 80 |
+
// Compared to Durand-Kerner, this method is slower but more stable/accurate.
|
| 81 |
+
// The real and/or imaginary variable may be NULL if the output is not needed.
|
| 82 |
+
bool FindPolynomialRootsCompanionMatrix(const Eigen::VectorXd& coeffs,
|
| 83 |
+
Eigen::VectorXd* real,
|
| 84 |
+
Eigen::VectorXd* imag);
|
| 85 |
+
|
| 86 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 87 |
+
// Implementation
|
| 88 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 89 |
+
|
| 90 |
+
template <typename T>
|
| 91 |
+
T EvaluatePolynomial(const Eigen::VectorXd& coeffs, const T& x) {
|
| 92 |
+
T value = 0.0;
|
| 93 |
+
for (Eigen::VectorXd::Index i = 0; i < coeffs.size(); ++i) {
|
| 94 |
+
value = value * x + coeffs(i);
|
| 95 |
+
}
|
| 96 |
+
return value;
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
} // namespace colmap
|
| 100 |
+
|
| 101 |
+
#endif // COLMAP_SRC_BASE_POLYNOMIAL_H_
|
colmap/include/colmap/base/pose.h
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_BASE_POSE_H_
|
| 33 |
+
#define COLMAP_SRC_BASE_POSE_H_
|
| 34 |
+
|
| 35 |
+
#include <vector>
|
| 36 |
+
|
| 37 |
+
#include <Eigen/Core>
|
| 38 |
+
|
| 39 |
+
#include "util/alignment.h"
|
| 40 |
+
#include "util/types.h"
|
| 41 |
+
|
| 42 |
+
namespace colmap {
|
| 43 |
+
|
| 44 |
+
// Compose the skew symmetric cross product matrix from a vector.
|
| 45 |
+
Eigen::Matrix3d CrossProductMatrix(const Eigen::Vector3d& vector);
|
| 46 |
+
|
| 47 |
+
// Convert 3D rotation matrix to Euler angles.
|
| 48 |
+
//
|
| 49 |
+
// The convention `R = Rx * Ry * Rz` is used,
|
| 50 |
+
// using a right-handed coordinate system.
|
| 51 |
+
//
|
| 52 |
+
// @param R 3x3 rotation matrix.
|
| 53 |
+
// @param rx, ry, rz Euler angles in radians.
|
| 54 |
+
void RotationMatrixToEulerAngles(const Eigen::Matrix3d& R, double* rx,
|
| 55 |
+
double* ry, double* rz);
|
| 56 |
+
|
| 57 |
+
// Convert Euler angles to 3D rotation matrix.
|
| 58 |
+
//
|
| 59 |
+
// The convention `R = Rz * Ry * Rx` is used,
|
| 60 |
+
// using a right-handed coordinate system.
|
| 61 |
+
//
|
| 62 |
+
// @param rx, ry, rz Euler angles in radians.
|
| 63 |
+
//
|
| 64 |
+
// @return 3x3 rotation matrix.
|
| 65 |
+
Eigen::Matrix3d EulerAnglesToRotationMatrix(const double rx, const double ry,
|
| 66 |
+
const double rz);
|
| 67 |
+
|
| 68 |
+
// Convert 3D rotation matrix to Quaternion representation.
|
| 69 |
+
//
|
| 70 |
+
// @param rot_mat 3x3 rotation matrix.
|
| 71 |
+
//
|
| 72 |
+
// @return Unit Quaternion rotation coefficients (w, x, y, z).
|
| 73 |
+
Eigen::Vector4d RotationMatrixToQuaternion(const Eigen::Matrix3d& rot_mat);
|
| 74 |
+
|
| 75 |
+
// Convert Quaternion representation to 3D rotation matrix.
|
| 76 |
+
//
|
| 77 |
+
// @param qvec Unit Quaternion rotation coefficients (w, x, y, z).
|
| 78 |
+
//
|
| 79 |
+
// @return 3x3 rotation matrix.
|
| 80 |
+
Eigen::Matrix3d QuaternionToRotationMatrix(const Eigen::Vector4d& qvec);
|
| 81 |
+
|
| 82 |
+
// Compose the Quaternion vector corresponding to a identity transformation.
|
| 83 |
+
inline Eigen::Vector4d ComposeIdentityQuaternion();
|
| 84 |
+
|
| 85 |
+
// Normalize Quaternion vector.
|
| 86 |
+
//
|
| 87 |
+
// @param qvec Quaternion rotation coefficients (w, x, y, z).
|
| 88 |
+
//
|
| 89 |
+
// @return Unit Quaternion rotation coefficients (w, x, y, z).
|
| 90 |
+
Eigen::Vector4d NormalizeQuaternion(const Eigen::Vector4d& qvec);
|
| 91 |
+
|
| 92 |
+
// Invert Quaternion vector to return Quaternion of inverse rotation.
|
| 93 |
+
//
|
| 94 |
+
// @param qvec Quaternion rotation coefficients (w, x, y, z).
|
| 95 |
+
//
|
| 96 |
+
// @return Inverse Quaternion rotation coefficients (w, x, y, z).
|
| 97 |
+
Eigen::Vector4d InvertQuaternion(const Eigen::Vector4d& qvec);
|
| 98 |
+
|
| 99 |
+
// Concatenate Quaternion rotations such that the rotation of `qvec1` is applied
|
| 100 |
+
// before the rotation of `qvec2`.
|
| 101 |
+
//
|
| 102 |
+
// @param qvec1 Quaternion rotation coefficients (w, x, y, z).
|
| 103 |
+
// @param qvec2 Quaternion rotation coefficients (w, x, y, z).
|
| 104 |
+
//
|
| 105 |
+
// @return Concatenated Quaternion coefficients (w, x, y, z).
|
| 106 |
+
Eigen::Vector4d ConcatenateQuaternions(const Eigen::Vector4d& qvec1,
|
| 107 |
+
const Eigen::Vector4d& qvec2);
|
| 108 |
+
|
| 109 |
+
// Transform point by quaternion rotation.
|
| 110 |
+
//
|
| 111 |
+
// @param qvec Quaternion rotation coefficients (w, x, y, z).
|
| 112 |
+
// @param point Point to rotate.
|
| 113 |
+
//
|
| 114 |
+
// @return Rotated point.
|
| 115 |
+
Eigen::Vector3d QuaternionRotatePoint(const Eigen::Vector4d& qvec,
|
| 116 |
+
const Eigen::Vector3d& point);
|
| 117 |
+
|
| 118 |
+
// Compute the weighted average of multiple Quaternions according to:
|
| 119 |
+
//
|
| 120 |
+
// Markley, F. Landis, et al. "Averaging quaternions."
|
| 121 |
+
// Journal of Guidance, Control, and Dynamics 30.4 (2007): 1193-1197.
|
| 122 |
+
//
|
| 123 |
+
// @param qvecs The Quaternions to be averaged.
|
| 124 |
+
// @param weights Non-negative weights.
|
| 125 |
+
//
|
| 126 |
+
// @return The average Quaternion.
|
| 127 |
+
Eigen::Vector4d AverageQuaternions(const std::vector<Eigen::Vector4d>& qvecs,
|
| 128 |
+
const std::vector<double>& weights);
|
| 129 |
+
|
| 130 |
+
// Compose rotation matrix that rotates unit vector 1 to unit vector 2.
|
| 131 |
+
// Note that when vector 1 points into the opposite direction of vector 2,
|
| 132 |
+
// the function returns an identity rotation.
|
| 133 |
+
Eigen::Matrix3d RotationFromUnitVectors(const Eigen::Vector3d& vec1,
|
| 134 |
+
const Eigen::Vector3d& vec2);
|
| 135 |
+
|
| 136 |
+
// Extract camera projection center from projection matrix, i.e. the projection
|
| 137 |
+
// center in world coordinates `-R^T t`.
|
| 138 |
+
Eigen::Vector3d ProjectionCenterFromMatrix(
|
| 139 |
+
const Eigen::Matrix3x4d& proj_matrix);
|
| 140 |
+
|
| 141 |
+
// Extract camera projection center from projection parameters.
|
| 142 |
+
//
|
| 143 |
+
// @param qvec Unit Quaternion rotation coefficients (w, x, y, z).
|
| 144 |
+
// @param tvec 3x1 translation vector.
|
| 145 |
+
//
|
| 146 |
+
// @return 3x1 camera projection center.
|
| 147 |
+
Eigen::Vector3d ProjectionCenterFromPose(const Eigen::Vector4d& qvec,
|
| 148 |
+
const Eigen::Vector3d& tvec);
|
| 149 |
+
|
| 150 |
+
// Compute the relative transformation from pose 1 to 2.
|
| 151 |
+
//
|
| 152 |
+
// @param qvec1, tvec1 First camera pose.
|
| 153 |
+
// @param qvec2, tvec2 Second camera pose.
|
| 154 |
+
// @param qvec12, tvec12 Relative pose.
|
| 155 |
+
void ComputeRelativePose(const Eigen::Vector4d& qvec1,
|
| 156 |
+
const Eigen::Vector3d& tvec1,
|
| 157 |
+
const Eigen::Vector4d& qvec2,
|
| 158 |
+
const Eigen::Vector3d& tvec2, Eigen::Vector4d* qvec12,
|
| 159 |
+
Eigen::Vector3d* tvec12);
|
| 160 |
+
|
| 161 |
+
// Concatenate the transformations of the two poses.
|
| 162 |
+
//
|
| 163 |
+
// @param qvec1, tvec1 First camera pose.
|
| 164 |
+
// @param qvec2, tvec2 Second camera pose.
|
| 165 |
+
// @param qvec12, tvec12 Concatenated pose.
|
| 166 |
+
void ConcatenatePoses(const Eigen::Vector4d& qvec1,
|
| 167 |
+
const Eigen::Vector3d& tvec1,
|
| 168 |
+
const Eigen::Vector4d& qvec2,
|
| 169 |
+
const Eigen::Vector3d& tvec2, Eigen::Vector4d* qvec12,
|
| 170 |
+
Eigen::Vector3d* tvec12);
|
| 171 |
+
|
| 172 |
+
// Invert transformation of the pose.
|
| 173 |
+
// @param qvec, tvec Input camera pose.
|
| 174 |
+
// @param inv_qvec, inv_tvec Inverse camera pose.
|
| 175 |
+
void InvertPose(const Eigen::Vector4d& qvec, const Eigen::Vector3d& tvec,
|
| 176 |
+
Eigen::Vector4d* inv_qvec, Eigen::Vector3d* inv_tvec);
|
| 177 |
+
|
| 178 |
+
// Linearly interpolate camera pose.
|
| 179 |
+
//
|
| 180 |
+
// @param qvec1, tvec1 Camera pose at t0 = 0.
|
| 181 |
+
// @param qvec2, tvec2 Camera pose at t1 = 1.
|
| 182 |
+
// @param t Interpolation time.
|
| 183 |
+
// @param qveci, tveci Camera pose at time t.
|
| 184 |
+
void InterpolatePose(const Eigen::Vector4d& qvec1, const Eigen::Vector3d& tvec1,
|
| 185 |
+
const Eigen::Vector4d& qvec2, const Eigen::Vector3d& tvec2,
|
| 186 |
+
const double t, Eigen::Vector4d* qveci,
|
| 187 |
+
Eigen::Vector3d* tveci);
|
| 188 |
+
|
| 189 |
+
// Calculate baseline vector from first to second pose.
|
| 190 |
+
//
|
| 191 |
+
// The given rotation and orientation is expected as the
|
| 192 |
+
// world to camera transformation.
|
| 193 |
+
//
|
| 194 |
+
// @param qvec1 Unit Quaternion rotation coefficients (w, x, y, z).
|
| 195 |
+
// @param tvec1 3x1 translation vector.
|
| 196 |
+
// @param qvec2 Unit Quaternion rotation coefficients (w, x, y, z).
|
| 197 |
+
// @param tvec2 3x1 translation vector.
|
| 198 |
+
//
|
| 199 |
+
// @return Baseline vector from 1 to 2.
|
| 200 |
+
Eigen::Vector3d CalculateBaseline(const Eigen::Vector4d& qvec1,
|
| 201 |
+
const Eigen::Vector3d& tvec1,
|
| 202 |
+
const Eigen::Vector4d& qvec2,
|
| 203 |
+
const Eigen::Vector3d& tvec2);
|
| 204 |
+
|
| 205 |
+
// Perform cheirality constraint test, i.e., determine which of the triangulated
|
| 206 |
+
// correspondences lie in front of of both cameras. The first camera has the
|
| 207 |
+
// projection matrix P1 = [I | 0] and the second camera has the projection
|
| 208 |
+
// matrix P2 = [R | t].
|
| 209 |
+
//
|
| 210 |
+
// @param R 3x3 rotation matrix of second projection matrix.
|
| 211 |
+
// @param t 3x1 translation vector of second projection matrix.
|
| 212 |
+
// @param points1 First set of corresponding points.
|
| 213 |
+
// @param points2 Second set of corresponding points.
|
| 214 |
+
// @param points3D Points that lie in front of both cameras.
|
| 215 |
+
bool CheckCheirality(const Eigen::Matrix3d& R, const Eigen::Vector3d& t,
|
| 216 |
+
const std::vector<Eigen::Vector2d>& points1,
|
| 217 |
+
const std::vector<Eigen::Vector2d>& points2,
|
| 218 |
+
std::vector<Eigen::Vector3d>* points3D);
|
| 219 |
+
|
| 220 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 221 |
+
// Implementation
|
| 222 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 223 |
+
|
| 224 |
+
Eigen::Vector4d ComposeIdentityQuaternion() {
|
| 225 |
+
return Eigen::Vector4d(1, 0, 0, 0);
|
| 226 |
+
}
|
| 227 |
+
|
| 228 |
+
} // namespace colmap
|
| 229 |
+
|
| 230 |
+
#endif // COLMAP_SRC_BASE_POSE_H_
|
colmap/include/colmap/base/projection.h
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_BASE_PROJECTION_H_
|
| 33 |
+
#define COLMAP_SRC_BASE_PROJECTION_H_
|
| 34 |
+
|
| 35 |
+
#include <limits>
|
| 36 |
+
#include <vector>
|
| 37 |
+
|
| 38 |
+
#include <Eigen/Core>
|
| 39 |
+
#include <Eigen/Geometry>
|
| 40 |
+
|
| 41 |
+
#include "base/camera.h"
|
| 42 |
+
|
| 43 |
+
namespace colmap {
|
| 44 |
+
|
| 45 |
+
// Compose projection matrix from rotation and translation components.
|
| 46 |
+
//
|
| 47 |
+
// The projection matrix transforms 3D world to image points.
|
| 48 |
+
//
|
| 49 |
+
// @param qvec Unit Quaternion rotation coefficients (w, x, y, z).
|
| 50 |
+
// @param tvec 3x1 translation vector.
|
| 51 |
+
//
|
| 52 |
+
// @return 3x4 projection matrix.
|
| 53 |
+
Eigen::Matrix3x4d ComposeProjectionMatrix(const Eigen::Vector4d& qvec,
|
| 54 |
+
const Eigen::Vector3d& tvec);
|
| 55 |
+
|
| 56 |
+
// Compose projection matrix from rotation matrix and translation components).
|
| 57 |
+
//
|
| 58 |
+
// The projection matrix transforms 3D world to image points.
|
| 59 |
+
//
|
| 60 |
+
// @param R 3x3 rotation matrix.
|
| 61 |
+
// @param t 3x1 translation vector.
|
| 62 |
+
//
|
| 63 |
+
// @return 3x4 projection matrix.
|
| 64 |
+
Eigen::Matrix3x4d ComposeProjectionMatrix(const Eigen::Matrix3d& R,
|
| 65 |
+
const Eigen::Vector3d& T);
|
| 66 |
+
|
| 67 |
+
// Invert projection matrix, defined as:
|
| 68 |
+
//
|
| 69 |
+
// P = [R | t] with R \in SO(3) and t \in R^3
|
| 70 |
+
//
|
| 71 |
+
// and the inverse projection matrix as:
|
| 72 |
+
//
|
| 73 |
+
// P' = [R^T | -R^T t]
|
| 74 |
+
//
|
| 75 |
+
// @param proj_matrix 3x4 projection matrix.
|
| 76 |
+
//
|
| 77 |
+
// @return 3x4 inverse projection matrix.
|
| 78 |
+
Eigen::Matrix3x4d InvertProjectionMatrix(const Eigen::Matrix3x4d& proj_matrix);
|
| 79 |
+
|
| 80 |
+
// Compute the closes rotation matrix with the closest Frobenius norm by setting
|
| 81 |
+
// the singular values of the given matrix to 1.
|
| 82 |
+
Eigen::Matrix3d ComputeClosestRotationMatrix(const Eigen::Matrix3d& matrix);
|
| 83 |
+
|
| 84 |
+
// Decompose projection matrix into intrinsic camera matrix, rotation matrix and
|
| 85 |
+
// translation vector. Returns false if decomposition fails. This implementation
|
| 86 |
+
// is inspired by the OpenCV implementation with some additional checks.
|
| 87 |
+
bool DecomposeProjectionMatrix(const Eigen::Matrix3x4d& proj_matrix,
|
| 88 |
+
Eigen::Matrix3d* K, Eigen::Matrix3d* R,
|
| 89 |
+
Eigen::Vector3d* T);
|
| 90 |
+
|
| 91 |
+
// Project 3D point to image.
|
| 92 |
+
//
|
| 93 |
+
// @param points3D 3D world point as 3x1 vector.
|
| 94 |
+
// @param proj_matrix 3x4 projection matrix.
|
| 95 |
+
// @param camera Camera used to project to image plane.
|
| 96 |
+
//
|
| 97 |
+
// @return Projected image point.
|
| 98 |
+
Eigen::Vector2d ProjectPointToImage(const Eigen::Vector3d& point3D,
|
| 99 |
+
const Eigen::Matrix3x4d& proj_matrix,
|
| 100 |
+
const Camera& camera);
|
| 101 |
+
|
| 102 |
+
// Calculate the reprojection error.
|
| 103 |
+
//
|
| 104 |
+
// The reprojection error is the Euclidean distance between the observation
|
| 105 |
+
// in the image and the projection of the 3D point into the image. If the
|
| 106 |
+
// 3D point is behind the camera, then this function returns DBL_MAX.
|
| 107 |
+
double CalculateSquaredReprojectionError(const Eigen::Vector2d& point2D,
|
| 108 |
+
const Eigen::Vector3d& point3D,
|
| 109 |
+
const Eigen::Vector4d& qvec,
|
| 110 |
+
const Eigen::Vector3d& tvec,
|
| 111 |
+
const Camera& camera);
|
| 112 |
+
double CalculateSquaredReprojectionError(const Eigen::Vector2d& point2D,
|
| 113 |
+
const Eigen::Vector3d& point3D,
|
| 114 |
+
const Eigen::Matrix3x4d& proj_matrix,
|
| 115 |
+
const Camera& camera);
|
| 116 |
+
|
| 117 |
+
// Calculate the angular error.
|
| 118 |
+
//
|
| 119 |
+
// The angular error is the angle between the observed viewing ray and the
|
| 120 |
+
// actual viewing ray from the camera center to the 3D point.
|
| 121 |
+
double CalculateAngularError(const Eigen::Vector2d& point2D,
|
| 122 |
+
const Eigen::Vector3d& point3D,
|
| 123 |
+
const Eigen::Vector4d& qvec,
|
| 124 |
+
const Eigen::Vector3d& tvec, const Camera& camera);
|
| 125 |
+
double CalculateAngularError(const Eigen::Vector2d& point2D,
|
| 126 |
+
const Eigen::Vector3d& point3D,
|
| 127 |
+
const Eigen::Matrix3x4d& proj_matrix,
|
| 128 |
+
const Camera& camera);
|
| 129 |
+
|
| 130 |
+
// Calculate angulate error using normalized image points.
|
| 131 |
+
//
|
| 132 |
+
// The angular error is the angle between the observed viewing ray and the
|
| 133 |
+
// actual viewing ray from the camera center to the 3D point.
|
| 134 |
+
double CalculateNormalizedAngularError(const Eigen::Vector2d& point2D,
|
| 135 |
+
const Eigen::Vector3d& point3D,
|
| 136 |
+
const Eigen::Vector4d& qvec,
|
| 137 |
+
const Eigen::Vector3d& tvec);
|
| 138 |
+
double CalculateNormalizedAngularError(const Eigen::Vector2d& point2D,
|
| 139 |
+
const Eigen::Vector3d& point3D,
|
| 140 |
+
const Eigen::Matrix3x4d& proj_matrix);
|
| 141 |
+
|
| 142 |
+
// Calculate depth of 3D point with respect to camera.
|
| 143 |
+
//
|
| 144 |
+
// The depth is defined as the Euclidean distance of a 3D point from the
|
| 145 |
+
// camera and is positive if the 3D point is in front and negative if
|
| 146 |
+
// behind of the camera.
|
| 147 |
+
//
|
| 148 |
+
// @param proj_matrix 3x4 projection matrix.
|
| 149 |
+
// @param point3D 3D point as 3x1 vector.
|
| 150 |
+
//
|
| 151 |
+
// @return Depth of 3D point.
|
| 152 |
+
double CalculateDepth(const Eigen::Matrix3x4d& proj_matrix,
|
| 153 |
+
const Eigen::Vector3d& point3D);
|
| 154 |
+
|
| 155 |
+
// Check if 3D point passes cheirality constraint,
|
| 156 |
+
// i.e. it lies in front of the camera and not in the image plane.
|
| 157 |
+
//
|
| 158 |
+
// @param proj_matrix 3x4 projection matrix.
|
| 159 |
+
// @param point3D 3D point as 3x1 vector.
|
| 160 |
+
//
|
| 161 |
+
// @return True if point lies in front of camera.
|
| 162 |
+
bool HasPointPositiveDepth(const Eigen::Matrix3x4d& proj_matrix,
|
| 163 |
+
const Eigen::Vector3d& point3D);
|
| 164 |
+
|
| 165 |
+
} // namespace colmap
|
| 166 |
+
|
| 167 |
+
#endif // COLMAP_SRC_BASE_PROJECTION_H_
|
colmap/include/colmap/base/reconstruction.h
ADDED
|
@@ -0,0 +1,651 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_BASE_RECONSTRUCTION_H_
|
| 33 |
+
#define COLMAP_SRC_BASE_RECONSTRUCTION_H_
|
| 34 |
+
|
| 35 |
+
#include <tuple>
|
| 36 |
+
#include <unordered_map>
|
| 37 |
+
#include <unordered_set>
|
| 38 |
+
#include <vector>
|
| 39 |
+
|
| 40 |
+
#include <Eigen/Core>
|
| 41 |
+
|
| 42 |
+
#include "base/camera.h"
|
| 43 |
+
#include "base/database.h"
|
| 44 |
+
#include "base/image.h"
|
| 45 |
+
#include "base/point2d.h"
|
| 46 |
+
#include "base/point3d.h"
|
| 47 |
+
#include "base/similarity_transform.h"
|
| 48 |
+
#include "base/track.h"
|
| 49 |
+
#include "estimators/similarity_transform.h"
|
| 50 |
+
#include "optim/loransac.h"
|
| 51 |
+
#include "util/alignment.h"
|
| 52 |
+
#include "util/types.h"
|
| 53 |
+
|
| 54 |
+
namespace colmap {
|
| 55 |
+
|
| 56 |
+
struct PlyPoint;
|
| 57 |
+
struct RANSACOptions;
|
| 58 |
+
class DatabaseCache;
|
| 59 |
+
class CorrespondenceGraph;
|
| 60 |
+
|
| 61 |
+
// Reconstruction class holds all information about a single reconstructed
|
| 62 |
+
// model. It is used by the mapping and bundle adjustment classes and can be
|
| 63 |
+
// written to and read from disk.
|
| 64 |
+
class Reconstruction {
|
| 65 |
+
public:
|
| 66 |
+
struct ImagePairStat {
|
| 67 |
+
// The number of triangulated correspondences between two images.
|
| 68 |
+
size_t num_tri_corrs = 0;
|
| 69 |
+
// The number of total correspondences/matches between two images.
|
| 70 |
+
size_t num_total_corrs = 0;
|
| 71 |
+
};
|
| 72 |
+
|
| 73 |
+
Reconstruction();
|
| 74 |
+
|
| 75 |
+
// Get number of objects.
|
| 76 |
+
inline size_t NumCameras() const;
|
| 77 |
+
inline size_t NumImages() const;
|
| 78 |
+
inline size_t NumRegImages() const;
|
| 79 |
+
inline size_t NumPoints3D() const;
|
| 80 |
+
inline size_t NumImagePairs() const;
|
| 81 |
+
|
| 82 |
+
// Get const objects.
|
| 83 |
+
inline const class Camera& Camera(const camera_t camera_id) const;
|
| 84 |
+
inline const class Image& Image(const image_t image_id) const;
|
| 85 |
+
inline const class Point3D& Point3D(const point3D_t point3D_id) const;
|
| 86 |
+
inline const ImagePairStat& ImagePair(const image_pair_t pair_id) const;
|
| 87 |
+
inline ImagePairStat& ImagePair(const image_t image_id1,
|
| 88 |
+
const image_t image_id2);
|
| 89 |
+
|
| 90 |
+
// Get mutable objects.
|
| 91 |
+
inline class Camera& Camera(const camera_t camera_id);
|
| 92 |
+
inline class Image& Image(const image_t image_id);
|
| 93 |
+
inline class Point3D& Point3D(const point3D_t point3D_id);
|
| 94 |
+
inline ImagePairStat& ImagePair(const image_pair_t pair_id);
|
| 95 |
+
inline const ImagePairStat& ImagePair(const image_t image_id1,
|
| 96 |
+
const image_t image_id2) const;
|
| 97 |
+
|
| 98 |
+
// Get reference to all objects.
|
| 99 |
+
inline const EIGEN_STL_UMAP(camera_t, class Camera) & Cameras() const;
|
| 100 |
+
inline const EIGEN_STL_UMAP(image_t, class Image) & Images() const;
|
| 101 |
+
inline const std::vector<image_t>& RegImageIds() const;
|
| 102 |
+
inline const EIGEN_STL_UMAP(point3D_t, class Point3D) & Points3D() const;
|
| 103 |
+
inline const std::unordered_map<image_pair_t, ImagePairStat>& ImagePairs()
|
| 104 |
+
const;
|
| 105 |
+
|
| 106 |
+
// Identifiers of all 3D points.
|
| 107 |
+
std::unordered_set<point3D_t> Point3DIds() const;
|
| 108 |
+
|
| 109 |
+
// Check whether specific object exists.
|
| 110 |
+
inline bool ExistsCamera(const camera_t camera_id) const;
|
| 111 |
+
inline bool ExistsImage(const image_t image_id) const;
|
| 112 |
+
inline bool ExistsPoint3D(const point3D_t point3D_id) const;
|
| 113 |
+
inline bool ExistsImagePair(const image_pair_t pair_id) const;
|
| 114 |
+
|
| 115 |
+
// Load data from given `DatabaseCache`.
|
| 116 |
+
void Load(const DatabaseCache& database_cache);
|
| 117 |
+
|
| 118 |
+
// Setup all relevant data structures before reconstruction. Note the
|
| 119 |
+
// correspondence graph object must live until `TearDown` is called.
|
| 120 |
+
void SetUp(const CorrespondenceGraph* correspondence_graph);
|
| 121 |
+
|
| 122 |
+
// Finalize the Reconstruction after the reconstruction has finished.
|
| 123 |
+
//
|
| 124 |
+
// Once a scene has been finalized, it cannot be used for reconstruction.
|
| 125 |
+
//
|
| 126 |
+
// This removes all not yet registered images and unused cameras, in order to
|
| 127 |
+
// save memory.
|
| 128 |
+
void TearDown();
|
| 129 |
+
|
| 130 |
+
// Add new camera. There is only one camera per image, while multiple images
|
| 131 |
+
// might be taken by the same camera.
|
| 132 |
+
void AddCamera(class Camera camera);
|
| 133 |
+
|
| 134 |
+
// Add new image.
|
| 135 |
+
void AddImage(class Image image);
|
| 136 |
+
|
| 137 |
+
// Add new 3D object, and return its unique ID.
|
| 138 |
+
point3D_t AddPoint3D(
|
| 139 |
+
const Eigen::Vector3d& xyz, Track track,
|
| 140 |
+
const Eigen::Vector3ub& color = Eigen::Vector3ub::Zero());
|
| 141 |
+
|
| 142 |
+
// Add observation to existing 3D point.
|
| 143 |
+
void AddObservation(const point3D_t point3D_id, const TrackElement& track_el);
|
| 144 |
+
|
| 145 |
+
// Merge two 3D points and return new identifier of new 3D point.
|
| 146 |
+
// The location of the merged 3D point is a weighted average of the two
|
| 147 |
+
// original 3D point's locations according to their track lengths.
|
| 148 |
+
point3D_t MergePoints3D(const point3D_t point3D_id1,
|
| 149 |
+
const point3D_t point3D_id2);
|
| 150 |
+
|
| 151 |
+
// Delete a 3D point, and all its references in the observed images.
|
| 152 |
+
void DeletePoint3D(const point3D_t point3D_id);
|
| 153 |
+
|
| 154 |
+
// Delete one observation from an image and the corresponding 3D point.
|
| 155 |
+
// Note that this deletes the entire 3D point, if the track has two elements
|
| 156 |
+
// prior to calling this method.
|
| 157 |
+
void DeleteObservation(const image_t image_id, const point2D_t point2D_idx);
|
| 158 |
+
|
| 159 |
+
// Delete all 2D points of all images and all 3D points.
|
| 160 |
+
void DeleteAllPoints2DAndPoints3D();
|
| 161 |
+
|
| 162 |
+
// Register an existing image.
|
| 163 |
+
void RegisterImage(const image_t image_id);
|
| 164 |
+
|
| 165 |
+
// De-register an existing image, and all its references.
|
| 166 |
+
void DeRegisterImage(const image_t image_id);
|
| 167 |
+
|
| 168 |
+
// Check if image is registered.
|
| 169 |
+
inline bool IsImageRegistered(const image_t image_id) const;
|
| 170 |
+
|
| 171 |
+
// Normalize scene by scaling and translation to avoid degenerate
|
| 172 |
+
// visualization after bundle adjustment and to improve numerical
|
| 173 |
+
// stability of algorithms.
|
| 174 |
+
//
|
| 175 |
+
// Translates scene such that the mean of the camera centers or point
|
| 176 |
+
// locations are at the origin of the coordinate system.
|
| 177 |
+
//
|
| 178 |
+
// Scales scene such that the minimum and maximum camera centers are at the
|
| 179 |
+
// given `extent`, whereas `p0` and `p1` determine the minimum and
|
| 180 |
+
// maximum percentiles of the camera centers considered.
|
| 181 |
+
void Normalize(const double extent = 10.0, const double p0 = 0.1,
|
| 182 |
+
const double p1 = 0.9, const bool use_images = true);
|
| 183 |
+
|
| 184 |
+
// Compute the centroid of the 3D points
|
| 185 |
+
Eigen::Vector3d ComputeCentroid(const double p0 = 0.1,
|
| 186 |
+
const double p1 = 0.9) const;
|
| 187 |
+
|
| 188 |
+
// Compute the bounding box corners of the 3D points
|
| 189 |
+
std::pair<Eigen::Vector3d, Eigen::Vector3d> ComputeBoundingBox(
|
| 190 |
+
const double p0 = 0.0, const double p1 = 1.0) const;
|
| 191 |
+
|
| 192 |
+
// Apply the 3D similarity transformation to all images and points.
|
| 193 |
+
void Transform(const SimilarityTransform3& tform);
|
| 194 |
+
|
| 195 |
+
// Creates a cropped reconstruction using the input bounds as corner points
|
| 196 |
+
// of the bounding box containing the included 3D points of the new
|
| 197 |
+
// reconstruction. Only the cameras and images of the included points are
|
| 198 |
+
// registered.
|
| 199 |
+
Reconstruction Crop(
|
| 200 |
+
const std::pair<Eigen::Vector3d, Eigen::Vector3d>& bbox) const;
|
| 201 |
+
|
| 202 |
+
// Merge the given reconstruction into this reconstruction by registering the
|
| 203 |
+
// images registered in the given but not in this reconstruction and by
|
| 204 |
+
// merging the two clouds and their tracks. The coordinate frames of the two
|
| 205 |
+
// reconstructions are aligned using the projection centers of common
|
| 206 |
+
// registered images. Return true if the two reconstructions could be merged.
|
| 207 |
+
bool Merge(const Reconstruction& reconstruction,
|
| 208 |
+
const double max_reproj_error);
|
| 209 |
+
|
| 210 |
+
// Align the given reconstruction with a set of pre-defined camera positions.
|
| 211 |
+
// Assuming that locations[i] gives the 3D coordinates of the center
|
| 212 |
+
// of projection of the image with name image_names[i].
|
| 213 |
+
template <bool kEstimateScale = true>
|
| 214 |
+
bool Align(const std::vector<std::string>& image_names,
|
| 215 |
+
const std::vector<Eigen::Vector3d>& locations,
|
| 216 |
+
const int min_common_images,
|
| 217 |
+
SimilarityTransform3* tform = nullptr);
|
| 218 |
+
|
| 219 |
+
// Robust alignment using RANSAC.
|
| 220 |
+
template <bool kEstimateScale = true>
|
| 221 |
+
bool AlignRobust(const std::vector<std::string>& image_names,
|
| 222 |
+
const std::vector<Eigen::Vector3d>& locations,
|
| 223 |
+
const int min_common_images,
|
| 224 |
+
const RANSACOptions& ransac_options,
|
| 225 |
+
SimilarityTransform3* tform = nullptr);
|
| 226 |
+
|
| 227 |
+
// Find specific image by name. Note that this uses linear search.
|
| 228 |
+
const class Image* FindImageWithName(const std::string& name) const;
|
| 229 |
+
|
| 230 |
+
// Find images that are both present in this and the given reconstruction.
|
| 231 |
+
std::vector<image_t> FindCommonRegImageIds(
|
| 232 |
+
const Reconstruction& reconstruction) const;
|
| 233 |
+
|
| 234 |
+
// Update the image identifiers to match the ones in the database by matching
|
| 235 |
+
// the names of the images.
|
| 236 |
+
void TranscribeImageIdsToDatabase(const Database& database);
|
| 237 |
+
|
| 238 |
+
// Filter 3D points with large reprojection error, negative depth, or
|
| 239 |
+
// insufficient triangulation angle.
|
| 240 |
+
//
|
| 241 |
+
// @param max_reproj_error The maximum reprojection error.
|
| 242 |
+
// @param min_tri_angle The minimum triangulation angle.
|
| 243 |
+
// @param point3D_ids The points to be filtered.
|
| 244 |
+
//
|
| 245 |
+
// @return The number of filtered observations.
|
| 246 |
+
size_t FilterPoints3D(const double max_reproj_error,
|
| 247 |
+
const double min_tri_angle,
|
| 248 |
+
const std::unordered_set<point3D_t>& point3D_ids);
|
| 249 |
+
size_t FilterPoints3DInImages(const double max_reproj_error,
|
| 250 |
+
const double min_tri_angle,
|
| 251 |
+
const std::unordered_set<image_t>& image_ids);
|
| 252 |
+
size_t FilterAllPoints3D(const double max_reproj_error,
|
| 253 |
+
const double min_tri_angle);
|
| 254 |
+
|
| 255 |
+
// Filter observations that have negative depth.
|
| 256 |
+
//
|
| 257 |
+
// @return The number of filtered observations.
|
| 258 |
+
size_t FilterObservationsWithNegativeDepth();
|
| 259 |
+
|
| 260 |
+
// Filter images without observations or bogus camera parameters.
|
| 261 |
+
//
|
| 262 |
+
// @return The identifiers of the filtered images.
|
| 263 |
+
std::vector<image_t> FilterImages(const double min_focal_length_ratio,
|
| 264 |
+
const double max_focal_length_ratio,
|
| 265 |
+
const double max_extra_param);
|
| 266 |
+
|
| 267 |
+
// Compute statistics for scene.
|
| 268 |
+
size_t ComputeNumObservations() const;
|
| 269 |
+
double ComputeMeanTrackLength() const;
|
| 270 |
+
double ComputeMeanObservationsPerRegImage() const;
|
| 271 |
+
double ComputeMeanReprojectionError() const;
|
| 272 |
+
|
| 273 |
+
// Read data from text or binary file. Prefer binary data if it exists.
|
| 274 |
+
void Read(const std::string& path);
|
| 275 |
+
void Write(const std::string& path) const;
|
| 276 |
+
|
| 277 |
+
// Read data from binary/text file.
|
| 278 |
+
void ReadText(const std::string& path);
|
| 279 |
+
void ReadBinary(const std::string& path);
|
| 280 |
+
|
| 281 |
+
// Write data from binary/text file.
|
| 282 |
+
void WriteText(const std::string& path) const;
|
| 283 |
+
void WriteBinary(const std::string& path) const;
|
| 284 |
+
|
| 285 |
+
// Convert 3D points in reconstruction to PLY point cloud.
|
| 286 |
+
std::vector<PlyPoint> ConvertToPLY() const;
|
| 287 |
+
|
| 288 |
+
// Import from other data formats. Note that these import functions are
|
| 289 |
+
// only intended for visualization of data and usable for reconstruction.
|
| 290 |
+
void ImportPLY(const std::string& path);
|
| 291 |
+
void ImportPLY(const std::vector<PlyPoint>& ply_points);
|
| 292 |
+
|
| 293 |
+
// Export to other data formats.
|
| 294 |
+
|
| 295 |
+
// Exports in NVM format http://ccwu.me/vsfm/doc.html#nvm. Only supports
|
| 296 |
+
// SIMPLE_RADIAL camera model when exporting distortion parameters. When
|
| 297 |
+
// skip_distortion == true it supports all camera models with the caveat that
|
| 298 |
+
// it's using the mean focal length which will be inaccurate for camera models
|
| 299 |
+
// with two focal lengths and distortion.
|
| 300 |
+
bool ExportNVM(const std::string& path, bool skip_distortion = false) const;
|
| 301 |
+
|
| 302 |
+
// Exports in CAM format which is a simple text file that contains pose
|
| 303 |
+
// information and camera intrinsics for each image and exports one file per
|
| 304 |
+
// image; it does not include information on the 3D points. The format is as
|
| 305 |
+
// follows (2 lines of text with space separated numbers):
|
| 306 |
+
// <Tvec; 3 values> <Rotation matrix in row-major format; 9 values>
|
| 307 |
+
// <focal_length> <k1> <k2> 1.0 <principal point X> <principal point Y>
|
| 308 |
+
// Note that focal length is relative to the image max(width, height),
|
| 309 |
+
// and principal points x and y are relative to width and height respectively.
|
| 310 |
+
//
|
| 311 |
+
// Only supports SIMPLE_RADIAL and RADIAL camera models when exporting
|
| 312 |
+
// distortion parameters. When skip_distortion == true it supports all camera
|
| 313 |
+
// models with the caveat that it's using the mean focal length which will be
|
| 314 |
+
// inaccurate for camera models with two focal lengths and distortion.
|
| 315 |
+
bool ExportCam(const std::string& path, bool skip_distortion = false) const;
|
| 316 |
+
|
| 317 |
+
// Exports in Recon3D format which consists of three text files with the
|
| 318 |
+
// following format and content:
|
| 319 |
+
// 1) imagemap_0.txt: a list of image numeric IDs with one entry per line.
|
| 320 |
+
// 2) urd-images.txt: A list of images with one entry per line as:
|
| 321 |
+
// <image file name> <width> <height>
|
| 322 |
+
// 3) synth_0.out: Contains information for image poses, camera intrinsics,
|
| 323 |
+
// and 3D points as:
|
| 324 |
+
// <N; num images> <M; num points>
|
| 325 |
+
// <N lines of image entries>
|
| 326 |
+
// <M lines of point entries>
|
| 327 |
+
//
|
| 328 |
+
// Each image entry consists of 5 lines as:
|
| 329 |
+
// <focal length> <k1> <k2>
|
| 330 |
+
// <Rotation matrix; 3x3 array>
|
| 331 |
+
// <Tvec; 3 values>
|
| 332 |
+
// Note that the focal length is scaled by 1 / max(width, height)
|
| 333 |
+
//
|
| 334 |
+
// Each point entry consists of 3 lines as:
|
| 335 |
+
// <point x, y, z coordinates>
|
| 336 |
+
// <point RGB color>
|
| 337 |
+
// <K; num track elements> <Track Element 1> ... <Track Element K>
|
| 338 |
+
//
|
| 339 |
+
// Each track elemenet is a sequence of 5 values as:
|
| 340 |
+
// <image ID> <2D point ID> -1.0 <X> <Y>
|
| 341 |
+
// Note that the 2D point coordinates are centered around the principal
|
| 342 |
+
// point and scaled by 1 / max(width, height).
|
| 343 |
+
//
|
| 344 |
+
// When skip_distortion == true it supports all camera models with the
|
| 345 |
+
// caveat that it's using the mean focal length which will be inaccurate
|
| 346 |
+
// for camera models with two focal lengths and distortion.
|
| 347 |
+
bool ExportRecon3D(const std::string& path,
|
| 348 |
+
bool skip_distortion = false) const;
|
| 349 |
+
|
| 350 |
+
// Exports in Bundler format https://www.cs.cornell.edu/~snavely/bundler/.
|
| 351 |
+
// Supports SIMPLE_PINHOLE, PINHOLE, SIMPLE_RADIAL and RADIAL camera models
|
| 352 |
+
// when exporting distortion parameters. When skip_distortion == true it
|
| 353 |
+
// supports all camera models with the caveat that it's using the mean focal
|
| 354 |
+
// length which will be inaccurate for camera models with two focal lengths
|
| 355 |
+
// and distortion.
|
| 356 |
+
bool ExportBundler(const std::string& path, const std::string& list_path,
|
| 357 |
+
bool skip_distortion = false) const;
|
| 358 |
+
|
| 359 |
+
// Exports 3D points only in PLY format.
|
| 360 |
+
void ExportPLY(const std::string& path) const;
|
| 361 |
+
|
| 362 |
+
// Exports in VRML format https://en.wikipedia.org/wiki/VRML.
|
| 363 |
+
void ExportVRML(const std::string& images_path,
|
| 364 |
+
const std::string& points3D_path, const double image_scale,
|
| 365 |
+
const Eigen::Vector3d& image_rgb) const;
|
| 366 |
+
|
| 367 |
+
// Extract colors for 3D points of given image. Colors will be extracted
|
| 368 |
+
// only for 3D points which are completely black.
|
| 369 |
+
//
|
| 370 |
+
// @param image_id Identifier of the image for which to extract colors.
|
| 371 |
+
// @param path Absolute or relative path to root folder of image.
|
| 372 |
+
// The image path is determined by concatenating the
|
| 373 |
+
// root path and the name of the image.
|
| 374 |
+
//
|
| 375 |
+
// @return True if image could be read at given path.
|
| 376 |
+
bool ExtractColorsForImage(const image_t image_id, const std::string& path);
|
| 377 |
+
|
| 378 |
+
// Extract colors for all 3D points by computing the mean color of all images.
|
| 379 |
+
//
|
| 380 |
+
// @param path Absolute or relative path to root folder of image.
|
| 381 |
+
// The image path is determined by concatenating the
|
| 382 |
+
// root path and the name of the image.
|
| 383 |
+
void ExtractColorsForAllImages(const std::string& path);
|
| 384 |
+
|
| 385 |
+
// Create all image sub-directories in the given path.
|
| 386 |
+
void CreateImageDirs(const std::string& path) const;
|
| 387 |
+
|
| 388 |
+
private:
|
| 389 |
+
size_t FilterPoints3DWithSmallTriangulationAngle(
|
| 390 |
+
const double min_tri_angle,
|
| 391 |
+
const std::unordered_set<point3D_t>& point3D_ids);
|
| 392 |
+
size_t FilterPoints3DWithLargeReprojectionError(
|
| 393 |
+
const double max_reproj_error,
|
| 394 |
+
const std::unordered_set<point3D_t>& point3D_ids);
|
| 395 |
+
|
| 396 |
+
std::tuple<Eigen::Vector3d, Eigen::Vector3d, Eigen::Vector3d>
|
| 397 |
+
ComputeBoundsAndCentroid(const double p0, const double p1,
|
| 398 |
+
const bool use_images) const;
|
| 399 |
+
|
| 400 |
+
void ReadCamerasText(const std::string& path);
|
| 401 |
+
void ReadImagesText(const std::string& path);
|
| 402 |
+
void ReadPoints3DText(const std::string& path);
|
| 403 |
+
void ReadCamerasBinary(const std::string& path);
|
| 404 |
+
void ReadImagesBinary(const std::string& path);
|
| 405 |
+
void ReadPoints3DBinary(const std::string& path);
|
| 406 |
+
|
| 407 |
+
void WriteCamerasText(const std::string& path) const;
|
| 408 |
+
void WriteImagesText(const std::string& path) const;
|
| 409 |
+
void WritePoints3DText(const std::string& path) const;
|
| 410 |
+
void WriteCamerasBinary(const std::string& path) const;
|
| 411 |
+
void WriteImagesBinary(const std::string& path) const;
|
| 412 |
+
void WritePoints3DBinary(const std::string& path) const;
|
| 413 |
+
|
| 414 |
+
void SetObservationAsTriangulated(const image_t image_id,
|
| 415 |
+
const point2D_t point2D_idx,
|
| 416 |
+
const bool is_continued_point3D);
|
| 417 |
+
void ResetTriObservations(const image_t image_id, const point2D_t point2D_idx,
|
| 418 |
+
const bool is_deleted_point3D);
|
| 419 |
+
|
| 420 |
+
const CorrespondenceGraph* correspondence_graph_;
|
| 421 |
+
|
| 422 |
+
EIGEN_STL_UMAP(camera_t, class Camera) cameras_;
|
| 423 |
+
EIGEN_STL_UMAP(image_t, class Image) images_;
|
| 424 |
+
EIGEN_STL_UMAP(point3D_t, class Point3D) points3D_;
|
| 425 |
+
|
| 426 |
+
std::unordered_map<image_pair_t, ImagePairStat> image_pair_stats_;
|
| 427 |
+
|
| 428 |
+
// { image_id, ... } where `images_.at(image_id).registered == true`.
|
| 429 |
+
std::vector<image_t> reg_image_ids_;
|
| 430 |
+
|
| 431 |
+
// Total number of added 3D points, used to generate unique identifiers.
|
| 432 |
+
point3D_t num_added_points3D_;
|
| 433 |
+
};
|
| 434 |
+
|
| 435 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 436 |
+
// Implementation
|
| 437 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 438 |
+
|
| 439 |
+
size_t Reconstruction::NumCameras() const { return cameras_.size(); }
|
| 440 |
+
|
| 441 |
+
size_t Reconstruction::NumImages() const { return images_.size(); }
|
| 442 |
+
|
| 443 |
+
size_t Reconstruction::NumRegImages() const { return reg_image_ids_.size(); }
|
| 444 |
+
|
| 445 |
+
size_t Reconstruction::NumPoints3D() const { return points3D_.size(); }
|
| 446 |
+
|
| 447 |
+
size_t Reconstruction::NumImagePairs() const {
|
| 448 |
+
return image_pair_stats_.size();
|
| 449 |
+
}
|
| 450 |
+
|
| 451 |
+
const class Camera& Reconstruction::Camera(const camera_t camera_id) const {
|
| 452 |
+
return cameras_.at(camera_id);
|
| 453 |
+
}
|
| 454 |
+
|
| 455 |
+
const class Image& Reconstruction::Image(const image_t image_id) const {
|
| 456 |
+
return images_.at(image_id);
|
| 457 |
+
}
|
| 458 |
+
|
| 459 |
+
const class Point3D& Reconstruction::Point3D(const point3D_t point3D_id) const {
|
| 460 |
+
return points3D_.at(point3D_id);
|
| 461 |
+
}
|
| 462 |
+
|
| 463 |
+
const Reconstruction::ImagePairStat& Reconstruction::ImagePair(
|
| 464 |
+
const image_pair_t pair_id) const {
|
| 465 |
+
return image_pair_stats_.at(pair_id);
|
| 466 |
+
}
|
| 467 |
+
|
| 468 |
+
const Reconstruction::ImagePairStat& Reconstruction::ImagePair(
|
| 469 |
+
const image_t image_id1, const image_t image_id2) const {
|
| 470 |
+
const auto pair_id = Database::ImagePairToPairId(image_id1, image_id2);
|
| 471 |
+
return image_pair_stats_.at(pair_id);
|
| 472 |
+
}
|
| 473 |
+
|
| 474 |
+
class Camera& Reconstruction::Camera(const camera_t camera_id) {
|
| 475 |
+
return cameras_.at(camera_id);
|
| 476 |
+
}
|
| 477 |
+
|
| 478 |
+
class Image& Reconstruction::Image(const image_t image_id) {
|
| 479 |
+
return images_.at(image_id);
|
| 480 |
+
}
|
| 481 |
+
|
| 482 |
+
class Point3D& Reconstruction::Point3D(const point3D_t point3D_id) {
|
| 483 |
+
return points3D_.at(point3D_id);
|
| 484 |
+
}
|
| 485 |
+
|
| 486 |
+
Reconstruction::ImagePairStat& Reconstruction::ImagePair(
|
| 487 |
+
const image_pair_t pair_id) {
|
| 488 |
+
return image_pair_stats_.at(pair_id);
|
| 489 |
+
}
|
| 490 |
+
|
| 491 |
+
Reconstruction::ImagePairStat& Reconstruction::ImagePair(
|
| 492 |
+
const image_t image_id1, const image_t image_id2) {
|
| 493 |
+
const auto pair_id = Database::ImagePairToPairId(image_id1, image_id2);
|
| 494 |
+
return image_pair_stats_.at(pair_id);
|
| 495 |
+
}
|
| 496 |
+
|
| 497 |
+
const EIGEN_STL_UMAP(camera_t, Camera) & Reconstruction::Cameras() const {
|
| 498 |
+
return cameras_;
|
| 499 |
+
}
|
| 500 |
+
|
| 501 |
+
const EIGEN_STL_UMAP(image_t, class Image) & Reconstruction::Images() const {
|
| 502 |
+
return images_;
|
| 503 |
+
}
|
| 504 |
+
|
| 505 |
+
const std::vector<image_t>& Reconstruction::RegImageIds() const {
|
| 506 |
+
return reg_image_ids_;
|
| 507 |
+
}
|
| 508 |
+
|
| 509 |
+
const EIGEN_STL_UMAP(point3D_t, Point3D) & Reconstruction::Points3D() const {
|
| 510 |
+
return points3D_;
|
| 511 |
+
}
|
| 512 |
+
|
| 513 |
+
const std::unordered_map<image_pair_t, Reconstruction::ImagePairStat>&
|
| 514 |
+
Reconstruction::ImagePairs() const {
|
| 515 |
+
return image_pair_stats_;
|
| 516 |
+
}
|
| 517 |
+
|
| 518 |
+
bool Reconstruction::ExistsCamera(const camera_t camera_id) const {
|
| 519 |
+
return cameras_.find(camera_id) != cameras_.end();
|
| 520 |
+
}
|
| 521 |
+
|
| 522 |
+
bool Reconstruction::ExistsImage(const image_t image_id) const {
|
| 523 |
+
return images_.find(image_id) != images_.end();
|
| 524 |
+
}
|
| 525 |
+
|
| 526 |
+
bool Reconstruction::ExistsPoint3D(const point3D_t point3D_id) const {
|
| 527 |
+
return points3D_.find(point3D_id) != points3D_.end();
|
| 528 |
+
}
|
| 529 |
+
|
| 530 |
+
bool Reconstruction::ExistsImagePair(const image_pair_t pair_id) const {
|
| 531 |
+
return image_pair_stats_.find(pair_id) != image_pair_stats_.end();
|
| 532 |
+
}
|
| 533 |
+
|
| 534 |
+
bool Reconstruction::IsImageRegistered(const image_t image_id) const {
|
| 535 |
+
return Image(image_id).IsRegistered();
|
| 536 |
+
}
|
| 537 |
+
|
| 538 |
+
template <bool kEstimateScale>
|
| 539 |
+
bool Reconstruction::Align(const std::vector<std::string>& image_names,
|
| 540 |
+
const std::vector<Eigen::Vector3d>& locations,
|
| 541 |
+
const int min_common_images,
|
| 542 |
+
SimilarityTransform3* tform) {
|
| 543 |
+
CHECK_GE(min_common_images, 3);
|
| 544 |
+
CHECK_EQ(image_names.size(), locations.size());
|
| 545 |
+
|
| 546 |
+
// Find out which images are contained in the reconstruction and get the
|
| 547 |
+
// positions of their camera centers.
|
| 548 |
+
std::unordered_set<image_t> common_image_ids;
|
| 549 |
+
std::vector<Eigen::Vector3d> src;
|
| 550 |
+
std::vector<Eigen::Vector3d> dst;
|
| 551 |
+
for (size_t i = 0; i < image_names.size(); ++i) {
|
| 552 |
+
const class Image* image = FindImageWithName(image_names[i]);
|
| 553 |
+
if (image == nullptr) {
|
| 554 |
+
continue;
|
| 555 |
+
}
|
| 556 |
+
|
| 557 |
+
if (!IsImageRegistered(image->ImageId())) {
|
| 558 |
+
continue;
|
| 559 |
+
}
|
| 560 |
+
|
| 561 |
+
// Ignore duplicate images.
|
| 562 |
+
if (common_image_ids.count(image->ImageId()) > 0) {
|
| 563 |
+
continue;
|
| 564 |
+
}
|
| 565 |
+
|
| 566 |
+
common_image_ids.insert(image->ImageId());
|
| 567 |
+
src.push_back(image->ProjectionCenter());
|
| 568 |
+
dst.push_back(locations[i]);
|
| 569 |
+
}
|
| 570 |
+
|
| 571 |
+
// Only compute the alignment if there are enough correspondences.
|
| 572 |
+
if (common_image_ids.size() < static_cast<size_t>(min_common_images)) {
|
| 573 |
+
return false;
|
| 574 |
+
}
|
| 575 |
+
|
| 576 |
+
SimilarityTransform3 transform;
|
| 577 |
+
if (!transform.Estimate<kEstimateScale>(src, dst)) {
|
| 578 |
+
return false;
|
| 579 |
+
}
|
| 580 |
+
|
| 581 |
+
Transform(transform);
|
| 582 |
+
|
| 583 |
+
if (tform != nullptr) {
|
| 584 |
+
*tform = transform;
|
| 585 |
+
}
|
| 586 |
+
|
| 587 |
+
return true;
|
| 588 |
+
}
|
| 589 |
+
|
| 590 |
+
template <bool kEstimateScale>
|
| 591 |
+
bool Reconstruction::AlignRobust(const std::vector<std::string>& image_names,
|
| 592 |
+
const std::vector<Eigen::Vector3d>& locations,
|
| 593 |
+
const int min_common_images,
|
| 594 |
+
const RANSACOptions& ransac_options,
|
| 595 |
+
SimilarityTransform3* tform) {
|
| 596 |
+
CHECK_GE(min_common_images, 3);
|
| 597 |
+
CHECK_EQ(image_names.size(), locations.size());
|
| 598 |
+
|
| 599 |
+
// Find out which images are contained in the reconstruction and get the
|
| 600 |
+
// positions of their camera centers.
|
| 601 |
+
std::unordered_set<image_t> common_image_ids;
|
| 602 |
+
std::vector<Eigen::Vector3d> src;
|
| 603 |
+
std::vector<Eigen::Vector3d> dst;
|
| 604 |
+
for (size_t i = 0; i < image_names.size(); ++i) {
|
| 605 |
+
const class Image* image = FindImageWithName(image_names[i]);
|
| 606 |
+
if (image == nullptr) {
|
| 607 |
+
continue;
|
| 608 |
+
}
|
| 609 |
+
|
| 610 |
+
if (!IsImageRegistered(image->ImageId())) {
|
| 611 |
+
continue;
|
| 612 |
+
}
|
| 613 |
+
|
| 614 |
+
// Ignore duplicate images.
|
| 615 |
+
if (common_image_ids.count(image->ImageId()) > 0) {
|
| 616 |
+
continue;
|
| 617 |
+
}
|
| 618 |
+
|
| 619 |
+
common_image_ids.insert(image->ImageId());
|
| 620 |
+
src.push_back(image->ProjectionCenter());
|
| 621 |
+
dst.push_back(locations[i]);
|
| 622 |
+
}
|
| 623 |
+
|
| 624 |
+
// Only compute the alignment if there are enough correspondences.
|
| 625 |
+
if (common_image_ids.size() < static_cast<size_t>(min_common_images)) {
|
| 626 |
+
return false;
|
| 627 |
+
}
|
| 628 |
+
|
| 629 |
+
LORANSAC<SimilarityTransformEstimator<3, kEstimateScale>,
|
| 630 |
+
SimilarityTransformEstimator<3, kEstimateScale>>
|
| 631 |
+
ransac(ransac_options);
|
| 632 |
+
|
| 633 |
+
const auto report = ransac.Estimate(src, dst);
|
| 634 |
+
|
| 635 |
+
if (report.support.num_inliers < static_cast<size_t>(min_common_images)) {
|
| 636 |
+
return false;
|
| 637 |
+
}
|
| 638 |
+
|
| 639 |
+
SimilarityTransform3 transform = SimilarityTransform3(report.model);
|
| 640 |
+
Transform(transform);
|
| 641 |
+
|
| 642 |
+
if (tform != nullptr) {
|
| 643 |
+
*tform = transform;
|
| 644 |
+
}
|
| 645 |
+
|
| 646 |
+
return true;
|
| 647 |
+
}
|
| 648 |
+
|
| 649 |
+
} // namespace colmap
|
| 650 |
+
|
| 651 |
+
#endif // COLMAP_SRC_BASE_RECONSTRUCTION_H_
|
colmap/include/colmap/base/reconstruction_manager.h
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_BASE_RECONSTRUCTION_MANAGER_H_
|
| 33 |
+
#define COLMAP_SRC_BASE_RECONSTRUCTION_MANAGER_H_
|
| 34 |
+
|
| 35 |
+
#include "base/reconstruction.h"
|
| 36 |
+
|
| 37 |
+
namespace colmap {
|
| 38 |
+
|
| 39 |
+
class OptionManager;
|
| 40 |
+
|
| 41 |
+
class ReconstructionManager {
|
| 42 |
+
public:
|
| 43 |
+
ReconstructionManager();
|
| 44 |
+
|
| 45 |
+
// Move constructor and assignment.
|
| 46 |
+
ReconstructionManager(ReconstructionManager&& other);
|
| 47 |
+
ReconstructionManager& operator=(ReconstructionManager&& other);
|
| 48 |
+
|
| 49 |
+
// The number of reconstructions managed.
|
| 50 |
+
size_t Size() const;
|
| 51 |
+
|
| 52 |
+
// Get a reference to a specific reconstruction.
|
| 53 |
+
const Reconstruction& Get(const size_t idx) const;
|
| 54 |
+
Reconstruction& Get(const size_t idx);
|
| 55 |
+
|
| 56 |
+
// Add a new empty reconstruction and return its index.
|
| 57 |
+
size_t Add();
|
| 58 |
+
|
| 59 |
+
// Delete a specific reconstruction.
|
| 60 |
+
void Delete(const size_t idx);
|
| 61 |
+
|
| 62 |
+
// Delete all reconstructions.
|
| 63 |
+
void Clear();
|
| 64 |
+
|
| 65 |
+
// Read and add a new reconstruction and return its index.
|
| 66 |
+
size_t Read(const std::string& path);
|
| 67 |
+
|
| 68 |
+
// Write all managed reconstructions into sub-folders "0", "1", "2", ...
|
| 69 |
+
// If the option manager object is not null, the options are written
|
| 70 |
+
// to each respective reconstruction folder as well.
|
| 71 |
+
void Write(const std::string& path, const OptionManager* options) const;
|
| 72 |
+
|
| 73 |
+
private:
|
| 74 |
+
NON_COPYABLE(ReconstructionManager)
|
| 75 |
+
|
| 76 |
+
std::vector<std::unique_ptr<Reconstruction>> reconstructions_;
|
| 77 |
+
};
|
| 78 |
+
|
| 79 |
+
} // namespace colmap
|
| 80 |
+
|
| 81 |
+
#endif // COLMAP_SRC_BASE_RECONSTRUCTION_MANAGER_H_
|
colmap/include/colmap/base/scene_clustering.h
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_BASE_SCENE_CLUSTERING_H_
|
| 33 |
+
#define COLMAP_SRC_BASE_SCENE_CLUSTERING_H_
|
| 34 |
+
|
| 35 |
+
#include <list>
|
| 36 |
+
#include <vector>
|
| 37 |
+
|
| 38 |
+
#include "base/database.h"
|
| 39 |
+
#include "util/types.h"
|
| 40 |
+
|
| 41 |
+
namespace colmap {
|
| 42 |
+
|
| 43 |
+
// Scene clustering approach using normalized cuts on the scene graph. The scene
|
| 44 |
+
// is hierarchically partitioned into overlapping clusters until a maximum
|
| 45 |
+
// number of images is in a leaf node.
|
| 46 |
+
class SceneClustering {
|
| 47 |
+
public:
|
| 48 |
+
struct Options {
|
| 49 |
+
// Flag for hierarchical vs flat clustering
|
| 50 |
+
bool is_hierarchical = true;
|
| 51 |
+
|
| 52 |
+
// The branching factor of the hierarchical clustering.
|
| 53 |
+
int branching = 2;
|
| 54 |
+
|
| 55 |
+
// The number of overlapping images between child clusters.
|
| 56 |
+
int image_overlap = 50;
|
| 57 |
+
|
| 58 |
+
// The max related images matches to look for in a flat cluster
|
| 59 |
+
int num_image_matches = 20;
|
| 60 |
+
|
| 61 |
+
// The maximum number of images in a leaf node cluster, otherwise the
|
| 62 |
+
// cluster is further partitioned using the given branching factor. Note
|
| 63 |
+
// that a cluster leaf node will have at most `leaf_max_num_images +
|
| 64 |
+
// overlap` images to satisfy the overlap constraint.
|
| 65 |
+
int leaf_max_num_images = 500;
|
| 66 |
+
|
| 67 |
+
bool Check() const;
|
| 68 |
+
};
|
| 69 |
+
|
| 70 |
+
struct Cluster {
|
| 71 |
+
std::vector<image_t> image_ids;
|
| 72 |
+
std::vector<Cluster> child_clusters;
|
| 73 |
+
};
|
| 74 |
+
|
| 75 |
+
SceneClustering(const Options& options);
|
| 76 |
+
|
| 77 |
+
void Partition(const std::vector<std::pair<image_t, image_t>>& image_pairs,
|
| 78 |
+
const std::vector<int>& num_inliers);
|
| 79 |
+
|
| 80 |
+
const Cluster* GetRootCluster() const;
|
| 81 |
+
std::vector<const Cluster*> GetLeafClusters() const;
|
| 82 |
+
|
| 83 |
+
static SceneClustering Create(const Options& options,
|
| 84 |
+
const Database& database);
|
| 85 |
+
|
| 86 |
+
private:
|
| 87 |
+
void PartitionHierarchicalCluster(
|
| 88 |
+
const std::vector<std::pair<int, int>>& edges,
|
| 89 |
+
const std::vector<int>& weights, Cluster* cluster);
|
| 90 |
+
|
| 91 |
+
void PartitionFlatCluster(const std::vector<std::pair<int, int>>& edges,
|
| 92 |
+
const std::vector<int>& weights);
|
| 93 |
+
|
| 94 |
+
const Options options_;
|
| 95 |
+
std::unique_ptr<Cluster> root_cluster_;
|
| 96 |
+
};
|
| 97 |
+
|
| 98 |
+
} // namespace colmap
|
| 99 |
+
|
| 100 |
+
#endif // COLMAP_SRC_BASE_SCENE_CLUSTERING_H_
|
colmap/include/colmap/base/similarity_transform.h
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_BASE_SIMILARITY_TRANSFORM_H_
|
| 33 |
+
#define COLMAP_SRC_BASE_SIMILARITY_TRANSFORM_H_
|
| 34 |
+
|
| 35 |
+
#include <vector>
|
| 36 |
+
|
| 37 |
+
#include <Eigen/Core>
|
| 38 |
+
#include <Eigen/Geometry>
|
| 39 |
+
|
| 40 |
+
#include "estimators/similarity_transform.h"
|
| 41 |
+
#include "util/alignment.h"
|
| 42 |
+
#include "util/types.h"
|
| 43 |
+
|
| 44 |
+
namespace colmap {
|
| 45 |
+
|
| 46 |
+
struct RANSACOptions;
|
| 47 |
+
class Reconstruction;
|
| 48 |
+
|
| 49 |
+
// 3D similarity transformation with 7 degrees of freedom.
|
| 50 |
+
class SimilarityTransform3 {
|
| 51 |
+
public:
|
| 52 |
+
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
| 53 |
+
|
| 54 |
+
SimilarityTransform3();
|
| 55 |
+
|
| 56 |
+
explicit SimilarityTransform3(const Eigen::Matrix3x4d& matrix);
|
| 57 |
+
|
| 58 |
+
explicit SimilarityTransform3(
|
| 59 |
+
const Eigen::Transform<double, 3, Eigen::Affine>& transform);
|
| 60 |
+
|
| 61 |
+
SimilarityTransform3(const double scale, const Eigen::Vector4d& qvec,
|
| 62 |
+
const Eigen::Vector3d& tvec);
|
| 63 |
+
|
| 64 |
+
void Write(const std::string& path);
|
| 65 |
+
|
| 66 |
+
template <bool kEstimateScale = true>
|
| 67 |
+
bool Estimate(const std::vector<Eigen::Vector3d>& src,
|
| 68 |
+
const std::vector<Eigen::Vector3d>& dst);
|
| 69 |
+
|
| 70 |
+
SimilarityTransform3 Inverse() const;
|
| 71 |
+
|
| 72 |
+
void TransformPoint(Eigen::Vector3d* xyz) const;
|
| 73 |
+
void TransformPose(Eigen::Vector4d* qvec, Eigen::Vector3d* tvec) const;
|
| 74 |
+
|
| 75 |
+
Eigen::Matrix4d Matrix() const;
|
| 76 |
+
double Scale() const;
|
| 77 |
+
Eigen::Vector4d Rotation() const;
|
| 78 |
+
Eigen::Vector3d Translation() const;
|
| 79 |
+
|
| 80 |
+
static SimilarityTransform3 FromFile(const std::string& path);
|
| 81 |
+
|
| 82 |
+
private:
|
| 83 |
+
Eigen::Transform<double, 3, Eigen::Affine> transform_;
|
| 84 |
+
};
|
| 85 |
+
|
| 86 |
+
// Robustly compute alignment between reconstructions by finding images that
|
| 87 |
+
// are registered in both reconstructions. The alignment is then estimated
|
| 88 |
+
// robustly inside RANSAC from corresponding projection centers. An alignment
|
| 89 |
+
// is verified by reprojecting common 3D point observations.
|
| 90 |
+
// The min_inlier_observations threshold determines how many observations
|
| 91 |
+
// in a common image must reproject within the given threshold.
|
| 92 |
+
bool ComputeAlignmentBetweenReconstructions(
|
| 93 |
+
const Reconstruction& src_reconstruction,
|
| 94 |
+
const Reconstruction& ref_reconstruction,
|
| 95 |
+
const double min_inlier_observations, const double max_reproj_error,
|
| 96 |
+
Eigen::Matrix3x4d* alignment);
|
| 97 |
+
|
| 98 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 99 |
+
// Implementation
|
| 100 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 101 |
+
|
| 102 |
+
template <bool kEstimateScale>
|
| 103 |
+
bool SimilarityTransform3::Estimate(const std::vector<Eigen::Vector3d>& src,
|
| 104 |
+
const std::vector<Eigen::Vector3d>& dst) {
|
| 105 |
+
const auto results =
|
| 106 |
+
SimilarityTransformEstimator<3, kEstimateScale>().Estimate(src, dst);
|
| 107 |
+
if (results.empty()) {
|
| 108 |
+
return false;
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
CHECK_EQ(results.size(), 1);
|
| 112 |
+
transform_.matrix().topLeftCorner<3, 4>() = results[0];
|
| 113 |
+
|
| 114 |
+
return true;
|
| 115 |
+
}
|
| 116 |
+
|
| 117 |
+
} // namespace colmap
|
| 118 |
+
|
| 119 |
+
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION_CUSTOM(colmap::SimilarityTransform3)
|
| 120 |
+
|
| 121 |
+
#endif // COLMAP_SRC_BASE_SIMILARITY_TRANSFORM_H_
|
colmap/include/colmap/base/track.h
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_BASE_TRACK_H_
|
| 33 |
+
#define COLMAP_SRC_BASE_TRACK_H_
|
| 34 |
+
|
| 35 |
+
#include <vector>
|
| 36 |
+
|
| 37 |
+
#include "util/logging.h"
|
| 38 |
+
#include "util/types.h"
|
| 39 |
+
|
| 40 |
+
namespace colmap {
|
| 41 |
+
|
| 42 |
+
// Track class stores all observations of a 3D point.
|
| 43 |
+
struct TrackElement {
|
| 44 |
+
TrackElement();
|
| 45 |
+
TrackElement(const image_t image_id, const point2D_t point2D_idx);
|
| 46 |
+
// The image in which the track element is observed.
|
| 47 |
+
image_t image_id;
|
| 48 |
+
// The point in the image that the track element is observed.
|
| 49 |
+
point2D_t point2D_idx;
|
| 50 |
+
};
|
| 51 |
+
|
| 52 |
+
class Track {
|
| 53 |
+
public:
|
| 54 |
+
Track();
|
| 55 |
+
|
| 56 |
+
// The number of track elements.
|
| 57 |
+
inline size_t Length() const;
|
| 58 |
+
|
| 59 |
+
// Access all elements.
|
| 60 |
+
inline const std::vector<TrackElement>& Elements() const;
|
| 61 |
+
inline std::vector<TrackElement>& Elements();
|
| 62 |
+
inline void SetElements(std::vector<TrackElement> elements);
|
| 63 |
+
|
| 64 |
+
// Access specific elements.
|
| 65 |
+
inline const TrackElement& Element(const size_t idx) const;
|
| 66 |
+
inline TrackElement& Element(const size_t idx);
|
| 67 |
+
inline void SetElement(const size_t idx, const TrackElement& element);
|
| 68 |
+
|
| 69 |
+
// Append new elements.
|
| 70 |
+
inline void AddElement(const TrackElement& element);
|
| 71 |
+
inline void AddElement(const image_t image_id, const point2D_t point2D_idx);
|
| 72 |
+
inline void AddElements(const std::vector<TrackElement>& elements);
|
| 73 |
+
|
| 74 |
+
// Delete existing element.
|
| 75 |
+
inline void DeleteElement(const size_t idx);
|
| 76 |
+
void DeleteElement(const image_t image_id, const point2D_t point2D_idx);
|
| 77 |
+
|
| 78 |
+
// Requests that the track capacity be at least enough to contain the
|
| 79 |
+
// specified number of elements.
|
| 80 |
+
inline void Reserve(const size_t num_elements);
|
| 81 |
+
|
| 82 |
+
// Shrink the capacity of track vector to fit its size to save memory.
|
| 83 |
+
inline void Compress();
|
| 84 |
+
|
| 85 |
+
private:
|
| 86 |
+
std::vector<TrackElement> elements_;
|
| 87 |
+
};
|
| 88 |
+
|
| 89 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 90 |
+
// Implementation
|
| 91 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 92 |
+
|
| 93 |
+
size_t Track::Length() const { return elements_.size(); }
|
| 94 |
+
|
| 95 |
+
const std::vector<TrackElement>& Track::Elements() const { return elements_; }
|
| 96 |
+
|
| 97 |
+
std::vector<TrackElement>& Track::Elements() { return elements_; }
|
| 98 |
+
|
| 99 |
+
void Track::SetElements(std::vector<TrackElement> elements) {
|
| 100 |
+
elements_ = std::move(elements);
|
| 101 |
+
}
|
| 102 |
+
|
| 103 |
+
// Access specific elements.
|
| 104 |
+
const TrackElement& Track::Element(const size_t idx) const {
|
| 105 |
+
return elements_.at(idx);
|
| 106 |
+
}
|
| 107 |
+
|
| 108 |
+
TrackElement& Track::Element(const size_t idx) { return elements_.at(idx); }
|
| 109 |
+
|
| 110 |
+
void Track::SetElement(const size_t idx, const TrackElement& element) {
|
| 111 |
+
elements_.at(idx) = element;
|
| 112 |
+
}
|
| 113 |
+
|
| 114 |
+
void Track::AddElement(const TrackElement& element) {
|
| 115 |
+
elements_.push_back(element);
|
| 116 |
+
}
|
| 117 |
+
|
| 118 |
+
void Track::AddElement(const image_t image_id, const point2D_t point2D_idx) {
|
| 119 |
+
elements_.emplace_back(image_id, point2D_idx);
|
| 120 |
+
}
|
| 121 |
+
|
| 122 |
+
void Track::AddElements(const std::vector<TrackElement>& elements) {
|
| 123 |
+
elements_.insert(elements_.end(), elements.begin(), elements.end());
|
| 124 |
+
}
|
| 125 |
+
|
| 126 |
+
void Track::DeleteElement(const size_t idx) {
|
| 127 |
+
CHECK_LT(idx, elements_.size());
|
| 128 |
+
elements_.erase(elements_.begin() + idx);
|
| 129 |
+
}
|
| 130 |
+
|
| 131 |
+
void Track::Reserve(const size_t num_elements) {
|
| 132 |
+
elements_.reserve(num_elements);
|
| 133 |
+
}
|
| 134 |
+
|
| 135 |
+
void Track::Compress() { elements_.shrink_to_fit(); }
|
| 136 |
+
|
| 137 |
+
} // namespace colmap
|
| 138 |
+
|
| 139 |
+
#endif // COLMAP_SRC_BASE_TRACK_H_
|
colmap/include/colmap/base/triangulation.h
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_BASE_TRIANGULATION_H_
|
| 33 |
+
#define COLMAP_SRC_BASE_TRIANGULATION_H_
|
| 34 |
+
|
| 35 |
+
#include <vector>
|
| 36 |
+
|
| 37 |
+
#include <Eigen/Core>
|
| 38 |
+
|
| 39 |
+
#include "base/camera.h"
|
| 40 |
+
#include "util/alignment.h"
|
| 41 |
+
#include "util/math.h"
|
| 42 |
+
#include "util/types.h"
|
| 43 |
+
|
| 44 |
+
namespace colmap {
|
| 45 |
+
|
| 46 |
+
// Triangulate 3D point from corresponding image point observations.
|
| 47 |
+
//
|
| 48 |
+
// Implementation of the direct linear transform triangulation method in
|
| 49 |
+
// R. Hartley and A. Zisserman, Multiple View Geometry in Computer Vision,
|
| 50 |
+
// Cambridge Univ. Press, 2003.
|
| 51 |
+
//
|
| 52 |
+
// @param proj_matrix1 Projection matrix of the first image as 3x4 matrix.
|
| 53 |
+
// @param proj_matrix2 Projection matrix of the second image as 3x4 matrix.
|
| 54 |
+
// @param point1 Corresponding 2D point in first image.
|
| 55 |
+
// @param point2 Corresponding 2D point in second image.
|
| 56 |
+
//
|
| 57 |
+
// @return Triangulated 3D point.
|
| 58 |
+
Eigen::Vector3d TriangulatePoint(const Eigen::Matrix3x4d& proj_matrix1,
|
| 59 |
+
const Eigen::Matrix3x4d& proj_matrix2,
|
| 60 |
+
const Eigen::Vector2d& point1,
|
| 61 |
+
const Eigen::Vector2d& point2);
|
| 62 |
+
|
| 63 |
+
// Triangulate multiple 3D points from multiple image correspondences.
|
| 64 |
+
std::vector<Eigen::Vector3d> TriangulatePoints(
|
| 65 |
+
const Eigen::Matrix3x4d& proj_matrix1,
|
| 66 |
+
const Eigen::Matrix3x4d& proj_matrix2,
|
| 67 |
+
const std::vector<Eigen::Vector2d>& points1,
|
| 68 |
+
const std::vector<Eigen::Vector2d>& points2);
|
| 69 |
+
|
| 70 |
+
// Triangulate point from multiple views minimizing the L2 error.
|
| 71 |
+
//
|
| 72 |
+
// @param proj_matrices Projection matrices of multi-view observations.
|
| 73 |
+
// @param points Image observations of multi-view observations.
|
| 74 |
+
//
|
| 75 |
+
// @return Estimated 3D point.
|
| 76 |
+
Eigen::Vector3d TriangulateMultiViewPoint(
|
| 77 |
+
const std::vector<Eigen::Matrix3x4d>& proj_matrices,
|
| 78 |
+
const std::vector<Eigen::Vector2d>& points);
|
| 79 |
+
|
| 80 |
+
// Triangulate optimal 3D point from corresponding image point observations by
|
| 81 |
+
// finding the optimal image observations.
|
| 82 |
+
//
|
| 83 |
+
// Note that camera poses should be very good in order for this method to yield
|
| 84 |
+
// good results. Otherwise just use `TriangulatePoint`.
|
| 85 |
+
//
|
| 86 |
+
// Implementation of the method described in
|
| 87 |
+
// P. Lindstrom, "Triangulation Made Easy," IEEE Computer Vision and Pattern
|
| 88 |
+
// Recognition 2010, pp. 1554-1561, June 2010.
|
| 89 |
+
//
|
| 90 |
+
// @param proj_matrix1 Projection matrix of the first image as 3x4 matrix.
|
| 91 |
+
// @param proj_matrix2 Projection matrix of the second image as 3x4 matrix.
|
| 92 |
+
// @param point1 Corresponding 2D point in first image.
|
| 93 |
+
// @param point2 Corresponding 2D point in second image.
|
| 94 |
+
//
|
| 95 |
+
// @return Triangulated optimal 3D point.
|
| 96 |
+
Eigen::Vector3d TriangulateOptimalPoint(const Eigen::Matrix3x4d& proj_matrix1,
|
| 97 |
+
const Eigen::Matrix3x4d& proj_matrix2,
|
| 98 |
+
const Eigen::Vector2d& point1,
|
| 99 |
+
const Eigen::Vector2d& point2);
|
| 100 |
+
|
| 101 |
+
// Triangulate multiple optimal 3D points from multiple image correspondences.
|
| 102 |
+
std::vector<Eigen::Vector3d> TriangulateOptimalPoints(
|
| 103 |
+
const Eigen::Matrix3x4d& proj_matrix1,
|
| 104 |
+
const Eigen::Matrix3x4d& proj_matrix2,
|
| 105 |
+
const std::vector<Eigen::Vector2d>& points1,
|
| 106 |
+
const std::vector<Eigen::Vector2d>& points2);
|
| 107 |
+
|
| 108 |
+
// Calculate angle in radians between the two rays of a triangulated point.
|
| 109 |
+
double CalculateTriangulationAngle(const Eigen::Vector3d& proj_center1,
|
| 110 |
+
const Eigen::Vector3d& proj_center2,
|
| 111 |
+
const Eigen::Vector3d& point3D);
|
| 112 |
+
std::vector<double> CalculateTriangulationAngles(
|
| 113 |
+
const Eigen::Vector3d& proj_center1, const Eigen::Vector3d& proj_center2,
|
| 114 |
+
const std::vector<Eigen::Vector3d>& points3D);
|
| 115 |
+
|
| 116 |
+
} // namespace colmap
|
| 117 |
+
|
| 118 |
+
#endif // COLMAP_SRC_BASE_TRIANGULATION_H_
|
colmap/include/colmap/base/undistortion.h
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_BASE_UNDISTORTION_H_
|
| 33 |
+
#define COLMAP_SRC_BASE_UNDISTORTION_H_
|
| 34 |
+
|
| 35 |
+
#include "base/reconstruction.h"
|
| 36 |
+
#include "util/alignment.h"
|
| 37 |
+
#include "util/bitmap.h"
|
| 38 |
+
#include "util/misc.h"
|
| 39 |
+
#include "util/threading.h"
|
| 40 |
+
|
| 41 |
+
namespace colmap {
|
| 42 |
+
|
| 43 |
+
struct UndistortCameraOptions {
|
| 44 |
+
// The amount of blank pixels in the undistorted image in the range [0, 1].
|
| 45 |
+
double blank_pixels = 0.0;
|
| 46 |
+
|
| 47 |
+
// Minimum and maximum scale change of camera used to satisfy the blank
|
| 48 |
+
// pixel constraint.
|
| 49 |
+
double min_scale = 0.2;
|
| 50 |
+
double max_scale = 2.0;
|
| 51 |
+
|
| 52 |
+
// Maximum image size in terms of width or height of the undistorted camera.
|
| 53 |
+
int max_image_size = -1;
|
| 54 |
+
|
| 55 |
+
// The 4 factors in the range [0, 1] that define the ROI (region of interest)
|
| 56 |
+
// in original image. The bounding box pixel coordinates are calculated as
|
| 57 |
+
// (roi_min_x * Width, roi_min_y * Height) and
|
| 58 |
+
// (roi_max_x * Width, roi_max_y * Height).
|
| 59 |
+
double roi_min_x = 0.0;
|
| 60 |
+
double roi_min_y = 0.0;
|
| 61 |
+
double roi_max_x = 1.0;
|
| 62 |
+
double roi_max_y = 1.0;
|
| 63 |
+
};
|
| 64 |
+
|
| 65 |
+
// Undistort images and export undistorted cameras, as required by the
|
| 66 |
+
// mvs::PatchMatchController class.
|
| 67 |
+
class COLMAPUndistorter : public Thread {
|
| 68 |
+
public:
|
| 69 |
+
COLMAPUndistorter(
|
| 70 |
+
const UndistortCameraOptions& options,
|
| 71 |
+
const Reconstruction& reconstruction, const std::string& image_path,
|
| 72 |
+
const std::string& output_path, const int num_related_images = 20,
|
| 73 |
+
const CopyType copy_type = CopyType::COPY,
|
| 74 |
+
const std::vector<image_t>& image_ids = std::vector<image_t>());
|
| 75 |
+
|
| 76 |
+
private:
|
| 77 |
+
void Run();
|
| 78 |
+
|
| 79 |
+
bool Undistort(const image_t image_id) const;
|
| 80 |
+
void WritePatchMatchConfig() const;
|
| 81 |
+
void WriteFusionConfig() const;
|
| 82 |
+
void WriteScript(const bool geometric) const;
|
| 83 |
+
|
| 84 |
+
UndistortCameraOptions options_;
|
| 85 |
+
const std::string image_path_;
|
| 86 |
+
const std::string output_path_;
|
| 87 |
+
const CopyType copy_type_;
|
| 88 |
+
const int num_patch_match_src_images_;
|
| 89 |
+
const Reconstruction& reconstruction_;
|
| 90 |
+
const std::vector<image_t> image_ids_;
|
| 91 |
+
std::vector<std::string> image_names_;
|
| 92 |
+
};
|
| 93 |
+
|
| 94 |
+
// Undistort images and prepare data for CMVS/PMVS.
|
| 95 |
+
class PMVSUndistorter : public Thread {
|
| 96 |
+
public:
|
| 97 |
+
PMVSUndistorter(const UndistortCameraOptions& options,
|
| 98 |
+
const Reconstruction& reconstruction,
|
| 99 |
+
const std::string& image_path,
|
| 100 |
+
const std::string& output_path);
|
| 101 |
+
|
| 102 |
+
private:
|
| 103 |
+
void Run();
|
| 104 |
+
|
| 105 |
+
bool Undistort(const size_t reg_image_idx) const;
|
| 106 |
+
void WriteVisibilityData() const;
|
| 107 |
+
void WriteOptionFile() const;
|
| 108 |
+
void WritePMVSScript() const;
|
| 109 |
+
void WriteCMVSPMVSScript() const;
|
| 110 |
+
void WriteCOLMAPScript(const bool geometric) const;
|
| 111 |
+
void WriteCMVSCOLMAPScript(const bool geometric) const;
|
| 112 |
+
|
| 113 |
+
UndistortCameraOptions options_;
|
| 114 |
+
std::string image_path_;
|
| 115 |
+
std::string output_path_;
|
| 116 |
+
const Reconstruction& reconstruction_;
|
| 117 |
+
};
|
| 118 |
+
|
| 119 |
+
// Undistort images and prepare data for CMP-MVS.
|
| 120 |
+
class CMPMVSUndistorter : public Thread {
|
| 121 |
+
public:
|
| 122 |
+
CMPMVSUndistorter(const UndistortCameraOptions& options,
|
| 123 |
+
const Reconstruction& reconstruction,
|
| 124 |
+
const std::string& image_path,
|
| 125 |
+
const std::string& output_path);
|
| 126 |
+
|
| 127 |
+
private:
|
| 128 |
+
void Run();
|
| 129 |
+
|
| 130 |
+
bool Undistort(const size_t reg_image_idx) const;
|
| 131 |
+
|
| 132 |
+
UndistortCameraOptions options_;
|
| 133 |
+
std::string image_path_;
|
| 134 |
+
std::string output_path_;
|
| 135 |
+
const Reconstruction& reconstruction_;
|
| 136 |
+
};
|
| 137 |
+
|
| 138 |
+
// Undistort images and export undistorted cameras without the need for a
|
| 139 |
+
// reconstruction. Instead, the image names and camera model information are
|
| 140 |
+
// read from a text file.
|
| 141 |
+
class PureImageUndistorter : public Thread {
|
| 142 |
+
public:
|
| 143 |
+
PureImageUndistorter(const UndistortCameraOptions& options,
|
| 144 |
+
const std::string& image_path,
|
| 145 |
+
const std::string& output_path,
|
| 146 |
+
const std::vector<std::pair<std::string, Camera>>&
|
| 147 |
+
image_names_and_cameras);
|
| 148 |
+
|
| 149 |
+
private:
|
| 150 |
+
void Run();
|
| 151 |
+
|
| 152 |
+
bool Undistort(const size_t reg_image_idx) const;
|
| 153 |
+
|
| 154 |
+
UndistortCameraOptions options_;
|
| 155 |
+
std::string image_path_;
|
| 156 |
+
std::string output_path_;
|
| 157 |
+
const std::vector<std::pair<std::string, Camera>>& image_names_and_cameras_;
|
| 158 |
+
};
|
| 159 |
+
|
| 160 |
+
// Rectify stereo image pairs.
|
| 161 |
+
class StereoImageRectifier : public Thread {
|
| 162 |
+
public:
|
| 163 |
+
StereoImageRectifier(
|
| 164 |
+
const UndistortCameraOptions& options,
|
| 165 |
+
const Reconstruction& reconstruction, const std::string& image_path,
|
| 166 |
+
const std::string& output_path,
|
| 167 |
+
const std::vector<std::pair<image_t, image_t>>& stereo_pairs);
|
| 168 |
+
|
| 169 |
+
private:
|
| 170 |
+
void Run();
|
| 171 |
+
|
| 172 |
+
void Rectify(const image_t image_id1, const image_t image_id2) const;
|
| 173 |
+
|
| 174 |
+
UndistortCameraOptions options_;
|
| 175 |
+
std::string image_path_;
|
| 176 |
+
std::string output_path_;
|
| 177 |
+
const std::vector<std::pair<image_t, image_t>>& stereo_pairs_;
|
| 178 |
+
const Reconstruction& reconstruction_;
|
| 179 |
+
};
|
| 180 |
+
|
| 181 |
+
// Undistort camera by resizing the image and shifting the principal point.
|
| 182 |
+
//
|
| 183 |
+
// The scaling factor is computed such that no blank pixels are in the
|
| 184 |
+
// undistorted image (blank_pixels=0) or all pixels in distorted image are
|
| 185 |
+
// contained in output image (blank_pixels=1).
|
| 186 |
+
//
|
| 187 |
+
// The focal length of the image is preserved and the dimensions of the
|
| 188 |
+
// undistorted pinhole camera are adjusted such that either all pixels in
|
| 189 |
+
// the undistorted image have a corresponding pixel in the distorted image
|
| 190 |
+
// (i.e. no blank pixels at the borders, for `blank_pixels=0`), or all pixels
|
| 191 |
+
// in the distorted image project have a corresponding pixel in the undistorted
|
| 192 |
+
// image (i.e. blank pixels at the borders, for `blank_pixels=1`). Intermediate
|
| 193 |
+
// states can be achieved by setting `blank_pixels` between 0 and 1.
|
| 194 |
+
//
|
| 195 |
+
// The relative location of the principal point of the distorted camera is
|
| 196 |
+
// preserved. The scaling of the image dimensions is subject to the `min_scale`,
|
| 197 |
+
// `max_scale`, and `max_image_size` constraints.
|
| 198 |
+
Camera UndistortCamera(const UndistortCameraOptions& options,
|
| 199 |
+
const Camera& camera);
|
| 200 |
+
|
| 201 |
+
// Undistort image such that the viewing geometry of the undistorted image
|
| 202 |
+
// follows a pinhole camera model. See `UndistortCamera` for more details
|
| 203 |
+
// on the undistortion conventions.
|
| 204 |
+
void UndistortImage(const UndistortCameraOptions& options,
|
| 205 |
+
const Bitmap& distorted_image,
|
| 206 |
+
const Camera& distorted_camera, Bitmap* undistorted_image,
|
| 207 |
+
Camera* undistorted_camera);
|
| 208 |
+
|
| 209 |
+
// Undistort all cameras in the reconstruction and accordingly all
|
| 210 |
+
// observations in their corresponding images.
|
| 211 |
+
void UndistortReconstruction(const UndistortCameraOptions& options,
|
| 212 |
+
Reconstruction* reconstruction);
|
| 213 |
+
|
| 214 |
+
// Compute stereo rectification homographies that transform two images,
|
| 215 |
+
// such that corresponding pixels in one image lie on the same scanline in the
|
| 216 |
+
// other image. The matrix Q transforms disparity values to world coordinates
|
| 217 |
+
// as [x, y, disparity, 1] * Q = [X, Y, Z, 1] * w. Note that this function
|
| 218 |
+
// assumes that the two cameras are already undistorted.
|
| 219 |
+
void RectifyStereoCameras(const Camera& camera1, const Camera& camera2,
|
| 220 |
+
const Eigen::Vector4d& qvec,
|
| 221 |
+
const Eigen::Vector3d& tvec, Eigen::Matrix3d* H1,
|
| 222 |
+
Eigen::Matrix3d* H2, Eigen::Matrix4d* Q);
|
| 223 |
+
|
| 224 |
+
// Rectify and undistort the stereo image pair using the given geometry.
|
| 225 |
+
void RectifyAndUndistortStereoImages(
|
| 226 |
+
const UndistortCameraOptions& options, const Bitmap& distorted_image1,
|
| 227 |
+
const Bitmap& distorted_image2, const Camera& distorted_camera1,
|
| 228 |
+
const Camera& distorted_camera2, const Eigen::Vector4d& qvec,
|
| 229 |
+
const Eigen::Vector3d& tvec, Bitmap* undistorted_image1,
|
| 230 |
+
Bitmap* undistorted_image2, Camera* undistorted_camera, Eigen::Matrix4d* Q);
|
| 231 |
+
|
| 232 |
+
} // namespace colmap
|
| 233 |
+
|
| 234 |
+
#endif // COLMAP_SRC_BASE_UNDISTORTION_H_
|
colmap/include/colmap/base/visibility_pyramid.h
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_BASE_VISIBILITY_PYRAMID_H_
|
| 33 |
+
#define COLMAP_SRC_BASE_VISIBILITY_PYRAMID_H_
|
| 34 |
+
|
| 35 |
+
#include <vector>
|
| 36 |
+
|
| 37 |
+
#include <Eigen/Core>
|
| 38 |
+
|
| 39 |
+
#include "util/alignment.h"
|
| 40 |
+
|
| 41 |
+
namespace colmap {
|
| 42 |
+
|
| 43 |
+
// A class that captures the distribution of points in a 2D grid.
|
| 44 |
+
// For example, to capture the distribution of visible 3D points in an image.
|
| 45 |
+
//
|
| 46 |
+
// The class captures the distribution of points by a score. A higher score
|
| 47 |
+
// corresponds to a more uniform distribution of the points in the grid.
|
| 48 |
+
//
|
| 49 |
+
// The score is computed by the number of populated cells in a multi-resolution
|
| 50 |
+
// pyramid. A populated cell contributes to the overall score if it is
|
| 51 |
+
// populated by at least one point and the contributed score is according
|
| 52 |
+
// to its resolution in the pyramid. A cell in a higher resolution level
|
| 53 |
+
// contributes a higher score to the overall score.
|
| 54 |
+
class VisibilityPyramid {
|
| 55 |
+
public:
|
| 56 |
+
VisibilityPyramid();
|
| 57 |
+
VisibilityPyramid(const size_t num_levels, const size_t width,
|
| 58 |
+
const size_t height);
|
| 59 |
+
|
| 60 |
+
void SetPoint(const double x, const double y);
|
| 61 |
+
void ResetPoint(const double x, const double y);
|
| 62 |
+
|
| 63 |
+
inline size_t NumLevels() const;
|
| 64 |
+
inline size_t Width() const;
|
| 65 |
+
inline size_t Height() const;
|
| 66 |
+
|
| 67 |
+
inline size_t Score() const;
|
| 68 |
+
inline size_t MaxScore() const;
|
| 69 |
+
|
| 70 |
+
private:
|
| 71 |
+
void CellForPoint(const double x, const double y, size_t* cx,
|
| 72 |
+
size_t* cy) const;
|
| 73 |
+
|
| 74 |
+
// Range of the input points.
|
| 75 |
+
size_t width_;
|
| 76 |
+
size_t height_;
|
| 77 |
+
|
| 78 |
+
// The overall visibility score.
|
| 79 |
+
size_t score_;
|
| 80 |
+
|
| 81 |
+
// The maximum score when all cells are populated.
|
| 82 |
+
size_t max_score_;
|
| 83 |
+
|
| 84 |
+
// The visibilty pyramid with multiple levels.
|
| 85 |
+
std::vector<Eigen::MatrixXi> pyramid_;
|
| 86 |
+
};
|
| 87 |
+
|
| 88 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 89 |
+
// Implementation
|
| 90 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 91 |
+
|
| 92 |
+
size_t VisibilityPyramid::NumLevels() const { return pyramid_.size(); }
|
| 93 |
+
|
| 94 |
+
size_t VisibilityPyramid::Width() const { return width_; }
|
| 95 |
+
|
| 96 |
+
size_t VisibilityPyramid::Height() const { return height_; }
|
| 97 |
+
|
| 98 |
+
size_t VisibilityPyramid::Score() const { return score_; }
|
| 99 |
+
|
| 100 |
+
size_t VisibilityPyramid::MaxScore() const { return max_score_; }
|
| 101 |
+
|
| 102 |
+
} // namespace colmap
|
| 103 |
+
|
| 104 |
+
#endif // COLMAP_SRC_BASE_VISIBILITY_PYRAMID_H_
|
colmap/include/colmap/base/warp.h
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_BASE_WARP_H_
|
| 33 |
+
#define COLMAP_SRC_BASE_WARP_H_
|
| 34 |
+
|
| 35 |
+
#include "base/camera.h"
|
| 36 |
+
#include "util/alignment.h"
|
| 37 |
+
#include "util/bitmap.h"
|
| 38 |
+
|
| 39 |
+
namespace colmap {
|
| 40 |
+
|
| 41 |
+
// Warp source image to target image by projecting the pixels of the target
|
| 42 |
+
// image up to infinity and projecting it down into the source image
|
| 43 |
+
// (i.e. an inverse mapping). The function allocates the target image.
|
| 44 |
+
void WarpImageBetweenCameras(const Camera& source_camera,
|
| 45 |
+
const Camera& target_camera,
|
| 46 |
+
const Bitmap& source_image, Bitmap* target_image);
|
| 47 |
+
|
| 48 |
+
// Warp an image with the given homography, where H defines the pixel mapping
|
| 49 |
+
// from the target to source image. Note that the pixel centers are assumed to
|
| 50 |
+
// have coordinates (0.5, 0.5).
|
| 51 |
+
void WarpImageWithHomography(const Eigen::Matrix3d& H,
|
| 52 |
+
const Bitmap& source_image, Bitmap* target_image);
|
| 53 |
+
|
| 54 |
+
// First, warp source image to target image by projecting the pixels of the
|
| 55 |
+
// target image up to infinity and projecting it down into the source image
|
| 56 |
+
// (i.e. an inverse mapping). Second, warp the coordinates from the first
|
| 57 |
+
// warping with the given homography. The function allocates the target image.
|
| 58 |
+
void WarpImageWithHomographyBetweenCameras(const Eigen::Matrix3d& H,
|
| 59 |
+
const Camera& source_camera,
|
| 60 |
+
const Camera& target_camera,
|
| 61 |
+
const Bitmap& source_image,
|
| 62 |
+
Bitmap* target_image);
|
| 63 |
+
|
| 64 |
+
// Resample row-major image using bilinear interpolation.
|
| 65 |
+
void ResampleImageBilinear(const float* data, const int rows, const int cols,
|
| 66 |
+
const int new_rows, const int new_cols,
|
| 67 |
+
float* resampled);
|
| 68 |
+
|
| 69 |
+
// Smooth row-major image using a Gaussian filter kernel.
|
| 70 |
+
void SmoothImage(const float* data, const int rows, const int cols,
|
| 71 |
+
const float sigma_r, const float sigma_c, float* smoothed);
|
| 72 |
+
|
| 73 |
+
// Downsample row-major image by first smoothing and then resampling.
|
| 74 |
+
void DownsampleImage(const float* data, const int rows, const int cols,
|
| 75 |
+
const int new_rows, const int new_cols,
|
| 76 |
+
float* downsampled);
|
| 77 |
+
|
| 78 |
+
} // namespace colmap
|
| 79 |
+
|
| 80 |
+
#endif // COLMAP_SRC_BASE_WARP_H_
|
colmap/include/colmap/controllers/automatic_reconstruction.h
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_CONTROLLERS_AUTOMATIC_RECONSTRUCTION_H_
|
| 33 |
+
#define COLMAP_SRC_CONTROLLERS_AUTOMATIC_RECONSTRUCTION_H_
|
| 34 |
+
|
| 35 |
+
#include <string>
|
| 36 |
+
|
| 37 |
+
#include "base/reconstruction_manager.h"
|
| 38 |
+
#include "util/option_manager.h"
|
| 39 |
+
#include "util/threading.h"
|
| 40 |
+
|
| 41 |
+
namespace colmap {
|
| 42 |
+
|
| 43 |
+
class AutomaticReconstructionController : public Thread {
|
| 44 |
+
public:
|
| 45 |
+
enum class DataType { INDIVIDUAL, VIDEO, INTERNET };
|
| 46 |
+
enum class Quality { LOW, MEDIUM, HIGH, EXTREME };
|
| 47 |
+
enum class Mesher { POISSON, DELAUNAY };
|
| 48 |
+
|
| 49 |
+
struct Options {
|
| 50 |
+
// The path to the workspace folder in which all results are stored.
|
| 51 |
+
std::string workspace_path;
|
| 52 |
+
|
| 53 |
+
// The path to the image folder which are used as input.
|
| 54 |
+
std::string image_path;
|
| 55 |
+
|
| 56 |
+
// The path to the mask folder which are used as input.
|
| 57 |
+
std::string mask_path;
|
| 58 |
+
|
| 59 |
+
// The path to the vocabulary tree for feature matching.
|
| 60 |
+
std::string vocab_tree_path;
|
| 61 |
+
|
| 62 |
+
// The type of input data used to choose optimal mapper settings.
|
| 63 |
+
DataType data_type = DataType::INDIVIDUAL;
|
| 64 |
+
|
| 65 |
+
// Whether to perform low- or high-quality reconstruction.
|
| 66 |
+
Quality quality = Quality::HIGH;
|
| 67 |
+
|
| 68 |
+
// Whether to use shared intrinsics or not.
|
| 69 |
+
bool single_camera = false;
|
| 70 |
+
|
| 71 |
+
// Which camera model to use for images.
|
| 72 |
+
std::string camera_model = "SIMPLE_RADIAL";
|
| 73 |
+
|
| 74 |
+
// Whether to perform sparse mapping.
|
| 75 |
+
bool sparse = true;
|
| 76 |
+
|
| 77 |
+
// Whether to perform dense mapping.
|
| 78 |
+
#ifdef CUDA_ENABLED
|
| 79 |
+
bool dense = true;
|
| 80 |
+
#else
|
| 81 |
+
bool dense = false;
|
| 82 |
+
#endif
|
| 83 |
+
|
| 84 |
+
// The meshing algorithm to be used.
|
| 85 |
+
Mesher mesher = Mesher::POISSON;
|
| 86 |
+
|
| 87 |
+
// The number of threads to use in all stages.
|
| 88 |
+
int num_threads = -1;
|
| 89 |
+
|
| 90 |
+
// Whether to use the GPU in feature extraction and matching.
|
| 91 |
+
bool use_gpu = true;
|
| 92 |
+
|
| 93 |
+
// Index of the GPU used for GPU stages. For multi-GPU computation,
|
| 94 |
+
// you should separate multiple GPU indices by comma, e.g., "0,1,2,3".
|
| 95 |
+
// By default, all GPUs will be used in all stages.
|
| 96 |
+
std::string gpu_index = "-1";
|
| 97 |
+
};
|
| 98 |
+
|
| 99 |
+
AutomaticReconstructionController(
|
| 100 |
+
const Options& options, ReconstructionManager* reconstruction_manager);
|
| 101 |
+
|
| 102 |
+
void Stop() override;
|
| 103 |
+
|
| 104 |
+
private:
|
| 105 |
+
void Run() override;
|
| 106 |
+
void RunFeatureExtraction();
|
| 107 |
+
void RunFeatureMatching();
|
| 108 |
+
void RunSparseMapper();
|
| 109 |
+
void RunDenseMapper();
|
| 110 |
+
|
| 111 |
+
const Options options_;
|
| 112 |
+
OptionManager option_manager_;
|
| 113 |
+
ReconstructionManager* reconstruction_manager_;
|
| 114 |
+
Thread* active_thread_;
|
| 115 |
+
std::unique_ptr<Thread> feature_extractor_;
|
| 116 |
+
std::unique_ptr<Thread> exhaustive_matcher_;
|
| 117 |
+
std::unique_ptr<Thread> sequential_matcher_;
|
| 118 |
+
std::unique_ptr<Thread> vocab_tree_matcher_;
|
| 119 |
+
};
|
| 120 |
+
|
| 121 |
+
} // namespace colmap
|
| 122 |
+
|
| 123 |
+
#endif // COLMAP_SRC_CONTROLLERS_AUTOMATIC_RECONSTRUCTION_H_
|
colmap/include/colmap/controllers/bundle_adjustment.h
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_CONTROLLERS_BUNDLE_ADJUSTMENT_H_
|
| 33 |
+
#define COLMAP_SRC_CONTROLLERS_BUNDLE_ADJUSTMENT_H_
|
| 34 |
+
|
| 35 |
+
#include "base/reconstruction.h"
|
| 36 |
+
#include "util/option_manager.h"
|
| 37 |
+
#include "util/threading.h"
|
| 38 |
+
|
| 39 |
+
namespace colmap {
|
| 40 |
+
|
| 41 |
+
// Class that controls the global bundle adjustment procedure.
|
| 42 |
+
class BundleAdjustmentController : public Thread {
|
| 43 |
+
public:
|
| 44 |
+
BundleAdjustmentController(const OptionManager& options,
|
| 45 |
+
Reconstruction* reconstruction);
|
| 46 |
+
|
| 47 |
+
private:
|
| 48 |
+
void Run();
|
| 49 |
+
|
| 50 |
+
const OptionManager options_;
|
| 51 |
+
Reconstruction* reconstruction_;
|
| 52 |
+
};
|
| 53 |
+
|
| 54 |
+
} // namespace colmap
|
| 55 |
+
|
| 56 |
+
#endif // COLMAP_SRC_CONTROLLERS_BUNDLE_ADJUSTMENT_H_
|
colmap/include/colmap/controllers/hierarchical_mapper.h
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_CONTROLLERS_HIERARCHICAL_MAPPER_H_
|
| 33 |
+
#define COLMAP_SRC_CONTROLLERS_HIERARCHICAL_MAPPER_H_
|
| 34 |
+
|
| 35 |
+
#include "base/reconstruction_manager.h"
|
| 36 |
+
#include "base/scene_clustering.h"
|
| 37 |
+
#include "controllers/incremental_mapper.h"
|
| 38 |
+
#include "util/threading.h"
|
| 39 |
+
|
| 40 |
+
namespace colmap {
|
| 41 |
+
|
| 42 |
+
// Hierarchical mapping first hierarchically partitions the scene into multiple
|
| 43 |
+
// overlapping clusters, then reconstructs them separately using incremental
|
| 44 |
+
// mapping, and finally merges them all into a globally consistent
|
| 45 |
+
// reconstruction. This is especially useful for larger-scale scenes, since
|
| 46 |
+
// incremental mapping becomes slow with an increasing number of images.
|
| 47 |
+
class HierarchicalMapperController : public Thread {
|
| 48 |
+
public:
|
| 49 |
+
struct Options {
|
| 50 |
+
// The path to the image folder which are used as input.
|
| 51 |
+
std::string image_path;
|
| 52 |
+
|
| 53 |
+
// The path to the database file which is used as input.
|
| 54 |
+
std::string database_path;
|
| 55 |
+
|
| 56 |
+
// The maximum number of trials to initialize a cluster.
|
| 57 |
+
int init_num_trials = 10;
|
| 58 |
+
|
| 59 |
+
// The number of workers used to reconstruct clusters in parallel.
|
| 60 |
+
int num_workers = -1;
|
| 61 |
+
|
| 62 |
+
bool Check() const;
|
| 63 |
+
};
|
| 64 |
+
|
| 65 |
+
HierarchicalMapperController(
|
| 66 |
+
const Options& options,
|
| 67 |
+
const SceneClustering::Options& clustering_options,
|
| 68 |
+
const IncrementalMapperOptions& mapper_options,
|
| 69 |
+
ReconstructionManager* reconstruction_manager);
|
| 70 |
+
|
| 71 |
+
private:
|
| 72 |
+
void Run() override;
|
| 73 |
+
|
| 74 |
+
const Options options_;
|
| 75 |
+
const SceneClustering::Options clustering_options_;
|
| 76 |
+
const IncrementalMapperOptions mapper_options_;
|
| 77 |
+
ReconstructionManager* reconstruction_manager_;
|
| 78 |
+
};
|
| 79 |
+
|
| 80 |
+
} // namespace colmap
|
| 81 |
+
|
| 82 |
+
#endif // COLMAP_SRC_CONTROLLERS_HIERARCHICAL_MAPPER_H_
|
colmap/include/colmap/controllers/incremental_mapper.h
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_CONTROLLERS_INCREMENTAL_MAPPER_H_
|
| 33 |
+
#define COLMAP_SRC_CONTROLLERS_INCREMENTAL_MAPPER_H_
|
| 34 |
+
|
| 35 |
+
#include "base/reconstruction_manager.h"
|
| 36 |
+
#include "sfm/incremental_mapper.h"
|
| 37 |
+
#include "util/threading.h"
|
| 38 |
+
|
| 39 |
+
namespace colmap {
|
| 40 |
+
|
| 41 |
+
struct IncrementalMapperOptions {
|
| 42 |
+
public:
|
| 43 |
+
// The minimum number of matches for inlier matches to be considered.
|
| 44 |
+
int min_num_matches = 15;
|
| 45 |
+
|
| 46 |
+
// Whether to ignore the inlier matches of watermark image pairs.
|
| 47 |
+
bool ignore_watermarks = false;
|
| 48 |
+
|
| 49 |
+
// Whether to reconstruct multiple sub-models.
|
| 50 |
+
bool multiple_models = true;
|
| 51 |
+
|
| 52 |
+
// The number of sub-models to reconstruct.
|
| 53 |
+
int max_num_models = 50;
|
| 54 |
+
|
| 55 |
+
// The maximum number of overlapping images between sub-models. If the
|
| 56 |
+
// current sub-models shares more than this number of images with another
|
| 57 |
+
// model, then the reconstruction is stopped.
|
| 58 |
+
int max_model_overlap = 20;
|
| 59 |
+
|
| 60 |
+
// The minimum number of registered images of a sub-model, otherwise the
|
| 61 |
+
// sub-model is discarded.
|
| 62 |
+
int min_model_size = 10;
|
| 63 |
+
|
| 64 |
+
// The image identifiers used to initialize the reconstruction. Note that
|
| 65 |
+
// only one or both image identifiers can be specified. In the former case,
|
| 66 |
+
// the second image is automatically determined.
|
| 67 |
+
int init_image_id1 = -1;
|
| 68 |
+
int init_image_id2 = -1;
|
| 69 |
+
|
| 70 |
+
// The number of trials to initialize the reconstruction.
|
| 71 |
+
int init_num_trials = 200;
|
| 72 |
+
|
| 73 |
+
// Whether to extract colors for reconstructed points.
|
| 74 |
+
bool extract_colors = true;
|
| 75 |
+
|
| 76 |
+
// The number of threads to use during reconstruction.
|
| 77 |
+
int num_threads = -1;
|
| 78 |
+
|
| 79 |
+
// Thresholds for filtering images with degenerate intrinsics.
|
| 80 |
+
double min_focal_length_ratio = 0.1;
|
| 81 |
+
double max_focal_length_ratio = 10.0;
|
| 82 |
+
double max_extra_param = 1.0;
|
| 83 |
+
|
| 84 |
+
// Which intrinsic parameters to optimize during the reconstruction.
|
| 85 |
+
bool ba_refine_focal_length = true;
|
| 86 |
+
bool ba_refine_principal_point = false;
|
| 87 |
+
bool ba_refine_extra_params = true;
|
| 88 |
+
|
| 89 |
+
// The minimum number of residuals per bundle adjustment problem to
|
| 90 |
+
// enable multi-threading solving of the problems.
|
| 91 |
+
int ba_min_num_residuals_for_multi_threading = 50000;
|
| 92 |
+
|
| 93 |
+
// The number of images to optimize in local bundle adjustment.
|
| 94 |
+
int ba_local_num_images = 6;
|
| 95 |
+
|
| 96 |
+
// Ceres solver function tolerance for local bundle adjustment
|
| 97 |
+
double ba_local_function_tolerance = 0.0;
|
| 98 |
+
|
| 99 |
+
// The maximum number of local bundle adjustment iterations.
|
| 100 |
+
int ba_local_max_num_iterations = 25;
|
| 101 |
+
|
| 102 |
+
// Whether to use PBA in global bundle adjustment.
|
| 103 |
+
bool ba_global_use_pba = false;
|
| 104 |
+
|
| 105 |
+
// The GPU index for PBA bundle adjustment.
|
| 106 |
+
int ba_global_pba_gpu_index = -1;
|
| 107 |
+
|
| 108 |
+
// The growth rates after which to perform global bundle adjustment.
|
| 109 |
+
double ba_global_images_ratio = 1.1;
|
| 110 |
+
double ba_global_points_ratio = 1.1;
|
| 111 |
+
int ba_global_images_freq = 500;
|
| 112 |
+
int ba_global_points_freq = 250000;
|
| 113 |
+
|
| 114 |
+
// Ceres solver function tolerance for global bundle adjustment
|
| 115 |
+
double ba_global_function_tolerance = 0.0;
|
| 116 |
+
|
| 117 |
+
// The maximum number of global bundle adjustment iterations.
|
| 118 |
+
int ba_global_max_num_iterations = 50;
|
| 119 |
+
|
| 120 |
+
// The thresholds for iterative bundle adjustment refinements.
|
| 121 |
+
int ba_local_max_refinements = 2;
|
| 122 |
+
double ba_local_max_refinement_change = 0.001;
|
| 123 |
+
int ba_global_max_refinements = 5;
|
| 124 |
+
double ba_global_max_refinement_change = 0.0005;
|
| 125 |
+
|
| 126 |
+
// Path to a folder with reconstruction snapshots during incremental
|
| 127 |
+
// reconstruction. Snapshots will be saved according to the specified
|
| 128 |
+
// frequency of registered images.
|
| 129 |
+
std::string snapshot_path = "";
|
| 130 |
+
int snapshot_images_freq = 0;
|
| 131 |
+
|
| 132 |
+
// Which images to reconstruct. If no images are specified, all images will
|
| 133 |
+
// be reconstructed by default.
|
| 134 |
+
std::unordered_set<std::string> image_names;
|
| 135 |
+
|
| 136 |
+
// If reconstruction is provided as input, fix the existing image poses.
|
| 137 |
+
bool fix_existing_images = false;
|
| 138 |
+
|
| 139 |
+
IncrementalMapper::Options Mapper() const;
|
| 140 |
+
IncrementalTriangulator::Options Triangulation() const;
|
| 141 |
+
BundleAdjustmentOptions LocalBundleAdjustment() const;
|
| 142 |
+
BundleAdjustmentOptions GlobalBundleAdjustment() const;
|
| 143 |
+
ParallelBundleAdjuster::Options ParallelGlobalBundleAdjustment() const;
|
| 144 |
+
|
| 145 |
+
bool Check() const;
|
| 146 |
+
|
| 147 |
+
private:
|
| 148 |
+
friend class OptionManager;
|
| 149 |
+
friend class MapperGeneralOptionsWidget;
|
| 150 |
+
friend class MapperTriangulationOptionsWidget;
|
| 151 |
+
friend class MapperRegistrationOptionsWidget;
|
| 152 |
+
friend class MapperInitializationOptionsWidget;
|
| 153 |
+
friend class MapperBundleAdjustmentOptionsWidget;
|
| 154 |
+
friend class MapperFilteringOptionsWidget;
|
| 155 |
+
friend class ReconstructionOptionsWidget;
|
| 156 |
+
IncrementalMapper::Options mapper;
|
| 157 |
+
IncrementalTriangulator::Options triangulation;
|
| 158 |
+
};
|
| 159 |
+
|
| 160 |
+
// Class that controls the incremental mapping procedure by iteratively
|
| 161 |
+
// initializing reconstructions from the same scene graph.
|
| 162 |
+
class IncrementalMapperController : public Thread {
|
| 163 |
+
public:
|
| 164 |
+
enum {
|
| 165 |
+
INITIAL_IMAGE_PAIR_REG_CALLBACK,
|
| 166 |
+
NEXT_IMAGE_REG_CALLBACK,
|
| 167 |
+
LAST_IMAGE_REG_CALLBACK,
|
| 168 |
+
};
|
| 169 |
+
|
| 170 |
+
IncrementalMapperController(const IncrementalMapperOptions* options,
|
| 171 |
+
const std::string& image_path,
|
| 172 |
+
const std::string& database_path,
|
| 173 |
+
ReconstructionManager* reconstruction_manager);
|
| 174 |
+
|
| 175 |
+
private:
|
| 176 |
+
void Run();
|
| 177 |
+
bool LoadDatabase();
|
| 178 |
+
void Reconstruct(const IncrementalMapper::Options& init_mapper_options);
|
| 179 |
+
|
| 180 |
+
const IncrementalMapperOptions* options_;
|
| 181 |
+
const std::string image_path_;
|
| 182 |
+
const std::string database_path_;
|
| 183 |
+
ReconstructionManager* reconstruction_manager_;
|
| 184 |
+
DatabaseCache database_cache_;
|
| 185 |
+
};
|
| 186 |
+
|
| 187 |
+
// Globally filter points and images in mapper.
|
| 188 |
+
size_t FilterPoints(const IncrementalMapperOptions& options,
|
| 189 |
+
IncrementalMapper* mapper);
|
| 190 |
+
size_t FilterImages(const IncrementalMapperOptions& options,
|
| 191 |
+
IncrementalMapper* mapper);
|
| 192 |
+
|
| 193 |
+
// Globally complete and merge tracks in mapper.
|
| 194 |
+
size_t CompleteAndMergeTracks(const IncrementalMapperOptions& options,
|
| 195 |
+
IncrementalMapper* mapper);
|
| 196 |
+
|
| 197 |
+
} // namespace colmap
|
| 198 |
+
|
| 199 |
+
#endif // COLMAP_SRC_CONTROLLERS_INCREMENTAL_MAPPER_H_
|
colmap/include/colmap/estimators/absolute_pose.h
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_ESTIMATORS_ABSOLUTE_POSE_H_
|
| 33 |
+
#define COLMAP_SRC_ESTIMATORS_ABSOLUTE_POSE_H_
|
| 34 |
+
|
| 35 |
+
#include <array>
|
| 36 |
+
#include <vector>
|
| 37 |
+
|
| 38 |
+
#include <Eigen/Core>
|
| 39 |
+
|
| 40 |
+
#include "util/alignment.h"
|
| 41 |
+
#include "util/types.h"
|
| 42 |
+
|
| 43 |
+
namespace colmap {
|
| 44 |
+
|
| 45 |
+
// Analytic solver for the P3P (Perspective-Three-Point) problem.
|
| 46 |
+
//
|
| 47 |
+
// The algorithm is based on the following paper:
|
| 48 |
+
//
|
| 49 |
+
// X.S. Gao, X.-R. Hou, J. Tang, H.-F. Chang. Complete Solution
|
| 50 |
+
// Classification for the Perspective-Three-Point Problem.
|
| 51 |
+
// http://www.mmrc.iss.ac.cn/~xgao/paper/ieee.pdf
|
| 52 |
+
class P3PEstimator {
|
| 53 |
+
public:
|
| 54 |
+
// The 2D image feature observations.
|
| 55 |
+
typedef Eigen::Vector2d X_t;
|
| 56 |
+
// The observed 3D features in the world frame.
|
| 57 |
+
typedef Eigen::Vector3d Y_t;
|
| 58 |
+
// The transformation from the world to the camera frame.
|
| 59 |
+
typedef Eigen::Matrix3x4d M_t;
|
| 60 |
+
|
| 61 |
+
// The minimum number of samples needed to estimate a model.
|
| 62 |
+
static const int kMinNumSamples = 3;
|
| 63 |
+
|
| 64 |
+
// Estimate the most probable solution of the P3P problem from a set of
|
| 65 |
+
// three 2D-3D point correspondences.
|
| 66 |
+
//
|
| 67 |
+
// @param points2D Normalized 2D image points as 3x2 matrix.
|
| 68 |
+
// @param points3D 3D world points as 3x3 matrix.
|
| 69 |
+
//
|
| 70 |
+
// @return Most probable pose as length-1 vector of a 3x4 matrix.
|
| 71 |
+
static std::vector<M_t> Estimate(const std::vector<X_t>& points2D,
|
| 72 |
+
const std::vector<Y_t>& points3D);
|
| 73 |
+
|
| 74 |
+
// Calculate the squared reprojection error given a set of 2D-3D point
|
| 75 |
+
// correspondences and a projection matrix.
|
| 76 |
+
//
|
| 77 |
+
// @param points2D Normalized 2D image points as Nx2 matrix.
|
| 78 |
+
// @param points3D 3D world points as Nx3 matrix.
|
| 79 |
+
// @param proj_matrix 3x4 projection matrix.
|
| 80 |
+
// @param residuals Output vector of residuals.
|
| 81 |
+
static void Residuals(const std::vector<X_t>& points2D,
|
| 82 |
+
const std::vector<Y_t>& points3D,
|
| 83 |
+
const M_t& proj_matrix, std::vector<double>* residuals);
|
| 84 |
+
};
|
| 85 |
+
|
| 86 |
+
// EPNP solver for the PNP (Perspective-N-Point) problem. The solver needs a
|
| 87 |
+
// minimum of 4 2D-3D correspondences.
|
| 88 |
+
//
|
| 89 |
+
// The algorithm is based on the following paper:
|
| 90 |
+
//
|
| 91 |
+
// Lepetit, Vincent, Francesc Moreno-Noguer, and Pascal Fua.
|
| 92 |
+
// "Epnp: An accurate o (n) solution to the pnp problem."
|
| 93 |
+
// International journal of computer vision 81.2 (2009): 155-166.
|
| 94 |
+
//
|
| 95 |
+
// The implementation is based on their original open-source release, but is
|
| 96 |
+
// ported to Eigen and contains several improvements over the original code.
|
| 97 |
+
class EPNPEstimator {
|
| 98 |
+
public:
|
| 99 |
+
// The 2D image feature observations.
|
| 100 |
+
typedef Eigen::Vector2d X_t;
|
| 101 |
+
// The observed 3D features in the world frame.
|
| 102 |
+
typedef Eigen::Vector3d Y_t;
|
| 103 |
+
// The transformation from the world to the camera frame.
|
| 104 |
+
typedef Eigen::Matrix3x4d M_t;
|
| 105 |
+
|
| 106 |
+
// The minimum number of samples needed to estimate a model.
|
| 107 |
+
static const int kMinNumSamples = 4;
|
| 108 |
+
|
| 109 |
+
// Estimate the most probable solution of the P3P problem from a set of
|
| 110 |
+
// three 2D-3D point correspondences.
|
| 111 |
+
//
|
| 112 |
+
// @param points2D Normalized 2D image points as 3x2 matrix.
|
| 113 |
+
// @param points3D 3D world points as 3x3 matrix.
|
| 114 |
+
//
|
| 115 |
+
// @return Most probable pose as length-1 vector of a 3x4 matrix.
|
| 116 |
+
static std::vector<M_t> Estimate(const std::vector<X_t>& points2D,
|
| 117 |
+
const std::vector<Y_t>& points3D);
|
| 118 |
+
|
| 119 |
+
// Calculate the squared reprojection error given a set of 2D-3D point
|
| 120 |
+
// correspondences and a projection matrix.
|
| 121 |
+
//
|
| 122 |
+
// @param points2D Normalized 2D image points as Nx2 matrix.
|
| 123 |
+
// @param points3D 3D world points as Nx3 matrix.
|
| 124 |
+
// @param proj_matrix 3x4 projection matrix.
|
| 125 |
+
// @param residuals Output vector of residuals.
|
| 126 |
+
static void Residuals(const std::vector<X_t>& points2D,
|
| 127 |
+
const std::vector<Y_t>& points3D,
|
| 128 |
+
const M_t& proj_matrix, std::vector<double>* residuals);
|
| 129 |
+
|
| 130 |
+
private:
|
| 131 |
+
bool ComputePose(const std::vector<Eigen::Vector2d>& points2D,
|
| 132 |
+
const std::vector<Eigen::Vector3d>& points3D,
|
| 133 |
+
Eigen::Matrix3x4d* proj_matrix);
|
| 134 |
+
|
| 135 |
+
void ChooseControlPoints();
|
| 136 |
+
bool ComputeBarycentricCoordinates();
|
| 137 |
+
|
| 138 |
+
Eigen::Matrix<double, Eigen::Dynamic, 12> ComputeM();
|
| 139 |
+
Eigen::Matrix<double, 6, 10> ComputeL6x10(
|
| 140 |
+
const Eigen::Matrix<double, 12, 12>& Ut);
|
| 141 |
+
Eigen::Matrix<double, 6, 1> ComputeRho();
|
| 142 |
+
|
| 143 |
+
void FindBetasApprox1(const Eigen::Matrix<double, 6, 10>& L_6x10,
|
| 144 |
+
const Eigen::Matrix<double, 6, 1>& rho,
|
| 145 |
+
Eigen::Vector4d* betas);
|
| 146 |
+
void FindBetasApprox2(const Eigen::Matrix<double, 6, 10>& L_6x10,
|
| 147 |
+
const Eigen::Matrix<double, 6, 1>& rho,
|
| 148 |
+
Eigen::Vector4d* betas);
|
| 149 |
+
void FindBetasApprox3(const Eigen::Matrix<double, 6, 10>& L_6x10,
|
| 150 |
+
const Eigen::Matrix<double, 6, 1>& rho,
|
| 151 |
+
Eigen::Vector4d* betas);
|
| 152 |
+
|
| 153 |
+
void RunGaussNewton(const Eigen::Matrix<double, 6, 10>& L_6x10,
|
| 154 |
+
const Eigen::Matrix<double, 6, 1>& rho,
|
| 155 |
+
Eigen::Vector4d* betas);
|
| 156 |
+
|
| 157 |
+
double ComputeRT(const Eigen::Matrix<double, 12, 12>& Ut,
|
| 158 |
+
const Eigen::Vector4d& betas, Eigen::Matrix3d* R,
|
| 159 |
+
Eigen::Vector3d* t);
|
| 160 |
+
|
| 161 |
+
void ComputeCcs(const Eigen::Vector4d& betas,
|
| 162 |
+
const Eigen::Matrix<double, 12, 12>& Ut);
|
| 163 |
+
void ComputePcs();
|
| 164 |
+
|
| 165 |
+
void SolveForSign();
|
| 166 |
+
|
| 167 |
+
void EstimateRT(Eigen::Matrix3d* R, Eigen::Vector3d* t);
|
| 168 |
+
|
| 169 |
+
double ComputeTotalReprojectionError(const Eigen::Matrix3d& R,
|
| 170 |
+
const Eigen::Vector3d& t);
|
| 171 |
+
|
| 172 |
+
const std::vector<Eigen::Vector2d>* points2D_ = nullptr;
|
| 173 |
+
const std::vector<Eigen::Vector3d>* points3D_ = nullptr;
|
| 174 |
+
std::vector<Eigen::Vector3d> pcs_;
|
| 175 |
+
std::vector<Eigen::Vector4d> alphas_;
|
| 176 |
+
std::array<Eigen::Vector3d, 4> cws_;
|
| 177 |
+
std::array<Eigen::Vector3d, 4> ccs_;
|
| 178 |
+
};
|
| 179 |
+
|
| 180 |
+
} // namespace colmap
|
| 181 |
+
|
| 182 |
+
#endif // COLMAP_SRC_ESTIMATORS_ABSOLUTE_POSE_H_
|
colmap/include/colmap/estimators/affine_transform.h
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_ESTIMATORS_AFFINE_TRANSFORM_H_
|
| 33 |
+
#define COLMAP_SRC_ESTIMATORS_AFFINE_TRANSFORM_H_
|
| 34 |
+
|
| 35 |
+
#include <vector>
|
| 36 |
+
|
| 37 |
+
#include <Eigen/Core>
|
| 38 |
+
|
| 39 |
+
#include "util/alignment.h"
|
| 40 |
+
#include "util/types.h"
|
| 41 |
+
|
| 42 |
+
namespace colmap {
|
| 43 |
+
|
| 44 |
+
class AffineTransformEstimator {
|
| 45 |
+
public:
|
| 46 |
+
typedef Eigen::Vector2d X_t;
|
| 47 |
+
typedef Eigen::Vector2d Y_t;
|
| 48 |
+
typedef Eigen::Matrix<double, 2, 3> M_t;
|
| 49 |
+
|
| 50 |
+
// The minimum number of samples needed to estimate a model.
|
| 51 |
+
static const int kMinNumSamples = 3;
|
| 52 |
+
|
| 53 |
+
// Estimate the affine transformation from at least 3 correspondences.
|
| 54 |
+
static std::vector<M_t> Estimate(const std::vector<X_t>& points1,
|
| 55 |
+
const std::vector<Y_t>& points2);
|
| 56 |
+
|
| 57 |
+
// Compute the squared transformation error.
|
| 58 |
+
static void Residuals(const std::vector<X_t>& points1,
|
| 59 |
+
const std::vector<Y_t>& points2, const M_t& E,
|
| 60 |
+
std::vector<double>* residuals);
|
| 61 |
+
};
|
| 62 |
+
|
| 63 |
+
} // namespace colmap
|
| 64 |
+
|
| 65 |
+
#endif // COLMAP_SRC_ESTIMATORS_AFFINE_TRANSFORM_H_
|
colmap/include/colmap/estimators/coordinate_frame.h
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_ESTIMATORS_COORDINATE_AXES_H_
|
| 33 |
+
#define COLMAP_SRC_ESTIMATORS_COORDINATE_AXES_H_
|
| 34 |
+
|
| 35 |
+
#include <Eigen/Core>
|
| 36 |
+
|
| 37 |
+
#include "base/reconstruction.h"
|
| 38 |
+
|
| 39 |
+
namespace colmap {
|
| 40 |
+
|
| 41 |
+
struct ManhattanWorldFrameEstimationOptions {
|
| 42 |
+
// The maximum image size for line detection.
|
| 43 |
+
int max_image_size = 1024;
|
| 44 |
+
// The minimum length of line segments in pixels.
|
| 45 |
+
double min_line_length = 3;
|
| 46 |
+
// The tolerance for classifying lines into horizontal/vertical.
|
| 47 |
+
double line_orientation_tolerance = 0.2;
|
| 48 |
+
// The maximum distance in pixels between lines and the vanishing points.
|
| 49 |
+
double max_line_vp_distance = 0.5;
|
| 50 |
+
// The maximum cosine distance between estimated axes to be inliers.
|
| 51 |
+
double max_axis_distance = 0.05;
|
| 52 |
+
};
|
| 53 |
+
|
| 54 |
+
// Estimate gravity vector by assuming gravity-aligned image orientation, i.e.
|
| 55 |
+
// the majority of images is assumed to have the gravity vector aligned with an
|
| 56 |
+
// upright image plane.
|
| 57 |
+
Eigen::Vector3d EstimateGravityVectorFromImageOrientation(
|
| 58 |
+
const Reconstruction& reconstruction,
|
| 59 |
+
const double max_axis_distance = 0.05);
|
| 60 |
+
|
| 61 |
+
// Estimate the coordinate frame of the reconstruction assuming a Manhattan
|
| 62 |
+
// world by finding the major vanishing points in each image. This function
|
| 63 |
+
// assumes that the majority of images is taken in upright direction, i.e.
|
| 64 |
+
// people are standing upright in the image. The orthonormal axes of the
|
| 65 |
+
// estimated coordinate frame will be given in the columns of the returned
|
| 66 |
+
// matrix. If one axis could not be determined, the respective column will be
|
| 67 |
+
// zero. The axes are specified in the world coordinate system in the order
|
| 68 |
+
// rightward, downward, forward.
|
| 69 |
+
Eigen::Matrix3d EstimateManhattanWorldFrame(
|
| 70 |
+
const ManhattanWorldFrameEstimationOptions& options,
|
| 71 |
+
const Reconstruction& reconstruction, const std::string& image_path);
|
| 72 |
+
|
| 73 |
+
// Aligns the reconstruction to the plane defined by running PCA on the 3D
|
| 74 |
+
// points. The model centroid is at the origin of the new coordinate system
|
| 75 |
+
// and the X axis is the first principal component with the Y axis being the
|
| 76 |
+
// second principal component
|
| 77 |
+
void AlignToPrincipalPlane(Reconstruction* recon, SimilarityTransform3* tform);
|
| 78 |
+
|
| 79 |
+
// Aligns the reconstruction to the local ENU plane orientation. Rotates the
|
| 80 |
+
// reconstruction such that the x-y plane aligns with the ENU tangent plane at
|
| 81 |
+
// the point cloud centroid and translates the origin to the centroid.
|
| 82 |
+
// If unscaled == true, then the original scale of the model remains unchanged.
|
| 83 |
+
void AlignToENUPlane(Reconstruction* recon, SimilarityTransform3* tform,
|
| 84 |
+
bool unscaled);
|
| 85 |
+
|
| 86 |
+
} // namespace colmap
|
| 87 |
+
|
| 88 |
+
#endif // COLMAP_SRC_ESTIMATORS_COORDINATE_AXES_H_
|
colmap/include/colmap/estimators/essential_matrix.h
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_ESTIMATORS_ESSENTIAL_MATRIX_H_
|
| 33 |
+
#define COLMAP_SRC_ESTIMATORS_ESSENTIAL_MATRIX_H_
|
| 34 |
+
|
| 35 |
+
#include <vector>
|
| 36 |
+
|
| 37 |
+
#include <Eigen/Core>
|
| 38 |
+
|
| 39 |
+
#include <ceres/ceres.h>
|
| 40 |
+
|
| 41 |
+
#include "util/alignment.h"
|
| 42 |
+
#include "util/types.h"
|
| 43 |
+
|
| 44 |
+
namespace colmap {
|
| 45 |
+
|
| 46 |
+
// Essential matrix estimator from corresponding normalized point pairs.
|
| 47 |
+
//
|
| 48 |
+
// This algorithm solves the 5-Point problem based on the following paper:
|
| 49 |
+
//
|
| 50 |
+
// D. Nister, An efficient solution to the five-point relative pose problem,
|
| 51 |
+
// IEEE-T-PAMI, 26(6), 2004.
|
| 52 |
+
// http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.86.8769
|
| 53 |
+
class EssentialMatrixFivePointEstimator {
|
| 54 |
+
public:
|
| 55 |
+
typedef Eigen::Vector2d X_t;
|
| 56 |
+
typedef Eigen::Vector2d Y_t;
|
| 57 |
+
typedef Eigen::Matrix3d M_t;
|
| 58 |
+
|
| 59 |
+
// The minimum number of samples needed to estimate a model.
|
| 60 |
+
static const int kMinNumSamples = 5;
|
| 61 |
+
|
| 62 |
+
// Estimate up to 10 possible essential matrix solutions from a set of
|
| 63 |
+
// corresponding points.
|
| 64 |
+
//
|
| 65 |
+
// The number of corresponding points must be at least 5.
|
| 66 |
+
//
|
| 67 |
+
// @param points1 First set of corresponding points.
|
| 68 |
+
// @param points2 Second set of corresponding points.
|
| 69 |
+
//
|
| 70 |
+
// @return Up to 10 solutions as a vector of 3x3 essential matrices.
|
| 71 |
+
static std::vector<M_t> Estimate(const std::vector<X_t>& points1,
|
| 72 |
+
const std::vector<Y_t>& points2);
|
| 73 |
+
|
| 74 |
+
// Calculate the residuals of a set of corresponding points and a given
|
| 75 |
+
// essential matrix.
|
| 76 |
+
//
|
| 77 |
+
// Residuals are defined as the squared Sampson error.
|
| 78 |
+
//
|
| 79 |
+
// @param points1 First set of corresponding points.
|
| 80 |
+
// @param points2 Second set of corresponding points.
|
| 81 |
+
// @param E 3x3 essential matrix.
|
| 82 |
+
// @param residuals Output vector of residuals.
|
| 83 |
+
static void Residuals(const std::vector<X_t>& points1,
|
| 84 |
+
const std::vector<Y_t>& points2, const M_t& E,
|
| 85 |
+
std::vector<double>* residuals);
|
| 86 |
+
};
|
| 87 |
+
|
| 88 |
+
// Essential matrix estimator from corresponding normalized point pairs.
|
| 89 |
+
//
|
| 90 |
+
// This algorithm solves the 8-Point problem based on the following paper:
|
| 91 |
+
//
|
| 92 |
+
// Hartley and Zisserman, Multiple View Geometry, algorithm 11.1, page 282.
|
| 93 |
+
class EssentialMatrixEightPointEstimator {
|
| 94 |
+
public:
|
| 95 |
+
typedef Eigen::Vector2d X_t;
|
| 96 |
+
typedef Eigen::Vector2d Y_t;
|
| 97 |
+
typedef Eigen::Matrix3d M_t;
|
| 98 |
+
|
| 99 |
+
// The minimum number of samples needed to estimate a model.
|
| 100 |
+
static const int kMinNumSamples = 8;
|
| 101 |
+
|
| 102 |
+
// Estimate essential matrix solutions from set of corresponding points.
|
| 103 |
+
//
|
| 104 |
+
// The number of corresponding points must be at least 8.
|
| 105 |
+
//
|
| 106 |
+
// @param points1 First set of corresponding points.
|
| 107 |
+
// @param points2 Second set of corresponding points.
|
| 108 |
+
static std::vector<M_t> Estimate(const std::vector<X_t>& points1,
|
| 109 |
+
const std::vector<Y_t>& points2);
|
| 110 |
+
|
| 111 |
+
// Calculate the residuals of a set of corresponding points and a given
|
| 112 |
+
// essential matrix.
|
| 113 |
+
//
|
| 114 |
+
// Residuals are defined as the squared Sampson error.
|
| 115 |
+
//
|
| 116 |
+
// @param points1 First set of corresponding points.
|
| 117 |
+
// @param points2 Second set of corresponding points.
|
| 118 |
+
// @param E 3x3 essential matrix.
|
| 119 |
+
// @param residuals Output vector of residuals.
|
| 120 |
+
static void Residuals(const std::vector<X_t>& points1,
|
| 121 |
+
const std::vector<Y_t>& points2, const M_t& E,
|
| 122 |
+
std::vector<double>* residuals);
|
| 123 |
+
};
|
| 124 |
+
|
| 125 |
+
} // namespace colmap
|
| 126 |
+
|
| 127 |
+
#endif // COLMAP_SRC_ESTIMATORS_ESSENTIAL_MATRIX_H_
|
colmap/include/colmap/estimators/essential_matrix_coeffs.h
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
{
|
| 33 |
+
const double* b = B.data();
|
| 34 |
+
|
| 35 |
+
coeffs(0) = b[0] * b[17] * b[34] + b[26] * b[4] * b[21] -
|
| 36 |
+
b[26] * b[17] * b[8] - b[13] * b[4] * b[34] -
|
| 37 |
+
b[0] * b[21] * b[30] + b[13] * b[30] * b[8];
|
| 38 |
+
coeffs(1) =
|
| 39 |
+
b[26] * b[4] * b[22] + b[14] * b[30] * b[8] + b[13] * b[31] * b[8] +
|
| 40 |
+
b[1] * b[17] * b[34] - b[13] * b[5] * b[34] + b[26] * b[5] * b[21] -
|
| 41 |
+
b[0] * b[21] * b[31] - b[26] * b[17] * b[9] - b[1] * b[21] * b[30] +
|
| 42 |
+
b[27] * b[4] * b[21] + b[0] * b[17] * b[35] - b[0] * b[22] * b[30] +
|
| 43 |
+
b[13] * b[30] * b[9] + b[0] * b[18] * b[34] - b[27] * b[17] * b[8] -
|
| 44 |
+
b[14] * b[4] * b[34] - b[13] * b[4] * b[35] - b[26] * b[18] * b[8];
|
| 45 |
+
coeffs(2) =
|
| 46 |
+
b[14] * b[30] * b[9] + b[14] * b[31] * b[8] + b[13] * b[31] * b[9] -
|
| 47 |
+
b[13] * b[4] * b[36] - b[13] * b[5] * b[35] + b[15] * b[30] * b[8] -
|
| 48 |
+
b[13] * b[6] * b[34] + b[13] * b[30] * b[10] + b[13] * b[32] * b[8] -
|
| 49 |
+
b[14] * b[4] * b[35] - b[14] * b[5] * b[34] + b[26] * b[4] * b[23] +
|
| 50 |
+
b[26] * b[5] * b[22] + b[26] * b[6] * b[21] - b[26] * b[17] * b[10] -
|
| 51 |
+
b[15] * b[4] * b[34] - b[26] * b[18] * b[9] - b[26] * b[19] * b[8] +
|
| 52 |
+
b[27] * b[4] * b[22] + b[27] * b[5] * b[21] - b[27] * b[17] * b[9] -
|
| 53 |
+
b[27] * b[18] * b[8] - b[1] * b[21] * b[31] - b[0] * b[23] * b[30] -
|
| 54 |
+
b[0] * b[21] * b[32] + b[28] * b[4] * b[21] - b[28] * b[17] * b[8] +
|
| 55 |
+
b[2] * b[17] * b[34] + b[0] * b[18] * b[35] - b[0] * b[22] * b[31] +
|
| 56 |
+
b[0] * b[17] * b[36] + b[0] * b[19] * b[34] - b[1] * b[22] * b[30] +
|
| 57 |
+
b[1] * b[18] * b[34] + b[1] * b[17] * b[35] - b[2] * b[21] * b[30];
|
| 58 |
+
coeffs(3) =
|
| 59 |
+
b[14] * b[30] * b[10] + b[14] * b[32] * b[8] - b[3] * b[21] * b[30] +
|
| 60 |
+
b[3] * b[17] * b[34] + b[13] * b[32] * b[9] + b[13] * b[33] * b[8] -
|
| 61 |
+
b[13] * b[4] * b[37] - b[13] * b[5] * b[36] + b[15] * b[30] * b[9] +
|
| 62 |
+
b[15] * b[31] * b[8] - b[16] * b[4] * b[34] - b[13] * b[6] * b[35] -
|
| 63 |
+
b[13] * b[7] * b[34] + b[13] * b[30] * b[11] + b[13] * b[31] * b[10] +
|
| 64 |
+
b[14] * b[31] * b[9] - b[14] * b[4] * b[36] - b[14] * b[5] * b[35] -
|
| 65 |
+
b[14] * b[6] * b[34] + b[16] * b[30] * b[8] - b[26] * b[20] * b[8] +
|
| 66 |
+
b[26] * b[4] * b[24] + b[26] * b[5] * b[23] + b[26] * b[6] * b[22] +
|
| 67 |
+
b[26] * b[7] * b[21] - b[26] * b[17] * b[11] - b[15] * b[4] * b[35] -
|
| 68 |
+
b[15] * b[5] * b[34] - b[26] * b[18] * b[10] - b[26] * b[19] * b[9] +
|
| 69 |
+
b[27] * b[4] * b[23] + b[27] * b[5] * b[22] + b[27] * b[6] * b[21] -
|
| 70 |
+
b[27] * b[17] * b[10] - b[27] * b[18] * b[9] - b[27] * b[19] * b[8] +
|
| 71 |
+
b[0] * b[17] * b[37] - b[0] * b[23] * b[31] - b[0] * b[24] * b[30] -
|
| 72 |
+
b[0] * b[21] * b[33] - b[29] * b[17] * b[8] + b[28] * b[4] * b[22] +
|
| 73 |
+
b[28] * b[5] * b[21] - b[28] * b[17] * b[9] - b[28] * b[18] * b[8] +
|
| 74 |
+
b[29] * b[4] * b[21] + b[1] * b[19] * b[34] - b[2] * b[21] * b[31] +
|
| 75 |
+
b[0] * b[20] * b[34] + b[0] * b[19] * b[35] + b[0] * b[18] * b[36] -
|
| 76 |
+
b[0] * b[22] * b[32] - b[1] * b[23] * b[30] - b[1] * b[21] * b[32] +
|
| 77 |
+
b[1] * b[18] * b[35] - b[1] * b[22] * b[31] - b[2] * b[22] * b[30] +
|
| 78 |
+
b[2] * b[17] * b[35] + b[1] * b[17] * b[36] + b[2] * b[18] * b[34];
|
| 79 |
+
coeffs(4) =
|
| 80 |
+
-b[14] * b[6] * b[35] - b[14] * b[7] * b[34] - b[3] * b[22] * b[30] -
|
| 81 |
+
b[3] * b[21] * b[31] + b[3] * b[17] * b[35] + b[3] * b[18] * b[34] +
|
| 82 |
+
b[13] * b[32] * b[10] + b[13] * b[33] * b[9] - b[13] * b[4] * b[38] -
|
| 83 |
+
b[13] * b[5] * b[37] - b[15] * b[6] * b[34] + b[15] * b[30] * b[10] +
|
| 84 |
+
b[15] * b[32] * b[8] - b[16] * b[4] * b[35] - b[13] * b[6] * b[36] -
|
| 85 |
+
b[13] * b[7] * b[35] + b[13] * b[31] * b[11] + b[13] * b[30] * b[12] +
|
| 86 |
+
b[14] * b[32] * b[9] + b[14] * b[33] * b[8] - b[14] * b[4] * b[37] -
|
| 87 |
+
b[14] * b[5] * b[36] + b[16] * b[30] * b[9] + b[16] * b[31] * b[8] -
|
| 88 |
+
b[26] * b[20] * b[9] + b[26] * b[4] * b[25] + b[26] * b[5] * b[24] +
|
| 89 |
+
b[26] * b[6] * b[23] + b[26] * b[7] * b[22] - b[26] * b[17] * b[12] +
|
| 90 |
+
b[14] * b[30] * b[11] + b[14] * b[31] * b[10] + b[15] * b[31] * b[9] -
|
| 91 |
+
b[15] * b[4] * b[36] - b[15] * b[5] * b[35] - b[26] * b[18] * b[11] -
|
| 92 |
+
b[26] * b[19] * b[10] - b[27] * b[20] * b[8] + b[27] * b[4] * b[24] +
|
| 93 |
+
b[27] * b[5] * b[23] + b[27] * b[6] * b[22] + b[27] * b[7] * b[21] -
|
| 94 |
+
b[27] * b[17] * b[11] - b[27] * b[18] * b[10] - b[27] * b[19] * b[9] -
|
| 95 |
+
b[16] * b[5] * b[34] - b[29] * b[17] * b[9] - b[29] * b[18] * b[8] +
|
| 96 |
+
b[28] * b[4] * b[23] + b[28] * b[5] * b[22] + b[28] * b[6] * b[21] -
|
| 97 |
+
b[28] * b[17] * b[10] - b[28] * b[18] * b[9] - b[28] * b[19] * b[8] +
|
| 98 |
+
b[29] * b[4] * b[22] + b[29] * b[5] * b[21] - b[2] * b[23] * b[30] +
|
| 99 |
+
b[2] * b[18] * b[35] - b[1] * b[22] * b[32] - b[2] * b[21] * b[32] +
|
| 100 |
+
b[2] * b[19] * b[34] + b[0] * b[19] * b[36] - b[0] * b[22] * b[33] +
|
| 101 |
+
b[0] * b[20] * b[35] - b[0] * b[23] * b[32] - b[0] * b[25] * b[30] +
|
| 102 |
+
b[0] * b[17] * b[38] + b[0] * b[18] * b[37] - b[0] * b[24] * b[31] +
|
| 103 |
+
b[1] * b[17] * b[37] - b[1] * b[23] * b[31] - b[1] * b[24] * b[30] -
|
| 104 |
+
b[1] * b[21] * b[33] + b[1] * b[20] * b[34] + b[1] * b[19] * b[35] +
|
| 105 |
+
b[1] * b[18] * b[36] + b[2] * b[17] * b[36] - b[2] * b[22] * b[31];
|
| 106 |
+
coeffs(5) =
|
| 107 |
+
-b[14] * b[6] * b[36] - b[14] * b[7] * b[35] + b[14] * b[31] * b[11] -
|
| 108 |
+
b[3] * b[23] * b[30] - b[3] * b[21] * b[32] + b[3] * b[18] * b[35] -
|
| 109 |
+
b[3] * b[22] * b[31] + b[3] * b[17] * b[36] + b[3] * b[19] * b[34] +
|
| 110 |
+
b[13] * b[32] * b[11] + b[13] * b[33] * b[10] - b[13] * b[5] * b[38] -
|
| 111 |
+
b[15] * b[6] * b[35] - b[15] * b[7] * b[34] + b[15] * b[30] * b[11] +
|
| 112 |
+
b[15] * b[31] * b[10] + b[16] * b[31] * b[9] - b[13] * b[6] * b[37] -
|
| 113 |
+
b[13] * b[7] * b[36] + b[13] * b[31] * b[12] + b[14] * b[32] * b[10] +
|
| 114 |
+
b[14] * b[33] * b[9] - b[14] * b[4] * b[38] - b[14] * b[5] * b[37] -
|
| 115 |
+
b[16] * b[6] * b[34] + b[16] * b[30] * b[10] + b[16] * b[32] * b[8] -
|
| 116 |
+
b[26] * b[20] * b[10] + b[26] * b[5] * b[25] + b[26] * b[6] * b[24] +
|
| 117 |
+
b[26] * b[7] * b[23] + b[14] * b[30] * b[12] + b[15] * b[32] * b[9] +
|
| 118 |
+
b[15] * b[33] * b[8] - b[15] * b[4] * b[37] - b[15] * b[5] * b[36] +
|
| 119 |
+
b[29] * b[5] * b[22] + b[29] * b[6] * b[21] - b[26] * b[18] * b[12] -
|
| 120 |
+
b[26] * b[19] * b[11] - b[27] * b[20] * b[9] + b[27] * b[4] * b[25] +
|
| 121 |
+
b[27] * b[5] * b[24] + b[27] * b[6] * b[23] + b[27] * b[7] * b[22] -
|
| 122 |
+
b[27] * b[17] * b[12] - b[27] * b[18] * b[11] - b[27] * b[19] * b[10] -
|
| 123 |
+
b[28] * b[20] * b[8] - b[16] * b[4] * b[36] - b[16] * b[5] * b[35] -
|
| 124 |
+
b[29] * b[17] * b[10] - b[29] * b[18] * b[9] - b[29] * b[19] * b[8] +
|
| 125 |
+
b[28] * b[4] * b[24] + b[28] * b[5] * b[23] + b[28] * b[6] * b[22] +
|
| 126 |
+
b[28] * b[7] * b[21] - b[28] * b[17] * b[11] - b[28] * b[18] * b[10] -
|
| 127 |
+
b[28] * b[19] * b[9] + b[29] * b[4] * b[23] - b[2] * b[22] * b[32] -
|
| 128 |
+
b[2] * b[21] * b[33] - b[1] * b[24] * b[31] + b[0] * b[18] * b[38] -
|
| 129 |
+
b[0] * b[24] * b[32] + b[0] * b[19] * b[37] + b[0] * b[20] * b[36] -
|
| 130 |
+
b[0] * b[25] * b[31] - b[0] * b[23] * b[33] + b[1] * b[19] * b[36] -
|
| 131 |
+
b[1] * b[22] * b[33] + b[1] * b[20] * b[35] + b[2] * b[19] * b[35] -
|
| 132 |
+
b[2] * b[24] * b[30] - b[2] * b[23] * b[31] + b[2] * b[20] * b[34] +
|
| 133 |
+
b[2] * b[17] * b[37] - b[1] * b[25] * b[30] + b[1] * b[18] * b[37] +
|
| 134 |
+
b[1] * b[17] * b[38] - b[1] * b[23] * b[32] + b[2] * b[18] * b[36];
|
| 135 |
+
coeffs(6) =
|
| 136 |
+
-b[14] * b[6] * b[37] - b[14] * b[7] * b[36] + b[14] * b[31] * b[12] +
|
| 137 |
+
b[3] * b[17] * b[37] - b[3] * b[23] * b[31] - b[3] * b[24] * b[30] -
|
| 138 |
+
b[3] * b[21] * b[33] + b[3] * b[20] * b[34] + b[3] * b[19] * b[35] +
|
| 139 |
+
b[3] * b[18] * b[36] - b[3] * b[22] * b[32] + b[13] * b[32] * b[12] +
|
| 140 |
+
b[13] * b[33] * b[11] - b[15] * b[6] * b[36] - b[15] * b[7] * b[35] +
|
| 141 |
+
b[15] * b[31] * b[11] + b[15] * b[30] * b[12] + b[16] * b[32] * b[9] +
|
| 142 |
+
b[16] * b[33] * b[8] - b[13] * b[6] * b[38] - b[13] * b[7] * b[37] +
|
| 143 |
+
b[14] * b[32] * b[11] + b[14] * b[33] * b[10] - b[14] * b[5] * b[38] -
|
| 144 |
+
b[16] * b[6] * b[35] - b[16] * b[7] * b[34] + b[16] * b[30] * b[11] +
|
| 145 |
+
b[16] * b[31] * b[10] - b[26] * b[19] * b[12] - b[26] * b[20] * b[11] +
|
| 146 |
+
b[26] * b[6] * b[25] + b[26] * b[7] * b[24] + b[15] * b[32] * b[10] +
|
| 147 |
+
b[15] * b[33] * b[9] - b[15] * b[4] * b[38] - b[15] * b[5] * b[37] +
|
| 148 |
+
b[29] * b[5] * b[23] + b[29] * b[6] * b[22] + b[29] * b[7] * b[21] -
|
| 149 |
+
b[27] * b[20] * b[10] + b[27] * b[5] * b[25] + b[27] * b[6] * b[24] +
|
| 150 |
+
b[27] * b[7] * b[23] - b[27] * b[18] * b[12] - b[27] * b[19] * b[11] -
|
| 151 |
+
b[28] * b[20] * b[9] - b[16] * b[4] * b[37] - b[16] * b[5] * b[36] +
|
| 152 |
+
b[0] * b[19] * b[38] - b[0] * b[24] * b[33] + b[0] * b[20] * b[37] -
|
| 153 |
+
b[29] * b[17] * b[11] - b[29] * b[18] * b[10] - b[29] * b[19] * b[9] +
|
| 154 |
+
b[28] * b[4] * b[25] + b[28] * b[5] * b[24] + b[28] * b[6] * b[23] +
|
| 155 |
+
b[28] * b[7] * b[22] - b[28] * b[17] * b[12] - b[28] * b[18] * b[11] -
|
| 156 |
+
b[28] * b[19] * b[10] - b[29] * b[20] * b[8] + b[29] * b[4] * b[24] +
|
| 157 |
+
b[2] * b[18] * b[37] - b[0] * b[25] * b[32] + b[1] * b[18] * b[38] -
|
| 158 |
+
b[1] * b[24] * b[32] + b[1] * b[19] * b[37] + b[1] * b[20] * b[36] -
|
| 159 |
+
b[1] * b[25] * b[31] + b[2] * b[17] * b[38] + b[2] * b[19] * b[36] -
|
| 160 |
+
b[2] * b[24] * b[31] - b[2] * b[22] * b[33] - b[2] * b[23] * b[32] +
|
| 161 |
+
b[2] * b[20] * b[35] - b[1] * b[23] * b[33] - b[2] * b[25] * b[30];
|
| 162 |
+
coeffs(7) =
|
| 163 |
+
-b[14] * b[6] * b[38] - b[14] * b[7] * b[37] + b[3] * b[19] * b[36] -
|
| 164 |
+
b[3] * b[22] * b[33] + b[3] * b[20] * b[35] - b[3] * b[23] * b[32] -
|
| 165 |
+
b[3] * b[25] * b[30] + b[3] * b[17] * b[38] + b[3] * b[18] * b[37] -
|
| 166 |
+
b[3] * b[24] * b[31] - b[15] * b[6] * b[37] - b[15] * b[7] * b[36] +
|
| 167 |
+
b[15] * b[31] * b[12] + b[16] * b[32] * b[10] + b[16] * b[33] * b[9] +
|
| 168 |
+
b[13] * b[33] * b[12] - b[13] * b[7] * b[38] + b[14] * b[32] * b[12] +
|
| 169 |
+
b[14] * b[33] * b[11] - b[16] * b[6] * b[36] - b[16] * b[7] * b[35] +
|
| 170 |
+
b[16] * b[31] * b[11] + b[16] * b[30] * b[12] + b[15] * b[32] * b[11] +
|
| 171 |
+
b[15] * b[33] * b[10] - b[15] * b[5] * b[38] + b[29] * b[5] * b[24] +
|
| 172 |
+
b[29] * b[6] * b[23] - b[26] * b[20] * b[12] + b[26] * b[7] * b[25] -
|
| 173 |
+
b[27] * b[19] * b[12] - b[27] * b[20] * b[11] + b[27] * b[6] * b[25] +
|
| 174 |
+
b[27] * b[7] * b[24] - b[28] * b[20] * b[10] - b[16] * b[4] * b[38] -
|
| 175 |
+
b[16] * b[5] * b[37] + b[29] * b[7] * b[22] - b[29] * b[17] * b[12] -
|
| 176 |
+
b[29] * b[18] * b[11] - b[29] * b[19] * b[10] + b[28] * b[5] * b[25] +
|
| 177 |
+
b[28] * b[6] * b[24] + b[28] * b[7] * b[23] - b[28] * b[18] * b[12] -
|
| 178 |
+
b[28] * b[19] * b[11] - b[29] * b[20] * b[9] + b[29] * b[4] * b[25] -
|
| 179 |
+
b[2] * b[24] * b[32] + b[0] * b[20] * b[38] - b[0] * b[25] * b[33] +
|
| 180 |
+
b[1] * b[19] * b[38] - b[1] * b[24] * b[33] + b[1] * b[20] * b[37] -
|
| 181 |
+
b[2] * b[25] * b[31] + b[2] * b[20] * b[36] - b[1] * b[25] * b[32] +
|
| 182 |
+
b[2] * b[19] * b[37] + b[2] * b[18] * b[38] - b[2] * b[23] * b[33];
|
| 183 |
+
coeffs(8) =
|
| 184 |
+
b[3] * b[18] * b[38] - b[3] * b[24] * b[32] + b[3] * b[19] * b[37] +
|
| 185 |
+
b[3] * b[20] * b[36] - b[3] * b[25] * b[31] - b[3] * b[23] * b[33] -
|
| 186 |
+
b[15] * b[6] * b[38] - b[15] * b[7] * b[37] + b[16] * b[32] * b[11] +
|
| 187 |
+
b[16] * b[33] * b[10] - b[16] * b[5] * b[38] - b[16] * b[6] * b[37] -
|
| 188 |
+
b[16] * b[7] * b[36] + b[16] * b[31] * b[12] + b[14] * b[33] * b[12] -
|
| 189 |
+
b[14] * b[7] * b[38] + b[15] * b[32] * b[12] + b[15] * b[33] * b[11] +
|
| 190 |
+
b[29] * b[5] * b[25] + b[29] * b[6] * b[24] - b[27] * b[20] * b[12] +
|
| 191 |
+
b[27] * b[7] * b[25] - b[28] * b[19] * b[12] - b[28] * b[20] * b[11] +
|
| 192 |
+
b[29] * b[7] * b[23] - b[29] * b[18] * b[12] - b[29] * b[19] * b[11] +
|
| 193 |
+
b[28] * b[6] * b[25] + b[28] * b[7] * b[24] - b[29] * b[20] * b[10] +
|
| 194 |
+
b[2] * b[19] * b[38] - b[1] * b[25] * b[33] + b[2] * b[20] * b[37] -
|
| 195 |
+
b[2] * b[24] * b[33] - b[2] * b[25] * b[32] + b[1] * b[20] * b[38];
|
| 196 |
+
coeffs(9) =
|
| 197 |
+
b[29] * b[7] * b[24] - b[29] * b[20] * b[11] + b[2] * b[20] * b[38] -
|
| 198 |
+
b[2] * b[25] * b[33] - b[28] * b[20] * b[12] + b[28] * b[7] * b[25] -
|
| 199 |
+
b[29] * b[19] * b[12] - b[3] * b[24] * b[33] + b[15] * b[33] * b[12] +
|
| 200 |
+
b[3] * b[19] * b[38] - b[16] * b[6] * b[38] + b[3] * b[20] * b[37] +
|
| 201 |
+
b[16] * b[32] * b[12] + b[29] * b[6] * b[25] - b[16] * b[7] * b[37] -
|
| 202 |
+
b[3] * b[25] * b[32] - b[15] * b[7] * b[38] + b[16] * b[33] * b[11];
|
| 203 |
+
coeffs(10) = -b[29] * b[20] * b[12] + b[29] * b[7] * b[25] +
|
| 204 |
+
b[16] * b[33] * b[12] - b[16] * b[7] * b[38] +
|
| 205 |
+
b[3] * b[20] * b[38] - b[3] * b[25] * b[33];
|
| 206 |
+
}
|
colmap/include/colmap/estimators/essential_matrix_poly.h
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
colmap/include/colmap/estimators/euclidean_transform.h
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_ESTIMATORS_EUCLIDEAN_TRANSFORM_H_
|
| 33 |
+
#define COLMAP_SRC_ESTIMATORS_EUCLIDEAN_TRANSFORM_H_
|
| 34 |
+
|
| 35 |
+
#include "base/similarity_transform.h"
|
| 36 |
+
#include "util/alignment.h"
|
| 37 |
+
|
| 38 |
+
namespace colmap {
|
| 39 |
+
|
| 40 |
+
// N-D Euclidean transform estimator from corresponding point pairs in the
|
| 41 |
+
// source and destination coordinate systems.
|
| 42 |
+
//
|
| 43 |
+
// This algorithm is based on the following paper:
|
| 44 |
+
//
|
| 45 |
+
// S. Umeyama. Least-Squares Estimation of Transformation Parameters
|
| 46 |
+
// Between Two Point Patterns. IEEE Transactions on Pattern Analysis and
|
| 47 |
+
// Machine Intelligence, Volume 13 Issue 4, Page 376-380, 1991.
|
| 48 |
+
// http://www.stanford.edu/class/cs273/refs/umeyama.pdf
|
| 49 |
+
//
|
| 50 |
+
// and uses the Eigen implementation.
|
| 51 |
+
template <int kDim>
|
| 52 |
+
using EuclideanTransformEstimator = SimilarityTransformEstimator<kDim, false>;
|
| 53 |
+
|
| 54 |
+
} // namespace colmap
|
| 55 |
+
|
| 56 |
+
#endif // COLMAP_SRC_ESTIMATORS_EUCLIDEAN_TRANSFORM_H_
|
colmap/include/colmap/estimators/fundamental_matrix.h
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_ESTIMATORS_FUNDAMENTAL_MATRIX_H_
|
| 33 |
+
#define COLMAP_SRC_ESTIMATORS_FUNDAMENTAL_MATRIX_H_
|
| 34 |
+
|
| 35 |
+
#include <vector>
|
| 36 |
+
|
| 37 |
+
#include <Eigen/Core>
|
| 38 |
+
|
| 39 |
+
#include "estimators/homography_matrix.h"
|
| 40 |
+
#include "util/alignment.h"
|
| 41 |
+
#include "util/types.h"
|
| 42 |
+
|
| 43 |
+
namespace colmap {
|
| 44 |
+
|
| 45 |
+
// Fundamental matrix estimator from corresponding point pairs.
|
| 46 |
+
//
|
| 47 |
+
// This algorithm solves the 7-Point problem and is based on the following
|
| 48 |
+
// paper:
|
| 49 |
+
//
|
| 50 |
+
// Zhengyou Zhang and T. Kanade, Determining the Epipolar Geometry and its
|
| 51 |
+
// Uncertainty: A Review, International Journal of Computer Vision, 1998.
|
| 52 |
+
// http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.33.4540
|
| 53 |
+
class FundamentalMatrixSevenPointEstimator {
|
| 54 |
+
public:
|
| 55 |
+
typedef Eigen::Vector2d X_t;
|
| 56 |
+
typedef Eigen::Vector2d Y_t;
|
| 57 |
+
typedef Eigen::Matrix3d M_t;
|
| 58 |
+
|
| 59 |
+
// The minimum number of samples needed to estimate a model.
|
| 60 |
+
static const int kMinNumSamples = 7;
|
| 61 |
+
|
| 62 |
+
// Estimate either 1 or 3 possible fundamental matrix solutions from a set of
|
| 63 |
+
// corresponding points.
|
| 64 |
+
//
|
| 65 |
+
// The number of corresponding points must be exactly 7.
|
| 66 |
+
//
|
| 67 |
+
// @param points1 First set of corresponding points.
|
| 68 |
+
// @param points2 Second set of corresponding points
|
| 69 |
+
//
|
| 70 |
+
// @return Up to 4 solutions as a vector of 3x3 fundamental matrices.
|
| 71 |
+
static std::vector<M_t> Estimate(const std::vector<X_t>& points1,
|
| 72 |
+
const std::vector<Y_t>& points2);
|
| 73 |
+
|
| 74 |
+
// Calculate the residuals of a set of corresponding points and a given
|
| 75 |
+
// fundamental matrix.
|
| 76 |
+
//
|
| 77 |
+
// Residuals are defined as the squared Sampson error.
|
| 78 |
+
//
|
| 79 |
+
// @param points1 First set of corresponding points as Nx2 matrix.
|
| 80 |
+
// @param points2 Second set of corresponding points as Nx2 matrix.
|
| 81 |
+
// @param F 3x3 fundamental matrix.
|
| 82 |
+
// @param residuals Output vector of residuals.
|
| 83 |
+
static void Residuals(const std::vector<X_t>& points1,
|
| 84 |
+
const std::vector<Y_t>& points2, const M_t& F,
|
| 85 |
+
std::vector<double>* residuals);
|
| 86 |
+
};
|
| 87 |
+
|
| 88 |
+
// Fundamental matrix estimator from corresponding point pairs.
|
| 89 |
+
//
|
| 90 |
+
// This algorithm solves the 8-Point problem based on the following paper:
|
| 91 |
+
//
|
| 92 |
+
// Hartley and Zisserman, Multiple View Geometry, algorithm 11.1, page 282.
|
| 93 |
+
class FundamentalMatrixEightPointEstimator {
|
| 94 |
+
public:
|
| 95 |
+
typedef Eigen::Vector2d X_t;
|
| 96 |
+
typedef Eigen::Vector2d Y_t;
|
| 97 |
+
typedef Eigen::Matrix3d M_t;
|
| 98 |
+
|
| 99 |
+
// The minimum number of samples needed to estimate a model.
|
| 100 |
+
static const int kMinNumSamples = 8;
|
| 101 |
+
|
| 102 |
+
// Estimate fundamental matrix solutions from a set of corresponding points.
|
| 103 |
+
//
|
| 104 |
+
// The number of corresponding points must be at least 8.
|
| 105 |
+
//
|
| 106 |
+
// @param points1 First set of corresponding points.
|
| 107 |
+
// @param points2 Second set of corresponding points
|
| 108 |
+
//
|
| 109 |
+
// @return Single solution as a vector of 3x3 fundamental matrices.
|
| 110 |
+
static std::vector<M_t> Estimate(const std::vector<X_t>& points1,
|
| 111 |
+
const std::vector<Y_t>& points2);
|
| 112 |
+
|
| 113 |
+
// Calculate the residuals of a set of corresponding points and a given
|
| 114 |
+
// fundamental matrix.
|
| 115 |
+
//
|
| 116 |
+
// Residuals are defined as the squared Sampson error.
|
| 117 |
+
//
|
| 118 |
+
// @param points1 First set of corresponding points as Nx2 matrix.
|
| 119 |
+
// @param points2 Second set of corresponding points as Nx2 matrix.
|
| 120 |
+
// @param F 3x3 fundamental matrix.
|
| 121 |
+
// @param residuals Output vector of residuals.
|
| 122 |
+
static void Residuals(const std::vector<X_t>& points1,
|
| 123 |
+
const std::vector<Y_t>& points2, const M_t& F,
|
| 124 |
+
std::vector<double>* residuals);
|
| 125 |
+
};
|
| 126 |
+
|
| 127 |
+
} // namespace colmap
|
| 128 |
+
|
| 129 |
+
#endif // COLMAP_SRC_ESTIMATORS_FUNDAMENTAL_MATRIX_H_
|
colmap/include/colmap/estimators/generalized_absolute_pose.h
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_ESTIMATORS_GENERALIZED_ABSOLUTE_POSE_H_
|
| 33 |
+
#define COLMAP_SRC_ESTIMATORS_GENERALIZED_ABSOLUTE_POSE_H_
|
| 34 |
+
|
| 35 |
+
#include <vector>
|
| 36 |
+
|
| 37 |
+
#include <Eigen/Core>
|
| 38 |
+
|
| 39 |
+
#include "util/alignment.h"
|
| 40 |
+
#include "util/types.h"
|
| 41 |
+
|
| 42 |
+
namespace colmap {
|
| 43 |
+
|
| 44 |
+
// Solver for the Generalized P3P problem (NP3P or GP3P), based on:
|
| 45 |
+
//
|
| 46 |
+
// Lee, Gim Hee, et al. "Minimal solutions for pose estimation of a
|
| 47 |
+
// multi-camera system." Robotics Research. Springer International
|
| 48 |
+
// Publishing, 2016. 521-538.
|
| 49 |
+
//
|
| 50 |
+
// This class is based on an original implementation by Federico Camposeco.
|
| 51 |
+
class GP3PEstimator {
|
| 52 |
+
public:
|
| 53 |
+
// The generalized image observations, which is composed of the relative pose
|
| 54 |
+
// of the specific camera in the generalized camera and its image observation.
|
| 55 |
+
struct X_t {
|
| 56 |
+
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
| 57 |
+
// The relative transformation from the generalized camera to the camera
|
| 58 |
+
// frame of the observation.
|
| 59 |
+
Eigen::Matrix3x4d rel_tform;
|
| 60 |
+
// The 2D image feature observation.
|
| 61 |
+
Eigen::Vector2d xy;
|
| 62 |
+
};
|
| 63 |
+
|
| 64 |
+
// The observed 3D feature points in the world frame.
|
| 65 |
+
typedef Eigen::Vector3d Y_t;
|
| 66 |
+
// The transformation from the world to the generalized camera frame.
|
| 67 |
+
typedef Eigen::Matrix3x4d M_t;
|
| 68 |
+
|
| 69 |
+
// The minimum number of samples needed to estimate a model.
|
| 70 |
+
static const int kMinNumSamples = 3;
|
| 71 |
+
|
| 72 |
+
enum class ResidualType {
|
| 73 |
+
CosineDistance,
|
| 74 |
+
ReprojectionError,
|
| 75 |
+
};
|
| 76 |
+
|
| 77 |
+
// Whether to compute the cosine similarity or the reprojection error.
|
| 78 |
+
// [WARNING] The reprojection error being in normalized coordinates,
|
| 79 |
+
// the unique error threshold of RANSAC corresponds to different pixel values
|
| 80 |
+
// in the different cameras of the rig if they have different intrinsics.
|
| 81 |
+
ResidualType residual_type = ResidualType::CosineDistance;
|
| 82 |
+
|
| 83 |
+
// Estimate the most probable solution of the GP3P problem from a set of
|
| 84 |
+
// three 2D-3D point correspondences.
|
| 85 |
+
static std::vector<M_t> Estimate(const std::vector<X_t>& points2D,
|
| 86 |
+
const std::vector<Y_t>& points3D);
|
| 87 |
+
|
| 88 |
+
// Calculate the squared cosine distance error between the rays given a set of
|
| 89 |
+
// 2D-3D point correspondences and a projection matrix of the generalized
|
| 90 |
+
// camera.
|
| 91 |
+
void Residuals(const std::vector<X_t>& points2D,
|
| 92 |
+
const std::vector<Y_t>& points3D,
|
| 93 |
+
const M_t& proj_matrix, std::vector<double>* residuals);
|
| 94 |
+
};
|
| 95 |
+
|
| 96 |
+
} // namespace colmap
|
| 97 |
+
|
| 98 |
+
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION_CUSTOM(colmap::GP3PEstimator::X_t)
|
| 99 |
+
|
| 100 |
+
#endif // COLMAP_SRC_ESTIMATORS_GENERALIZED_ABSOLUTE_POSE_H_
|
colmap/include/colmap/estimators/generalized_absolute_pose_coeffs.h
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_ESTIMATORS_GENERALIZED_ABSOLUTE_POSE_COEFFS_H_
|
| 33 |
+
#define COLMAP_SRC_ESTIMATORS_GENERALIZED_ABSOLUTE_POSE_COEFFS_H_
|
| 34 |
+
|
| 35 |
+
#include <Eigen/Core>
|
| 36 |
+
|
| 37 |
+
namespace colmap {
|
| 38 |
+
|
| 39 |
+
Eigen::Matrix<double, 9, 1> ComputeDepthsSylvesterCoeffs(
|
| 40 |
+
const Eigen::Matrix<double, 3, 6>& K);
|
| 41 |
+
|
| 42 |
+
} // namespace colmap
|
| 43 |
+
|
| 44 |
+
#endif // COLMAP_SRC_ESTIMATORS_GENERALIZED_ABSOLUTE_POSE_COEFFS_H_
|
colmap/include/colmap/estimators/generalized_relative_pose.h
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_ESTIMATORS_GENERALIZED_RELATIVE_POSE_H_
|
| 33 |
+
#define COLMAP_SRC_ESTIMATORS_GENERALIZED_RELATIVE_POSE_H_
|
| 34 |
+
|
| 35 |
+
#include <vector>
|
| 36 |
+
|
| 37 |
+
#include <Eigen/Core>
|
| 38 |
+
|
| 39 |
+
#include "util/alignment.h"
|
| 40 |
+
#include "util/types.h"
|
| 41 |
+
|
| 42 |
+
namespace colmap {
|
| 43 |
+
|
| 44 |
+
// Solver for the Generalized Relative Pose problem using a minimal of 8 2D-2D
|
| 45 |
+
// correspondences. This implementation is based on:
|
| 46 |
+
//
|
| 47 |
+
// "Efficient Computation of Relative Pose for Multi-Camera Systems",
|
| 48 |
+
// Kneip and Li. CVPR 2014.
|
| 49 |
+
//
|
| 50 |
+
// Note that the solution to this problem is degenerate in the case of pure
|
| 51 |
+
// translation and when all correspondences are observed from the same cameras.
|
| 52 |
+
//
|
| 53 |
+
// The implementation is a modified and improved version of Kneip's original
|
| 54 |
+
// implementation in OpenGV licensed under the BSD license.
|
| 55 |
+
class GR6PEstimator {
|
| 56 |
+
public:
|
| 57 |
+
// The generalized image observations of the left camera, which is composed of
|
| 58 |
+
// the relative pose of the specific camera in the generalized camera and its
|
| 59 |
+
// image observation.
|
| 60 |
+
struct X_t {
|
| 61 |
+
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
| 62 |
+
// The relative transformation from the generalized camera to the camera
|
| 63 |
+
// frame of the observation.
|
| 64 |
+
Eigen::Matrix3x4d rel_tform;
|
| 65 |
+
// The 2D image feature observation.
|
| 66 |
+
Eigen::Vector2d xy;
|
| 67 |
+
};
|
| 68 |
+
|
| 69 |
+
// The normalized image feature points in the left camera.
|
| 70 |
+
typedef X_t Y_t;
|
| 71 |
+
// The relative transformation between the two generalized cameras.
|
| 72 |
+
typedef Eigen::Matrix3x4d M_t;
|
| 73 |
+
|
| 74 |
+
// The minimum number of samples needed to estimate a model. Note that in
|
| 75 |
+
// theory the minimum required number of samples is 6 but Laurent Kneip showed
|
| 76 |
+
// in his paper that using 8 samples is more stable.
|
| 77 |
+
static const int kMinNumSamples = 8;
|
| 78 |
+
|
| 79 |
+
// Estimate the most probable solution of the GR6P problem from a set of
|
| 80 |
+
// six 2D-2D point correspondences.
|
| 81 |
+
static std::vector<M_t> Estimate(const std::vector<X_t>& points1,
|
| 82 |
+
const std::vector<Y_t>& points2);
|
| 83 |
+
|
| 84 |
+
// Calculate the squared Sampson error between corresponding points.
|
| 85 |
+
static void Residuals(const std::vector<X_t>& points1,
|
| 86 |
+
const std::vector<Y_t>& points2, const M_t& proj_matrix,
|
| 87 |
+
std::vector<double>* residuals);
|
| 88 |
+
};
|
| 89 |
+
|
| 90 |
+
} // namespace colmap
|
| 91 |
+
|
| 92 |
+
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION_CUSTOM(colmap::GR6PEstimator::X_t)
|
| 93 |
+
|
| 94 |
+
#endif // COLMAP_SRC_ESTIMATORS_GENERALIZED_RELATIVE_POSE_H_
|
colmap/include/colmap/estimators/homography_matrix.h
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_ESTIMATORS_HOMOGRAPHY_MATRIX_H_
|
| 33 |
+
#define COLMAP_SRC_ESTIMATORS_HOMOGRAPHY_MATRIX_H_
|
| 34 |
+
|
| 35 |
+
#include <vector>
|
| 36 |
+
|
| 37 |
+
#include <Eigen/Core>
|
| 38 |
+
|
| 39 |
+
#include "util/alignment.h"
|
| 40 |
+
#include "util/types.h"
|
| 41 |
+
|
| 42 |
+
namespace colmap {
|
| 43 |
+
|
| 44 |
+
// Direct linear transformation algorithm to compute the homography between
|
| 45 |
+
// point pairs. This algorithm computes the least squares estimate for
|
| 46 |
+
// the homography from at least 4 correspondences.
|
| 47 |
+
class HomographyMatrixEstimator {
|
| 48 |
+
public:
|
| 49 |
+
typedef Eigen::Vector2d X_t;
|
| 50 |
+
typedef Eigen::Vector2d Y_t;
|
| 51 |
+
typedef Eigen::Matrix3d M_t;
|
| 52 |
+
|
| 53 |
+
// The minimum number of samples needed to estimate a model.
|
| 54 |
+
static const int kMinNumSamples = 4;
|
| 55 |
+
|
| 56 |
+
// Estimate the projective transformation (homography).
|
| 57 |
+
//
|
| 58 |
+
// The number of corresponding points must be at least 4.
|
| 59 |
+
//
|
| 60 |
+
// @param points1 First set of corresponding points.
|
| 61 |
+
// @param points2 Second set of corresponding points.
|
| 62 |
+
//
|
| 63 |
+
// @return 3x3 homogeneous transformation matrix.
|
| 64 |
+
static std::vector<M_t> Estimate(const std::vector<X_t>& points1,
|
| 65 |
+
const std::vector<Y_t>& points2);
|
| 66 |
+
|
| 67 |
+
// Calculate the transformation error for each corresponding point pair.
|
| 68 |
+
//
|
| 69 |
+
// Residuals are defined as the squared transformation error when
|
| 70 |
+
// transforming the source to the destination coordinates.
|
| 71 |
+
//
|
| 72 |
+
// @param points1 First set of corresponding points.
|
| 73 |
+
// @param points2 Second set of corresponding points.
|
| 74 |
+
// @param H 3x3 projective matrix.
|
| 75 |
+
// @param residuals Output vector of residuals.
|
| 76 |
+
static void Residuals(const std::vector<X_t>& points1,
|
| 77 |
+
const std::vector<Y_t>& points2, const M_t& H,
|
| 78 |
+
std::vector<double>* residuals);
|
| 79 |
+
};
|
| 80 |
+
|
| 81 |
+
} // namespace colmap
|
| 82 |
+
|
| 83 |
+
#endif // COLMAP_SRC_ESTIMATORS_HOMOGRAPHY_MATRIX_H_
|
colmap/include/colmap/estimators/pose.h
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_ESTIMATORS_POSE_H_
|
| 33 |
+
#define COLMAP_SRC_ESTIMATORS_POSE_H_
|
| 34 |
+
|
| 35 |
+
#include <vector>
|
| 36 |
+
|
| 37 |
+
#include <Eigen/Core>
|
| 38 |
+
|
| 39 |
+
#include <ceres/ceres.h>
|
| 40 |
+
|
| 41 |
+
#include "base/camera.h"
|
| 42 |
+
#include "base/camera_models.h"
|
| 43 |
+
#include "optim/loransac.h"
|
| 44 |
+
#include "util/alignment.h"
|
| 45 |
+
#include "util/logging.h"
|
| 46 |
+
#include "util/threading.h"
|
| 47 |
+
#include "util/types.h"
|
| 48 |
+
|
| 49 |
+
namespace colmap {
|
| 50 |
+
|
| 51 |
+
struct AbsolutePoseEstimationOptions {
|
| 52 |
+
// Whether to estimate the focal length.
|
| 53 |
+
bool estimate_focal_length = false;
|
| 54 |
+
|
| 55 |
+
// Number of discrete samples for focal length estimation.
|
| 56 |
+
size_t num_focal_length_samples = 30;
|
| 57 |
+
|
| 58 |
+
// Minimum focal length ratio for discrete focal length sampling
|
| 59 |
+
// around focal length of given camera.
|
| 60 |
+
double min_focal_length_ratio = 0.2;
|
| 61 |
+
|
| 62 |
+
// Maximum focal length ratio for discrete focal length sampling
|
| 63 |
+
// around focal length of given camera.
|
| 64 |
+
double max_focal_length_ratio = 5;
|
| 65 |
+
|
| 66 |
+
// Number of threads for parallel estimation of focal length.
|
| 67 |
+
int num_threads = ThreadPool::kMaxNumThreads;
|
| 68 |
+
|
| 69 |
+
// Options used for P3P RANSAC.
|
| 70 |
+
RANSACOptions ransac_options;
|
| 71 |
+
|
| 72 |
+
void Check() const {
|
| 73 |
+
CHECK_GT(num_focal_length_samples, 0);
|
| 74 |
+
CHECK_GT(min_focal_length_ratio, 0);
|
| 75 |
+
CHECK_GT(max_focal_length_ratio, 0);
|
| 76 |
+
CHECK_LT(min_focal_length_ratio, max_focal_length_ratio);
|
| 77 |
+
ransac_options.Check();
|
| 78 |
+
}
|
| 79 |
+
};
|
| 80 |
+
|
| 81 |
+
struct AbsolutePoseRefinementOptions {
|
| 82 |
+
// Convergence criterion.
|
| 83 |
+
double gradient_tolerance = 1.0;
|
| 84 |
+
|
| 85 |
+
// Maximum number of solver iterations.
|
| 86 |
+
int max_num_iterations = 100;
|
| 87 |
+
|
| 88 |
+
// Scaling factor determines at which residual robustification takes place.
|
| 89 |
+
double loss_function_scale = 1.0;
|
| 90 |
+
|
| 91 |
+
// Whether to refine the focal length parameter group.
|
| 92 |
+
bool refine_focal_length = true;
|
| 93 |
+
|
| 94 |
+
// Whether to refine the extra parameter group.
|
| 95 |
+
bool refine_extra_params = true;
|
| 96 |
+
|
| 97 |
+
// Whether to print final summary.
|
| 98 |
+
bool print_summary = true;
|
| 99 |
+
|
| 100 |
+
void Check() const {
|
| 101 |
+
CHECK_GE(gradient_tolerance, 0.0);
|
| 102 |
+
CHECK_GE(max_num_iterations, 0);
|
| 103 |
+
CHECK_GE(loss_function_scale, 0.0);
|
| 104 |
+
}
|
| 105 |
+
};
|
| 106 |
+
|
| 107 |
+
// Estimate absolute pose (optionally focal length) from 2D-3D correspondences.
|
| 108 |
+
//
|
| 109 |
+
// Focal length estimation is performed using discrete sampling around the
|
| 110 |
+
// focal length of the given camera. The focal length that results in the
|
| 111 |
+
// maximal number of inliers is assigned to the given camera.
|
| 112 |
+
//
|
| 113 |
+
// @param options Absolute pose estimation options.
|
| 114 |
+
// @param points2D Corresponding 2D points.
|
| 115 |
+
// @param points3D Corresponding 3D points.
|
| 116 |
+
// @param qvec Estimated rotation component as
|
| 117 |
+
// unit Quaternion coefficients (w, x, y, z).
|
| 118 |
+
// @param tvec Estimated translation component.
|
| 119 |
+
// @param camera Camera for which to estimate pose. Modified
|
| 120 |
+
// in-place to store the estimated focal length.
|
| 121 |
+
// @param num_inliers Number of inliers in RANSAC.
|
| 122 |
+
// @param inlier_mask Inlier mask for 2D-3D correspondences.
|
| 123 |
+
//
|
| 124 |
+
// @return Whether pose is estimated successfully.
|
| 125 |
+
bool EstimateAbsolutePose(const AbsolutePoseEstimationOptions& options,
|
| 126 |
+
const std::vector<Eigen::Vector2d>& points2D,
|
| 127 |
+
const std::vector<Eigen::Vector3d>& points3D,
|
| 128 |
+
Eigen::Vector4d* qvec, Eigen::Vector3d* tvec,
|
| 129 |
+
Camera* camera, size_t* num_inliers,
|
| 130 |
+
std::vector<char>* inlier_mask);
|
| 131 |
+
|
| 132 |
+
// Estimate relative from 2D-2D correspondences.
|
| 133 |
+
//
|
| 134 |
+
// Pose of first camera is assumed to be at the origin without rotation. Pose
|
| 135 |
+
// of second camera is given as world-to-image transformation,
|
| 136 |
+
// i.e. `x2 = [R | t] * X2`.
|
| 137 |
+
//
|
| 138 |
+
// @param ransac_options RANSAC options.
|
| 139 |
+
// @param points1 Corresponding 2D points.
|
| 140 |
+
// @param points2 Corresponding 2D points.
|
| 141 |
+
// @param qvec Estimated rotation component as
|
| 142 |
+
// unit Quaternion coefficients (w, x, y, z).
|
| 143 |
+
// @param tvec Estimated translation component.
|
| 144 |
+
//
|
| 145 |
+
// @return Number of RANSAC inliers.
|
| 146 |
+
size_t EstimateRelativePose(const RANSACOptions& ransac_options,
|
| 147 |
+
const std::vector<Eigen::Vector2d>& points1,
|
| 148 |
+
const std::vector<Eigen::Vector2d>& points2,
|
| 149 |
+
Eigen::Vector4d* qvec, Eigen::Vector3d* tvec);
|
| 150 |
+
|
| 151 |
+
// Refine absolute pose (optionally focal length) from 2D-3D correspondences.
|
| 152 |
+
//
|
| 153 |
+
// @param options Refinement options.
|
| 154 |
+
// @param inlier_mask Inlier mask for 2D-3D correspondences.
|
| 155 |
+
// @param points2D Corresponding 2D points.
|
| 156 |
+
// @param points3D Corresponding 3D points.
|
| 157 |
+
// @param qvec Estimated rotation component as
|
| 158 |
+
// unit Quaternion coefficients (w, x, y, z).
|
| 159 |
+
// @param tvec Estimated translation component.
|
| 160 |
+
// @param camera Camera for which to estimate pose. Modified
|
| 161 |
+
// in-place to store the estimated focal length.
|
| 162 |
+
// @param rot_tvec_covariance Estimated 6x6 covariance matrix of
|
| 163 |
+
// the rotation (as axis-angle, in tangent space)
|
| 164 |
+
// and translation terms (optional).
|
| 165 |
+
//
|
| 166 |
+
// @return Whether the solution is usable.
|
| 167 |
+
bool RefineAbsolutePose(const AbsolutePoseRefinementOptions& options,
|
| 168 |
+
const std::vector<char>& inlier_mask,
|
| 169 |
+
const std::vector<Eigen::Vector2d>& points2D,
|
| 170 |
+
const std::vector<Eigen::Vector3d>& points3D,
|
| 171 |
+
Eigen::Vector4d* qvec, Eigen::Vector3d* tvec,
|
| 172 |
+
Camera* camera,
|
| 173 |
+
Eigen::Matrix6d* rot_tvec_covariance = nullptr);
|
| 174 |
+
|
| 175 |
+
// Refine relative pose of two cameras.
|
| 176 |
+
//
|
| 177 |
+
// Minimizes the Sampson error between corresponding normalized points using
|
| 178 |
+
// a robust cost function, i.e. the corresponding points need not necessarily
|
| 179 |
+
// be inliers given a sufficient initial guess for the relative pose.
|
| 180 |
+
//
|
| 181 |
+
// Assumes that first camera pose has projection matrix P = [I | 0], and
|
| 182 |
+
// pose of second camera is given as transformation from world to camera system.
|
| 183 |
+
//
|
| 184 |
+
// Assumes that the given translation vector is normalized, and refines
|
| 185 |
+
// the translation up to an unknown scale (i.e. refined translation vector
|
| 186 |
+
// is a unit vector again).
|
| 187 |
+
//
|
| 188 |
+
// @param options Solver options.
|
| 189 |
+
// @param points1 First set of corresponding points.
|
| 190 |
+
// @param points2 Second set of corresponding points.
|
| 191 |
+
// @param qvec Unit Quaternion rotation coefficients (w, x, y, z).
|
| 192 |
+
// @param tvec 3x1 translation vector.
|
| 193 |
+
//
|
| 194 |
+
// @return Flag indicating if solution is usable.
|
| 195 |
+
bool RefineRelativePose(const ceres::Solver::Options& options,
|
| 196 |
+
const std::vector<Eigen::Vector2d>& points1,
|
| 197 |
+
const std::vector<Eigen::Vector2d>& points2,
|
| 198 |
+
Eigen::Vector4d* qvec, Eigen::Vector3d* tvec);
|
| 199 |
+
|
| 200 |
+
// Refine generalized absolute pose (optionally focal lengths)
|
| 201 |
+
// from 2D-3D correspondences.
|
| 202 |
+
//
|
| 203 |
+
// @param options Refinement options.
|
| 204 |
+
// @param inlier_mask Inlier mask for 2D-3D correspondences.
|
| 205 |
+
// @param points2D Corresponding 2D points.
|
| 206 |
+
// @param points3D Corresponding 3D points.
|
| 207 |
+
// @param camera_idxs Index of the rig camera for each correspondence.
|
| 208 |
+
// @param rig_qvecs Relative rotations from rig to each camera frame
|
| 209 |
+
// @param rig_tvecs Relative translations from rig
|
| 210 |
+
// to each camera frame.
|
| 211 |
+
// @param qvec Estimated rotation component of the rig as
|
| 212 |
+
// unit Quaternion coefficients (w, x, y, z).
|
| 213 |
+
// @param tvec Estimated translation component of the rig.
|
| 214 |
+
// @param cameras Cameras for which to estimate pose. Modified
|
| 215 |
+
// in-place to store the estimated focal lengths.
|
| 216 |
+
// @param rot_tvec_covariance Estimated 6x6 covariance matrix of
|
| 217 |
+
// the rotation (as axis-angle, in tangent space)
|
| 218 |
+
// and translation terms (optional).
|
| 219 |
+
//
|
| 220 |
+
// @return Whether the solution is usable.
|
| 221 |
+
bool RefineGeneralizedAbsolutePose(
|
| 222 |
+
const AbsolutePoseRefinementOptions& options,
|
| 223 |
+
const std::vector<char>& inlier_mask,
|
| 224 |
+
const std::vector<Eigen::Vector2d>& points2D,
|
| 225 |
+
const std::vector<Eigen::Vector3d>& points3D,
|
| 226 |
+
const std::vector<size_t>& camera_idxs,
|
| 227 |
+
const std::vector<Eigen::Vector4d>& rig_qvecs,
|
| 228 |
+
const std::vector<Eigen::Vector3d>& rig_tvecs, Eigen::Vector4d* qvec,
|
| 229 |
+
Eigen::Vector3d* tvec, std::vector<Camera>* cameras,
|
| 230 |
+
Eigen::Matrix6d* rot_tvec_covariance = nullptr);
|
| 231 |
+
|
| 232 |
+
} // namespace colmap
|
| 233 |
+
|
| 234 |
+
#endif // COLMAP_SRC_ESTIMATORS_POSE_H_
|
colmap/include/colmap/estimators/similarity_transform.h
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_ESTIMATORS_SIMILARITY_TRANSFORM_H_
|
| 33 |
+
#define COLMAP_SRC_ESTIMATORS_SIMILARITY_TRANSFORM_H_
|
| 34 |
+
|
| 35 |
+
#include <vector>
|
| 36 |
+
|
| 37 |
+
#include <Eigen/Core>
|
| 38 |
+
#include <Eigen/Geometry>
|
| 39 |
+
|
| 40 |
+
#include "base/projection.h"
|
| 41 |
+
#include "util/alignment.h"
|
| 42 |
+
#include "util/logging.h"
|
| 43 |
+
#include "util/types.h"
|
| 44 |
+
|
| 45 |
+
namespace colmap {
|
| 46 |
+
|
| 47 |
+
// N-D similarity transform estimator from corresponding point pairs in the
|
| 48 |
+
// source and destination coordinate systems.
|
| 49 |
+
//
|
| 50 |
+
// This algorithm is based on the following paper:
|
| 51 |
+
//
|
| 52 |
+
// S. Umeyama. Least-Squares Estimation of Transformation Parameters
|
| 53 |
+
// Between Two Point Patterns. IEEE Transactions on Pattern Analysis and
|
| 54 |
+
// Machine Intelligence, Volume 13 Issue 4, Page 376-380, 1991.
|
| 55 |
+
// http://www.stanford.edu/class/cs273/refs/umeyama.pdf
|
| 56 |
+
//
|
| 57 |
+
// and uses the Eigen implementation.
|
| 58 |
+
template <int kDim, bool kEstimateScale = true>
|
| 59 |
+
class SimilarityTransformEstimator {
|
| 60 |
+
public:
|
| 61 |
+
typedef Eigen::Matrix<double, kDim, 1> X_t;
|
| 62 |
+
typedef Eigen::Matrix<double, kDim, 1> Y_t;
|
| 63 |
+
typedef Eigen::Matrix<double, kDim, kDim + 1> M_t;
|
| 64 |
+
|
| 65 |
+
// The minimum number of samples needed to estimate a model. Note that
|
| 66 |
+
// this only returns the true minimal sample in the two-dimensional case.
|
| 67 |
+
// For higher dimensions, the system will alway be over-determined.
|
| 68 |
+
static const int kMinNumSamples = kDim;
|
| 69 |
+
|
| 70 |
+
// Estimate the similarity transform.
|
| 71 |
+
//
|
| 72 |
+
// @param src Set of corresponding source points.
|
| 73 |
+
// @param dst Set of corresponding destination points.
|
| 74 |
+
//
|
| 75 |
+
// @return 4x4 homogeneous transformation matrix.
|
| 76 |
+
static std::vector<M_t> Estimate(const std::vector<X_t>& src,
|
| 77 |
+
const std::vector<Y_t>& dst);
|
| 78 |
+
|
| 79 |
+
// Calculate the transformation error for each corresponding point pair.
|
| 80 |
+
//
|
| 81 |
+
// Residuals are defined as the squared transformation error when
|
| 82 |
+
// transforming the source to the destination coordinates.
|
| 83 |
+
//
|
| 84 |
+
// @param src Set of corresponding points in the source coordinate
|
| 85 |
+
// system as a Nx3 matrix.
|
| 86 |
+
// @param dst Set of corresponding points in the destination
|
| 87 |
+
// coordinate system as a Nx3 matrix.
|
| 88 |
+
// @param matrix 4x4 homogeneous transformation matrix.
|
| 89 |
+
// @param residuals Output vector of residuals for each point pair.
|
| 90 |
+
static void Residuals(const std::vector<X_t>& src,
|
| 91 |
+
const std::vector<Y_t>& dst, const M_t& matrix,
|
| 92 |
+
std::vector<double>* residuals);
|
| 93 |
+
};
|
| 94 |
+
|
| 95 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 96 |
+
// Implementation
|
| 97 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 98 |
+
|
| 99 |
+
template <int kDim, bool kEstimateScale>
|
| 100 |
+
std::vector<typename SimilarityTransformEstimator<kDim, kEstimateScale>::M_t>
|
| 101 |
+
SimilarityTransformEstimator<kDim, kEstimateScale>::Estimate(
|
| 102 |
+
const std::vector<X_t>& src, const std::vector<Y_t>& dst) {
|
| 103 |
+
CHECK_EQ(src.size(), dst.size());
|
| 104 |
+
|
| 105 |
+
Eigen::Matrix<double, kDim, Eigen::Dynamic> src_mat(kDim, src.size());
|
| 106 |
+
Eigen::Matrix<double, kDim, Eigen::Dynamic> dst_mat(kDim, dst.size());
|
| 107 |
+
for (size_t i = 0; i < src.size(); ++i) {
|
| 108 |
+
src_mat.col(i) = src[i];
|
| 109 |
+
dst_mat.col(i) = dst[i];
|
| 110 |
+
}
|
| 111 |
+
|
| 112 |
+
const M_t model = Eigen::umeyama(src_mat, dst_mat, kEstimateScale)
|
| 113 |
+
.topLeftCorner(kDim, kDim + 1);
|
| 114 |
+
|
| 115 |
+
if (model.array().isNaN().any()) {
|
| 116 |
+
return std::vector<M_t>{};
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
return {model};
|
| 120 |
+
}
|
| 121 |
+
|
| 122 |
+
template <int kDim, bool kEstimateScale>
|
| 123 |
+
void SimilarityTransformEstimator<kDim, kEstimateScale>::Residuals(
|
| 124 |
+
const std::vector<X_t>& src, const std::vector<Y_t>& dst, const M_t& matrix,
|
| 125 |
+
std::vector<double>* residuals) {
|
| 126 |
+
CHECK_EQ(src.size(), dst.size());
|
| 127 |
+
|
| 128 |
+
residuals->resize(src.size());
|
| 129 |
+
|
| 130 |
+
for (size_t i = 0; i < src.size(); ++i) {
|
| 131 |
+
const Y_t dst_transformed = matrix * src[i].homogeneous();
|
| 132 |
+
(*residuals)[i] = (dst[i] - dst_transformed).squaredNorm();
|
| 133 |
+
}
|
| 134 |
+
}
|
| 135 |
+
|
| 136 |
+
} // namespace colmap
|
| 137 |
+
|
| 138 |
+
#endif // COLMAP_SRC_ESTIMATORS_SIMILARITY_TRANSFORM_H_
|
colmap/include/colmap/estimators/translation_transform.h
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) 2023, ETH Zurich and UNC Chapel Hill.
|
| 2 |
+
// All rights reserved.
|
| 3 |
+
//
|
| 4 |
+
// Redistribution and use in source and binary forms, with or without
|
| 5 |
+
// modification, are permitted provided that the following conditions are met:
|
| 6 |
+
//
|
| 7 |
+
// * Redistributions of source code must retain the above copyright
|
| 8 |
+
// notice, this list of conditions and the following disclaimer.
|
| 9 |
+
//
|
| 10 |
+
// * Redistributions in binary form must reproduce the above copyright
|
| 11 |
+
// notice, this list of conditions and the following disclaimer in the
|
| 12 |
+
// documentation and/or other materials provided with the distribution.
|
| 13 |
+
//
|
| 14 |
+
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
|
| 15 |
+
// its contributors may be used to endorse or promote products derived
|
| 16 |
+
// from this software without specific prior written permission.
|
| 17 |
+
//
|
| 18 |
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 19 |
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 20 |
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 21 |
+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
| 22 |
+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 23 |
+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 24 |
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 25 |
+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 26 |
+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 27 |
+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| 28 |
+
// POSSIBILITY OF SUCH DAMAGE.
|
| 29 |
+
//
|
| 30 |
+
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
|
| 31 |
+
|
| 32 |
+
#ifndef COLMAP_SRC_BASE_SIMILARITY_TRANSFORM_H_
|
| 33 |
+
#define COLMAP_SRC_BASE_SIMILARITY_TRANSFORM_H_
|
| 34 |
+
|
| 35 |
+
#include <vector>
|
| 36 |
+
|
| 37 |
+
#include <Eigen/Core>
|
| 38 |
+
#include <Eigen/Geometry>
|
| 39 |
+
|
| 40 |
+
#include "util/alignment.h"
|
| 41 |
+
#include "util/logging.h"
|
| 42 |
+
#include "util/types.h"
|
| 43 |
+
|
| 44 |
+
namespace colmap {
|
| 45 |
+
|
| 46 |
+
// Estimate a N-D translation transformation between point pairs.
|
| 47 |
+
template <int kDim>
|
| 48 |
+
class TranslationTransformEstimator {
|
| 49 |
+
public:
|
| 50 |
+
typedef Eigen::Matrix<double, kDim, 1> X_t;
|
| 51 |
+
typedef Eigen::Matrix<double, kDim, 1> Y_t;
|
| 52 |
+
typedef Eigen::Matrix<double, kDim, 1> M_t;
|
| 53 |
+
|
| 54 |
+
// The minimum number of samples needed to estimate a model.
|
| 55 |
+
static const int kMinNumSamples = 1;
|
| 56 |
+
|
| 57 |
+
// Estimate the 2D translation transform.
|
| 58 |
+
//
|
| 59 |
+
// @param points1 Set of corresponding source 2D points.
|
| 60 |
+
// @param points2 Set of corresponding destination 2D points.
|
| 61 |
+
//
|
| 62 |
+
// @return Translation vector.
|
| 63 |
+
static std::vector<M_t> Estimate(const std::vector<X_t>& points1,
|
| 64 |
+
const std::vector<Y_t>& points2);
|
| 65 |
+
|
| 66 |
+
// Calculate the squared translation error.
|
| 67 |
+
//
|
| 68 |
+
// @param points1 Set of corresponding source 2D points.
|
| 69 |
+
// @param points2 Set of corresponding destination 2D points.
|
| 70 |
+
// @param translation Translation vector.
|
| 71 |
+
// @param residuals Output vector of residuals for each point pair.
|
| 72 |
+
static void Residuals(const std::vector<X_t>& points1,
|
| 73 |
+
const std::vector<Y_t>& points2, const M_t& translation,
|
| 74 |
+
std::vector<double>* residuals);
|
| 75 |
+
};
|
| 76 |
+
|
| 77 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 78 |
+
// Implementation
|
| 79 |
+
////////////////////////////////////////////////////////////////////////////////
|
| 80 |
+
|
| 81 |
+
template <int kDim>
|
| 82 |
+
std::vector<typename TranslationTransformEstimator<kDim>::M_t>
|
| 83 |
+
TranslationTransformEstimator<kDim>::Estimate(const std::vector<X_t>& points1,
|
| 84 |
+
const std::vector<Y_t>& points2) {
|
| 85 |
+
CHECK_EQ(points1.size(), points2.size());
|
| 86 |
+
|
| 87 |
+
X_t mean_src = X_t::Zero();
|
| 88 |
+
Y_t mean_dst = Y_t::Zero();
|
| 89 |
+
|
| 90 |
+
for (size_t i = 0; i < points1.size(); ++i) {
|
| 91 |
+
mean_src += points1[i];
|
| 92 |
+
mean_dst += points2[i];
|
| 93 |
+
}
|
| 94 |
+
|
| 95 |
+
mean_src /= points1.size();
|
| 96 |
+
mean_dst /= points2.size();
|
| 97 |
+
|
| 98 |
+
std::vector<M_t> models(1);
|
| 99 |
+
models[0] = mean_dst - mean_src;
|
| 100 |
+
|
| 101 |
+
return models;
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
template <int kDim>
|
| 105 |
+
void TranslationTransformEstimator<kDim>::Residuals(
|
| 106 |
+
const std::vector<X_t>& points1, const std::vector<Y_t>& points2,
|
| 107 |
+
const M_t& translation, std::vector<double>* residuals) {
|
| 108 |
+
CHECK_EQ(points1.size(), points2.size());
|
| 109 |
+
|
| 110 |
+
residuals->resize(points1.size());
|
| 111 |
+
|
| 112 |
+
for (size_t i = 0; i < points1.size(); ++i) {
|
| 113 |
+
const M_t diff = points2[i] - points1[i] - translation;
|
| 114 |
+
(*residuals)[i] = diff.squaredNorm();
|
| 115 |
+
}
|
| 116 |
+
}
|
| 117 |
+
|
| 118 |
+
} // namespace colmap
|
| 119 |
+
|
| 120 |
+
#endif // COLMAP_SRC_BASE_SIMILARITY_TRANSFORM_H_
|