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