00001 #include "rgrl_transformation.h"
00002
00003
00004
00005
00006
00007
00008 #include <rgrl/rgrl_util.h>
00009 #include <vnl/vnl_math.h>
00010 #include <vnl/vnl_least_squares_function.h>
00011 #include <vnl/algo/vnl_levenberg_marquardt.h>
00012
00013 #include <vcl_iostream.h>
00014 #include <vcl_cassert.h>
00015
00016 #include <vnl/vnl_cross.h>
00017 #include <vnl/vnl_double_3.h>
00018 #include <vnl/vnl_double_2.h>
00019 #include <vnl/algo/vnl_symmetric_eigensystem.h>
00020
00021 rgrl_transformation::
00022 rgrl_transformation( const vnl_matrix<double>& cov )
00023 : is_covar_set_(false)
00024 {
00025 set_covar( cov );
00026 }
00027
00028 rgrl_transformation::
00029 ~rgrl_transformation()
00030 {
00031 }
00032
00033 void
00034 rgrl_transformation::
00035 map_location( vnl_vector<double> const& from,
00036 vnl_vector<double> & to ) const
00037 {
00038 map_loc( from, to );
00039 }
00040
00041 vnl_vector<double>
00042 rgrl_transformation::
00043 map_location( vnl_vector<double> const& p ) const
00044 {
00045 vnl_vector<double> result( p.size() );
00046 map_loc( p, result );
00047 return result;
00048 }
00049
00050 void
00051 rgrl_transformation::
00052 map_direction( vnl_vector<double> const& from_loc,
00053 vnl_vector<double> const& from_dir,
00054 vnl_vector<double> & to_dir ) const
00055 {
00056 map_dir( from_loc, from_dir, to_dir );
00057 }
00058
00059 void
00060 rgrl_transformation::
00061 map_tangent( vnl_vector<double> const& from_loc,
00062 vnl_vector<double> const& from_dir,
00063 vnl_vector<double> & to_dir ) const
00064 {
00065 vnl_matrix<double> J;
00066 this->jacobian_wrt_loc( J, from_loc );
00067 assert ( from_loc.size() == J.cols() );
00068 assert ( from_dir.size() == J.cols() );
00069
00070 to_dir = J * from_dir;
00071 to_dir.normalize();
00072 }
00073
00074 void
00075 rgrl_transformation::
00076 map_normal( vnl_vector<double> const & from_loc,
00077 vnl_vector<double> const & from_dir,
00078 vnl_vector<double> & to_dir ) const
00079 {
00080 #if 0
00081
00082 vnl_matrix< double > tangent_subspace;
00083 vnl_matrix<double> one_row( 1, from_dir.size() );
00084 one_row.set_row( 0, from_dir );
00085 vnl_svd<double> normal_svd( one_row );
00086 tangent_subspace = normal_svd.nullspace();
00087 assert ( tangent_subspace.columns() == from_dir. size() - 1 );
00088
00089
00090 map_normal( from_loc, from_dir, tangent_subspace, to_dir );
00091 #endif
00092
00093
00094 unsigned int m = from_loc.size();
00095 if (m == 2)
00096 {
00097
00098 vnl_vector< double > from_tangent(2);
00099 from_tangent[0] = from_dir[1];
00100 from_tangent[1] = -from_dir[0];
00101
00102
00103 vnl_vector< double > xformed_tangent;
00104 map_tangent(from_loc, from_tangent, xformed_tangent);
00105
00106
00107 xformed_tangent.normalize();
00108 to_dir.set_size( 2 );
00109 to_dir[0] = -xformed_tangent[1];
00110 to_dir[1] = xformed_tangent[0];
00111 }
00112 else
00113 {
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129 vnl_double_3 from_tangent0;
00130 vnl_double_3 from_tangent1;
00131
00132 unsigned int min_index=0;
00133 double min = vcl_abs(from_dir[0]);
00134 for ( unsigned int i=1; i<3; i++)
00135 if ( vcl_abs(from_dir[i]) < min ) {
00136 min = vcl_abs( from_dir[i] );
00137 min_index = i;
00138 }
00139
00140
00141 vnl_double_2 t, n;
00142 for (unsigned int i=0,j=0; i<3; ++i)
00143 if ( i != min_index )
00144 n[j++] = from_dir[i];
00145
00146 t[0] = n[1];
00147 t[1] = -n[0];
00148
00149
00150 for (unsigned int i=0,j=0; i<3; ++i)
00151 if ( i != min_index )
00152 from_tangent0[i] = t[j++];
00153 else
00154 from_tangent0[i] = 0.0;
00155
00156
00157 from_tangent1 = vnl_cross_3d( vnl_double_3(from_dir), from_tangent0 );
00158
00159
00160 vnl_vector< double > xformed_tangent0;
00161 vnl_vector< double > xformed_tangent1;
00162 map_tangent(from_loc, from_tangent0.as_ref(), xformed_tangent0);
00163 map_tangent(from_loc, from_tangent1.as_ref(), xformed_tangent1);
00164 to_dir = vnl_cross_3d( xformed_tangent0, xformed_tangent1 );
00165 to_dir.normalize();
00166 }
00167 }
00168
00169 void
00170 rgrl_transformation::
00171 map_normal( vnl_vector<double> const & from_loc,
00172 vnl_vector<double> const & ,
00173 vnl_matrix< double > const& tangent_subspace,
00174 vnl_vector<double> & to_dir ) const
00175 {
00176 #if 0
00177
00178 vnl_matrix< double > xform_tangent_subspace = tangent_subspace.transpose();
00179 vnl_vector< double > xformed_tangent;
00180 for ( unsigned int i = 0; i< tangent_subspace.columns(); i++ ) {
00181 map_tangent(from_loc, tangent_subspace.get_column(i), xformed_tangent);
00182 xform_tangent_subspace.set_row(i, xformed_tangent);
00183 }
00184
00185
00186
00187
00188 if ( tangent_subspace.columns() == 2 ) {
00189
00190 vnl_vector< double > tangent1 = xform_tangent_subspace.get_row(0);
00191 vnl_vector< double > tangent2 = xform_tangent_subspace.get_row(1);
00192 vnl_vector< double > ortho_tangent = tangent2 - inner_product(tangent2,tangent1)* tangent1;
00193 xform_tangent_subspace.set_row(1, ortho_tangent.normalize());
00194 }
00195
00196
00197 vnl_svd<double> tangent_svd( xform_tangent_subspace );
00198 assert ( tangent_svd.nullspace().columns() == 1 );
00199 to_dir = tangent_svd.nullspace().get_column(0);
00200 #endif
00201
00202 unsigned int m = tangent_subspace.rows();
00203 if (m == 2) {
00204 vnl_vector< double > xformed_tangent;
00205 map_tangent(from_loc, tangent_subspace.get_column(0), xformed_tangent);
00206 xformed_tangent.normalize();
00207 to_dir.set_size( 2 );
00208 to_dir[0] = -xformed_tangent[1];
00209 to_dir[1] = xformed_tangent[0];
00210 }
00211 else {
00212 vnl_vector< double > xformed_tangent0;
00213 vnl_vector< double > xformed_tangent1;
00214 map_tangent(from_loc, tangent_subspace.get_column(0), xformed_tangent0);
00215 map_tangent(from_loc, tangent_subspace.get_column(1), xformed_tangent1);
00216 to_dir = vnl_cross_3d( xformed_tangent0, xformed_tangent1 );
00217 to_dir.normalize();
00218 }
00219 }
00220
00221 double
00222 rgrl_transformation::
00223 map_intensity( vnl_vector<double> const& ,
00224 double intensity ) const
00225 {
00226 return intensity;
00227 }
00228
00229 double
00230 rgrl_transformation::
00231 log_det_covar() const
00232 {
00233 return log_det_sym_matrix( covar_ );
00234 }
00235
00236 double
00237 rgrl_transformation::
00238 log_det_sym_matrix( vnl_matrix<double> const& m ) const
00239 {
00240 assert( m.rows() && m.cols() );
00241 assert( m.rows() == m.cols() );
00242
00243
00244
00245
00246
00247
00248
00249 double result = 0;
00250 vnl_symmetric_eigensystem<double> eig(m);
00251 for ( unsigned i=0; i<m.rows(); ++i )
00252 result += vcl_log( eig.get_eigenvalue(i) );
00253 return result;
00254 }
00255
00256 double
00257 rgrl_transformation::
00258 log_det_covar_deficient( int rank ) const
00259 {
00260
00261
00262 vcl_vector<unsigned int> zero_indices;
00263 for ( unsigned i=0; i<covar_.rows(); ++i )
00264 if ( !covar_(i,i) ) {
00265
00266
00267 bool all_zero=true;
00268 for ( unsigned j=0; j<covar_.cols()&&all_zero; ++j )
00269 if ( covar_(i,j) )
00270 all_zero=false;
00271
00272 if ( all_zero )
00273 zero_indices.push_back( i );
00274 }
00275
00276 vnl_matrix<double> m;
00277
00278 if ( !zero_indices.empty() ) {
00279
00280
00281
00282 const unsigned int num = covar_.rows() - zero_indices.size();
00283 m.set_size( num, num );
00284 for ( unsigned i=0,ic=0,iz=0; i<covar_.rows(); ++i ) {
00285
00286 if ( iz<zero_indices.size() && i == zero_indices[iz] ) {
00287 ++iz;
00288 continue;
00289 }
00290
00291 for ( unsigned j=0,jc=0,jz=0; j<covar_.cols(); ++j ) {
00292
00293 if ( jz<zero_indices.size() && j == zero_indices[jz] ) {
00294 ++jz;
00295 continue;
00296 }
00297 m( ic, jc ) = covar_( i, j );
00298
00299 ++jc;
00300 }
00301
00302 ++ic;
00303 }
00304 }
00305 else
00306 m = covar_;
00307
00308
00309 const int num = m.rows();
00310
00311
00312 if ( rank <= 0 )
00313 rank = num;
00314
00315 double result = 0;
00316 vnl_symmetric_eigensystem<double> eig(m);
00317 for ( int i=0; i<rank; ++i )
00318 result += vcl_log( eig.get_eigenvalue(num-1-i) );
00319 return result;
00320 }
00321
00322
00323 vnl_matrix<double>
00324 rgrl_transformation::
00325 covar() const
00326 {
00327 assert( is_covar_set_ );
00328 return covar_;
00329 }
00330
00331 vnl_matrix<double>
00332 rgrl_transformation::
00333 jacobian( vnl_vector<double> const& from_loc ) const
00334 {
00335 vnl_matrix<double> jac;
00336 this->jacobian_wrt_loc( jac, from_loc );
00337
00338 return jac;
00339 }
00340
00341
00342 void
00343 rgrl_transformation::
00344 set_covar( const vnl_matrix<double>& covar )
00345 {
00346 covar_ = covar;
00347 if ( covar.rows() > 0 && covar.cols() > 0 ) {
00348 is_covar_set_ = true;
00349 }
00350 }
00351
00352
00353
00354
00355 void
00356 rgrl_transformation::
00357 set_scaling_factors( vnl_vector<double> const& scaling )
00358 {
00359
00360
00361 for ( unsigned int i=0; i<scaling.size(); ++i )
00362 assert( vnl_math_isfinite( scaling[i] ) );
00363
00364 scaling_factors_ = scaling;
00365 }
00366
00367
00368 vcl_ostream&
00369 operator<< (vcl_ostream& os, rgrl_transformation const& xform )
00370 {
00371 xform.write( os );
00372 return os;
00373 }
00374
00375
00376 void
00377 rgrl_transformation::
00378 write( vcl_ostream& os ) const
00379 {
00380 if ( is_covar_set() )
00381 {
00382
00383 os << "COVARIANCE\n"
00384 << covar_.rows() << ' ' << covar_.cols() << vcl_endl
00385 << covar_ << vcl_endl;
00386 }
00387
00388 if ( scaling_factors_.size() )
00389 {
00390
00391 os << "SCALING_FACTORS\n"
00392 << scaling_factors_.size() << vcl_endl
00393 << scaling_factors_ << vcl_endl;
00394 }
00395 }
00396
00397
00398 bool
00399 rgrl_transformation::
00400 read( vcl_istream& is )
00401 {
00402 vcl_streampos pos;
00403 vcl_string tag_str;
00404
00405
00406 rgrl_util_skip_empty_lines( is );
00407 if ( !is.good() )
00408 return true;
00409
00410 tag_str="";
00411 pos = is.tellg();
00412 vcl_getline( is, tag_str );
00413
00414 if ( tag_str.find("COVARIANCE") == 0 )
00415 {
00416
00417 int m=-1, n=-1;
00418 vnl_matrix<double> cov;
00419
00420
00421 is >> m >> n;
00422 if ( !is || m<=0 || n<=0 )
00423 return false;
00424
00425 cov.set_size(m, n);
00426 cov.fill(0.0);
00427 is >> cov;
00428
00429 if ( !is.good() )
00430 return false;
00431
00432 this->set_covar( cov );
00433
00434
00435
00436 rgrl_util_skip_empty_lines( is );
00437 if ( is.eof() )
00438 return true;
00439
00440 tag_str="";
00441 pos = is.tellg();
00442 vcl_getline( is, tag_str );
00443 }
00444
00445 if ( tag_str.find("SCALING_FACTORS") == 0 )
00446 {
00447
00448 int m=-1;
00449
00450
00451 is >> m;
00452
00453 if ( !is || m<=0 )
00454 return false;
00455
00456 scaling_factors_.set_size( m );
00457 is >> scaling_factors_;
00458
00459 return is.good();
00460 }
00461
00462
00463 is.seekg( pos );
00464 return is.good();
00465 }
00466
00467
00468 class inverse_mapping_func
00469 : public vnl_least_squares_function
00470 {
00471 public:
00472 inverse_mapping_func( rgrl_transformation const* xform_ptr, vnl_vector<double> const& to_loc )
00473 : vnl_least_squares_function( to_loc.size(), to_loc.size(), use_gradient ),
00474 xform_( xform_ptr ), to_loc_( to_loc )
00475 {}
00476
00477
00478 void f(vnl_vector<double> const& x, vnl_vector<double>& fx);
00479
00480
00481 void gradf(vnl_vector<double> const& x, vnl_matrix<double>& jacobian);
00482
00483 public:
00484 const rgrl_transformation* xform_;
00485 vnl_vector<double> to_loc_;
00486 };
00487
00488
00489 void
00490 inverse_mapping_func::
00491 f(vnl_vector<double> const& x, vnl_vector<double>& fx)
00492 {
00493 assert( xform_ );
00494
00495
00496
00497 xform_->map_location( x, fx );
00498
00499
00500 fx -= to_loc_;
00501 }
00502
00503 void
00504 inverse_mapping_func::
00505 gradf(vnl_vector<double> const& x, vnl_matrix<double>& jacobian)
00506 {
00507 assert( xform_ );
00508
00509
00510
00511 xform_->jacobian_wrt_loc( jacobian, x );
00512 }
00513
00514
00515 void
00516 rgrl_transformation::
00517 inv_map( const vnl_vector<double>& to,
00518 bool initialize_next,
00519 const vnl_vector<double>& ,
00520 vnl_vector<double>& from,
00521 vnl_vector<double>& from_next_est) const
00522 {
00523
00524 if ( to.size() == 2 )
00525 {
00526 static inverse_mapping_func inv_map_func( this, to );
00527
00528
00529 inv_map_func.to_loc_ = to;
00530 inv_map_func.xform_ = this;
00531
00532
00533 static vnl_levenberg_marquardt lm( inv_map_func );
00534
00535
00536
00537
00538 lm.set_f_tolerance( 1e-4 );
00539 lm.set_x_tolerance( 1e-3 );
00540 lm.set_max_function_evals( 100 );
00541
00542
00543 bool ret = lm.minimize_using_gradient( from );
00544
00545 if ( !ret ) {
00546 WarningMacro( "Levenberg-Marquardt in rgrl_transformation::inv_map has failed!!!" );
00547 return;
00548 }
00549 }
00550 else if ( to.size() == 3 )
00551 {
00552 static inverse_mapping_func inv_map_func( this, to );
00553
00554
00555 inv_map_func.to_loc_ = to;
00556 inv_map_func.xform_ = this;
00557
00558
00559 static vnl_levenberg_marquardt lm( inv_map_func );
00560
00561
00562
00563
00564 lm.set_f_tolerance( 1e-4 );
00565 lm.set_x_tolerance( 1e-3 );
00566 lm.set_max_function_evals( 100 );
00567
00568
00569 bool ret = lm.minimize_using_gradient( from );
00570
00571 if ( !ret ) {
00572 WarningMacro( "Levenberg-Marquardt in rgrl_transformation::inv_map has failed!!!" );
00573 return;
00574 }
00575 }
00576 else
00577 {
00578 assert( ! "Other dimensioin is not implemented!" );
00579 return;
00580 }
00581
00582
00583
00584
00585
00586
00587
00588
00589 if ( initialize_next ) {
00590 from_next_est = from;
00591 }
00592 }
00593
00594
00595
00596 void
00597 rgrl_transformation::
00598 inv_map( const vnl_vector<double>& to,
00599 vnl_vector<double>& from ) const
00600 {
00601 const bool initialize_next = false;
00602 vnl_vector<double> unused;
00603 inv_map( to, initialize_next, unused, from, unused );
00604 }
00605
00606
00607
00608 rgrl_transformation_sptr
00609 rgrl_transformation::
00610 inverse_transform() const
00611 {
00612 assert( !"Should never reach rgrl_transformation::inverse_transform()" );
00613 return 0;
00614 }
00615