TooN
sim3.h
1 // -*- c++ -*-
2 
3 // Copyright (C) 2011 Tom Drummond (twd20@cam.ac.uk)
4 
5 //All rights reserved.
6 //
7 //Redistribution and use in source and binary forms, with or without
8 //modification, are permitted provided that the following conditions
9 //are met:
10 //1. Redistributions of source code must retain the above copyright
11 // notice, this list of conditions and the following disclaimer.
12 //2. Redistributions in binary form must reproduce the above copyright
13 // notice, this list of conditions and the following disclaimer in the
14 // documentation and/or other materials provided with the distribution.
15 //
16 //THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
17 //AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 //IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 //ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
20 //LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 //CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 //SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 //INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 //CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 //ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 //POSSIBILITY OF SUCH DAMAGE.
27 
28 #ifndef TOON_INCLUDE_SIM3_H
29 #define TOON_INCLUDE_SIM3_H
30 
31 #include <TooN/se3.h>
32 
33 namespace TooN {
34 
35 
47 template <typename Precision = DefaultPrecision>
48 class SIM3 {
49 public:
51  inline SIM3() : my_scale(1) {}
52 
53  template <int S, typename P, typename A>
54  SIM3(const SO3<Precision> & R, const Vector<S, P, A>& T, const Precision & s) : my_se3(R,T), my_scale(s) {}
55  template <int S, typename P, typename A>
56  SIM3(const Vector<S, P, A> & v) { *this = exp(v); }
57 
59  inline SO3<Precision>& get_rotation(){return my_se3.get_rotation();}
61  inline const SO3<Precision>& get_rotation() const {return my_se3.get_rotation();}
62 
64  inline Vector<3, Precision>& get_translation() {return my_se3.get_translation();}
66  inline const Vector<3, Precision>& get_translation() const {return my_se3.get_translation();}
67 
69  inline Precision & get_scale() { return my_scale; }
71  inline const Precision & get_scale() const { return my_scale; }
72 
76  template <int S, typename P, typename A>
77  static inline SIM3 exp(const Vector<S, P, A>& vect);
78 
81  static inline Vector<7, Precision> ln(const SIM3& se3);
83  inline Vector<7, Precision> ln() const { return SIM3::ln(*this); }
84 
85  inline SIM3 inverse() const {
86  const SO3<Precision> rinv = get_rotation().inverse();
87  const Precision inv_scale = 1/my_scale;
88  return SIM3(rinv, -(inv_scale*(rinv*get_translation())), inv_scale);
89  }
90 
93  inline SIM3& operator *=(const SIM3& rhs) {
95  get_rotation() *= rhs.get_rotation();
96  get_scale() *= rhs.get_scale();
97  return *this;
98  }
99 
102  return *this = SIM3<>();
103  }
104 
107  template<typename P>
110  }
111 
112  inline SIM3& left_multiply_by(const SIM3& left) {
113  get_translation() = left.get_translation() + left.get_rotation() * (left.get_scale() * get_translation());
114  get_rotation() = left.get_rotation() * get_rotation();
115  get_scale() = left.get_scale() * get_scale();
116  return *this;
117  }
118 
119  static inline Matrix<4,4,Precision> generator(int i){
120  Matrix<4,4,Precision> result(Zeros);
121  if(i < 3){
122  result(i,3)=1;
123  return result;
124  }
125  if(i < 6){
126  result[(i+1)%3][(i+2)%3] = -1;
127  result[(i+2)%3][(i+1)%3] = 1;
128  return result;
129  }
130  result(0,0) = 1;
131  result(1,1) = 1;
132  result(2,2) = 1;
133  return result;
134  }
135 
137  template<typename Base>
139  {
140  Vector<4, Precision> result(Zeros);
141  if(i < 3){
142  result[i]=pos[3];
143  return result;
144  }
145  if(i < 6){
146  result[(i+1)%3] = - pos[(i+2)%3];
147  result[(i+2)%3] = pos[(i+1)%3];
148  return result;
149  }
150  result.template slice<0,3>() = pos.template slice<0,3>();
151  return result;
152  }
153 
159  template<int S, typename P2, typename Accessor>
160  inline Vector<7, Precision> adjoint(const Vector<S,P2, Accessor>& vect)const;
161 
164  template<int S, typename P2, typename Accessor>
166 
168  template <int R, int C, typename P2, typename Accessor>
170 
172  template <int R, int C, typename P2, typename Accessor>
174 
175 private:
176  SE3<Precision> my_se3;
177  Precision my_scale;
178 };
179 
181 template<class P>
182 SIM3<P> operator *(const SIM3<P>& lhs, const SE3<P>& rhs_) {
183  SIM3<P> rhs;
184  rhs.get_rotation() = rhs_.get_rotation();
185  rhs.get_translation() = rhs_.get_translation();
186  return lhs*rhs;
187 }
188 
189 // transfers a vector in the Lie algebra
190 // from one coord frame to another
191 // so that exp(adjoint(vect)) = (*this) * exp(vect) * (this->inverse())
192 template<typename Precision>
193 template<int S, typename P2, typename Accessor>
195  SizeMismatch<7,S>::test(7, vect.size());
196  Vector<7, Precision> result;
197  result.template slice<3,3>() = get_rotation() * vect.template slice<3,3>();
198  result.template slice<0,3>() = get_rotation() * vect.template slice<0,3>();
199  result.template slice<0,3>() += get_translation() ^ result.template slice<3,3>();
200  return result;
201 }
202 
203 // tansfers covectors between frames
204 // (using the transpose of the inverse of the adjoint)
205 // so that trinvadjoint(vect1) * adjoint(vect2) = vect1 * vect2
206 template<typename Precision>
207 template<int S, typename P2, typename Accessor>
209  SizeMismatch<7,S>::test(7, vect.size());
210  Vector<7, Precision> result;
211  result.template slice<3,3>() = get_rotation() * vect.template slice<3,3>();
212  result.template slice<0,3>() = get_rotation() * vect.template slice<0,3>();
213  result.template slice<3,3>() += get_translation() ^ result.template slice<0,3>();
214  return result;
215 }
216 
217 template<typename Precision>
218 template<int R, int C, typename P2, typename Accessor>
220  SizeMismatch<7,R>::test(7, M.num_cols());
221  SizeMismatch<7,C>::test(7, M.num_rows());
222 
223  Matrix<7,7,Precision> result;
224  for(int i=0; i<7; i++){
225  result.T()[i] = adjoint(M.T()[i]);
226  }
227  for(int i=0; i<7; i++){
228  result[i] = adjoint(result[i]);
229  }
230  return result;
231 }
232 
233 template<typename Precision>
234 template<int R, int C, typename P2, typename Accessor>
236  SizeMismatch<7,R>::test(7, M.num_cols());
237  SizeMismatch<7,C>::test(7, M.num_rows());
238 
239  Matrix<7,7,Precision> result;
240  for(int i=0; i<7; i++){
241  result.T()[i] = trinvadjoint(M.T()[i]);
242  }
243  for(int i=0; i<7; i++){
244  result[i] = trinvadjoint(result[i]);
245  }
246  return result;
247 }
248 
251 template <typename Precision>
252 inline std::ostream& operator <<(std::ostream& os, const SIM3<Precision>& rhs){
253  std::streamsize fw = os.width();
254  for(int i=0; i<3; i++){
255  os.width(fw);
256  os << rhs.get_rotation().get_matrix()[i] * rhs.get_scale();
257  os.width(fw);
258  os << rhs.get_translation()[i] << '\n';
259  }
260  return os;
261 }
262 
263 
266 template <typename Precision>
267 inline std::istream& operator>>(std::istream& is, SIM3<Precision>& rhs){
268  for(int i=0; i<3; i++){
269  is >> rhs.get_rotation().my_matrix[i].ref() >> rhs.get_translation()[i];
270  }
271  rhs.get_scale() = (norm(rhs.get_rotation().my_matrix[0]) + norm(rhs.get_rotation().my_matrix[1]) + norm(rhs.get_rotation().my_matrix[2]))/3;
272  rhs.get_rotation().coerce();
273  return is;
274 }
275 
277 // operator * //
278 // SIM3 * Vector //
280 
281 namespace Internal {
282 template<int S, typename PV, typename A, typename P>
283 struct SIM3VMult;
284 }
285 
286 template<int S, typename PV, typename A, typename P>
287 struct Operator<Internal::SIM3VMult<S,PV,A,P> > {
288  const SIM3<P> & lhs;
289  const Vector<S,PV,A> & rhs;
290 
291  Operator(const SIM3<P> & l, const Vector<S,PV,A> & r ) : lhs(l), rhs(r) {}
292 
293  template <int S0, typename P0, typename A0>
294  void eval(Vector<S0, P0, A0> & res ) const {
295  SizeMismatch<4,S>::test(4, rhs.size());
296  res.template slice<0,3>()=lhs.get_rotation() * (lhs.get_scale() * rhs.template slice<0,3>());
297  res.template slice<0,3>()+=TooN::operator*(lhs.get_translation(),rhs[3]);
298  res[3] = rhs[3];
299  }
300  int size() const { return 4; }
301 };
302 
305 template<int S, typename PV, typename A, typename P> inline
308 }
309 
312 template <typename PV, typename A, typename P> inline
314  return lhs.get_translation() + lhs.get_rotation() * (lhs.get_scale() * rhs);
315 }
316 
318 // operator * //
319 // Vector * SIM3 //
321 
322 namespace Internal {
323 template<int S, typename PV, typename A, typename P>
324 struct VSIM3Mult;
325 }
326 
327 template<int S, typename PV, typename A, typename P>
328 struct Operator<Internal::VSIM3Mult<S,PV,A,P> > {
329  const Vector<S,PV,A> & lhs;
330  const SIM3<P> & rhs;
331 
332  Operator( const Vector<S,PV,A> & l, const SIM3<P> & r ) : lhs(l), rhs(r) {}
333 
334  template <int S0, typename P0, typename A0>
335  void eval(Vector<S0, P0, A0> & res ) const {
336  SizeMismatch<4,S>::test(4, lhs.size());
337  res.template slice<0,3>()= rhs.get_scale() * lhs.template slice<0,3>() * rhs.get_rotation();
338  res[3] = lhs[3];
339  res[3] += lhs.template slice<0,3>() * rhs.get_translation();
340  }
341  int size() const { return 4; }
342 };
343 
346 template<int S, typename PV, typename A, typename P> inline
349 }
350 
352 // operator * //
353 // SIM3 * Matrix //
355 
356 namespace Internal {
357 template <int R, int C, typename PM, typename A, typename P>
358 struct SIM3MMult;
359 }
360 
361 template<int R, int Cols, typename PM, typename A, typename P>
362 struct Operator<Internal::SIM3MMult<R, Cols, PM, A, P> > {
363  const SIM3<P> & lhs;
364  const Matrix<R,Cols,PM,A> & rhs;
365 
366  Operator(const SIM3<P> & l, const Matrix<R,Cols,PM,A> & r ) : lhs(l), rhs(r) {}
367 
368  template <int R0, int C0, typename P0, typename A0>
369  void eval(Matrix<R0, C0, P0, A0> & res ) const {
370  SizeMismatch<4,R>::test(4, rhs.num_rows());
371  for(int i=0; i<rhs.num_cols(); ++i)
372  res.T()[i] = lhs * rhs.T()[i];
373  }
374  int num_cols() const { return rhs.num_cols(); }
375  int num_rows() const { return 4; }
376 };
377 
380 template <int R, int Cols, typename PM, typename A, typename P> inline
383 }
384 
386 // operator * //
387 // Matrix * SIM3 //
389 
390 namespace Internal {
391 template <int Rows, int C, typename PM, typename A, typename P>
392 struct MSIM3Mult;
393 }
394 
395 template<int Rows, int C, typename PM, typename A, typename P>
396 struct Operator<Internal::MSIM3Mult<Rows, C, PM, A, P> > {
397  const Matrix<Rows,C,PM,A> & lhs;
398  const SIM3<P> & rhs;
399 
400  Operator( const Matrix<Rows,C,PM,A> & l, const SIM3<P> & r ) : lhs(l), rhs(r) {}
401 
402  template <int R0, int C0, typename P0, typename A0>
403  void eval(Matrix<R0, C0, P0, A0> & res ) const {
404  SizeMismatch<4, C>::test(4, lhs.num_cols());
405  for(int i=0; i<lhs.num_rows(); ++i)
406  res[i] = lhs[i] * rhs;
407  }
408  int num_cols() const { return 4; }
409  int num_rows() const { return lhs.num_rows(); }
410 };
411 
414 template <int Rows, int C, typename PM, typename A, typename P> inline
417 }
418 
419 namespace Internal {
420 
422 template <typename Precision>
423 inline Vector<3, Precision> compute_rodrigues_coefficients_sim3( const Precision & s, const Precision & t ){
424  using std::exp;
425 
426  Vector<3, Precision> coeff;
427  const Precision es = exp(s);
428 
429  // 4 cases for s -> 0 and/or theta -> 0
430  // the Taylor expansions were calculated with Maple 12 and truncated at the 3rd power,
431  // such that eps^3 < 1e-18 which results in approximately 1 + eps^3 = 1
432  static const Precision eps = 1e-6;
433 
434  if(fabs(s) < eps && fabs(t) < eps){
435  coeff[0] = 1 + s/2 + s*s/6;
436  coeff[1] = 1/2 + s/3 - t*t/24 + s*s/8;
437  coeff[2] = 1/6 + s/8 - t*t/120 + s*s/20;
438  } else if(fabs(s) < eps) {
439  coeff[0] = 1 + s/2 + s*s/6;
440  coeff[1] = (1-cos(t))/(t*t) + (sin(t)-cos(t)*t)*s/(t*t*t)+(2*sin(t)*t-t*t*cos(t)-2+2*cos(t))*s*s/(2*t*t*t*t);
441  coeff[2] = (t-sin(t))/(t*t*t) - (-t*t-2+2*cos(t)+2*sin(t)*t)*s/(2*t*t*t*t) - (-t*t*t+6*cos(t)*t+3*sin(t)*t*t-6*sin(t))*s*s/(6*t*t*t*t*t);
442  } else if(fabs(t) < eps) {
443  coeff[0] = (es - 1)/s;
444  coeff[1] = (s*es+1-es)/(s*s) - (6*s*es+6-6*es+es*s*s*s-3*es*s*s)*t*t/(6*s*s*s*s);
445  coeff[2] = (es*s*s-2*s*es+2*es-2)/(2*s*s*s) - (es*s*s*s*s-4*es*s*s*s+12*es*s*s-24*s*es+24*es-24)*t*t/(24*s*s*s*s*s);
446  } else {
447  const Precision a = es * sin(t);
448  const Precision b = es * cos(t);
449  const Precision inv_s_theta = 1/(s*s + t*t);
450 
451  coeff[0] = (es - 1)/s;
452  coeff[1] = (a*s + (1-b)*t) * inv_s_theta / t;
453  coeff[2] = (coeff[0] - ((b-1)*s + a*t) * inv_s_theta) / (t*t);
454  }
455 
456  return coeff;
457 }
458 
459 }
460 
461 template <typename Precision>
462 template <int S, typename P, typename VA>
464  SizeMismatch<7,S>::test(7, mu.size());
465  using std::exp;
466 
467  SIM3<Precision> result;
468 
469  // scale
470  result.get_scale() = exp(mu[6]);
471 
472  // rotation
473  const Vector<3,Precision> w = mu.template slice<3,3>();
474  const Precision t = norm(w);
475  result.get_rotation() = SO3<>::exp(w);
476 
477  // translation
478  const Vector<3, Precision> coeff = Internal::compute_rodrigues_coefficients_sim3(mu[6],t);
479  const Vector<3,Precision> cross = w ^ mu.template slice<0,3>();
480  result.get_translation() = coeff[0] * mu.template slice<0,3>() + TooN::operator*(coeff[1], cross) + TooN::operator*(coeff[2], (w ^ cross));
481 
482  return result;
483 }
484 
485 template <typename Precision>
487  using std::sqrt;
488  using std::log;
489 
490  Vector<7, Precision> result;
491 
492  // rotation
493  result.template slice<3,3>() = sim3.get_rotation().ln();
494  const Precision theta = norm(result.template slice<3,3>());
495 
496  // scale
497  const Precision es = sim3.get_scale();
498  const Precision s = log(sim3.get_scale());
499  result[6] = s;
500 
501  // Translation
502  const Vector<3, Precision> coeff = Internal::compute_rodrigues_coefficients_sim3(s, theta);
503  const Matrix<3,3, Precision> cross = cross_product_matrix(result.template slice<3,3>());
504  const Matrix<3,3, Precision> W = Identity * coeff[0] + cross * coeff[1] + cross * cross * coeff[2];
505 
506  result.template slice<0,3>() = gaussian_elimination(W, sim3.get_translation());
507 
508  return result;
509 }
510 
511 #if 0
512 template <typename Precision>
513 inline SE3<Precision> operator*(const SO3<Precision>& lhs, const SE3<Precision>& rhs){
514  return SE3<Precision>(lhs*rhs.get_rotation(),lhs*rhs.get_translation());
515 }
516 #endif
517 
518 }
519 
520 #endif
Matrix< R, C, P > exp(const Matrix< R, C, P, B > &m)
computes the matrix exponential of a matrix m by scaling m by 1/(powers of 2), using Taylor series an...
Definition: helpers.h:330
Definition: sim3.h:358
Represent a three-dimensional Euclidean transformation (a rotation and a translation).
Definition: se3.h:48
Matrix< R, C, P > log(const Matrix< R, C, P, B > &m)
computes the matrix logarithm of a matrix m using the inverse scaling and squaring method...
Definition: helpers.h:373
Precision norm(const Vector< Size, Precision, Base > &v)
Compute the norm of v.
Definition: helpers.h:97
const SO3< Precision > & get_rotation() const
Definition: sim3.h:61
static SO3 exp(const Vector< S, VP, A > &vect)
Exponentiate a vector in the Lie algebra to generate a new SO3.
Pretty generic SFINAE introspection generator.
Definition: vec_test.cc:21
SO3< Precision > & get_rotation()
Returns the rotation part of the transformation as a SO3.
Definition: sim3.h:59
static SIM3 exp(const Vector< S, P, A > &vect)
Exponentiate a Vector in the Lie Algebra to generate a new SIM3.
Vector< 7, Precision > ln() const
Definition: sim3.h:83
Vector< 7, Precision > adjoint(const Vector< S, P2, Accessor > &vect) const
Transfer a matrix in the Lie Algebra from one co-ordinate frame to another.
Definition: sim3.h:194
A matrix.
Definition: matrix.hh:105
Definition: operators.hh:119
Vector< 3, Precision > & get_translation()
Returns the translation part of the transformation as a Vector.
Definition: sim3.h:64
Definition: sim3.h:392
Matrix< Rows, 4, typename Internal::MultiplyType< PM, P >::type > operator*(const Matrix< Rows, C, PM, A > &lhs, const SIM3< P > &rhs)
Left-multiply by a Matrix.
Definition: sim3.h:415
TooN::Matrix< 3, 3, P > cross_product_matrix(const Vector< Size, P, B > &vec)
creates an returns a cross product matrix M from a 3 vector v, such that for all vectors w...
Definition: helpers.h:444
SIM3 & operator*=(const SIM3 &rhs)
Right-multiply by another SIM3 (concatenate the two transformations)
Definition: sim3.h:93
Vector< 4, typename Internal::MultiplyType< P, PV >::type > operator*(const Vector< S, PV, A > &lhs, const SIM3< P > &rhs)
Left-multiply by a Vector.
Definition: sim3.h:347
Class to represent a three-dimensional rotation matrix.
Definition: so3.h:37
const Vector< 3, Precision > & get_translation() const
Definition: sim3.h:66
Precision & get_scale()
Returns the scale factor.
Definition: sim3.h:69
Definition: sim3.h:324
Definition: objects.h:36
const Precision & get_scale() const
Definition: sim3.h:71
SIM3< typename Internal::MultiplyType< Precision, P >::type > operator*(const SIM3< P > &rhs) const
Right-multiply by another SIM3 (concatenate the two transformations)
Definition: sim3.h:108
static Vector< 4, Precision > generator_field(int i, const Vector< 4, Precision, Base > &pos)
Returns the i-th generator times pos.
Definition: sim3.h:138
Vector< 7, Precision > trinvadjoint(const Vector< S, P2, Accessor > &vect) const
Transfer covectors between frames (using the transpose of the inverse of the adjoint) so that trinvad...
Definition: sim3.h:208
Vector< 4, typename Internal::MultiplyType< P, PV >::type > operator*(const SIM3< P > &lhs, const Vector< S, PV, A > &rhs)
Right-multiply by a Vector.
Definition: sim3.h:306
Vector< 3, typename Internal::MultiplyType< P, PV >::type > operator*(const SIM3< P > &lhs, const Vector< 3, PV, A > &rhs)
Right-multiply by a Vector.
Definition: sim3.h:313
Represent a three-dimensional similarity transformation (a rotation, a scale factor and a translation...
Definition: sim3.h:48
Matrix< R, C, P > sqrt(const Matrix< R, C, P, B > &m)
computes a matrix square root of a matrix m by the product form of the Denman and Beavers iteration a...
Definition: helpers.h:350
Definition: size_mismatch.hh:103
Vector< 3, Precision > & get_translation()
Returns the translation part of the transformation as a Vector.
Definition: se3.h:67
SIM3 & operator=(const TooN::Operator< TooN::Internal::Identity< TooN::Internal::One >> &)
Reset back to the identity transform.
Definition: sim3.h:101
Vector< N, Precision > gaussian_elimination(Matrix< N, N, Precision > A, Vector< N, Precision > b)
Return the solution for , given and .
Definition: gaussian_elimination.h:43
SO3< Precision > & get_rotation()
Returns the rotation part of the transformation as a SO3.
Definition: se3.h:62
std::istream & operator>>(std::istream &is, SIM3< Precision > &rhs)
Reads an SIM3 from a stream.
Definition: sim3.h:267
Definition: sim3.h:283
Matrix< 4, Cols, typename Internal::MultiplyType< P, PM >::type > operator*(const SIM3< P > &lhs, const Matrix< R, Cols, PM, A > &rhs)
Right-multiply by a Matrix.
Definition: sim3.h:381
SIM3()
Default constructor. Initialises the the rotation to zero (the identity), the scale to one and the tr...
Definition: sim3.h:51