ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
absolute_pose_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/absolute_pose"
33 #include "util/testing.h"
34 
35 #include <Eigen/Core>
36 
37 #include "base/pose.h"
41 #include "optim/ransac.h"
42 #include "util/random.h"
43 
44 using namespace colmap;
45 
47  SetPRNGSeed(0);
48 
49  std::vector<Eigen::Vector3d> points3D;
50  points3D.emplace_back(1, 1, 1);
51  points3D.emplace_back(0, 1, 1);
52  points3D.emplace_back(3, 1.0, 4);
53  points3D.emplace_back(3, 1.1, 4);
54  points3D.emplace_back(3, 1.2, 4);
55  points3D.emplace_back(3, 1.3, 4);
56  points3D.emplace_back(3, 1.4, 4);
57  points3D.emplace_back(2, 1, 7);
58 
59  auto points3D_faulty = points3D;
60  for (size_t i = 0; i < points3D.size(); ++i) {
61  points3D_faulty[i](0) = 20;
62  }
63 
64  for (double qx = 0; qx < 1; qx += 0.2) {
65  for (double tx = 0; tx < 1; tx += 0.1) {
66  const SimilarityTransform3 orig_tform(1, Eigen::Vector4d(1, qx, 0, 0),
67  Eigen::Vector3d(tx, 0, 0));
68 
69  // Project points to camera coordinate system.
70  std::vector<Eigen::Vector2d> points2D;
71  for (size_t i = 0; i < points3D.size(); ++i) {
72  Eigen::Vector3d point3D_camera = points3D[i];
73  orig_tform.TransformPoint(&point3D_camera);
74  points2D.push_back(point3D_camera.hnormalized());
75  }
76 
77  RANSACOptions options;
78  options.max_error = 1e-5;
79  RANSAC<P3PEstimator> ransac(options);
80  const auto report = ransac.Estimate(points2D, points3D);
81 
82  BOOST_CHECK_EQUAL(report.success, true);
83 
84  // Test if correct transformation has been determined.
85  const double matrix_diff =
86  (orig_tform.Matrix().topLeftCorner<3, 4>() - report.model).norm();
87  BOOST_CHECK(matrix_diff < 1e-2);
88 
89  // Test residuals of exact points.
90  std::vector<double> residuals;
91  P3PEstimator::Residuals(points2D, points3D, report.model, &residuals);
92  for (size_t i = 0; i < residuals.size(); ++i) {
93  BOOST_CHECK(residuals[i] < 1e-3);
94  }
95 
96  // Test residuals of faulty points.
97  P3PEstimator::Residuals(points2D, points3D_faulty, report.model,
98  &residuals);
99  for (size_t i = 0; i < residuals.size(); ++i) {
100  BOOST_CHECK(residuals[i] > 0.1);
101  }
102  }
103  }
104 }
105 
107  SetPRNGSeed(0);
108 
109  std::vector<Eigen::Vector3d> points3D;
110  points3D.emplace_back(1, 1, 1);
111  points3D.emplace_back(0, 1, 1);
112  points3D.emplace_back(3, 1.0, 4);
113  points3D.emplace_back(3, 1.1, 4);
114  points3D.emplace_back(3, 1.2, 4);
115  points3D.emplace_back(3, 1.3, 4);
116  points3D.emplace_back(3, 1.4, 4);
117  points3D.emplace_back(2, 1, 7);
118 
119  auto points3D_faulty = points3D;
120  for (size_t i = 0; i < points3D.size(); ++i) {
121  points3D_faulty[i](0) = 20;
122  }
123 
124  for (double qx = 0; qx < 1; qx += 0.2) {
125  for (double tx = 0; tx < 1; tx += 0.1) {
126  const SimilarityTransform3 orig_tform(1, Eigen::Vector4d(1, qx, 0, 0),
127  Eigen::Vector3d(tx, 0, 0));
128 
129  // Project points to camera coordinate system.
130  std::vector<Eigen::Vector2d> points2D;
131  for (size_t i = 0; i < points3D.size(); ++i) {
132  Eigen::Vector3d point3D_camera = points3D[i];
133  orig_tform.TransformPoint(&point3D_camera);
134  points2D.push_back(point3D_camera.hnormalized());
135  }
136 
137  RANSACOptions options;
138  options.max_error = 1e-5;
139  RANSAC<EPNPEstimator> ransac(options);
140  const auto report = ransac.Estimate(points2D, points3D);
141 
142  BOOST_CHECK_EQUAL(report.success, true);
143 
144  // Test if correct transformation has been determined.
145  const double matrix_diff =
146  (orig_tform.Matrix().topLeftCorner<3, 4>() - report.model).norm();
147  BOOST_CHECK(matrix_diff < 1e-3);
148 
149  // Test residuals of exact points.
150  std::vector<double> residuals;
151  EPNPEstimator::Residuals(points2D, points3D, report.model, &residuals);
152  for (size_t i = 0; i < residuals.size(); ++i) {
153  BOOST_CHECK(residuals[i] < 1e-3);
154  }
155 
156  // Test residuals of faulty points.
157  EPNPEstimator::Residuals(points2D, points3D_faulty, report.model,
158  &residuals);
159  for (size_t i = 0; i < residuals.size(); ++i) {
160  BOOST_CHECK(residuals[i] > 0.1);
161  }
162  }
163  }
164 }
165 
166 BOOST_AUTO_TEST_CASE(TestEPNP_BrokenSolveSignCase) {
167  std::vector<Eigen::Vector2d> points2D;
168  points2D.emplace_back(-2.6783007931074532e-01, 5.3457197430746251e-01);
169  points2D.emplace_back(-4.2629907287470264e-01, 7.5623350319519789e-01);
170  points2D.emplace_back(-1.6767413005963930e-01, -1.3387172544910089e-01);
171  points2D.emplace_back(-5.6616329720373559e-02, 2.3621156497739373e-01);
172  points2D.emplace_back(-1.7721225948969935e-01, 2.3395366792735982e-02);
173  points2D.emplace_back(-5.1836259886632222e-02, -4.4380694271927049e-02);
174  points2D.emplace_back(-3.5897765845560037e-01, 1.6252721078589397e-01);
175  points2D.emplace_back(2.7057324473684058e-01, -1.4067450104631887e-01);
176  points2D.emplace_back(-2.5811166424334520e-01, 8.0167171300227366e-02);
177  points2D.emplace_back(2.0239567448222310e-02, -3.2845953375344145e-01);
178  points2D.emplace_back(4.2571014715170657e-01, -2.8321173570154773e-01);
179  points2D.emplace_back(-5.4597596412987237e-01, 9.1431935871671977e-02);
180 
181  std::vector<Eigen::Vector3d> points3D;
182  points3D.emplace_back(4.4276865308679305e+00, -1.3384364366019632e+00,
183  -3.5997423085253892e+00);
184  points3D.emplace_back(2.7278555252512309e+00, -3.8152996187231392e-01,
185  -2.6558518399902824e+00);
186  points3D.emplace_back(4.8548566083054894e+00, -1.4756197433631739e+00,
187  -6.8274946022490501e-01);
188  points3D.emplace_back(3.1523013527998449e+00, -1.3377020437938025e+00,
189  -1.6443269301929087e+00);
190  points3D.emplace_back(3.8551679771512073e+00, -1.0557700545885551e+00,
191  -1.1695994508851486e+00);
192  points3D.emplace_back(5.9571373150353812e+00, -2.6120646101684555e+00,
193  -1.0841441206050342e+00);
194  points3D.emplace_back(6.3287088499358894e+00, -1.1761274755817175e+00,
195  -2.5951879774151583e+00);
196  points3D.emplace_back(2.3005305990121250e+00, -1.4019796626800123e+00,
197  -4.4485464455072321e-01);
198  points3D.emplace_back(5.9816859934587354e+00, -1.4211814511691452e+00,
199  -2.0285923889293449e+00);
200  points3D.emplace_back(5.2543344690665457e+00, -2.3389255564264144e+00,
201  4.3708173185524052e-01);
202  points3D.emplace_back(3.2181599245991688e+00, -2.8906671988445098e+00,
203  2.6825718150064348e-01);
204  points3D.emplace_back(4.4592895306946758e+00, -9.1235241641579902e-03,
205  -1.6555237117970871e+00);
206 
207  const std::vector<EPNPEstimator::M_t> output =
208  EPNPEstimator::Estimate(points2D, points3D);
209 
210  BOOST_CHECK_EQUAL(output.size(), 1);
211 
212  double reproj = 0.0;
213  for (size_t i = 0; i < points3D.size(); ++i) {
214  reproj +=
215  ((output[0] * points3D[i].homogeneous()).hnormalized() - points2D[i])
216  .norm();
217  }
218 
219  BOOST_CHECK(reproj < 0.2);
220 }
BOOST_AUTO_TEST_CASE(TestP3P)
static void Residuals(const std::vector< X_t > &points2D, const std::vector< Y_t > &points3D, const M_t &proj_matrix, std::vector< double > *residuals)
static std::vector< M_t > Estimate(const std::vector< X_t > &points2D, const std::vector< Y_t > &points3D)
static void Residuals(const std::vector< X_t > &points2D, const std::vector< Y_t > &points3D, const M_t &proj_matrix, std::vector< double > *residuals)
Report Estimate(const std::vector< typename Estimator::X_t > &X, const std::vector< typename Estimator::Y_t > &Y)
Definition: ransac.h:159
Eigen::Matrix4d Matrix() const
void TransformPoint(Eigen::Vector3d *xyz) const
const double * e
void SetPRNGSeed(unsigned seed)
Definition: random.cc:40