contrib/rpl/rgrl/rgrl_trans_rigid.cxx
Go to the documentation of this file.
00001 #include "rgrl_trans_rigid.h"
00002 //:
00003 // \file
00004 // \author Tomasz Malisiewicz
00005 // \date   March 2004
00006 
00007 #include <vcl_cassert.h>
00008 #include <vnl/algo/vnl_svd.h>
00009 #include <vnl/vnl_math.h>
00010 #include <rgrl/rgrl_util.h>
00011 
00012 rgrl_trans_rigid::
00013 rgrl_trans_rigid( unsigned int dimension )
00014   : R_( vnl_matrix<double>( dimension, dimension, vnl_matrix_identity ) ),
00015     trans_( vnl_vector<double>( dimension, 0.0 ) )
00016 {
00017   // only accept 2d or 3d rigid transformation, it can be zero when using a reader to initialize it
00018   assert (dimension==0 || dimension==2 || dimension==3);
00019 }
00020 
00021 rgrl_trans_rigid::
00022 rgrl_trans_rigid( vnl_matrix<double> const& rot,
00023                   vnl_vector<double> const& in_trans )
00024   : R_( rot ),
00025     trans_( in_trans )
00026 {
00027   assert ( R_.rows() == R_.cols() );  //make sure rotation is square matrix
00028   assert ( R_.rows() == trans_.size() );
00029 }
00030 
00031 rgrl_trans_rigid::
00032 rgrl_trans_rigid( vnl_matrix<double> const& rot,
00033                   vnl_vector<double> const& in_trans,
00034                   vnl_matrix<double> const& in_covar )
00035   : rgrl_transformation( in_covar ),
00036     R_( rot ),
00037     trans_( in_trans )
00038 {
00039   assert ( R_.rows() == R_.cols() );
00040   assert ( R_.rows() == trans_.size() );
00041   if ( is_covar_set() ) {
00042     assert ( covar_.rows() == covar_.cols() );
00043     assert ( ( R_.rows() != 2 || covar_.rows() == 3 ) ); // 2d has 3 params (1 angle + 2 displacements)
00044     assert ( ( R_.rows() != 3 || covar_.rows() == 6 ) ); // 3d has 6 params (3 angles + 3 displacements)
00045   }
00046 }
00047 
00048 void rgrl_trans_rigid::set_translation(double tx, double ty, double tz)
00049 {
00050   assert ( trans_.size() == 3);
00051   trans_[0]=tx;
00052   trans_[1]=ty;
00053   trans_[2]=tz;
00054 }
00055 
00056 void rgrl_trans_rigid::set_translation(double tx, double ty)
00057 {
00058   assert ( trans_.size() == 2);
00059   trans_[0]=tx;
00060   trans_[1]=ty;
00061 }
00062 
00063 void rgrl_trans_rigid::set_rotation(double theta, double alpha, double phi)
00064 {
00065   assert ( trans_.size() == 3);
00066 
00067   double cos_a = vcl_cos(alpha), sin_a = vcl_sin(alpha),
00068          cos_t = vcl_cos(theta), sin_t = vcl_sin(theta),
00069          cos_p = vcl_cos(phi),   sin_p = vcl_sin(phi);
00070   R_(0,0) =cos_a*cos_t ;                   R_(0,1) = -cos_a*sin_t;                   R_(0,2)=sin_a;
00071   R_(1,0) =cos_t*sin_a*sin_p+cos_p*sin_t;  R_(1,1) = -sin_a*sin_p*sin_t+cos_p*cos_t; R_(1,2)=-cos_a*sin_p;
00072   R_(2,0)=-cos_p*cos_t*sin_a+sin_p*sin_t;  R_(2,1) = cos_p*sin_a*sin_t+cos_t*sin_p;  R_(2,2)=cos_a*cos_p;
00073 }
00074 
00075 void rgrl_trans_rigid::set_rotation(double theta)
00076 {
00077   assert ( trans_.size() == 2);
00078 
00079   R_(0,0) = vcl_cos(theta);    R_(0,1) = vcl_sin(theta);
00080   R_(1,0) = -vcl_sin(theta);   R_(1,1) = vcl_cos(theta);
00081 }
00082 
00083 void rgrl_trans_rigid::determine_angles(double& phi, double& alpha, double& theta) const
00084 {
00085   assert (trans_.size() == 3);
00086 
00087   alpha = vcl_asin( R_(0,2) );
00088 
00089   if (R_(0,0) * vcl_cos(alpha) > 0)
00090   {
00091     theta = vcl_atan( -1 * R_(0,1)/R_(0,0) );
00092   }
00093   else
00094   {
00095     theta = vcl_atan( -1 * R_(0,1)/R_(0,0) ) + vnl_math::pi;
00096   }
00097 
00098   if (R_(2,2) * vcl_cos(alpha) > 0 )
00099   {
00100     phi = vcl_atan( -1 * R_(1,2) / R_(2,2) );
00101   }
00102   else
00103   {
00104     phi = vcl_atan( -1 * R_(1,2) / R_(2,2) ) + vnl_math::pi;
00105   }
00106 }
00107 
00108 void rgrl_trans_rigid::determine_angles( double& theta ) const
00109 {
00110   assert (trans_.size() == 2);
00111   theta = vcl_asin( R_(0,1) );
00112 }
00113 
00114 void
00115 rgrl_trans_rigid::
00116 map_loc( vnl_vector<double> const& from,
00117          vnl_vector<double>      & to   ) const
00118 {
00119   assert ( from.size() == R_.rows() );
00120   to = R_ * from + trans_;
00121 }
00122 
00123 void
00124 rgrl_trans_rigid::
00125 map_dir( vnl_vector<double> const& from_loc,
00126          vnl_vector<double> const& from_dir,
00127          vnl_vector<double>      & to_dir    ) const
00128 {
00129   assert ( from_loc.size() == R_.cols() );
00130   assert ( from_dir.size() == R_.cols() );
00131   to_dir = R_ * from_dir;
00132   to_dir.normalize();
00133 }
00134 
00135 vnl_matrix<double>
00136 rgrl_trans_rigid::
00137 transfer_error_covar( vnl_vector<double> const& p  ) const
00138 {
00139   assert ( is_covar_set() );
00140   assert ( p.size() == trans_.size() );
00141   vnl_matrix<double> jacobian(3,6,0.0);
00142 
00143   double phi,alpha,theta;
00144 
00145   determine_angles(phi,alpha,theta);
00146 
00147   vnl_matrix<double> Rphid(3,3,0.0);
00148   vnl_matrix<double> Ralphad(3,3,0.0);
00149   vnl_matrix<double> Rthetad(3,3,0.0);
00150 
00151   // derivative matrices now
00152   Rthetad(0,0) = -vcl_sin(theta);
00153   Rthetad(0,1) = -vcl_cos(theta);
00154   Rthetad(1,0) = vcl_cos(theta);
00155   Rthetad(1,1) = -vcl_sin(theta);
00156 
00157   Ralphad(0,0) = -vcl_sin(alpha);
00158   Ralphad(0,2) = vcl_cos(alpha);
00159   Ralphad(2,0) = -vcl_cos(alpha);
00160   Ralphad(2,2) = -vcl_sin(alpha);
00161 
00162   Rphid(1,1) = -vcl_sin(phi);
00163   Rphid(1,2) = -vcl_cos(phi);
00164   Rphid(2,1) = vcl_cos(phi);
00165   Rphid(2,2) = -vcl_sin(phi);
00166 
00167   jacobian.set_column(0,Rthetad*p);
00168   jacobian.set_column(1,Ralphad*p);
00169   jacobian.set_column(2,Rphid*p);
00170   jacobian.update(vnl_matrix<double>(3,3,vnl_matrix_identity),0,3);
00171 
00172   return jacobian * covar_ * jacobian.transpose();
00173 }
00174 
00175 vnl_matrix<double> const&
00176 rgrl_trans_rigid::
00177 R() const
00178 {
00179   return R_;
00180 }
00181 
00182 vnl_vector<double>
00183 rgrl_trans_rigid::
00184 t() const
00185 {
00186   return trans_;
00187 }
00188 
00189 void
00190 rgrl_trans_rigid::
00191 inv_map( const vnl_vector<double>& to,
00192          bool initialize_next,
00193          const vnl_vector<double>& to_delta,
00194          vnl_vector<double>& from,
00195          vnl_vector<double>& from_next_est) const
00196 {
00197   const double epsilon = 0.01;
00198   vnl_vector<double> to_est = this->map_location(from);
00199 
00200   // compute the inverse of the Jacobian, which is the R_^-1
00201   vnl_svd<double> svd( R_ );
00202   vnl_matrix<double> J_inv = svd.inverse();
00203 
00204   // update from to become true inv_map of to, based on A^-1 and (to - to_est)
00205   if (vnl_vector_ssd(to, to_est) > epsilon*epsilon) {
00206     from += J_inv * (to - to_est);
00207   }
00208   if ( initialize_next ) {
00209     from_next_est = from + (J_inv * to_delta);
00210   }
00211 }
00212 
00213 void
00214 rgrl_trans_rigid::
00215 jacobian_wrt_loc( vnl_matrix<double>& jac, vnl_vector<double> const& /*from_loc*/ ) const
00216 {
00217   jac = R_;
00218 }
00219 
00220 void
00221 rgrl_trans_rigid::
00222 inv_map( const vnl_vector<double>& to,
00223          vnl_vector<double>& from ) const
00224 {
00225   vnl_svd<double> svd( R_ );
00226   from = svd.inverse()*to - svd.inverse()*trans_;
00227 }
00228 
00229 rgrl_transformation_sptr 
00230 rgrl_trans_rigid::
00231 inverse_transform( ) const
00232 {
00233   vnl_matrix<double> invR = R().transpose();
00234   rgrl_transformation_sptr result = new rgrl_trans_rigid( invR, -invR * t() );
00235 
00236   const unsigned m = scaling_factors_.size();
00237   if ( m > 0 ) {
00238     vnl_vector<double> scaling( m );
00239     for ( unsigned int i=0; i<m; ++i )
00240       scaling[i] = 1.0 / scaling_factors_[i];
00241     result->set_scaling_factors( scaling );
00242   }
00243 
00244   return result;
00245 }
00246 
00247 rgrl_transformation_sptr
00248 rgrl_trans_rigid::
00249 scale_by( double scale ) const
00250 {
00251   rgrl_transformation_sptr xform 
00252     = new rgrl_trans_rigid( R_, trans_ * scale,
00253                             covar_ );
00254   xform->set_scaling_factors( this->scaling_factors() );
00255   return xform;
00256 }
00257 
00258 void
00259 rgrl_trans_rigid::
00260 write( vcl_ostream& os ) const
00261 {
00262   // tag
00263   os << "RIGID\n"
00264   // parameters
00265      << trans_.size() << vcl_endl
00266      << R_ << trans_ << vcl_endl;
00267 
00268   // parent
00269   rgrl_transformation::write( os );
00270 }
00271 
00272 bool
00273 rgrl_trans_rigid::
00274 read( vcl_istream& is )
00275 {
00276   int dim;
00277 
00278   // skip empty lines
00279   rgrl_util_skip_empty_lines( is );
00280 
00281   vcl_string str;
00282   vcl_getline( is, str );
00283 
00284   // The token should appear at the beginning of line
00285   if ( str.find( "RIGID" ) != 0 ) {
00286     WarningMacro( "The tag is not RIGID. reading is aborted.\n" );
00287     return false;
00288   }
00289 
00290   // input global xform
00291   dim=-1;
00292   is >> dim;
00293   if ( dim > 0 ) {
00294     R_.set_size( dim, dim );
00295     trans_.set_size( dim );
00296     is >> R_ >> trans_;
00297   }
00298 
00299   // parent
00300   return is.good() && rgrl_transformation::read( is );
00301 }
00302 
00303 //: make a clone copy
00304 rgrl_transformation_sptr 
00305 rgrl_trans_rigid::
00306 clone() const
00307 {
00308   return new rgrl_trans_rigid( *this );
00309 }