45 struct ReconstructionAlignmentEstimator {
48 typedef const Image* X_t;
49 typedef const Image* Y_t;
52 void SetMaxReprojError(
const double max_reproj_error) {
53 max_squared_reproj_error_ = max_reproj_error * max_reproj_error;
56 void SetReconstructions(
const Reconstruction* reconstruction1,
57 const Reconstruction* reconstruction2) {
58 CHECK_NOTNULL(reconstruction1);
59 CHECK_NOTNULL(reconstruction2);
60 reconstruction1_ = reconstruction1;
61 reconstruction2_ = reconstruction2;
65 std::vector<M_t> Estimate(
const std::vector<X_t>& images1,
66 const std::vector<Y_t>& images2)
const {
67 CHECK_GE(images1.size(), 3);
68 CHECK_GE(images2.size(), 3);
69 CHECK_EQ(images1.size(), images2.size());
71 std::vector<Eigen::Vector3d> proj_centers1(images1.size());
72 std::vector<Eigen::Vector3d> proj_centers2(images2.size());
73 for (
size_t i = 0; i < images1.size(); ++i) {
74 CHECK_EQ(images1[i]->ImageId(), images2[i]->ImageId());
75 proj_centers1[i] = images1[i]->ProjectionCenter();
76 proj_centers2[i] = images2[i]->ProjectionCenter();
79 SimilarityTransform3 tform12;
80 tform12.Estimate(proj_centers1, proj_centers2);
82 return {tform12.Matrix().topRows<3>()};
90 void Residuals(
const std::vector<X_t>& images1,
91 const std::vector<Y_t>& images2,
const M_t& alignment12,
92 std::vector<double>* residuals)
const {
93 CHECK_EQ(images1.size(), images2.size());
94 CHECK_NOTNULL(reconstruction1_);
95 CHECK_NOTNULL(reconstruction2_);
98 SimilarityTransform3(alignment12).Inverse().Matrix().topRows<3>();
100 residuals->resize(images1.size());
102 for (
size_t i = 0; i < images1.size(); ++i) {
103 const auto& image1 = *images1[i];
104 const auto& image2 = *images2[i];
106 CHECK_EQ(image1.ImageId(), image2.ImageId());
107 CHECK_EQ(image1.CameraId(), image2.CameraId());
109 const auto& camera1 = reconstruction1_->Camera(image1.CameraId());
110 const auto& camera2 = reconstruction2_->Camera(image2.CameraId());
115 CHECK_EQ(image1.NumPoints2D(), image2.NumPoints2D());
117 size_t num_inliers = 0;
118 size_t num_common_points = 0;
120 for (
point2D_t point2D_idx = 0; point2D_idx < image1.NumPoints2D();
124 const auto& point2D1 = image1.Point2D(point2D_idx);
125 if (!point2D1.HasPoint3D()) {
129 const auto& point2D2 = image2.Point2D(point2D_idx);
130 if (!point2D2.HasPoint3D()) {
134 num_common_points += 1;
137 const Eigen::Vector3d xyz12 =
139 reconstruction1_->Point3D(point2D1.Point3DId()).XYZ().homogeneous();
141 proj_matrix2, camera2) >
142 max_squared_reproj_error_) {
147 const Eigen::Vector3d xyz21 =
149 reconstruction2_->Point3D(point2D2.Point3DId()).XYZ().homogeneous();
151 proj_matrix1, camera1) >
152 max_squared_reproj_error_) {
159 if (num_common_points == 0) {
160 (*residuals)[i] = 1.0;
162 const double negative_inlier_ratio =
163 1.0 -
static_cast<double>(num_inliers) /
164 static_cast<double>(num_common_points);
165 (*residuals)[i] = negative_inlier_ratio * negative_inlier_ratio;
171 double max_squared_reproj_error_ = 0.0;
172 const Reconstruction* reconstruction1_ =
nullptr;
173 const Reconstruction* reconstruction2_ =
nullptr;
180 Eigen::Vector3d(0, 0, 0)) {}
183 transform_.matrix().topLeftCorner<3, 4>() = matrix;
187 const Eigen::Transform<double, 3, Eigen::Affine>& transform)
188 : transform_(transform) {}
191 const Eigen::Vector4d& qvec,
192 const Eigen::Vector3d& tvec) {
193 Eigen::Matrix4d matrix = Eigen::MatrixXd::Identity(4, 4);
195 matrix.block<3, 3>(0, 0) *= scale;
196 transform_.matrix() = matrix;
200 std::ofstream file(
path, std::ios::trunc);
201 CHECK(file.is_open()) <<
path;
204 file << transform_.matrix() <<
std::endl;
212 *xyz = transform_ * *xyz;
216 Eigen::Vector3d* tvec)
const {
231 Eigen::Matrix4d src_matrix = Eigen::MatrixXd::Identity(4, 4);
233 Eigen::Matrix4d dst_matrix =
234 src_matrix.matrix() * transform_.inverse().matrix();
235 dst_matrix *=
Scale();
238 *tvec = dst_matrix.block<3, 1>(0, 3);
242 return transform_.matrix();
246 return Matrix().block<1, 3>(0, 0).norm();
254 return Matrix().block<3, 1>(0, 3);
258 std::ifstream file(
path);
259 CHECK(file.is_open()) <<
path;
261 Eigen::Matrix4d matrix = Eigen::MatrixXd::Identity(4, 4);
262 for (
int i = 0; i < matrix.rows(); ++i) {
263 for (
int j = 0; j < matrix.cols(); ++j) {
264 file >> matrix(i, j);
268 tform.transform_.matrix() = matrix;
275 const double min_inlier_observations,
const double max_reproj_error,
277 CHECK_GE(min_inlier_observations, 0.0);
278 CHECK_LE(min_inlier_observations, 1.0);
281 ransac_options.
max_error = 1.0 - min_inlier_observations;
285 ransac(ransac_options);
286 ransac.
estimator.SetMaxReprojError(max_reproj_error);
287 ransac.
estimator.SetReconstructions(&src_reconstruction, &ref_reconstruction);
290 &ref_reconstruction);
292 const auto& common_image_ids =
295 if (common_image_ids.size() < 3) {
299 std::vector<const Image*> src_images(common_image_ids.size());
300 std::vector<const Image*> ref_images(common_image_ids.size());
301 for (
size_t i = 0; i < common_image_ids.size(); ++i) {
302 src_images[i] = &src_reconstruction.
Image(common_image_ids[i]);
303 ref_images[i] = &ref_reconstruction.
Image(common_image_ids[i]);
306 const auto report = ransac.
Estimate(src_images, ref_images);
308 if (report.success) {
309 *alignment = report.model;
312 return report.success;
Report Estimate(const std::vector< typename Estimator::X_t > &X, const std::vector< typename Estimator::Y_t > &Y)
LocalEstimator local_estimator
std::vector< image_t > FindCommonRegImageIds(const Reconstruction &reconstruction) const
const class Image & Image(const image_t image_id) const
Matrix< double, 3, 4 > Matrix3x4d
QTextStream & endl(QTextStream &stream)
static const std::string path
bool ComputeAlignmentBetweenReconstructions(const Reconstruction &src_reconstruction, const Reconstruction &ref_reconstruction, const double min_inlier_observations, const double max_reproj_error, Eigen::Matrix3x4d *alignment)
double CalculateSquaredReprojectionError(const Eigen::Vector2d &point2D, const Eigen::Vector3d &point3D, const Eigen::Vector4d &qvec, const Eigen::Vector3d &tvec, const Camera &camera)
Eigen::Vector4d ComposeIdentityQuaternion()
Eigen::Vector4d RotationMatrixToQuaternion(const Eigen::Matrix3d &rot_mat)
Eigen::Matrix3x4d ComposeProjectionMatrix(const Eigen::Vector4d &qvec, const Eigen::Vector3d &tvec)