Blender V4.3
resect_test.cc
Go to the documentation of this file.
1// Copyright (c) 2009 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
23#include "testing/testing.h"
24
25#if 0
26// Generates all necessary inputs and expected outputs for EuclideanResection.
27void CreateCameraSystem(const Mat3& KK,
28 const Mat3X& x_image,
29 const Vec& X_distances,
30 const Mat3& R_input,
31 const Vec3& T_input,
32 Mat2X *x_camera,
33 Mat3X *X_world,
34 Mat3 *R_expected,
35 Vec3 *T_expected) {
36 int num_points = x_image.cols();
37
38 Mat3X x_unit_cam(3, num_points);
39 x_unit_cam = KK.inverse() * x_image;
40
41 // Create normalized camera coordinates to be used as an input to the PnP
42 // function, instead of using NormalizeColumnVectors(&x_unit_cam).
43 *x_camera = x_unit_cam.block(0, 0, 2, num_points);
44 for (int i = 0; i < num_points; ++i) {
45 x_unit_cam.col(i).normalize();
46 }
47
48 // Create the 3D points in the camera system.
49 Mat X_camera(3, num_points);
50 for (int i = 0; i < num_points; ++i) {
51 X_camera.col(i) = X_distances(i) * x_unit_cam.col(i);
52 }
53
54 // Apply the transformation to the camera 3D points
55 Mat translation_matrix(3, num_points);
56 translation_matrix.row(0).setConstant(T_input(0));
57 translation_matrix.row(1).setConstant(T_input(1));
58 translation_matrix.row(2).setConstant(T_input(2));
59
60 *X_world = R_input * X_camera + translation_matrix;
61
62 // Create the expected result for comparison.
63 *R_expected = R_input.transpose();
64 *T_expected = *R_expected * (-T_input);
65};
66
67TEST(AbsoluteOrientation, QuaternionSolution) {
68 int num_points = 4;
69 Mat X;
70 Mat Xp;
71 X = 100 * Mat::Random(3, num_points);
72
73 // Create a random translation and rotation.
74 Mat3 R_input;
75 R_input = Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ())
76 * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitY())
77 * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ());
78
79 Vec3 t_input;
80 t_input.setRandom();
81 t_input = 100 * t_input;
82
83 Mat translation_matrix(3, num_points);
84 translation_matrix.row(0).setConstant(t_input(0));
85 translation_matrix.row(1).setConstant(t_input(1));
86 translation_matrix.row(2).setConstant(t_input(2));
87
88 // Create the transformed 3D points Xp as Xp = R * X + t.
89 Xp = R_input * X + translation_matrix;
90
91 // Output variables.
92 Mat3 R;
93 Vec3 t;
94
95 AbsoluteOrientation(X, Xp, &R, &t);
96
97 EXPECT_MATRIX_NEAR(t, t_input, 1e-6);
98 EXPECT_MATRIX_NEAR(R, R_input, 1e-8);
99}
100
101TEST(EuclideanResection, Points4KnownImagePointsRandomTranslationRotation) {
102 // In this test only the translation and rotation are random. The image
103 // points are selected from a real case and are well conditioned.
104 Vec2i image_dimensions;
105 image_dimensions << 1600, 1200;
106
107 Mat3 KK;
108 KK << 2796, 0, 804,
109 0 , 2796, 641,
110 0, 0, 1;
111
112 // The real image points.
113 int num_points = 4;
114 Mat3X x_image(3, num_points);
115 x_image << 1164.06, 734.948, 749.599, 430.727,
116 681.386, 844.59, 496.315, 580.775,
117 1, 1, 1, 1;
118
119
120 // A vector of the 4 distances to the 3D points.
121 Vec X_distances = 100 * Vec::Random(num_points).array().abs();
122
123 // Create the random camera motion R and t that resection should recover.
124 Mat3 R_input;
125 R_input = Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ())
126 * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitY())
127 * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ());
128
129 Vec3 T_input;
130 T_input.setRandom();
131 T_input = 100 * T_input;
132
133 // Create the camera system, also getting the expected result of the
134 // transformation.
135 Mat3 R_expected;
136 Vec3 T_expected;
137 Mat3X X_world;
138 Mat2X x_camera;
139 CreateCameraSystem(KK, x_image, X_distances, R_input, T_input,
140 &x_camera, &X_world, &R_expected, &T_expected);
141
142 // Finally, run the code under test.
143 Mat3 R_output;
144 Vec3 T_output;
145 EuclideanResection(x_camera, X_world,
146 &R_output, &T_output,
147 RESECTION_ANSAR_DANIILIDIS);
148
149 EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5);
150 EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7);
151
152 // For now, the EPnP doesn't have a non-linear optimization step and so is
153 // not precise enough with only 4 points.
154 //
155 // TODO(jmichot): Reenable this test when there is nonlinear refinement.
156# if 0
157 R_output.setIdentity();
158 T_output.setZero();
159
160 EuclideanResection(x_camera, X_world,
161 &R_output, &T_output,
162 RESECTION_EPNP);
163
164 EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5);
165 EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7);*/
166# endif
167}
168
169// TODO(jmichot): Reduce the code duplication here with the code above.
170TEST(EuclideanResection, Points6AllRandomInput) {
171 Mat3 KK;
172 KK << 2796, 0, 804,
173 0 , 2796, 641,
174 0, 0, 1;
175
176 // Create random image points for a 1600x1200 image.
177 int w = 1600;
178 int h = 1200;
179 int num_points = 6;
180 Mat3X x_image(3, num_points);
181 x_image.row(0) = w * Vec::Random(num_points).array().abs();
182 x_image.row(1) = h * Vec::Random(num_points).array().abs();
183 x_image.row(2).setOnes();
184
185 // Normalized camera coordinates to be used as an input to the PnP function.
186 Mat2X x_camera;
187 Vec X_distances = 100 * Vec::Random(num_points).array().abs();
188
189 // Create the random camera motion R and t that resection should recover.
190 Mat3 R_input;
191 R_input = Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ())
192 * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitY())
193 * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ());
194
195 Vec3 T_input;
196 T_input.setRandom();
197 T_input = 100 * T_input;
198
199 // Create the camera system.
200 Mat3 R_expected;
201 Vec3 T_expected;
202 Mat3X X_world;
203 CreateCameraSystem(KK, x_image, X_distances, R_input, T_input,
204 &x_camera, &X_world, &R_expected, &T_expected);
205
206 // Test each of the resection methods.
207 {
208 Mat3 R_output;
209 Vec3 T_output;
210 EuclideanResection(x_camera, X_world,
211 &R_output, &T_output,
212 RESECTION_ANSAR_DANIILIDIS);
213 EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5);
214 EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7);
215 }
216 {
217 Mat3 R_output;
218 Vec3 T_output;
219 EuclideanResection(x_camera, X_world,
220 &R_output, &T_output,
221 RESECTION_EPNP);
222 EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5);
223 EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7);
224 }
225 {
226 Mat3 R_output;
227 Vec3 T_output;
228 EuclideanResection(x_image, X_world, KK,
229 &R_output, &T_output);
230 EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5);
231 EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7);
232 }
233}
234#endif
TEST(array_store, Nop)
#define X
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
static void CreateCameraSystem(const Mat3 &KK, const Mat3X &x_image, const Vec &X_distances, const Mat3 &R_input, const Vec3 &T_input, Mat2X *x_camera, Mat3X *X_world, Mat3 *R_expected, Vec3 *T_expected)
float[3][3] Mat3
Definition gpu_matrix.cc:28
#define R
VecMat::Vec2< int > Vec2i
Definition Geom.h:21
bool EuclideanResection(const Mat2X &x_camera, const Mat3X &X_world, Mat3 *R, Vec3 *t, ResectionMethod method)
void AbsoluteOrientation(const Mat3X &X, const Mat3X &Xp, Mat3 *R, Vec3 *t)
Eigen::VectorXd Vec
Definition numeric.h:61
Eigen::MatrixXd Mat
Definition numeric.h:60
Eigen::Vector3d Vec3
Definition numeric.h:106
Eigen::Matrix< double, 3, Eigen::Dynamic > Mat3X
Definition numeric.h:92
Eigen::Matrix< double, 2, Eigen::Dynamic > Mat2X
Definition numeric.h:91