contrib/oxl/mvl/mvl_five_point_camera_pencil.cxx
Go to the documentation of this file.
00001 // This is oxl/mvl/mvl_five_point_camera_pencil.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 // \file
00007 // \author fsm
00008 
00009 #include "mvl_five_point_camera_pencil.h"
00010 
00011 #include <vcl_cmath.h>
00012 #include <vnl/vnl_double_3.h>
00013 #include <vnl/algo/vnl_svd.h>
00014 
00015 bool mvl_five_point_camera_pencil(double const xs[5],
00016                                   double const ys[5],
00017                                   vnl_double_3x4 *A,
00018                                   vnl_double_3x4 *B)
00019 {
00020   // normalization: translate the last point to the origin
00021   // and scale each other point by the hypot() of the first
00022   // two components.
00023   vnl_double_3x4 design;
00024   for (int i=0; i<4; ++i) {
00025     double u = xs[i] - xs[4];
00026     double v = ys[i] - ys[4];
00027     double one_over_r = 1.0 / vcl_sqrt(u*u + v*v);
00028     if (! one_over_r)
00029       return false;
00030     design[0][i] = u * one_over_r;
00031     design[1][i] = v * one_over_r;
00032     design[2][i] = one_over_r;
00033   }
00034 
00035   // Since we know the coordinates of the first five world points, we
00036   // know the columns of the camera matrix P, up to scale:
00037   //   $ P= [ l1*x1 | l2*x2 | l3*x3 | l4*x4 ] $
00038   //
00039   // and also:
00040   //   x5 ~ l1*x1 + l2*x2 + l3*x3 + l4*x4
00041   //
00042   // The space of such l = [l1; l2; l3; l4] can be found as the 2D
00043   // nullspace of linear system
00044   //   $ x5 \times [ x1; x2; x3; x4 ] l = 0 $
00045   // Since x5 = [ 0; 0; 1 ], this just means we take the nullspace
00046   // of the leading 2x4 submatrix of [ x1; x2; x3; x4 ].
00047 #ifdef DEBUG
00048   vcl_cerr << "design = "; vnl_matlab_print(vcl_cerr,design);
00049 #endif
00050   vnl_svd<double> svd(design.extract(2, 4));
00051 #ifdef DEBUG
00052   vcl_cerr << "singvals = " << svd.W() << vcl_endl;
00053 #endif
00054 
00055   // get basis for nullspace :
00056   vnl_vector<double> a(svd.V().get_column(2));
00057   vnl_vector<double> b(svd.V().get_column(3));
00058 #ifdef DEBUG
00059   vcl_cerr << "a = "; vnl_matlab_print(vcl_cerr,a);
00060   vcl_cerr << "b = "; vnl_matlab_print(vcl_cerr,b);
00061 #endif
00062 
00063   // make the 3x4 cameras :
00064   *A = design;
00065   A->scale_column(0, a[0]);
00066   A->scale_column(1, a[1]);
00067   A->scale_column(2, a[2]);
00068   A->scale_column(3, a[3]);
00069   *B = design;
00070   B->scale_column(0, b[0]);
00071   B->scale_column(1, b[1]);
00072   B->scale_column(2, b[2]);
00073   B->scale_column(3, b[3]);
00074 #ifdef DEBUG
00075   vcl_cerr << "A = "; vnl_matlab_print(vcl_cerr,A);
00076   vcl_cerr << "B = "; vnl_matlab_print(vcl_cerr,B);
00077 #endif
00078 
00079   // translate the last point back again.
00080   for (int i=0; i<4; ++i) {
00081     (*A)[0][i] += xs[4] * (*A)[2][i];
00082     (*A)[1][i] += ys[4] * (*A)[2][i];
00083 
00084     (*B)[0][i] += xs[4] * (*B)[2][i];
00085     (*B)[1][i] += ys[4] * (*B)[2][i];
00086   }
00087 
00088   return true;
00089 }
00090 
00091 bool mvl_five_point_camera_pencil_parameters(vnl_double_3x4 const &A,
00092                                              vnl_double_3x4 const &B,
00093                                              vnl_double_4 const &X,
00094                                              double u, double v,
00095                                              double st[2],
00096                                              double res[2])
00097 {
00098   // project.
00099   vnl_double_3 AX = A * X;
00100   vnl_double_3 BX = B * X;
00101 
00102   // translate (u, v) to origin (0, 0)
00103   AX[0] -= u * AX[2]; AX[1] -= v * AX[2];
00104   BX[0] -= u * BX[2]; BX[1] -= v * BX[2];
00105 
00106   // this line wants to pass through the origin. alas, it might not.
00107   vnl_double_3 l = vnl_cross_3d(AX, BX);
00108 
00109   if (st) {
00110     double s =  (l[1]*BX[0] - l[0]*BX[1]);
00111     double t = -(l[1]*AX[0] - l[0]*AX[1]);
00112 #if 1
00113     double n = vcl_sqrt(s*s + t*t);
00114     if (n == 0)
00115       return false;
00116     st[0] = s/n;
00117     st[1] = t/n;
00118 #else
00119     st[0] = s;
00120     st[1] = t;
00121 #endif
00122 
00123 #ifdef DEBUG
00124     vcl_cerr << A << vcl_endl
00125              << B << vcl_endl
00126              << X << vcl_endl
00127              << u << ' ' << v << vcl_endl
00128              << st[0] << ' ' << st[1] << vcl_endl;
00129 #endif
00130   }
00131 
00132   if (res) {
00133     // squared magnitude of the normal vector :
00134     double nn = l[0]*l[0] + l[1]*l[1];
00135     if (nn == 0)
00136       return false; // if it's the line at infinity, fail
00137 
00138     // the residuals are :
00139     res[0] = l[0] * l[2] / nn;
00140     res[1] = l[1] * l[2] / nn;
00141   }
00142 
00143   return true;
00144 }