contrib/oxl/mvl/FMatrixPlanar.cxx
Go to the documentation of this file.
00001 // This is oxl/mvl/FMatrixPlanar.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 // \file
00007 
00008 #include "FMatrixPlanar.h"
00009 
00010 #include <vcl_cassert.h>
00011 #include <vcl_iostream.h>
00012 #include <vcl_cmath.h>
00013 #include <vnl/vnl_double_3.h>
00014 
00015 #include <vnl/algo/vnl_svd.h>
00016 #include <vnl/vnl_math.h>
00017 #include <vnl/algo/vnl_symmetric_eigensystem.h>
00018 
00019 #include <mvl/FMatrix.h>
00020 
00021 //--------------------------------------------------------------
00022 //
00023 //: Default constructor.
00024 
00025 FMatrixPlanar::FMatrixPlanar()
00026 {
00027   rank2_flag_ = true;
00028 }
00029 
00030 //--------------------------------------------------------------
00031 //
00032 //: Constructor.
00033 
00034 FMatrixPlanar::FMatrixPlanar(const double* f_matrix)
00035 {
00036   rank2_flag_ = true;
00037   set(f_matrix);
00038 }
00039 
00040 //--------------------------------------------------------------
00041 //
00042 //: Constructor.
00043 
00044 FMatrixPlanar::FMatrixPlanar(const vnl_double_3x3& f_matrix)
00045 {
00046   rank2_flag_ = true;
00047   set(f_matrix.data_block());
00048 }
00049 
00050 
00051 //--------------------------------------------------------------
00052 //
00053 //: Destructor.
00054 
00055 FMatrixPlanar::~FMatrixPlanar()
00056 {
00057 }
00058 
00059 //--------------------------------------------------------------
00060 //
00061 //: Set the fundamental matrix using the two-dimensional array f_matrix.
00062 // Only returns true if f_matrix contained a planar matrix, not an
00063 // approximation to one. Otherwise returns false and the matrix is not set.
00064 // Patch on FMatrixSkew::set (const vnl_double_3x3& f_matrix ).
00065 
00066 bool FMatrixPlanar::set (const double* f_matrix )
00067 {
00068   vnl_double_3x3 temp(f_matrix);
00069   return set(temp);
00070 }
00071 
00072 
00073 //--------------------------------------------------------------
00074 //
00075 //: Set the fundamental matrix using the vnl_double_3x3 f_matrix.
00076 // Only returns true if f_matrix contained a planar matrix, not an
00077 // approximation to one. The test is against a Rank 2 constraint for
00078 // both ${\tt F}$ and the symmetric part ({\tt F}+{\tt F}^\top).
00079 // Otherwise returns false and the matrix is not set.
00080 
00081 bool
00082 FMatrixPlanar::set (vnl_double_3x3 const& f_matrix )
00083 {
00084   int row_index, col_index;
00085 
00086 #ifdef PARANOID
00087 
00088   // CRUDE test for planar form with tolerance 0
00089   // test F and F+F' are Rank 2
00090   // HACK: has been altered to have some tolerances
00091   bool planar = true;
00092   vnl_svd<double> svd(f_matrix.as_ref(),1e-8);
00093   if (svd.rank()!=2)
00094   {
00095     planar = false;
00096     vcl_cerr << "WARNING in FMatrixPlanar::set\n"
00097              << "F matrix not rank 2: svd = " << svd.W() << vcl_endl;
00098   }
00099   else
00100   {
00101     vnl_svd<double> svd((f_matrix + f_matrix.transpose()).as_ref(),1e-8);
00102     if (svd.rank()!=2)
00103     {
00104       planar = false;
00105       vcl_cerr << "WARNING in FMatrixPlanar::set\n"
00106                << "Symmetric part matrix not rank 2: svd = " << svd.W() << '\n';
00107     }
00108   }
00109 
00110   if (!planar)
00111   {
00112     vcl_cerr << "WARNING: F matrix not planar so cannot allocate to FMatrixPlanar\n" ;
00113     return FALSE;
00114   }
00115 
00116 #endif
00117 
00118   for (row_index = 0; row_index < 3; row_index++)
00119     for (col_index = 0; col_index < 3; col_index++)
00120     {
00121       f_matrix_. put (row_index, col_index,f_matrix.get(row_index,col_index));
00122       ft_matrix_. put (col_index, row_index,f_matrix.get(row_index,col_index));
00123     }
00124 
00125   // set rank flag true
00126 
00127   this->set_rank2_flag(true);
00128 
00129   return true;
00130 }
00131 
00132 
00133 //----------------------------------------------------------------
00134 //
00135 //: Initialises the FMatrixPlanar using a general fundamental matrix F.
00136 // Does so by finding the nearest planar fundamental matrix to F.
00137 // This should be used prior to FMPlanarComputeNonLinear to give
00138 // an initial value for the non-linear minimisation.
00139 // This function is required as trying to set FMatrixPlanar using a
00140 // general fundamental matrix
00141 // will fail as it does not satisfy the extra constraint of
00142 // \f$\det ({\tt F} + {\tt F}^\top) = 0\f$.
00143 
00144 void FMatrixPlanar::init(const FMatrix& F)
00145 {
00146   // this converts to 6 parameter form of [e2]x[ls]x[e1]x - see A Zisserman
00147   // HACK this is not the most efficient/accurate way to convert to this form
00148   // as it goes via the Armstrong implementation of the
00149   // Lingrand Veiville formula (ECCV96).
00150   // This should be redone at some point.
00151 
00152   vgl_homg_point_2d<double> e1,e2;
00153   F.get_epipoles(e1,e2);
00154 
00155   vnl_symmetric_eigensystem<double> symm_eig((F.get_matrix()+F.get_matrix().transpose()).as_ref()); // size 3x3
00156 
00157   double eig0 = symm_eig.D(0,0);
00158   double eig1 = symm_eig.D(2,2);
00159 
00160   vnl_double_3 v0 = symm_eig.get_eigenvector(0);
00161   vnl_double_3 v1 = symm_eig.get_eigenvector(2);
00162 
00163   vnl_double_3 f1, f2;
00164 
00165   if (eig0 > 0 && eig1 < 0) {
00166     f1 = vcl_sqrt(eig0)*v0 + vcl_sqrt(-eig1)*v1;
00167     f2 = vcl_sqrt(eig0)*v0 - vcl_sqrt(-eig1)*v1;
00168   }
00169   else if (eig0 < 0 && eig1 > 0) {
00170     f1 = vcl_sqrt(eig1)*v1 + vcl_sqrt(-eig0)*v0;
00171     f2 = vcl_sqrt(eig1)*v1 - vcl_sqrt(-eig0)*v0;
00172   }
00173   else {
00174     vcl_cerr << "ERROR in FMatrix::init\n"
00175              << "EXITING...\n";
00176     assert(false);
00177   }
00178 
00179 #define dot_n(a,b) (a.x()*b(0)/a.w()+a.y()*b(1)/a.w()+b(2))
00180   vnl_double_3 ls;
00181   if (vcl_fabs(dot_n(e1,f1))+
00182       vcl_fabs(dot_n(e2,f1)) >
00183       vcl_fabs(dot_n(e1,f2))+
00184       vcl_fabs(dot_n(e2,f2)) )
00185     ls = f1;
00186   else
00187     ls = f2;
00188 #undef dot_n
00189 
00190   ls.normalize();
00191 
00192   double ls_thi = vcl_acos(ls[2]);
00193   if (ls_thi < 0) ls_thi += vnl_math::pi;
00194 
00195   double ls_theta;
00196   if (ls[1] >= 0)
00197     ls_theta =  vcl_acos(ls[0]/vcl_sin(ls_thi));
00198   else
00199     ls_theta = -vcl_acos(ls[0]/vcl_sin(ls_thi));
00200 
00201   double ls1 = vcl_cos(ls_theta)*vcl_sin(ls_thi);
00202   double ls2 = vcl_sin(ls_theta)*vcl_sin(ls_thi);
00203   double ls3 = vcl_cos(ls_thi);
00204 
00205   double list1[9] = {0,-1.0,e1.y()/e1.w(),
00206                      1,0,-e1.x()/e1.w(),
00207                      -e1.y()/e1.w(),e1.x()/e1.w(),0};
00208   double list2[9] = {0,-ls3,ls2,ls3,0,-ls1,-ls2,ls1,0};
00209   double list3[9] = {0,-1.0,e2.y()/e2.w(),
00210                      1,0,-e2.x()/e2.w(),
00211                      -e2.y()/e2.w(),e2.x()/e2.w(),0};
00212 
00213   vnl_double_3x3 mat1(list1),mat2(list2),mat3(list3);
00214 
00215   vnl_double_3x3 fmat = mat1*mat2*mat3;
00216 
00217   fmat /= fmat.fro_norm();
00218 
00219   // store the corrected fmatrix
00220   set(fmat);
00221 }