contrib/rpl/rgrl/rgrl_trans_quadratic.cxx
Go to the documentation of this file.
00001 #include "rgrl_trans_quadratic.h"
00002 //:
00003 // \file
00004 // \author Charlene Tsai
00005 // \date   Sep 2003
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_quadratic::
00013 rgrl_trans_quadratic( unsigned int dim)
00014   : Q_( vnl_matrix<double>( dim, dim + int(dim*(dim-1)/2), 0.0 ) ),
00015     A_( vnl_matrix<double>( dim, dim, vnl_matrix_identity ) ),
00016     trans_( vnl_vector<double>( dim, 0.0 ) ),
00017     from_centre_( dim, 0.0 )
00018 {
00019 }
00020 
00021 rgrl_trans_quadratic::
00022 rgrl_trans_quadratic( vnl_matrix<double> const& in_Q,
00023                       vnl_matrix<double> const& in_A,
00024                       vnl_vector<double> const& in_trans,
00025                       vnl_matrix<double> const& in_covar )
00026   : rgrl_transformation( in_covar ),
00027     Q_( in_Q ),
00028     A_( in_A ),
00029     trans_( in_trans ),
00030     from_centre_( in_trans.size(), 0.0 )
00031 {
00032   assert ( Q_.rows() + Q_.rows()*(Q_.rows()-1)/2 == Q_.cols() );
00033   assert ( A_.rows() == A_.cols() );
00034   assert ( A_.rows() == trans_.size() );
00035   if ( is_covar_set() ) {
00036     assert ( covar_.rows() == covar_.cols() );
00037     assert ( covar_.rows() == A_.rows()* (Q_.cols()+A_.cols() + 1 ) );
00038   }
00039 }
00040 
00041 rgrl_trans_quadratic::
00042 rgrl_trans_quadratic( vnl_matrix<double> const& in_Q,
00043                       vnl_matrix<double> const& in_A,
00044                       vnl_vector<double> const& in_trans )
00045   : Q_( in_Q ),
00046     A_( in_A ),
00047     trans_( in_trans ),
00048     from_centre_( in_trans.size(), 0.0 )
00049 {
00050   assert ( Q_.rows() + Q_.rows()*(Q_.rows()-1)/2 == Q_.cols() );
00051   assert ( A_.rows() == A_.cols() );
00052   assert ( A_.rows() == trans_.size() );
00053 }
00054 
00055 
00056 rgrl_trans_quadratic::
00057 rgrl_trans_quadratic( vnl_matrix<double> const& in_Q,
00058                       vnl_matrix<double> const& in_A,
00059                       vnl_vector<double> const& in_trans,
00060                       vnl_matrix<double> const& in_covar,
00061                       vnl_vector<double> const& in_from_centre,
00062                       vnl_vector<double> const& in_to_centre )
00063   : rgrl_transformation( in_covar ),
00064     Q_( in_Q ),
00065     A_( in_A ),
00066     trans_( in_trans ),
00067     from_centre_( in_from_centre )
00068 {
00069   assert ( Q_.rows() + Q_.rows()*(Q_.rows()-1)/2 == Q_.cols() );
00070   assert ( A_.rows() == A_.cols() );
00071   assert ( A_.rows() == trans_.size() );
00072   assert ( from_centre_.size() == trans_.size() );
00073   if ( is_covar_set() ) {
00074     assert ( covar_.rows() == covar_.cols() );
00075     assert ( covar_.rows() == A_.rows()* ( Q_.cols() + A_.cols() + 1) );
00076   }
00077 
00078   // Uncenter the transform
00079   vnl_vector<double> new_trans;
00080   map_loc( -in_from_centre, new_trans );
00081   trans_ = new_trans + in_to_centre;
00082 
00083   if (A_.rows() == 2) { //2D
00084     vnl_matrix<double> new_A(2,2, 0.0);
00085     new_A(0,0) = -2*in_from_centre[0]*Q_(0,0)-in_from_centre[1]*Q_(0,2)+A_(0,0);
00086     new_A(0,1) = -2*in_from_centre[1]*Q_(0,1)-in_from_centre[0]*Q_(0,2)+A_(0,1);
00087     new_A(1,0) = -2*in_from_centre[0]*Q_(1,0)-in_from_centre[1]*Q_(1,2)+A_(1,0);
00088     new_A(1,1) = -2*in_from_centre[1]*Q_(1,1)-in_from_centre[0]*Q_(1,2)+A_(1,1);
00089     A_ = new_A;
00090   }
00091   else { //3D,
00092     vnl_matrix<double> new_A(3,3, 0.0);
00093     double cx = in_from_centre[0];
00094     double cy = in_from_centre[1];
00095     double cz = in_from_centre[2];
00096 
00097     new_A(0,0) = -2*cx*Q_(0,0)-cy*Q_(0,3)-cz*Q_(0,5)+A_(0,0);
00098     new_A(0,1) = -2*cy*Q_(0,1)-cx*Q_(0,3)-cz*Q_(0,4)+A_(0,1);
00099     new_A(0,2) = -2*cz*Q_(0,2)-cy*Q_(0,4)-cx*Q_(0,5)+A_(0,2);
00100 
00101     new_A(1,0) = -2*cx*Q_(1,0)-cy*Q_(1,3)-cz*Q_(1,5)+A_(1,0);
00102     new_A(1,1) = -2*cy*Q_(1,1)-cx*Q_(1,3)-cz*Q_(1,4)+A_(1,1);
00103     new_A(1,2) = -2*cz*Q_(1,2)-cy*Q_(1,4)-cx*Q_(1,5)+A_(1,2);
00104 
00105     new_A(2,0) = -2*cx*Q_(2,0)-cy*Q_(2,3)-cz*Q_(2,5)+A_(2,0);
00106     new_A(2,1) = -2*cy*Q_(2,1)-cx*Q_(2,3)-cz*Q_(2,4)+A_(2,1);
00107     new_A(2,2) = -2*cz*Q_(2,2)-cy*Q_(2,4)-cx*Q_(2,5)+A_(2,2);
00108 
00109     A_ = new_A;
00110   }
00111 }
00112 
00113 void
00114 rgrl_trans_quadratic::
00115 set_from_center( vnl_vector<double> const& from_center )
00116 {
00117   from_centre_ = from_center;
00118 }
00119 
00120 void
00121 rgrl_trans_quadratic::
00122 map_loc( vnl_vector<double> const& from,
00123          vnl_vector<double>      & to   ) const
00124 {
00125   assert ( from.size() == A_.rows() );
00126   vnl_vector<double> hot = higher_order_terms(from);
00127   to = Q_ * hot + A_ * from + trans_;
00128 }
00129 
00130 
00131 void
00132 rgrl_trans_quadratic::
00133 map_dir( vnl_vector<double> const& from_loc,
00134          vnl_vector<double> const& from_dir,
00135          vnl_vector<double>      & to_dir    ) const
00136 {
00137   assert ( from_loc.size() == A_.cols() );
00138   assert ( from_dir.size() == A_.cols() );
00139   vnl_vector<double> to_loc_begin, to_loc_end;
00140   this->map_loc(from_loc, to_loc_begin);
00141   this->map_loc(from_loc+from_dir, to_loc_end);
00142 
00143   to_dir = to_loc_end - to_loc_begin;
00144   to_dir.normalize();
00145 }
00146 
00147 
00148 vnl_matrix<double>
00149 rgrl_trans_quadratic::
00150 transfer_error_covar( vnl_vector<double> const& p  ) const
00151 {
00152   unsigned const m = A_.rows();
00153 
00154   assert ( is_covar_set() );
00155   assert ( p.size() == m );
00156   int num_terms = m+int(m*(m-1)/2) + m +1;
00157 
00158   vnl_matrix<double> temp( m, m*num_terms, 0.0 );
00159   vnl_vector<double> p_centered = p - from_centre_;
00160   vnl_vector<double> hot = higher_order_terms(p_centered);
00161 
00162   for ( unsigned i=0; i < m; ++i ) {
00163     unsigned off = i*num_terms;
00164     for ( unsigned j=0; j < hot.size(); ++j ) {
00165       temp(i,off+j) = hot[j];
00166     }
00167     off += hot.size();
00168     for ( unsigned j=0; j < m; ++j ) {
00169       temp(i,off+j) = p_centered[j];
00170     }
00171     temp(i,off+m) = 1.0;
00172   }
00173 
00174   return temp * covar_ * temp.transpose();
00175 }
00176 
00177 vnl_matrix<double> const&
00178 rgrl_trans_quadratic::
00179 Q() const
00180 {
00181   return Q_;
00182 }
00183 
00184 vnl_matrix<double> const&
00185 rgrl_trans_quadratic::
00186 A() const
00187 {
00188   return A_;
00189 }
00190 
00191 
00192 vnl_vector<double> const&
00193 rgrl_trans_quadratic::
00194 t() const
00195 {
00196   return trans_;
00197 }
00198 
00199 void
00200 rgrl_trans_quadratic::
00201 inv_map( const vnl_vector<double>& to,
00202          bool initialize_next,
00203          const vnl_vector<double>& to_delta,
00204          vnl_vector<double>& from,
00205          vnl_vector<double>& from_next_est) const
00206 {
00207   const double epsilon = 0.01;
00208   const double eps_squared = epsilon*epsilon;
00209   int t=0;
00210   const int max_t = 20;  //  Generally, only one or two iterations should be needed.
00211   assert (to.size() == from.size());
00212   int m = to.size();
00213   vnl_vector<double> to_est = this->map_location(from);
00214   vnl_matrix<double> approx_A_inv;
00215 
00216   while ( vnl_vector_ssd(to, to_est) > eps_squared && t<max_t ) {
00217     t ++ ;
00218     // compute the inverse of the approximated affine
00219     vnl_matrix<double> approx_A = A_;
00220     vnl_matrix<double> X(Q_.cols(), Q_.rows(), 0.0); //content of X depends on m
00221     if (m == 2) { //2D
00222       X(0,0) = 2*from[0]; X(1,1) = 2*from[1];
00223       X(2,0) = from[1]; X(2,1) = from[0];
00224     }
00225     else { //3D
00226       X(0,0) = 2*from[0]; X(1,1) = 2*from[1]; X(2,2) = 2*from[2];
00227       X(3,0) = from[1]; X(2,1) = from[0];
00228       X(4,1) = from[2]; X(4,2) = from[1];
00229       X(5,0) = from[2]; X(5,2) = from[0];
00230     }
00231     approx_A += Q_*X;
00232     vnl_svd<double> svd(approx_A);
00233     approx_A_inv = svd.inverse();
00234 
00235     // increase from by approx_A^-1*(to-to_est)
00236     from += 0.95 * approx_A_inv * (to - to_est);
00237     to_est = this->map_location(from);
00238   }
00239   if ( t > max_t )
00240     DebugMacro( 0, " rgrl_trans_quadratic::inv_map()--  no convergence\n");
00241 
00242   if ( initialize_next ) {
00243     if ( t == 0 ) { //approx_A_inv not yet calculated
00244       vnl_matrix<double> approx_A = A_;
00245       vnl_matrix<double> X(Q_.cols(), Q_.rows(), 0.0); //content of X depends on m
00246       if (m == 2) { //2D
00247         X(0,0) = 2*from[0]; X(1,1) = 2*from[1];
00248         X(2,0) = from[1]; X(2,1) = from[0];
00249       }
00250       else { //3D
00251         X(0,0) = 2*from[0]; X(1,1) = 2*from[1]; X(2,2) = 2*from[2];
00252         X(3,0) = from[1]; X(2,1) = from[0];
00253         X(4,1) = from[2]; X(4,2) = from[1];
00254         X(5,0) = from[2]; X(5,2) = from[0];
00255       }
00256       approx_A += Q_*X;
00257       vnl_svd<double> svd(approx_A);
00258       approx_A_inv = svd.inverse();
00259     }
00260     from_next_est = from + approx_A_inv * to_delta;
00261   }
00262 }
00263 
00264 void
00265 rgrl_trans_quadratic::
00266 jacobian_wrt_loc( vnl_matrix<double>& jacobian_Q, vnl_vector<double> const& from_loc ) const
00267 {
00268   unsigned int m = trans_.size();
00269   jacobian_Q.set_size(m, m);
00270   if ( m == 2 ) {
00271     for (unsigned int i = 0; i<m; i++) {
00272       jacobian_Q(i,0) = 2*Q_(i,0)*from_loc[0] + Q_(i,2)*from_loc[1];
00273       jacobian_Q(i,1) = 2*Q_(i,1)*from_loc[1] + Q_(i,2)*from_loc[0];
00274     }
00275   }
00276   else { // m == 3
00277     for (unsigned int i = 0; i<m; i++) {
00278       jacobian_Q(i,0) = 2*Q_(i,0)*from_loc[0] + Q_(i,3)*from_loc[1] + Q_(i,5)*from_loc[2];
00279       jacobian_Q(i,1) = 2*Q_(i,1)*from_loc[1] + Q_(i,3)*from_loc[0] + Q_(i,4)*from_loc[2];
00280       jacobian_Q(i,2) = 2*Q_(i,2)*from_loc[2] + Q_(i,4)*from_loc[1] + Q_(i,5)*from_loc[0];
00281     }
00282   }
00283 
00284   //return A_ + jacobian_Q;
00285   jacobian_Q += A_;
00286 }
00287 
00288 rgrl_transformation_sptr
00289 rgrl_trans_quadratic::
00290 scale_by( double scale ) const
00291 {
00292   rgrl_trans_quadratic* quad = new rgrl_trans_quadratic( Q_/scale, A_,
00293                                                          trans_ * scale,
00294                                                          covar_);
00295   quad->set_from_center( from_centre_ * scale );
00296   quad->set_scaling_factors( this->scaling_factors() );
00297 
00298   return quad;
00299 }
00300 
00301 vnl_vector<double>
00302 rgrl_trans_quadratic::
00303 higher_order_terms(vnl_vector<double> p) const
00304 {
00305   int m = p.size();
00306   vnl_vector<double> higher_terms( m + int(m*(m-1)/2));
00307 
00308   if (m == 3) {
00309     higher_terms[0] = vnl_math_sqr(p[0]);   //x^2
00310     higher_terms[1] = vnl_math_sqr(p[1]);   //y^2
00311     higher_terms[2] = vnl_math_sqr(p[2]);   //z^2
00312     higher_terms[3] = p[0]*p[1];       //xy
00313     higher_terms[4] = p[1]*p[2];       //yz
00314     higher_terms[5] = p[0]*p[2];       //xz
00315   }
00316   else { //m ==2
00317     higher_terms[0] = vnl_math_sqr(p[0]);         //x^2
00318     higher_terms[1] = vnl_math_sqr(p[1]);         //y^2
00319     higher_terms[2] = p[0]*p[1];                  //xy
00320   }
00321 
00322   return higher_terms;
00323 }
00324 
00325 void
00326 rgrl_trans_quadratic::
00327 write( vcl_ostream& os ) const
00328 {
00329   vnl_vector<double> origin(from_centre_.size(), 0.0);
00330   // tag
00331   os << "QUADRATIC\n"
00332   // parameters
00333      << t().size() << vcl_endl
00334      << Q_<< A_ << trans_ << ' ' << origin << vcl_endl;
00335 
00336   // parent
00337   rgrl_transformation::write( os );
00338 }
00339 
00340 bool
00341 rgrl_trans_quadratic::
00342 read( vcl_istream& is )
00343 {
00344   // skip empty lines
00345   rgrl_util_skip_empty_lines( is );
00346 
00347   vcl_string str;
00348   vcl_getline( is, str );
00349 
00350   // The token should appear at the beginning of line
00351   if ( str.find( "QUADRATIC" ) != 0 ) {
00352     WarningMacro( "The tag is not QUADRATIC. reading is aborted.\n" );
00353     return false;
00354   }
00355 
00356   // input global xform
00357   int dim=-1;
00358   is >> dim;
00359   if ( dim > 0 ) {
00360     Q_.set_size( dim, dim + int(dim*(dim-1)/2) );
00361     A_.set_size( dim, dim );
00362     trans_.set_size( dim );
00363     from_centre_.set_size( dim );
00364     is >> Q_ >> A_ >> trans_ >> from_centre_;
00365   }
00366 
00367   // parent
00368   return is.good() && rgrl_transformation::read( is );
00369 }
00370 
00371 void
00372 rgrl_trans_quadratic::
00373 inv_map( vnl_vector<double> const& /*to*/,
00374          vnl_vector<double>& /*from*/ ) const
00375 {
00376   assert ( ! "rgrl_trans_quadratic::inv_map() is not defined" );
00377 }
00378 
00379 rgrl_transformation_sptr
00380 rgrl_trans_quadratic::
00381 inverse_transform( ) const
00382 {
00383   assert ( ! "rgrl_trans_quadratic::inverse_transform() is not defined" );
00384   return 0;
00385 }
00386 
00387 //: make a clone copy
00388 rgrl_transformation_sptr 
00389 rgrl_trans_quadratic::
00390 clone() const
00391 {
00392   return new rgrl_trans_quadratic( *this );
00393 }