Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
TestRMatrix.cpp
1 /* This file is part of the BIAS library (Basic ImageAlgorithmS).
2 
3  Copyright (C) 2003-2009 (see file CONTACT for details)
4  Multimediale Systeme der Informationsverarbeitung
5  Institut fuer Informatik
6  Christian-Albrechts-Universitaet Kiel
7 
8  BIAS is free software; you can redistribute it and/or modify
9  it under the terms of the GNU Lesser General Public License as published by
10  the Free Software Foundation; either version 2.1 of the License, or
11  (at your option) any later version.
12 
13  BIAS is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU Lesser General Public License for more details.
17 
18  You should have received a copy of the GNU Lesser General Public License
19  along with BIAS; if not, write to the Free Software
20  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
21 
22 #include <Geometry/RMatrix.hh>
23 #include <Base/Geometry/RMatrixBase.hh>
24 #include <Base/Math/Random.hh>
25 #include <Base/Math/Vector3.hh>
26 #include <iostream>
27 #include <stdio.h>
28 #include <string>
29 #include <vector>
30 
31 using namespace BIAS;
32 using namespace std;
33 
34 void computeRandomVec(BIAS::Random &random, BIAS::Vector3<double> &vec)
35 {
36  double phi = random.GetUniformDistributed(-1.0, 1.0) * M_PI;
37  double theta = random.GetUniformDistributed(-0.5, 0.5) * M_PI;
38  vec[0] = sin(phi) * cos(theta);
39  vec[1] = -sin(theta);
40  vec[2] = cos(phi) * cos(theta);
41 }
42 
43 void printMatrix3x3(BIAS::Matrix3x3<double> &mat, const std::string &name)
44 {
45  printf("%s = [ % 1.6f % 1.6f % 1.6f ; % 1.6f % 1.6f % 1.6f ; % 1.6f % 1.6f % 1.6f ]\n",
46  name.c_str(), mat[0][0], mat[0][1], mat[0][2],
47  mat[1][0], mat[1][1], mat[1][2], mat[2][0], mat[2][1], mat[2][2]);
48 }
49 
50 /**
51  @file TestRMatrix.cpp
52  @brief Comparison of RMatrix and RMatrixNase classes for testing.
53 
54  Computes random rotation matrices from slightly non-orthogonal row vectors
55  and applies different orthonormalization strategies implemented in RMatrix
56  and RMatrixBase EnforceConstraints() methods. The resulting matrices are
57  compared and their orthonormality constraints are checked for validity.
58 
59  Addtional, random vectors are rotated by the resulting matrices and their
60  differences are evaluated. Note that the resulting matrices will differ by
61  an order of magnitude comparable to the error on the matrix rows. This is
62  due to the different orthonormalisation algorithms used (Gram-Schmidt vs.
63  SVD based orthonormalization). However, the SVD based method from RMatrix
64  provides better results as compared to the original rotation matrix.
65 
66  @relates RMatrix
67  @ingroup g_tests
68  @author MIP
69 */
70 int main(int argc, char *argv[])
71 {
72  // read parameters
73  const int numMatrix = argc > 1 ? std::max(1, atoi(argv[1])) : 100;
74  const int numVector = argc > 2 ? std::max(1, atoi(argv[2])) : 100;
75  const double errorStd = argc > 3 ? std::min(1.0, fabs(atof(argv[3]))) : 0.01;
76  const double matrixErrorThreshold = 1; //0.01;
77  const double matrixCheckThreshold = 1e-10;
78  Random random;
79  cout << "\nUsage : TestRMatrix [<num matrices>] [<num vectors>] [<error sigma>]\n\n"
80  << "Starting tests with " << numMatrix << " rotation matrices and "
81  << numVector << " 3d vectors with error sigma " << errorStd << " ...\n";
82 
83  // create random vectors for matrix-vector-multiplication tests
84  vector<Vector3<double> > vecs3d(numVector);
85  for (int vnum = 0; vnum < numVector; vnum++)
86  computeRandomVec(random, vecs3d[vnum]);
87  double meanVectorError = 0, stdVectorError = 0;
88 
89  // create random rotation matrices from row vectors
90  Vector3<double> rx, ry, rz;
91  RMatrix R;
92  RMatrixBase Rbase, Rgt;
93  double meanMatrixError = 0, stdMatrixError = 0;
94  int numMatrixFailed = 0;
95  for (int mnum = 0; mnum < numMatrix; mnum++)
96  {
97  // compute orthonormal vectors
98  computeRandomVec(random, rx);
99  int min_id = (fabs(rx[1]) < fabs(rx[0])) ? 1 : 0;
100  if (fabs(rx[2]) < fabs(rx[min_id])) min_id = 2;
101  ry.SetZero();
102  ry[min_id] = 1;
103  rz = rx.CrossProduct(ry);
104  rz.Normalize();
105  ry = rx.CrossProduct(rz);
106  ry.Normalize();
107 
108  // check ground truth rotation matrix
109  for (int k = 0; k < 3; k++) {
110  Rgt[0][k] = rx[k];
111  Rgt[1][k] = ry[k];
112  Rgt[2][k] = rz[k];
113  }
114  if (Rgt.GetDeterminant() < 0) Rgt *= -1.0;
115  BIASASSERT(Rgt.Check(matrixCheckThreshold));
116 
117  // distort vectors
118  for (int k = 0; k < 3; k++) {
119  rx[k] += random.GetNormalDistributed(0, errorStd);
120  ry[k] += random.GetNormalDistributed(0, errorStd);
121  rz[k] += random.GetNormalDistributed(0, errorStd);
122  }
123  rx.Normalize();
124  ry.Normalize();
125  rz.Normalize();
126 
127  // set rotation matrices from vectors
128  for (int k = 0; k < 3; k++) {
129  R[0][k] = Rbase[0][k] = rx[k];
130  R[1][k] = Rbase[1][k] = ry[k];
131  R[2][k] = Rbase[2][k] = rz[k];
132  }
133  R.EnforceConstraints();
134  Rbase.EnforceConstraints();
135  const bool checkR = R.Check(matrixCheckThreshold);
136  const bool checkRbase = Rbase.Check(matrixCheckThreshold);
137 
138  // evaluate matrix error
139  double error = (Matrix3x3<double>(R) - Matrix3x3<double>(Rbase)).NormL2();
140  meanMatrixError += error;
141  stdMatrixError += error * error;
142  if (error > matrixErrorThreshold || !checkR || !checkRbase) {
143  numMatrixFailed++;
144  cout << "Test " << (mnum+1) << " / " << numMatrix << " failed : \n";
145  if (!checkR)
146  cout << "-> R is not orthonormal : "
147  << R.GetCheckFailureReason(matrixCheckThreshold) << "\n";
148  if (!checkRbase)
149  cout << "-> Rbase is not orthonormal : "
150  << Rbase.GetCheckFailureReason(matrixCheckThreshold) << "\n";
151  if (error > matrixErrorThreshold)
152  cout << "-> Difference " << error << " is too large!\n";
153  printMatrix3x3(R, "-> R");
154  printMatrix3x3(Rbase, "-> Rbase");
155  cout << "--------------------------------------------------\n";
156  }
157 
158  // evaluate matrix-vector-multiplication errors
159  for (int vnum = 0; vnum < numVector; vnum++) {
160  error = (R*vecs3d[vnum] - Rbase*vecs3d[vnum]).NormL2();
161  meanVectorError += error;
162  stdVectorError += error * error;
163  }
164  }
165 
166  // print results
167  meanMatrixError /= numMatrix;
168  stdMatrixError = sqrt(stdMatrixError / numMatrix -
169  meanMatrixError * meanMatrixError);
170  meanVectorError /= numMatrix * numVector;
171  stdVectorError = sqrt(stdVectorError / (numMatrix * numVector) -
172  meanVectorError * meanVectorError);
173  cout << "\nResults : " << numMatrixFailed << " / " << numMatrix
174  << " tests failed (" << numMatrixFailed / (0.01 * numMatrix) << " %)\n";
175  cout << "-> average difference between RMatrix and RMatrixBase : "
176  << meanMatrixError << " +- " << stdMatrixError << "\n"
177  << "-> average difference between rotated unit vectors : "
178  << meanVectorError << " +- " << stdVectorError << "\n\n";
179 
180  return 0;
181 }
virtual void EnforceConstraints()
Enforce orthonormality constraints and right-handed rotation with SVD.
Definition: RMatrix.cpp:49
void SetZero()
set all values to 0
Definition: Vector3.hh:559
bool Check(const double eps=std::numeric_limits< double >::epsilon(), const bool verbose=false) const
Check if this is a rotation matrix, i.e.
double GetUniformDistributed(const double min, const double max)
on succesive calls return uniform distributed random variable between min and max ...
Definition: Random.hh:84
3D rotation matrix
Definition: RMatrix.hh:49
virtual void EnforceConstraints()
Enforce orthonormality constraint on rotation matrix and sets determinant to +1.
std::string GetCheckFailureReason(const double eps=std::numeric_limits< double >::epsilon()) const
Return the reason for the constraint check failure in a human readable string.
void CrossProduct(const Vector3< T > &argvec, Vector3< T > &destvec) const
cross product of two vectors destvec = this x argvec
Definition: Vector3.hh:594
T GetDeterminant() const
returns the Determinant |A| of this
Definition: Matrix3x3.cpp:347
Implements a 3D rotation matrix.
Definition: RMatrixBase.hh:44
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
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