00001
00002
00003
00004
00005
00006 #include "rgrl_est_spline.h"
00007 #include "rgrl_spline.h"
00008 #include "rgrl_match_set.h"
00009 #include "rgrl_trans_spline.h"
00010 #include "rgrl_cast.h"
00011 #include <vnl/vnl_math.h>
00012 #include <vnl/algo/vnl_svd.h>
00013 #include <vnl/vnl_vector.h>
00014 #include <vnl/algo/vnl_levenberg_marquardt.h>
00015 #include <vnl/vnl_least_squares_function.h>
00016 #include <vnl/vnl_cost_function.h>
00017 #include <vnl/algo/vnl_conjugate_gradient.h>
00018 #include <vnl/algo/vnl_amoeba.h>
00019 #include <vnl/algo/vnl_powell.h>
00020 #include <vnl/algo/vnl_lbfgs.h>
00021 #include <vcl_iostream.h>
00022 #include <vul/vul_timer.h>
00023 #include <vcl_cassert.h>
00024
00025 namespace{
00026
00027 struct spline_least_squares_func : public vnl_least_squares_function
00028 {
00029 spline_least_squares_func( rgrl_spline_sptr spline,
00030 vcl_vector< vnl_vector< double > > const& pts,
00031 vnl_diag_matrix<double> const& wgt,
00032 vnl_vector<double> const& displacement,
00033 vcl_vector<unsigned> const& free_control_pt_index )
00034 : vnl_least_squares_function( free_control_pt_index.size(), pts.size(), use_gradient ),
00035
00036 spline_( spline ),
00037 pts_( pts ), wgt_( wgt ), displacement_( displacement ),
00038 free_control_pt_index_( free_control_pt_index )
00039 {
00040 assert( pts.size() == wgt.rows() );
00041 assert( displacement.size() == wgt.rows() );
00042 }
00043
00044
00045 void f( vnl_vector< double > const& x, vnl_vector< double > & fx )
00046 {
00047
00048 assert( x.size() == free_control_pt_index_.size() );
00049 vnl_vector< double > c( spline_->num_of_control_points(), 0.0 );
00050 for ( unsigned i=0; i< free_control_pt_index_.size(); ++i )
00051 c[ free_control_pt_index_[i] ] = x[ i ];
00052
00053 spline_->set_control_points( c );
00054
00055 assert( fx.size() == pts_.size() );
00056 for ( unsigned i = 0; i < pts_.size(); ++i ) {
00057 fx[ i ] = ( displacement_[ i ] - spline_->f_x( pts_[ i ] ) )
00058 * vcl_sqrt( wgt_[ i ] );
00059 }
00060 }
00061
00062
00063 void gradf( vnl_vector< double > const& x, vnl_matrix< double > & jacobian )
00064 {
00065 assert( x.size() == free_control_pt_index_.size() );
00066 vnl_vector< double > c( spline_->num_of_control_points(), 0.0 );
00067 for ( unsigned i=0; i< free_control_pt_index_.size(); ++i )
00068 c[ free_control_pt_index_[i] ] = x[ i ];
00069
00070 spline_->set_control_points( c );
00071 vnl_vector< double > gr;
00072 for ( unsigned i = 0; i < pts_.size(); ++i ) {
00073 spline_->basis_response( pts_[i], gr );
00074 for ( unsigned j = 0; j < x.size(); ++j )
00075 jacobian[ i ][ j ] = - gr[ free_control_pt_index_[j] ] * vcl_sqrt( wgt_[ i ] );
00076 }
00077 }
00078
00079 private:
00080 rgrl_spline_sptr spline_;
00081 vcl_vector< vnl_vector< double > > pts_;
00082 vnl_diag_matrix< double > wgt_;
00083 vnl_vector< double > displacement_;
00084 vcl_vector< unsigned > free_control_pt_index_;
00085 };
00086
00087
00088 struct spline_cost_function : public vnl_cost_function
00089 {
00090 spline_cost_function( rgrl_spline_sptr spline,
00091 vcl_vector< vnl_vector< double > > pts,
00092 vnl_diag_matrix<double> wgt,
00093 vnl_vector<double> displacement )
00094 : vnl_cost_function( spline->num_of_control_points() ),
00095 spline_( spline ),
00096 pts_( pts ), wgt_( wgt ), displacement_( displacement )
00097 {
00098 assert( pts.size() == wgt.rows() );
00099 assert( displacement.size() == wgt.rows() );
00100 }
00101
00102
00103 double f( vnl_vector< double > const& x )
00104 {
00105 double fx = 0;
00106 spline_->set_control_points( x );
00107 for ( unsigned i = 0; i < pts_.size(); ++i ) {
00108 fx += vnl_math_sqr( displacement_[ i ] - spline_->f_x( pts_[ i ] ) )
00109 * wgt_[ i ] ;
00110 }
00111 return fx;
00112 }
00113
00114 void gradf (vnl_vector< double > const &x, vnl_vector< double > &gradient )
00115 {
00116 gradient.fill( 0.0 );
00117 vnl_vector< double > gr;
00118 for ( unsigned i=0; i<pts_.size(); ++i ) {
00119 spline_->basis_response( pts_[i], gr );
00120 for ( unsigned j=0; j<spline_->num_of_control_points(); ++j ) {
00121 gradient[ j ] -= 2 * ( displacement_[i] - spline_->f_x( pts_[i] ) ) * wgt_[i]* gr[j];
00122 }
00123 }
00124 }
00125
00126 private:
00127 rgrl_spline_sptr spline_;
00128 vcl_vector< vnl_vector< double > > pts_;
00129 vnl_diag_matrix< double > wgt_;
00130 vnl_vector< double > displacement_;
00131 };
00132 }
00133
00134 rgrl_est_spline::
00135 rgrl_est_spline( unsigned dof,
00136 rgrl_mask_box const& roi, vnl_vector<double> const& delta,
00137 vnl_vector< unsigned > const& m,
00138 bool use_thin_plate, double lambda )
00139 : rgrl_nonlinear_estimator( dof ),
00140 roi_(roi), delta_(delta),
00141 m_( m ),
00142 use_thin_plate_( use_thin_plate ),
00143 lambda_(lambda),
00144 optimize_method_( RGRL_LEVENBERG_MARQUARDT ),
00145 global_xform_( 0 )
00146 {
00147 unsigned num_control = 1;
00148 for ( unsigned i=0; i<m.size(); ++i )
00149 num_control *= m[i] + 3;
00150
00151 assert( num_control == dof );
00152 }
00153
00154 rgrl_est_spline::
00155 rgrl_est_spline( unsigned dof,
00156 rgrl_transformation_sptr global_xform,
00157 rgrl_mask_box const& roi, vnl_vector<double> const& delta,
00158 vnl_vector< unsigned > const& m,
00159 bool use_thin_plate, double lambda )
00160 : rgrl_nonlinear_estimator( dof ),
00161 roi_(roi), delta_(delta),
00162 m_( m ),
00163 use_thin_plate_( use_thin_plate ),
00164 lambda_(lambda),
00165 optimize_method_( RGRL_LEVENBERG_MARQUARDT ),
00166 global_xform_( global_xform )
00167 {
00168 unsigned num_control = 1;
00169 for ( unsigned i=0; i<m.size(); ++i )
00170 num_control *= m[i] + 3;
00171
00172 vcl_cerr << "rgrl_est_spline.cxx : number of control points: " << num_control << ", dof=" << dof << vcl_endl;
00173 assert( num_control == dof );
00174 }
00175
00176 void
00177 rgrl_est_spline::
00178 point_in_knots( vnl_vector< double > const& point, vnl_vector< double > & spline_pt ) const
00179 {
00180 spline_pt.set_size( point.size() );
00181 for ( unsigned i = 0; i < point.size(); ++i ) {
00182 spline_pt[ i ] = point[ i ] / delta_[ i ];
00183 }
00184 }
00185
00186 rgrl_transformation_sptr
00187 rgrl_est_spline::
00188 estimate( rgrl_set_of<rgrl_match_set_sptr> const& matches,
00189 rgrl_transformation const& cur_transform ) const
00190 {
00191 typedef rgrl_match_set::const_from_iterator FIter;
00192 typedef FIter::to_iterator TIter;
00193
00194 unsigned dim = delta_.size();
00195
00196
00197
00198 unsigned num_match = 0;
00199 for ( unsigned ms=0; ms < matches.size(); ++ms ) {
00200 rgrl_match_set const& match_set = *matches[ms];
00201 for ( FIter fi = match_set.from_begin(); fi != match_set.from_end(); ++fi ) {
00202 vnl_vector<double> const& from_pt = fi.from_feature()->location();
00203
00204 if ( roi_.inside( from_pt ) ) {
00205 num_match += fi.size();
00206 }
00207 }
00208 }
00209
00210 vcl_vector< rgrl_spline_sptr > splines( dim );
00211 if ( cur_transform.is_type( rgrl_trans_spline::type_id() ) ) {
00212 rgrl_trans_spline const& cur_trans_spline = dynamic_cast< rgrl_trans_spline const& >(cur_transform);
00213 vcl_cerr << "delta_: " << delta_ << vcl_endl
00214 << "current transformation's delta_: " << cur_trans_spline.get_delta() << vcl_endl;
00215 if ( ( delta_ - cur_trans_spline.get_delta()/2 ).two_norm() < 1e-5 ) {
00216 for ( unsigned i=0; i<dim; ++i ) {
00217 splines[ i ] = cur_trans_spline.get_spline( i )->refinement( m_ );
00218 }
00219 DebugMacro(1, "###spline is initialized by refinement\n" );
00220 }
00221 else if ( ( delta_ - cur_trans_spline.get_delta() ).two_norm() < 1e-5 ) {
00222 DebugMacro(1, "###spline is initialized by copying\n" );
00223 for ( unsigned i=0; i<dim; ++i )
00224 splines[ i ] = new rgrl_spline( *(cur_trans_spline.get_spline( i )) );
00225 }
00226 else {
00227 DebugMacro(1, "create spline with m_=" << m_ << "\n");
00228 for ( unsigned i=0; i<dim; ++i )
00229 splines[ i ] = new rgrl_spline( m_ );
00230 }
00231 }
00232 else {
00233 DebugMacro(1, "create spline with m_=" << m_ << "\n" );
00234 for ( unsigned i=0; i<dim; ++i )
00235 splines[ i ] = new rgrl_spline( m_ );
00236 }
00237
00238 unsigned int num_control = splines[0]->num_of_control_points();
00239
00240 vnl_diag_matrix<double> wgt( num_match, 0 );
00241 vnl_matrix<double> displacement( num_match, dim );
00242 vnl_matrix<double> g( num_match, num_control );
00243
00244
00245 vnl_vector< double > tmp( dim, 0.0 );
00246 vcl_vector< vnl_vector< double > > from_pts_in_knots( num_match, tmp );
00247
00248
00249
00250 vcl_vector< unsigned > free_control_pt_index;
00251
00252 {
00253 unsigned i=0;
00254 vcl_vector< double > score_constraint( num_control, 0.0 );
00255 vcl_vector< bool > control_point_constraint( num_control, false );
00256 for ( unsigned ms=0; ms < matches.size(); ++ms ) {
00257 rgrl_match_set const& match_set = *matches[ms];
00258 DebugMacro_abv(2, "rgrl_est_spline.cxx: from_pt \t to_pt \t displacement\n");
00259 for ( FIter fi = match_set.from_begin(); fi != match_set.from_end(); ++fi ) {
00260 vnl_vector<double> const& from_pt = fi.from_feature()->location();
00261
00262 if ( roi_.inside( from_pt ) && fi.size() != 0 ) {
00263
00264 point_in_knots( from_pt, from_pts_in_knots[i] );
00265
00266 vnl_vector< double > gr;
00267
00268 splines[0]->basis_response( from_pts_in_knots[i], gr );
00269
00270
00271 for ( unsigned j=0; j<num_control; ++j ) {
00272 if ( !control_point_constraint[ j ] ) {
00273 score_constraint[ j ] += gr[j];
00274 if ( score_constraint[j] > 1e-3 )
00275 control_point_constraint[ j ] = true;
00276 }
00277 }
00278
00279 for ( TIter ti = fi.begin(); ti != fi.end(); ++ti ) {
00280 if ( !global_xform_ ) {
00281 displacement.set_row( i, ti.to_feature()->location() - from_pt );
00282
00283 DebugMacro_abv(2, from_pt << " \t " << ti.to_feature()->location() << " \t " << displacement.get_row( i ) << "\n" );
00284 }
00285 else {
00286 displacement.set_row( i, ti.to_feature()->location() - global_xform_->map_location( from_pt ) );
00287
00288 DebugMacro_abv(2, global_xform_->map_location( from_pt ) << " \t " << ti.to_feature()->location()
00289 << " \t " << displacement.get_row( i ) << "\n" );
00290 }
00291 g.set_row( i, gr );
00292 wgt[i] = ti.cumulative_weight();
00293 ++i;
00294 }
00295 }
00296 }
00297 }
00298
00299
00300 for ( unsigned i=0; i<num_control; ++i ) {
00301 if ( control_point_constraint[ i ] )
00302 free_control_pt_index.push_back( i );
00303 }
00304 }
00305
00306 vcl_cerr << "\nafter reduce dof, dof=" << free_control_pt_index.size() << vcl_endl;
00307 DebugMacro( 1, "\nafter reduce dof, dof=" << free_control_pt_index.size()<< vcl_endl );
00308
00309 vul_timer timer;
00310
00311 if ( optimize_method_ == RGRL_LEVENBERG_MARQUARDT )
00312 {
00313 DebugMacro( 1, "Levenberg marquardt :\n" );
00314 vnl_matrix< double > covar;
00315
00316 if (this->debug_flag() > 1) {
00317 vcl_cout << "rgrl_est_spline.cxx: displacement \t weight\n";
00318 for ( unsigned i=0; i<displacement.rows(); ++i )
00319 vcl_cout << i << " " << displacement.get_row( i ) << " \t " << wgt[i] << '\n';
00320 }
00321
00322 for ( unsigned i = 0; i < dim ; ++i ) {
00323 spline_least_squares_func f( splines[i], from_pts_in_knots, wgt, displacement.get_column( i ), free_control_pt_index );
00324 vnl_levenberg_marquardt minimizer( f );
00325
00326 vnl_vector< double > x( free_control_pt_index.size(), 0 );
00327 vnl_vector< double > & c = splines[i]->get_control_points();
00328 for ( unsigned j=0; j<x.size(); ++j )
00329 x[ j ] = c[ free_control_pt_index[ j ] ];
00330 if (this->debug_flag() > 1 ) timer.mark();
00331 minimizer.minimize( x );
00332 minimizer.diagnose_outcome(vcl_cout);
00333 if (this->debug_flag() > 1 ) {
00334 timer.print( vcl_cout );
00335 vcl_cout << "computing covariance\n";
00336 timer.mark();
00337 if ( i==0 )
00338 covar = minimizer.get_JtJ();
00339 timer.print( vcl_cout );
00340 vcl_cout << "covariance " << covar.rows() << 'x' << covar.columns() << vcl_endl;
00341 }
00342
00343
00344
00345 for ( unsigned j=0; j<x.size(); ++j )
00346 c[ free_control_pt_index[ j ] ] = x[ j ];
00347 splines[i]->set_control_points( c );
00348 DebugMacro( 1, "control points:\n" << c << vcl_endl );
00349 }
00350 return new rgrl_trans_spline( splines, vnl_vector<double>(dim,0.0), delta_, global_xform_ );
00351 }
00352 else if ( optimize_method_ == RGRL_CONJUGATE_GRADIENT ) {
00353 DebugMacro( 1, "Conjugate Gradient\n" );
00354 for ( unsigned i = 0; i < dim ; ++i ) {
00355 spline_cost_function f( splines[i], from_pts_in_knots, wgt, displacement.get_column( i ) );
00356 vnl_conjugate_gradient minimizer( f );
00357
00358
00359 vnl_vector< double > c( splines[i]->num_of_control_points(), 0 );
00360 minimizer.minimize( c );
00361 splines[i]->set_control_points( c );
00362 DebugMacro( 1, "control points:\n" << c << "\n" );
00363 }
00364 if ( this->debug_flag() > 1) timer.print( vcl_cout );
00365 return new rgrl_trans_spline( splines, vnl_vector<double>(dim,0.0), delta_, global_xform_ );
00366 }
00367 else if ( optimize_method_ == RGRL_AMOEBA ) {
00368 DebugMacro( 1, "Nelder-Meade downhill simplex (AMOEBA)\n" );
00369 for ( unsigned i = 0; i < dim ; ++i ) {
00370 spline_cost_function f( splines[i], from_pts_in_knots, wgt, displacement.get_column( i ) );
00371 vnl_amoeba minimizer( f );
00372
00373
00374 vnl_vector< double > c( splines[i]->num_of_control_points(), 0 );
00375 minimizer.minimize( c );
00376 splines[i]->set_control_points( c );
00377 DebugMacro( 1, "control points:\n" << c << "\n" );
00378 }
00379 if (this->debug_flag() > 1) timer.print( vcl_cout );
00380 return new rgrl_trans_spline( splines, vnl_vector<double>(dim,0.0), delta_, global_xform_ );
00381 }
00382 else if ( optimize_method_ == RGRL_POWELL ) {
00383 DebugMacro( 1, "Powell's direction-set\n " );
00384 for ( unsigned i = 0; i < dim ; ++i ) {
00385 spline_cost_function f( splines[i], from_pts_in_knots, wgt, displacement.get_column( i ) );
00386 vnl_powell minimizer( &f );
00387
00388
00389 vnl_vector< double > c( splines[i]->num_of_control_points(), 0 );
00390 minimizer.minimize( c );
00391 splines[i]->set_control_points( c );
00392 DebugMacro( 1, "control points:\n" << c << "\n" );
00393 }
00394 if (this->debug_flag() > 1) timer.print( vcl_cout );
00395 return new rgrl_trans_spline( splines, vnl_vector<double>(dim,0.0), delta_, global_xform_ );
00396 }
00397 else if ( optimize_method_ == RGRL_LBFGS ) {
00398 DebugMacro( 1, "LBFGS\n" );
00399 for ( unsigned i = 0; i < dim ; ++i ) {
00400 spline_cost_function f( splines[i], from_pts_in_knots, wgt, displacement.get_column( i ) );
00401 vnl_lbfgs minimizer( f );
00402
00403
00404 vnl_vector< double > c( splines[i]->num_of_control_points(), 0 );
00405 minimizer.minimize( c );
00406 splines[i]->set_control_points( c );
00407 DebugMacro( 1, "control points:\n" << c << "\n" );
00408 }
00409 if (this->debug_flag()> 1) timer.print( vcl_cout );
00410 return new rgrl_trans_spline( splines, vnl_vector<double>(dim,0.0), delta_, global_xform_ );
00411 }
00412 else {
00413
00414
00415
00416
00417
00418
00419
00420
00421 DebugMacro( 1, "No approximation\n" );
00422
00423 vnl_matrix<double> X0;
00424 vnl_matrix<double> covar;
00425
00426 if ( use_thin_plate_ ) {
00427 vnl_matrix<double> X1 = g.transpose() * wgt.asMatrix();
00428 vnl_matrix<double> X3;
00429
00430 {
00431 vnl_matrix<double> X2 = X1 * g;
00432 vnl_matrix<double> k;
00433 splines[0]->thin_plate_regularization(k);
00434 vnl_svd<double> svd( X2 + lambda_ * k );
00435 X3 = svd.inverse();
00436 }
00437 X0 = X3 * X1;
00438 covar = X0 * X1.transpose() * X3.transpose();
00439 }
00440 else {
00441 vnl_matrix<double> X1 = g.transpose() * wgt.asMatrix();
00442 vnl_matrix<double> X3;
00443
00444 {
00445 vnl_matrix<double> X2 = X1 * g;
00446 vnl_svd<double> svd( X2 );
00447 X3 = svd.inverse();
00448 }
00449 X0 = X3 * X1;
00450 covar = X0 * X1.transpose() * X3.transpose();
00451 }
00452
00453
00454 for ( unsigned j = 0; j < dim ; ++j ) {
00455 vnl_vector<double> c = displacement.get_column( j ).pre_multiply( X0 );
00456 splines[j]->set_control_points(c);
00457 }
00458 if (this->debug_flag()>1) timer.print( vcl_cout );
00459 return new rgrl_trans_spline( splines, vnl_vector<double>(dim,0.0), delta_, covar, global_xform_ );
00460 }
00461 }
00462
00463 rgrl_transformation_sptr
00464 rgrl_est_spline::
00465 estimate( rgrl_match_set_sptr matches,
00466 rgrl_transformation const& cur_transform ) const
00467 {
00468
00469 return rgrl_estimator::estimate( matches, cur_transform );
00470 }
00471
00472 const vcl_type_info&
00473 rgrl_est_spline::
00474 transformation_type() const
00475 {
00476 return rgrl_trans_spline::type_id();
00477 }