ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
fundamental_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 
33 
34 #include <cfloat>
35 #include <complex>
36 #include <vector>
37 
38 #include <Eigen/Geometry>
39 #include <Eigen/LU>
40 #include <Eigen/SVD>
41 
42 #include "base/polynomial.h"
43 #include "estimators/utils.h"
44 #include "util/logging.h"
45 
46 namespace colmap {
47 
48 std::vector<FundamentalMatrixSevenPointEstimator::M_t>
50  const std::vector<X_t>& points1, const std::vector<Y_t>& points2) {
51  CHECK_EQ(points1.size(), 7);
52  CHECK_EQ(points2.size(), 7);
53 
54  // Note that no normalization of the points is necessary here.
55 
56  // Setup system of equations: [points2(i,:), 1]' * F * [points1(i,:), 1]'.
57  Eigen::Matrix<double, 7, 9> A;
58  for (size_t i = 0; i < 7; ++i) {
59  const double x0 = points1[i](0);
60  const double y0 = points1[i](1);
61  const double x1 = points2[i](0);
62  const double y1 = points2[i](1);
63  A(i, 0) = x1 * x0;
64  A(i, 1) = x1 * y0;
65  A(i, 2) = x1;
66  A(i, 3) = y1 * x0;
67  A(i, 4) = y1 * y0;
68  A(i, 5) = y1;
69  A(i, 6) = x0;
70  A(i, 7) = y0;
71  A(i, 8) = 1;
72  }
73 
74  // 9 unknowns with 7 equations, so we have 2D null space.
75  Eigen::JacobiSVD<Eigen::Matrix<double, 7, 9>> svd(A, Eigen::ComputeFullV);
76  const Eigen::Matrix<double, 9, 9> f = svd.matrixV();
77  Eigen::Matrix<double, 1, 9> f1 = f.col(7);
78  Eigen::Matrix<double, 1, 9> f2 = f.col(8);
79 
80  f1 -= f2;
81 
82  // Normalize, such that lambda + mu = 1
83  // and add constraint det(F) = det(lambda * f1 + (1 - lambda) * f2).
84 
85  const double t0 = f1(4) * f1(8) - f1(5) * f1(7);
86  const double t1 = f1(3) * f1(8) - f1(5) * f1(6);
87  const double t2 = f1(3) * f1(7) - f1(4) * f1(6);
88  const double t3 = f2(4) * f2(8) - f2(5) * f2(7);
89  const double t4 = f2(3) * f2(8) - f2(5) * f2(6);
90  const double t5 = f2(3) * f2(7) - f2(4) * f2(6);
91 
92  Eigen::Vector4d coeffs;
93  coeffs(0) = f1(0) * t0 - f1(1) * t1 + f1(2) * t2;
94  coeffs(1) = f2(0) * t0 - f2(1) * t1 + f2(2) * t2 -
95  f2(3) * (f1(1) * f1(8) - f1(2) * f1(7)) +
96  f2(4) * (f1(0) * f1(8) - f1(2) * f1(6)) -
97  f2(5) * (f1(0) * f1(7) - f1(1) * f1(6)) +
98  f2(6) * (f1(1) * f1(5) - f1(2) * f1(4)) -
99  f2(7) * (f1(0) * f1(5) - f1(2) * f1(3)) +
100  f2(8) * (f1(0) * f1(4) - f1(1) * f1(3));
101  coeffs(2) = f1(0) * t3 - f1(1) * t4 + f1(2) * t5 -
102  f1(3) * (f2(1) * f2(8) - f2(2) * f2(7)) +
103  f1(4) * (f2(0) * f2(8) - f2(2) * f2(6)) -
104  f1(5) * (f2(0) * f2(7) - f2(1) * f2(6)) +
105  f1(6) * (f2(1) * f2(5) - f2(2) * f2(4)) -
106  f1(7) * (f2(0) * f2(5) - f2(2) * f2(3)) +
107  f1(8) * (f2(0) * f2(4) - f2(1) * f2(3));
108  coeffs(3) = f2(0) * t3 - f2(1) * t4 + f2(2) * t5;
109 
110  Eigen::VectorXd roots_real;
111  Eigen::VectorXd roots_imag;
112  if (!FindPolynomialRootsCompanionMatrix(coeffs, &roots_real, &roots_imag)) {
113  return {};
114  }
115 
116  std::vector<M_t> models;
117  models.reserve(roots_real.size());
118 
119  for (Eigen::VectorXd::Index i = 0; i < roots_real.size(); ++i) {
120  const double kMaxRootImag = 1e-10;
121  if (std::abs(roots_imag(i)) > kMaxRootImag) {
122  continue;
123  }
124 
125  const double lambda = roots_real(i);
126  const double mu = 1;
127 
128  Eigen::MatrixXd F = lambda * f1 + mu * f2;
129 
130  F.resize(3, 3);
131 
132  const double kEps = 1e-10;
133  if (std::abs(F(2, 2)) < kEps) {
134  continue;
135  }
136 
137  F /= F(2, 2);
138 
139  models.push_back(F.transpose());
140  }
141 
142  return models;
143 }
144 
146  const std::vector<X_t>& points1, const std::vector<Y_t>& points2,
147  const M_t& F, std::vector<double>* residuals) {
148  ComputeSquaredSampsonError(points1, points2, F, residuals);
149 }
150 
151 std::vector<FundamentalMatrixEightPointEstimator::M_t>
153  const std::vector<X_t>& points1, const std::vector<Y_t>& points2) {
154  CHECK_EQ(points1.size(), points2.size());
155 
156  // Center and normalize image points for better numerical stability.
157  std::vector<X_t> normed_points1;
158  std::vector<Y_t> normed_points2;
159  Eigen::Matrix3d points1_norm_matrix;
160  Eigen::Matrix3d points2_norm_matrix;
161  CenterAndNormalizeImagePoints(points1, &normed_points1, &points1_norm_matrix);
162  CenterAndNormalizeImagePoints(points2, &normed_points2, &points2_norm_matrix);
163 
164  // Setup homogeneous linear equation as x2' * F * x1 = 0.
165  Eigen::Matrix<double, Eigen::Dynamic, 9> cmatrix(points1.size(), 9);
166  for (size_t i = 0; i < points1.size(); ++i) {
167  cmatrix.block<1, 3>(i, 0) = normed_points1[i].homogeneous();
168  cmatrix.block<1, 3>(i, 0) *= normed_points2[i].x();
169  cmatrix.block<1, 3>(i, 3) = normed_points1[i].homogeneous();
170  cmatrix.block<1, 3>(i, 3) *= normed_points2[i].y();
171  cmatrix.block<1, 3>(i, 6) = normed_points1[i].homogeneous();
172  }
173 
174  // Solve for the nullspace of the constraint matrix.
175  Eigen::JacobiSVD<Eigen::Matrix<double, Eigen::Dynamic, 9>> cmatrix_svd(
176  cmatrix, Eigen::ComputeFullV);
177  const Eigen::VectorXd cmatrix_nullspace = cmatrix_svd.matrixV().col(8);
178  const Eigen::Map<const Eigen::Matrix3d> ematrix_t(cmatrix_nullspace.data());
179 
180  // Enforcing the internal constraint that two singular values must non-zero
181  // and one must be zero.
182  Eigen::JacobiSVD<Eigen::Matrix3d> fmatrix_svd(
183  ematrix_t.transpose(), Eigen::ComputeFullU | Eigen::ComputeFullV);
184  Eigen::Vector3d singular_values = fmatrix_svd.singularValues();
185  singular_values(2) = 0.0;
186  const Eigen::Matrix3d F = fmatrix_svd.matrixU() *
187  singular_values.asDiagonal() *
188  fmatrix_svd.matrixV().transpose();
189 
190  const std::vector<M_t> models = {points2_norm_matrix.transpose() * F *
191  points1_norm_matrix};
192  return models;
193 }
194 
196  const std::vector<X_t>& points1, const std::vector<Y_t>& points2,
197  const M_t& E, std::vector<double>* residuals) {
198  ComputeSquaredSampsonError(points1, points2, E, residuals);
199 }
200 
201 } // namespace colmap
static void Residuals(const std::vector< X_t > &points1, const std::vector< Y_t > &points2, const M_t &F, std::vector< double > *residuals)
static std::vector< M_t > Estimate(const std::vector< X_t > &points1, const std::vector< Y_t > &points2)
static void Residuals(const std::vector< X_t > &points1, const std::vector< Y_t > &points2, const M_t &F, std::vector< double > *residuals)
static std::vector< M_t > Estimate(const std::vector< X_t > &points1, const std::vector< Y_t > &points2)
coeffs(0)
const double * e
normal_z y
normal_z x
bool FindPolynomialRootsCompanionMatrix(const Eigen::VectorXd &coeffs_all, Eigen::VectorXd *real, Eigen::VectorXd *imag)
Definition: polynomial.cc:208
void CenterAndNormalizeImagePoints(const std::vector< Eigen::Vector2d > &points, std::vector< Eigen::Vector2d > *normed_points, Eigen::Matrix3d *matrix)
Definition: utils.cc:38
void ComputeSquaredSampsonError(const std::vector< Eigen::Vector2d > &points1, const std::vector< Eigen::Vector2d > &points2, const Eigen::Matrix3d &E, std::vector< double > *residuals)
Definition: utils.cc:87
Eigen::MatrixXd::Index Index
Definition: knncpp.h:26