ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
generalized_relative_pose.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 
32 // Note that part of this code is licensed under the following conditions.
33 // Author: Laurent Kneip
34 // Contact: kneip.laurent@gmail.com
35 // License: Copyright (c) 2013 Laurent Kneip, ANU. All rights reserved.
36 //
37 // Redistribution and use in source and binary forms, with or without
38 // modification, are permitted provided that the following conditions are met:
39 // * Redistributions of source code must retain the above copyright
40 // notice, this list of conditions and the following disclaimer.
41 // * Redistributions in binary form must reproduce the above copyright
42 // notice, this list of conditions and the following disclaimer in the
43 // documentation and/or other materials provided with the distribution.
44 // * Neither the name of ANU nor the names of its contributors may be
45 // used to endorse or promote products derived from this software without
46 // specific prior written permission.
47 //
48 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
49 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 // ARE DISCLAIMED. IN NO EVENT SHALL ANU OR THE CONTRIBUTORS BE LIABLE FOR ANY
52 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
53 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
54 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
55 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
56 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
57 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
58 
60 
61 #include "base/essential_matrix.h"
62 #include "base/pose.h"
63 #include "base/projection.h"
64 #include "base/triangulation.h"
65 #include "util/logging.h"
66 #include "util/random.h"
67 
68 namespace colmap {
69 namespace {
70 
71 void ComposePlueckerData(const Eigen::Matrix3x4d& rel_tform,
72  const Eigen::Vector2d& point2D,
73  Eigen::Vector3d* proj_center,
74  Eigen::Vector6d* pluecker) {
75  const Eigen::Matrix3x4d inv_proj_matrix = InvertProjectionMatrix(rel_tform);
76  const Eigen::Vector3d bearing =
77  inv_proj_matrix.leftCols<3>() * point2D.homogeneous();
78  const Eigen::Vector3d bearing_normalized = bearing.normalized();
79  *proj_center = inv_proj_matrix.rightCols<1>();
80  *pluecker << bearing_normalized, proj_center->cross(bearing_normalized);
81 }
82 
83 Eigen::Matrix3d CayleyToRotationMatrix(const Eigen::Vector3d& cayley) {
84  const double cayley0_sqr = cayley[0] * cayley[0];
85  const double cayley1_sqr = cayley[1] * cayley[1];
86  const double cayley2_sqr = cayley[2] * cayley[2];
87  const double cayley01 = cayley[0] * cayley[1];
88  const double cayley12 = cayley[1] * cayley[2];
89  const double cayley02 = cayley[0] * cayley[2];
90 
91  const double scale = 1 + cayley0_sqr + cayley1_sqr + cayley2_sqr;
92  const double inv_scale = 1.0 / scale;
93 
94  Eigen::Matrix3d R;
95 
96  R(0, 0) = inv_scale * (1 + cayley0_sqr - cayley1_sqr - cayley2_sqr);
97  R(0, 1) = inv_scale * (2 * (cayley01 - cayley[2]));
98  R(0, 2) = inv_scale * (2 * (cayley02 + cayley[1]));
99  R(1, 0) = inv_scale * (2 * (cayley01 + cayley[2]));
100  R(1, 1) = inv_scale * (1 - cayley0_sqr + cayley1_sqr - cayley2_sqr);
101  R(1, 2) = inv_scale * (2 * (cayley12 - cayley[0]));
102  R(2, 0) = inv_scale * (2 * (cayley02 - cayley[1]));
103  R(2, 1) = inv_scale * (2 * (cayley12 + cayley[0]));
104  R(2, 2) = inv_scale * (1 - cayley0_sqr - cayley1_sqr + cayley2_sqr);
105 
106  return R;
107 }
108 
109 Eigen::Vector3d RotationMatrixToCaley(const Eigen::Matrix3d& R) {
110  const Eigen::Matrix3d C1 = R - Eigen::Matrix3d::Identity();
111  const Eigen::Matrix3d C2 = R + Eigen::Matrix3d::Identity();
112  const Eigen::Matrix3d C = C1 * C2.inverse();
113  return Eigen::Vector3d(-C(1, 2), C(0, 2), -C(0, 1));
114 }
115 
116 Eigen::Vector3d ComputeRotationBetweenPoints(
117  const std::vector<Eigen::Vector6d>& plueckers1,
118  const std::vector<Eigen::Vector6d>& plueckers2) {
119  CHECK_EQ(plueckers1.size(), plueckers2.size());
120 
121  // Compute the center of all observed points.
122  Eigen::Vector3d points_center1 = Eigen::Vector3d::Zero();
123  Eigen::Vector3d points_center2 = Eigen::Vector3d::Zero();
124  for (size_t i = 0; i < plueckers1.size(); i++) {
125  points_center1 += plueckers1[i].head<3>();
126  points_center2 += plueckers2[i].head<3>();
127  }
128  points_center1 = points_center1 / plueckers1.size();
129  points_center2 = points_center2 / plueckers1.size();
130 
131  Eigen::Matrix3d Hcross = Eigen::Matrix3d::Zero();
132  for (size_t i = 0; i < plueckers1.size(); i++) {
133  const Eigen::Vector3d f1 = plueckers1[i].head<3>() - points_center1;
134  const Eigen::Vector3d f2 = plueckers2[i].head<3>() - points_center2;
135  Hcross += f2 * f1.transpose();
136  }
137 
138  const Eigen::JacobiSVD<Eigen::Matrix3d> svd(
139  Hcross, Eigen::ComputeFullU | Eigen::ComputeFullV);
140  const Eigen::Matrix3d V = svd.matrixV();
141  const Eigen::Matrix3d U = svd.matrixU();
142 
143  Eigen::Matrix3d R = V * U.transpose();
144  if (R.determinant() < 0) {
145  Eigen::Matrix3d V_prime;
146  V_prime.col(0) = V.col(0);
147  V_prime.col(1) = V.col(1);
148  V_prime.col(2) = -V.col(2);
149  R = V_prime * U.transpose();
150  }
151 
152  return RotationMatrixToCaley(R);
153 }
154 
155 Eigen::Matrix4d ComposeG(const Eigen::Matrix3d& xxF, const Eigen::Matrix3d& yyF,
156  const Eigen::Matrix3d& zzF, const Eigen::Matrix3d& xyF,
157  const Eigen::Matrix3d& yzF, const Eigen::Matrix3d& zxF,
158  const Eigen::Matrix<double, 3, 9>& x1P,
159  const Eigen::Matrix<double, 3, 9>& y1P,
160  const Eigen::Matrix<double, 3, 9>& z1P,
161  const Eigen::Matrix<double, 3, 9>& x2P,
162  const Eigen::Matrix<double, 3, 9>& y2P,
163  const Eigen::Matrix<double, 3, 9>& z2P,
164  const Eigen::Matrix<double, 9, 9>& m11P,
165  const Eigen::Matrix<double, 9, 9>& m12P,
166  const Eigen::Matrix<double, 9, 9>& m22P,
167  const Eigen::Vector3d& rotation) {
168  const Eigen::Matrix3d R = CayleyToRotationMatrix(rotation);
169 
170  Eigen::Matrix<double, 1, 9> R_rows;
171  R_rows << R.row(0), R.row(1), R.row(2);
172 
173  Eigen::Matrix<double, 9, 1> R_cols;
174  R_cols << R.col(0), R.col(1), R.col(2);
175 
176  const Eigen::Vector3d xxFr1t = xxF * R.row(1).transpose();
177  const Eigen::Vector3d yyFr0t = yyF * R.row(0).transpose();
178  const Eigen::Vector3d zzFr0t = zzF * R.row(0).transpose();
179  const Eigen::Vector3d yzFr0t = yzF * R.row(0).transpose();
180  const Eigen::Vector3d xyFr1t = xyF * R.row(1).transpose();
181  const Eigen::Vector3d xyFr2t = xyF * R.row(2).transpose();
182  const Eigen::Vector3d zxFr1t = zxF * R.row(1).transpose();
183  const Eigen::Vector3d zxFr2t = zxF * R.row(2).transpose();
184 
185  const Eigen::Vector3d x1PC = x1P * R_cols;
186  const Eigen::Vector3d y1PC = y1P * R_cols;
187  const Eigen::Vector3d z1PC = z1P * R_cols;
188 
189  const Eigen::Vector3d x2PR = x2P * R_rows.transpose();
190  const Eigen::Vector3d y2PR = y2P * R_rows.transpose();
191  const Eigen::Vector3d z2PR = z2P * R_rows.transpose();
192 
193  Eigen::Matrix4d G;
194 
195  G(0, 0) = R.row(2) * yyF * R.row(2).transpose();
196  G(0, 0) += -2.0 * R.row(2) * yzF * R.row(1).transpose();
197  G(0, 0) += R.row(1) * zzF * R.row(1).transpose();
198 
199  G(0, 1) = R.row(2) * yzFr0t;
200  G(0, 1) += -1.0 * R.row(2) * xyFr2t;
201  G(0, 1) += -1.0 * R.row(1) * zzFr0t;
202  G(0, 1) += R.row(1) * zxFr2t;
203 
204  G(0, 2) = R.row(2) * xyFr1t;
205  G(0, 2) += -1.0 * R.row(2) * yyFr0t;
206  G(0, 2) += -1.0 * R.row(1) * zxFr1t;
207  G(0, 2) += R.row(1) * yzFr0t;
208 
209  G(1, 1) = R.row(0) * zzFr0t;
210  G(1, 1) += -2.0 * R.row(0) * zxFr2t;
211  G(1, 1) += R.row(2) * xxF * R.row(2).transpose();
212 
213  G(1, 2) = R.row(0) * zxFr1t;
214  G(1, 2) += -1.0 * R.row(0) * yzFr0t;
215  G(1, 2) += -1.0 * R.row(2) * xxFr1t;
216  G(1, 2) += R.row(0) * xyFr2t;
217 
218  G(2, 2) = R.row(1) * xxFr1t;
219  G(2, 2) += -2.0 * R.row(0) * xyFr1t;
220  G(2, 2) += R.row(0) * yyFr0t;
221 
222  G(1, 0) = G(0, 1);
223  G(2, 0) = G(0, 2);
224  G(2, 1) = G(1, 2);
225 
226  G(0, 3) = R.row(2) * y1PC;
227  G(0, 3) += R.row(2) * y2PR;
228  G(0, 3) += -1.0 * R.row(1) * z1PC;
229  G(0, 3) += -1.0 * R.row(1) * z2PR;
230 
231  G(1, 3) = R.row(0) * z1PC;
232  G(1, 3) += R.row(0) * z2PR;
233  G(1, 3) += -1.0 * R.row(2) * x1PC;
234  G(1, 3) += -1.0 * R.row(2) * x2PR;
235 
236  G(2, 3) = R.row(1) * x1PC;
237  G(2, 3) += R.row(1) * x2PR;
238  G(2, 3) += -1.0 * R.row(0) * y1PC;
239  G(2, 3) += -1.0 * R.row(0) * y2PR;
240 
241  G(3, 3) = -1.0 * R_cols.transpose() * m11P * R_cols;
242  G(3, 3) += -1.0 * R_rows * m22P * R_rows.transpose();
243  G(3, 3) += -2.0 * R_rows * m12P * R_cols;
244 
245  G(3, 0) = G(0, 3);
246  G(3, 1) = G(1, 3);
247  G(3, 2) = G(2, 3);
248 
249  return G;
250 }
251 
252 Eigen::Vector4d ComputeEigenValue(
253  const Eigen::Matrix3d& xxF, const Eigen::Matrix3d& yyF,
254  const Eigen::Matrix3d& zzF, const Eigen::Matrix3d& xyF,
255  const Eigen::Matrix3d& yzF, const Eigen::Matrix3d& zxF,
256  const Eigen::Matrix<double, 3, 9>& x1P,
257  const Eigen::Matrix<double, 3, 9>& y1P,
258  const Eigen::Matrix<double, 3, 9>& z1P,
259  const Eigen::Matrix<double, 3, 9>& x2P,
260  const Eigen::Matrix<double, 3, 9>& y2P,
261  const Eigen::Matrix<double, 3, 9>& z2P,
262  const Eigen::Matrix<double, 9, 9>& m11P,
263  const Eigen::Matrix<double, 9, 9>& m12P,
264  const Eigen::Matrix<double, 9, 9>& m22P, const Eigen::Vector3d& rotation) {
265  const Eigen::Matrix4d G =
266  ComposeG(xxF, yyF, zzF, xyF, yzF, zxF, x1P, y1P, z1P, x2P, y2P, z2P, m11P,
267  m12P, m22P, rotation);
268 
269  // Compute the roots in closed-form.
270  // const double G00_2 = G(0,0) * G(0,0);
271  const double G01_2 = G(0, 1) * G(0, 1);
272  const double G02_2 = G(0, 2) * G(0, 2);
273  const double G03_2 = G(0, 3) * G(0, 3);
274  // const double G11_2 = G(1,1) * G(1,1);
275  const double G12_2 = G(1, 2) * G(1, 2);
276  const double G13_2 = G(1, 3) * G(1, 3);
277  // const double G22_2 = G(2,2) * G(2,2);
278  const double G23_2 = G(2, 3) * G(2, 3);
279  // const double G33_2 = G(3,3) * G(3,3);
280 
281  const double B = -G(3, 3) - G(2, 2) - G(1, 1) - G(0, 0);
282  const double C = -G23_2 + G(2, 2) * G(3, 3) - G13_2 - G12_2 +
283  G(1, 1) * G(3, 3) + G(1, 1) * G(2, 2) - G03_2 - G02_2 -
284  G01_2 + G(0, 0) * G(3, 3) + G(0, 0) * G(2, 2) +
285  G(0, 0) * G(1, 1);
286  const double D =
287  G13_2 * G(2, 2) - 2.0 * G(1, 2) * G(1, 3) * G(2, 3) + G12_2 * G(3, 3) +
288  G(1, 1) * G23_2 - G(1, 1) * G(2, 2) * G(3, 3) + G03_2 * G(2, 2) +
289  G03_2 * G(1, 1) - 2.0 * G(0, 2) * G(0, 3) * G(2, 3) + G02_2 * G(3, 3) +
290  G02_2 * G(1, 1) - 2.0 * G(0, 1) * G(0, 3) * G(1, 3) -
291  2.0 * G(0, 1) * G(0, 2) * G(1, 2) + G01_2 * G(3, 3) + G01_2 * G(2, 2) +
292  G(0, 0) * G23_2 - G(0, 0) * G(2, 2) * G(3, 3) + G(0, 0) * G13_2 +
293  G(0, 0) * G12_2 - G(0, 0) * G(1, 1) * G(3, 3) -
294  G(0, 0) * G(1, 1) * G(2, 2);
295  const double E =
296  G03_2 * G12_2 - G03_2 * G(1, 1) * G(2, 2) -
297  2.0 * G(0, 2) * G(0, 3) * G(1, 2) * G(1, 3) +
298  2.0 * G(0, 2) * G(0, 3) * G(1, 1) * G(2, 3) + G02_2 * G13_2 -
299  G02_2 * G(1, 1) * G(3, 3) + 2.0 * G(0, 1) * G(0, 3) * G(1, 3) * G(2, 2) -
300  2.0 * G(0, 1) * G(0, 3) * G(1, 2) * G(2, 3) -
301  2.0 * G(0, 1) * G(0, 2) * G(1, 3) * G(2, 3) +
302  2.0 * G(0, 1) * G(0, 2) * G(1, 2) * G(3, 3) + G01_2 * G23_2 -
303  G01_2 * G(2, 2) * G(3, 3) - G(0, 0) * G13_2 * G(2, 2) +
304  2.0 * G(0, 0) * G(1, 2) * G(1, 3) * G(2, 3) - G(0, 0) * G12_2 * G(3, 3) -
305  G(0, 0) * G(1, 1) * G23_2 + G(0, 0) * G(1, 1) * G(2, 2) * G(3, 3);
306 
307  const double B_pw2 = B * B;
308  const double B_pw3 = B_pw2 * B;
309  const double B_pw4 = B_pw3 * B;
310  const double alpha = -0.375 * B_pw2 + C;
311  const double beta = B_pw3 / 8.0 - B * C / 2.0 + D;
312  const double gamma = -0.01171875 * B_pw4 + B_pw2 * C / 16.0 - B * D / 4.0 + E;
313  const double alpha_pw2 = alpha * alpha;
314  const double alpha_pw3 = alpha_pw2 * alpha;
315  const double p = -alpha_pw2 / 12.0 - gamma;
316  const double q = -alpha_pw3 / 108.0 + alpha * gamma / 3.0 - beta * beta / 8.0;
317  const double helper1 = -p * p * p / 27.0;
318  const double theta2 = pow(helper1, (1.0 / 3.0));
319  const double theta1 =
320  std::sqrt(theta2) *
321  std::cos((1.0 / 3.0) * std::acos((-q / 2.0) / std::sqrt(helper1)));
322  const double y = -(5.0 / 6.0) * alpha -
323  ((1.0 / 3.0) * p * theta1 - theta1 * theta2) / theta2;
324  const double w = std::sqrt(alpha + 2.0 * y);
325 
326  Eigen::Vector4d roots;
327  roots(0) = -B / 4.0 + 0.5 * w +
328  0.5 * std::sqrt(-3.0 * alpha - 2.0 * y - 2.0 * beta / w);
329  roots(1) = -B / 4.0 + 0.5 * w -
330  0.5 * std::sqrt(-3.0 * alpha - 2.0 * y - 2.0 * beta / w);
331  roots(2) = -B / 4.0 - 0.5 * w +
332  0.5 * std::sqrt(-3.0 * alpha - 2.0 * y + 2.0 * beta / w);
333  roots(3) = -B / 4.0 - 0.5 * w -
334  0.5 * std::sqrt(-3.0 * alpha - 2.0 * y + 2.0 * beta / w);
335  return roots;
336 }
337 
338 double ComputeCost(const Eigen::Matrix3d& xxF, const Eigen::Matrix3d& yyF,
339  const Eigen::Matrix3d& zzF, const Eigen::Matrix3d& xyF,
340  const Eigen::Matrix3d& yzF, const Eigen::Matrix3d& zxF,
341  const Eigen::Matrix<double, 3, 9>& x1P,
342  const Eigen::Matrix<double, 3, 9>& y1P,
343  const Eigen::Matrix<double, 3, 9>& z1P,
344  const Eigen::Matrix<double, 3, 9>& x2P,
345  const Eigen::Matrix<double, 3, 9>& y2P,
346  const Eigen::Matrix<double, 3, 9>& z2P,
347  const Eigen::Matrix<double, 9, 9>& m11P,
348  const Eigen::Matrix<double, 9, 9>& m12P,
349  const Eigen::Matrix<double, 9, 9>& m22P,
350  const Eigen::Vector3d& rotation, const int step) {
351  CHECK_GE(step, 0);
352  CHECK_LE(step, 1);
353 
354  const Eigen::Vector4d roots =
355  ComputeEigenValue(xxF, yyF, zzF, xyF, yzF, zxF, x1P, y1P, z1P, x2P, y2P,
356  z2P, m11P, m12P, m22P, rotation);
357 
358  if (step == 0) {
359  return roots[2];
360  } else if (step == 1) {
361  return roots[3];
362  }
363 
364  return 0;
365 }
366 
367 Eigen::Vector3d ComputeJacobian(
368  const Eigen::Matrix3d& xxF, const Eigen::Matrix3d& yyF,
369  const Eigen::Matrix3d& zzF, const Eigen::Matrix3d& xyF,
370  const Eigen::Matrix3d& yzF, const Eigen::Matrix3d& zxF,
371  const Eigen::Matrix<double, 3, 9>& x1P,
372  const Eigen::Matrix<double, 3, 9>& y1P,
373  const Eigen::Matrix<double, 3, 9>& z1P,
374  const Eigen::Matrix<double, 3, 9>& x2P,
375  const Eigen::Matrix<double, 3, 9>& y2P,
376  const Eigen::Matrix<double, 3, 9>& z2P,
377  const Eigen::Matrix<double, 9, 9>& m11P,
378  const Eigen::Matrix<double, 9, 9>& m12P,
379  const Eigen::Matrix<double, 9, 9>& m22P, const Eigen::Vector3d& rotation,
380  const double current_cost, const int step) {
381  Eigen::Vector3d jacobian;
382  const double kEpsilon = 0.00000001;
383  for (int j = 0; j < 3; j++) {
384  Eigen::Vector3d cayley_j = rotation;
385  cayley_j[j] += kEpsilon;
386  const double cost_j =
387  ComputeCost(xxF, yyF, zzF, xyF, yzF, zxF, x1P, y1P, z1P, x2P, y2P, z2P,
388  m11P, m12P, m22P, cayley_j, step);
389  jacobian(j) = cost_j - current_cost;
390  }
391  return jacobian;
392 }
393 
394 } // namespace
395 
396 std::vector<GR6PEstimator::M_t> GR6PEstimator::Estimate(
397  const std::vector<X_t>& points1, const std::vector<Y_t>& points2) {
398  CHECK_GE(points1.size(), 6);
399  CHECK_EQ(points1.size(), points2.size());
400 
401  std::vector<Eigen::Vector3d> proj_centers1(points1.size());
402  std::vector<Eigen::Vector3d> proj_centers2(points1.size());
403  std::vector<Eigen::Vector6d> plueckers1(points1.size());
404  std::vector<Eigen::Vector6d> plueckers2(points1.size());
405  for (size_t i = 0; i < points1.size(); ++i) {
406  ComposePlueckerData(points1[i].rel_tform, points1[i].xy, &proj_centers1[i],
407  &plueckers1[i]);
408  ComposePlueckerData(points2[i].rel_tform, points2[i].xy, &proj_centers2[i],
409  &plueckers2[i]);
410  }
411 
412  Eigen::Matrix3d xxF = Eigen::Matrix3d::Zero();
413  Eigen::Matrix3d yyF = Eigen::Matrix3d::Zero();
414  Eigen::Matrix3d zzF = Eigen::Matrix3d::Zero();
415  Eigen::Matrix3d xyF = Eigen::Matrix3d::Zero();
416  Eigen::Matrix3d yzF = Eigen::Matrix3d::Zero();
417  Eigen::Matrix3d zxF = Eigen::Matrix3d::Zero();
418 
419  Eigen::Matrix<double, 3, 9> x1P = Eigen::Matrix<double, 3, 9>::Zero();
420  Eigen::Matrix<double, 3, 9> y1P = Eigen::Matrix<double, 3, 9>::Zero();
421  Eigen::Matrix<double, 3, 9> z1P = Eigen::Matrix<double, 3, 9>::Zero();
422  Eigen::Matrix<double, 3, 9> x2P = Eigen::Matrix<double, 3, 9>::Zero();
423  Eigen::Matrix<double, 3, 9> y2P = Eigen::Matrix<double, 3, 9>::Zero();
424  Eigen::Matrix<double, 3, 9> z2P = Eigen::Matrix<double, 3, 9>::Zero();
425 
426  Eigen::Matrix<double, 9, 9> m11P = Eigen::Matrix<double, 9, 9>::Zero();
427  Eigen::Matrix<double, 9, 9> m12P = Eigen::Matrix<double, 9, 9>::Zero();
428  Eigen::Matrix<double, 9, 9> m22P = Eigen::Matrix<double, 9, 9>::Zero();
429 
430  for (size_t i = 0; i < points1.size(); ++i) {
431  const Eigen::Vector3d f1 = plueckers1[i].head<3>();
432  const Eigen::Vector3d f2 = plueckers2[i].head<3>();
433  const Eigen::Vector3d t1 = proj_centers1[i];
434  const Eigen::Vector3d t2 = proj_centers2[i];
435 
436  const Eigen::Matrix3d F = f2 * f2.transpose();
437  xxF += f1[0] * f1[0] * F;
438  yyF += f1[1] * f1[1] * F;
439  zzF += f1[2] * f1[2] * F;
440  xyF += f1[0] * f1[1] * F;
441  yzF += f1[1] * f1[2] * F;
442  zxF += f1[2] * f1[0] * F;
443 
444  Eigen::Matrix<double, 9, 1> ff1;
445  ff1(0) = f1[0] * (f2[1] * t2[2] - f2[2] * t2[1]);
446  ff1(1) = f1[1] * (f2[1] * t2[2] - f2[2] * t2[1]);
447  ff1(2) = f1[2] * (f2[1] * t2[2] - f2[2] * t2[1]);
448  ff1(3) = f1[0] * (f2[2] * t2[0] - f2[0] * t2[2]);
449  ff1(4) = f1[1] * (f2[2] * t2[0] - f2[0] * t2[2]);
450  ff1(5) = f1[2] * (f2[2] * t2[0] - f2[0] * t2[2]);
451  ff1(6) = f1[0] * (f2[0] * t2[1] - f2[1] * t2[0]);
452  ff1(7) = f1[1] * (f2[0] * t2[1] - f2[1] * t2[0]);
453  ff1(8) = f1[2] * (f2[0] * t2[1] - f2[1] * t2[0]);
454 
455  x1P += f1[0] * f2 * ff1.transpose();
456  y1P += f1[1] * f2 * ff1.transpose();
457  z1P += f1[2] * f2 * ff1.transpose();
458 
459  Eigen::Matrix<double, 9, 1> ff2;
460  ff2(0) = f2[0] * (f1[1] * t1[2] - f1[2] * t1[1]);
461  ff2(1) = f2[1] * (f1[1] * t1[2] - f1[2] * t1[1]);
462  ff2(2) = f2[2] * (f1[1] * t1[2] - f1[2] * t1[1]);
463  ff2(3) = f2[0] * (f1[2] * t1[0] - f1[0] * t1[2]);
464  ff2(4) = f2[1] * (f1[2] * t1[0] - f1[0] * t1[2]);
465  ff2(5) = f2[2] * (f1[2] * t1[0] - f1[0] * t1[2]);
466  ff2(6) = f2[0] * (f1[0] * t1[1] - f1[1] * t1[0]);
467  ff2(7) = f2[1] * (f1[0] * t1[1] - f1[1] * t1[0]);
468  ff2(8) = f2[2] * (f1[0] * t1[1] - f1[1] * t1[0]);
469 
470  x2P += f1[0] * f2 * ff2.transpose();
471  y2P += f1[1] * f2 * ff2.transpose();
472  z2P += f1[2] * f2 * ff2.transpose();
473 
474  m11P -= ff1 * ff1.transpose();
475  m22P -= ff2 * ff2.transpose();
476  m12P -= ff2 * ff1.transpose();
477  }
478 
479  const Eigen::Vector3d initial_rotation =
480  ComputeRotationBetweenPoints(plueckers1, plueckers2);
481 
482  const double kMinLambda = 0.00001;
483  const double kMaxLambda = 0.08;
484  const double kLambdaModifier = 2.0;
485  const int kMaxNumIterations = 50;
486  const bool kDisableIncrements = true;
487 
488  double perturbation_amplitude = 0.3;
489  int num_random_trials = 0;
490 
491  Eigen::Vector3d rotation;
492  while (num_random_trials < 5) {
493  if (num_random_trials > 2) {
494  perturbation_amplitude = 0.6;
495  }
496 
497  if (num_random_trials == 0) {
498  rotation = initial_rotation;
499  } else {
500  const Eigen::Vector3d perturbation(
501  RandomReal<double>(-perturbation_amplitude, perturbation_amplitude),
502  RandomReal<double>(-perturbation_amplitude, perturbation_amplitude),
503  RandomReal<double>(-perturbation_amplitude, perturbation_amplitude));
504  rotation = initial_rotation + perturbation;
505  }
506 
507  double lambda = 0.01;
508  int num_iterations = 0;
509  double smallest_eigen_value =
510  ComputeCost(xxF, yyF, zzF, xyF, yzF, zxF, x1P, y1P, z1P, x2P, y2P, z2P,
511  m11P, m12P, m22P, rotation, 1);
512 
513  for (int iter = 0; iter < kMaxNumIterations; ++iter) {
514  const Eigen::Vector3d jacobian = ComputeJacobian(
515  xxF, yyF, zzF, xyF, yzF, zxF, x1P, y1P, z1P, x2P, y2P, z2P, m11P,
516  m12P, m22P, rotation, smallest_eigen_value, 1);
517 
518  const Eigen::Vector3d normalized_jacobian = jacobian.normalized();
519 
520  Eigen::Vector3d sampling_point = rotation - lambda * normalized_jacobian;
521  double sampling_eigen_value =
522  ComputeCost(xxF, yyF, zzF, xyF, yzF, zxF, x1P, y1P, z1P, x2P, y2P,
523  z2P, m11P, m12P, m22P, sampling_point, 1);
524 
525  if (num_iterations == 0 || !kDisableIncrements) {
526  while (sampling_eigen_value < smallest_eigen_value) {
527  smallest_eigen_value = sampling_eigen_value;
528  if (lambda * kLambdaModifier > kMaxLambda) {
529  break;
530  }
531  lambda *= kLambdaModifier;
532  sampling_point = rotation - lambda * normalized_jacobian;
533  sampling_eigen_value =
534  ComputeCost(xxF, yyF, zzF, xyF, yzF, zxF, x1P, y1P, z1P, x2P, y2P,
535  z2P, m11P, m12P, m22P, sampling_point, 1);
536  }
537  }
538 
539  while (sampling_eigen_value > smallest_eigen_value) {
540  lambda /= kLambdaModifier;
541  sampling_point = rotation - lambda * normalized_jacobian;
542  sampling_eigen_value =
543  ComputeCost(xxF, yyF, zzF, xyF, yzF, zxF, x1P, y1P, z1P, x2P, y2P,
544  z2P, m11P, m12P, m22P, sampling_point, 1);
545  }
546 
547  rotation = sampling_point;
548  smallest_eigen_value = sampling_eigen_value;
549 
550  if (lambda < kMinLambda) {
551  break;
552  }
553  }
554 
555  if (rotation.norm() < 0.01) {
556  const double eigen_value2 =
557  ComputeCost(xxF, yyF, zzF, xyF, yzF, zxF, x1P, y1P, z1P, x2P, y2P,
558  z2P, m11P, m12P, m22P, rotation, 0);
559  if (eigen_value2 > 0.001) {
560  num_random_trials += 1;
561  } else {
562  break;
563  }
564  } else {
565  break;
566  }
567  }
568 
569  const Eigen::Matrix3d R = CayleyToRotationMatrix(rotation).transpose();
570 
571  const Eigen::Matrix4d G =
572  ComposeG(xxF, yyF, zzF, xyF, yzF, zxF, x1P, y1P, z1P, x2P, y2P, z2P, m11P,
573  m12P, m22P, rotation);
574 
575  const Eigen::EigenSolver<Eigen::Matrix4d> eigen_solver_G(G, true);
576  const Eigen::Matrix4cd V = eigen_solver_G.eigenvectors();
577  const Eigen::Matrix3x4d VV = V.real().colwise().hnormalized();
578 
579  std::vector<M_t> models(4);
580  for (int i = 0; i < 4; ++i) {
581  models[i].leftCols<3>() = R;
582  models[i].rightCols<1>() = -R * VV.col(i);
583  }
584 
585  return models;
586 }
587 
588 void GR6PEstimator::Residuals(const std::vector<X_t>& points1,
589  const std::vector<Y_t>& points2,
590  const M_t& proj_matrix,
591  std::vector<double>* residuals) {
592  CHECK_EQ(points1.size(), points2.size());
593 
594  residuals->resize(points1.size(), 0);
595 
596  Eigen::Matrix4d proj_matrix_homogeneous;
597  proj_matrix_homogeneous.topRows<3>() = proj_matrix;
598  proj_matrix_homogeneous.bottomRows<1>() = Eigen::Vector4d(0, 0, 0, 1);
599 
600  for (size_t i = 0; i < points1.size(); ++i) {
601  const Eigen::Matrix3x4d& proj_matrix1 = points1[i].rel_tform;
602  const Eigen::Matrix3x4d& proj_matrix2 =
603  points2[i].rel_tform * proj_matrix_homogeneous;
604  const Eigen::Matrix3d R12 =
605  proj_matrix2.leftCols<3>() * proj_matrix1.leftCols<3>().transpose();
606  const Eigen::Vector3d t12 =
607  proj_matrix2.rightCols<1>() - R12 * proj_matrix1.rightCols<1>();
608  const Eigen::Matrix3d E = EssentialMatrixFromPose(R12, t12);
609  const Eigen::Vector3d Ex1 = E * points1[i].xy.homogeneous();
610  const Eigen::Vector3d Etx2 = E.transpose() * points2[i].xy.homogeneous();
611  const double x2tEx1 = points2[i].xy.homogeneous().transpose() * Ex1;
612  (*residuals)[i] = x2tEx1 * x2tEx1 /
613  (Ex1(0) * Ex1(0) + Ex1(1) * Ex1(1) + Etx2(0) * Etx2(0) +
614  Etx2(1) * Etx2(1));
615  }
616 }
617 
618 } // namespace colmap
Eigen::Matrix3d rotation
Definition: VoxelGridIO.cpp:27
static void Residuals(const std::vector< X_t > &points1, const std::vector< Y_t > &points2, const M_t &proj_matrix, std::vector< double > *residuals)
static std::vector< M_t > Estimate(const std::vector< X_t > &points1, const std::vector< Y_t > &points2)
normal_z y
Matrix< double, 3, 4 > Matrix3x4d
Definition: types.h:39
Eigen::Matrix< double, 6, 1 > Vector6d
Definition: Eigen.h:107
Eigen::Matrix3d EssentialMatrixFromPose(const Eigen::Matrix3d &R, const Eigen::Vector3d &t)
Eigen::Matrix3x4d InvertProjectionMatrix(const Eigen::Matrix3x4d &proj_matrix)
Definition: projection.cc:55
Eigen::Vector2f t12