1 // This file is part of OpenMVG, an Open Multiple View Geometry C++ library.
2
3 // Copyright (c) 2012, 2013 Pierre MOULON.
4
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
9 #include "openMVG/geometry/rigid_transformation3D_srt.hpp"
10 #include "openMVG/system/logger.hpp"
11
12 #include <unsupported/Eigen/NonLinearOptimization>
13 #include <unsupported/Eigen/NumericalDiff>
14
15 namespace openMVG{
16 namespace geometry{
17
FindRTS(const Mat & x1,const Mat & x2,double * S,Vec3 * t,Mat3 * R)18 bool FindRTS
19 (
20 const Mat &x1,
21 const Mat &x2,
22 double * S,
23 Vec3 * t,
24 Mat3 * R
25 )
26 {
27 if ( x1.cols() < 3 || x2.cols() < 3 )
28 {
29 OPENMVG_LOG_ERROR << "At least 3 points are required for computing a RTS transform.";
30 return false;
31 }
32
33 assert( 3 == x1.rows() );
34 assert( 3 <= x1.cols() );
35 assert( x1.rows() == x2.rows() );
36 assert( x1.cols() == x2.cols() );
37
38 // Get the transformation via Umeyama's least squares algorithm. This returns
39 // a matrix of the form:
40 // [ s * R t]
41 // [ 0 1]
42 // from which we can extract the scale, rotation, and translation.
43 const Eigen::Matrix4d transform = Eigen::umeyama( x1, x2, true );
44
45 // Check critical cases
46 *R = transform.topLeftCorner<3, 3>();
47 if ( R->determinant() < 0 )
48 {
49 return false;
50 }
51 *S = pow( R->determinant(), 1.0 / 3.0 );
52 // Check for degenerate case (if all points have the same value...)
53 if ( *S < std::numeric_limits<double>::epsilon() )
54 {
55 OPENMVG_LOG_ERROR << "Degeneration configuration for a RTS transform estimation.";
56 return false;
57 }
58
59 // Extract transformation parameters
60 *S = pow( R->determinant(), 1.0 / 3.0 );
61 *R /= *S;
62 *t = transform.topRightCorner<3, 1>();
63
64 return true;
65 }
66
lm_SRTRefine_functor(int inputs,int values,const Mat & x1,const Mat & x2,const double & S,const Mat3 & R,const Vec & t)67 lm_SRTRefine_functor::lm_SRTRefine_functor( int inputs, int values,
68 const Mat &x1, const Mat &x2,
69 const double &S, const Mat3 & R, const Vec &t ): Functor<double>( inputs, values ),
70 x1_( x1 ), x2_( x2 ), t_( t ), R_( R ), S_( S ) { }
71
operator ()(const Vec & x,Vec & fvec) const72 int lm_SRTRefine_functor::operator()( const Vec &x, Vec &fvec ) const
73 {
74 // convert x to rotation matrix and a translation vector and a Scale factor
75 // x = {tx,ty,tz,anglex,angley,anglez,S}
76 Vec3 transAdd = x.block<3, 1>( 0, 0 );
77 Vec3 rot = x.block<3, 1>( 3, 0 );
78 double Sadd = x( 6 );
79
80 //Build the rotation matrix
81 Mat3 Rcor =
82 ( Eigen::AngleAxis<double>( rot( 0 ), Vec3::UnitX() )
83 * Eigen::AngleAxis<double>( rot( 1 ), Vec3::UnitY() )
84 * Eigen::AngleAxis<double>( rot( 2 ), Vec3::UnitZ() ) ).toRotationMatrix();
85
86 const Mat3 nR = R_ * Rcor;
87 const Vec3 nt = t_ + transAdd;
88 const double nS = S_ + Sadd;
89
90 // Evaluate re-projection errors
91 Vec3 proj;
92 for ( Mat::Index i = 0; i < x1_.cols(); ++i )
93 {
94 proj = x2_.col( i ) - ( nS * nR * ( x1_.col( i ) ) + nt );
95 fvec[i * 3] = proj( 0 );
96 fvec[i * 3 + 1] = proj( 1 );
97 fvec[i * 3 + 2] = proj( 2 );
98 }
99 return 0;
100 }
101
102
lm_RRefine_functor(int inputs,int values,const Mat & x1,const Mat & x2,const double & S,const Mat3 & R,const Vec & t)103 lm_RRefine_functor::lm_RRefine_functor( int inputs, int values,
104 const Mat &x1, const Mat &x2,
105 const double &S, const Mat3 & R, const Vec &t ): Functor<double>( inputs, values ),
106 x1_( x1 ), x2_( x2 ), t_( t ), R_( R ), S_( S ) { }
107
operator ()(const Vec & x,Vec & fvec) const108 int lm_RRefine_functor::operator()( const Vec &x, Vec &fvec ) const
109 {
110 // convert x to rotation matrix
111 // x = {anglex,angley,anglez}
112 Vec3 rot = x.block<3, 1>( 0, 0 );
113
114 //Build the rotation matrix
115 Mat3 Rcor =
116 ( Eigen::AngleAxis<double>( rot( 0 ), Vec3::UnitX() )
117 * Eigen::AngleAxis<double>( rot( 1 ), Vec3::UnitY() )
118 * Eigen::AngleAxis<double>( rot( 2 ), Vec3::UnitZ() ) ).toRotationMatrix();
119
120 const Mat3 nR = R_ * Rcor;
121 const Vec3 nt = t_;
122 const double nS = S_;
123
124 // Evaluate re-projection errors
125 Vec3 proj;
126 for ( Mat::Index i = 0; i < x1_.cols(); ++i )
127 {
128 proj = x2_.col( i ) - ( nS * nR * ( x1_.col( i ) ) + nt );
129 fvec[i * 3] = proj( 0 );
130 fvec[i * 3 + 1] = proj( 1 );
131 fvec[i * 3 + 2] = proj( 2 );
132 }
133 return 0;
134 }
135
Refine_RTS(const Mat & x1,const Mat & x2,double * S,Vec3 * t,Mat3 * R)136 void Refine_RTS
137 (
138 const Mat &x1,
139 const Mat &x2,
140 double * S,
141 Vec3 * t,
142 Mat3 * R
143 )
144 {
145 {
146 lm_SRTRefine_functor functor( 7, 3 * x1.cols(), x1, x2, *S, *R, *t );
147
148 Eigen::NumericalDiff<lm_SRTRefine_functor> numDiff( functor );
149
150 Eigen::LevenbergMarquardt<Eigen::NumericalDiff<lm_SRTRefine_functor>> lm( numDiff );
151 lm.parameters.maxfev = 1000;
152 Vec xlm = Vec::Zero( 7 ); // The deviation vector {tx,ty,tz,rotX,rotY,rotZ,S}
153
154 lm.minimize( xlm );
155
156 const Vec3 transAdd = xlm.block<3, 1>( 0, 0 );
157 const Vec3 rot = xlm.block<3, 1>( 3, 0 );
158 const double SAdd = xlm( 6 );
159
160 //Build the rotation matrix
161 const Mat3 Rcor =
162 ( Eigen::AngleAxis<double>( rot( 0 ), Vec3::UnitX() )
163 * Eigen::AngleAxis<double>( rot( 1 ), Vec3::UnitY() )
164 * Eigen::AngleAxis<double>( rot( 2 ), Vec3::UnitZ() ) ).toRotationMatrix();
165
166 *R = ( *R ) * Rcor;
167 *t = ( *t ) + transAdd;
168 *S = ( *S ) + SAdd;
169 }
170
171 // Refine rotation
172 {
173 lm_RRefine_functor functor( 3, 3 * x1.cols(), x1, x2, *S, *R, *t );
174
175 Eigen::NumericalDiff<lm_RRefine_functor> numDiff( functor );
176
177 Eigen::LevenbergMarquardt<Eigen::NumericalDiff<lm_RRefine_functor>> lm( numDiff );
178 lm.parameters.maxfev = 1000;
179 Vec xlm = Vec::Zero( 3 ); // The deviation vector {rotX,rotY,rotZ}
180
181 lm.minimize( xlm );
182
183 const Vec3 rot = xlm.block<3, 1>( 0, 0 );
184
185 //Build the rotation matrix
186 const Mat3 Rcor =
187 ( Eigen::AngleAxis<double>( rot( 0 ), Vec3::UnitX() )
188 * Eigen::AngleAxis<double>( rot( 1 ), Vec3::UnitY() )
189 * Eigen::AngleAxis<double>( rot( 2 ), Vec3::UnitZ() ) ).toRotationMatrix();
190
191 *R = ( *R ) * Rcor;
192 }
193 }
194
195 } // namespace geometry
196 } // namespace openMVG
197