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 } else
00305 m = covar_;
00306
00307
00308 const int num = m.rows();
00309
00310
00311 if ( rank <= 0 )
00312 rank = num;
00313
00314 double result = 0;
00315 vnl_symmetric_eigensystem<double> eig(m);
00316 for ( int i=0; i<rank; ++i )
00317 result += vcl_log( eig.get_eigenvalue(num-1-i) );
00318 return result;
00319 }
00320
00321
00322 vnl_matrix<double>
00323 rgrl_transformation::
00324 covar() const
00325 {
00326 assert( is_covar_set_ );
00327 return covar_;
00328 }
00329
00330 vnl_matrix<double>
00331 rgrl_transformation::
00332 jacobian( vnl_vector<double> const& from_loc ) const
00333 {
00334 vnl_matrix<double> jac;
00335 this->jacobian_wrt_loc( jac, from_loc );
00336
00337 return jac;
00338 }
00339
00340
00341 void
00342 rgrl_transformation::
00343 set_covar( const vnl_matrix<double>& covar )
00344 {
00345 covar_ = covar;
00346 if ( covar.rows() > 0 && covar.cols() > 0 ) {
00347 is_covar_set_ = true;
00348 }
00349 }
00350
00351
00352
00353
00354 void
00355 rgrl_transformation::
00356 set_scaling_factors( vnl_vector<double> const& scaling )
00357 {
00358
00359
00360 for ( unsigned int i=0; i<scaling.size(); ++i )
00361 assert( vnl_math_isfinite( scaling[i] ) );
00362
00363 scaling_factors_ = scaling;
00364 }
00365
00366
00367 vcl_ostream&
00368 operator<< (vcl_ostream& os, rgrl_transformation const& xform )
00369 {
00370 xform.write( os );
00371 return os;
00372 }
00373
00374
00375 void
00376 rgrl_transformation::
00377 write( vcl_ostream& os ) const
00378 {
00379 if ( is_covar_set() )
00380 {
00381
00382 os << "COVARIANCE\n"
00383 << covar_.rows() << ' ' << covar_.cols() << vcl_endl
00384 << covar_ << vcl_endl;
00385 }
00386
00387 if ( scaling_factors_.size() )
00388 {
00389
00390 os << "SCALING_FACTORS\n"
00391 << scaling_factors_.size() << vcl_endl
00392 << scaling_factors_ << vcl_endl;
00393 }
00394 }
00395
00396
00397 bool
00398 rgrl_transformation::
00399 read( vcl_istream& is )
00400 {
00401 vcl_streampos pos;
00402 vcl_string tag_str;
00403
00404
00405 rgrl_util_skip_empty_lines( is );
00406 if ( !is.good() )
00407 return true;
00408
00409 tag_str="";
00410 pos = is.tellg();
00411 vcl_getline( is, tag_str );
00412
00413 if ( tag_str.find("COVARIANCE") == 0 )
00414 {
00415
00416 int m=-1, n=-1;
00417 vnl_matrix<double> cov;
00418
00419
00420 is >> m >> n;
00421 if ( !is || m<=0 || n<=0 )
00422 return false;
00423
00424 cov.set_size(m, n);
00425 cov.fill(0.0);
00426 is >> cov;
00427
00428 if ( !is.good() )
00429 return false;
00430
00431 this->set_covar( cov );
00432
00433
00434
00435 rgrl_util_skip_empty_lines( is );
00436 if ( is.eof() )
00437 return true;
00438
00439 tag_str="";
00440 pos = is.tellg();
00441 vcl_getline( is, tag_str );
00442 }
00443
00444 if ( tag_str.find("SCALING_FACTORS") == 0 )
00445 {
00446
00447 int m=-1;
00448
00449
00450 is >> m;
00451
00452 if ( !is || m<=0 )
00453 return false;
00454
00455 scaling_factors_.set_size( m );
00456 is >> scaling_factors_;
00457
00458 return is.good();
00459 }
00460
00461
00462 is.seekg( pos );
00463 return is.good();
00464 }
00465
00466
00467 class inverse_mapping_func
00468 : public vnl_least_squares_function
00469 {
00470 public:
00471 inverse_mapping_func( rgrl_transformation const* xform_ptr, vnl_vector<double> const& to_loc )
00472 : vnl_least_squares_function( to_loc.size(), to_loc.size(), use_gradient ),
00473 xform_( xform_ptr ), to_loc_( to_loc )
00474 {}
00475
00476
00477 void f(vnl_vector<double> const& x, vnl_vector<double>& fx);
00478
00479
00480 void gradf(vnl_vector<double> const& x, vnl_matrix<double>& jacobian);
00481
00482 public:
00483 const rgrl_transformation* xform_;
00484 vnl_vector<double> to_loc_;
00485 };
00486
00487
00488 void
00489 inverse_mapping_func::
00490 f(vnl_vector<double> const& x, vnl_vector<double>& fx)
00491 {
00492 assert( xform_ );
00493
00494
00495
00496 xform_->map_location( x, fx );
00497
00498
00499 fx -= to_loc_;
00500 }
00501
00502 void
00503 inverse_mapping_func::
00504 gradf(vnl_vector<double> const& x, vnl_matrix<double>& jacobian)
00505 {
00506 assert( xform_ );
00507
00508
00509
00510 xform_->jacobian_wrt_loc( jacobian, x );
00511 }
00512
00513
00514 void
00515 rgrl_transformation::
00516 inv_map( const vnl_vector<double>& to,
00517 bool initialize_next,
00518 const vnl_vector<double>& ,
00519 vnl_vector<double>& from,
00520 vnl_vector<double>& from_next_est) const
00521 {
00522
00523 if ( to.size() == 2 )
00524 {
00525 static inverse_mapping_func inv_map_func( this, to );
00526
00527
00528 inv_map_func.to_loc_ = to;
00529 inv_map_func.xform_ = this;
00530
00531
00532 static vnl_levenberg_marquardt lm( inv_map_func );
00533
00534
00535
00536
00537 lm.set_f_tolerance( 1e-4 );
00538 lm.set_x_tolerance( 1e-3 );
00539 lm.set_max_function_evals( 100 );
00540
00541
00542 bool ret = lm.minimize_using_gradient( from );
00543
00544 if ( !ret ) {
00545 WarningMacro( "Levenberg-Marquatt in rgrl_transformation::inv_map has failed!!!" );
00546 return;
00547 }
00548 }
00549 else if ( to.size() == 3 )
00550 {
00551 static inverse_mapping_func inv_map_func( this, to );
00552
00553
00554 inv_map_func.to_loc_ = to;
00555 inv_map_func.xform_ = this;
00556
00557
00558 static vnl_levenberg_marquardt lm( inv_map_func );
00559
00560
00561
00562
00563 lm.set_f_tolerance( 1e-4 );
00564 lm.set_x_tolerance( 1e-3 );
00565 lm.set_max_function_evals( 100 );
00566
00567
00568 bool ret = lm.minimize_using_gradient( from );
00569
00570 if ( !ret ) {
00571 WarningMacro( "Levenberg-Marquatt in rgrl_transformation::inv_map has failed!!!" );
00572 return;
00573 }
00574 }
00575 else
00576 {
00577 assert( ! "Other dimensioin is not implemented!" );
00578 return;
00579 }
00580
00581
00582
00583
00584
00585
00586
00587
00588 if ( initialize_next ) {
00589 from_next_est = from;
00590 }
00591 }
00592
00593
00594
00595 void
00596 rgrl_transformation::
00597 inv_map( const vnl_vector<double>& to,
00598 vnl_vector<double>& from ) const
00599 {
00600 const bool initialize_next = false;
00601 vnl_vector<double> unused;
00602 inv_map( to, initialize_next, unused, from, unused );
00603 }
00604
00605
00606
00607 rgrl_transformation_sptr
00608 rgrl_transformation::
00609 inverse_transform() const
00610 {
00611 assert( !"Should never reach rgrl_transformation::inverse_transform()" );
00612 return 0;
00613 }
00614