Blender V5.0
resect.cc
Go to the documentation of this file.
1// Copyright (c) 2011 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
22
23#include <cstdio>
24
25#include "libmv/base/vector.h"
34
35namespace libmv {
36namespace {
37
38Mat2X PointMatrixFromMarkers(const vector<Marker>& markers) {
39 Mat2X points(2, markers.size());
40 for (int i = 0; i < markers.size(); ++i) {
41 points(0, i) = markers[i].x;
42 points(1, i) = markers[i].y;
43 }
44 return points;
45}
46
47// Uses an incremental rotation:
48//
49// x = R' * R * X + t;
50//
51// to avoid issues with the rotation representation. R' is derived from a
52// euler vector encoding the rotation in 3 parameters; the direction is the
53// axis to rotate around and the magnitude is the amount of the rotation.
54struct EuclideanResectCostFunction {
55 public:
56 typedef Vec FMatrixType;
57 typedef Vec6 XMatrixType;
58
59 EuclideanResectCostFunction(const vector<Marker>& markers,
60 const EuclideanReconstruction& reconstruction,
61 const Mat3& initial_R)
62 : markers(markers),
63 reconstruction(reconstruction),
64 initial_R(initial_R) {}
65
66 // dRt has dR (delta R) encoded as a euler vector in the first 3 parameters,
67 // followed by t in the next 3 parameters.
68 Vec operator()(const Vec6& dRt) const {
69 // Unpack R, t from dRt.
70 Mat3 R = RotationFromEulerVector(dRt.head<3>()) * initial_R;
71 Vec3 t = dRt.tail<3>();
72
73 // Compute the reprojection error for each coordinate.
74 Vec residuals(2 * markers.size());
75 residuals.setZero();
76 for (int i = 0; i < markers.size(); ++i) {
77 const EuclideanPoint& point =
78 *reconstruction.PointForTrack(markers[i].track);
79 Vec3 projected = R * point.X + t;
80 projected /= projected(2);
81 residuals[2 * i + 0] = projected(0) - markers[i].x;
82 residuals[2 * i + 1] = projected(1) - markers[i].y;
83 }
84 return residuals;
85 }
86
87 const vector<Marker>& markers;
88 const EuclideanReconstruction& reconstruction;
89 const Mat3& initial_R;
90};
91
92} // namespace
93
94bool EuclideanResect(const vector<Marker>& markers,
95 EuclideanReconstruction* reconstruction,
96 bool final_pass) {
97 if (markers.size() < 5) {
98 return false;
99 }
100 Mat2X points_2d = PointMatrixFromMarkers(markers);
101 Mat3X points_3d(3, markers.size());
102 for (int i = 0; i < markers.size(); i++) {
103 points_3d.col(i) = reconstruction->PointForTrack(markers[i].track)->X;
104 }
105 LG << "Points for resect:\n" << points_2d;
106
107 Mat3 R;
108 Vec3 t;
109
110 if (0 ||
112 points_2d, points_3d, &R, &t, euclidean_resection::RESECTION_EPNP)) {
113 // printf("Resection for image %d failed\n", markers[0].image);
114 LG << "Resection for image " << markers[0].image << " failed;"
115 << " trying fallback projective resection.";
116
117 LG << "No fallback; failing resection for " << markers[0].image;
118 return false;
119
120 if (!final_pass) {
121 return false;
122 }
123 // Euclidean resection failed. Fall back to projective resection, which is
124 // less reliable but better conditioned when there are many points.
125 Mat34 P;
126 Mat4X points_3d_homogeneous(4, markers.size());
127 for (int i = 0; i < markers.size(); i++) {
128 points_3d_homogeneous.col(i).head<3>() = points_3d.col(i);
129 points_3d_homogeneous(3, i) = 1.0;
130 }
131 resection::Resection(points_2d, points_3d_homogeneous, &P);
132 if ((P * points_3d_homogeneous.col(0))(2) < 0) {
133 LG << "Point behind camera; switch sign.";
134 P = -P;
135 }
136
137 Mat3 ignored;
138 KRt_From_P(P, &ignored, &R, &t);
139
140 // The R matrix should be a rotation, but don't rely on it.
141 Eigen::JacobiSVD<Mat3> svd(R, Eigen::ComputeFullU | Eigen::ComputeFullV);
142
143 LG << "Resection rotation is: " << svd.singularValues().transpose();
144 LG << "Determinant is: " << R.determinant();
145
146 // Correct to make R a rotation.
147 R = svd.matrixU() * svd.matrixV().transpose();
148
149 Vec3 xx = R * points_3d.col(0) + t;
150 if (xx(2) < 0.0) {
151 LG << "Final point is still behind camera...";
152 }
153 // XXX Need to check if error is horrible and fail here too in that case.
154 }
155
156 // Refine the result.
158
159 // Give the cost our initial guess for R.
160 EuclideanResectCostFunction resect_cost(markers, *reconstruction, R);
161
162 // Encode the initial parameters: start with zero delta rotation, and the
163 // guess for t obtained from resection.
164 Vec6 dRt = Vec6::Zero();
165 dRt.tail<3>() = t;
166
167 Solver solver(resect_cost);
168
169 Solver::SolverParameters params;
170 /* Solver::Results results = */ solver.minimize(params, &dRt);
171 LG << "LM found incremental rotation: " << dRt.head<3>().transpose();
172 // TODO(keir): Check results to ensure clean termination.
173
174 // Unpack the rotation and translation.
175 R = RotationFromEulerVector(dRt.head<3>()) * R;
176 t = dRt.tail<3>();
177
178 LG << "Resection for image " << markers[0].image << " got:\n"
179 << "R:\n"
180 << R << "\nt:\n"
181 << t;
182 reconstruction->InsertCamera(markers[0].image, R, t);
183 return true;
184}
185
186namespace {
187
188// Directly parameterize the projection matrix, P, which is a 12 parameter
189// homogeneous entry. In theory P should be parameterized with only 11
190// parametetrs, but in practice it works fine to let the extra degree of
191// freedom drift.
192struct ProjectiveResectCostFunction {
193 public:
194 typedef Vec FMatrixType;
195 typedef Vec12 XMatrixType;
196
197 ProjectiveResectCostFunction(const vector<Marker>& markers,
198 const ProjectiveReconstruction& reconstruction)
199 : markers(markers), reconstruction(reconstruction) {}
200
201 Vec operator()(const Vec12& vector_P) const {
202 // Unpack P from vector_P.
203 Map<const Mat34> P(vector_P.data(), 3, 4);
204
205 // Compute the reprojection error for each coordinate.
206 Vec residuals(2 * markers.size());
207 residuals.setZero();
208 for (int i = 0; i < markers.size(); ++i) {
209 const ProjectivePoint& point =
210 *reconstruction.PointForTrack(markers[i].track);
211 Vec3 projected = P * point.X;
212 projected /= projected(2);
213 residuals[2 * i + 0] = projected(0) - markers[i].x;
214 residuals[2 * i + 1] = projected(1) - markers[i].y;
215 }
216 return residuals;
217 }
218
219 const vector<Marker>& markers;
220 const ProjectiveReconstruction& reconstruction;
221};
222
223} // namespace
224
226 ProjectiveReconstruction* reconstruction) {
227 if (markers.size() < 5) {
228 return false;
229 }
230
231 // Stack the homogeneous 3D points as the columns of a matrix.
232 Mat2X points_2d = PointMatrixFromMarkers(markers);
233 Mat4X points_3d_homogeneous(4, markers.size());
234 for (int i = 0; i < markers.size(); i++) {
235 points_3d_homogeneous.col(i) =
236 reconstruction->PointForTrack(markers[i].track)->X;
237 }
238 LG << "Points for resect:\n" << points_2d;
239
240 // Resection the point.
241 Mat34 P;
242 resection::Resection(points_2d, points_3d_homogeneous, &P);
243
244 // Flip the sign of P if necessary to keep the point in front of the camera.
245 if ((P * points_3d_homogeneous.col(0))(2) < 0) {
246 LG << "Point behind camera; switch sign.";
247 P = -P;
248 }
249
250 // TODO(keir): Check if error is horrible and fail in that case.
251
252 // Refine the resulting projection matrix using geometric error.
254
255 ProjectiveResectCostFunction resect_cost(markers, *reconstruction);
256
257 // Pack the initial P matrix into a size-12 vector..
258 Vec12 vector_P = Map<Vec12>(P.data());
259
260 Solver solver(resect_cost);
261
262 Solver::SolverParameters params;
263 /* Solver::Results results = */ solver.minimize(params, &vector_P);
264 // TODO(keir): Check results to ensure clean termination.
265
266 // Unpack the projection matrix.
267 P = Map<Mat34>(vector_P.data(), 3, 4);
268
269 LG << "Resection for image " << markers[0].image << " got:\n"
270 << "P:\n"
271 << P;
272 reconstruction->InsertCamera(markers[0].image, P);
273 return true;
274}
275} // namespace libmv
SIMD_FORCE_INLINE btVector3 operator()(const btVector3 &x) const
Return the transform of the vector.
Definition btTransform.h:90
EuclideanPoint * PointForTrack(int track)
Returns a pointer to the point corresponding to track.
void InsertCamera(int image, const Mat3 &R, const Vec3 &t)
ProjectivePoint * PointForTrack(int track)
Returns a pointer to the point corresponding to track.
MatBase< R, C > transpose(MatBase< C, R >) RET
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
#define LG
#define R
bool EuclideanResection(const Mat2X &x_camera, const Mat3X &X_world, Mat3 *R, Vec3 *t, ResectionMethod method)
void Resection(const Matrix< T, 2, Dynamic > &x, const Matrix< T, 4, Dynamic > &X, Matrix< T, 3, 4 > *P)
Definition resection.h:37
Eigen::VectorXd Vec
Definition numeric.h:64
Eigen::Matrix< double, 6, 1 > Vec6
Definition numeric.h:112
bool ProjectiveResect(const vector< Marker > &markers, ProjectiveReconstruction *reconstruction)
Definition resect.cc:225
Mat3 RotationFromEulerVector(Vec3 euler_vector)
Returns the rotaiton matrix built from given vector of euler angles.
Definition numeric.h:487
Eigen::Matrix< double, 3, 3 > Mat3
Definition numeric.h:75
bool EuclideanResect(const vector< Marker > &markers, EuclideanReconstruction *reconstruction, bool final_pass)
Definition resect.cc:94
void KRt_From_P(const Mat34 &P, Mat3 *Kp, Mat3 *Rp, Vec3 *tp)
Definition projection.cc:32
Eigen::Matrix< double, 3, 4 > Mat34
Definition numeric.h:76
std::vector< ElementType, Eigen::aligned_allocator< ElementType > > vector
Eigen::Vector3d Vec3
Definition numeric.h:109
Eigen::Matrix< double, 4, Eigen::Dynamic > Mat4X
Definition numeric.h:96
Eigen::Matrix< double, 3, Eigen::Dynamic > Mat3X
Definition numeric.h:95
Eigen::Matrix< double, 12, 1 > Vec12
Definition numeric.h:118
Eigen::Matrix< double, 2, Eigen::Dynamic > Mat2X
Definition numeric.h:94
i
Definition text_draw.cc:230