00001
00002 #include "FMatrixCompute7Point.h"
00003
00004
00005
00006
00007
00008
00009 #include <vcl_vector.h>
00010 #include <vcl_iostream.h>
00011 #include <vcl_cmath.h>
00012
00013 #include <vnl/vnl_matrix.h>
00014 #include <vnl/vnl_math.h>
00015 #include <vnl/algo/vnl_svd.h>
00016
00017 #include <mvl/HomgMetric.h>
00018 #include <mvl/PairMatchSetCorner.h>
00019 #include <mvl/FDesignMatrix.h>
00020 #include <mvl/HomgNorm2D.h>
00021
00022 FMatrixCompute7Point::FMatrixCompute7Point(bool precondition, bool rank2_truncate)
00023 : precondition_(precondition),
00024 rank2_truncate_(rank2_truncate)
00025 {
00026 }
00027
00028
00029
00030
00031
00032
00033
00034
00035 bool FMatrixCompute7Point::compute(PairMatchSetCorner& matches, vcl_vector<FMatrix*>& F)
00036 {
00037
00038 vcl_vector<HomgPoint2D> points1(matches.count());
00039 vcl_vector<HomgPoint2D> points2(matches.count());
00040 matches.extract_matches(points1, points2);
00041 return compute(points1, points2, F);
00042 }
00043
00044
00045 bool FMatrixCompute7Point::compute (vcl_vector<vgl_homg_point_2d<double> >& points1,
00046 vcl_vector<vgl_homg_point_2d<double> >& points2,
00047 vcl_vector<FMatrix*>& F)
00048 {
00049 if (points1.size() < 7 || points2.size() < 7) {
00050 vcl_cerr << "FMatrixCompute7Point: Need at least 7 point pairs.\n"
00051 << "Number in each set: " << points1.size() << ", " << points2.size() << vcl_endl;
00052 return false;
00053 }
00054
00055 if (precondition_) {
00056
00057 HomgNorm2D conditioned1(points1);
00058 HomgNorm2D conditioned2(points2);
00059
00060
00061 if (!compute_preconditioned(conditioned1.get_normalized_points(),
00062 conditioned2.get_normalized_points(), F))
00063 return false;
00064
00065
00066 for (unsigned int i = 0; i < F.size(); i++) {
00067 FMatrix* oldF = F[i];
00068 F[i] = new FMatrix(HomgMetric::homg_to_image_F(*F[i], &conditioned1,
00069 &conditioned2));
00070 delete oldF;
00071 }
00072 }
00073 else
00074 if (!compute_preconditioned(points1, points2, F))
00075 return false;
00076
00077 return true;
00078 }
00079
00080
00081 bool FMatrixCompute7Point::compute(vcl_vector<HomgPoint2D>& points1,
00082 vcl_vector<HomgPoint2D>& points2,
00083 vcl_vector<FMatrix*>& F)
00084 {
00085 if (points1.size() < 7 || points2.size() < 7) {
00086 vcl_cerr << "FMatrixCompute7Point: Need at least 7 point pairs.\n"
00087 << "Number in each set: " << points1.size() << ", " << points2.size() << vcl_endl;
00088 return false;
00089 }
00090
00091 if (precondition_) {
00092
00093 HomgNorm2D conditioned1(points1);
00094 HomgNorm2D conditioned2(points2);
00095
00096
00097 if (!compute_preconditioned(conditioned1.get_normalized_points(),
00098 conditioned2.get_normalized_points(), F))
00099 return false;
00100
00101
00102 for (unsigned int i = 0; i < F.size(); i++) {
00103 FMatrix* oldF = F[i];
00104 F[i] = new FMatrix(HomgMetric::homg_to_image_F(*F[i], &conditioned1,
00105 &conditioned2));
00106 delete oldF;
00107 }
00108 return true;
00109 }
00110 else return compute_preconditioned(points1, points2, F);
00111 }
00112
00113
00114 bool FMatrixCompute7Point::compute_preconditioned(vcl_vector<vgl_homg_point_2d<double> >& points1,
00115 vcl_vector<vgl_homg_point_2d<double> >& points2,
00116 vcl_vector<FMatrix*>& F)
00117 {
00118
00119 FDesignMatrix design(points1, points2);
00120
00121
00122 design.normalize_rows();
00123
00124
00125 vnl_svd<double> svd(design);
00126
00127 vnl_matrix<double> W = svd.nullspace();
00128
00129
00130
00131
00132 FMatrix F1(vnl_double_3x3(W.get_column(0).data_block()));
00133 FMatrix F2(vnl_double_3x3(W.get_column(1).data_block()));
00134
00135
00136
00137 vcl_vector<double> a = FMatrixCompute7Point::GetCoef(F1, F2);
00138 vcl_vector<double> roots = FMatrixCompute7Point::solve_cubic(a);
00139
00140 if (roots.empty())
00141 return false;
00142
00143 for (unsigned int i = 0; i < roots.size(); i++) {
00144 vnl_matrix<double> F_temp =
00145 F1.get_matrix().as_ref()*roots[0] + F2.get_matrix()*(1 - roots[i]);
00146 F.push_back(new FMatrix(F_temp));
00147 }
00148
00149 if (rank2_truncate_) {
00150 for (unsigned int h = 0; h < F.size(); ++h) {
00151 F[h]->set_rank2_using_svd();
00152 }
00153 }
00154 return true;
00155 }
00156
00157
00158 bool FMatrixCompute7Point::compute_preconditioned(vcl_vector<HomgPoint2D>& points1,
00159 vcl_vector<HomgPoint2D>& points2,
00160 vcl_vector<FMatrix*>& F)
00161 {
00162
00163 FDesignMatrix design(points1, points2);
00164
00165
00166 design.normalize_rows();
00167
00168
00169 vnl_svd<double> svd(design);
00170
00171 vnl_matrix<double> W = svd.nullspace();
00172
00173
00174
00175
00176 FMatrix F1(vnl_double_3x3(W.get_column(0).data_block()));
00177 FMatrix F2(vnl_double_3x3(W.get_column(1).data_block()));
00178
00179
00180
00181 vcl_vector<double> a = FMatrixCompute7Point::GetCoef(F1, F2);
00182 vcl_vector<double> roots = FMatrixCompute7Point::solve_cubic(a);
00183
00184 for (unsigned int i = 0; i < roots.size(); i++) {
00185 vnl_matrix<double> F_temp =
00186 F1.get_matrix().as_ref()*roots[0] + F2.get_matrix()*(1 - roots[i]);
00187 F.push_back(new FMatrix(F_temp));
00188 }
00189
00190 if (rank2_truncate_) {
00191 for (unsigned int h = 0; h < F.size(); ++h) {
00192 F[h]->set_rank2_using_svd();
00193 }
00194 }
00195 return true;
00196 }
00197
00198
00199
00200
00201
00202 vcl_vector<double> FMatrixCompute7Point::GetCoef(FMatrix const& F1, FMatrix const& F2)
00203 {
00204 double a=F1.get(0,0), j=F2.get(0,0), aa=a-j,
00205 b=F1.get(0,1), k=F2.get(0,1), bb=b-k,
00206 c=F1.get(0,2), l=F2.get(0,2), cc=c-l,
00207 d=F1.get(1,0), m=F2.get(1,0), dd=d-m,
00208 e=F1.get(1,1), n=F2.get(1,1), ee=e-n,
00209 f=F1.get(1,2), o=F2.get(1,2), ff=f-o,
00210 g=F1.get(2,0), p=F2.get(2,0), gg=g-p,
00211 h=F1.get(2,1), q=F2.get(2,1), hh=h-q,
00212 i=F1.get(2,2), r=F2.get(2,2), ii=i-r;
00213
00214 double a1=ee*ii-ff*hh, b1=ee*r+ii*n-ff*q-hh*o, c1=r*n-o*q;
00215 double d1=bb*ii-cc*hh, e1=bb*r+ii*k-cc*q-hh*l, f1=r*k-l*q;
00216 double g1=bb*ff-cc*ee, h1=bb*o+ff*k-cc*n-ee*l, i1=o*k-l*n;
00217
00218 vcl_vector<double> v;
00219 v.push_back(aa*a1-dd*d1+gg*g1);
00220 v.push_back(aa*b1+a1*j-dd*e1-d1*m+gg*h1+g1*p);
00221 v.push_back(aa*c1+b1*j-dd*f1-e1*m+gg*i1+h1*p);
00222 v.push_back(c1*j-f1*m+i1*p);
00223
00224 return v;
00225 }
00226
00227
00228
00229
00230
00231
00232
00233
00234 vcl_vector<double> FMatrixCompute7Point::solve_quadratic (vcl_vector<double> v)
00235 {
00236 double a = v[1], b = v[2], c = v[3];
00237 double s = (b > 0.0) ? 1.0 : -1.0;
00238 double d = b * b - 4 * a * c;
00239
00240
00241 if ( d > -1e-5 && d < 0)
00242 d = 0.0;
00243
00244 if (d < 0.0)
00245 return vcl_vector<double>();
00246
00247 double q = -0.5 * ( b + s * vcl_sqrt(d));
00248
00249 vcl_vector<double> l; l.push_back(q/a); l.push_back(c/q);
00250 return l;
00251 }
00252
00253
00254 inline double my_cbrt(double x)
00255 {
00256 return (x>=0) ? vcl_exp(vcl_log(x)/3.0) : -vcl_exp(vcl_log(-x)/3.0);
00257 }
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269 vcl_vector<double> FMatrixCompute7Point::solve_cubic(vcl_vector<double> v)
00270 {
00271 double a = v[0], b = v[1], c = v[2], d = v[3];
00272
00273
00274 double len = a*a + b*b + c*c + d*d;
00275 if (vcl_abs(a*a/len) < 1e-6 )
00276 return FMatrixCompute7Point::solve_quadratic(v);
00277
00278 b /= a; c /= a; d /= a; b /= 3;
00279
00280 double q = b*b - c/3;
00281 double r = b*(b*b-c/2) + d/2;
00282
00283
00284 if (q == 0) {
00285 vcl_vector<double> w; w.push_back(my_cbrt(-2*r) - b); return w;
00286 }
00287
00288
00289
00290
00291 d = r*r - q*q*q;
00292 if ( d >= 0.0 )
00293 {
00294 double z = my_cbrt(-r + vcl_sqrt(d));
00295
00296 vcl_vector<double> w; w.push_back(z + q/z - b); return w;
00297 }
00298
00299
00300 c = vcl_sqrt(q);
00301 double theta = vcl_acos( r/q/c ) / 3;
00302 vcl_vector<double> l;
00303 l.push_back(-2.0*c*vcl_cos(theta) - b);
00304 l.push_back(-2.0*c*vcl_cos(theta + 2*vnl_math::pi/3) - b);
00305 l.push_back(-2.0*c*vcl_cos(theta - 2*vnl_math::pi/3) - b);
00306 return l;
00307 }