ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
homography_matrix.cc
Go to the documentation of this file.
1 // Copyright (c) 2018, 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 #include "base/homography_matrix.h"
33 
34 #include <array>
35 
36 #include <Eigen/Dense>
37 
38 #include "base/pose.h"
39 #include "util/logging.h"
40 #include "util/math.h"
41 
42 namespace colmap {
43 namespace {
44 
45 double ComputeOppositeOfMinor(const Eigen::Matrix3d& matrix, const size_t row,
46  const size_t col) {
47  const size_t col1 = col == 0 ? 1 : 0;
48  const size_t col2 = col == 2 ? 1 : 2;
49  const size_t row1 = row == 0 ? 1 : 0;
50  const size_t row2 = row == 2 ? 1 : 2;
51  return (matrix(row1, col2) * matrix(row2, col1) -
52  matrix(row1, col1) * matrix(row2, col2));
53 }
54 
55 Eigen::Matrix3d ComputeHomographyRotation(const Eigen::Matrix3d& H_normalized,
56  const Eigen::Vector3d& tstar,
57  const Eigen::Vector3d& n,
58  const double v) {
59  return H_normalized *
60  (Eigen::Matrix3d::Identity() - (2.0 / v) * tstar * n.transpose());
61 }
62 
63 } // namespace
64 
65 void DecomposeHomographyMatrix(const Eigen::Matrix3d& H,
66  const Eigen::Matrix3d& K1,
67  const Eigen::Matrix3d& K2,
68  std::vector<Eigen::Matrix3d>* R,
69  std::vector<Eigen::Vector3d>* t,
70  std::vector<Eigen::Vector3d>* n) {
71  // Remove calibration from homography.
72  Eigen::Matrix3d H_normalized = K2.inverse() * H * K1;
73 
74  // Remove scale from normalized homography.
75  Eigen::JacobiSVD<Eigen::Matrix3d> hmatrix_norm_svd(H_normalized);
76  H_normalized.array() /= hmatrix_norm_svd.singularValues()[1];
77 
78  // Ensure that we always return rotations, and never reflections.
79  //
80  // It's enough to take det(H_normalized) > 0.
81  //
82  // To see this:
83  // - In the paper: R := H_normalized * (Id + x y^t)^{-1} (page 32).
84  // - Can check that this implies that R is orthogonal: RR^t = Id.
85  // - To return a rotation, we also need det(R) > 0.
86  // - By Sylvester's idenitity: det(Id + x y^t) = (1 + x^t y), which
87  // is positive by choice of x and y (page 24).
88  // - So det(R) and det(H_normalized) have the same sign.
89  if (H_normalized.determinant() < 0) {
90  H_normalized.array() *= -1.0;
91  }
92 
93  const Eigen::Matrix3d S =
94  H_normalized.transpose() * H_normalized - Eigen::Matrix3d::Identity();
95 
96  // Check if H is rotation matrix.
97  const double kMinInfinityNorm = 1e-3;
98  if (S.lpNorm<Eigen::Infinity>() < kMinInfinityNorm) {
99  *R = {H_normalized};
100  *t = {Eigen::Vector3d::Zero()};
101  *n = {Eigen::Vector3d::Zero()};
102  return;
103  }
104 
105  const double M00 = ComputeOppositeOfMinor(S, 0, 0);
106  const double M11 = ComputeOppositeOfMinor(S, 1, 1);
107  const double M22 = ComputeOppositeOfMinor(S, 2, 2);
108 
109  const double rtM00 = std::sqrt(M00);
110  const double rtM11 = std::sqrt(M11);
111  const double rtM22 = std::sqrt(M22);
112 
113  const double M01 = ComputeOppositeOfMinor(S, 0, 1);
114  const double M12 = ComputeOppositeOfMinor(S, 1, 2);
115  const double M02 = ComputeOppositeOfMinor(S, 0, 2);
116 
117  const int e12 = SignOfNumber(M12);
118  const int e02 = SignOfNumber(M02);
119  const int e01 = SignOfNumber(M01);
120 
121  const double nS00 = std::abs(S(0, 0));
122  const double nS11 = std::abs(S(1, 1));
123  const double nS22 = std::abs(S(2, 2));
124 
125  const std::array<double, 3> nS{{nS00, nS11, nS22}};
126  const size_t idx =
127  std::distance(nS.begin(), std::max_element(nS.begin(), nS.end()));
128 
129  Eigen::Vector3d np1;
130  Eigen::Vector3d np2;
131  if (idx == 0) {
132  np1[0] = S(0, 0);
133  np2[0] = S(0, 0);
134  np1[1] = S(0, 1) + rtM22;
135  np2[1] = S(0, 1) - rtM22;
136  np1[2] = S(0, 2) + e12 * rtM11;
137  np2[2] = S(0, 2) - e12 * rtM11;
138  } else if (idx == 1) {
139  np1[0] = S(0, 1) + rtM22;
140  np2[0] = S(0, 1) - rtM22;
141  np1[1] = S(1, 1);
142  np2[1] = S(1, 1);
143  np1[2] = S(1, 2) - e02 * rtM00;
144  np2[2] = S(1, 2) + e02 * rtM00;
145  } else if (idx == 2) {
146  np1[0] = S(0, 2) + e01 * rtM11;
147  np2[0] = S(0, 2) - e01 * rtM11;
148  np1[1] = S(1, 2) + rtM00;
149  np2[1] = S(1, 2) - rtM00;
150  np1[2] = S(2, 2);
151  np2[2] = S(2, 2);
152  }
153 
154  const double traceS = S.trace();
155  const double v = 2.0 * std::sqrt(1.0 + traceS - M00 - M11 - M22);
156 
157  const double ESii = SignOfNumber(S(idx, idx));
158  const double r_2 = 2 + traceS + v;
159  const double nt_2 = 2 + traceS - v;
160 
161  const double r = std::sqrt(r_2);
162  const double n_t = std::sqrt(nt_2);
163 
164  const Eigen::Vector3d n1 = np1.normalized();
165  const Eigen::Vector3d n2 = np2.normalized();
166 
167  const double half_nt = 0.5 * n_t;
168  const double esii_t_r = ESii * r;
169 
170  const Eigen::Vector3d t1_star = half_nt * (esii_t_r * n2 - n_t * n1);
171  const Eigen::Vector3d t2_star = half_nt * (esii_t_r * n1 - n_t * n2);
172 
173  const Eigen::Matrix3d R1 =
174  ComputeHomographyRotation(H_normalized, t1_star, n1, v);
175  const Eigen::Vector3d t1 = R1 * t1_star;
176 
177  const Eigen::Matrix3d R2 =
178  ComputeHomographyRotation(H_normalized, t2_star, n2, v);
179  const Eigen::Vector3d t2 = R2 * t2_star;
180 
181  *R = {R1, R1, R2, R2};
182  *t = {t1, -t1, t2, -t2};
183  *n = {-n1, n1, -n2, n2};
184 }
185 
186 void PoseFromHomographyMatrix(const Eigen::Matrix3d& H,
187  const Eigen::Matrix3d& K1,
188  const Eigen::Matrix3d& K2,
189  const std::vector<Eigen::Vector2d>& points1,
190  const std::vector<Eigen::Vector2d>& points2,
191  Eigen::Matrix3d* R, Eigen::Vector3d* t,
192  Eigen::Vector3d* n,
193  std::vector<Eigen::Vector3d>* points3D) {
194  CHECK_EQ(points1.size(), points2.size());
195 
196  std::vector<Eigen::Matrix3d> R_cmbs;
197  std::vector<Eigen::Vector3d> t_cmbs;
198  std::vector<Eigen::Vector3d> n_cmbs;
199  DecomposeHomographyMatrix(H, K1, K2, &R_cmbs, &t_cmbs, &n_cmbs);
200 
201  points3D->clear();
202  for (size_t i = 0; i < R_cmbs.size(); ++i) {
203  std::vector<Eigen::Vector3d> points3D_cmb;
204  CheckCheirality(R_cmbs[i], t_cmbs[i], points1, points2, &points3D_cmb);
205  if (points3D_cmb.size() >= points3D->size()) {
206  *R = R_cmbs[i];
207  *t = t_cmbs[i];
208  *n = n_cmbs[i];
209  *points3D = points3D_cmb;
210  }
211  }
212 }
213 
214 Eigen::Matrix3d HomographyMatrixFromPose(const Eigen::Matrix3d& K1,
215  const Eigen::Matrix3d& K2,
216  const Eigen::Matrix3d& R,
217  const Eigen::Vector3d& t,
218  const Eigen::Vector3d& n,
219  const double d) {
220  CHECK_GT(d, 0);
221  return K2 * (R - t * n.normalized().transpose() / d) * K1.inverse();
222 }
223 
224 } // namespace colmap
const double * e
static double distance(T *pot1, T *pot2)
Definition: utils.h:111
void PoseFromHomographyMatrix(const Eigen::Matrix3d &H, const Eigen::Matrix3d &K1, const Eigen::Matrix3d &K2, const std::vector< Eigen::Vector2d > &points1, const std::vector< Eigen::Vector2d > &points2, Eigen::Matrix3d *R, Eigen::Vector3d *t, Eigen::Vector3d *n, std::vector< Eigen::Vector3d > *points3D)
int SignOfNumber(const T val)
Definition: math.h:156
Eigen::Matrix3d HomographyMatrixFromPose(const Eigen::Matrix3d &K1, const Eigen::Matrix3d &K2, const Eigen::Matrix3d &R, const Eigen::Vector3d &t, const Eigen::Vector3d &n, const double d)
void DecomposeHomographyMatrix(const Eigen::Matrix3d &H, const Eigen::Matrix3d &K1, const Eigen::Matrix3d &K2, std::vector< Eigen::Matrix3d > *R, std::vector< Eigen::Vector3d > *t, std::vector< Eigen::Vector3d > *n)
bool CheckCheirality(const Eigen::Matrix3d &R, const Eigen::Vector3d &t, const std::vector< Eigen::Vector2d > &points1, const std::vector< Eigen::Vector2d > &points2, std::vector< Eigen::Vector3d > *points3D)
Definition: pose.cc:225