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

Generated on Fri Aug 29 05:23:54 2008 for contrib/brl/bmvl/bcal by  doxygen 1.5.1