00001
00002 #include "vmal_rectifier.h"
00003
00004
00005
00006 #include <vmal/vmal_convert_vtol.h>
00007 #include <vcl_cmath.h>
00008 #include <vbl/vbl_bounding_box.h>
00009 #include <vnl/algo/vnl_svd.h>
00010 #include <vnl/vnl_inverse.h>
00011 #include <vnl/algo/vnl_determinant.h>
00012 #include <vnl/vnl_vector.h>
00013
00014 #include <mvl/FMatrix.h>
00015 #include <mvl/FMatrixComputeLinear.h>
00016 #include <mvl/FMatrixComputeRANSAC.h>
00017 #include <mvl/FMatrixComputeMLESAC.h>
00018 #include <mvl/FMatrixComputeRobust.h>
00019 #include <vil/vil_bilin_interp.h>
00020
00021 vmal_rectifier::vmal_rectifier()
00022 {
00023 lines0_p_=NULL;
00024 lines0_q_=NULL;
00025 lines1_p_=NULL;
00026 lines1_q_=NULL;
00027 points0_=NULL;
00028 points1_=NULL;
00029 rectL = new vil_image_view<vxl_byte>(1,1,1);
00030 rectR = new vil_image_view<vxl_byte>(1,1,1);
00031
00032
00033 }
00034
00035 vmal_rectifier::vmal_rectifier(vmal_multi_view_data_vertex_sptr mvd_vertex,
00036 vmal_multi_view_data_edge_sptr mvd_edge,
00037 int ima_height, int ima_width) :
00038 is_f_compute_(false)
00039 {
00040 lines0_p_=NULL;
00041 lines0_q_=NULL;
00042 lines1_p_=NULL;
00043 lines1_q_=NULL;
00044 points0_=NULL;
00045 rectL = new vil_image_view<vxl_byte>(1,1,1);
00046 rectR = new vil_image_view<vxl_byte>(1,1,1);
00047
00048 if ((mvd_vertex->get_nb_views()>1) && (mvd_edge->get_nb_views()>1))
00049 {
00050
00051 vcl_vector<vtol_edge_2d_sptr> tmp_lines0;
00052 vcl_vector<vtol_edge_2d_sptr> tmp_lines1;
00053
00054 mvd_edge->get(0,1,tmp_lines0,tmp_lines1);
00055 numpoints_=tmp_lines0.size();
00056
00057 convert_lines_double_3(tmp_lines0, lines0_p_, lines0_q_);
00058 convert_lines_double_3(tmp_lines1, lines1_p_, lines1_q_);
00059
00060 vcl_vector<vtol_vertex_2d_sptr> tmp_points0;
00061 vcl_vector<vtol_vertex_2d_sptr> tmp_points1;
00062
00063 mvd_vertex->get(0,1,tmp_points0,tmp_points1);
00064
00065 convert_points_double_3(tmp_points0, points0_);
00066 convert_points_double_3(tmp_points1, points1_);
00067 height_=ima_height;
00068 width_=ima_width;
00069 }
00070 }
00071
00072
00073
00074 vmal_rectifier::vmal_rectifier(vcl_vector< vnl_vector<double> >* pts0,
00075 vcl_vector< vnl_vector<double> >* pts1,
00076 int ima_height, int ima_width) :
00077 lines0_p_(0), lines0_q_(0), lines1_p_(0), lines1_q_(0),
00078 numpoints_(pts0->size()), height_(ima_height), width_(ima_width),
00079 is_f_compute_(false)
00080 {
00081 rectL = new vil_image_view<vxl_byte>(1,1,1);
00082 rectR = new vil_image_view<vxl_byte>(1,1,1);
00083
00084
00085 points0_ = new vnl_double_3[numpoints_];
00086 points1_ = new vnl_double_3[numpoints_];
00087 vcl_vector< vnl_vector<double> >::iterator vit0 = pts0->begin();
00088 vcl_vector< vnl_vector<double> >::iterator vit1 = pts1->begin();
00089 for (int i=0; i<numpoints_; ++i,++vit0,++vit1)
00090 {
00091 points0_[i][0] = (*vit0)[0];
00092 points0_[i][1] = (*vit0)[1];
00093 points0_[i][2] = 1.0;
00094 points1_[i][0] = (*vit1)[0];
00095 points1_[i][1] = (*vit1)[1];
00096 points1_[i][2] = 1.0;
00097 }
00098 }
00099
00100
00101 vmal_rectifier::~vmal_rectifier()
00102 {
00103 delete [] points0_;
00104 delete [] points1_;
00105 delete [] lines0_p_;
00106 delete [] lines0_q_;
00107 delete [] lines1_p_;
00108 delete [] lines1_q_;
00109 delete rectL;
00110 delete rectR;
00111 }
00112
00113 void vmal_rectifier::rectification_matrix(vnl_double_3x3& H0,
00114 vnl_double_3x3& H1)
00115 {
00116 if (!is_f_compute_)
00117 {
00118 is_f_compute_=true;
00119 vcl_vector<HomgPoint2D> v_points0;
00120 vcl_vector<HomgPoint2D> v_points1;
00121 for (int i=0;i<numpoints_;i++)
00122 {
00123 HomgPoint2D tmp_point0(points0_[i][0],points0_[i][1]);
00124 HomgPoint2D tmp_point1(points1_[i][0],points1_[i][1]);
00125 v_points0.push_back(tmp_point0);
00126 v_points1.push_back(tmp_point1);
00127 }
00128
00129 FMatrixComputeLinear tmp_fcom(true,true);
00130 FMatrix tmp_f;
00131 tmp_fcom.compute(v_points0,v_points1,& tmp_f);
00132 tmp_f.get(&F12_.as_ref().non_const());
00133
00134 vcl_cout << "Fundamental Matrix:\n" << tmp_f << vcl_endl;
00135
00136 HomgPoint2D epi1;
00137 HomgPoint2D epi2;
00138
00139 tmp_f.get_epipoles (&epi1, &epi2);
00140 double x1,y1;
00141 double x2,y2;
00142 epi1.get_nonhomogeneous(x1,y1);
00143 epi2.get_nonhomogeneous(x2,y2);
00144
00145 vnl_double_3 tmp_epi1;
00146 tmp_epi1[0]=x1;
00147 tmp_epi1[1]=y1;
00148 tmp_epi1[2]=1.0;
00149
00150 vnl_double_3 tmp_epi2;
00151 tmp_epi2[0]=x2;
00152 tmp_epi2[1]=y2;
00153 tmp_epi2[2]=1.0;
00154
00155 epipoles_.push_back(tmp_epi1);
00156 epipoles_.push_back(tmp_epi2);
00157 }
00158 bool affine=false;
00159 int out_height;
00160 int out_width;
00161 int sweeti=(int)(width_/2);
00162 int sweetj=(int)(height_/2);
00163
00164 compute_joint_epipolar_transform_new(
00165 points0_,
00166 points1_,
00167 numpoints_,
00168 H0_, H1_,
00169 height_, width_,
00170 out_height, out_width,
00171 sweeti, sweetj,
00172 affine);
00173 H0=H0_;
00174 H1=H1_;
00175
00176 }
00177
00178
00179
00180
00181
00182 void vmal_rectifier::set_tritensor(TriTensor &tri)
00183 {
00184
00185
00186 is_f_compute_=true;
00187 tritensor_=tri;
00188
00189 HomgPoint2D epi12=tri.get_epipole_12();
00190 FMatrix F12(tri.get_fmatrix_12());
00191
00192 double x,y;
00193 epi12.get_nonhomogeneous(x,y);
00194
00195 vnl_double_3 tmp_epi;
00196 tmp_epi[0]=x;
00197 tmp_epi[1]=y;
00198 tmp_epi[2]=1.0;
00199
00200 epipoles_.push_back(tmp_epi);
00201 F12.get(&F12_.as_ref().non_const());
00202 }
00203
00204 void vmal_rectifier::compute_joint_epipolar_transform_new (
00205 vnl_double_3* points0,
00206 vnl_double_3* points1,
00207 int numpoints,
00208 vnl_double_3x3 &H0, vnl_double_3x3 &H1,
00209 int , int ,
00210 int & , int & ,
00211 double sweeti, double sweetj,
00212 bool affine
00213 )
00214 {
00215
00216 compute_initial_joint_epipolar_transforms (points0, points1, numpoints,
00217 H0, H1, sweeti, sweetj, affine);
00218
00219
00220 apply_affine_correction (points0, points1, numpoints, H0, H1);
00221 #if 0
00222
00223 center_overlap_region (H0, im1_roi, H1, im2_roi, output_roi);
00224 #endif
00225
00226
00227
00228
00229
00230
00231 conditional_rectify_rotate180 (H0, H1);
00232 #if 0
00233
00234 conditional_rectify_rotate180 (output_roi, H0, H1);
00235 #endif
00236 vcl_cerr << "vmal_rectifier::compute_joint_epipolar_transform_new() not yet fully implemented\n";
00237 }
00238
00239 void vmal_rectifier::compute_initial_joint_epipolar_transforms (
00240 vnl_double_3* ,
00241 vnl_double_3* ,
00242 int ,
00243 vnl_double_3x3 &H0, vnl_double_3x3 &H1,
00244 double sweeti, double sweetj,
00245 bool
00246 )
00247 {
00248
00249
00250
00251 if (is_f_compute_)
00252 {
00253
00254
00255 if ( !compute_initial_joint_epipolar_transforms (F12_,sweeti, sweetj, H0, H1))
00256 {
00257
00258 vcl_cerr<<"Computation of epipolar transform failed\n";
00259 }
00260 }
00261 else
00262 {
00263 vcl_cerr << "vmal_rectifier::compute_initial_joint_epipolar_transforms() not yet fully implemented\n";
00264 #if 0
00265
00266 rhMatrix Q(3, 3);
00267
00268
00269 if (affine)
00270 {
00271
00272
00273 affine_solveQmatrix (u1, v1, u2, v2, numpoints, Q);
00274 checkQmatrix (u1, v1, u2, v2, numpoints, Q);
00275 }
00276 else
00277 {
00278 solveQmatrix (u1, v1, u2, v2, numpoints, Q);
00279 refine_Q_matrix (u1, v1, u2, v2, numpoints, Q);
00280 checkQmatrix (u1, v1, u2, v2, numpoints, Q);
00281 }
00282
00283
00284 if ( !compute_initial_joint_epipolar_transforms (Q, sweeti, sweetj, H0, H1))
00285 {
00286
00287 error_message ("Computation of epipolar transform failed\n");
00288 bail_out (2);
00289 }
00290 #endif
00291 }
00292 }
00293
00294
00295
00296
00297
00298 int vmal_rectifier::compute_initial_joint_epipolar_transforms (
00299 const vnl_double_3x3 &Q,
00300 double ci, double cj,
00301 vnl_double_3x3 &H0,
00302 vnl_double_3x3 &H1
00303 )
00304 {
00305
00306 vnl_double_3 p1 = epipoles_[0];
00307
00308
00309
00310
00311 H0[0][0] = 1.0; H0[0][1] = 0.0; H0[0][2] = -ci;
00312 H0[1][0] = 0.0; H0[1][1] = 1.0; H0[1][2] = -cj;
00313 H0[2][0] = 0.0; H0[2][1] = 0.0; H0[2][2] = 1.0;
00314
00315
00316 p1 = H0 * p1;
00317
00318
00319 if (p1[0] == 0.0 && p1[1] == 0.0)
00320 {
00321 vcl_cerr<<"Error : Epipole is at image center\n";
00322 return 0;
00323 }
00324
00325
00326 double theta = vcl_atan2 (p1[1], p1[0]);
00327 double c = vcl_cos (theta);
00328 double s = vcl_sin (theta);
00329
00330 vnl_double_3x3 T;
00331
00332 T[0][0] = c; T[0][1] = s; T[0][2] = 0.0;
00333 T[1][0] = -s; T[1][1] = c; T[1][2] = 0.0;
00334 T[2][0] = 0.0; T[2][1] = 0.0; T[2][2] = 1.0;
00335
00336
00337 H0 = T * H0;
00338 p1 = T * p1;
00339 vnl_double_3 ep1=H0*epipoles_[0];
00340
00341
00342 double x = p1[2]/p1[0];
00343
00344 vnl_double_3x3 E;
00345 E[0][0] = 1.0; E[0][1] = 0.0; E[0][2] = 0.0;
00346 E[1][0] = 0.0; E[1][1] = 1.0; E[1][2] = 0.0;
00347 E[2][0] = -x; E[2][1] = 0.0; E[2][2] = 1.0;
00348
00349
00350 H0 = E * H0;
00351 ep1=H0*epipoles_[0];
00352 vcl_cout << "vmal_rectifier::c_i_j_e_t: epipole[0] at infinity = " << ep1 << vcl_endl;
00353
00354 H1 = matching_transform (Q.transpose(), H0);
00355
00356 vnl_double_3 ep2=H1*epipoles_[1];
00357 vcl_cout << "vmal_rectifier::c_i_j_e_t: epipole[1] at infinity = " << ep2 << vcl_endl;
00358
00359
00360 return 1;
00361 }
00362
00363 vnl_double_3x3 vmal_rectifier::matching_transform (
00364 const vnl_double_3x3 &Q,
00365 const vnl_double_3x3 &H1
00366 )
00367 {
00368
00369
00370 vnl_double_3x3 S, M;
00371 factor_Q_matrix_SR (Q, M, S);
00372
00373
00374 vnl_double_3x3 H0 = H1 * M;
00375 return H0;
00376 }
00377
00378
00379 void vmal_rectifier::factor_Q_matrix_SR (
00380 const vnl_double_3x3 &Q,
00381 vnl_double_3x3 &R,
00382 vnl_double_3x3 &S)
00383 {
00384 double r, s;
00385
00386
00387
00388 vnl_svd<double> SVD(Q);
00389 vnl_double_3x3 U(SVD.U());
00390 vnl_double_3x3 V(SVD.V());
00391
00392 vnl_double_3x3 E(0.0);
00393 vnl_double_3x3 Z(0.0);
00394 E[1][0]=E[2][2]=1;
00395 E[0][1]=-1;
00396 Z[0][1]=1;Z[1][0]=-1;
00397
00398 r = SVD.W(0);
00399 s = SVD.W(1);
00400
00401
00402 vnl_double_3x3 Vt = V.transpose();
00403 vnl_double_3x3 Ut = U.transpose();
00404
00405
00406 vnl_double_3x3 RS;
00407 RS[0][0] = r; RS[0][1] = 0; RS[0][2] = 0;
00408 RS[1][0] = 0; RS[1][1] = s; RS[1][2] = 0;
00409 RS[2][0] = 0; RS[2][1] = 0; RS[2][2] = s;
00410
00411
00412
00413 R=(U * E * RS * Vt);
00414
00415
00416 S=(U * Z * Ut);
00417 }
00418
00419 vnl_double_3x3 vmal_rectifier::affine_correction (
00420 vnl_double_3* points0,
00421 vnl_double_3* points1,
00422 int numpoints,
00423 const vnl_double_3x3 &H0,
00424 const vnl_double_3x3 &H1)
00425 {
00426
00427
00428
00429
00430 vnl_matrix<double> E(numpoints, 3);
00431 vnl_vector<double> x(numpoints);
00432
00433 for (int i=0; i<numpoints; i++)
00434 {
00435
00436 vnl_double_3 u2hat = H1 * points1[i];
00437 double uu2 = u2hat[0]/u2hat[2];
00438 double vv2 = u2hat[1]/u2hat[2];
00439
00440 vnl_double_3 u1hat = H0 * points0[i];
00441 double uu1 = u1hat[0]/u1hat[2];
00442
00443
00444 E[i][0] = uu2;
00445 E[i][1] = vv2;
00446 E[i][2] = 1.0;
00447 x[i] = uu1;
00448 }
00449
00450
00451 vnl_svd<double> SVD(E);
00452 vnl_double_3 a=SVD.solve(x);
00453
00454
00455
00456 vnl_double_3x3 A;
00457 A.set_identity();
00458 A[0][0] = a[0]; A[0][1] = a[1]; A[0][2] = a[2];
00459
00460
00461 return A;
00462 }
00463
00464 void vmal_rectifier::apply_affine_correction (
00465 vnl_double_3* points0,
00466 vnl_double_3* points1,
00467 int numpoints,
00468 vnl_double_3x3 &H0, vnl_double_3x3 &H1
00469 )
00470 {
00471
00472 vnl_double_3x3 A = affine_correction (points0, points1, numpoints, H0, H1);
00473
00474
00475 H1 = A * H1;
00476
00477
00478 if (vnl_determinant (H1) < 0.0) H1 = -H1;
00479 }
00480
00481 void vmal_rectifier::rectify_rotate90 (
00482 int &height, int &width,
00483 vnl_double_3x3 &H0,
00484 vnl_double_3x3 &H1
00485 )
00486 {
00487
00488
00489
00490
00491 vnl_double_3x3 R;
00492
00493
00494
00495
00496 R[0][0] = 0.0; R[0][1] = -1.0; R[0][2] = 0.0;
00497 R[1][0] = 1.0; R[1][1] = 0.0; R[1][2] = 0.0;
00498 R[2][0] = 0.0; R[2][1] = 0.0; R[2][2] = 1.0;
00499
00500
00501 H0 = R * H0;
00502 H1 = R * H1;
00503
00504
00505 int t = width; width = height; height = t;
00506 }
00507
00508
00509
00510 void vmal_rectifier::conditional_rectify_rotate180 (
00511 vnl_double_3x3 &H0,
00512 vnl_double_3x3 &H1
00513 )
00514 {
00515
00516
00517 if ( H1[0][0]/H1[2][2] > 0)
00518 return;
00519
00520
00521
00522 vnl_double_3x3 R;
00523
00524 R[0][0] = -1.0; R[0][1] = 0.0; R[0][2] = 0.0;
00525 R[1][0] = 0.0; R[1][1] = -1.0; R[1][2] = 0.0;
00526 R[2][0] = 0.0; R[2][1] = 0.0; R[2][2] = 1.0;
00527
00528
00529 H0 = R * H0;
00530 H1 = R * H1;
00531 }
00532
00533
00534
00535
00536
00537
00538 void vmal_rectifier::resample(vnl_double_3x3 H0, vnl_double_3x3 H1,
00539 vil_image_view<vxl_byte> imgL,
00540 vil_image_view<vxl_byte> imgR)
00541 {
00542
00543 vnl_double_3 ipointL;
00544 vnl_double_3 opointL;
00545 vnl_double_3 ipointR;
00546 vnl_double_3 opointR;
00547 vbl_bounding_box<double,2> boxL;
00548
00549 int img_h = imgL.nj();
00550 int img_w = imgL.ni();
00551 for (int i=0; i<img_h; i++)
00552 {
00553 for (int j=0; j<img_w; j++)
00554 {
00555 ipointL[0]=j; ipointL[1]=i; ipointL[2]=1.0;
00556 ipointR[0]=j; ipointR[1]=i; ipointR[2]=1.0;
00557 opointL = H0 * ipointL;
00558 opointR = H1 * ipointR;
00559 opointL /= opointL[2];
00560 opointR /= opointR[2];
00561
00562 boxL.update(opointL[0],opointL[1]);
00563
00564 }
00565 }
00566
00567
00568
00569
00570
00571
00572 vnl_double_3x3 H0inv = vnl_inverse(H0);
00573 vnl_double_3x3 H1inv = vnl_inverse(H1);
00574
00575 int img2_h = int(boxL.max()[1] - boxL.min()[1] + 1);
00576 int img2_w = int(boxL.max()[0] - boxL.min()[0] + 1);
00577 int planes=1;
00578
00579
00580 rectL->set_size(img2_w,img2_h,planes);
00581 rectR->set_size(img2_w,img2_h,planes);
00582
00583 for (int i=0; i<img2_h; i++)
00584 {
00585 for (int j=0; j<img2_w; j++)
00586 {
00587
00588 opointL[0]=j+boxL.min()[0]; opointL[1]=i+boxL.min()[1]; opointL[2]=1.0;
00589
00590
00591 ipointL = H0inv * opointL; ipointL /= ipointL[2];
00592 ipointR = H1inv * opointL; ipointR /= ipointR[2];
00593
00594
00595 if (ipointL[0] >= 0 && ipointL[0] < img_w-1 &&
00596 ipointL[1] >= 0 && ipointL[1] < img_h-1)
00597 {
00598
00599 (*rectL)(j,i) = (vxl_byte)vil_bilin_interp(imgL,ipointL[0],ipointL[1],0);
00600 }
00601 else
00602 (*rectL)(j,i) = vxl_byte(0);
00603
00604 if (ipointR[0] >= 0 && ipointR[0] < img_w-1 &&
00605 ipointR[1] >= 0 && ipointR[1] < img_h-1)
00606 {
00607
00608 (*rectR)(j,i) = (vxl_byte)vil_bilin_interp(imgR,ipointR[0],ipointR[1],0);
00609 }
00610 else
00611 (*rectR)(j,i) = vxl_byte(0);
00612 }
00613 }
00614 }