ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
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 #include "base/pose.h"
33 
34 #include <Eigen/Eigenvalues>
35 
36 #include "base/projection.h"
37 #include "base/triangulation.h"
38 
39 namespace colmap {
40 
41 Eigen::Matrix3d CrossProductMatrix(const Eigen::Vector3d& vector) {
42  Eigen::Matrix3d matrix;
43  matrix << 0, -vector(2), vector(1), vector(2), 0, -vector(0), -vector(1),
44  vector(0), 0;
45  return matrix;
46 }
47 
48 void RotationMatrixToEulerAngles(const Eigen::Matrix3d& R, double* rx,
49  double* ry, double* rz) {
50  *rx = std::atan2(R(2, 1), R(2, 2));
51  *ry = std::asin(-R(2, 0));
52  *rz = std::atan2(R(1, 0), R(0, 0));
53 
54  *rx = IsNaN(*rx) ? 0 : *rx;
55  *ry = IsNaN(*ry) ? 0 : *ry;
56  *rz = IsNaN(*rz) ? 0 : *rz;
57 }
58 
59 Eigen::Matrix3d EulerAnglesToRotationMatrix(const double rx, const double ry,
60  const double rz) {
61  const Eigen::Matrix3d Rx =
62  Eigen::AngleAxisd(rx, Eigen::Vector3d::UnitX()).toRotationMatrix();
63  const Eigen::Matrix3d Ry =
64  Eigen::AngleAxisd(ry, Eigen::Vector3d::UnitY()).toRotationMatrix();
65  const Eigen::Matrix3d Rz =
66  Eigen::AngleAxisd(rz, Eigen::Vector3d::UnitZ()).toRotationMatrix();
67  return Rz * Ry * Rx;
68 }
69 
70 Eigen::Vector4d RotationMatrixToQuaternion(const Eigen::Matrix3d& rot_mat) {
71  const Eigen::Quaterniond quat(rot_mat);
72  return Eigen::Vector4d(quat.w(), quat.x(), quat.y(), quat.z());
73 }
74 
75 Eigen::Matrix3d QuaternionToRotationMatrix(const Eigen::Vector4d& qvec) {
76  const Eigen::Vector4d normalized_qvec = NormalizeQuaternion(qvec);
77  const Eigen::Quaterniond quat(normalized_qvec(0), normalized_qvec(1),
78  normalized_qvec(2), normalized_qvec(3));
79  return quat.toRotationMatrix();
80 }
81 
82 Eigen::Vector4d NormalizeQuaternion(const Eigen::Vector4d& qvec) {
83  const double norm = qvec.norm();
84  if (norm == 0) {
85  // We do not just use (1, 0, 0, 0) because that is a constant and when used
86  // for automatic differentiation that would lead to a zero derivative.
87  return Eigen::Vector4d(1.0, qvec(1), qvec(2), qvec(3));
88  } else {
89  return qvec / norm;
90  }
91 }
92 
93 Eigen::Vector4d InvertQuaternion(const Eigen::Vector4d& qvec) {
94  return Eigen::Vector4d(qvec(0), -qvec(1), -qvec(2), -qvec(3));
95 }
96 
97 Eigen::Vector4d ConcatenateQuaternions(const Eigen::Vector4d& qvec1,
98  const Eigen::Vector4d& qvec2) {
99  const Eigen::Vector4d normalized_qvec1 = NormalizeQuaternion(qvec1);
100  const Eigen::Vector4d normalized_qvec2 = NormalizeQuaternion(qvec2);
101  const Eigen::Quaterniond quat1(normalized_qvec1(0), normalized_qvec1(1),
102  normalized_qvec1(2), normalized_qvec1(3));
103  const Eigen::Quaterniond quat2(normalized_qvec2(0), normalized_qvec2(1),
104  normalized_qvec2(2), normalized_qvec2(3));
105  const Eigen::Quaterniond cat_quat = quat2 * quat1;
106  return NormalizeQuaternion(
107  Eigen::Vector4d(cat_quat.w(), cat_quat.x(), cat_quat.y(), cat_quat.z()));
108 }
109 
110 Eigen::Vector3d QuaternionRotatePoint(const Eigen::Vector4d& qvec,
111  const Eigen::Vector3d& point) {
112  const Eigen::Vector4d normalized_qvec = NormalizeQuaternion(qvec);
113  const Eigen::Quaterniond quat(normalized_qvec(0), normalized_qvec(1),
114  normalized_qvec(2), normalized_qvec(3));
115  return quat * point;
116 }
117 
118 Eigen::Vector4d AverageQuaternions(const std::vector<Eigen::Vector4d>& qvecs,
119  const std::vector<double>& weights) {
120  CHECK_EQ(qvecs.size(), weights.size());
121  CHECK_GT(qvecs.size(), 0);
122 
123  if (qvecs.size() == 1) {
124  return qvecs[0];
125  }
126 
127  Eigen::Matrix4d A = Eigen::Matrix4d::Zero();
128  double weight_sum = 0;
129 
130  for (size_t i = 0; i < qvecs.size(); ++i) {
131  CHECK_GT(weights[i], 0);
132  const Eigen::Vector4d qvec = NormalizeQuaternion(qvecs[i]);
133  A += weights[i] * qvec * qvec.transpose();
134  weight_sum += weights[i];
135  }
136 
137  A.array() /= weight_sum;
138 
139  const Eigen::Matrix4d eigenvectors =
140  Eigen::SelfAdjointEigenSolver<Eigen::Matrix4d>(A).eigenvectors();
141 
142  return eigenvectors.col(3);
143 }
144 
145 Eigen::Matrix3d RotationFromUnitVectors(const Eigen::Vector3d& vector1,
146  const Eigen::Vector3d& vector2) {
147  const Eigen::Vector3d v1 = vector1.normalized();
148  const Eigen::Vector3d v2 = vector2.normalized();
149  const Eigen::Vector3d v = v1.cross(v2);
150  const Eigen::Matrix3d v_x = CrossProductMatrix(v);
151  const double c = v1.dot(v2);
152  if (c == -1) {
153  return Eigen::Matrix3d::Identity();
154  } else {
155  return Eigen::Matrix3d::Identity() + v_x + 1 / (1 + c) * (v_x * v_x);
156  }
157 }
158 
160  const Eigen::Matrix3x4d& proj_matrix) {
161  return -proj_matrix.leftCols<3>().transpose() * proj_matrix.rightCols<1>();
162 }
163 
164 Eigen::Vector3d ProjectionCenterFromPose(const Eigen::Vector4d& qvec,
165  const Eigen::Vector3d& tvec) {
166  // Inverse rotation as conjugate quaternion.
167  const Eigen::Vector4d normalized_qvec = NormalizeQuaternion(qvec);
168  const Eigen::Quaterniond quat(normalized_qvec(0), -normalized_qvec(1),
169  -normalized_qvec(2), -normalized_qvec(3));
170  return quat * -tvec;
171 }
172 
173 void ComputeRelativePose(const Eigen::Vector4d& qvec1,
174  const Eigen::Vector3d& tvec1,
175  const Eigen::Vector4d& qvec2,
176  const Eigen::Vector3d& tvec2, Eigen::Vector4d* qvec12,
177  Eigen::Vector3d* tvec12) {
178  const Eigen::Vector4d inv_qvec1 = InvertQuaternion(qvec1);
179  *qvec12 = ConcatenateQuaternions(inv_qvec1, qvec2);
180  *tvec12 = tvec2 - QuaternionRotatePoint(*qvec12, tvec1);
181 }
182 
183 void ConcatenatePoses(const Eigen::Vector4d& qvec1,
184  const Eigen::Vector3d& tvec1,
185  const Eigen::Vector4d& qvec2,
186  const Eigen::Vector3d& tvec2, Eigen::Vector4d* qvec12,
187  Eigen::Vector3d* tvec12) {
188  *qvec12 = ConcatenateQuaternions(qvec1, qvec2);
189  *tvec12 = tvec2 + QuaternionRotatePoint(qvec2, tvec1);
190 }
191 
192 void InvertPose(const Eigen::Vector4d& qvec, const Eigen::Vector3d& tvec,
193  Eigen::Vector4d* inv_qvec, Eigen::Vector3d* inv_tvec) {
194  *inv_qvec = InvertQuaternion(qvec);
195  *inv_tvec = -QuaternionRotatePoint(*inv_qvec, tvec);
196 }
197 
198 void InterpolatePose(const Eigen::Vector4d& qvec1, const Eigen::Vector3d& tvec1,
199  const Eigen::Vector4d& qvec2, const Eigen::Vector3d& tvec2,
200  const double t, Eigen::Vector4d* qveci,
201  Eigen::Vector3d* tveci) {
202  const Eigen::Vector4d normalized_qvec1 = NormalizeQuaternion(qvec1);
203  const Eigen::Vector4d normalized_qvec2 = NormalizeQuaternion(qvec2);
204  const Eigen::Quaterniond quat1(normalized_qvec1(0), normalized_qvec1(1),
205  normalized_qvec1(2), normalized_qvec1(3));
206  const Eigen::Quaterniond quat2(normalized_qvec2(0), normalized_qvec2(1),
207  normalized_qvec2(2), normalized_qvec2(3));
208  const Eigen::Vector3d tvec12 = tvec2 - tvec1;
209 
210  const Eigen::Quaterniond quati = quat1.slerp(t, quat2);
211 
212  *qveci = Eigen::Vector4d(quati.w(), quati.x(), quati.y(), quati.z());
213  *tveci = tvec1 + tvec12 * t;
214 }
215 
216 Eigen::Vector3d CalculateBaseline(const Eigen::Vector4d& qvec1,
217  const Eigen::Vector3d& tvec1,
218  const Eigen::Vector4d& qvec2,
219  const Eigen::Vector3d& tvec2) {
220  const Eigen::Vector3d center1 = ProjectionCenterFromPose(qvec1, tvec1);
221  const Eigen::Vector3d center2 = ProjectionCenterFromPose(qvec2, tvec2);
222  return center2 - center1;
223 }
224 
225 bool CheckCheirality(const Eigen::Matrix3d& R, const Eigen::Vector3d& t,
226  const std::vector<Eigen::Vector2d>& points1,
227  const std::vector<Eigen::Vector2d>& points2,
228  std::vector<Eigen::Vector3d>* points3D) {
229  CHECK_EQ(points1.size(), points2.size());
230  const Eigen::Matrix3x4d proj_matrix1 = Eigen::Matrix3x4d::Identity();
231  const Eigen::Matrix3x4d proj_matrix2 = ComposeProjectionMatrix(R, t);
232  const double kMinDepth = std::numeric_limits<double>::epsilon();
233  const double max_depth = 1000.0f * (R.transpose() * t).norm();
234  points3D->clear();
235  for (size_t i = 0; i < points1.size(); ++i) {
236  const Eigen::Vector3d point3D =
237  TriangulatePoint(proj_matrix1, proj_matrix2, points1[i], points2[i]);
238  const double depth1 = CalculateDepth(proj_matrix1, point3D);
239  if (depth1 > kMinDepth && depth1 < max_depth) {
240  const double depth2 = CalculateDepth(proj_matrix2, point3D);
241  if (depth2 > kMinDepth && depth2 < max_depth) {
242  points3D->push_back(point3D);
243  }
244  }
245  }
246  return !points3D->empty();
247 }
248 
249 } // namespace colmap
Matrix< double, 3, 4 > Matrix3x4d
Definition: types.h:39
Eigen::Vector3d ProjectionCenterFromMatrix(const Eigen::Matrix3x4d &proj_matrix)
Definition: pose.cc:159
Eigen::Matrix3d RotationFromUnitVectors(const Eigen::Vector3d &vector1, const Eigen::Vector3d &vector2)
Definition: pose.cc:145
void ComputeRelativePose(const Eigen::Vector4d &qvec1, const Eigen::Vector3d &tvec1, const Eigen::Vector4d &qvec2, const Eigen::Vector3d &tvec2, Eigen::Vector4d *qvec12, Eigen::Vector3d *tvec12)
Definition: pose.cc:173
Eigen::Matrix3d EulerAnglesToRotationMatrix(const double rx, const double ry, const double rz)
Definition: pose.cc:59
void InvertPose(const Eigen::Vector4d &qvec, const Eigen::Vector3d &tvec, Eigen::Vector4d *inv_qvec, Eigen::Vector3d *inv_tvec)
Definition: pose.cc:192
Eigen::Matrix3d CrossProductMatrix(const Eigen::Vector3d &vector)
Definition: pose.cc:41
Eigen::Vector4d NormalizeQuaternion(const Eigen::Vector4d &qvec)
Definition: pose.cc:82
Eigen::Vector4d AverageQuaternions(const std::vector< Eigen::Vector4d > &qvecs, const std::vector< double > &weights)
Definition: pose.cc:118
void ConcatenatePoses(const Eigen::Vector4d &qvec1, const Eigen::Vector3d &tvec1, const Eigen::Vector4d &qvec2, const Eigen::Vector3d &tvec2, Eigen::Vector4d *qvec12, Eigen::Vector3d *tvec12)
Definition: pose.cc:183
double CalculateDepth(const Eigen::Matrix3x4d &proj_matrix, const Eigen::Vector3d &point3D)
Definition: projection.cc:185
Eigen::Vector3d TriangulatePoint(const Eigen::Matrix3x4d &proj_matrix1, const Eigen::Matrix3x4d &proj_matrix2, const Eigen::Vector2d &point1, const Eigen::Vector2d &point2)
Eigen::Vector4d RotationMatrixToQuaternion(const Eigen::Matrix3d &rot_mat)
Definition: pose.cc:70
Eigen::Vector4d ConcatenateQuaternions(const Eigen::Vector4d &qvec1, const Eigen::Vector4d &qvec2)
Definition: pose.cc:97
Eigen::Vector4d InvertQuaternion(const Eigen::Vector4d &qvec)
Definition: pose.cc:93
Eigen::Vector3d QuaternionRotatePoint(const Eigen::Vector4d &qvec, const Eigen::Vector3d &point)
Definition: pose.cc:110
Eigen::Vector3d ProjectionCenterFromPose(const Eigen::Vector4d &qvec, const Eigen::Vector3d &tvec)
Definition: pose.cc:164
bool IsNaN(const float x)
Definition: math.h:160
Eigen::Vector3d CalculateBaseline(const Eigen::Vector4d &qvec1, const Eigen::Vector3d &tvec1, const Eigen::Vector4d &qvec2, const Eigen::Vector3d &tvec2)
Definition: pose.cc:216
void RotationMatrixToEulerAngles(const Eigen::Matrix3d &R, double *rx, double *ry, double *rz)
Definition: pose.cc:48
Eigen::Matrix3x4d ComposeProjectionMatrix(const Eigen::Vector4d &qvec, const Eigen::Vector3d &tvec)
Definition: projection.cc:39
void InterpolatePose(const Eigen::Vector4d &qvec1, const Eigen::Vector3d &tvec1, const Eigen::Vector4d &qvec2, const Eigen::Vector3d &tvec2, const double t, Eigen::Vector4d *qveci, Eigen::Vector3d *tveci)
Definition: pose.cc:198
bool CheckCheirality(const Eigen::Matrix3d &R, const Eigen::Vector3d &t, const std::vector< Eigen::Vector2d > &points1, const std::vector< Eigen::Vector2d > &points2, std::vector< Eigen::Vector3d > *points3D)
Definition: pose.cc:225
Eigen::Matrix3d QuaternionToRotationMatrix(const Eigen::Vector4d &qvec)
Definition: pose.cc:75