Blender V4.3
fundamental.cc
Go to the documentation of this file.
1// Copyright (c) 2007, 2008 libmv authors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to
5// deal in the Software without restriction, including without limitation the
6// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7// sell copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19// IN THE SOFTWARE.
20
22
23#include "ceres/ceres.h"
29#include "libmv/numeric/poly.h"
30
31namespace libmv {
32
33static void EliminateRow(const Mat34& P, int row, Mat* X) {
34 X->resize(2, 4);
35
36 int first_row = (row + 1) % 3;
37 int second_row = (row + 2) % 3;
38
39 for (int i = 0; i < 4; ++i) {
40 (*X)(0, i) = P(first_row, i);
41 (*X)(1, i) = P(second_row, i);
42 }
43}
44
45void ProjectionsFromFundamental(const Mat3& F, Mat34* P1, Mat34* P2) {
46 *P1 << Mat3::Identity(), Vec3::Zero();
47 Vec3 e2;
48 Mat3 Ft = F.transpose();
49 Nullspace(&Ft, &e2);
50 *P2 << CrossProductMatrix(e2) * F, e2;
51}
52
53// Addapted from vgg_F_from_P.
54void FundamentalFromProjections(const Mat34& P1, const Mat34& P2, Mat3* F) {
55 Mat X[3];
56 Mat Y[3];
57 Mat XY;
58
59 for (int i = 0; i < 3; ++i) {
60 EliminateRow(P1, i, X + i);
61 EliminateRow(P2, i, Y + i);
62 }
63
64 for (int i = 0; i < 3; ++i) {
65 for (int j = 0; j < 3; ++j) {
66 VerticalStack(X[j], Y[i], &XY);
67 (*F)(i, j) = XY.determinant();
68 }
69 }
70}
71
72// HZ 11.1 pag.279 (x1 = x, x2 = x')
73// http://www.cs.unc.edu/~marc/tutorial/node54.html
74static double EightPointSolver(const Mat& x1, const Mat& x2, Mat3* F) {
75 DCHECK_EQ(x1.rows(), 2);
76 DCHECK_GE(x1.cols(), 8);
77 DCHECK_EQ(x1.rows(), x2.rows());
78 DCHECK_EQ(x1.cols(), x2.cols());
79
80 int n = x1.cols();
81 Mat A(n, 9);
82 for (int i = 0; i < n; ++i) {
83 A(i, 0) = x2(0, i) * x1(0, i);
84 A(i, 1) = x2(0, i) * x1(1, i);
85 A(i, 2) = x2(0, i);
86 A(i, 3) = x2(1, i) * x1(0, i);
87 A(i, 4) = x2(1, i) * x1(1, i);
88 A(i, 5) = x2(1, i);
89 A(i, 6) = x1(0, i);
90 A(i, 7) = x1(1, i);
91 A(i, 8) = 1;
92 }
93
94 Vec9 f;
95 double smaller_singular_value = Nullspace(&A, &f);
96 *F = Map<RMat3>(f.data());
97 return smaller_singular_value;
98}
99
100// HZ 11.1.1 pag.280
102 Eigen::JacobiSVD<Mat3> USV(*F, Eigen::ComputeFullU | Eigen::ComputeFullV);
103 Vec3 d = USV.singularValues();
104 d(2) = 0.0;
105 *F = USV.matrixU() * d.asDiagonal() * USV.matrixV().transpose();
106}
107
108// HZ 11.2 pag.281 (x1 = x, x2 = x')
109double NormalizedEightPointSolver(const Mat& x1, const Mat& x2, Mat3* F) {
110 DCHECK_EQ(x1.rows(), 2);
111 DCHECK_GE(x1.cols(), 8);
112 DCHECK_EQ(x1.rows(), x2.rows());
113 DCHECK_EQ(x1.cols(), x2.cols());
114
115 // Normalize the data.
116 Mat3 T1, T2;
119 Mat x1_normalized, x2_normalized;
120 ApplyTransformationToPoints(x1, T1, &x1_normalized);
121 ApplyTransformationToPoints(x2, T2, &x2_normalized);
122
123 // Estimate the fundamental matrix.
124 double smaller_singular_value =
125 EightPointSolver(x1_normalized, x2_normalized, F);
127
128 // Denormalize the fundamental matrix.
129 *F = T2.transpose() * (*F) * T1;
130
131 return smaller_singular_value;
132}
133
134// Seven-point algorithm.
135// http://www.cs.unc.edu/~marc/tutorial/node55.html
137 const Mat& x2,
138 std::vector<Mat3>* F) {
139 DCHECK_EQ(x1.rows(), 2);
140 DCHECK_EQ(x1.cols(), 7);
141 DCHECK_EQ(x1.rows(), x2.rows());
142 DCHECK_EQ(x2.cols(), x2.cols());
143
144 // Build a 9 x n matrix from point matches, where each row is equivalent to
145 // the equation x'T*F*x = 0 for a single correspondence pair (x', x). The
146 // domain of the matrix is a 9 element vector corresponding to F. The
147 // nullspace should be rank two; the two dimensions correspond to the set of
148 // F matrices satisfying the epipolar geometry.
149 Matrix<double, 7, 9> A;
150 for (int ii = 0; ii < 7; ++ii) {
151 A(ii, 0) = x1(0, ii) * x2(0, ii); // 0 represents x coords,
152 A(ii, 1) = x1(1, ii) * x2(0, ii); // 1 represents y coords.
153 A(ii, 2) = x2(0, ii);
154 A(ii, 3) = x1(0, ii) * x2(1, ii);
155 A(ii, 4) = x1(1, ii) * x2(1, ii);
156 A(ii, 5) = x2(1, ii);
157 A(ii, 6) = x1(0, ii);
158 A(ii, 7) = x1(1, ii);
159 A(ii, 8) = 1.0;
160 }
161
162 // Find the two F matrices in the nullspace of A.
163 Vec9 f1, f2;
164 double s = Nullspace2(&A, &f1, &f2);
165 Mat3 F1 = Map<RMat3>(f1.data());
166 Mat3 F2 = Map<RMat3>(f2.data());
167
168 // Then, use the condition det(F) = 0 to determine F. In other words, solve
169 // det(F1 + a*F2) = 0 for a.
170 double a = F1(0, 0), j = F2(0, 0);
171 double b = F1(0, 1), k = F2(0, 1);
172 double c = F1(0, 2), l = F2(0, 2);
173 double d = F1(1, 0), m = F2(1, 0);
174 double e = F1(1, 1), n = F2(1, 1);
175 double f = F1(1, 2), o = F2(1, 2);
176 double g = F1(2, 0), p = F2(2, 0);
177 double h = F1(2, 1), q = F2(2, 1);
178 double i = F1(2, 2), r = F2(2, 2);
179
180 // Run fundamental_7point_coeffs.py to get the below coefficients.
181 // The coefficients are in ascending powers of alpha, i.e. P[N]*x^N.
182 double P[4] = {
183 a * e * i + b * f * g + c * d * h - a * f * h - b * d * i - c * e * g,
184 a * e * r + a * i * n + b * f * p + b * g * o + c * d * q + c * h * m +
185 d * h * l + e * i * j + f * g * k - a * f * q - a * h * o -
186 b * d * r - b * i * m - c * e * p - c * g * n - d * i * k -
187 e * g * l - f * h * j,
188 a * n * r + b * o * p + c * m * q + d * l * q + e * j * r + f * k * p +
189 g * k * o + h * l * m + i * j * n - a * o * q - b * m * r -
190 c * n * p - d * k * r - e * l * p - f * j * q - g * l * n -
191 h * j * o - i * k * m,
192 j * n * r + k * o * p + l * m * q - j * o * q - k * m * r - l * n * p,
193 };
194
195 // Solve for the roots of P[3]*x^3 + P[2]*x^2 + P[1]*x + P[0] = 0.
196 double roots[3];
197 int num_roots = SolveCubicPolynomial(P, roots);
198
199 // Build the fundamental matrix for each solution.
200 for (int kk = 0; kk < num_roots; ++kk) {
201 F->push_back(F1 + roots[kk] * F2);
202 }
203 return s;
204}
205
207 const Mat& x2,
208 std::vector<Mat3>* F) {
209 DCHECK_EQ(x1.rows(), 2);
210 DCHECK_GE(x1.cols(), 7);
211 DCHECK_EQ(x1.rows(), x2.rows());
212 DCHECK_EQ(x1.cols(), x2.cols());
213
214 // Normalize the data.
215 Mat3 T1, T2;
218 Mat x1_normalized, x2_normalized;
219 ApplyTransformationToPoints(x1, T1, &x1_normalized);
220 ApplyTransformationToPoints(x2, T2, &x2_normalized);
221
222 // Estimate the fundamental matrix.
223 double smaller_singular_value = FundamentalFrom7CorrespondencesLinear(
224 x1_normalized, x2_normalized, &(*F));
225
226 for (int k = 0; k < F->size(); ++k) {
227 Mat3& Fmat = (*F)[k];
228 // Denormalize the fundamental matrix.
229 Fmat = T2.transpose() * Fmat * T1;
230 }
231 return smaller_singular_value;
232}
233
234void NormalizeFundamental(const Mat3& F, Mat3* F_normalized) {
235 *F_normalized = F / FrobeniusNorm(F);
236 if ((*F_normalized)(2, 2) < 0) {
237 *F_normalized *= -1;
238 }
239}
240
241double SampsonDistance(const Mat& F, const Vec2& x1, const Vec2& x2) {
242 Vec3 x(x1(0), x1(1), 1.0);
243 Vec3 y(x2(0), x2(1), 1.0);
244
245 Vec3 F_x = F * x;
246 Vec3 Ft_y = F.transpose() * y;
247 double y_F_x = y.dot(F_x);
248
249 return Square(y_F_x) /
250 (F_x.head<2>().squaredNorm() + Ft_y.head<2>().squaredNorm());
251}
252
253double SymmetricEpipolarDistance(const Mat& F, const Vec2& x1, const Vec2& x2) {
254 Vec3 x(x1(0), x1(1), 1.0);
255 Vec3 y(x2(0), x2(1), 1.0);
256
257 Vec3 F_x = F * x;
258 Vec3 Ft_y = F.transpose() * y;
259 double y_F_x = y.dot(F_x);
260
261 return Square(y_F_x) *
262 (1 / F_x.head<2>().squaredNorm() + 1 / Ft_y.head<2>().squaredNorm());
263}
264
265// HZ 9.6 pag 257 (formula 9.12)
267 const Mat3& K1,
268 const Mat3& K2,
269 Mat3* E) {
270 *E = K2.transpose() * F * K1;
271}
272
273// HZ 9.6 pag 257 (formula 9.12)
274// Or http://ai.stanford.edu/~birch/projective/node20.html
276 const Mat3& K1,
277 const Mat3& K2,
278 Mat3* F) {
279 *F = K2.inverse().transpose() * E * K1.inverse();
280}
281
283 const Vec3& t1,
284 const Mat3& R2,
285 const Vec3& t2,
286 Mat3* R,
287 Vec3* t) {
288 *R = R2 * R1.transpose();
289 *t = t2 - (*R) * t1;
290}
291
292// HZ 9.6 pag 257
294 const Mat3& R1, const Vec3& t1, const Mat3& R2, const Vec3& t2, Mat3* E) {
295 Mat3 R;
296 Vec3 t;
297 RelativeCameraMotion(R1, t1, R2, t2, &R, &t);
298 Mat3 Tx = CrossProductMatrix(t);
299 *E = Tx * R;
300}
301
302// HZ 9.6 pag 259 (Result 9.19)
304 std::vector<Mat3>* Rs,
305 std::vector<Vec3>* ts) {
306 Eigen::JacobiSVD<Mat3> USV(E, Eigen::ComputeFullU | Eigen::ComputeFullV);
307 Mat3 U = USV.matrixU();
308 Mat3 Vt = USV.matrixV().transpose();
309
310 // Last column of U is undetermined since d = (a a 0).
311 if (U.determinant() < 0) {
312 U.col(2) *= -1;
313 }
314 // Last row of Vt is undetermined since d = (a a 0).
315 if (Vt.determinant() < 0) {
316 Vt.row(2) *= -1;
317 }
318
319 Mat3 W;
320 // clang-format off
321 W << 0, -1, 0,
322 1, 0, 0,
323 0, 0, 1;
324 // clang-format on
325
326 Mat3 U_W_Vt = U * W * Vt;
327 Mat3 U_Wt_Vt = U * W.transpose() * Vt;
328
329 Rs->resize(4);
330 (*Rs)[0] = U_W_Vt;
331 (*Rs)[1] = U_W_Vt;
332 (*Rs)[2] = U_Wt_Vt;
333 (*Rs)[3] = U_Wt_Vt;
334
335 ts->resize(4);
336 (*ts)[0] = U.col(2);
337 (*ts)[1] = -U.col(2);
338 (*ts)[2] = U.col(2);
339 (*ts)[3] = -U.col(2);
340}
341
342int MotionFromEssentialChooseSolution(const std::vector<Mat3>& Rs,
343 const std::vector<Vec3>& ts,
344 const Mat3& K1,
345 const Vec2& x1,
346 const Mat3& K2,
347 const Vec2& x2) {
348 DCHECK_EQ(4, Rs.size());
349 DCHECK_EQ(4, ts.size());
350
351 Mat34 P1, P2;
352 Mat3 R1;
353 Vec3 t1;
354 R1.setIdentity();
355 t1.setZero();
356 P_From_KRt(K1, R1, t1, &P1);
357 for (int i = 0; i < 4; ++i) {
358 const Mat3& R2 = Rs[i];
359 const Vec3& t2 = ts[i];
360 P_From_KRt(K2, R2, t2, &P2);
361 Vec3 X;
362 TriangulateDLT(P1, x1, P2, x2, &X);
363 double d1 = Depth(R1, t1, X);
364 double d2 = Depth(R2, t2, X);
365 // Test if point is front to the two cameras.
366 if (d1 > 0 && d2 > 0) {
367 return i;
368 }
369 }
370 return -1;
371}
372
374 const Mat3& K1,
375 const Vec2& x1,
376 const Mat3& K2,
377 const Vec2& x2,
378 Mat3* R,
379 Vec3* t) {
380 std::vector<Mat3> Rs;
381 std::vector<Vec3> ts;
382 MotionFromEssential(E, &Rs, &ts);
383 int solution = MotionFromEssentialChooseSolution(Rs, ts, K1, x1, K2, x2);
384 if (solution >= 0) {
385 *R = Rs[solution];
386 *t = ts[solution];
387 return true;
388 } else {
389 return false;
390 }
391}
392
393void FundamentalToEssential(const Mat3& F, Mat3* E) {
394 Eigen::JacobiSVD<Mat3> svd(F, Eigen::ComputeFullU | Eigen::ComputeFullV);
395
396 // See Hartley & Zisserman page 294, result 11.1, which shows how to get the
397 // closest essential matrix to a matrix that is "almost" an essential matrix.
398 double a = svd.singularValues()(0);
399 double b = svd.singularValues()(1);
400 double s = (a + b) / 2.0;
401
402 LG << "Initial reconstruction's rotation is non-euclidean by "
403 << (((a - b) / std::max(a, b)) * 100)
404 << "%; singular values:" << svd.singularValues().transpose();
405
406 Vec3 diag;
407 diag << s, s, 0;
408
409 *E = svd.matrixU() * diag.asDiagonal() * svd.matrixV().transpose();
410}
411
412// Default settings for fundamental estimation which should be suitable
413// for a wide range of use cases.
415 : max_num_iterations(50), expected_average_symmetric_distance(1e-16) {
416}
417
418namespace {
419// Cost functor which computes symmetric epipolar distance
420// used for fundamental matrix refinement.
421class FundamentalSymmetricEpipolarCostFunctor {
422 public:
423 FundamentalSymmetricEpipolarCostFunctor(const Vec2& x, const Vec2& y)
424 : x_(x), y_(y) {}
425
426 template <typename T>
427 bool operator()(const T* fundamental_parameters, T* residuals) const {
428 typedef Eigen::Matrix<T, 3, 3> Mat3;
429 typedef Eigen::Matrix<T, 3, 1> Vec3;
430
431 Mat3 F(fundamental_parameters);
432
433 Vec3 x(T(x_(0)), T(x_(1)), T(1.0));
434 Vec3 y(T(y_(0)), T(y_(1)), T(1.0));
435
436 Vec3 F_x = F * x;
437 Vec3 Ft_y = F.transpose() * y;
438 T y_F_x = y.dot(F_x);
439
440 residuals[0] = y_F_x * T(1) / F_x.head(2).norm();
441 residuals[1] = y_F_x * T(1) / Ft_y.head(2).norm();
442
443 return true;
444 }
445
446 const Mat x_;
447 const Mat y_;
448};
449
450// Termination checking callback used for fundamental estimation.
451// It finished the minimization as soon as actual average of
452// symmetric epipolar distance is less or equal to the expected
453// average value.
454class TerminationCheckingCallback : public ceres::IterationCallback {
455 public:
456 TerminationCheckingCallback(const Mat& x1,
457 const Mat& x2,
458 const EstimateFundamentalOptions& options,
459 Mat3* F)
460 : options_(options), x1_(x1), x2_(x2), F_(F) {}
461
462 virtual ceres::CallbackReturnType operator()(
463 const ceres::IterationSummary& summary) {
464 // If the step wasn't successful, there's nothing to do.
465 if (!summary.step_is_successful) {
466 return ceres::SOLVER_CONTINUE;
467 }
468
469 // Calculate average of symmetric epipolar distance.
470 double average_distance = 0.0;
471 for (int i = 0; i < x1_.cols(); i++) {
472 average_distance = SymmetricEpipolarDistance(*F_, x1_.col(i), x2_.col(i));
473 }
474 average_distance /= x1_.cols();
475
476 if (average_distance <= options_.expected_average_symmetric_distance) {
477 return ceres::SOLVER_TERMINATE_SUCCESSFULLY;
478 }
479
480 return ceres::SOLVER_CONTINUE;
481 }
482
483 private:
484 const EstimateFundamentalOptions& options_;
485 const Mat& x1_;
486 const Mat& x2_;
487 Mat3* F_;
488};
489} // namespace
490
491/* Fundamental transformation estimation. */
493 const Mat& x1,
494 const Mat& x2,
496 Mat3* F) {
497 // Step 1: Algebraic fundamental estimation.
498
499 // Assume algebraic estiation always succeeds,
501
502 LG << "Estimated matrix after algebraic estimation:\n" << *F;
503
504 // Step 2: Refine matrix using Ceres minimizer.
505 ceres::Problem problem;
506 for (int i = 0; i < x1.cols(); i++) {
507 FundamentalSymmetricEpipolarCostFunctor*
508 fundamental_symmetric_epipolar_cost_function =
509 new FundamentalSymmetricEpipolarCostFunctor(x1.col(i), x2.col(i));
510
511 problem.AddResidualBlock(
512 new ceres::AutoDiffCostFunction<FundamentalSymmetricEpipolarCostFunctor,
513 2, // num_residuals
514 9>(
515 fundamental_symmetric_epipolar_cost_function),
516 NULL,
517 F->data());
518 }
519
520 // Configure the solve.
521 ceres::Solver::Options solver_options;
522 solver_options.linear_solver_type = ceres::DENSE_QR;
523 solver_options.max_num_iterations = options.max_num_iterations;
524 solver_options.update_state_every_iteration = true;
525
526 // Terminate if the average symmetric distance is good enough.
527 TerminationCheckingCallback callback(x1, x2, options, F);
528 solver_options.callbacks.push_back(&callback);
529
530 // Run the solve.
531 ceres::Solver::Summary summary;
532 ceres::Solve(solver_options, &problem, &summary);
533
534 VLOG(1) << "Summary:\n" << summary.FullReport();
535
536 LG << "Final refined matrix:\n" << *F;
537
538 return summary.IsSolutionUsable();
539}
540
541} // namespace libmv
#define X
#define Y
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Map
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
#define XY(_x, _y)
#define A
unsigned int U
Definition btGjkEpa3.h:78
SIMD_FORCE_INLINE btVector3 operator()(const btVector3 &x) const
Return the transform of the vector.
Definition btTransform.h:90
local_group_size(16, 16) .push_constant(Type b
CCL_NAMESPACE_BEGIN struct Options options
DEGForeachIDComponentCallback callback
#define NULL
const Mat y_
const Mat x_
float[3][3] Mat3
Definition gpu_matrix.cc:28
#define LG
#define VLOG(severity)
Definition log.h:34
#define DCHECK_EQ(a, b)
Definition log.h:59
#define DCHECK_GE(a, b)
Definition log.h:57
#define Square(a, x, y)
#define T
#define F
#define R
#define T2
Definition md5.cpp:19
#define T1
Definition md5.cpp:18
double FundamentalFrom7CorrespondencesLinear(const Mat &x1, const Mat &x2, std::vector< Mat3 > *F)
int SolveCubicPolynomial(Real a, Real b, Real c, Real *x0, Real *x1, Real *x2)
Definition poly.h:40
void EssentialFromRt(const Mat3 &R1, const Vec3 &t1, const Mat3 &R2, const Vec3 &t2, Mat3 *E)
double SampsonDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2)
double Nullspace(TMat *A, TVec *nullspace)
Definition numeric.h:158
void FundamentalFromEssential(const Mat3 &E, const Mat3 &K1, const Mat3 &K2, Mat3 *F)
void FundamentalFromProjections(const Mat34 &P1, const Mat34 &P2, Mat3 *F)
bool EstimateFundamentalFromCorrespondences(const Mat &x1, const Mat &x2, const EstimateFundamentalOptions &options, Mat3 *F)
Mat3 CrossProductMatrix(const Vec3 &x)
Definition numeric.cc:80
static void EliminateRow(const Mat34 &P, int row, Mat *X)
void PreconditionerFromPoints(const Mat &points, Mat3 *T)
void VerticalStack(const TTop &top, const TBot &bottom, TStacked *stacked)
Definition numeric.h:418
Eigen::Matrix< double, 3, 3 > Mat3
Definition numeric.h:72
Eigen::Vector2d Vec2
Definition numeric.h:105
void TriangulateDLT(const Mat34 &P1, const Vec2 &x1, const Mat34 &P2, const Vec2 &x2, Vec4 *X_homogeneous)
void EnforceFundamentalRank2Constraint(Mat3 *F)
Eigen::MatrixXd Mat
Definition numeric.h:60
double Depth(const Mat3 &R, const Vec3 &t, const Vec3 &X)
void ProjectionsFromFundamental(const Mat3 &F, Mat34 *P1, Mat34 *P2)
void MotionFromEssential(const Mat3 &E, std::vector< Mat3 > *Rs, std::vector< Vec3 > *ts)
bool MotionFromEssentialAndCorrespondence(const Mat3 &E, const Mat3 &K1, const Vec2 &x1, const Mat3 &K2, const Vec2 &x2, Mat3 *R, Vec3 *t)
Eigen::Matrix< double, 3, 4 > Mat34
Definition numeric.h:73
void NormalizeFundamental(const Mat3 &F, Mat3 *F_normalized)
void ApplyTransformationToPoints(const Mat &points, const Mat3 &T, Mat *transformed_points)
int MotionFromEssentialChooseSolution(const std::vector< Mat3 > &Rs, const std::vector< Vec3 > &ts, const Mat3 &K1, const Vec2 &x1, const Mat3 &K2, const Vec2 &x2)
void EssentialFromFundamental(const Mat3 &F, const Mat3 &K1, const Mat3 &K2, Mat3 *E)
double NormalizedEightPointSolver(const Mat &x1, const Mat &x2, Mat3 *F)
void RelativeCameraMotion(const Mat3 &R1, const Vec3 &t1, const Mat3 &R2, const Vec3 &t2, Mat3 *R, Vec3 *t)
Eigen::Vector3d Vec3
Definition numeric.h:106
static double EightPointSolver(const Mat &x1, const Mat &x2, Mat3 *F)
double FrobeniusNorm(const TMat &A)
Definition numeric.h:273
double SymmetricEpipolarDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2)
void FundamentalToEssential(const Mat3 &F, Mat3 *E)
Eigen::Matrix< double, 9, 1 > Vec9
Definition numeric.h:112
double FundamentalFromCorrespondences7Point(const Mat &x1, const Mat &x2, std::vector< Mat3 > *F)
double Nullspace2(TMat *A, TVec1 *x1, TVec2 *x2)
Definition numeric.h:174
void P_From_KRt(const Mat3 &K, const Mat3 &R, const Vec3 &t, Mat34 *P)
Definition projection.cc:26