contrib/rpl/rrel/rrel_quad_est.cxx
Go to the documentation of this file.
00001 #include "rrel_quad_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_quad_est::
00014 rrel_quad_est( const vcl_vector< vgl_point_2d<double> > & from_pts,
00015                  const vcl_vector< vgl_point_2d<double> > & to_pts )
00016   : rrel_estimation_problem( 12, 6 /*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   dim_ = dim;
00035   quad_dof_ = (dim+1)*dim;
00036   min_num_pts_ = dim+1;
00037   num_samples_ = size;
00038 }
00039 
00040 rrel_quad_est::
00041 rrel_quad_est( const vcl_vector< vnl_vector<double> > & from_pts,
00042                  const vcl_vector< vnl_vector<double> > & to_pts,
00043                  unsigned int dim )
00044 : rrel_estimation_problem( ((dim+3)*dim/2+1)*dim /*dof*/,
00045                            ((dim+3)*dim/2+1)/*points to instantiate*/ ),
00046     from_pts_( from_pts ), to_pts_( to_pts )
00047 {
00048   // only deals with 2D for now
00049   assert( dim == 2 );
00050   assert( from_pts.size() == to_pts.size() );
00051   const unsigned size = from_pts.size();
00052 
00053   dim_ = dim;
00054   quad_dof_ = ((dim+3)*dim/2+1)*dim;
00055   min_num_pts_ = (dim+3)*dim/2+1;
00056   num_samples_ = size;
00057 }
00058 
00059 rrel_quad_est::~rrel_quad_est()
00060 {
00061 }
00062 
00063 
00064 unsigned int
00065 rrel_quad_est::num_samples( ) const
00066 {
00067   return num_samples_;
00068 }
00069 
00070 inline
00071 void expand_quad( const vnl_vector<double>& s,
00072                   vnl_vector<double>& des,
00073                   unsigned ind=0)
00074 {
00075   // 1.0
00076   des(ind++) = 1.0;
00077 
00078   // affine term
00079   for ( unsigned int i=0; i<s.size(); ++i )
00080     des(ind++) = s(i);
00081 
00082   // cross term
00083   for ( unsigned int i=0; i<s.size()-1; ++i )
00084     for ( unsigned int j=i+1; j<s.size(); ++j )
00085       des(ind++) = s(i) * s(j);
00086 
00087   // quad term
00088   for ( unsigned int i=0; i<s.size(); ++i )
00089     des(ind++) = s(i)*s(i);
00090 }
00091 
00092 inline
00093 void copy_to_nth_pos( vnl_vector<double>& des, unsigned c,
00094                       const vnl_vector<double> s )
00095 {
00096   for ( unsigned int i=0; i<s.size(); ++i )
00097     des(c+i) = s(i);
00098 }
00099 
00100 vnl_matrix<double>
00101 rrel_quad_est::
00102 A( const vnl_vector<double>& params ) const
00103 {
00104   vnl_matrix<double> A( dim_, min_num_pts_, 0.0 );
00105   for ( unsigned ind=0,i=0; i<min_num_pts_; ++i )
00106     for ( unsigned j=0; j<dim_; ++j )
00107       A(j, i) = params(ind++);  // filling it column first
00108   return A;
00109 }
00110 
00111 vnl_vector<double>
00112 rrel_quad_est::
00113 trans( const vnl_vector<double>& params ) const
00114 {
00115   vnl_vector<double> trans( dim_, 0.0 );
00116   for ( unsigned int i=0; i<dim_; ++i ) {
00117     trans[i] = params( i );
00118   }
00119   return trans;
00120 }
00121 
00122 //  The equation to be solved is A p = b, where A is a dof_ x dof_
00123 //  array formed from the independent variables and b is dof_ x 1 and
00124 //  formed from the dependent variables.  If A is not full-rank, false
00125 //  is returned.  Otherwise, params = A^{-1} b and true is returned.
00126 //
00127 bool
00128 rrel_quad_est::
00129 fit_from_minimal_set( const vcl_vector<int>& point_indices,
00130                       vnl_vector<double>& params ) const
00131 {
00132   if ( point_indices.size() != min_num_pts_ ) {
00133     vcl_cerr << "rrel_quad_est::fit_from_minimal_sample  The number of point "
00134              << "indices must agree with the fit degrees of freedom.\n";
00135     return false;
00136   }
00137 
00138   vnl_matrix<double> A( min_num_pts_,  min_num_pts_, 1.0 );
00139   vnl_matrix<double> bs( min_num_pts_, dim_, 0.0 );
00140   vnl_vector<double> expanded( min_num_pts_ );
00141   for ( unsigned int i=0; i<min_num_pts_; ++i ) {
00142     int index = point_indices[i];
00143     expand_quad( from_pts_[index], expanded );
00144     A.set_row( i, expanded );
00145 
00146     const vnl_vector<double>& one_to = to_pts_[index];
00147     for ( unsigned int j=0; j<dim_; ++j )
00148       bs[i][j] = one_to[j];
00149   }
00150 
00151   vnl_svd<double> svd( A, 1.0e-8 );
00152   if ( (unsigned int)svd.rank() < min_num_pts_ ) {
00153     return false;    // singular fit --- no error message needed
00154   }
00155   else {
00156     params.set_size( quad_dof_ );
00157     vnl_matrix<double> sol;
00158     sol = svd.inverse() * bs;
00159     for ( unsigned int j=0; j<min_num_pts_; ++j )
00160       copy_to_nth_pos( params, j*dim_, sol.get_row(j) );
00161     return true;
00162   }
00163 }
00164 
00165 
00166 void
00167 rrel_quad_est::compute_residuals( const vnl_vector<double>& params,
00168                                           vcl_vector<double>& residuals ) const
00169 {
00170   assert( residuals.size() == num_samples_ );
00171 
00172   vnl_matrix<double> A( dim_, min_num_pts_ );
00173   for ( unsigned ind=0,i=0; i<min_num_pts_; ++i )
00174     for ( unsigned j=0; j<dim_; ++j )
00175       A(j, i) = params(ind++);  // filling it column first
00176 
00177   vnl_vector<double> diff;
00178   vnl_vector<double> expanded( min_num_pts_, 0.0 );
00179   for ( unsigned int i=0; i<num_samples_; ++i ) {
00180     expand_quad( from_pts_[i], expanded );
00181     diff = A * expanded;
00182     diff -= to_pts_[i];
00183     residuals[i] = diff.two_norm();
00184   }
00185 }
00186 
00187 
00188 bool
00189 rrel_quad_est::
00190 weighted_least_squares_fit( vnl_vector<double>& params,
00191                             vnl_matrix<double>& norm_covar,
00192                             const vcl_vector<double>* weights ) const
00193 {
00194   vnl_matrix<double> sumProds(min_num_pts_, min_num_pts_, 0.0);
00195   vnl_matrix<double> sumDists(min_num_pts_, dim_, 0.0);
00196 
00197   vcl_vector<double> tmp_wgts;
00198   if ( !weights ) {
00199     // set weight to one
00200     tmp_wgts.resize( num_samples_ );
00201     vcl_fill( tmp_wgts.begin(), tmp_wgts.end(), 1.0 );
00202     weights = &tmp_wgts;
00203   }
00204   //  Aside:  this probably would be faster if I used iterators...
00205 
00206   vnl_vector<double> ind_vars( min_num_pts_, 1.0 );
00207   for ( unsigned int i=0; i<num_samples_; ++i ) {
00208     // copy first #dim# elements
00209     expand_quad( from_pts_[i], ind_vars );
00210     for ( unsigned int j=0; j<min_num_pts_; ++j ) {
00211       for ( unsigned int k=j; k<min_num_pts_; k++ )
00212         sumProds(j,k) += ind_vars[j] * ind_vars[k] * (*weights)[i];
00213 
00214       // set right hand side
00215       for ( unsigned int k=0; k<dim_; ++k )
00216         sumDists(j,k) += ind_vars[j] * to_pts_[i][k] * (*weights)[i];
00217     }
00218   }
00219 
00220   for ( unsigned int j=1; j<min_num_pts_; j++ )
00221     for ( unsigned int k=0; k<j; k++ )
00222       sumProds(j,k) = sumProds(k,j);
00223 
00224   vnl_svd<double> svd( sumProds, 1.0e-8 );
00225   if ( (unsigned int)svd.rank() < min_num_pts_ ) {
00226     vcl_cerr << "rrel_quad_est::WeightedLeastSquaresFit --- singularity!\n";
00227     return false;
00228   }
00229   else {
00230     vnl_matrix<double> sumP_inv( svd.inverse() );
00231     vnl_matrix<double> int_result = sumP_inv * sumDists;
00232     norm_covar = sumP_inv;
00233 
00234     params.set_size( quad_dof_ );
00235     for ( unsigned int j=0; j<min_num_pts_; ++j )
00236       copy_to_nth_pos( params, j*dim_, int_result.get_row(j) );
00237     return true;
00238   }
00239 }