contrib/rpl/rgrl/rgrl_est_spline.cxx
Go to the documentation of this file.
00001 //:
00002 // \file
00003 // \author Lee, Ying-Lin (Bess)
00004 // \date   Sept 2003
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   // for Levenberg Marquardt
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,    // ( num of residuals ) x ( num of residuals )
00032                                vnl_vector<double> const& displacement, // ( num of residuals ) x 1
00033                                vcl_vector<unsigned> const& free_control_pt_index )
00034         : vnl_least_squares_function( free_control_pt_index.size(), pts.size(), use_gradient ),
00035                                 //number of unknowns, number of residuals, has gradient function or not
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     // x is the parameters
00045     void f( vnl_vector< double > const& x, vnl_vector< double > & fx )
00046     {
00047       // x is the dof-reduced parameters. Convert it back to control points
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       // check the number of residuals
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     // x is the parameters
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   // for Conjugate Gradient and other optimizers
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,    // ( num of residuals ) x ( num of residuals )
00093                           vnl_vector<double> displacement ) // ( num of residuals ) x 1
00094       : vnl_cost_function( spline->num_of_control_points() ),  //number of unknowns
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     // x is the parameters
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 } // namespace
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   // Find the number of correspondences
00197 //  vnl_vector<int> num( dim, 0 );
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       // If the point is not inside the region of interest, skip it.
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   // from points in the spline coordinates
00245   vnl_vector< double > tmp( dim, 0.0 );
00246   vcl_vector< vnl_vector< double > > from_pts_in_knots( num_match, tmp );
00247 
00248   // The index of control points that have constraints.
00249   // Used for reducing the degree of freedom
00250   vcl_vector< unsigned > free_control_pt_index;
00251   // calculate weight, displacement for each match
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         // If the point is not inside the region of interest, skip it.
00262         if ( roi_.inside( from_pt ) && fi.size() != 0 ) {
00263           // convert it into spline's coordinates
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           // see on which control points the point gives constraints
00271           for ( unsigned j=0; j<num_control; ++j ) {
00272             if ( !control_point_constraint[ j ] ) { // && gr[j]>1e-4
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     // recording which control points have constraints.
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   // Levenberg Marquardt
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       // initialization of c is important
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       // Convert x back to control points
00344 //      vnl_vector< double > c( splines[i]->num_of_control_points(), 0.0 );
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       // initialization of c is important
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       // initialization of c is important
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       // initialization of c is important
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       // initialization of c is important
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 {   //    // No approximation
00413     // Without thin-plate constraints:
00414     // Cost = (Z - G*C)^T * W * (Z - G*C)
00415     // => C = (G^T * W * G)^{-1} * G^T * W * Z
00416     // With thin-plate constraints:
00417     // Cost = (Z - G*C)^T * W * (Z - G*C) + C^T * K * C,
00418     // where K is the symmetric thin-plate regularization
00419     // => C = (G^T * W * G + \lambda * K)^{-1} * G^T * W * Z
00420     //DBG( vcl_cout << "No approximation\n" );
00421     DebugMacro( 1, "No approximation\n" );
00422 
00423     vnl_matrix<double> X0;
00424     vnl_matrix<double> covar;
00425     // get the covariance
00426     if ( use_thin_plate_ ) {
00427       vnl_matrix<double> X1 = g.transpose() * wgt.asMatrix();
00428       vnl_matrix<double> X3;
00429       // covariance = sigma^2 * (G^T * W * G + \lambda * K)^{-1} * G^T * W^2 * G * (G^T *  W * G + \lambda * K)^{-T}
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       // covariance = sigma^2 * (G^T * W * G)^{-1} * G^T * W^2 * G * (G^T *  W * G)^{-T}
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     // Calculate the parameters of splines
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   // use base class implementation
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 }