Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members

bcal_zhang_linear_calibrate.cxx

Go to the documentation of this file.
00001 // bcal_zhang_linear_calibrate.cpp: implementation of the bcal_zhang_linear_calibrate class.
00002 //
00003 //////////////////////////////////////////////////////////////////////
00004 #include "bcal_zhang_linear_calibrate.h"
00005 #include <vnl/vnl_inverse.h>
00006 #include <vnl/vnl_double_3.h> // for vnl_cross_3d
00007 #include <vgl/algo/vgl_h_matrix_2d_compute_linear.h>
00008 #include <vcl_cassert.h>
00009 #include <vcl_cmath.h>
00010 #include <vnl/algo/vnl_svd.h>
00011 
00012 //////////////////////////////////////////////////////////////////////
00013 // Construction/Destruction
00014 //////////////////////////////////////////////////////////////////////
00015 
00016 bcal_zhang_linear_calibrate::bcal_zhang_linear_calibrate()
00017 {
00018   cam_graph_ptr_ = 0;
00019 }
00020 
00021 bcal_zhang_linear_calibrate::~bcal_zhang_linear_calibrate()
00022 {
00023   clear();
00024 }
00025 
00026 
00027 void bcal_zhang_linear_calibrate::
00028 setCameraGraph(bcal_camera_graph<bcal_calibrate_plane, bcal_zhang_camera_node, bcal_euclidean_transformation> *pG)
00029 {
00030   cam_graph_ptr_ = pG;
00031   initialize();
00032 }
00033 
00034 
00035 int bcal_zhang_linear_calibrate::compute_homography()
00036 {
00037   if (!cam_graph_ptr_){
00038     vcl_cerr<<"empty graphy, need to set graph first\n";
00039     return 1;
00040   }
00041 
00042   vgl_h_matrix_2d_compute_linear hmcl;
00043 
00044   int size = cam_graph_ptr_->num_vertice();
00045   clear(); h_matrice_.resize(size);
00046 
00047   vcl_vector<vgl_homg_point_2d<double> > &p0 = cam_graph_ptr_->get_source()->get_points();
00048 
00049 
00050   for (int i=0; i<size; i++) {// for each camera
00051     bcal_zhang_camera_node *cam = cam_graph_ptr_->get_vertex_from_pos(i);
00052     assert(cam);
00053     // compute homography
00054     int nViews = cam->num_views();
00055     h_matrice_[i] = new vgl_h_matrix_2d<double> [nViews];
00056     for (int j=0; j<nViews; j++){ // for each view
00057       vcl_vector<vgl_homg_point_2d<double> > &p1 = cam->getPoints(j);
00058       h_matrice_[i][j] = hmcl.compute(p0, p1);
00059     }
00060   }
00061   return 0;
00062 }
00063 
00064 int bcal_zhang_linear_calibrate::initialize()
00065 {
00066   // resize h_matrice_
00067   int num_camera = cam_graph_ptr_->num_vertice();
00068   clear(); h_matrice_.resize(num_camera);
00069   num_views_.resize(num_camera);
00070 
00071   // allocate vgl_h_matrix_2d<double> for each views
00072   for (int i=0; i<num_camera; i++){ // from camera 1 to camera n
00073     bcal_zhang_camera_node *cam = cam_graph_ptr_->get_vertex_from_pos(i);
00074     assert(cam);
00075 
00076     int nViews = cam->num_views();
00077     num_views_[i] = nViews;
00078     for (int j=0; j<nViews; j++)
00079       h_matrice_[i] = new vgl_h_matrix_2d<double> [nViews];
00080   }
00081 
00082   return 0;
00083 }
00084 
00085 int bcal_zhang_linear_calibrate::clear()
00086 {
00087   int size = h_matrice_.size();
00088 
00089   // delete all the data
00090   for (int i=0; i<size; i++){
00091     delete [] h_matrice_[i];
00092   }
00093   return 0;
00094 }
00095 
00096 
00097 vnl_vector_fixed<double, 6> bcal_zhang_linear_calibrate::homg_constrain(const vgl_h_matrix_2d<double> &hm, int i, int j)
00098 {
00099   vnl_vector_fixed<double, 6> v;
00100 
00101   assert(i>=0 && i<=2);
00102   assert(j>=0 && j<=2);
00103 
00104   v[0] = hm.get(0,i) * hm.get(0,j);
00105   v[1] = hm.get(0,i) * hm.get(1,j) + hm.get(1,i) * hm.get(0,j);
00106   v[2] = hm.get(1,i) * hm.get(1,j);
00107   v[3] = hm.get(2,i) * hm.get(0,j) + hm.get(0,i) * hm.get(2,j);
00108   v[4] = hm.get(2,i) * hm.get(1,j) + hm.get(1,i) * hm.get(2,j);
00109   v[5] = hm.get(2,i) * hm.get(2,j);
00110 
00111   return v;
00112 }
00113 
00114 int bcal_zhang_linear_calibrate::calibrate()
00115 {
00116   this->initialize();
00117 
00118   // get homographies
00119   compute_homography();
00120 
00121   // calibrate cameras
00122   calibrate_intrinsic();
00123   calibrate_extrinsic();
00124 
00125   return 0;
00126 }
00127 
00128 vnl_double_3x3 bcal_zhang_linear_calibrate::compute_intrinsic(vgl_h_matrix_2d<double> *hm_list, int n_hm)
00129 {
00130   assert(n_hm > 3);
00131 
00132   // 1) construct V matrix
00133   vnl_matrix<double> v(n_hm*2, 6);
00134 
00135   vnl_vector_fixed<double, 6> v11, v12, v22, v11_v22;
00136   for (int i=0; i<n_hm; i++){
00137     v11 = homg_constrain(hm_list[i], 0, 0);
00138     v12 = homg_constrain(hm_list[i], 0, 1);
00139     v22 = homg_constrain(hm_list[i], 1, 1);
00140     v11_v22 = v11 - v22;
00141 
00142     for (int j=0; j<6; j++){
00143       v[i*2][j] = v12[j];
00144       v[i*2+1][j] = v11_v22[j];
00145     }
00146   }
00147 
00148   // 2) now solve for b
00149   vnl_svd<double> svd(v);
00150   vnl_vector_fixed<double, 6> b;
00151   for (int i=0; i<6; i++)
00152     b[i] = svd.V(i, 5);
00153 
00154   double sv4 = svd.W(4);
00155   double sv5 = svd.W(5);
00156 
00157   if (sv5){ /* error check */
00158     double ratio = sv4/sv5;
00159 
00160     if (vcl_fabs(ratio) < 200){
00161       vcl_cerr << "Warning after comparing the singular values\n"
00162                << "It may be that the system of homographies is underconstrained:\n"
00163                << sv4 <<  ' ' << sv5 << '\n';
00164     }
00165   }
00166 
00167   // 3) get intrinsinsic parameter
00168   double B11,B12,B22,B13,B23,B33;
00169 
00170   B11 = b[0];
00171   B12 = b[1];
00172   B22 = b[2];
00173   B13 = b[3];
00174   B23 = b[4];
00175   B33 = b[5];
00176 
00177   double v0 = (B12*B13 - B11*B23)/(B11*B22 - B12*B12);
00178   double lamda = B33 - (B13*B13 + v0*(B12*B13-B11*B23))/B11;
00179   double alpha = vcl_sqrt(vcl_fabs(lamda/B11));
00180   double beta = vcl_sqrt(vcl_fabs(lamda * B11 /(B11*B22 - B12*B12)));
00181   double gamma = 0.0-B12*alpha*alpha*beta/lamda;
00182   double u0 = gamma*v0/beta - B13*alpha*alpha/lamda;
00183 
00184   vnl_double_3x3 k(0.0);
00185   k[0][0] = alpha;
00186   k[0][1] = gamma;
00187   k[0][2] = u0;
00188   k[1][1] = beta;
00189   k[1][2] = v0;
00190   k[2][2] = 1;
00191 
00192   return k;
00193 }
00194 
00195 vgl_h_matrix_3d<double> bcal_zhang_linear_calibrate::
00196 compute_extrinsic(vgl_h_matrix_2d<double> const &H, vnl_double_3x3 const &A)
00197 {
00198   // let A = the intrinsic parameters;
00199   // let the Extrinsic parameters = (R | t) where R is a rotion matrix
00200   // and t is a translation matrix.
00201   // let R = (r1,r2,r3) where ri is the ith column vector
00202   //  let H = the homogrhaphy = (h1,h2,h3)
00203   // let l = 1/||A^-1 h1||
00204   // it turns out that:
00205   // r1 = l A^-1 h1
00206   // r2 = l A^-1 h2
00207   // r3 = r1 x r2
00208   // t = l A^-1 h3
00209   // Due to noise r1,r2,r3 might not be a pure rotation matrix.
00210   // In this case we will have to find the closest pure rotation matrix
00211 
00212 
00213   // compute A_inv which is the inverse of the intrinsic parameters
00214   vnl_double_3x3 A_inv = vnl_inverse(A);
00215 
00216   // get h1 h2 h3
00217   vnl_double_3 h1, h2, h3;
00218   for (int i=0;i<3;i++){
00219     h1[i] = H.get(i,0);
00220     h2[i] = H.get(i,1);
00221     h3[i] = H.get(i,2);
00222   }
00223 
00224   // compute l = 1.0 / ||(A_inv * h1)||
00225   vnl_double_3 hold = A_inv * h1;
00226   double mag = hold.two_norm();
00227   double l = mag ? 1.0/mag : 1.0;
00228 
00229   // calcuate r1 = l A_inv h1
00230   vnl_double_3 r1 = l * A_inv * h1;
00231 
00232   // calcuate r2 = l A_inv h2
00233   vnl_double_3 r2 = l * A_inv * h2;
00234 
00235   // note that although r1 will have a unit normal,
00236   // r2 is not guaranteed to have a unit normal due
00237   // to noise.
00238 
00239   // caluculate r3 = r1 x r2
00240   vnl_double_3 r3 = vnl_cross_3d(r1,r2);
00241 
00242   vnl_double_3x3 Q;
00243   for (int i=0; i<3; i++){
00244     Q[i][0] = r1[i];
00245     Q[i][1] = r2[i];
00246     Q[i][2] = r3[i];
00247   }
00248 
00249   // since due to noise r2 and r3 might not be unit vecotors
00250   // we must find the closest valid rotation matrix
00251   vnl_double_3x3 R = get_closest_rotation(Q);
00252 
00253   // calculate t = l A_inv h3
00254   vnl_double_3 t = l * A_inv * h3;
00255 
00256   // make a transformation matrix to return
00257   return vgl_h_matrix_3d<double>(R, t);
00258 }
00259 
00260 vnl_double_3x3 bcal_zhang_linear_calibrate::get_closest_rotation(const vnl_double_3x3 &Q)
00261 {
00262   // let Q = U S V^T
00263   // it turns out that R = UV^T is the closest valid rotation matrix;
00264   // to Q.
00265   vnl_svd<double> svd(Q);
00266 
00267   vnl_double_3x3 R = svd.U() * svd.V().transpose();
00268 
00269   return R;
00270 }
00271 
00272 void bcal_zhang_linear_calibrate::calibrate_intrinsic()
00273 {
00274   int num_camera = cam_graph_ptr_->num_vertice();
00275   for (int i= 0; i<num_camera; i++){
00276     bcal_zhang_camera_node *cam = cam_graph_ptr_->get_vertex_from_pos(i);
00277     assert(cam);
00278     vnl_double_3x3 K = compute_intrinsic(h_matrice_[i], num_views_[i]);
00279     cam->set_intrinsic(K);
00280     vcl_cerr<<"intrinsic parameters K is:\n"<<cam->get_intrinsic()<<'\n';
00281   }
00282 }
00283 
00284 int bcal_zhang_linear_calibrate::calibrate_extrinsic()
00285 {
00286   int num_camera = cam_graph_ptr_->num_vertice();
00287 
00288   for (int i= 0; i<num_camera; i++){// for each camera
00289     // get edge
00290     bcal_zhang_camera_node *cam = cam_graph_ptr_->get_vertex_from_pos(i);
00291     assert(cam);
00292     int source_id = cam_graph_ptr_->get_source_id();
00293     int vertex_id = cam_graph_ptr_->get_vertex_id(i);
00294     bcal_euclidean_transformation *e = cam_graph_ptr_->get_edge(source_id, vertex_id);
00295     assert(e != 0) ;
00296 
00297     // compute and set extrinsic parameter
00298     vnl_double_3x3 K = cam->get_intrinsic();
00299     int num_views = cam->num_views();
00300 
00301     vcl_vector<vgl_h_matrix_3d<double> > trans_list(num_views);
00302     for (int j=0; j< num_views; j++){ // for each view
00303       trans_list[j] = compute_extrinsic(h_matrice_[i][j], K);
00304     }
00305 
00306     // store it into edge
00307     e->set_transformations(trans_list);
00308   }
00309 
00310   return 0;
00311 }

Generated on Thu Jan 10 14:53:50 2008 for contrib/brl/bmvl/bcal by  doxygen 1.4.4