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