00001
00002 #ifndef vpgl_fm_compute_7_point_cxx_
00003 #define vpgl_fm_compute_7_point_cxx_
00004
00005
00006
00007 #include "vpgl_fm_compute_7_point.h"
00008
00009 #include <vnl/vnl_fwd.h>
00010 #include <vnl/vnl_math.h>
00011 #include <vgl/algo/vgl_norm_trans_2d.h>
00012 #include <vcl_iostream.h>
00013
00014
00015 bool
00016 vpgl_fm_compute_7_point::compute(
00017 const vcl_vector< vgl_homg_point_2d<double> >& pr,
00018 const vcl_vector< vgl_homg_point_2d<double> >& pl,
00019 vcl_vector< vpgl_fundamental_matrix<double>* >& fm )
00020 {
00021
00022 if ( pr.size() < 7 || pl.size() < 7 ) {
00023 vcl_cerr << "vpgl_fm_compute_7_point: Need at least 7 point pairs.\n"
00024 << "Number in each set: " << pr.size() << ", " << pl.size() << vcl_endl;
00025 return false;
00026 }
00027
00028
00029 if ( pr.size() != pl.size() ) {
00030 vcl_cerr << "vpgl_fm_compute_7_point: Need correspondence lists of same size.\n";
00031 return false;
00032 }
00033
00034
00035 vcl_vector< vgl_homg_point_2d<double> > pr_norm, pl_norm;
00036 vgl_norm_trans_2d<double> prnt, plnt;
00037 if ( precondition_ ) {
00038 prnt.compute_from_points(pr);
00039 plnt.compute_from_points(pl);
00040 for ( unsigned i = 0; i < pl.size(); i++ ) {
00041 pr_norm.push_back( prnt*pr[i] );
00042 pl_norm.push_back( plnt*pl[i] );
00043 }
00044 }
00045 else {
00046 for ( unsigned i = 0; i < pl.size(); i++ ) {
00047 pr_norm.push_back( pr[i] );
00048 pl_norm.push_back( pl[i] );
00049 }
00050 }
00051
00052
00053 vnl_matrix<double> design_matrix(pr_norm.size(),9);
00054 for ( unsigned r = 0; r < pr_norm.size(); r++ ) {
00055 design_matrix(r,0) = pr_norm[r].x()*pl_norm[r].x();
00056 design_matrix(r,1) = pr_norm[r].y()*pl_norm[r].x();
00057 design_matrix(r,2) = pr_norm[r].w()*pl_norm[r].x();
00058 design_matrix(r,3) = pr_norm[r].x()*pl_norm[r].y();
00059 design_matrix(r,4) = pr_norm[r].y()*pl_norm[r].y();
00060 design_matrix(r,5) = pr_norm[r].w()*pl_norm[r].y();
00061 design_matrix(r,6) = pr_norm[r].x()*pl_norm[r].w();
00062 design_matrix(r,7) = pr_norm[r].y()*pl_norm[r].w();
00063 design_matrix(r,8) = pr_norm[r].w()*pl_norm[r].w();
00064 }
00065
00066 design_matrix.normalize_rows();
00067 vnl_svd<double> design_svd( design_matrix );
00068 vnl_matrix<double> W = design_svd.nullspace();
00069
00070
00071
00072
00073
00074 vnl_double_3x3 F1(W.get_column(0).data_block());
00075 vnl_double_3x3 F2(W.get_column(1).data_block());
00076
00077
00078
00079 vcl_vector<double> a = get_coeffs(F1, F2);
00080 vcl_vector<double> roots = solve_cubic(a);
00081 for (unsigned int i = 0; i < roots.size(); i++) {
00082 vpgl_fundamental_matrix<double> F_temp( F1.as_ref()*roots[0] + F2*(1 - roots[i]) );
00083 if ( precondition_ )
00084 F_temp.set_matrix( plnt.get_matrix().transpose()*F_temp.get_matrix()*prnt.get_matrix() );
00085 fm.push_back( new vpgl_fundamental_matrix<double>(F_temp) );
00086 }
00087 return true;
00088 };
00089
00090
00091
00092 vcl_vector<double>
00093 vpgl_fm_compute_7_point::get_coeffs( vnl_double_3x3 const& F1,
00094 vnl_double_3x3 const& F2 )
00095 {
00096
00097 double a=F1(0,0), j=F2(0,0), aa=a-j,
00098 b=F1(0,1), k=F2(0,1), bb=b-k,
00099 c=F1(0,2), l=F2(0,2), cc=c-l,
00100 d=F1(1,0), m=F2(1,0), dd=d-m,
00101 e=F1(1,1), n=F2(1,1), ee=e-n,
00102 f=F1(1,2), o=F2(1,2), ff=f-o,
00103 g=F1(2,0), p=F2(2,0), gg=g-p,
00104 h=F1(2,1), q=F2(2,1), hh=h-q,
00105 i=F1(2,2), r=F2(2,2), ii=i-r;
00106
00107 double a1=ee*ii-ff*hh, b1=ee*r+ii*n-ff*q-hh*o, c1=r*n-o*q;
00108 double d1=bb*ii-cc*hh, e1=bb*r+ii*k-cc*q-hh*l, f1=r*k-l*q;
00109 double g1=bb*ff-cc*ee, h1=bb*o+ff*k-cc*n-ee*l, i1=o*k-l*n;
00110
00111 vcl_vector<double> v;
00112 v.push_back(aa*a1-dd*d1+gg*g1);
00113 v.push_back(aa*b1+a1*j-dd*e1-d1*m+gg*h1+g1*p);
00114 v.push_back(aa*c1+b1*j-dd*f1-e1*m+gg*i1+h1*p);
00115 v.push_back(c1*j-f1*m+i1*p);
00116
00117 return v;
00118 };
00119
00120
00121
00122 vcl_vector<double>
00123 vpgl_fm_compute_7_point::solve_quadratic( vcl_vector<double> v )
00124 {
00125 double a = v[1], b = v[2], c = v[3];
00126 double s = (b > 0.0) ? 1.0 : -1.0;
00127 double d = b * b - 4 * a * c;
00128
00129
00130 if ( d > -1e-5 && d < 0)
00131 d = 0.0;
00132
00133 if (d < 0.0)
00134 return vcl_vector<double>();
00135
00136 double q = -0.5 * ( b + s * vcl_sqrt(d));
00137 vcl_vector<double> l; l.push_back(q/a); l.push_back(c/q);
00138 return l;
00139 };
00140
00141
00142
00143 vcl_vector<double>
00144 vpgl_fm_compute_7_point::solve_cubic( vcl_vector<double> v )
00145 {
00146 double a = v[0], b = v[1], c = v[2], d = v[3];
00147
00148
00149 double len = a*a + b*b + c*c + d*d;
00150 if (vcl_abs(a*a/len) < 1e-6 )
00151 return solve_quadratic(v);
00152
00153 b /= a; c /= a; d /= a; b /= 3;
00154
00155 double q = b*b - c/3;
00156 double r = b*(b*b-c/2) + d/2;
00157
00158
00159 if (q == 0) {
00160 vcl_vector<double> w;
00161 double cbrt = (r<0) ? vcl_exp(vcl_log(-2*r)/3.0) : -vcl_exp(vcl_log(2*r)/3.0);
00162 w.push_back(cbrt - b);
00163 return w;
00164 }
00165
00166
00167
00168
00169 d = r*r - q*q*q;
00170 if ( d >= 0.0 ) {
00171
00172 double z;
00173 if ( -r + vcl_sqrt(d) >= 0 ) z = vcl_exp(vcl_log(-r + vcl_sqrt(d))/3.0);
00174 else z = -vcl_exp(vcl_log(-r + vcl_sqrt(d))/3.0);
00175
00176
00177 vcl_vector<double> w; w.push_back(z + q/z - b); return w;
00178 }
00179
00180
00181 c = vcl_sqrt(q);
00182 double theta = vcl_acos( r/q/c ) / 3;
00183 vcl_vector<double> l;
00184 l.push_back(-2.0*c*vcl_cos(theta) - b);
00185 l.push_back(-2.0*c*vcl_cos(theta + 2*vnl_math::pi/3) - b);
00186 l.push_back(-2.0*c*vcl_cos(theta - 2*vnl_math::pi/3) - b);
00187 return l;
00188 };
00189
00190
00191 #endif // vpgl_fm_compute_7_point_cxx_