Blender V5.0
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
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
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.
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
#define U
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
#define XY(_x, _y)
#define A
SIMD_FORCE_INLINE btVector3 operator()(const btVector3 &x) const
Return the transform of the vector.
Definition btTransform.h:90
CCL_NAMESPACE_BEGIN struct Options options
float[3][3] Mat3
Definition gpu_matrix.cc:28
#define LG
#define DCHECK_EQ(a, b)
Definition log.h:144
#define DCHECK_GE(a, b)
Definition log.h:142
#define Square(a, x, y)
#define T
#define F
#define R
#define T2
Definition md5.cpp:21
#define T1
Definition md5.cpp:20
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:161
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:421
Eigen::Matrix< double, 3, 3 > Mat3
Definition numeric.h:75
Eigen::Vector2d Vec2
Definition numeric.h:108
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:63
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:76
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:109
static double EightPointSolver(const Mat &x1, const Mat &x2, Mat3 *F)
double FrobeniusNorm(const TMat &A)
Definition numeric.h:276
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:115
double FundamentalFromCorrespondences7Point(const Mat &x1, const Mat &x2, std::vector< Mat3 > *F)
double Nullspace2(TMat *A, TVec1 *x1, TVec2 *x2)
Definition numeric.h:177
void P_From_KRt(const Mat3 &K, const Mat3 &R, const Vec3 &t, Mat34 *P)
Definition projection.cc:26
i
Definition text_draw.cc:230