00001
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005
00006
00007
00008 #include "FManifoldProject.h"
00009
00010 #include <vnl/vnl_double_2x2.h>
00011 #include <vnl/vnl_double_4.h>
00012 #include <vnl/algo/vnl_symmetric_eigensystem.h>
00013 #include <vnl/algo/vnl_rpoly_roots.h>
00014 #include <vnl/vnl_real_polynomial.h>
00015 #include <vnl/algo/vnl_svd.h>
00016 #include <vnl/vnl_diag_matrix.h>
00017 #include <vnl/vnl_math.h>
00018 #include <vgl/vgl_homg_point_2d.h>
00019
00020 #include <mvl/HomgPoint2D.h>
00021 #include <mvl/FMatrix.h>
00022 #include <mvl/HomgOperator2D.h>
00023
00024 #include <vcl_iostream.h>
00025
00026
00027 FManifoldProject::FManifoldProject(const FMatrix& Fobj)
00028 {
00029 set_F(Fobj);
00030 }
00031
00032
00033 FManifoldProject::FManifoldProject() {}
00034
00035
00036 void FManifoldProject::set_F(const FMatrix& Fobj)
00037 {
00038 F_ = Fobj.get_matrix();
00039
00040 F_.assert_finite();
00041
00042
00043 vnl_double_2x2 f22 = F_.extract(2,2);
00044
00045
00046 A_.fill(0.0);
00047 A_.update(0.5*f22.transpose().as_ref(), 0, 2);
00048 A_.update(0.5*f22.as_ref(), 2, 0);
00049
00050 vnl_double_4 b(F_(2,0), F_(2,1), F_(0,2), F_(1,2));
00051
00052 double c = F_(2,2);
00053
00054
00055 vnl_symmetric_eigensystem<double> eig(A_.as_ref());
00056
00057 #ifdef DEBUG
00058 vcl_cerr << vnl_svd<double>(F_);
00059 MATLABPRINT(F_);
00060 MATLABPRINT(eig.D);
00061 #endif // DEBUG
00062
00063
00064 affine_F_ = eig.D(3,3) < 1e-6;
00065 if (affine_F_) {
00066 #ifdef DEBUG
00067 vcl_cerr << "FManifoldProject: Affine F = " << F_ << vcl_endl;
00068 #endif // DEBUG
00069 double s = 1.0 / b.magnitude();
00070 t_ = b * s;
00071 d_[0] = c * s;
00072 }
00073 else {
00074
00075 t_ = -0.5 * eig.solve(b.as_ref());
00076
00077 vnl_double_4 At = A_*t_;
00078 vnl_double_4 Bprime = 2.0*At + b;
00079 double tAt = dot_product(t_, At);
00080 double Cprime = tAt + dot_product(t_, b) + c;
00081
00082
00083 if (vnl_math_abs(Cprime) > 1e-6) {
00084 vcl_cerr << "FManifoldProject: ** HartleySturm: F = " << F_ << vcl_endl
00085 << "FManifoldProject: ** HartleySturm: B = " << Bprime << vcl_endl
00086 << "FManifoldProject: ** HartleySturm: Cerror = " << Cprime << vcl_endl
00087 << "FManifoldProject: ** HartleySturm: F not rank 2 ?\n"
00088 << "FManifoldProject: singular values are " << vnl_svd<double>(F_.as_ref()).W() << vcl_endl;
00089 }
00090
00091
00092
00093
00094
00095
00096 {
00097 int I[] = { 0, 3, 1, 2 };
00098 for (int col = 0; col < 4; ++col) {
00099 int from_col = I[col];
00100 d_[col] = eig.D(from_col,from_col);
00101 for (int r=0;r<4;++r)
00102 V_(r,col) = eig.V(r, from_col);
00103 }
00104 }
00105 }
00106 }
00107
00108
00109
00110 double FManifoldProject::correct(vgl_homg_point_2d<double> const& p1,
00111 vgl_homg_point_2d<double> const& p2,
00112 vgl_homg_point_2d<double>& out1,
00113 vgl_homg_point_2d<double>& out2) const
00114 {
00115 if (p1.w()==0 || p2.w()==0) {
00116 vcl_cerr << "FManifoldProject: p1 or p2 at infinity\n";
00117 out1 = p1; out2 = p2; return 1e33;
00118 }
00119
00120 double p_out[4];
00121 double d = correct(p1.x()/p1.w(), p1.y()/p1.w(), p2.x()/p2.w(), p2.y()/p2.w(),
00122 p_out, p_out+1, p_out+2, p_out+3);
00123
00124 out1.set(p_out[0], p_out[1], 1.0);
00125 out2.set(p_out[2], p_out[3], 1.0);
00126 return d;
00127 }
00128
00129
00130
00131 double FManifoldProject::correct(const HomgPoint2D& p1, const HomgPoint2D& p2, HomgPoint2D* out1, HomgPoint2D* out2) const
00132 {
00133 double p[4];
00134 if (!p1.get_nonhomogeneous(p[0], p[1]) ||
00135 !p2.get_nonhomogeneous(p[2], p[3])) {
00136 vcl_cerr << "FManifoldProject: p1 or p2 at infinity\n";
00137 *out1 = p1;
00138 *out2 = p2;
00139 return 1e30;
00140 }
00141
00142 double p_out[4];
00143 double d = correct(p[0], p[1], p[2], p[3], &p_out[0], &p_out[1], &p_out[2], &p_out[3]);
00144
00145 out1->set(p_out[0], p_out[1], 1.0);
00146 out2->set(p_out[2], p_out[3], 1.0);
00147 return d;
00148 }
00149
00150
00151
00152 double FManifoldProject::correct(double x1, double y1, double x2, double y2,
00153 double *ox1, double *oy1, double *ox2, double *oy2) const
00154 {
00155
00156 vnl_double_4 p;
00157 p[0] = x1;
00158 p[1] = y1;
00159 p[2] = x2;
00160 p[3] = y2;
00161
00162 if (affine_F_) {
00163
00164
00165
00166
00167 const vnl_double_4& n = t_;
00168 double d = d_[0];
00169
00170 double distance = (dot_product(n, p) + d);
00171 *ox1 = p[0];
00172 *oy1 = p[1];
00173 *ox2 = p[2];
00174 *oy2 = p[3];
00175
00176 vnl_double_3 l = F_ * vnl_double_3(p[2], p[3], 1.0);
00177 double EPIDIST = (l[0] * p[0] + l[1] * p[1] + l[2])/vcl_sqrt(l[0]*l[0]+l[1]*l[1]);
00178 if (EPIDIST > 1e-4) {
00179 vcl_cerr << "FManifoldProject: Affine F: EPIDIST = " << EPIDIST << vcl_endl
00180 << "FManifoldProject: Affine F: p = " << (dot_product(p,n) + d) << vcl_endl;
00181 #if 0
00182 double EPI1 = dot_product(out2->get_vector(), F_*out1->get_vector());
00183 double EPI2 = dot_product(p, n) + d;
00184 vcl_cerr << "t = " << n << ' ' << d << vcl_endl
00185 << "F_ = " << F_ << vcl_endl
00186 << "FManifoldProject: Affine F: E = " << (EPI1 - EPI2) << vcl_endl;
00187 vcl_abort();
00188 #endif // 0
00189 }
00190
00191 return distance * distance;
00192 }
00193
00194
00195 vnl_double_4 pprime = V_.transpose() * (p - t_);
00196
00197
00198 double b1 = 1./d_[0]; double a1 = vnl_math_sqr(pprime[0])*b1;
00199 double b2 = 1./d_[1]; double a2 = vnl_math_sqr(pprime[1])*b2;
00200 double b3 = 1./d_[2]; double a3 = vnl_math_sqr(pprime[2])*b3;
00201 double b4 = 1./d_[3]; double a4 = vnl_math_sqr(pprime[3])*b4;
00202
00203 if (vnl_math_max(vnl_math_abs(b1 + b2), vnl_math_abs(b3 + b4)) > 1e-7) {
00204 vcl_cerr << "FManifoldProject: B = [" <<b1<< ' ' <<b2<< ' ' <<b3<< ' ' <<b4<< "];\n"
00205 << "FManifoldProject: b1 != -b2 or b3 != -b4\n";
00206 }
00207
00208
00209
00210
00211
00212
00213 static vnl_vector<double> coeffs_(7);
00214 double b12 = b1*b1;
00215 double b32 = b3*b3;
00216 double b14 = b12*b12;
00217 double b34 = b32*b32;
00218
00219 coeffs_[6] = a3*b14*b32 + a4*b14*b32 + a1*b12*b34 + a2*b12*b34;
00220 coeffs_[5] = (2*a3*b14*b3 - 2*a4*b14*b3 + 2*a1*b1*b34 - 2*a2*b1*b34);
00221 coeffs_[4] = (a3*b14 + a4*b14 - 2*(a1 +a2 + a3 + a4)*b12*b32 + a1*b34 + a2*b34);
00222 coeffs_[3] = (-4*a3*b12*b3 + 4*a4*b12*b3 - 4*a1*b1*b32 + 4*a2*b1*b32);
00223 coeffs_[2] = (a1*b12 + a2*b12 - 2*a3*b12 - 2*a4*b12 - 2*a1*b32 - 2*a2*b32 + a3*b32 + a4*b32);
00224 coeffs_[1] = 2*(b3*(a3 - a4) + b1*(a1 - a2));
00225 coeffs_[0] = (a1 + a2 + a3 + a4);
00226
00227
00228 coeffs_ /= coeffs_.magnitude();
00229
00230 vnl_real_polynomial poly(coeffs_);
00231 vnl_rpoly_roots roots(coeffs_);
00232 double dmin = 1e30;
00233 vnl_double_4 Xmin;
00234 vnl_vector<double> realroots = roots.realroots(1e-8);
00235 int errs = 0;
00236 bool got_one = false;
00237 for (unsigned i = 0; i < realroots.size(); ++i) {
00238 double lambda = realroots[i];
00239
00240
00241 double RATPOLY_RESIDUAL = (a1/vnl_math_sqr(b1 - lambda) +
00242 a2/vnl_math_sqr(b2 - lambda) +
00243 a3/vnl_math_sqr(b3 - lambda) +
00244 a4/vnl_math_sqr(b4 - lambda));
00245
00246 if (vcl_fabs(RATPOLY_RESIDUAL) > 1e-8)
00247 continue;
00248
00249 vnl_diag_matrix<double> Dinv((1.0 - lambda * d_).as_ref());
00250 Dinv.invert_in_place();
00251 vnl_double_4 Xp = Dinv * pprime.as_ref();
00252 vnl_double_4 X = V_ * Xp + t_;
00253
00254
00255 {
00256 HomgPoint2D X1(X[0], X[1]);
00257 HomgPoint2D X2(X[2], X[3]);
00258 double EPIDIST = HomgOperator2D::perp_dist_squared(X2, HomgLine2D(F_*X1.get_vector()));
00259 if (0 && EPIDIST > 1e-12) {
00260
00261
00262 vcl_cerr << "FManifoldProject: A root has epidist = " << vcl_sqrt(EPIDIST) << vcl_endl
00263 << " coeffs: " << coeffs_ << vcl_endl
00264 << " root = " << lambda << vcl_endl
00265 << " poly residual = " << poly.evaluate(lambda) << vcl_endl
00266 << " rational poly residual = " << RATPOLY_RESIDUAL << vcl_endl;
00267 ++ errs;
00268 break;
00269 }
00270 }
00271
00272 double dist = (X - p).squared_magnitude();
00273 if (!got_one || dist < dmin) {
00274 dmin = dist;
00275 Xmin = X;
00276 got_one = true;
00277 }
00278 }
00279
00280 if (!got_one) {
00281 vcl_cerr << "FManifoldProject: AROOGAH. Final epipolar distance = " << dmin << ", errs = " << errs << vcl_endl;
00282 *ox1 = x1;
00283 *oy1 = y1;
00284 *ox2 = x2;
00285 *oy2 = y2;
00286 }
00287 else {
00288 *ox1 = Xmin[0];
00289 *oy1 = Xmin[1];
00290 *ox2 = Xmin[2];
00291 *oy2 = Xmin[3];
00292 }
00293
00294 return dmin;
00295 }