ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
homography_matrix_test.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 #define TEST_NAME "base/homography_matrix"
33 #include "util/testing.h"
34 
35 #include <cmath>
36 
37 #include <Eigen/Geometry>
38 
39 #include "base/homography_matrix.h"
40 
41 using namespace colmap;
42 
43 // Note that the test case values are obtained from OpenCV.
44 BOOST_AUTO_TEST_CASE(TestDecomposeHomographyMatrix) {
45  Eigen::Matrix3d H;
46  H << 2.649157564634028, 4.583875997496426, 70.694447785121326,
47  -1.072756858861583, 3.533262150437228, 1513.656999614321649,
48  0.001303887589576, 0.003042206876298, 1;
49  H *= 3;
50 
51  Eigen::Matrix3d K;
52  K << 640, 0, 320, 0, 640, 240, 0, 0, 1;
53 
54  std::vector<Eigen::Matrix3d> R;
55  std::vector<Eigen::Vector3d> t;
56  std::vector<Eigen::Vector3d> n;
57  DecomposeHomographyMatrix(H, K, K, &R, &t, &n);
58 
59  BOOST_CHECK_EQUAL(R.size(), 4);
60  BOOST_CHECK_EQUAL(t.size(), 4);
61  BOOST_CHECK_EQUAL(n.size(), 4);
62 
63  Eigen::Matrix3d R_ref;
64  R_ref << 0.43307983549125, 0.545749113549648, -0.717356090899523,
65  -0.85630229674426, 0.497582023798831, -0.138414255706431,
66  0.281404038139784, 0.67421809131173, 0.682818960388909;
67  const Eigen::Vector3d t_ref(1.826751712278038, 1.264718492450820,
68  0.195080809998819);
69  const Eigen::Vector3d n_ref(-0.244875830334816, -0.480857890778889,
70  -0.841909446789566);
71 
72  bool ref_solution_exists = false;
73  for (size_t i = 0; i < 4; ++i) {
74  const double kEps = 1e-6;
75  if ((R[i] - R_ref).norm() < kEps && (t[i] - t_ref).norm() < kEps &&
76  (n[i] - n_ref).norm() < kEps) {
77  ref_solution_exists = true;
78  }
79  }
80  BOOST_CHECK(ref_solution_exists);
81 }
82 
83 BOOST_AUTO_TEST_CASE(TestDecomposeHomographyMatrixRandom) {
84  const int numIters = 100;
85 
86  const double epsilon = 1e-6;
87 
88  const Eigen::Matrix3d id3 = Eigen::Matrix3d::Identity();
89 
90  for (int i = 0; i < numIters; ++i) {
91  const Eigen::Matrix3d H = Eigen::Matrix3d::Random();
92 
93  if (std::abs(H.determinant()) < epsilon) {
94  continue;
95  }
96 
97  std::vector<Eigen::Matrix3d> R;
98  std::vector<Eigen::Vector3d> t;
99  std::vector<Eigen::Vector3d> n;
100  DecomposeHomographyMatrix(H, id3, id3, &R, &t, &n);
101 
102  BOOST_CHECK_EQUAL(R.size(), 4);
103  BOOST_CHECK_EQUAL(t.size(), 4);
104  BOOST_CHECK_EQUAL(n.size(), 4);
105 
106  // Test that each candidate rotation is a rotation
107  for (const Eigen::Matrix3d& candidate_R : R) {
108  const Eigen::Matrix3d orthog_error =
109  candidate_R.transpose() * candidate_R - id3;
110 
111  // Check that candidate_R is an orthognal matrix
112  BOOST_CHECK_LT(orthog_error.lpNorm<Eigen::Infinity>(), epsilon);
113 
114  // Check determinant is 1
115  BOOST_CHECK_CLOSE(candidate_R.determinant(), 1.0, epsilon);
116  }
117  }
118 }
119 
120 BOOST_AUTO_TEST_CASE(TestPoseFromHomographyMatrix) {
121  const Eigen::Matrix3d K1 = Eigen::Matrix3d::Identity();
122  const Eigen::Matrix3d K2 = Eigen::Matrix3d::Identity();
123  const Eigen::Matrix3d R_ref = Eigen::Matrix3d::Identity();
124  const Eigen::Vector3d t_ref(1, 0, 0);
125  const Eigen::Vector3d n_ref(-1, 0, 0);
126  const double d_ref = 1;
127  const Eigen::Matrix3d H =
128  HomographyMatrixFromPose(K1, K2, R_ref, t_ref, n_ref, d_ref);
129 
130  std::vector<Eigen::Vector2d> points1;
131  points1.emplace_back(0.1, 0.4);
132  points1.emplace_back(0.2, 0.3);
133  points1.emplace_back(0.3, 0.2);
134  points1.emplace_back(0.4, 0.1);
135 
136  std::vector<Eigen::Vector2d> points2;
137  for (const auto& point1 : points1) {
138  const Eigen::Vector3d point2 = H * point1.homogeneous();
139  points2.push_back(point2.hnormalized());
140  }
141 
142  Eigen::Matrix3d R;
143  Eigen::Vector3d t;
144  Eigen::Vector3d n;
145  std::vector<Eigen::Vector3d> points3D;
146  PoseFromHomographyMatrix(H, K1, K2, points1, points2, &R, &t, &n, &points3D);
147 
148  BOOST_CHECK_EQUAL(R, R_ref);
149  BOOST_CHECK_EQUAL(t, t_ref);
150  BOOST_CHECK_EQUAL(n, n_ref);
151  BOOST_CHECK_EQUAL(points3D.size(), points1.size());
152 }
153 
154 BOOST_AUTO_TEST_CASE(TestHomographyMatrixFromPosePureRotation) {
155  const Eigen::Matrix3d K1 = Eigen::Matrix3d::Identity();
156  const Eigen::Matrix3d K2 = Eigen::Matrix3d::Identity();
157  const Eigen::Matrix3d R = Eigen::Matrix3d::Identity();
158  const Eigen::Vector3d t(0, 0, 0);
159  const Eigen::Vector3d n(-1, 0, 0);
160  const double d = 1;
161  const Eigen::Matrix3d H = HomographyMatrixFromPose(K1, K2, R, t, n, d);
162  BOOST_CHECK_EQUAL(H, Eigen::Matrix3d::Identity());
163 }
164 
165 BOOST_AUTO_TEST_CASE(TestHomographyMatrixFromPosePlanarScene) {
166  const Eigen::Matrix3d K1 = Eigen::Matrix3d::Identity();
167  const Eigen::Matrix3d K2 = Eigen::Matrix3d::Identity();
168  const Eigen::Matrix3d R = Eigen::Matrix3d::Identity();
169  const Eigen::Vector3d t(1, 0, 0);
170  const Eigen::Vector3d n(-1, 0, 0);
171  const double d = 1;
172  const Eigen::Matrix3d H = HomographyMatrixFromPose(K1, K2, R, t, n, d);
173  Eigen::Matrix3d H_ref;
174  H_ref << 2, 0, 0, 0, 1, 0, 0, 0, 1;
175  BOOST_CHECK_EQUAL(H, H_ref);
176 }
BOOST_AUTO_TEST_CASE(TestDecomposeHomographyMatrix)
const double * e
void PoseFromHomographyMatrix(const Eigen::Matrix3d &H, const Eigen::Matrix3d &K1, const Eigen::Matrix3d &K2, const std::vector< Eigen::Vector2d > &points1, const std::vector< Eigen::Vector2d > &points2, Eigen::Matrix3d *R, Eigen::Vector3d *t, Eigen::Vector3d *n, std::vector< Eigen::Vector3d > *points3D)
Eigen::Matrix3d HomographyMatrixFromPose(const Eigen::Matrix3d &K1, const Eigen::Matrix3d &K2, const Eigen::Matrix3d &R, const Eigen::Vector3d &t, const Eigen::Vector3d &n, const double d)
void DecomposeHomographyMatrix(const Eigen::Matrix3d &H, const Eigen::Matrix3d &K1, const Eigen::Matrix3d &K2, std::vector< Eigen::Matrix3d > *R, std::vector< Eigen::Vector3d > *t, std::vector< Eigen::Vector3d > *n)