ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
essential_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/essential_matrix.h"
33 
34 #include <array>
35 
36 #include "base/pose.h"
37 #include "estimators/pose.h"
38 
39 namespace colmap {
40 
41 void DecomposeEssentialMatrix(const Eigen::Matrix3d& E, Eigen::Matrix3d* R1,
42  Eigen::Matrix3d* R2, Eigen::Vector3d* t) {
43  Eigen::JacobiSVD<Eigen::Matrix3d> svd(
44  E, Eigen::ComputeFullU | Eigen::ComputeFullV);
45  Eigen::Matrix3d U = svd.matrixU();
46  Eigen::Matrix3d V = svd.matrixV().transpose();
47 
48  if (U.determinant() < 0) {
49  U *= -1;
50  }
51  if (V.determinant() < 0) {
52  V *= -1;
53  }
54 
55  Eigen::Matrix3d W;
56  W << 0, 1, 0, -1, 0, 0, 0, 0, 1;
57 
58  *R1 = U * W * V;
59  *R2 = U * W.transpose() * V;
60  *t = U.col(2).normalized();
61 }
62 
63 void PoseFromEssentialMatrix(const Eigen::Matrix3d& E,
64  const std::vector<Eigen::Vector2d>& points1,
65  const std::vector<Eigen::Vector2d>& points2,
66  Eigen::Matrix3d* R, Eigen::Vector3d* t,
67  std::vector<Eigen::Vector3d>* points3D) {
68  CHECK_EQ(points1.size(), points2.size());
69 
70  Eigen::Matrix3d R1;
71  Eigen::Matrix3d R2;
72  DecomposeEssentialMatrix(E, &R1, &R2, t);
73 
74  // Generate all possible projection matrix combinations.
75  const std::array<Eigen::Matrix3d, 4> R_cmbs{{R1, R2, R1, R2}};
76  const std::array<Eigen::Vector3d, 4> t_cmbs{{*t, *t, -*t, -*t}};
77 
78  points3D->clear();
79  for (size_t i = 0; i < R_cmbs.size(); ++i) {
80  std::vector<Eigen::Vector3d> points3D_cmb;
81  CheckCheirality(R_cmbs[i], t_cmbs[i], points1, points2, &points3D_cmb);
82  if (points3D_cmb.size() >= points3D->size()) {
83  *R = R_cmbs[i];
84  *t = t_cmbs[i];
85  *points3D = points3D_cmb;
86  }
87  }
88 }
89 
90 Eigen::Matrix3d EssentialMatrixFromPose(const Eigen::Matrix3d& R,
91  const Eigen::Vector3d& t) {
92  return CrossProductMatrix(t.normalized()) * R;
93 }
94 
96  const Eigen::Matrix3x4d& proj_matrix1,
97  const Eigen::Matrix3x4d& proj_matrix2) {
98  const Eigen::Matrix3d R1 = proj_matrix1.leftCols<3>();
99  const Eigen::Matrix3d R2 = proj_matrix2.leftCols<3>();
100  const Eigen::Vector3d t1 = proj_matrix1.rightCols<1>();
101  const Eigen::Vector3d t2 = proj_matrix2.rightCols<1>();
102 
103  // Relative transformation between to cameras.
104  const Eigen::Matrix3d R = R2 * R1.transpose();
105  const Eigen::Vector3d t = t2 - R * t1;
106 
107  return EssentialMatrixFromPose(R, t);
108 }
109 
110 void FindOptimalImageObservations(const Eigen::Matrix3d& E,
111  const Eigen::Vector2d& point1,
112  const Eigen::Vector2d& point2,
113  Eigen::Vector2d* optimal_point1,
114  Eigen::Vector2d* optimal_point2) {
115  const Eigen::Vector3d& point1h = point1.homogeneous();
116  const Eigen::Vector3d& point2h = point2.homogeneous();
117 
118  Eigen::Matrix<double, 2, 3> S;
119  S << 1, 0, 0, 0, 1, 0;
120 
121  // Epipolar lines.
122  Eigen::Vector2d n1 = S * E * point2h;
123  Eigen::Vector2d n2 = S * E.transpose() * point1h;
124 
125  const Eigen::Matrix2d E_tilde = E.block<2, 2>(0, 0);
126 
127  const double a = n1.transpose() * E_tilde * n2;
128  const double b = (n1.squaredNorm() + n2.squaredNorm()) / 2.0;
129  const double c = point1h.transpose() * E * point2h;
130  const double d = sqrt(b * b - a * c);
131  double lambda = c / (b + d);
132 
133  n1 -= E_tilde * lambda * n1;
134  n2 -= E_tilde.transpose() * lambda * n2;
135 
136  lambda *= (2.0 * d) / (n1.squaredNorm() + n2.squaredNorm());
137 
138  *optimal_point1 = (point1h - S.transpose() * lambda * n1).hnormalized();
139  *optimal_point2 = (point2h - S.transpose() * lambda * n2).hnormalized();
140 }
141 
142 Eigen::Vector3d EpipoleFromEssentialMatrix(const Eigen::Matrix3d& E,
143  const bool left_image) {
144  Eigen::Vector3d e;
145  if (left_image) {
146  Eigen::JacobiSVD<Eigen::Matrix3d> svd(E, Eigen::ComputeFullV);
147  e = svd.matrixV().block<3, 1>(0, 2);
148  } else {
149  Eigen::JacobiSVD<Eigen::Matrix3d> svd(E.transpose(), Eigen::ComputeFullV);
150  e = svd.matrixV().block<3, 1>(0, 2);
151  }
152  return e;
153 }
154 
155 Eigen::Matrix3d InvertEssentialMatrix(const Eigen::Matrix3d& E) {
156  return E.transpose();
157 }
158 
159 bool RefineEssentialMatrix(const ceres::Solver::Options& options,
160  const std::vector<Eigen::Vector2d>& points1,
161  const std::vector<Eigen::Vector2d>& points2,
162  const std::vector<char>& inlier_mask,
163  Eigen::Matrix3d* E) {
164  CHECK_EQ(points1.size(), points2.size());
165  CHECK_EQ(points1.size(), inlier_mask.size());
166 
167  // Extract inlier points for decomposing the essential matrix into
168  // rotation and translation components.
169 
170  size_t num_inliers = 0;
171  for (const auto inlier : inlier_mask) {
172  if (inlier) {
173  num_inliers += 1;
174  }
175  }
176 
177  std::vector<Eigen::Vector2d> inlier_points1(num_inliers);
178  std::vector<Eigen::Vector2d> inlier_points2(num_inliers);
179  size_t j = 0;
180  for (size_t i = 0; i < inlier_mask.size(); ++i) {
181  if (inlier_mask[i]) {
182  inlier_points1[j] = points1[i];
183  inlier_points2[j] = points2[i];
184  j += 1;
185  }
186  }
187 
188  // Extract relative pose from essential matrix.
189 
190  Eigen::Matrix3d R;
191  Eigen::Vector3d tvec;
192  std::vector<Eigen::Vector3d> points3D;
193  PoseFromEssentialMatrix(*E, inlier_points1, inlier_points2, &R, &tvec,
194  &points3D);
195 
196  Eigen::Vector4d qvec = RotationMatrixToQuaternion(R);
197 
198  if (points3D.size() == 0) {
199  return false;
200  }
201 
202  // Refine essential matrix, use all points so that refinement is able to
203  // consider points as inliers that were originally outliers.
204 
205  const bool refinement_success =
206  RefineRelativePose(options, inlier_points1, inlier_points2, &qvec, &tvec);
207 
208  if (!refinement_success) {
209  return false;
210  }
211 
212  // Compose refined essential matrix.
213  const Eigen::Matrix3d rot_mat = QuaternionToRotationMatrix(qvec);
214  *E = EssentialMatrixFromPose(rot_mat, tvec);
215 
216  return true;
217 }
218 
219 } // namespace colmap
a[190]
const double * e
Matrix< double, 3, 4 > Matrix3x4d
Definition: types.h:39
Eigen::Matrix3d InvertEssentialMatrix(const Eigen::Matrix3d &E)
Eigen::Matrix3d EssentialMatrixFromAbsolutePoses(const Eigen::Matrix3x4d &proj_matrix1, const Eigen::Matrix3x4d &proj_matrix2)
void FindOptimalImageObservations(const Eigen::Matrix3d &E, const Eigen::Vector2d &point1, const Eigen::Vector2d &point2, Eigen::Vector2d *optimal_point1, Eigen::Vector2d *optimal_point2)
Eigen::Matrix3d CrossProductMatrix(const Eigen::Vector3d &vector)
Definition: pose.cc:41
Eigen::Matrix3d EssentialMatrixFromPose(const Eigen::Matrix3d &R, const Eigen::Vector3d &t)
void DecomposeEssentialMatrix(const Eigen::Matrix3d &E, Eigen::Matrix3d *R1, Eigen::Matrix3d *R2, Eigen::Vector3d *t)
Eigen::Vector4d RotationMatrixToQuaternion(const Eigen::Matrix3d &rot_mat)
Definition: pose.cc:70
Eigen::Vector3d EpipoleFromEssentialMatrix(const Eigen::Matrix3d &E, const bool left_image)
bool RefineRelativePose(const ceres::Solver::Options &options, const std::vector< Eigen::Vector2d > &points1, const std::vector< Eigen::Vector2d > &points2, Eigen::Vector4d *qvec, Eigen::Vector3d *tvec)
Definition: pose.cc:330
void PoseFromEssentialMatrix(const Eigen::Matrix3d &E, const std::vector< Eigen::Vector2d > &points1, const std::vector< Eigen::Vector2d > &points2, Eigen::Matrix3d *R, Eigen::Vector3d *t, std::vector< Eigen::Vector3d > *points3D)
bool RefineEssentialMatrix(const ceres::Solver::Options &options, const std::vector< Eigen::Vector2d > &points1, const std::vector< Eigen::Vector2d > &points2, const std::vector< char > &inlier_mask, Eigen::Matrix3d *E)
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
Eigen::Matrix3d QuaternionToRotationMatrix(const Eigen::Vector4d &qvec)
Definition: pose.cc:75