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/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
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++) {
00052 bcal_zhang_camera_node *cam = cam_graph_ptr_->get_vertex_from_pos(i);
00053 assert(cam);
00054
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++){
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
00068 int num_camera = cam_graph_ptr_->num_vertice();
00069 clear(); h_matrice_.resize(num_camera);
00070 num_views_.resize(num_camera);
00071
00072
00073 for (int i=0; i<num_camera; i++){
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
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
00120 compute_homography();
00121
00122
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
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
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){
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
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
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215 vnl_double_3x3 A_inv = vnl_inverse(A);
00216
00217
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
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
00231 vnl_double_3 r1 = l * A_inv * h1;
00232
00233
00234 vnl_double_3 r2 = l * A_inv * h2;
00235
00236
00237
00238
00239
00240
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
00251
00252 vnl_double_3x3 R = get_closest_rotation(Q);
00253
00254
00255 vnl_double_3 t = l * A_inv * h3;
00256
00257
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
00264
00265
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++){
00290
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
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++){
00304 trans_list[j] = compute_extrinsic(h_matrice_[i][j], K);
00305 }
00306
00307
00308 e->set_transformations(trans_list);
00309 }
00310
00311 return 0;
00312 }