contrib/oxl/mvl/FMatrixSkew.cxx
Go to the documentation of this file.
00001 // This is oxl/mvl/FMatrixSkew.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 //  \file
00007 
00008 #include "FMatrixSkew.h"
00009 #include <vcl_iostream.h>
00010 #include <vcl_cmath.h>
00011 #include <vnl/vnl_matrix.h>
00012 #include <mvl/HomgLine2D.h>
00013 #include <mvl/HomgOperator2D.h>
00014 #include <mvl/HomgPoint2D.h>
00015 #include <mvl/PMatrix.h>
00016 
00017 //--------------------------------------------------------------
00018 //
00019 //: Default constructor.
00020 
00021 FMatrixSkew::FMatrixSkew()
00022 {
00023   rank2_flag_ = true;
00024 }
00025 
00026 //--------------------------------------------------------------
00027 //
00028 //: Constructor.
00029 
00030 FMatrixSkew::FMatrixSkew(const double* f_matrix)
00031 {
00032   rank2_flag_ = true;
00033   set(f_matrix);
00034 }
00035 
00036 //--------------------------------------------------------------
00037 //
00038 //: Constructor.
00039 
00040 FMatrixSkew::FMatrixSkew(const vnl_matrix<double>& f_matrix)
00041 {
00042   rank2_flag_ = true;
00043   set(f_matrix.data_block());
00044 }
00045 
00046 
00047 //--------------------------------------------------------------
00048 //
00049 //: Destructor.
00050 
00051 FMatrixSkew::~FMatrixSkew()
00052 {
00053 }
00054 
00055 
00056 //--------------------------------------------------------------
00057 //
00058 //: Compute the epipole which is the same in each image.
00059 //  Returns true as FMatrixSkew is always Rank 2.
00060 
00061 bool
00062 FMatrixSkew::get_epipoles(vgl_homg_point_2d<double>& epipole1,
00063                           vgl_homg_point_2d<double>& epipole2) const
00064 {
00065   // fm_compute_epipoles
00066   epipole1.set( f_matrix_.get(1,2),
00067                -f_matrix_.get(0,2),
00068                 f_matrix_.get(0,1));
00069   epipole2.set( f_matrix_.get(1,2),
00070                -f_matrix_.get(0,2),
00071                 f_matrix_.get(0,1));
00072   return true;
00073 }
00074 
00075 
00076 //--------------------------------------------------------------
00077 //
00078 //: Compute the epipole which is the same in each image.
00079 //  Returns true as FMatrixSkew is always Rank 2.
00080 
00081 bool
00082 FMatrixSkew::get_epipoles(HomgPoint2D *epipole1_ptr, HomgPoint2D *epipole2_ptr) const
00083 {
00084   // fm_compute_epipoles
00085   epipole1_ptr->set( f_matrix_.get(1,2),
00086                     -f_matrix_.get(0,2),
00087                      f_matrix_.get(0,1));
00088   epipole2_ptr->set( f_matrix_.get(1,2),
00089                     -f_matrix_.get(0,2),
00090                      f_matrix_.get(0,1));
00091   return true;
00092 }
00093 
00094 
00095 //-----------------------------------------------------------------------------
00096 //
00097 //: Decompose F to the product of a skew-symmetric matrix and a Rank 3 matrix.
00098 //    Actually returns current matrix and identity matrix.
00099 
00100 void
00101 FMatrixSkew::decompose_to_skew_rank3(vnl_matrix<double> *skew_matrix_ptr,
00102                                      vnl_matrix<double> *rank3_matrix_ptr) const
00103 {
00104   *skew_matrix_ptr = this->get_matrix().as_ref();
00105   rank3_matrix_ptr->fill(0.0);
00106   rank3_matrix_ptr->fill_diagonal(1.0);
00107 }
00108 
00109 //-------------------------------------------------------------------
00110 //
00111 //: Null function as already Rank 2.
00112 
00113 inline void
00114 FMatrixSkew::set_rank2_using_svd (void)
00115 {
00116 }
00117 
00118 //-----------------------------------------------------------------------------
00119 //
00120 //: Returns current matrix which is already Rank 2.
00121 
00122 inline FMatrixSkew
00123 FMatrixSkew::get_rank2_truncated()
00124 {
00125   return *this;
00126 }
00127 
00128 
00129 //-----------------------------------------------------------------------------
00130 //
00131 //: Find nearest match which is in agreement with F.
00132 // For a specified pair of matching points, find the nearest (minimum sum
00133 // of squared image distances) match which is in perfect agreement with
00134 // the epipolar geometry of the F matrix.
00135 // For skew symmetric matrix a reduced form with only a quadratic equation
00136 // can be used (see Armstrong Zisserman Beardsley, BMVC 94 ).
00137 
00138 void
00139 FMatrixSkew::find_nearest_perfect_match(vgl_homg_point_2d<double> const& point1,
00140                                         vgl_homg_point_2d<double> const& point2,
00141                                         vgl_homg_point_2d<double>& perfect_point1,
00142                                         vgl_homg_point_2d<double>& perfect_point2) const
00143 {
00144   // get the epipole
00145   vgl_homg_point_2d<double> e1,e2;
00146   get_epipoles(e1,e2);
00147 
00148   // scale points if not already done and transform such that  e1->(0,0)
00149   double u1 = point1.x()/point1.w() - e1.x()/e1.w();
00150   double v1 = point1.y()/point1.w() - e1.y()/e1.w();
00151   double u2 = point2.x()/point2.w() - e2.x()/e2.w();
00152   double v2 = point2.y()/point2.w() - e2.y()/e2.w();
00153 
00154   // form quadratic equation
00155   double a_qd = (u1*v1 + u2*v2);
00156   double b_qd = u1*u1 + u2*u2 - v1*v1 - v2*v2;
00157   double c_qd = -(u1*v1 + u2*v2);
00158 
00159   // solve quadratic for two solutions
00160   double temp = b_qd * b_qd - 4 * a_qd * c_qd;
00161 
00162   if (temp < 0)
00163   {
00164     vcl_cerr << "Error in FMatrixSkew::find_nearest_perfect_match\n"
00165              << "Imaginary solution obtained\n"
00166              << "No solution returned\n";
00167     return;
00168   }
00169 
00170   double ttheta1 = (-b_qd + vcl_sqrt(temp))/(2*a_qd);
00171   double ttheta2 = (-b_qd - vcl_sqrt(temp))/(2*a_qd);
00172 
00173   double theta1 = vcl_atan(ttheta1);
00174   double theta2 = vcl_atan(ttheta2);
00175 
00176   double ctheta1 = vcl_cos(theta1), stheta1 = vcl_sin(theta1);
00177   double ctheta2 = vcl_cos(theta2), stheta2 = vcl_sin(theta2);
00178 
00179   double dist11 = stheta1*u1 - ctheta1*v1;
00180   double dist12 = stheta1*u2 - ctheta1*v2;
00181   double dist21 = stheta2*u1 - ctheta2*v1;
00182   double dist22 = stheta2*u2 - ctheta2*v2;
00183 
00184   // find correct solution with minimum distance - set to theta1
00185   if (vcl_fabs(dist11) + vcl_fabs(dist12) > vcl_fabs(dist21) + vcl_fabs(dist22))
00186   {
00187     stheta1 = stheta2;
00188     ctheta1 = ctheta2;
00189     dist11   = dist21;
00190     dist12   = dist22;
00191   }
00192 
00193   // do with per_proj... in HomgOp2D::
00194   perfect_point1.set(u1-dist11*stheta1+e1.x()/e1.w(),
00195                      v1+dist11*ctheta1+e1.y()/e1.w(),1);
00196   perfect_point2.set(u2-dist12*stheta1+e2.x()/e2.w(),
00197                      v2+dist12*ctheta1+e2.y()/e2.w(),1);
00198 }
00199 
00200 //-----------------------------------------------------------------------------
00201 //
00202 //: Find nearest match which is in agreement with F.
00203 // For a specified pair of matching points, find the nearest (minimum sum
00204 // of squared image distances) match which is in perfect agreement with
00205 // the epipolar geometry of the F matrix.
00206 // For skew symmetric matrix a reduced form with only a quadratic equation
00207 // can be used (see Armstrong Zisserman Beardsley, BMVC 94 ).
00208 
00209 void
00210 FMatrixSkew::find_nearest_perfect_match(const HomgPoint2D& point1,
00211                                         const HomgPoint2D& point2,
00212                                         HomgPoint2D *perfect_point1_ptr,
00213                                         HomgPoint2D *perfect_point2_ptr) const
00214 {
00215   // get the epipole
00216   HomgPoint2D e1,e2;
00217   get_epipoles(&e1,&e2);
00218 
00219   // scale points if not already done and transform such that  e1->(0,0)
00220   double u1 = point1.x()/point1.w() - e1.x()/e1.w();
00221   double v1 = point1.y()/point1.w() - e1.y()/e1.w();
00222   double u2 = point2.x()/point2.w() - e2.x()/e2.w();
00223   double v2 = point2.y()/point2.w() - e2.y()/e2.w();
00224 
00225   // form quadratic equation
00226   double a_qd = (u1*v1 + u2*v2);
00227   double b_qd = u1*u1 + u2*u2 - v1*v1 - v2*v2;
00228   double c_qd = -(u1*v1 + u2*v2);
00229 
00230   // solve quadratic for two solutions
00231   double temp = b_qd * b_qd - 4 * a_qd * c_qd;
00232 
00233   if (temp < 0)
00234   {
00235     vcl_cerr << "Error in FMatrixSkew::find_nearest_perfect_match\n"
00236              << "Imaginary solution obtained\n"
00237              << "No solution returned\n";
00238     return;
00239   }
00240 
00241   double ttheta1 = (-b_qd + vcl_sqrt(temp))/(2*a_qd);
00242   double ttheta2 = (-b_qd - vcl_sqrt(temp))/(2*a_qd);
00243 
00244   double theta1 = vcl_atan(ttheta1);
00245   double theta2 = vcl_atan(ttheta2);
00246 
00247   double ctheta1 = vcl_cos(theta1), stheta1 = vcl_sin(theta1);
00248   double ctheta2 = vcl_cos(theta2), stheta2 = vcl_sin(theta2);
00249 
00250   double dist11 = stheta1*u1 - ctheta1*v1;
00251   double dist12 = stheta1*u2 - ctheta1*v2;
00252   double dist21 = stheta2*u1 - ctheta2*v1;
00253   double dist22 = stheta2*u2 - ctheta2*v2;
00254 
00255   // find correct solution with minimum distance - set to theta1
00256   if (vcl_fabs(dist11) + vcl_fabs(dist12) > vcl_fabs(dist21) + vcl_fabs(dist22))
00257   {
00258     stheta1 = stheta2;
00259     ctheta1 = ctheta2;
00260     dist11   = dist21;
00261     dist12   = dist22;
00262   }
00263 
00264   // do with per_proj... in HomgOp2D::
00265   perfect_point1_ptr->set(u1-dist11*stheta1+e1.x()/e1.w(),
00266                           v1+dist11*ctheta1+e1.y()/e1.w(),1);
00267   perfect_point2_ptr->set(u2-dist12*stheta1+e2.x()/e2.w(),
00268                           v2+dist12*ctheta1+e2.y()/e2.w(),1);
00269 }
00270 
00271 
00272 //--------------------------------------------------------------
00273 //
00274 //: Set the fundamental matrix using the two-dimensional array f_matrix.
00275 // Only returns true if f_matrix contained a
00276 // skew matrix, not an approximation to one.
00277 // The test is against a 0.0 tolerance.
00278 // Otherwise returns false and the matrix is not set.
00279 
00280 bool FMatrixSkew::set (const double* f_matrix )
00281 {
00282   int row_index, col_index;
00283 
00284   // should be set to 0.0
00285   const double tolerance=0.0;
00286 
00287   // CRUDE test for skewness with tolerance 0
00288   // test diagonal is zero and asymmetric
00289   if ((f_matrix[1] + f_matrix[3] > tolerance) |
00290       (f_matrix[2] + f_matrix[6] > tolerance) |
00291       (f_matrix[5] + f_matrix[7] > tolerance) |
00292       (f_matrix[0] > tolerance) |
00293       (f_matrix[4] > tolerance) |
00294       (f_matrix[8] > tolerance) )
00295   {
00296     vcl_cerr << "WARNING: F matrix not skew symmetric so cannot allocate to FMatrixSkew\n" ;
00297     return false;
00298   }
00299 
00300   for (row_index = 0; row_index < 3; row_index++)
00301     for (col_index = 0; col_index < 3; col_index++)
00302     {
00303       double v = *f_matrix++;
00304       f_matrix_. put (row_index, col_index,v);
00305       ft_matrix_. put (col_index, row_index,v);
00306     }
00307 
00308   // set rank flag true
00309 
00310   FMatrix::set_rank2_flag(true);
00311 
00312   return true;
00313 }
00314 
00315 
00316 //--------------------------------------------------------------
00317 //
00318 //: Set the fundamental matrix using the vnl_matrix<double> f_matrix.
00319 // Only returns true if f_matrix contained a
00320 // skew matrix, not an approximation to one.
00321 // Otherwise returns false and the matrix is not set.
00322 // Patch on FMatrixSkew::set (const double*).
00323 
00324 inline bool
00325 FMatrixSkew::set (const vnl_matrix<double>& f_matrix )
00326 {
00327   return set(f_matrix.data_block());
00328 }
00329 
00330 
00331 //----------------------------------------------------------------
00332 //
00333 //: Returns the rank2_flag_ which is always true for FMatrixSkew.
00334 
00335 inline bool
00336 FMatrixSkew::get_rank2_flag (void) const
00337 {
00338   return true;
00339 }
00340 
00341 //----------------------------------------------------------------
00342 //
00343 //: Set the rank2_flag_. Null function as always set true.
00344 
00345 inline void
00346 FMatrixSkew::set_rank2_flag (bool)
00347 {
00348   FMatrix::set_rank2_flag(true);
00349 }