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 )
00017 {
00018 assert( from_pts.size() == to_pts.size() );
00019
00020 const unsigned dim = 2;
00021 const unsigned size = from_pts.size();
00022
00023
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 , dim+1 ),
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
00108
00109
00110
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;
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
00180 tmp_wgts.resize( num_samples_ );
00181 vcl_fill( tmp_wgts.begin(), tmp_wgts.end(), 1.0 );
00182 weights = &tmp_wgts;
00183 }
00184
00185
00186 vnl_vector<double> ind_vars( min_num_pts_, 1.0 );
00187 for ( unsigned int i=0; i<num_samples_; ++i ) {
00188
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
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 }