00001
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 , ( homog_dof / 2 ) )
00017 {
00018 assert( homog_dof%2 == 0 );
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 , ( homog_dof / 2 ) ),
00044 from_pts_( from_pts ), to_pts_( to_pts )
00045 {
00046 assert( homog_dof%2 == 0 );
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;
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>& ,
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 }