Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
ExampleRotationAveraging.cpp
1 #include <Geometry/RotationAveraging.hh>
2 #include <Base/Geometry/Quaternion.hh>
3 #include <Base/Math/Matrix.hh>
4 #include <Base/Math/Random.hh>
5 #include <Geometry/RMatrix.hh>
6 #include <fstream>
7 #include <string>
8 #include <vector>
9 
10 using namespace std;
11 using namespace BIAS;
12 
13 /**
14  @example ExampleRotationAveraging
15  @brief Example for usage of rotation averaging. Compares different
16  algorithms to compute the mean of rotations with respect to
17  some distance measure d: SO(3) x SO(3) -> R.
18  @see RotationAveraging
19  @ingroup g_examples
20  @author esquivel
21  @date 09/2011
22  */
23 
24 double AngleError(const BIAS::RMatrix &R, const BIAS::RMatrix &S)
25 {
26  BIAS::RMatrix dR = R * S.Transpose();
27  double dAngle = dR.GetRotationAngle();
28  return std::min(fabs(dAngle), std::min(fabs(dAngle + 2*M_PI), fabs(dAngle - 2*M_PI)));
29 }
30 
31 double AngleError(const BIAS::Quaternion<double> &Q, const BIAS::Quaternion<double> &P)
32 {
33  BIAS::Quaternion<double> dQ = Q * P.Inverse();
34  double dAngle = dQ.GetRotationAngle();
35  return std::min(fabs(dAngle), std::min(fabs(dAngle + 2*M_PI), fabs(dAngle - 2*M_PI)));
36 }
37 
38 void AccumulateError(double error, double &sum, double &sqsum, unsigned int &count)
39 {
40  sum += error;
41  sqsum += error*error;
42  count++;
43 }
44 
45 int main(int argc, char** argv)
46 {
47  const unsigned int trials = 100;
48  const double sigma = 2.0 * M_PI / 180.0;
49  const unsigned int minNum = 10, maxNum = 80, numStep = 10;
50  const unsigned int range = (maxNum - minNum) / numStep + 1;
51  const unsigned int methods = 7;
52  std::vector<std::vector<double> > avgErrors(methods, std::vector<double>(range, 0.0));
53  std::vector<std::vector<double> > stdErrors(methods, std::vector<double>(range, 0.0));
54  std::vector<std::string> methodNames(methods);
55  methodNames[0] = "angle/axis L2-mean";
56  methodNames[1] = "quaternion L2-mean";
57  methodNames[2] = "geodesic L2-mean";
58  methodNames[3] = "geodesic L1-mean";
59  methodNames[4] = "chordal L2-mean";
60  methodNames[5] = "quaternion L2 (quat.)";
61  methodNames[6] = "chordal L2 (quat.)";
62 
63  BIAS::Random randomizer;
64  BIAS::RotationAveraging algorithm;
65  algorithm.SetTolerance(1e-12);
66  algorithm.SetMaxIterations(25);
67 
68  cout << "Computing mean rotation for " << minNum << " to " << maxNum
69  << " rotation measurements with angular error of sigma = "
70  << sigma * 180.0 / M_PI << " degree for " << trials << " trials" << endl;
71  for (unsigned int k = 0; k < range; k++)
72  {
73  const unsigned int num = minNum + k * numStep;
74  std::vector<unsigned int> numSuccess(methods, 0);
75  for (unsigned int t = 0; t < trials; t++)
76  {
77  // Compute ground truth rotation R_gt
78  BIAS::RMatrix gtR;
79  BIAS::Vector3<double> gtAxis;
80  for (unsigned int j = 0; j < 3; j++)
81  gtAxis[j] = randomizer.GetUniformDistributed(-1.0, 1.0);
82  gtAxis.Normalize();
83  double gtAngle = randomizer.GetUniformDistributed(0.0, M_PI/2);
84  gtR.SetFromAxisAngle(gtAngle * gtAxis);
86  gtR.GetQuaternion(gtQ);
87 
88  // Compute n random measurements R_i for R_gt with noise
89  std::vector<BIAS::RMatrix> measR;
90  measR.reserve(num);
91  std::vector<BIAS::Quaternion<double> > measQ;
92  measQ.reserve(num);
93  for (unsigned int i = 0; i < num; i++)
94  {
95  BIAS::Vector3<double> errAxis;
96  for (unsigned int j = 0; j < 3; j++)
97  errAxis[j] = randomizer.GetUniformDistributed(-1.0, 1.0);
98  errAxis.Normalize();
99  double errAngle = randomizer.GetNormalDistributed(0.0, sigma);
100  BIAS::RMatrix errR;
101  errR.SetFromAxisAngle(errAngle * errAxis);
102  measR.push_back(gtR * errR);
104  errR.GetQuaternion(errQ);
105  measQ.push_back(gtQ * errQ);
106  }
107  // Compute mean rotation with different methods
108  BIAS::RMatrix meanR;
110  if (algorithm.LogarithmicL2Mean(measR, meanR) == 0)
111  AccumulateError(AngleError(gtR, meanR),
112  avgErrors[0][k], stdErrors[0][k], numSuccess[0]);
113  if (algorithm.QuaternionL2Mean(measR, meanR) == 0)
114  AccumulateError(AngleError(gtR, meanR),
115  avgErrors[1][k], stdErrors[1][k], numSuccess[1]);
116  if (algorithm.GeodesicL2Mean(measR, meanR) == 0)
117  AccumulateError(AngleError(gtR, meanR),
118  avgErrors[2][k], stdErrors[2][k], numSuccess[2]);
119  if (algorithm.GeodesicL1Mean(measR, meanR) == 0)
120  AccumulateError(AngleError(gtR, meanR),
121  avgErrors[3][k], stdErrors[3][k], numSuccess[3]);
122  if (algorithm.ChordalL2Mean(measR, meanR) == 0)
123  AccumulateError(AngleError(gtR, meanR),
124  avgErrors[4][k], stdErrors[4][k], numSuccess[4]);
125  if (algorithm.QuaternionL2Mean(measQ, meanQ) == 0)
126  AccumulateError(AngleError(gtQ, meanQ),
127  avgErrors[5][k], stdErrors[5][k], numSuccess[5]);
128  if (algorithm.ChordalL2Mean(measQ, meanQ) == 0)
129  AccumulateError(AngleError(gtQ, meanQ),
130  avgErrors[6][k], stdErrors[6][k], numSuccess[6]);
131  cout << "\r" << (int)(100.0 * (k*trials+t+1) / (double)(range*trials))
132  << "% done..." << flush;
133  }
134  // Compute mean estimation error
135  for (unsigned int m = 0; m < methods; m++) {
136  avgErrors[m][k] /= (double)numSuccess[m];
137  stdErrors[m][k] = sqrt(stdErrors[m][k] / (double)numSuccess[m] -
138  avgErrors[m][k]*avgErrors[m][k]);
139  }
140  }
141  cout << endl;
142 
143  // Print results
144  printf(" %21s ", "Average errors");
145  for (unsigned int k = 0; k < range; k++)
146  printf("| %8d ", minNum + k * numStep);
147  cout << "rotations" << endl << flush;
148  for (unsigned int i = 0; i < 23; i++)
149  cout << "-";
150  for (unsigned int k = 0; k < range; k++)
151  cout << "+----------";
152  cout << "---------" << endl << flush;
153  for (unsigned int m = 0; m < methods; m++) {
154  printf(" %21s ", methodNames[m].c_str());
155  for (unsigned int k = 0; k < range; k++)
156  printf("| %6f ", avgErrors[m][k]*180.0/M_PI);
157  cout << "degree" << endl << flush;
158  printf(" %18s +- ", "");
159  for (unsigned int k = 0; k < range; k++)
160  printf("| %6f ", stdErrors[m][k]*180.0/M_PI);
161  cout << "degree" << endl << flush;
162  for (unsigned int i = 0; i < 23; i++)
163  cout << "-";
164  for (unsigned int k = 0; k < range; k++)
165  cout << "+----------";
166  cout << "---------" << endl << flush;
167  }
168 
169  // Write results to log file
170  const std::string filename = "ExampleRotationAveraging.log";
171  std::ofstream fout(filename.c_str());
172  for (unsigned int k = 0; k < range; k++)
173  fout << minNum + k * numStep << " ";
174  fout << endl << flush;
175  for (unsigned int m = 0; m < methods; m++) {
176  for (unsigned int k = 0; k < range; k++)
177  fout << avgErrors[m][k] << " ";
178  fout << endl << flush;
179  }
180  fout.close();
181  cout << "Results written to file \"" << filename << "\"." << endl;
182 
183  // Write results to Matlab file
184  const std::string mfilename = "ExampleRotationAveraging.m";
185  std::ofstream mfout(mfilename.c_str());
186  mfout << "x = [ ";
187  for (unsigned int k = 0; k < range; k++)
188  mfout << minNum + k * numStep << " ";
189  mfout << "];" << endl << flush;
190  mfout << "y = [ ";
191  for (unsigned int m = 0; m < methods; m++) {
192  for (unsigned int k = 0; k < range; k++)
193  mfout << avgErrors[m][k] << " ";
194  if (m+1 == methods)
195  mfout << "];" << endl << flush;
196  else
197  mfout << endl << " " << flush;
198  }
199  mfout << "plot(x, y*180/pi)" << endl;
200  mfout << "legend(";
201  for (unsigned int m = 0; m < methods; m++) {
202  mfout << "'" << methodNames[m] << "'";
203  if (m+1 < methods) mfout << ", ";
204  }
205  mfout << ")" << endl << flush;
206  mfout.close();
207  cout << "Created Matlab plot file \"" << mfilename << "\"." << endl;
208 
209  return 0;
210 }
void SetMaxIterations(unsigned int num)
Set maximal number of iterations for geodesic L1-/L2-mean computation.
int ChordalL2Mean(const std::vector< BIAS::RMatrix > &R, BIAS::RMatrix &meanR)
Compute chordal L2-mean of rotations.
int LogarithmicL2Mean(const std::vector< BIAS::RMatrix > &R, BIAS::RMatrix &meanR)
Compute matrix logarithm L2-mean of rotations.
double GetUniformDistributed(const double min, const double max)
on succesive calls return uniform distributed random variable between min and max ...
Definition: Random.hh:84
void SetTolerance(double epsilon)
Set threshold for convergence of iterative geodesic L1-/L2-mean computation.
int GetQuaternion(Quaternion< ROTATION_MATRIX_TYPE > &quat) const
Calculates quaternion representation for this rotation matrix.
3D rotation matrix
Definition: RMatrix.hh:49
Quaternion< QUAT_TYPE > Inverse() const
returns the Inverse rotation Quaternion
Definition: Quaternion.hh:42
QUAT_TYPE GetRotationAngle() const
Returns rotation angle notation in radians.
int GeodesicL1Mean(const std::vector< BIAS::RMatrix > &R, BIAS::RMatrix &meanR)
Compute geodesic L1-mean (geodesic median) of rotations.
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.
Matrix3x3< T > Transpose() const
returns transposed matrix tested 12.06.2002
Definition: Matrix3x3.cpp:167
Computes mean of rotations due to different measures.
double GetNormalDistributed(const double mean, const double sigma)
on succesive calls return normal distributed random variable with mean and standard deviation sigma ...
Definition: Random.hh:71
int QuaternionL2Mean(const std::vector< BIAS::RMatrix > &R, BIAS::RMatrix &meanR)
Compute quaternion L2-mean of rotations.
ROTATION_MATRIX_TYPE GetRotationAngle() const
Interface for angle component of GetRotationAxisAngle()
Vector3< T > & Normalize()
normalize this vector to length 1
Definition: Vector3.hh:663
class for producing random numbers from different distributions
Definition: Random.hh:51