00001
00002
00003
00004 #include "bcal_zhang_linear_calibrate.h"
00005 #include <vnl/vnl_inverse.h>
00006 #include <vnl/vnl_double_3.h>
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
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++) {
00051 bcal_zhang_camera_node *cam = cam_graph_ptr_->get_vertex_from_pos(i);
00052 assert(cam);
00053
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++){
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
00067 int num_camera = cam_graph_ptr_->num_vertice();
00068 clear(); h_matrice_.resize(num_camera);
00069 num_views_.resize(num_camera);
00070
00071
00072 for (int i=0; i<num_camera; i++){
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
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
00119 compute_homography();
00120
00121
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
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
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){
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
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
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214 vnl_double_3x3 A_inv = vnl_inverse(A);
00215
00216
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
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
00230 vnl_double_3 r1 = l * A_inv * h1;
00231
00232
00233 vnl_double_3 r2 = l * A_inv * h2;
00234
00235
00236
00237
00238
00239
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
00250
00251 vnl_double_3x3 R = get_closest_rotation(Q);
00252
00253
00254 vnl_double_3 t = l * A_inv * h3;
00255
00256
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
00263
00264
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++){
00289
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
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++){
00303 trans_list[j] = compute_extrinsic(h_matrice_[i][j], K);
00304 }
00305
00306
00307 e->set_transformations(trans_list);
00308 }
00309
00310 return 0;
00311 }