Skip to content

Commit 516306a

Browse files
committed
common: implement custom RQ decomposition
1 parent 000443e commit 516306a

File tree

2 files changed

+92
-2
lines changed

2 files changed

+92
-2
lines changed

libs/Common/Util.inl

+91
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,97 @@ inline TMatrix<TYPE,3,3> CreateF(const TMatrix<TYPE,3,3>& R, const TMatrix<TYPE,
177177
/*----------------------------------------------------------------*/
178178

179179

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+
180271
// compute the angle between the two rotations given
181272
// as in: "Disambiguating Visual Relations Using Loop Constraints", 2010
182273
// returns cos(angle) (same as cos(ComputeAngleSO3(I))

libs/MVS/Camera.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,7 @@ void MVS::DecomposeProjectionMatrix(const PMatrix& P, KMatrix& K, RMatrix& R, CM
137137
const Vec4 hC(P.RightNullVector());
138138
C = CMatrix(hC[0],hC[1],hC[2]) * INVERT(hC[3]);
139139
// perform RQ decomposition
140-
const cv::Mat mP(3,4,cv::DataType<REAL>::type,const_cast<REAL*>(P.val));
141-
cv::RQDecomp3x3(mP(cv::Rect(0,0, 3,3)), K, R);
140+
RQDecomp3x3<REAL>(cv::Mat(3,4,cv::DataType<REAL>::type,const_cast<REAL*>(P.val))(cv::Rect(0,0, 3,3)), K, R);
142141
// normalize calibration matrix
143142
K *= INVERT(K(2,2));
144143
// ensure positive focal length

0 commit comments

Comments
 (0)