Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
RotationAveraging.cpp
1 #include "RotationAveraging.hh"
2 
3 #include <Base/Math/Matrix.hh>
4 #include <Base/Math/Matrix3x3.hh>
5 #include <Base/Math/Vector.hh>
6 #include <Base/Common/CompareFloatingPoint.hh>
7 #include <Base/Geometry/Quaternion.hh>
8 #include <Geometry/RMatrix.hh>
9 #include <MathAlgo/SVD3x3.hh>
10 
11 using namespace std;
12 using namespace BIAS;
13 
14 RotationAveraging::RotationAveraging() : tolerance_(1e-10), maxIters_(10)
15 {
16  NewDebugLevel("ROTATIONAVERGAGE_ITERS");
17  //AddDebugLevel("ROTATIONAVERGAGE_ITERS");
18 }
19 
21 GeodesicL1Mean(const std::vector<BIAS::RMatrix> &R, BIAS::RMatrix &meanR)
22 {
23  BIASASSERT(TestRotations(R));
24  const unsigned int n = R.size();
25  BIAS::RMatrix resR, meanResR;
26  BIAS::Vector3<double> resW, meanResW;
27  double scale;
28  int res = GeodesicL2Mean(R, meanR);
29  if (res != 0) {
30  BIASERR("Initialization of mean rotation via geodesic L2-mean failed!");
31  return res;
32  }
33  double updateAngle; //, lastUpdateAngle = 0.0;
34  for (unsigned int iter = 0; iter < maxIters_; iter++)
35  {
36  // Compute mean normalized residual rotation
37  meanResW.SetZero();
38  scale = 0.0;
39  for (unsigned int i = 0; i < n; i++)
40  {
41  resR = R[i] * meanR.Transpose();
42  resR.GetRotationAxisAngle(resW);
43  if (BIAS::Equal(resW.NormL2(), 0.0))
44  continue;
45  scale += 1.0 / resW.NormL2();
46  resW.Normalize();
47  meanResW += resW;
48  }
49  if (!BIAS::Equal(scale, 0.0))
50  meanResW.MultiplyIP(1.0 / scale);
51  // Update mean rotation
52  updateAngle = meanResW.NormL2();
53  BCDOUT(ROTATIONAVERGAGE_ITERS, "Geodesic L1-mean : Iteration " << iter
54  << " : update angle = " << (updateAngle * 180.0 / M_PI) << " degree" << endl);
55  //if (fabs(updateAngle - lastUpdateAngle) < tolerance_)
56  if (updateAngle < tolerance_)
57  break;
58  else {
59  //lastUpdateAngle = updateAngle;
60  meanResW.Normalize();
61  meanResR.Set(meanResW, updateAngle);
62  meanR = meanResR * meanR;
63  }
64  }
65  return 0;
66 }
67 
69 GeodesicL2Mean(const std::vector<BIAS::RMatrix> &R, BIAS::RMatrix &meanR)
70 {
71  BIASASSERT(TestRotations(R));
72  const unsigned int n = R.size();
73  BIAS::RMatrix resR, meanResR;
74  BIAS::Vector3<double> resW, meanResW;
75  meanR = R[0];
76  double updateAngle; //, lastUpdateAngle = 0.0;
77  for (unsigned int iter = 0; iter < maxIters_; iter++)
78  {
79  // Compute mean residual rotation
80  meanResW.SetZero();
81  for (unsigned int i = 0; i < n; i++)
82  {
83  resR = meanR.Transpose() * R[i];
84  resR.GetRotationAxisAngle(resW);
85  meanResW += resW;
86  }
87  meanResW /= (double)n;
88  // Update mean rotation
89  updateAngle = meanResW.NormL2();
90  BCDOUT(ROTATIONAVERGAGE_ITERS, "Geodesic L2-mean : Iteration " << iter
91  << " : update angle = " << (updateAngle * 180.0 / M_PI) << " degree" << endl);
92  //if (fabs(updateAngle - lastUpdateAngle) < tolerance_)
93  if (updateAngle < tolerance_)
94  break;
95  else {
96  //lastUpdateAngle = updateAngle;
97  meanResW.Normalize();
98  meanResR.Set(meanResW, updateAngle);
99  meanR *= meanResR;
100  }
101  }
102  return 0;
103 }
104 
106 QuaternionL2Mean(const std::vector<BIAS::RMatrix> &R, BIAS::RMatrix &meanR)
107 {
109  std::vector<BIAS::Quaternion<double> > Q;
110  Q.reserve(R.size());
111  for (unsigned int i = 0; i < R.size(); i++) {
112  R[i].GetQuaternion(q);
113  Q.push_back(q);
114  }
116  int res = QuaternionL2Mean(Q, meanQ);
117  if (res == 0)
118  meanR.SetFromQuaternion(meanQ);
119  return res;
120 }
121 
125 {
126  BIASASSERT(TestRotations(Q));
127  meanQ.SetZero();
128  for (unsigned int i = 0; i < Q.size(); i++) {
129  if (Q[i][3] < 0)
130  meanQ -= Q[i];
131  else
132  meanQ += Q[i];
133  }
134  meanQ.MultiplyIP(1.0 / (double)Q.size());
135  meanQ.Normalize();
136  return 0;
137 }
138 
140 LogarithmicL2Mean(const std::vector<BIAS::RMatrix> &R, BIAS::RMatrix &meanR)
141 {
142  BIASASSERT(TestRotations(R));
143  BIAS::Vector3<double> w, meanW(0.0, 0.0, 0.0);
144  for (unsigned int i = 0; i < R.size(); i++) {
145  R[i].GetRotationAxisAngle(w);
146  meanW += w;
147  }
148  meanW.MultiplyIP(1.0 / (double)R.size());
149  meanR.SetFromAxisAngle(meanW);
150  return 0;
151 }
152 
154 ChordalL2Mean(const std::vector<BIAS::RMatrix> &R, BIAS::RMatrix &meanR)
155 {
156  // Implementation of the first algorithm in sec. 3.1 [2]
157  BIASASSERT(TestRotations(R));
159  for (unsigned int i = 0; i < R.size(); i++)
160  S += R[i];
161  S /= (double)R.size();
162  meanR = S;
163  // Set R = U * V^T with S = U * D * V^T calculated from SVD,
164  // multiply R by -1 if determinant det(R) is negative
165  meanR.EnforceConstraints();
166  return 0;
167 }
168 
172 {
173  // Implementation of the second algorithm in sec. 3.1 [2]
174  BIASASSERT(TestRotations(Q));
175  meanQ.SetZero();
177  for (unsigned int i = 0; i < Q.size(); i++)
178  for (unsigned int j = 0; j < 4; j++)
179  for (unsigned int k = 0; k < 4; k++)
180  A[j][k] += Q[i][j]*Q[i][k];
181  BIAS::SVD svd(A);
182  meanQ = BIAS::Quaternion<double>(svd.GetV().GetCol(0));
183  meanQ.Normalize();
184  return 0;
185 }
186 
187 bool RotationAveraging::
188 TestRotations(const std::vector<BIAS::RMatrix> &R)
189 {
190  if (R.empty()) {
191  BIASERR("No input rotations given!");
192  return false;
193  }
194  for (unsigned int i = 0; i < R.size(); i++) {
195  if (BIAS::GreaterEqual(fabs(R[i].GetRotationAngle()), 180.0)) {
196  BIASERR("Input rotation angle larger than 180 degree!");
197  return false;
198  }
199  }
200  return true;
201 }
202 
203 bool RotationAveraging::
204 TestRotations(const std::vector<BIAS::Quaternion<double> > &Q)
205 {
206  if (Q.empty()) {
207  BIASERR("No input rotations given!");
208  return false;
209  }
210  for (unsigned int i = 0; i < Q.size(); i++) {
211  if (BIAS::GreaterEqual(fabs(Q[i].GetRotationAngle()), 180.0)) {
212  BIASERR("Input rotation angle is larger than 180 degree!");
213  return false;
214  }
215  }
216  return true;
217 }
virtual void EnforceConstraints()
Enforce orthonormality constraints and right-handed rotation with SVD.
Definition: RMatrix.cpp:49
computes and holds the singular value decomposition of a rectangular (not necessarily quadratic) Matr...
Definition: SVD.hh:92
int ChordalL2Mean(const std::vector< BIAS::RMatrix > &R, BIAS::RMatrix &meanR)
Compute chordal L2-mean of rotations.
void SetZero()
set all values to 0
Definition: Vector4.hh:702
void SetZero()
set all values to 0
Definition: Vector3.hh:559
int LogarithmicL2Mean(const std::vector< BIAS::RMatrix > &R, BIAS::RMatrix &meanR)
Compute matrix logarithm L2-mean of rotations.
Vector< T > GetCol(const int &col) const
return a copy of column &quot;col&quot;, zero based counting
Definition: Matrix.cpp:252
int SetFromQuaternion(const Quaternion< ROTATION_MATRIX_TYPE > &q)
Set rotation matrix from a quaternion.
3D rotation matrix
Definition: RMatrix.hh:49
void Normalize()
Scales quaternion to unit length, i.e.
Definition: Quaternion.hh:236
void Set(const Vector3< ROTATION_MATRIX_TYPE > &w, const ROTATION_MATRIX_TYPE phi)
Set from rotation axis w and angle phi (in rad)
bool GreaterEqual(const T left, const T right, const T eps=std::numeric_limits< T >::epsilon())
comparison function for floating point values
Matrix< double > GetV() const
return V
Definition: SVD.hh:396
int GeodesicL1Mean(const std::vector< BIAS::RMatrix > &R, BIAS::RMatrix &meanR)
Compute geodesic L1-mean (geodesic median) of rotations.
long int NewDebugLevel(const std::string &name)
creates a new debuglevel
Definition: Debug.hh:474
void MultiplyIP(const T &scalar)
Multiplication (in place) of an scalar.
Definition: Vector3.hh:326
void SetFromAxisAngle(Vector3< ROTATION_MATRIX_TYPE > w)
Set from rotation axis * angle (modified Rodrigues vector)
int GeodesicL2Mean(const std::vector< BIAS::RMatrix > &R, BIAS::RMatrix &meanR)
Compute geodesic L2-mean (Karcher/geometric mean) of rotations.
bool Equal(const T left, const T right, const T eps)
comparison function for floating point values See http://www.boost.org/libs/test/doc/components/test_...
Matrix3x3< T > Transpose() const
returns transposed matrix tested 12.06.2002
Definition: Matrix3x3.cpp:167
void MultiplyIP(const T &scalar)
Multiplication (in place) of an scalar.
Definition: Vector4.hh:609
int GetRotationAxisAngle(Vector3< ROTATION_MATRIX_TYPE > &axis, ROTATION_MATRIX_TYPE &angle) const
Calculates angle and rotation axis representation for this rotation matrix.
int QuaternionL2Mean(const std::vector< BIAS::RMatrix > &R, BIAS::RMatrix &meanR)
Compute quaternion L2-mean of rotations.
Vector3< T > & Normalize()
normalize this vector to length 1
Definition: Vector3.hh:663
double NormL2() const
the L2 norm sqrt(a^2 + b^2 + c^2)
Definition: Vector3.hh:633