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