contrib/rpl/rrel/rrel_homography2d_est.cxx
Go to the documentation of this file.
00001 // This is rpl/rrel/rrel_homography2d_est.cxx
00002 #include "rrel_homography2d_est.h"
00003 
00004 #include <vgl/vgl_homg_point_2d.h>
00005 #include <vnl/vnl_vector.h>
00006 #include <vnl/vnl_math.h>
00007 #include <vnl/algo/vnl_svd.h>
00008 
00009 #include <vcl_iostream.h>
00010 #include <vcl_cassert.h>
00011 #include <vcl_cmath.h>
00012 
00013 rrel_homography2d_est :: rrel_homography2d_est( const vcl_vector< vgl_homg_point_2d<double> > & from_pts,
00014                                                 const vcl_vector< vgl_homg_point_2d<double> > & to_pts,
00015                                                 unsigned int homog_dof )
00016   : rrel_estimation_problem( homog_dof /*dof*/, ( homog_dof / 2 ) /*points to instantiate*/ )
00017 {
00018   assert( homog_dof%2 == 0 ); // Make sure DOF is even
00019   assert( from_pts.size() == to_pts.size() );
00020   vnl_vector< double > p(3), q(3);
00021 
00022   for ( unsigned int i=0; i<from_pts.size(); ++i )
00023   {
00024     p[0] = from_pts[i].x();
00025     p[1] = from_pts[i].y();
00026     p[2] = from_pts[i].w();
00027     assert( p[2] != 0 );
00028     from_pts_.push_back( p );
00029     q[0] = to_pts[i].x();
00030     q[1] = to_pts[i].y();
00031     q[2] = to_pts[i].w();
00032     assert( q[2] != 0 );
00033     to_pts_.push_back( q );
00034   }
00035 
00036   homog_dof_ = homog_dof;
00037   min_num_pts_ = homog_dof_ / 2;
00038 }
00039 
00040 rrel_homography2d_est :: rrel_homography2d_est( const vcl_vector< vnl_vector<double> > & from_pts,
00041                                                 const vcl_vector< vnl_vector<double> > & to_pts,
00042                                                 unsigned int homog_dof )
00043   : rrel_estimation_problem( homog_dof /*dof*/, ( homog_dof / 2 ) /*points to instantiate*/ ),
00044     from_pts_( from_pts ), to_pts_( to_pts )
00045 {
00046   assert( homog_dof%2 == 0 ); // Make sure DOF is even
00047   assert( from_pts_.size() == to_pts_.size() );
00048   for ( unsigned int i=0; i<from_pts_.size(); ++i ) {
00049     assert( from_pts_[ i ][ 2 ] != 0 );
00050     assert( to_pts_[ i ][ 2 ] != 0 );
00051   }
00052 
00053   homog_dof_ = homog_dof;
00054   min_num_pts_ = homog_dof_ / 2;
00055 }
00056 
00057 rrel_homography2d_est::~rrel_homography2d_est()
00058 {
00059 }
00060 
00061 
00062 unsigned int
00063 rrel_homography2d_est :: num_samples( ) const
00064 {
00065   return from_pts_.size();
00066 }
00067 
00068 
00069 bool
00070 rrel_homography2d_est :: fit_from_minimal_set( const vcl_vector<int>& point_indices,
00071                                                vnl_vector<double>& params ) const
00072 {
00073   vnl_matrix< double > A(9, 9, 0.0);
00074   assert( point_indices.size() == min_num_pts_ );
00075 
00076   for ( unsigned int i=0; i<min_num_pts_; ++i )
00077   {
00078     int loc = point_indices[ i ];
00079     A( 2*i, 0 ) = A( 2*i+1, 3 ) = from_pts_[ loc ][ 0 ] * to_pts_[ loc ][ 2 ];
00080     A( 2*i, 1 ) = A( 2*i+1, 4 ) = from_pts_[ loc ][ 1 ] * to_pts_[ loc ][ 2 ];
00081     A( 2*i, 2 ) = A( 2*i+1, 5 ) = from_pts_[ loc ][ 2 ] * to_pts_[ loc ][ 2 ];
00082     A( 2*i, 6 ) = -1 * from_pts_[ loc ][ 0 ] * to_pts_[ loc ][ 0 ];
00083     A( 2*i, 7 ) = -1 * from_pts_[ loc ][ 1 ] * to_pts_[ loc ][ 0 ];
00084     A( 2*i, 8 ) = -1 * from_pts_[ loc ][ 2 ] * to_pts_[ loc ][ 0 ];
00085     A( 2*i+1, 6 ) = -1 * from_pts_[ loc ][ 0 ] * to_pts_[ loc ][ 1 ];
00086     A( 2*i+1, 7 ) = -1 * from_pts_[ loc ][ 1 ] * to_pts_[ loc ][ 1 ];
00087     A( 2*i+1, 8 ) = -1 * from_pts_[ loc ][ 2 ] * to_pts_[ loc ][ 1 ];
00088   }
00089 
00090   vnl_svd<double> svd( A, 1.0e-8 );
00091 
00092   if ( svd.rank() < homog_dof_ ) {
00093     return false;    // singular fit
00094   }
00095   else {
00096     params = svd.nullvector();
00097     return true;
00098   }
00099 }
00100 
00101 void
00102 rrel_homography2d_est :: compute_residuals( const vnl_vector<double>& params,
00103                                             vcl_vector<double>& residuals ) const
00104 {
00105   vnl_matrix< double > H(3,3);
00106   int r,c;
00107   for ( r=0; r<3; ++r )
00108     for ( c=0; c<3; ++c )
00109       H( r, c ) = params[ 3*r + c ];
00110 
00111   vnl_svd< double > svd_H( H );
00112   if ( svd_H.rank() < 3 )
00113     vcl_cerr << "rrel_homography2d_est :: compute_residuals  rank(H) < 3!!";
00114   vnl_matrix< double > H_inv( svd_H.inverse() );
00115 
00116   if ( residuals.size() != from_pts_.size() )
00117     residuals.resize( from_pts_.size() );
00118 
00119   vnl_vector< double > trans_pt( 3 ), inv_trans_pt( 3 );
00120   double del_x, del_y, inv_del_x, inv_del_y;
00121 
00122   for ( unsigned int i=0; i<from_pts_.size(); ++i )
00123   {
00124     trans_pt = H * from_pts_[ i ];
00125     inv_trans_pt = H_inv * to_pts_[ i ];
00126 
00127     if ( from_pts_[ i ][ 2 ] == 0 || to_pts_[ i ][ 2 ] == 0
00128          || trans_pt[ 2 ] == 0 || inv_trans_pt[ 2 ] == 0 ) {
00129       residuals[ i ] = 1e10;
00130     }
00131     else {
00132       del_x = trans_pt[ 0 ] / trans_pt[ 2 ] - to_pts_[ i ][ 0 ] / to_pts_[ i ][ 2 ];
00133       del_y = trans_pt[ 1 ] / trans_pt[ 2 ] - to_pts_[ i ][ 1 ] / to_pts_[ i ][ 2 ];
00134       inv_del_x = inv_trans_pt[ 0 ] / inv_trans_pt[ 2 ] - from_pts_[ i ][ 0 ] / from_pts_[ i ][ 2 ];
00135       inv_del_y = inv_trans_pt[ 1 ] / inv_trans_pt[ 2 ] - from_pts_[ i ][ 1 ] / from_pts_[ i ][ 2 ];
00136       residuals [ i ] = vcl_sqrt( vnl_math_sqr(del_x)     + vnl_math_sqr(del_y)
00137                                 + vnl_math_sqr(inv_del_x) + vnl_math_sqr(inv_del_y) );
00138     }
00139   }
00140 }
00141 
00142 
00143 bool
00144 rrel_homography2d_est :: weighted_least_squares_fit( vnl_vector<double>& params,
00145                                                      vnl_matrix<double>& /* norm_covar */,
00146                                                      const vcl_vector<double>* weights ) const
00147 {
00148   const vcl_vector<double> * w;
00149   if ( weights )
00150     w = weights;
00151   else
00152     w = new vcl_vector<double>( from_pts_.size(), 1 );
00153 
00154   vcl_vector< vnl_vector<double> > norm_from, norm_to;
00155   vnl_matrix< double > norm_matrix_from(3,3), norm_matrix_to(3,3);
00156 
00157   this -> normalize( from_pts_, *w, norm_from, norm_matrix_from );
00158   this -> normalize( to_pts_, *w, norm_to, norm_matrix_to );
00159 
00160   vnl_matrix< double > A( 2*from_pts_.size(), 9, 0.0 );
00161   for ( unsigned int i=0; i<from_pts_.size(); ++i )
00162   {
00163     A( 2*i, 0 ) = A( 2*i+1, 3 ) = (*w)[i] * norm_from[ i ][ 0 ] * norm_to[ i ][ 2 ];
00164     A( 2*i, 1 ) = A( 2*i+1, 4 ) = (*w)[i] * norm_from[ i ][ 1 ] * norm_to[ i ][ 2 ];
00165     A( 2*i, 2 ) = A( 2*i+1, 5 ) = (*w)[i] * norm_from[ i ][ 2 ] * norm_to[ i ][ 2 ];
00166     A( 2*i, 6 ) = (*w)[i] * -1 * norm_from[ i ][ 0 ] * norm_to[ i ][ 0 ];
00167     A( 2*i, 7 ) = (*w)[i] * -1 * norm_from[ i ][ 1 ] * norm_to[ i ][ 0 ];
00168     A( 2*i, 8 ) = (*w)[i] * -1 * norm_from[ i ][ 2 ] * norm_to[ i ][ 0 ];
00169     A( 2*i+1, 6 ) = (*w)[i] * -1 * norm_from[ i ][ 0 ] * norm_to[ i ][ 1 ];
00170     A( 2*i+1, 7 ) = (*w)[i] * -1 * norm_from[ i ][ 1 ] * norm_to[ i ][ 1 ];
00171     A( 2*i+1, 8 ) = (*w)[i] * -1 * norm_from[ i ][ 2 ] * norm_to[ i ][ 1 ];
00172   }
00173 
00174   vnl_svd<double> svd( A, 1.0e-8 );
00175 
00176   bool result;
00177   if ( svd.rank() < homog_dof_ ) {
00178     result= false;
00179   }
00180   else
00181   {
00182     vnl_vector< double > nparams = svd.nullvector();
00183     vnl_matrix< double > normH( 3, 3 );
00184     params_to_homog(nparams, normH);
00185 
00186     vnl_svd<double> svd_norm_to( norm_matrix_to );
00187     assert( svd_norm_to.rank() == 3 );
00188     vnl_matrix< double > H = svd_norm_to.inverse() * normH * norm_matrix_from;
00189 
00190     params.set_size(9);
00191     homog_to_params(H, params);
00192 
00193     result = true;
00194   }
00195 
00196   if ( !weights )
00197     delete w;
00198 
00199   return result;
00200 }
00201 
00202 void
00203 rrel_homography2d_est :: homog_to_params(const vnl_matrix<double>& m,
00204                                          vnl_vector<double>&       p) const
00205 {
00206   for ( int r=0; r<3; ++r )
00207     for ( int c=0; c<3; ++c )
00208       p( 3*r + c ) = m( r, c );
00209 }
00210 
00211 void
00212 rrel_homography2d_est :: params_to_homog(const vnl_vector<double>& p,
00213                                          vnl_matrix<double>&       m) const
00214 {
00215   for ( int r=0; r<3; ++r )
00216     for ( int c=0; c<3; ++c )
00217       m( r, c ) = p( 3*r + c );
00218 }
00219 
00220 void
00221 rrel_homography2d_est :: normalize( const vcl_vector< vnl_vector<double> >& pts,
00222                                     const vcl_vector< double >& wgts,
00223                                     vcl_vector< vnl_vector<double> > & norm_pts,
00224                                     vnl_matrix< double > & norm_matrix ) const
00225 {
00226   norm_pts.resize( pts.size() );
00227   norm_matrix.set_size( 3, 3 );
00228   norm_matrix.fill( 0.0 );
00229 
00230   vnl_vector<double> center( 2, 0.0 );
00231   double sum_wgt = 0;
00232   unsigned int i;
00233 
00234   for ( i=0; i<pts.size(); ++i ) {
00235     center[0] += wgts[i] * pts[i][0] / pts[i][2];
00236     center[1] += wgts[i] * pts[i][1] / pts[i][2];
00237     sum_wgt += wgts[i];
00238   }
00239   center /= sum_wgt;
00240 
00241   double avg_distance = 0;
00242   for ( i=0; i<pts.size(); ++i ) {
00243     avg_distance += wgts[i] * vcl_sqrt( vnl_math_sqr( pts[i][0] / pts[i][2] - center[0] ) +
00244                                         vnl_math_sqr( pts[i][1] / pts[i][2] - center[1] ) );
00245   }
00246   avg_distance /= sum_wgt;
00247 
00248   norm_matrix( 0, 0 ) = 1.0 / avg_distance;
00249   norm_matrix( 0, 2 ) = -center[0] / avg_distance;
00250   norm_matrix( 1, 1 ) = 1.0 / avg_distance;
00251   norm_matrix( 1, 2 ) = -center[1] / avg_distance;
00252   norm_matrix( 2, 2 ) = 1.0;
00253 
00254   for ( i=0; i<pts.size(); ++i )
00255     norm_pts[i] = norm_matrix * pts[i];
00256 }
00257 
00258 
00259 void
00260 rrel_homography2d_est :: print_points() const
00261 {
00262 }