23#include "ceres/ceres.h"
36 int first_row = (row + 1) % 3;
37 int second_row = (row + 2) % 3;
39 for (
int i = 0;
i < 4; ++
i) {
40 (*X)(0,
i) =
P(first_row,
i);
41 (*X)(1,
i) =
P(second_row,
i);
46 *P1 << Mat3::Identity(), Vec3::Zero();
48 Mat3 Ft =
F.transpose();
59 for (
int i = 0;
i < 3; ++
i) {
64 for (
int i = 0;
i < 3; ++
i) {
65 for (
int j = 0; j < 3; ++j) {
67 (*F)(
i, j) =
XY.determinant();
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);
86 A(
i, 3) = x2(1,
i) * x1(0,
i);
87 A(
i, 4) = x2(1,
i) * x1(1,
i);
95 double smaller_singular_value =
Nullspace(&
A, &f);
97 return smaller_singular_value;
102 Eigen::JacobiSVD<Mat3> USV(*
F, Eigen::ComputeFullU | Eigen::ComputeFullV);
103 Vec3 d = USV.singularValues();
105 *
F = USV.matrixU() * d.asDiagonal() * USV.matrixV().transpose();
119 Mat x1_normalized, x2_normalized;
124 double smaller_singular_value =
129 *
F =
T2.transpose() * (*F) *
T1;
131 return smaller_singular_value;
138 std::vector<Mat3>*
F) {
149 Matrix<double, 7, 9>
A;
150 for (
int ii = 0; ii < 7; ++ii) {
151 A(ii, 0) = x1(0, ii) * x2(0, ii);
152 A(ii, 1) = x1(1, ii) * x2(0, ii);
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);
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);
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,
200 for (
int kk = 0; kk < num_roots; ++kk) {
201 F->push_back(F1 + roots[kk] * F2);
208 std::vector<Mat3>*
F) {
218 Mat x1_normalized, x2_normalized;
224 x1_normalized, x2_normalized, &(*
F));
226 for (
int k = 0; k <
F->size(); ++k) {
227 Mat3& Fmat = (*F)[k];
229 Fmat =
T2.transpose() * Fmat *
T1;
231 return smaller_singular_value;
236 if ((*F_normalized)(2, 2) < 0) {
242 Vec3 x(x1(0), x1(1), 1.0);
243 Vec3 y(x2(0), x2(1), 1.0);
246 Vec3 Ft_y =
F.transpose() *
y;
247 double y_F_x =
y.dot(F_x);
250 (F_x.head<2>().squaredNorm() + Ft_y.head<2>().squaredNorm());
254 Vec3 x(x1(0), x1(1), 1.0);
255 Vec3 y(x2(0), x2(1), 1.0);
258 Vec3 Ft_y =
F.transpose() *
y;
259 double y_F_x =
y.dot(F_x);
262 (1 / F_x.head<2>().squaredNorm() + 1 / Ft_y.head<2>().squaredNorm());
270 *E = K2.transpose() *
F * K1;
279 *
F = K2.inverse().transpose() * E * K1.inverse();
288 *
R = R2 * R1.transpose();
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();
311 if (
U.determinant() < 0) {
315 if (Vt.determinant() < 0) {
327 Mat3 U_Wt_Vt =
U *
W.transpose() * Vt;
337 (*ts)[1] = -
U.col(2);
339 (*ts)[3] = -
U.col(2);
343 const std::vector<Vec3>& ts,
357 for (
int i = 0;
i < 4; ++
i) {
358 const Mat3& R2 = Rs[
i];
359 const Vec3& t2 = ts[
i];
363 double d1 =
Depth(R1, t1,
X);
364 double d2 =
Depth(R2, t2,
X);
366 if (d1 > 0 && d2 > 0) {
380 std::vector<Mat3> Rs;
381 std::vector<Vec3> ts;
394 Eigen::JacobiSVD<Mat3> svd(
F, Eigen::ComputeFullU | Eigen::ComputeFullV);
398 double a = svd.singularValues()(0);
399 double b = svd.singularValues()(1);
400 double s = (a +
b) / 2.0;
402 LG <<
"Initial reconstruction's rotation is non-euclidean by "
403 << (((a -
b) / std::max(a,
b)) * 100)
404 <<
"%; singular values:" << svd.singularValues().transpose();
409 *E = svd.matrixU() * diag.asDiagonal() * svd.matrixV().transpose();
421class FundamentalSymmetricEpipolarCostFunctor {
423 FundamentalSymmetricEpipolarCostFunctor(
const Vec2&
x,
const Vec2&
y)
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;
431 Mat3 F(fundamental_parameters);
437 Vec3 Ft_y =
F.transpose() *
y;
438 T y_F_x =
y.dot(F_x);
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();
454class TerminationCheckingCallback :
public ceres::IterationCallback {
456 TerminationCheckingCallback(
const Mat& x1,
458 const EstimateFundamentalOptions&
options,
460 : options_(
options), x1_(x1), x2_(x2), F_(
F) {}
463 const ceres::IterationSummary& summary) {
465 if (!summary.step_is_successful) {
466 return ceres::SOLVER_CONTINUE;
470 double average_distance = 0.0;
471 for (
int i = 0;
i < x1_.cols();
i++) {
474 average_distance /= x1_.cols();
476 if (average_distance <= options_.expected_average_symmetric_distance) {
477 return ceres::SOLVER_TERMINATE_SUCCESSFULLY;
480 return ceres::SOLVER_CONTINUE;
484 const EstimateFundamentalOptions& options_;
502 LG <<
"Estimated matrix after algebraic estimation:\n" << *
F;
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));
511 problem.AddResidualBlock(
512 new ceres::AutoDiffCostFunction<FundamentalSymmetricEpipolarCostFunctor,
515 fundamental_symmetric_epipolar_cost_function),
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;
527 TerminationCheckingCallback callback(x1, x2,
options,
F);
528 solver_options.callbacks.push_back(&callback);
531 ceres::Solver::Summary summary;
532 ceres::Solve(solver_options, &problem, &summary);
534 VLOG(1) <<
"Summary:\n" << summary.FullReport();
536 LG <<
"Final refined matrix:\n" << *
F;
538 return summary.IsSolutionUsable();
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
CCL_NAMESPACE_BEGIN struct Options options
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)
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)
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)
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)
Eigen::Matrix< double, 3, 3 > Mat3
void TriangulateDLT(const Mat34 &P1, const Vec2 &x1, const Mat34 &P2, const Vec2 &x2, Vec4 *X_homogeneous)
void EnforceFundamentalRank2Constraint(Mat3 *F)
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
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)
static double EightPointSolver(const Mat &x1, const Mat &x2, Mat3 *F)
double FrobeniusNorm(const TMat &A)
double SymmetricEpipolarDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2)
void FundamentalToEssential(const Mat3 &F, Mat3 *E)
Eigen::Matrix< double, 9, 1 > Vec9
double FundamentalFromCorrespondences7Point(const Mat &x1, const Mat &x2, std::vector< Mat3 > *F)
double Nullspace2(TMat *A, TVec1 *x1, TVec2 *x2)
void P_From_KRt(const Mat3 &K, const Mat3 &R, const Vec3 &t, Mat34 *P)
double expected_average_symmetric_distance
EstimateFundamentalOptions(void)