core/vgl/algo/vgl_h_matrix_3d_compute_linear.cxx
Go to the documentation of this file.
00001 // This is core/vgl/algo/vgl_h_matrix_3d_compute_linear.cxx
00002 #include "vgl_h_matrix_3d_compute_linear.h"
00003 //:
00004 // \file
00005 
00006 #include <vcl_iostream.h>
00007 #include <vcl_cmath.h>
00008 #include <vcl_cassert.h>
00009 #include <vgl/algo/vgl_norm_trans_3d.h>
00010 #include <vnl/algo/vnl_svd.h>
00011 
00012 const int TM_UNKNOWNS_COUNT = 16;
00013 const double DEGENERACY_THRESHOLD = 0.00001;  
00014   
00015 
00016 //: Compute a 3D-to-3D homography using linear least squares.
00017 // Returns false if the calculation fails or there are fewer than five point
00018 // matches in the list.  The algorithm finds the nullvector of the $6 n \times 16$ design
00019 // matrix:
00020 
00021 //:Assumes all corresponding points have equal weight
00022 bool vgl_h_matrix_3d_compute_linear::
00023 solve_linear_problem(vcl_vector<vgl_homg_point_3d<double> > const& p1,
00024                      vcl_vector<vgl_homg_point_3d<double> > const& p2,
00025                      vgl_h_matrix_3d<double>& H)
00026 {
00027   int n = p1.size();
00028   //transform the point sets and fill the design matrix
00029   vnl_matrix<double> D(n*6, TM_UNKNOWNS_COUNT);
00030   
00031   int row = 0;
00032   for (int i = 0; i < n; i++) {
00033     //double x1 = p1[i].x(), x2 = p1[i].y(), x3 = p1[i].z(), x4 = p1[i].w();
00034     //double y1 = p2[i].x(), y2 = p2[i].y(), y3 = p2[i].z(), y4 = p2[i].w();
00035     double x1 = p2[i].x(), x2 = p2[i].y(), x3 = p2[i].z(), x4 = p2[i].w();
00036     double y1 = p1[i].x(), y2 = p1[i].y(), y3 = p1[i].z(), y4 = p1[i].w();
00037 
00038     D(row, 0) = -x2*y1;   D(row, 1) = x1*y1;   D(row, 2) = 0;      D(row, 3) = 0;      
00039     D(row, 4) = -x2*y2;   D(row, 5) = x1*y2;   D(row, 6) = 0;      D(row, 7) = 0;       
00040     D(row, 8) = -x2*y3;   D(row, 9) = x1*y3;   D(row, 10) = 0;     D(row, 11) = 0;    
00041     D(row, 12) = -x2*y4;  D(row, 13) = x1*y4;  D(row, 14) = 0;     D(row, 15) = 0;
00042     ++row;
00043     D(row, 0) = -x3*y1;   D(row, 1) = 0;       D(row, 2) = x1*y1;  D(row, 3) = 0;      
00044     D(row, 4) = -x3*y2;   D(row, 5) = 0;       D(row, 6) = x1*y2;  D(row, 7) = 0;       
00045     D(row, 8) = -x3*y3;   D(row, 9) = 0;       D(row, 10) = x1*y3; D(row, 11) = 0;    
00046     D(row, 12) = -x3*y4;  D(row, 13) = 0;      D(row, 14) = x1*y4;   D(row, 15) = 0;
00047     ++row;
00048     D(row, 0) = -x4*y1;   D(row, 1) = 0;       D(row, 2) = 0;      D(row, 3) = x1*y1;      
00049     D(row, 4) = -x4*y2;   D(row, 5) = 0;       D(row, 6) = 0;      D(row, 7) = x1*y2;       
00050     D(row, 8) = -x4*y3;   D(row, 9) = 0;       D(row, 10) = 0;     D(row, 11) = x1*y3;    
00051     D(row, 12) = -x4*y4;  D(row, 13) = 0;      D(row, 14) = 0;     D(row, 15) = x1*y4;
00052     ++row;
00053     D(row, 0) = 0;        D(row, 1) = -x4*y1;  D(row, 2) = 0;      D(row, 3) = x2*y1;      
00054     D(row, 4) = 0;        D(row, 5) = -x4*y2;  D(row, 6) = 0;      D(row, 7) = x2*y2;       
00055     D(row, 8) = 0;        D(row, 9) = -x4*y3;  D(row, 10) = 0;     D(row, 11) = x2*y3;    
00056     D(row, 12) = 0;       D(row, 13) = -x4*y4; D(row, 14) = 0;     D(row, 15) = x2*y4;
00057     ++row;
00058     D(row, 0) = 0;        D(row, 1) = 0;       D(row, 2) = -x4*y1;      D(row, 3) = x3*y1;      
00059     D(row, 4) = 0;        D(row, 5) = 0;       D(row, 6) = -x4*y2;      D(row, 7) = x3*y2;       
00060     D(row, 8) = 0;        D(row, 9) = 0;       D(row, 10) = -x4*y3;     D(row, 11) = x3*y3;    
00061     D(row, 12) = 0;       D(row, 13) = 0;      D(row, 14) = -x4*y4;     D(row, 15) = x3*y4;
00062     ++row;
00063     D(row, 0) = 0;        D(row, 1) = -x3*y1;       D(row, 2) = x2*y1;      D(row, 3) = 0;      
00064     D(row, 4) = 0;        D(row, 5) = -x3*y2;       D(row, 6) = x2*y2;      D(row, 7) = 0;       
00065     D(row, 8) = 0;        D(row, 9) = -x3*y3;       D(row, 10) = x2*y3;     D(row, 11) = 0;    
00066     D(row, 12) = 0;       D(row, 13) = -x3*y4;      D(row, 14) = x2*y4;     D(row, 15) = 0;
00067     ++row;
00068   }
00069 
00070   D.normalize_rows();
00071   vnl_svd<double> svd(D);
00072 
00073   //
00074   // FSM added :
00075   //
00076   if (svd.W(15)<DEGENERACY_THRESHOLD*svd.W(16)) {
00077     vcl_cerr << "vgl_h_matrix_3d_compute_linear : design matrix has rank < 16\n"
00078              << "vgl_h_matrix_3d_compute_linear : probably due to degenerate point configuration\n";
00079     return false;
00080   }
00081   // form the matrix from the nullvector
00082   H.set(svd.nullvector().data_block());
00083   return true;
00084 }
00085 
00086 bool vgl_h_matrix_3d_compute_linear::
00087 compute_p(vcl_vector<vgl_homg_point_3d<double> > const& points1,
00088           vcl_vector<vgl_homg_point_3d<double> > const& points2,
00089           vgl_h_matrix_3d<double>& H)
00090 {
00091   //number of points must be the same
00092   assert(points1.size() == points2.size());
00093   int n = points1.size();
00094 
00095   if (n * 3 < TM_UNKNOWNS_COUNT - 1) {
00096     vcl_cerr << "vgl_h_matrix_3d_compute_linear: Need at least 5 matches.\n";
00097     if (n == 0) vcl_cerr << "Could be vcl_vector setlength idiosyncrasies!\n";
00098     return false;
00099   }
00100 
00101   //compute the normalizing transforms
00102   vgl_norm_trans_3d<double> tr1, tr2;
00103   if (!tr1.compute_from_points(points1))
00104     return false;
00105   if (!tr2.compute_from_points(points2))
00106     return false;
00107   vcl_vector<vgl_homg_point_3d<double> > tpoints1, tpoints2;
00108   for (int i = 0; i<n; i++)
00109   {
00110     tpoints1.push_back(tr1(points1[i]));
00111     tpoints2.push_back(tr2(points2[i]));
00112   }
00113   vgl_h_matrix_3d<double> hh(tpoints1, tpoints2);
00114   //vgl_h_matrix_3d<double> hh;
00115   //if (!solve_linear_problem(tpoints1,tpoints2,hh))
00116     //return false;
00117 
00118   //
00119   // Next, hh has to be transformed back to the coordinate system of
00120   // the original point sets, i.e.,
00121   //  p1' = tr1 p1 , p2' = tr2 p2
00122   // hh was determined from the transform relation
00123   //  p2' = hh p1', thus
00124   // (tr2 p2) = hh (tr1 p1)
00125   //  p2 = (tr2^-1 hh tr1) p1 = H p1
00126   vgl_h_matrix_3d<double> tr2_inv = tr2.get_inverse();
00127   H = tr2_inv*hh*tr1;
00128   return true;
00129 }
00130 
00131 
00132