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