00001 #include "rgrl_trans_reduced_quad.h"
00002
00003
00004
00005
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() );
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
00076 if (A_.rows() == 2) {
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 {
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 );
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;
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
00202 vnl_matrix<double> approx_A = A_;
00203 vnl_matrix<double> X(Q_.cols(), Q_.rows(), 0.0);
00204 if (m == 2) {
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 {
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
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 ) {
00227 vnl_matrix<double> approx_A = A_;
00228 vnl_matrix<double> X(Q_.cols(), Q_.rows(), 0.0);
00229 if (m == 2) {
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 {
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
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]);
00285 higher_terms[1] = vnl_math_sqr(p[1]);
00286 higher_terms[2] = vnl_math_sqr(p[2]);
00287 higher_terms[3] = p[0]*p[1];
00288 higher_terms[4] = p[1]*p[2];
00289 higher_terms[5] = p[0]*p[2];
00290 }
00291 else {
00292 higher_terms[0] = vnl_math_sqr(p[0]);
00293 higher_terms[1] = vnl_math_sqr(p[1]);
00294 higher_terms[2] = p[0]*p[1];
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
00306 os << "REDUCED_QUADRATIC\n"
00307
00308 << t().size() << vcl_endl
00309 << Q_<< A_ << trans_ << ' ' << origin << vcl_endl;
00310
00311
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
00322 rgrl_util_skip_empty_lines( is );
00323
00324 vcl_string str;
00325 vcl_getline( is, str );
00326
00327
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
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
00345 return is.good() && rgrl_transformation::read( is );
00346 }
00347
00348 void
00349 rgrl_trans_reduced_quad::
00350 inv_map( vnl_vector<double> const& ,
00351 vnl_vector<double>& ) 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
00365 rgrl_transformation_sptr
00366 rgrl_trans_reduced_quad::
00367 clone() const
00368 {
00369 return new rgrl_trans_reduced_quad( *this );
00370 }