contrib/rpl/rrel/rrel_affine_est.cxx
Go to the documentation of this file.
00001 #include "rrel_affine_est.h"
00002 
00003 #include <vnl/vnl_matrix.h>
00004 #include <vnl/vnl_vector.h>
00005 #include <vnl/algo/vnl_svd.h>
00006 #include <vgl/vgl_point_2d.h>
00007 
00008 #include <vcl_iostream.h>
00009 #include <vcl_vector.h>
00010 #include <vcl_cassert.h>
00011 #include <vcl_algorithm.h>
00012 
00013 rrel_affine_est::
00014 rrel_affine_est( const vcl_vector< vgl_point_2d<double> > & from_pts,
00015                  const vcl_vector< vgl_point_2d<double> > & to_pts )
00016   : rrel_estimation_problem( 6, 3 /*points to instantiate*/ )
00017 {
00018   assert( from_pts.size() == to_pts.size() );
00019 
00020   const unsigned dim  = 2;
00021   const unsigned size = from_pts.size();
00022 
00023   // convert from vector to vnl_vector type
00024   vnl_vector<double> pt( dim );
00025   for ( unsigned int i=0; i<size; ++i ) {
00026     pt[0] = from_pts[i].x();
00027     pt[1] = from_pts[i].y();
00028     from_pts_[i] = pt;
00029     pt[0] = to_pts[i].x();
00030     pt[1] = to_pts[i].y();
00031     to_pts_[i] = pt;
00032   }
00033 
00034   affine_dof_ = (dim+1)*dim;
00035   min_num_pts_ = dim+1;
00036   num_samples_ = size;
00037 }
00038 
00039 rrel_affine_est::
00040 rrel_affine_est( const vcl_vector< vnl_vector<double> > & from_pts,
00041                  const vcl_vector< vnl_vector<double> > & to_pts,
00042                  unsigned int dim )
00043   : rrel_estimation_problem( (dim+1)*dim /*dof*/,  dim+1/*points to instantiate*/ ),
00044     from_pts_( from_pts ), to_pts_( to_pts )
00045 {
00046   assert( from_pts.size() == to_pts.size() );
00047   const unsigned size = from_pts.size();
00048 
00049   affine_dof_ = (dim+1)*dim;
00050   min_num_pts_ = dim+1;
00051   num_samples_ = size;
00052 }
00053 
00054 rrel_affine_est::~rrel_affine_est()
00055 {
00056 }
00057 
00058 
00059 unsigned int
00060 rrel_affine_est::num_samples( ) const
00061 {
00062   return num_samples_;
00063 }
00064 
00065 inline
00066 void set_row_wise( vnl_matrix<double>& des, unsigned r, unsigned c,
00067                    const vnl_vector<double>& s )
00068 {
00069   for ( unsigned int i=0; i<s.size(); ++i )
00070     des(r, c+i) = s(i);
00071 }
00072 
00073 inline
00074 void copy_to_nth_pos( vnl_vector<double>& des, unsigned c,
00075                       const vnl_vector<double> s )
00076 {
00077   for ( unsigned int i=0; i<s.size(); ++i )
00078     des(c+i) = s(i);
00079 }
00080 
00081 vnl_matrix<double>
00082 rrel_affine_est::
00083 A( const vnl_vector<double>& params ) const
00084 {
00085   vnl_matrix<double> A( min_num_pts_-1, min_num_pts_-1, 0.0 );
00086   unsigned index;
00087   for ( unsigned int i=0; i<min_num_pts_-1; ++i ) {
00088     index = i*min_num_pts_;
00089     for ( unsigned int j=0; j<min_num_pts_-1; ++j )
00090       A(i,j) = params(index+j);
00091   }
00092   return A;
00093 }
00094 
00095 vnl_vector<double>
00096 rrel_affine_est::
00097 trans( const vnl_vector<double>& params ) const
00098 {
00099   vnl_vector<double> trans( min_num_pts_-1, 0.0 );
00100   const unsigned shift = min_num_pts_-1;
00101   for ( unsigned int i=0; i<min_num_pts_-1; ++i ) {
00102     trans[i] = params( i*min_num_pts_ + shift );
00103   }
00104   return trans;
00105 }
00106 
00107 //  The equation to be solved is A p = b, where A is a dof_ x dof_
00108 //  array formed from the independent variables and b is dof_ x 1 and
00109 //  formed from the dependent variables.  If A is not full-rank, false
00110 //  is returned.  Otherwise, params = A^{-1} b and true is returned.
00111 //
00112 bool
00113 rrel_affine_est::
00114 fit_from_minimal_set( const vcl_vector<int>& point_indices,
00115                       vnl_vector<double>& params ) const
00116 {
00117   if ( point_indices.size() != min_num_pts_ ) {
00118     vcl_cerr << "rrel_affine_est::fit_from_minimal_sample  The number of point "
00119              << "indices must agree with the fit degrees of freedom.\n";
00120     return false;
00121   }
00122 
00123   vnl_matrix<double> A( min_num_pts_,  min_num_pts_, 1.0 );
00124   vnl_matrix<double> bs( min_num_pts_, min_num_pts_-1, 0.0 );
00125   for ( unsigned int i=0; i<min_num_pts_; ++i ) {
00126     int index = point_indices[i];
00127     set_row_wise( A, i, 0, from_pts_[index] );
00128 
00129     const vnl_vector<double>& one_to = to_pts_[index];
00130     for ( unsigned int j=0; j<min_num_pts_-1; ++j )
00131       bs[i][j] = one_to[j];
00132   }
00133 
00134   vnl_svd<double> svd( A, 1.0e-8 );
00135   if ( (unsigned int)svd.rank() < min_num_pts_ ) {
00136     return false;    // singular fit --- no error message needed
00137   }
00138   else {
00139     params.set_size( affine_dof_ );
00140     vnl_matrix<double> sol;
00141     sol = svd.inverse() * bs;
00142     for ( unsigned int j=0; j<min_num_pts_-1; ++j )
00143       copy_to_nth_pos( params, j*min_num_pts_, sol.get_column(j) );
00144     return true;
00145   }
00146 }
00147 
00148 
00149 void
00150 rrel_affine_est::compute_residuals( const vnl_vector<double>& params,
00151                                           vcl_vector<double>& residuals ) const
00152 {
00153   assert( residuals.size() == num_samples_ );
00154 
00155   const vnl_matrix<double> A=this->A( params );
00156   const vnl_vector<double> t=trans( params );
00157 
00158   vnl_vector<double> diff;
00159   for ( unsigned int i=0; i<num_samples_; ++i ) {
00160     diff = A*from_pts_[i];
00161     diff += t;
00162     diff -= to_pts_[i];
00163     residuals[i] = diff.two_norm();
00164   }
00165 }
00166 
00167 
00168 bool
00169 rrel_affine_est::
00170 weighted_least_squares_fit( vnl_vector<double>& params,
00171                             vnl_matrix<double>& norm_covar,
00172                             const vcl_vector<double>* weights ) const
00173 {
00174   vnl_matrix<double> sumProds(min_num_pts_, min_num_pts_, 0.0);
00175   vnl_matrix<double> sumDists(min_num_pts_, min_num_pts_-1, 0.0);
00176 
00177   vcl_vector<double> tmp_wgts;
00178   if ( !weights ) {
00179     // set weight to one
00180     tmp_wgts.resize( num_samples_ );
00181     vcl_fill( tmp_wgts.begin(), tmp_wgts.end(), 1.0 );
00182     weights = &tmp_wgts;
00183   }
00184   //  Aside:  this probably would be faster if I used iterators...
00185 
00186   vnl_vector<double> ind_vars( min_num_pts_, 1.0 );
00187   for ( unsigned int i=0; i<num_samples_; ++i ) {
00188     // copy first #dim# elements
00189     copy_to_nth_pos( ind_vars, 0, from_pts_[i] );
00190     for ( unsigned int j=0; j<min_num_pts_; ++j ) {
00191       for ( unsigned int k=j; k<min_num_pts_; k++ )
00192         sumProds(j,k) += ind_vars[j] * ind_vars[k] * (*weights)[i];
00193 
00194       // set right hand side
00195       for ( unsigned int k=0; k<min_num_pts_-1; ++k )
00196         sumDists(j,k) += ind_vars[j] * to_pts_[i][k] * (*weights)[i];
00197     }
00198   }
00199 
00200   for ( unsigned int j=1; j<min_num_pts_; j++ )
00201     for ( unsigned int k=0; k<j; k++ )
00202       sumProds(j,k) = sumProds(k,j);
00203 
00204   vnl_svd<double> svd( sumProds, 1.0e-8 );
00205   if ( (unsigned int)svd.rank() < min_num_pts_ ) {
00206     vcl_cerr << "rrel_affine_est::WeightedLeastSquaresFit --- singularity!\n";
00207     return false;
00208   }
00209   else {
00210     vnl_matrix<double> sumP_inv( svd.inverse() );
00211     vnl_matrix<double> int_result = sumP_inv * sumDists;
00212     norm_covar = sumP_inv;
00213 
00214     params.set_size( affine_dof_ );
00215     for ( unsigned int j=0; j<min_num_pts_-1; ++j )
00216       copy_to_nth_pos( params, j*min_num_pts_, int_result.get_column(j) );
00217     return true;
00218   }
00219 }