1 // Copyright (c) 2010 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
21 // This file is part of OpenMVG, an Open Multiple View Geometry C++ library.
22
23 // Copyright (c) 2012, 2013 Pierre MOULON.
24
25 // This Source Code Form is subject to the terms of the Mozilla Public
26 // License, v. 2.0. If a copy of the MPL was not distributed with this
27 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
28
29 #include "openMVG/multiview/projection.hpp"
30 #include "openMVG/numeric/numeric.h"
31
32 namespace openMVG {
33
34 /// Compute P = K[R|t]
P_From_KRt(const Mat3 & K,const Mat3 & R,const Vec3 & t,Mat34 * P)35 void P_From_KRt(
36 const Mat3 &K, const Mat3 &R, const Vec3 &t, Mat34 *P) {
37 *P = K * HStack(R,t);
38 }
39
KRt_From_P(const Mat34 & P,Mat3 * Kp,Mat3 * Rp,Vec3 * tp)40 void KRt_From_P(const Mat34 &P, Mat3 *Kp, Mat3 *Rp, Vec3 *tp) {
41 // Decompose using the RQ decomposition HZ A4.1.1 pag.579.
42 Mat3 K = P.block(0, 0, 3, 3);
43
44 Mat3 Q;
45 Q.setIdentity();
46
47 // Set K(2,1) to zero.
48 if (K(2,1) != 0) {
49 double c = -K(2,2);
50 double s = K(2,1);
51 double l = std::hypot(c, s);
52 c /= l; s /= l;
53 Mat3 Qx;
54 Qx << 1, 0, 0,
55 0, c, -s,
56 0, s, c;
57 K = K * Qx;
58 Q = Qx.transpose() * Q;
59 }
60 // Set K(2,0) to zero.
61 if (K(2,0) != 0) {
62 double c = K(2,2);
63 double s = K(2,0);
64 double l = std::hypot(c, s);
65 c /= l; s /= l;
66 Mat3 Qy;
67 Qy << c, 0, s,
68 0, 1, 0,
69 -s, 0, c;
70 K = K * Qy;
71 Q = Qy.transpose() * Q;
72 }
73 // Set K(1,0) to zero.
74 if (K(1,0) != 0) {
75 double c = -K(1,1);
76 double s = K(1,0);
77 double l = std::hypot(c, s);
78 c /= l; s /= l;
79 Mat3 Qz;
80 Qz << c,-s, 0,
81 s, c, 0,
82 0, 0, 1;
83 K = K * Qz;
84 Q = Qz.transpose() * Q;
85 }
86
87 Mat3 R = Q;
88
89 //Mat3 H = P.block(0, 0, 3, 3);
90 // RQ decomposition
91 //Eigen::HouseholderQR<Mat3> qr(H);
92 //Mat3 K = qr.matrixQR().triangularView<Eigen::Upper>();
93 //Mat3 R = qr.householderQ();
94
95 // Ensure that the diagonal is positive and R determinant == 1.
96 if (K(2,2) < 0) {
97 K = -K;
98 R = -R;
99 }
100 if (K(1,1) < 0) {
101 Mat3 S;
102 S << 1, 0, 0,
103 0,-1, 0,
104 0, 0, 1;
105 K = K * S;
106 R = S * R;
107 }
108 if (K(0,0) < 0) {
109 Mat3 S;
110 S << -1, 0, 0,
111 0, 1, 0,
112 0, 0, 1;
113 K = K * S;
114 R = S * R;
115 }
116
117 // Compute translation.
118 Eigen::PartialPivLU<Mat3> lu(K);
119 Vec3 t = lu.solve(P.col(3));
120
121 if (R.determinant()<0) {
122 R = -R;
123 t = -t;
124 }
125
126 // scale K so that K(2,2) = 1
127 K = K / K(2,2);
128
129 *Kp = K;
130 *Rp = R;
131 *tp = t;
132 }
133
F_from_P(const Mat34 & P1,const Mat34 & P2)134 Mat3 F_from_P(const Mat34 & P1, const Mat34 & P2)
135 {
136 Mat3 F12;
137
138 using Mat24 = Eigen::Matrix<double, 2, 4>;
139 Mat24 X1 = P1.block<2, 4>(1, 0);
140 Mat24 X2; X2 << P1.row(2), P1.row(0);
141 Mat24 X3 = P1.block<2, 4>(0, 0);
142 Mat24 Y1 = P2.block<2, 4>(1, 0);
143 Mat24 Y2; Y2 << P2.row(2), P2.row(0);
144 Mat24 Y3 = P2.block<2, 4>(0, 0);
145
146
147 Mat4 X1Y1, X2Y1, X3Y1, X1Y2, X2Y2, X3Y2, X1Y3, X2Y3, X3Y3;
148 X1Y1 << X1, Y1; X2Y1 << X2, Y1; X3Y1 << X3, Y1;
149 X1Y2 << X1, Y2; X2Y2 << X2, Y2; X3Y2 << X3, Y2;
150 X1Y3 << X1, Y3; X2Y3 << X2, Y3; X3Y3 << X3, Y3;
151
152
153 F12 <<
154 X1Y1.determinant(), X2Y1.determinant(), X3Y1.determinant(),
155 X1Y2.determinant(), X2Y2.determinant(), X3Y2.determinant(),
156 X1Y3.determinant(), X2Y3.determinant(), X3Y3.determinant();
157
158 return F12;
159 }
160
Project(const Mat34 & P,const Vec3 & X)161 Vec2 Project(const Mat34 &P, const Vec3 &X) {
162 return Vec3(P * X.homogeneous()).hnormalized();
163 }
164
Project(const Mat34 & P,const Mat3X & X,Mat2X * x)165 void Project(const Mat34 &P, const Mat3X &X, Mat2X *x) {
166 x->resize(2, X.cols());
167 for (size_t c = 0; c < static_cast<size_t>(X.cols()); ++c) {
168 x->col(c) = Project(P, Vec3(X.col(c)));
169 }
170 }
171
Project(const Mat34 & P,const Mat4X & X,Mat2X * x)172 void Project(const Mat34 &P, const Mat4X &X, Mat2X *x) {
173 x->resize(2, X.cols());
174 for (Mat4X::Index c = 0; c < X.cols(); ++c) {
175 const Vec3 hx = P * X.col(c);
176 x->col(c) = hx.hnormalized();
177 }
178 }
179
Project(const Mat34 & P,const Mat3X & X)180 Mat2X Project(const Mat34 &P, const Mat3X &X) {
181 Mat2X x(2, X.cols());
182 Project(P, X, &x);
183 return x;
184 }
185
Project(const Mat34 & P,const Mat4X & X)186 Mat2X Project(const Mat34 &P, const Mat4X &X) {
187 Mat2X x(2, X.cols());
188 Project(P, X, &x);
189 return x;
190 }
191
Depth(const Mat3 & R,const Vec3 & t,const Vec3 & X)192 double Depth(const Mat3 &R, const Vec3 &t, const Vec3 &X) {
193 return (R*X)[2] + t[2];
194 }
195
196 /// Estimates the root mean square error (2D)
RootMeanSquareError(const Mat2X & x_image,const Mat4X & X_world,const Mat34 & P)197 double RootMeanSquareError(const Mat2X &x_image,
198 const Mat4X &X_world,
199 const Mat34 &P) {
200 const Mat2X::Index num_points = x_image.cols();
201 const Mat2X dx = Project(P, X_world) - x_image;
202 return std::sqrt(dx.squaredNorm() / num_points);
203 }
204
205 /// Estimates the root mean square error (2D)
RootMeanSquareError(const Mat2X & x_image,const Mat3X & X_world,const Mat3 & K,const Mat3 & R,const Vec3 & t)206 double RootMeanSquareError(const Mat2X &x_image,
207 const Mat3X &X_world,
208 const Mat3 &K,
209 const Mat3 &R,
210 const Vec3 &t) {
211 Mat34 P;
212 P_From_KRt(K, R, t, &P);
213 return RootMeanSquareError(x_image, X_world.colwise().homogeneous(), P);
214 }
215
216 } // namespace openMVG
217