00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "viso_stereo.h"
00023 #include "P3p.h"
00024 #include <eigen3/Eigen/Dense>
00025 #include "ceres/ceres.h"
00026 #include "glog/logging.h"
00027
00028 #include <TooN/TooN.h>
00029 #include <algorithm>
00030
00031 using ceres::AutoDiffCostFunction;
00032 using ceres::CostFunction;
00033 using ceres::Problem;
00034 using ceres::Solver;
00035 using ceres::Solve;
00036 using ceres::CauchyLoss;
00037 using ceres::ArctanLoss;
00038 using namespace std;
00039
00040
00041 struct ExponentialResidual {
00042 ExponentialResidual(double u, double v, double xp, double yp ,double zp)
00043 : u_(u), v_(v), xp_(xp), yp_(yp), zp_(zp)
00044 {}
00045
00046 template <typename T> bool operator()(
00047 const T* const rx,
00048 const T* const ry,
00049 const T* const rz,
00050 const T* const tx,
00051 const T* const ty,
00052 const T* const tz,
00053 T* residual) const
00054 {
00055
00056 T sx = sin(rx[0]); T cx = cos(rx[0]); T sy = sin(ry[0]);
00057 T cy = cos(ry[0]); T sz = sin(rz[0]); T cz = cos(rz[0]);
00058
00059
00060 T r00 = +cy*cz; T r01 = -cy*sz; T r02 = +sy;
00061 T r10 = +sx*sy*cz+cx*sz; T r11 = -sx*sy*sz+cx*cz; T r12 = -sx*cy;
00062 T r20 = -cx*sy*cz+sx*sz; T r21 = +cx*sy*sz+sx*cz; T r22 = +cx*cy;
00063
00064 T point_Predicted_x = r00*xp_ + r01*yp_ + r02*zp_ + tx[0];
00065 T point_Predicted_y = r10*xp_ + r11*yp_ + r12*zp_ + ty[0];
00066 T point_Predicted_z = r20*xp_ + r21*yp_ + r22*zp_ + tz[0];
00067
00068 T u_Predicted = 582.508667*point_Predicted_x/point_Predicted_z + 520.5;
00069 T v_Predicted = 582.508667*point_Predicted_y/point_Predicted_z + 506.5;
00070 residual[0] = (u_-u_Predicted);
00071 residual[1] = (v_-v_Predicted);
00072 return true;
00073 }
00074
00075 private:
00076 const double u_;
00077 const double v_;
00078 const double xp_;
00079 const double yp_;
00080 const double zp_;
00081 };
00082
00083 VisualOdometryStereo::VisualOdometryStereo (parameters param) : param(param), VisualOdometry(param) {
00084 rx_old = 0.0;
00085 ry_old = 0.0;
00086 rz_old = 0.0;
00087 tx_old = 0.0;
00088 ty_old = 0.0;
00089 tz_old = 0.0;
00090 matcher->setIntrinsics(param.calib.f,param.calib.cu,param.calib.cv,param.base);
00091 }
00092
00093 VisualOdometryStereo::~VisualOdometryStereo() {}
00094
00095 bool VisualOdometryStereo::process (uint8_t *I1,uint8_t *I2,int32_t* dims,bool replace) {
00096 matcher->pushBack(I1,I2,dims,replace);
00097 if (Tr_valid) matcher->matchFeatures(2,&Tr_delta);
00098 else matcher->matchFeatures(2);
00099 p_matched = matcher->getMatches();
00100 int n = p_matched.size();
00101 p_matched.clear();
00102 matcher->bucketFeatures(param.bucket.max_features,param.bucket.bucket_width,param.bucket.bucket_height);
00103 int width = param.bucket.bucket_width;
00104 int height = param.bucket.bucket_height;
00105 int number_of_matches = 350;
00106 while(n > number_of_matches)
00107 {
00108 matcher->bucketFeatures(param.bucket.max_features, width, height);
00109 n = matcher->getMatches().size();
00110 width++;
00111 height++;
00112 }
00113
00114 p_matched = matcher->getMatches();
00115 return updateMotion();
00116 }
00117
00118
00119 bool VisualOdometryStereo::justice2Matches(Matcher::p_match &m1,Matcher::p_match &m2)
00120 {
00121 double d1p = max(m1.u1p - m1.u2p,0.0001f);
00122 double d1c = max(m1.u1c - m1.u2c,0.0001f);
00123 double x1p = (m1.u1p-param.calib.cu)*param.base/d1p;
00124 double y1p = (m1.v1p-param.calib.cv)*param.base/d1p;
00125 double z1p = param.calib.f*param.base/d1p;
00126 double x1c = (m1.u1c-param.calib.cu)*param.base/d1c;
00127 double y1c = (m1.v1c-param.calib.cv)*param.base/d1c;
00128 double z1c = param.calib.f*param.base/d1c;
00129
00130 double d2p = max(m2.u1p - m2.u2p,0.0001f);
00131 double d2c = max(m2.u1c - m2.u2c,0.0001f);
00132 double x2p = (m2.u1p-param.calib.cu)*param.base/d2p;
00133 double y2p = (m2.v1p-param.calib.cv)*param.base/d2p;
00134 double z2p = param.calib.f*param.base/d2p;
00135 double x2c = (m2.u1c-param.calib.cu)*param.base/d2c;
00136 double y2c = (m2.v1c-param.calib.cv)*param.base/d2c;
00137 double z2c = param.calib.f*param.base/d2c;
00138
00139 double dist1 = sqrt(pow(x1p-x2p,2)+pow(y1p-y2p,2)+pow(z1p-z2p,2));
00140 double dist2 = sqrt(pow(x1c-x2c,2)+pow(y1c-y2c,2)+pow(z1c-z2c,2));
00141 double diff = fabs(dist1-dist2);
00142 if(diff< 0.25 && dist1<5.0)
00143 return true;
00144 else
00145 return false;
00146 }
00147
00148
00149 void VisualOdometryStereo::creatAdjMatrix(vector<Matcher::p_match>& p_matched,bool** &conn)
00150 {
00151 int size = p_matched.size();
00152 conn = new bool*[size];
00153 for (int i=0; i < size; i++) {
00154 conn[i] = new bool[size];
00155 memset(conn[i], 0, size * sizeof(bool));
00156 }
00157 for(int i=0;i<size;++i)
00158 for(int j=0;j<=i;++j)
00159 if(justice2Matches(p_matched[i],p_matched[j]))
00160 {
00161 conn[i][j]=true;
00162 conn[j][i]=true;
00163 }
00164 }
00165
00166
00167 vector<double> VisualOdometryStereo::estimateMotionMaxClique (vector<Matcher::p_match> p_matched)
00168 {
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310 int32_t N = p_matched.size();
00311 double rx=rx_old,ry=ry_old,rz=rz_old,tx=tx_old,ty=ty_old,tz=tz_old;
00312 Problem problem;
00313
00314
00315 vector<double> tr_delta;
00316 tr_delta.resize(6);
00317 vector<double> tr_delta_curr;
00318 tr_delta_curr.resize(6);
00319
00320 if (N<6)
00321 return vector<double>();
00322 bool** conn;
00323 int* qmax,qsize;
00324 creatAdjMatrix(p_matched,conn);
00325
00326 Maxclique md(conn,N);
00327 md.mcq(qmax, qsize);
00328
00329 std::vector<int32_t> inliers_maxclique;
00330 for (int i = 0; i < qsize; i++)
00331 inliers_maxclique.push_back(qmax[i]);
00332 bool success=true;
00333
00334 std::vector<Matcher::p_match> p_matched_maxclique;
00335 for(int i = 0; i<inliers_maxclique.size(); ++i)
00336 {
00337 p_matched_maxclique.push_back(p_matched[inliers_maxclique[i] ]);
00338 }
00339 int32_t N_ = p_matched_maxclique.size();
00340 p_matched.clear();
00341 p_matched = p_matched_maxclique;
00342 p_matched1 = p_matched_maxclique;
00343
00344 X = new double[N_];
00345 Y = new double[N_];
00346 Z = new double[N_];
00347 XC = new double[N_];
00348 YC = new double[N_];
00349 ZC = new double[N_];
00350 J = new double[4*N_*6];
00351 p_predict = new double[4*N_];
00352 p_observe = new double[4*N_];
00353 p_residual = new double[4*N_];
00354
00355 for (int32_t i=0; i<N_; i++) {
00356 double d = max(p_matched_maxclique[i].u1p - p_matched_maxclique[i].u2p,0.0001f);
00357 X[i] = (p_matched_maxclique[i].u1p-param.calib.cu)*param.base/d;
00358 Y[i] = (p_matched_maxclique[i].v1p-param.calib.cv)*param.base/d;
00359 Z[i] = param.calib.f*param.base/d;
00360 XC[i] = (p_matched_maxclique[i].u1c-param.calib.cu)*param.base/d;
00361 YC[i] = (p_matched_maxclique[i].v1c-param.calib.cv)*param.base/d;
00362 ZC[i] = param.calib.f*param.base/d;
00363 }
00364 inliers.clear();
00365
00366 for (int32_t k=0;k<param.ransac_iters;k++) {
00367
00368
00369 vector<int32_t> active = getRandomSample(N_,3);
00370
00371
00372 for (int32_t i=0; i<6; i++)
00373 tr_delta_curr[i] = 0;
00374
00375
00376 VisualOdometryStereo::result result = UPDATED;
00377 int32_t iter=0;
00378 while (result==UPDATED) {
00379 result = updateParameters(p_matched_maxclique,active,tr_delta_curr,1,1e-8);
00380 if (iter++ > 100 || result==CONVERGED)
00381 break;
00382 }
00383
00384 if (result==CONVERGED) {
00385 vector<int32_t> inliers_curr = getInlier(p_matched_maxclique,tr_delta_curr);
00386 if (inliers_curr.size()>inliers.size()) {
00387 inliers = inliers_curr;
00388 tr_delta = tr_delta_curr;
00389 }
00390 }
00391 }
00392 rx = tr_delta[0]; ry = tr_delta[1]; rz = tr_delta[2];
00393 tx = tr_delta[3]; ty = tr_delta[4]; tz = tr_delta[5];
00394 std::cout<<"inliers of MaxClique:\t"<<inliers.size()<<"\tp_matched N N_:"<<N<<" "<<N_<<"\t"<<(double)inliers.size()*100/N_<<std::endl;
00395
00396
00397 for(int i=0;i<inliers.size();++i)
00398 {
00399 problem.AddResidualBlock(
00400 new AutoDiffCostFunction<ExponentialResidual, 2, 1, 1,1,1,1,1>(
00401 new ExponentialResidual(p_matched_maxclique[inliers[i]].u1c,p_matched_maxclique[inliers[i]].v1c,X[inliers[i]],Y[inliers[i]],Z[inliers[i]])),
00402 new CauchyLoss(0.5),
00403
00404 &rx, &ry,&rz,&tx,&ty,&tz);
00405 }
00406
00407 Solver::Options options;
00408 options.max_num_iterations = 100;
00409 options.linear_solver_type = ceres::DENSE_QR;
00410 options.minimizer_progress_to_stdout = false;
00411
00412 Solver::Summary summary;
00413 Solve(options, &problem, &summary);
00414 if(summary.IsSolutionUsable()==false)
00415 {
00416 success = false;
00417 std::cout <<"UN CONVERGED!!!\n" <<summary.BriefReport() << "\n";
00418 }
00419
00420 tr_delta[0] = rx;
00421 tr_delta[1] = ry;
00422 tr_delta[2] = rz;
00423 tr_delta[3] = tx;
00424 tr_delta[4] = ty;
00425 tr_delta[5] = tz;
00426
00427 for (int i=0;i<N;i++)
00428 delete [] conn[i];
00429 delete [] conn;
00430 delete [] qmax;
00431
00432 delete[] X;
00433 delete[] Y;
00434 delete[] Z;
00435 delete[] XC;
00436 delete[] YC;
00437 delete[] ZC;
00438 delete[] J;
00439 delete[] p_predict;
00440 delete[] p_observe;
00441 delete[] p_residual;
00442
00443 if (success) return tr_delta;
00444 else return vector<double>();
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536 }
00537 vector<double> VisualOdometryStereo::estimateMotionLinear (vector<Matcher::p_match> p_matched)
00538 {
00539 if(p_matched.size()<6)
00540 return vector<double> ();
00541 TooN::Matrix<3,4> tr_delta,tr_delta_curr;
00542 tr_delta = TooN::Data(0,1,0,0,
00543 0,0,1,0,
00544 0,0,0,1);
00545 tr_delta_curr = TooN::Data(0,1,0,0,
00546 0,0,1,0,
00547 0,0,0,1);
00548
00549
00550 bool success = true;
00551
00552
00553 double width=0,height=0;
00554 for (vector<Matcher::p_match>::iterator it=p_matched.begin(); it!=p_matched.end(); it++) {
00555 if (it->u1c>width) width = it->u1c;
00556 if (it->v1c>height) height = it->v1c;
00557 }
00558 double min_dist = min(width,height)/3.0;
00559
00560
00561 int32_t N = p_matched.size();
00562 if (N<6)
00563 return vector<double>();
00564
00565
00566 X = new double[N];
00567 Y = new double[N];
00568 Z = new double[N];
00569 XC = new double[N];
00570 YC = new double[N];
00571 ZC = new double[N];
00572 J = new double[4*N*6];
00573 p_predict = new double[4*N];
00574 p_observe = new double[4*N];
00575 p_residual = new double[4*N];
00576
00577
00578 for (int32_t i=0; i<N; i++) {
00579 double d = max(p_matched[i].u1p - p_matched[i].u2p,0.0001f);
00580 X[i] = (p_matched[i].u1p-param.calib.cu)*param.base/d;
00581 Y[i] = (p_matched[i].v1p-param.calib.cv)*param.base/d;
00582 Z[i] = param.calib.f*param.base/d;
00583 XC[i] = (p_matched[i].u1c-param.calib.cu)*param.base/d;
00584 YC[i] = (p_matched[i].v1c-param.calib.cv)*param.base/d;
00585 ZC[i] = param.calib.f*param.base/d;
00586 }
00587
00588 inliers.clear();
00589
00590 for (int32_t k=0;k<param.ransac_iters;k++) {
00591
00592
00593 vector<int32_t> active = getRandomSample(N,3);
00594
00595
00596
00597
00598 VisualOdometryStereo::result result = UPDATED;
00599 result = updateParametersP3p(p_matched,active,tr_delta_curr,1,1e-6);
00600 if(result == CONVERGED)
00601 {
00602 vector<int32_t> inliers_curr = getInlier(p_matched,tr_delta_curr);
00603 if (inliers_curr.size()>inliers.size()) {
00604 inliers = inliers_curr;
00605 tr_delta = tr_delta_curr;
00606 }
00607 }
00608 }
00609
00610 vector<double> tr_delta_vec;
00611 tr_delta_vec.resize(6);
00612 tr_delta_vec[0] = tr_delta[2][2];
00613 tr_delta_vec[1] = tr_delta[2][1];
00614 tr_delta_vec[2] = tr_delta[1][1];
00615 tr_delta_vec[3] = tr_delta[0][0];
00616 tr_delta_vec[4] = tr_delta[0][1];
00617 tr_delta_vec[5] = tr_delta[0][2];
00618
00619
00620 std::cout<<"inliers of P3p:\t"<<inliers.size()<<"\tp_matched :\t"<<p_matched.size()<<"\t"<<(double)inliers.size()*100/p_matched.size()<<std::endl;
00621
00622 double rx=rx_old,ry=ry_old,rz=rz_old,tx=tx_old,ty=ty_old,tz=tz_old;
00623 rx = tr_delta_vec[0]; ry = tr_delta_vec[1]; rz = tr_delta_vec[2];
00624 tx = tr_delta_vec[3]; ty = tr_delta_vec[4]; tz = tr_delta_vec[5];
00625 Problem problem;
00626 for(int i=0;i<inliers.size();++i)
00627 {
00628 problem.AddResidualBlock(
00629 new AutoDiffCostFunction<ExponentialResidual, 2, 1, 1,1,1,1,1>(
00630 new ExponentialResidual(p_matched[inliers[i]].u1c,p_matched[inliers[i]].v1c,X[inliers[i]],Y[inliers[i]],Z[inliers[i]])),
00631 new CauchyLoss(2.0),
00632
00633 &rx, &ry,&rz,&tx,&ty,&tz);
00634 }
00635
00636 Solver::Options options;
00637 options.max_num_iterations = 20;
00638 options.linear_solver_type = ceres::DENSE_QR;
00639 options.minimizer_progress_to_stdout = false;
00640
00641 Solver::Summary summary;
00642 Solve(options, &problem, &summary);
00643 if(summary.IsSolutionUsable()==false)
00644 {
00645 success = false;
00646 std::cout <<"UN CONVERGED!!!\n" <<summary.BriefReport() << "\n";
00647 }
00648
00649 tr_delta_vec[0] = rx;
00650 tr_delta_vec[1] = ry;
00651 tr_delta_vec[2] = rz;
00652 tr_delta_vec[3] = tx;
00653 tr_delta_vec[4] = ty;
00654 tr_delta_vec[5] = tz;
00655
00656 p_matched1 = p_matched;
00657
00658 if (success) return tr_delta_vec;
00659 else return vector<double>();
00660 delete[] X;
00661 delete[] Y;
00662 delete[] Z;
00663 delete[] XC;
00664 delete[] YC;
00665 delete[] ZC;
00666 delete[] J;
00667 delete[] p_predict;
00668 delete[] p_observe;
00669 delete[] p_residual;
00670 return vector<double>();
00671 }
00672
00673 vector<double> VisualOdometryStereo::estimateMotion (vector<Matcher::p_match> p_matched) {
00674
00675
00676 bool success = true;
00677
00678
00679 double width=0,height=0;
00680 for (vector<Matcher::p_match>::iterator it=p_matched.begin(); it!=p_matched.end(); it++) {
00681 if (it->u1c>width) width = it->u1c;
00682 if (it->v1c>height) height = it->v1c;
00683 }
00684 double min_dist = min(width,height)/3.0;
00685
00686
00687 int32_t N = p_matched.size();
00688 if (N<6)
00689 return vector<double>();
00690 double rx=rx_old,ry=ry_old,rz=rz_old,tx=tx_old,ty=ty_old,tz=tz_old;
00691
00692 X = new double[N];
00693 Y = new double[N];
00694 Z = new double[N];
00695 XC = new double[N];
00696 YC = new double[N];
00697 ZC = new double[N];
00698 J = new double[4*N*6];
00699 p_predict = new double[4*N];
00700 p_observe = new double[4*N];
00701 p_residual = new double[4*N];
00702
00703
00704 for (int32_t i=0; i<N; i++) {
00705 double d = max(p_matched[i].u1p - p_matched[i].u2p,0.0001f);
00706 X[i] = (p_matched[i].u1p-param.calib.cu)*param.base/d;
00707 Y[i] = (p_matched[i].v1p-param.calib.cv)*param.base/d;
00708 Z[i] = param.calib.f*param.base/d;
00709 XC[i] = (p_matched[i].u1c-param.calib.cu)*param.base/d;
00710 YC[i] = (p_matched[i].v1c-param.calib.cv)*param.base/d;
00711 ZC[i] = param.calib.f*param.base/d;
00712 }
00713
00714
00715 vector<double> tr_delta;
00716 vector<double> tr_delta_curr;
00717 tr_delta_curr.resize(6);
00718
00719
00720 inliers.clear();
00721
00722
00723 for (int32_t k=0;k<param.ransac_iters;k++) {
00724
00725
00726 vector<int32_t> active = getRandomSample(N,3);
00727
00728
00729 for (int32_t i=0; i<6; i++)
00730 tr_delta_curr[i] = 0;
00731
00732
00733 VisualOdometryStereo::result result = UPDATED;
00734 int32_t iter=0;
00735 while (result==UPDATED) {
00736 result = updateParameters(p_matched,active,tr_delta_curr,1,1e-6);
00737 if (iter++ > 20 || result==CONVERGED)
00738 break;
00739 }
00740
00741 if (result==CONVERGED) {
00742 vector<int32_t> inliers_curr = getInlier(p_matched,tr_delta_curr);
00743 if (inliers_curr.size()>inliers.size()) {
00744 inliers = inliers_curr;
00745 tr_delta = tr_delta_curr;
00746 }
00747 }
00748 }
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770 rx = tr_delta[0]; ry = tr_delta[1]; rz = tr_delta[2];
00771 tx = tr_delta[3]; ty = tr_delta[4]; tz = tr_delta[5];
00772 std::cout<<"inliers of newton-gauss:\t"<<inliers.size()<<"\tp_matched :\t"<<p_matched.size()<<"\t"<<(double)inliers.size()*100/p_matched.size()<<std::endl;
00773 Problem problem;
00774
00775 for(int i=0;i<inliers.size();++i)
00776 {
00777 problem.AddResidualBlock(
00778 new AutoDiffCostFunction<ExponentialResidual, 2, 1, 1,1,1,1,1>(
00779 new ExponentialResidual(p_matched[inliers[i]].u1c,p_matched[inliers[i]].v1c,X[inliers[i]],Y[inliers[i]],Z[inliers[i]])),
00780 new CauchyLoss(0.5),
00781
00782 &rx, &ry,&rz,&tx,&ty,&tz);
00783 }
00784
00785 Solver::Options options;
00786 options.max_num_iterations = 100;
00787 options.linear_solver_type = ceres::DENSE_QR;
00788 options.minimizer_progress_to_stdout = false;
00789
00790 Solver::Summary summary;
00791 Solve(options, &problem, &summary);
00792 if(summary.IsSolutionUsable()==false)
00793 {
00794 success = false;
00795 std::cout <<"UN CONVERGED!!!\n" <<summary.BriefReport() << "\n";
00796 }
00797
00798 tr_delta[0] = rx;
00799 tr_delta[1] = ry;
00800 tr_delta[2] = rz;
00801 tr_delta[3] = tx;
00802 tr_delta[4] = ty;
00803 tr_delta[5] = tz;
00804
00805
00806 delete[] X;
00807 delete[] Y;
00808 delete[] Z;
00809 delete[] XC;
00810 delete[] YC;
00811 delete[] ZC;
00812 delete[] J;
00813 delete[] p_predict;
00814 delete[] p_observe;
00815 delete[] p_residual;
00816
00817 p_matched1 = p_matched;
00818
00819 if (success) return tr_delta;
00820 else return vector<double>();
00821 }
00822
00823 vector<int32_t> VisualOdometryStereo::getInlier(vector<Matcher::p_match> &p_matched,vector<double> &tr) {
00824
00825
00826 vector<int32_t> active;
00827 for (int32_t i=0; i<(int32_t)p_matched.size(); i++)
00828 active.push_back(i);
00829
00830
00831 computeObservations(p_matched,active);
00832 computeResidualsAndJacobian(tr,active);
00833
00834
00835 vector<int32_t> inliers;
00836 for (int32_t i=0; i<(int32_t)p_matched.size(); i++)
00837 if (pow(p_observe[4*i+0]-p_predict[4*i+0],2)+pow(p_observe[4*i+1]-p_predict[4*i+1],2) +
00838 pow(p_observe[4*i+2]-p_predict[4*i+2],2)+pow(p_observe[4*i+3]-p_predict[4*i+3],2) < param.inlier_threshold*param.inlier_threshold)
00839 inliers.push_back(i);
00840 return inliers;
00841 }
00842
00843 vector<int32_t> VisualOdometryStereo::getInlier(vector<Matcher::p_match> &p_matched,TooN::Matrix<3,4> &tr)
00844 {
00845
00846 vector<int32_t> active;
00847 for (int32_t i=0; i<(int32_t)p_matched.size(); i++)
00848 active.push_back(i);
00849
00850
00851 computeObservations(p_matched,active);
00852 computeResidualsAndJacobianP3p(tr,active);
00853
00854
00855 vector<int32_t> inliers;
00856 for (int32_t i=0; i<(int32_t)p_matched.size(); i++)
00857 if (pow(p_observe[4*i+0]-p_predict[4*i+0],2)+pow(p_observe[4*i+1]-p_predict[4*i+1],2) +
00858 pow(p_observe[4*i+2]-p_predict[4*i+2],2)+pow(p_observe[4*i+3]-p_predict[4*i+3],2) < param.inlier_threshold*param.inlier_threshold)
00859 inliers.push_back(i);
00860 return inliers;
00861 }
00862 VisualOdometryStereo::result VisualOdometryStereo::updateParametersP3p(vector<Matcher::p_match> &p_matched,vector<int32_t> &active,TooN::Matrix<3,4> &tr,double step_size,double eps)
00863 {
00864 if(active.size()!=3)
00865 return FAILED;
00866 TooN::Matrix<3,3> features;
00867 TooN::Matrix<3,3> worldPoints;
00868 TooN::Matrix<3,16> solutions;
00869 for(int i=0;i<3;++i)
00870 {
00871 double normPc = sqrt(pow(X[active[i]],2)+pow(Y[active[i]],2)+pow(Z[active[i]],2));
00872 worldPoints[0][i] = XC[active[i]];
00873 worldPoints[1][i] = YC[active[i]];
00874 worldPoints[2][i] = ZC[active[i]];
00875
00876 features[0][i] = X[active[i]]/normPc;
00877 features[1][i] = Y[active[i]]/normPc;
00878 features[2][i] = Z[active[i]]/normPc;
00879 }
00880 P3p myP3p;
00881 if(myP3p.computePoses(features,worldPoints,solutions) != 0)
00882 return FAILED;
00883 for(int i=0;i<4;++i)
00884 {
00885 if(fabs(solutions[0][4*i])<0.3 && fabs(solutions[1][4*i])<0.3 && fabs(solutions[2][4*i])<0.3)
00886 {
00887 tr = solutions.slice(0,4*i,3,4);
00888
00889
00890 return CONVERGED;
00891 }
00892 }
00893 return FAILED;
00894 }
00895 VisualOdometryStereo::result VisualOdometryStereo::updateParametersLinear(vector<Matcher::p_match> &p_matched,vector<int32_t> &active,vector<double> &tr,double step_size,double eps)
00896 {
00897
00898
00899
00900
00901
00902
00903
00904
00905
00906
00907
00908
00909
00910
00911
00912
00913
00914
00915
00916
00917
00918
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955
00956
00957
00958
00959
00960
00961
00962
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990
00991 }
00992
00993 VisualOdometryStereo::result VisualOdometryStereo::updateParameters(vector<Matcher::p_match> &p_matched,vector<int32_t> &active,vector<double> &tr,double step_size,double eps) {
00994
00995
00996 if (active.size()<3)
00997 return FAILED;
00998
00999
01000 computeObservations(p_matched,active);
01001 computeResidualsAndJacobian(tr,active);
01002
01003 Matrix A(6,6);
01004 Matrix B(6,1);
01005
01006 for (int32_t m=0; m<6; m++) {
01007 for (int32_t n=0; n<6; n++) {
01008 double a = 0;
01009 for (int32_t i=0; i<4*(int32_t)active.size(); i++) {
01010 a += J[i*6+m]*J[i*6+n];
01011 }
01012 A.val[m][n] = a;
01013 }
01014 double b = 0;
01015 for (int32_t i=0; i<4*(int32_t)active.size(); i++) {
01016 b += J[i*6+m]*(p_residual[i]);
01017 }
01018 B.val[m][0] = b;
01019 }
01020
01021
01022 if (B.solve(A)) {
01023 bool converged = true;
01024 for (int32_t m=0; m<6; m++) {
01025 tr[m] += step_size*B.val[m][0];
01026 if (fabs(B.val[m][0])>eps)
01027 converged = false;
01028 }
01029 if (converged)
01030 return CONVERGED;
01031 else
01032 return UPDATED;
01033 } else {
01034 return FAILED;
01035 }
01036 }
01037
01038 void VisualOdometryStereo::computeObservations(vector<Matcher::p_match> &p_matched,vector<int32_t> &active) {
01039
01040
01041
01042 for (int32_t i=0; i<(int32_t)active.size(); i++) {
01043 p_observe[4*i+0] = p_matched[active[i]].u1c;
01044 p_observe[4*i+1] = p_matched[active[i]].v1c;
01045 p_observe[4*i+2] = p_matched[active[i]].u2c;
01046 p_observe[4*i+3] = p_matched[active[i]].v2c;
01047 }
01048 }
01049
01050 void VisualOdometryStereo::computeResidualsAndJacobianP3p(TooN::Matrix<3,4> &tr,vector<int32_t> &active)
01051 {
01052
01053 double tx = tr[0][0]; double ty = tr[1][0]; double tz = tr[2][0];
01054
01055
01056 double r00 = tr[0][1]; double r01 = tr[0][2]; double r02 = tr[0][3];
01057 double r10 = tr[1][1]; double r11 = tr[1][2]; double r12 = tr[1][3];
01058 double r20 = tr[2][1]; double r21 = tr[2][2]; double r22 = tr[2][3];
01059
01060
01061 double X1p,Y1p,Z1p;
01062 double X1c,Y1c,Z1c,X2c;
01063 double X1cd,Y1cd,Z1cd;
01064
01065
01066 for (int32_t i=0; i<(int32_t)active.size(); i++) {
01067
01068
01069 X1p = X[active[i]];
01070 Y1p = Y[active[i]];
01071 Z1p = Z[active[i]];
01072
01073
01074 X1c = r00*X1p+r01*Y1p+r02*Z1p+tx;
01075 Y1c = r10*X1p+r11*Y1p+r12*Z1p+ty;
01076 Z1c = r20*X1p+r21*Y1p+r22*Z1p+tz;
01077
01078
01079
01080 double weight = 1.0;
01081 if (param.reweighting)
01082 weight = 1.0/(fabs(p_observe[4*i+0]-param.calib.cu)/fabs(param.calib.cu) + 0.05);
01083
01084
01085 X2c = X1c-param.base;
01086
01087
01088
01089
01090 p_predict[4*i+0] = param.calib.f*X1c/Z1c+param.calib.cu;
01091 p_predict[4*i+1] = param.calib.f*Y1c/Z1c+param.calib.cv;
01092 p_predict[4*i+2] = param.calib.f*X2c/Z1c+param.calib.cu;
01093 p_predict[4*i+3] = param.calib.f*Y1c/Z1c+param.calib.cv;
01094
01095
01096 p_residual[4*i+0] = weight*(p_observe[4*i+0]-p_predict[4*i+0]);
01097 p_residual[4*i+1] = weight*(p_observe[4*i+1]-p_predict[4*i+1]);
01098 p_residual[4*i+2] = weight*(p_observe[4*i+2]-p_predict[4*i+2]);
01099 p_residual[4*i+3] = weight*(p_observe[4*i+3]-p_predict[4*i+3]);
01100 }
01101 }
01102
01103 void VisualOdometryStereo::computeResidualsAndJacobian(vector<double> &tr,vector<int32_t> &active) {
01104
01105
01106 double rx = tr[0]; double ry = tr[1]; double rz = tr[2];
01107 double tx = tr[3]; double ty = tr[4]; double tz = tr[5];
01108
01109
01110 double sx = sin(rx); double cx = cos(rx); double sy = sin(ry);
01111 double cy = cos(ry); double sz = sin(rz); double cz = cos(rz);
01112
01113
01114 double r00 = +cy*cz; double r01 = -cy*sz; double r02 = +sy;
01115 double r10 = +sx*sy*cz+cx*sz; double r11 = -sx*sy*sz+cx*cz; double r12 = -sx*cy;
01116 double r20 = -cx*sy*cz+sx*sz; double r21 = +cx*sy*sz+sx*cz; double r22 = +cx*cy;
01117 double rdrx10 = +cx*sy*cz-sx*sz; double rdrx11 = -cx*sy*sz-sx*cz; double rdrx12 = -cx*cy;
01118 double rdrx20 = +sx*sy*cz+cx*sz; double rdrx21 = -sx*sy*sz+cx*cz; double rdrx22 = -sx*cy;
01119 double rdry00 = -sy*cz; double rdry01 = +sy*sz; double rdry02 = +cy;
01120 double rdry10 = +sx*cy*cz; double rdry11 = -sx*cy*sz; double rdry12 = +sx*sy;
01121 double rdry20 = -cx*cy*cz; double rdry21 = +cx*cy*sz; double rdry22 = -cx*sy;
01122 double rdrz00 = -cy*sz; double rdrz01 = -cy*cz;
01123 double rdrz10 = -sx*sy*sz+cx*cz; double rdrz11 = -sx*sy*cz-cx*sz;
01124 double rdrz20 = +cx*sy*sz+sx*cz; double rdrz21 = +cx*sy*cz-sx*sz;
01125
01126
01127 double X1p,Y1p,Z1p;
01128 double X1c,Y1c,Z1c,X2c;
01129 double X1cd,Y1cd,Z1cd;
01130
01131
01132 for (int32_t i=0; i<(int32_t)active.size(); i++) {
01133
01134
01135 X1p = X[active[i]];
01136 Y1p = Y[active[i]];
01137 Z1p = Z[active[i]];
01138
01139
01140 X1c = r00*X1p+r01*Y1p+r02*Z1p+tx;
01141 Y1c = r10*X1p+r11*Y1p+r12*Z1p+ty;
01142 Z1c = r20*X1p+r21*Y1p+r22*Z1p+tz;
01143
01144
01145
01146 double weight = 1.0;
01147 if (param.reweighting)
01148 weight = 1.0/(fabs(p_observe[4*i+0]-param.calib.cu)/fabs(param.calib.cu) + 0.05);
01149
01150
01151 X2c = X1c-param.base;
01152
01153
01154 for (int32_t j=0; j<6; j++) {
01155
01156
01157 switch (j) {
01158 case 0: X1cd = 0;
01159 Y1cd = rdrx10*X1p+rdrx11*Y1p+rdrx12*Z1p;
01160 Z1cd = rdrx20*X1p+rdrx21*Y1p+rdrx22*Z1p;
01161 break;
01162 case 1: X1cd = rdry00*X1p+rdry01*Y1p+rdry02*Z1p;
01163 Y1cd = rdry10*X1p+rdry11*Y1p+rdry12*Z1p;
01164 Z1cd = rdry20*X1p+rdry21*Y1p+rdry22*Z1p;
01165 break;
01166 case 2: X1cd = rdrz00*X1p+rdrz01*Y1p;
01167 Y1cd = rdrz10*X1p+rdrz11*Y1p;
01168 Z1cd = rdrz20*X1p+rdrz21*Y1p;
01169 break;
01170 case 3: X1cd = 1; Y1cd = 0; Z1cd = 0; break;
01171 case 4: X1cd = 0; Y1cd = 1; Z1cd = 0; break;
01172 case 5: X1cd = 0; Y1cd = 0; Z1cd = 1; break;
01173 }
01174
01175
01176 J[(4*i+0)*6+j] = weight*param.calib.f*(X1cd*Z1c-X1c*Z1cd)/(Z1c*Z1c);
01177 J[(4*i+1)*6+j] = weight*param.calib.f*(Y1cd*Z1c-Y1c*Z1cd)/(Z1c*Z1c);
01178 J[(4*i+2)*6+j] = weight*param.calib.f*(X1cd*Z1c-X2c*Z1cd)/(Z1c*Z1c);
01179 J[(4*i+3)*6+j] = weight*param.calib.f*(Y1cd*Z1c-Y1c*Z1cd)/(Z1c*Z1c);
01180 }
01181
01182
01183 p_predict[4*i+0] = param.calib.f*X1c/Z1c+param.calib.cu;
01184 p_predict[4*i+1] = param.calib.f*Y1c/Z1c+param.calib.cv;
01185 p_predict[4*i+2] = param.calib.f*X2c/Z1c+param.calib.cu;
01186 p_predict[4*i+3] = param.calib.f*Y1c/Z1c+param.calib.cv;
01187
01188
01189 p_residual[4*i+0] = weight*(p_observe[4*i+0]-p_predict[4*i+0]);
01190 p_residual[4*i+1] = weight*(p_observe[4*i+1]-p_predict[4*i+1]);
01191 p_residual[4*i+2] = weight*(p_observe[4*i+2]-p_predict[4*i+2]);
01192 p_residual[4*i+3] = weight*(p_observe[4*i+3]-p_predict[4*i+3]);
01193 }
01194 }
01195