Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
RMatrix.cpp
1 /*
2 This file is part of the BIAS library (Basic ImageAlgorithmS).
3 
4 Copyright (C) 2003-2009 (see file CONTACT for details)
5  Multimediale Systeme der Informationsverarbeitung
6  Institut fuer Informatik
7  Christian-Albrechts-Universitaet Kiel
8 
9 
10 BIAS is free software; you can redistribute it and/or modify
11 it under the terms of the GNU Lesser General Public License as published by
12 the Free Software Foundation; either version 2.1 of the License, or
13 (at your option) any later version.
14 
15 BIAS is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Lesser General Public License for more details.
19 
20 You should have received a copy of the GNU Lesser General Public License
21 along with BIAS; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24 
25 
26 #include "RMatrix.hh"
27 #include <MathAlgo/SVD.hh>
28 #include <MathAlgo/Minpack.hh>
29 
30 using namespace BIAS;
31 using namespace std;
32 
33 
35 {}
36 
38  : RMatrixBase(mat)
39 {
40  if ((mat.num_rows() != 3) || (mat.num_cols() != 3)) {
41  BIASERR("wrong matrix size "<<mat.num_rows()<<"x"
42  << mat.num_cols());
43  }
44  pvecR_ = NULL;
45  bestErrorSoFar_ = DBL_MAX;
46  bestQuaternionSoFar_.Set(0,0,0,1);
47 }
48 
50 {
51  // enforce real rotation matrix using SVD
52  // by setting all singular values to unity
53  SVD RotSVD(Matrix<ROTATION_MATRIX_TYPE>(*this));
54  Matrix3x3<ROTATION_MATRIX_TYPE> UVT = RotSVD.GetU() * RotSVD.GetVT();
55  memcpy(this->Data_, UVT.GetData(), 9*sizeof(ROTATION_MATRIX_TYPE));
56 
57  // enforce right-handed system (det = +1)
58  if (this->GetDeterminant() < 0) *this *= -1.0;
59 }
60 
61 int ErrorFunctionAverageRMatrix(void *p, int numerrors, int numvars,
62  const double *x, double *fvec, int iflag)
63 {
64  BIASASSERT(numvars==4);
65  RMatrix *pInstance = (RMatrix *)p;
66  // create rotation matrix vector from parametrization
67  Quaternion<double> q(x[0],x[1],x[2],x[3]);
68  q.Normalize();
69  RMatrixBase R;
70  R.SetFromQuaternion(q);
71 
72 
73  // compute residuum
74  double error = 0, err;
75  for (unsigned int j=0; j<pInstance->pvecR_->size(); j++) {
76  for (unsigned int row=0; row<3; row++) {
77  for (unsigned int col=0; col<3; col++) {
78  err = fvec[9*j+3*col+row]
79  = R[row][col] - (*pInstance->pvecR_)[j][row][col];
80  error += err*err;
81  }
82  }
83  }
84 
85  // in case LM runs out of iterations, remember best in a global variable
86  if (error<pInstance->bestErrorSoFar_) {
87  pInstance->bestErrorSoFar_ = error;
88  pInstance->bestQuaternionSoFar_ = q;
89  }
90  cout<<error<<" ";
91  return 0;
92 }
93 
94 RMatrix RMatrix::GetAverageRMatrix(std::vector<RMatrix>& vecR,
95  bool RefineRotation)
96 {
97  if (vecR.empty()) {
98  BIASERR("Empty vector given for average rotation matrix estimation!");
99  return RMatrix(MatrixIdentity);
100  }
101  BIASWARN("Untested code for average rotation matrix computation so far!");
102  RMatrix result = vecR[0];
103  Vector3<double> axis(0,0,0);
104  double angle(0.0);
105  double weight(1.0);
106  // For the first two matrices we have RDiff = vecR[0] * vecR[1].Transpose();
107  // Therefore result = sqrt(Rdiff) * vecR[1] = sqrt(Rdiff^T) * vecR[1]
108  // is an average orientation, where square root is realized by axis-angle
109  // decomposition (sqrt = half angle)
110  for (unsigned int i = 1; i < vecR.size(); i++) {
111  // After the first averaging, our result becomes more reliable, so
112  // use a higher weight each time.
113  // This is equivalent to not using sqrt = ^0.5 but ^weight
114  weight = 1.0 / double(i+1);
115  RMatrix RDiff = result * vecR[i].Transpose();
116  RDiff.GetRotationAxisAngle(axis, angle);
117  // Compute transposed of difference multiplied by -1 and go only by
118  // weight into this new direction
119  angle *= -1.0 * weight;
120  RDiff.Set(axis, angle);
121  result = RDiff * result;
122  result.EnforceConstraints();
123  }
124 
125  // Take this as start value for nonlinear optimization (opt.)
126  if (RefineRotation) {
127  pvecR_ = &vecR;
128  bestErrorSoFar_ = DBL_MAX;
129  long int num_params = 4;
130  long int num_errors = 9 * vecR.size();
131  long int max_error_calls = 1000;
132  double epsilon = 0.02; // used for Jcobian approximation
133 
134  // Setup parametrization
135  Quaternion<double> q(0,0,0,1), qres(0,0,0,1);
136  result.GetQuaternion(q);
137  Vector<double> qvec(4), qresvec(4);
138  for (unsigned int i = 0; i < 4; i++) qvec[i] = q[i];
139 
140  // Compute solution with Levenberg-Marquardt algorithm
141  long int LMResult =
142  LevenbergMarquardtExtended(&ErrorFunctionAverageRMatrix,
143  (void*)(this), num_errors, num_params,
144  qvec, qresvec, epsilon,
145  1e-10, max_error_calls);
146  if ((LMResult != LM_OK) && (LMResult != LM_TOO_MANY_IT)) {
147  BIASERR("Error in Levenberg-Marquardt optimization (error code is "
148  << LMResult << ")");
149  } else {
150  cout << "Levenberg-Marquardt optimization finished with code "
151  << LMResult << endl;
153  cout << "-> best error so far is " << bestErrorSoFar_ << endl;
154  }
155  }
156 
157  return result;
158 }
virtual void EnforceConstraints()
Enforce orthonormality constraints and right-handed rotation with SVD.
Definition: RMatrix.cpp:49
long int LevenbergMarquardtExtended(minpack_funcder_mn fun, void *p, long int m, long int n, Vector< double > &InitialGuess, Vector< double > &Result, double Tolerance, long int MaxIter)
Solves an overdetermined system f(x) = 0 of m non-linear equations with n parameters using the extend...
Definition: Minpack.cpp:131
std::vector< RMatrix > * pvecR_
Definition: RMatrix.hh:82
computes and holds the singular value decomposition of a rectangular (not necessarily quadratic) Matr...
Definition: SVD.hh:92
Subscript num_cols() const
Definition: cmat.h:320
void Set(const T &scalar)
set all elements to a scalat value
Definition: Vector4.hh:421
int SetFromQuaternion(const Quaternion< ROTATION_MATRIX_TYPE > &q)
Set rotation matrix from a quaternion.
int GetQuaternion(Quaternion< ROTATION_MATRIX_TYPE > &quat) const
Calculates quaternion representation for this rotation matrix.
double bestErrorSoFar_
Definition: RMatrix.hh:84
3D rotation matrix
Definition: RMatrix.hh:49
virtual ~RMatrix()
Definition: RMatrix.cpp:34
void Set(const Vector3< ROTATION_MATRIX_TYPE > &w, const ROTATION_MATRIX_TYPE phi)
Set from rotation axis w and angle phi (in rad)
const Matrix< double > & GetVT() const
return VT (=transposed(V))
Definition: SVD.hh:177
Quaternion< double > bestQuaternionSoFar_
Definition: RMatrix.hh:86
matrix class with arbitrary size, indexing is row major.
RMatrix GetAverageRMatrix(std::vector< RMatrix > &vecR, bool RefineRotation=true)
Compute average rotation by pairwise weighted averaging of matrices.
Definition: RMatrix.cpp:94
const Matrix< double > & GetU() const
return U U is a m x m orthogonal matrix
Definition: SVD.hh:187
ROTATION_MATRIX_TYPE GetDeterminant() const
returns the Determinant |A| of this
Implements a 3D rotation matrix.
Definition: RMatrixBase.hh:44
Subscript num_rows() const
Definition: cmat.h:319
int GetRotationAxisAngle(Vector3< ROTATION_MATRIX_TYPE > &axis, ROTATION_MATRIX_TYPE &angle) const
Calculates angle and rotation axis representation for this rotation matrix.