00001 #include "rgrl_est_homography2d.h"
00002
00003 #include "rgrl_trans_homography2d.h"
00004 #include "rgrl_match_set.h"
00005
00006 #include <vnl/algo/vnl_svd.h>
00007 #include <vnl/vnl_math.h>
00008 #include <vnl/vnl_double_3x3.h>
00009 #include <vnl/vnl_det.h>
00010
00011
00012 rgrl_est_homography2d::
00013 rgrl_est_homography2d( double condition_num_thrd )
00014 : condition_num_thrd_( condition_num_thrd )
00015 {
00016 rgrl_estimator::set_param_dof( 8 );
00017 }
00018
00019 rgrl_transformation_sptr
00020 rgrl_est_homography2d::
00021 estimate( rgrl_set_of<rgrl_match_set_sptr> const& matches,
00022 rgrl_transformation const& ) const
00023 {
00024
00025
00026
00027
00028 vcl_vector< vnl_vector<double> > norm_from_pts, norm_to_pts;
00029 vcl_vector< double > wgts;
00030 double from_scale, to_scale;
00031 vnl_vector<double> from_center(2), to_center(2);
00032 if ( !normalize( matches, norm_from_pts, norm_to_pts, wgts, from_scale, to_scale,
00033 from_center, to_center ) )
00034 return 0;
00035
00036 vnl_matrix< double > A( 2*norm_from_pts.size(), 9, 0.0 );
00037 for ( unsigned int i=0; i<norm_from_pts.size(); ++i ) {
00038 A( 2*i, 0 ) = A( 2*i+1, 3 ) = wgts[i] * norm_from_pts[i][0] * norm_to_pts[i][2];
00039 A( 2*i, 1 ) = A( 2*i+1, 4 ) = wgts[i] * norm_from_pts[i][1] * norm_to_pts[i][2];
00040 A( 2*i, 2 ) = A( 2*i+1, 5 ) = wgts[i] * norm_from_pts[i][2] * norm_to_pts[i][2];
00041 A( 2*i, 6 ) = wgts[i] * -1 * norm_from_pts[i][0] * norm_to_pts[i][0];
00042 A( 2*i, 7 ) = wgts[i] * -1 * norm_from_pts[i][1] * norm_to_pts[i][0];
00043 A( 2*i, 8 ) = wgts[i] * -1 * norm_from_pts[i][2] * norm_to_pts[i][0];
00044 A( 2*i+1, 6 ) = wgts[i] * -1 * norm_from_pts[i][0] * norm_to_pts[i][1];
00045 A( 2*i+1, 7 ) = wgts[i] * -1 * norm_from_pts[i][1] * norm_to_pts[i][1];
00046 A( 2*i+1, 8 ) = wgts[i] * -1 * norm_from_pts[i][2] * norm_to_pts[i][1];
00047 }
00048 vnl_svd<double> svd( A, 1.0e-8 );
00049
00050 if ( svd.rank() < 8 ) {
00051 DebugMacro(1, "rank ("<<svd.rank()<<") no solution." );
00052 return 0;
00053 }
00054 else {
00055 vnl_vector< double > nparams = svd.nullvector();
00056 vnl_matrix< double > normH( 3, 3 );
00057 for ( int r=0; r<3; ++r )
00058 for ( int c=0; c<3; ++c )
00059 normH( r, c ) = nparams( 3*r + c );
00060
00061
00062 vnl_double_3x3 tmpH(normH);
00063 if ( vcl_abs(vnl_det(tmpH)) < 1e-8 )
00064 return 0;
00065
00066 vnl_matrix<double> to_scale_matrix_inv(3,3,vnl_matrix_identity);
00067 vnl_matrix<double> from_scale_matrix(3,3,vnl_matrix_identity);
00068 to_scale_matrix_inv(0,0) = 1/to_scale;
00069 to_scale_matrix_inv(1,1) = 1/to_scale;
00070 from_scale_matrix(0,0) = from_scale;
00071 from_scale_matrix(1,1) = from_scale;
00072
00073
00074
00075
00076 vnl_matrix< double > H = to_scale_matrix_inv * normH * from_scale_matrix;
00077 vnl_matrix<double> covar(9,9,0.0);
00078 estimate_covariance( norm_from_pts, norm_to_pts, wgts,
00079 from_scale, to_scale, covar);
00080
00081 return new rgrl_trans_homography2d( H, covar, from_center, to_center );
00082 }
00083 }
00084
00085
00086 rgrl_transformation_sptr
00087 rgrl_est_homography2d::
00088 estimate( rgrl_match_set_sptr matches,
00089 rgrl_transformation const& cur_transform ) const
00090 {
00091
00092 return rgrl_estimator::estimate( matches, cur_transform );
00093 }
00094
00095 const vcl_type_info&
00096 rgrl_est_homography2d::
00097 transformation_type() const
00098 {
00099 return rgrl_trans_homography2d::type_id();
00100 }
00101
00102 bool
00103 rgrl_est_homography2d::
00104 normalize( rgrl_set_of<rgrl_match_set_sptr> const& matches,
00105 vcl_vector< vnl_vector<double> >& norm_froms,
00106 vcl_vector< vnl_vector<double> >& norm_tos,
00107 vcl_vector< double >& wgts,
00108 double& from_scale,
00109 double& to_scale,
00110 vnl_vector< double > & from_center,
00111 vnl_vector< double > & to_center ) const
00112 {
00113
00114
00115 typedef rgrl_match_set::const_from_iterator FIter;
00116 typedef FIter::to_iterator TIter;
00117
00118 vnl_matrix<double> from_norm_matrix(3,3,0.0);
00119 vnl_matrix<double> to_norm_matrix(3,3,0.0);
00120 norm_froms.reserve( matches[0]->from_size() );
00121
00122
00123
00124 from_center.fill( 0.0 );
00125 to_center.fill( 0.0 );
00126 vnl_vector<double> from_pt( 2 );
00127 vnl_vector<double> to_pt( 2 );
00128 double sum_wgt = 0;
00129
00130 for ( unsigned ms=0; ms < matches.size(); ++ms ) {
00131 rgrl_match_set const& match_set = *matches[ms];
00132 for ( FIter fi = match_set.from_begin(); fi != match_set.from_end(); ++fi ){
00133 for ( TIter ti = fi.begin(); ti != fi.end(); ++ti ) {
00134 double const wgt = ti.cumulative_weight();
00135 from_pt = fi.from_feature()->location();
00136 from_center += from_pt * wgt;
00137 to_pt = ti.to_feature()->location();
00138 to_center += to_pt * wgt;
00139 sum_wgt += wgt;
00140 }
00141 }
00142 }
00143
00144
00145 if ( sum_wgt < 1e-13 ) {
00146 return false;
00147 }
00148
00149 from_center /= sum_wgt;
00150 to_center /= sum_wgt;
00151
00152
00153
00154 double from_avg_distance = 0;
00155 double to_avg_distance = 0;
00156 for ( unsigned ms=0; ms < matches.size(); ++ms ) {
00157 rgrl_match_set const& match_set = *matches[ms];
00158 for ( FIter fi = match_set.from_begin(); fi != match_set.from_end(); ++fi ){
00159 for ( TIter ti = fi.begin(); ti != fi.end(); ++ti ) {
00160 double const wgt = ti.cumulative_weight();
00161 from_pt = fi.from_feature()->location();
00162 from_avg_distance +=
00163 wgt * vcl_sqrt( vnl_math_sqr( from_pt[0] - from_center[0] ) +
00164 vnl_math_sqr( from_pt[1] - from_center[1] ) );
00165 to_pt = ti.to_feature()->location();
00166 to_avg_distance +=
00167 wgt * vcl_sqrt( vnl_math_sqr( to_pt[0] - to_center[0] ) +
00168 vnl_math_sqr( to_pt[1] - to_center[1] ) );
00169 }
00170 }
00171 }
00172 from_avg_distance /= sum_wgt;
00173 to_avg_distance /= sum_wgt;
00174
00175
00176
00177 from_norm_matrix( 0, 0 ) = 1.0 / from_avg_distance;
00178 from_norm_matrix( 0, 2 ) = -from_center[0] / from_avg_distance;
00179 from_norm_matrix( 1, 1 ) = 1.0 / from_avg_distance;
00180 from_norm_matrix( 1, 2 ) = -from_center[1] / from_avg_distance;
00181 from_norm_matrix( 2, 2 ) = 1.0;
00182 from_scale = 1.0 / from_avg_distance;
00183
00184
00185
00186 to_norm_matrix( 0, 0 ) = 1.0 / to_avg_distance;
00187 to_norm_matrix( 0, 2 ) = -to_center[0] / to_avg_distance;
00188 to_norm_matrix( 1, 1 ) = 1.0 / to_avg_distance;
00189 to_norm_matrix( 1, 2 ) = -to_center[1] / to_avg_distance;
00190 to_norm_matrix( 2, 2 ) = 1.0;
00191 to_scale = 1.0 / to_avg_distance;
00192
00193
00194 vnl_vector<double> norm_from_pt(3,1.0);
00195 vnl_vector<double> norm_to_pt(3,1.0);
00196 for ( unsigned ms=0; ms < matches.size(); ++ms ) {
00197 rgrl_match_set const& match_set = *matches[ms];
00198 for ( FIter fi = match_set.from_begin(); fi != match_set.from_end(); ++fi ){
00199 norm_from_pt[0] = fi.from_feature()->location()[0];
00200 norm_from_pt[1] = fi.from_feature()->location()[1];
00201 for ( TIter ti = fi.begin(); ti != fi.end(); ++ti ) {
00202 norm_to_pt[0] = ti.to_feature()->location()[0];
00203 norm_to_pt[1] = ti.to_feature()->location()[1];
00204 norm_froms.push_back( from_norm_matrix * norm_from_pt );
00205 norm_tos.push_back( to_norm_matrix * norm_to_pt );
00206 wgts.push_back( ti.cumulative_weight() );
00207 }
00208 }
00209 }
00210
00211 return true;
00212 }
00213
00214 void
00215 rgrl_est_homography2d::
00216 estimate_covariance( const vcl_vector< vnl_vector<double> >& norm_froms,
00217 const vcl_vector< vnl_vector<double> >& norm_tos,
00218 const vcl_vector< double >& wgts,
00219 double from_scale,
00220 double to_scale,
00221 vnl_matrix<double>& covar ) const
00222 {
00223 vnl_matrix<double> JTJ(9,9, 0.0);
00224 vnl_matrix<double> J(2,9, 0.0);
00225
00226 for (unsigned int i = 0; i<norm_froms.size(); i++) {
00227 J(0,0) = J(1,3) = norm_froms[i][0];
00228 J(0,1) = J(1,4) = norm_froms[i][1];
00229 J(0,2) = J(1,5) = norm_froms[i][2];
00230
00231 J(0,6) = -norm_tos[i][0]*norm_froms[i][0];
00232 J(0,7) = -norm_tos[i][0]*norm_froms[i][1];
00233 J(0,8) = -norm_tos[i][0]*norm_froms[i][2];
00234
00235 J(1,6) = -norm_tos[i][1]*norm_froms[i][0];
00236 J(1,7) = -norm_tos[i][1]*norm_froms[i][1];
00237 J(1,8) = -norm_tos[i][1]*norm_froms[i][2];
00238
00239 JTJ += wgts[i]*J.transpose()*J;
00240 }
00241
00242 vnl_svd<double> svd( J, 1.0e-8 );
00243 covar = svd.inverse();
00244
00245
00246
00247 }