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