@@ -177,6 +177,97 @@ inline TMatrix<TYPE,3,3> CreateF(const TMatrix<TYPE,3,3>& R, const TMatrix<TYPE,
177
177
/* ----------------------------------------------------------------*/
178
178
179
179
180
+ // computes an RQ decomposition of 3x3 matrices as in:
181
+ // "Computing euler angles from a rotation matrix", Gregory G Slabaugh, 1999
182
+ template <typename Scalar>
183
+ inline void RQDecomp3x3 (Eigen::Matrix<Scalar,3 ,3 > M, Eigen::Matrix<Scalar,3 ,3 >& R, Eigen::Matrix<Scalar,3 ,3 >& Q) {
184
+ // find Givens rotation for x axis:
185
+ // | 1 0 0 |
186
+ // Qx = | 0 c s |, c = m33/sqrt(m32^2 + m33^2), s = m32/sqrt(m32^2 + m33^2)
187
+ // | 0 -s c |
188
+ Eigen::Matrix<Scalar,2 ,1 > cs = Eigen::Matrix<Scalar,2 ,1 >(M (2 ,2 ), M (2 ,1 )).normalized ();
189
+ Eigen::Matrix<Scalar,3 ,3 > Qx{ {1 , 0 , 0 }, {0 , cs.x (), cs.y ()}, {0 , -cs.y (), cs.x ()} };
190
+ R.noalias () = M * Qx;
191
+ ASSERT (std::abs (R (2 ,1 )) < FLT_EPSILON);
192
+ R (2 ,1 ) = 0 ;
193
+ // find Givens rotation for y axis:
194
+ // | c 0 -s |
195
+ // Qy = | 0 1 0 |, c = m33/sqrt(m31^2 + m33^2), s = -m31/sqrt(m31^2 + m33^2)
196
+ // | s 0 c |
197
+ cs = Eigen::Matrix<Scalar,2 ,1 >(R (2 ,2 ), -R (2 ,0 )).normalized ();
198
+ Eigen::Matrix<Scalar,3 ,3 > Qy{ {cs.x (), 0 , -cs.y ()}, {0 , 1 , 0 }, {cs.y (), 0 , cs.x ()} };
199
+ M.noalias () = R * Qy;
200
+ ASSERT (std::abs (M (2 ,0 )) < FLT_EPSILON);
201
+ M (2 ,0 ) = 0 ;
202
+ // find Givens rotation for z axis:
203
+ // | c s 0 |
204
+ // Qz = |-s c 0 |, c = m22/sqrt(m21^2 + m22^2), s = m21/sqrt(m21^2 + m22^2)
205
+ // | 0 0 1 |
206
+ cs = Eigen::Matrix<Scalar,2 ,1 >(M (1 ,1 ), M (1 ,0 )).normalized ();
207
+ Eigen::Matrix<Scalar,3 ,3 > Qz{ {cs.x (), cs.y (), 0 }, {-cs.y (), cs.x (), 0 }, {0 , 0 , 1 } };
208
+ R.noalias () = M * Qz;
209
+ ASSERT (std::abs (R (1 ,0 )) < FLT_EPSILON);
210
+ R (1 ,0 ) = 0 ;
211
+ // solve the decomposition ambiguity:
212
+ // - diagonal entries of R, except the last one, shall be positive
213
+ // - rotate R by 180 degree if necessary
214
+ if (R (0 ,0 ) < 0 ) {
215
+ if (R (1 ,1 ) < 0 ) {
216
+ // rotate around z for 180 degree:
217
+ // |-1, 0, 0|
218
+ // | 0, -1, 0|
219
+ // | 0, 0, 1|
220
+ R (0 ,0 ) *= -1 ;
221
+ R (0 ,1 ) *= -1 ;
222
+ R (1 ,1 ) *= -1 ;
223
+ Qz (0 ,0 ) *= -1 ;
224
+ Qz (0 ,1 ) *= -1 ;
225
+ Qz (1 ,0 ) *= -1 ;
226
+ Qz (1 ,1 ) *= -1 ;
227
+ } else {
228
+ // rotate around y for 180 degree:
229
+ // |-1, 0, 0|
230
+ // | 0, 1, 0|
231
+ // | 0, 0, -1|
232
+ R (0 ,0 ) *= -1 ;
233
+ R (0 ,2 ) *= -1 ;
234
+ R (1 ,2 ) *= -1 ;
235
+ R (2 ,2 ) *= -1 ;
236
+ Qz.transposeInPlace ();
237
+ Qy (0 ,0 ) *= -1 ;
238
+ Qy (0 ,2 ) *= -1 ;
239
+ Qy (2 ,0 ) *= -1 ;
240
+ Qy (2 ,2 ) *= -1 ;
241
+ }
242
+ } else if (R (1 ,1 ) < 0 ) {
243
+ // rotate around x for 180 degree:
244
+ // | 1, 0, 0|
245
+ // | 0, -1, 0|
246
+ // | 0, 0, -1|
247
+ R (0 ,1 ) *= -1 ;
248
+ R (0 ,2 ) *= -1 ;
249
+ R (1 ,1 ) *= -1 ;
250
+ R (1 ,2 ) *= -1 ;
251
+ R (2 ,2 ) *= -1 ;
252
+ Qz.transposeInPlace ();
253
+ Qy.transposeInPlace ();
254
+ Qx (1 ,1 ) *= -1 ;
255
+ Qx (1 ,2 ) *= -1 ;
256
+ Qx (2 ,1 ) *= -1 ;
257
+ Qx (2 ,2 ) *= -1 ;
258
+ }
259
+ // calculate orthogonal matrix
260
+ Q.noalias () = Qz.transpose () * Qy.transpose () * Qx.transpose ();
261
+ }
262
+ template <typename TYPE>
263
+ inline void RQDecomp3x3 (const TMatrix<TYPE,3 ,3 >& M, TMatrix<TYPE,3 ,3 >& R, TMatrix<TYPE,3 ,3 >& Q) {
264
+ Eigen::Matrix<TYPE,3 ,3 > _M ((TMatrix<TYPE,3 ,3 >::CEMatMap)M), _R ((TMatrix<TYPE,3 ,3 >::CEMatMap)R), _Q ((TMatrix<TYPE,3 ,3 >::CEMatMap)Q);
265
+ RQDecomp3x3<TYPE>(_M, _R, _Q);
266
+ R = _R; Q = _Q;
267
+ } // RQDecomp3x3
268
+ /* ----------------------------------------------------------------*/
269
+
270
+
180
271
// compute the angle between the two rotations given
181
272
// as in: "Disambiguating Visual Relations Using Loop Constraints", 2010
182
273
// returns cos(angle) (same as cos(ComputeAngleSO3(I))
0 commit comments