00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040 #include <vslam_system/vo.h>
00041 #include <cstdio>
00042
00043 using namespace std;
00044 using namespace frame_common;
00045 using namespace Eigen;
00046 using namespace sba;
00047
00048 namespace vslam
00049 {
00050
00051
00052 voSt::voSt(boost::shared_ptr<pe::PoseEstimator> pose_estimator, int ws, int wf, int mini, double mind, double mina)
00053 {
00054
00055 pose_estimator_ = pose_estimator;
00056
00057
00058 wsize = ws;
00059 wfixed = wf;
00060 mindist = mind;
00061 minang = mina;
00062 mininls = mini;
00063 doPointPlane = true;
00064
00065
00066 sba.useCholmod(true);
00067
00068
00069 srand(time(NULL));
00070 }
00071
00072
00073 bool voSt::addFrame(const Frame &fnew)
00074 {
00075 int nframes = frames.size();
00076 bool init = nframes == 0;
00077
00078
00079 if (nframes >= wsize)
00080 removeFrame();
00081
00082
00083 Quaterniond fq;
00084 Vector4d trans;
00085 int inl = 0;
00086 if (init)
00087 {
00088 trans = Vector4d(0,0,0,1);
00089 fq.coeffs() = Vector4d(0,0,0,1);
00090 }
00091 else
00092 {
00093
00094 Frame &refFrame = frames.back();
00095
00096 inl = pose_estimator_->estimate(refFrame,fnew);
00097 fq = Quaterniond(pose_estimator_->rot);
00098 trans.head(3) = pose_estimator_->trans;
00099 trans(3) = 1.0;
00100
00101
00102 double dist = pose_estimator_->trans.norm();
00103 double angledist = fq.angularDistance(fq.Identity());
00104 if(pose_estimator_->getMethod() == pe::PoseEstimator::Stereo)
00105 {
00106
00107
00108
00109 if (((dist < mindist && angledist < minang) && (inl > mininls)))
00110 {
00111
00112 cout << "[Stereo VO] Skipping frame " << (mindist) << " " << (minang) << " " << (inl) << "/" << (mininls) << endl;
00113 refFrame.setTKpts(trans,fq);
00114 return false;
00115 }
00116 }
00117 else
00118 {
00119 if(inl < mininls) return false;
00120 if((pose_estimator_->getMethod() == pe::PoseEstimator::PnP && dist < mindist) && inl > mininls)
00121 {
00122 cout << "dist = " << dist << " maxdist = " << mindist << " inl = " << inl
00123 << " mininls = " << mininls << endl;
00124 return false;
00125 }
00126 }
00127 }
00128
00129 Matrix<double,3,4> f2w, f2w_frame0, f2w_frame1;
00130 if (!init)
00131 {
00132
00133 Node &nd0 = sba.nodes.back();
00134 Quaterniond fq0;
00135 fq0 = nd0.qrot;
00136 fq = fq*fq0;
00137
00138
00139 if (isnan(fq.x()) || isnan(fq.y()) || isnan(fq.z()) || isnan(fq.w()))
00140 return false;
00141
00142 transformF2W(f2w,nd0.trans,fq0);
00143 trans.head(3) = f2w*trans;
00144
00145
00146
00147 transformF2W(f2w_frame0,nd0.trans,nd0.qrot);
00148 }
00149
00150
00151
00152 sba.addNode(trans, fq, fnew.cam, init);
00153
00154 int ndi = sba.nodes.size()-1;
00155
00156 Node &nd1 = sba.nodes.back();
00157 transformF2W(f2w_frame1,nd1.trans,nd1.qrot);
00158
00159
00160
00161 frames.push_back(fnew);
00162 Frame &f1 = frames.back();
00163
00164 f1.ipts.assign(f1.kpts.size(), -1);
00165
00166
00167 if (init)
00168 {
00169 init = false;
00170 return true;
00171 }
00172
00173
00174 Frame &f0 = *(frames.end()-2);
00175 nframes = frames.size();
00176
00177
00178 addProjections(f0, f1, frames, sba, pose_estimator_->inliers, f2w_frame0, ndi-1, ndi, &ipts);
00179
00180
00181 int nfree = wsize-wfixed;
00182 if (nframes <= nfree)
00183 sba.nFixed = 1;
00184 else
00185 sba.nFixed = wfixed - (wsize - nframes);
00186
00187 cout << "[Stereo VO] Inliers: " << inl << " Nodes: " << sba.nodes.size() << " Points: " << sba.tracks.size() << endl;
00188 sba.verbose = 0;
00189 sba.doSBA(4,1.0e-5,0);
00190
00191
00192
00193 if (pointcloud_proc_ && doPointPlane)
00194 {
00195 pointcloud_proc_->match(f0, f1, pose_estimator_->trans, Quaterniond(pose_estimator_->rot), pointcloud_matches_);
00196 addPointCloudProjections(f0, f1, sba, pointcloud_matches_, f2w_frame0, f2w_frame1, ndi-1, ndi, &ipts);
00197 }
00198
00199 return true;
00200 }
00201
00202
00203
00204
00205 void voSt::removeFrame()
00206 {
00207 vector<int> pidx(sba.tracks.size());
00208
00209
00210
00211 int tn = 0;
00212 for(size_t i=0; i<sba.tracks.size(); i++)
00213 {
00214 ProjMap &prjs = sba.tracks[i].projections;
00215 if (prjs.size() == 0) continue;
00216 int n = 0;
00217 for(ProjMap::iterator itr = prjs.begin(); itr != prjs.end(); itr++)
00218 {
00219 Proj &prj = itr->second;
00220 prj.ndi -= 1;
00221 if (prj.ndi >= 0) n++;
00222 else prj.isValid = false;
00223 }
00224 if (n < 2)
00225 pidx[i] = -1;
00226 else
00227 pidx[i] = tn++;
00228 }
00229
00230
00231
00232
00233 for (int i=0; i<(int)pidx.size(); i++)
00234 {
00235 if (pidx[i] < 0 || pidx[i] == i) continue;
00236 sba.tracks[pidx[i]] = sba.tracks[i];
00237 ipts[pidx[i]] = ipts[i];
00238 }
00239 sba.tracks.resize(tn);
00240 ipts.resize(tn);
00241
00242
00243 sba.nodes.erase(sba.nodes.begin());
00244 frames.erase(frames.begin());
00245 for (int i=0; i<(int)frames.size(); i++)
00246 {
00247 Frame &f = frames[i];
00248 for (int j=0; j<(int)f.ipts.size(); j++)
00249 if (f.ipts[j] >= 0)
00250 f.ipts[j] = pidx[f.ipts[j]];
00251 for (int j=0; j<(int)f.pl_ipts.size(); j++)
00252 if (f.pl_ipts[j] >= 0)
00253 f.pl_ipts[j] = pidx[f.pl_ipts[j]];
00254
00255 }
00256
00257
00258 for(size_t i=0; i<sba.tracks.size(); i++)
00259 {
00260 ProjMap &prjs = sba.tracks[i].projections;
00261 if (prjs.size() == 0) continue;
00262 for(ProjMap::iterator itr = prjs.begin(); itr != prjs.end(); itr++)
00263 {
00264 Proj &prj = itr->second;
00265 if (prj.pointPlane && prj.plane_point_index >= 0)
00266 {
00267 prj.plane_point_index = pidx[prj.plane_point_index];
00268 prj.plane_node_index -= 1;
00269 if (prj.plane_node_index < 0 || prj.plane_point_index < 0)
00270 prj.isValid = false;
00271 }
00272 }
00273 }
00274 }
00275
00276
00277
00278 void voSt::transferLatestFrame(std::vector<fc::Frame, Eigen::aligned_allocator<fc::Frame> > &eframes,
00279 SysSBA &esba)
00280 {
00281 bool init = esba.nodes.size() == 0;
00282
00283
00284 Frame &f1 = eframes.back();
00285
00286
00287 f1.ipts.assign(f1.kpts.size(), -1);
00288 f1.pl_ipts.assign(f1.pl_pts.size(), -1);
00289
00290
00291 f1.pl_ipts.assign(f1.pl_pts.size(), -1);
00292
00293
00294
00295
00296
00297 Quaterniond fq;
00298 Vector4d trans;
00299 if (init)
00300 {
00302
00303
00304
00305 trans = Vector4d(0,0,0,1);
00306 fq.coeffs() = Vector4d(0,0,0,1);
00307 }
00308 else
00309 {
00311
00312 transformN2N(trans, fq, *(sba.nodes.end()-2), *(sba.nodes.end()-1));
00313
00314
00315
00316
00317 }
00318
00319 Matrix<double,3,4> f2w, f2w_frame0, f2w_frame1;
00320 if (!init)
00321 {
00322
00323 Node &nd0 = esba.nodes.back();
00324 Quaterniond fq0;
00325 fq0 = nd0.qrot;
00326 fq = fq0*fq;
00327
00328
00329 transformF2W(f2w,nd0.trans,fq0);
00330 trans.head(3) = f2w*trans;
00331
00332 transformF2W(f2w_frame0,nd0.trans,nd0.qrot);
00333
00334
00335 }
00336
00337
00338
00339 esba.addNode(trans, fq, f1.cam, init);
00340
00341 int ndi = esba.nodes.size()-1;
00342
00343 Node &nd1 = esba.nodes.back();
00344 transformF2W(f2w_frame1,nd1.trans,nd1.qrot);
00345
00346 if (init)
00347 return;
00348
00351 Frame &f0 = *(eframes.end()-2);
00352 addProjections(f0, f1, eframes, esba, pose_estimator_->inliers, f2w_frame0, ndi-1, ndi, NULL);
00353 esba.doSBA(3,1.0e-4,SBA_SPARSE_CHOLESKY);
00354 if (doPointPlane)
00355 addPointCloudProjections(f0, f1, esba, pointcloud_matches_, f2w_frame0, f2w_frame1, ndi-1, ndi, NULL);
00356 }
00357
00358
00359
00360
00361
00362 int voSt::findTransform(int frameId, int n, Vector4d &trans, Quaterniond &qr,
00363 Matrix<double,6,6> &prec)
00364 {
00365
00366 int fi = 0;
00367 for (; fi < (int)frames.size(); fi++)
00368 {
00369 if (frameId == frames[fi].frameId)
00370 break;
00371 }
00372 if (fi >= (int)frames.size())
00373 return -1;
00374
00375
00376 int fi1 = fi+n;
00377 if (fi1 >= (int)frames.size())
00378 fi1 = frames.size()-1;
00379
00380
00381 Node &nd0 = sba.nodes[fi];
00382 Node &nd1 = sba.nodes[fi1];
00383 transformN2N(trans,qr,nd0,nd1);
00384
00385 prec.setIdentity();
00386 prec(3,3) = prec(4,4) = prec(5,5) = 10;
00387
00388 return frames[fi1].frameId;
00389 }
00390
00391
00392
00393 int voSt::findNode(int frameId)
00394 {
00395 int fi = 0;
00396 for (; fi < (int)frames.size(); fi++)
00397 {
00398 if (frameId == frames[fi].frameId)
00399 return fi;
00400 }
00401 return -1;
00402 }
00403
00404
00405 void addProjections(fc::Frame &f0, fc::Frame &f1,
00406 std::vector<fc::Frame, Eigen::aligned_allocator<fc::Frame> > &frames,
00407 SysSBA &sba, const std::vector<cv::DMatch> &inliers,
00408 const Matrix<double,3,4>& f2w, int ndi0, int ndi1, std::vector<int>* ipts)
00409 {
00410
00411 vector<bool> matched0(f0.ipts.size(),0);
00412 vector<bool> matched1(f1.ipts.size(),0);
00413
00414
00415
00416 bool stereo = f1.isStereo;
00417
00418
00419 for (int i=0; i<(int)inliers.size(); i++)
00420 {
00421 int i0 = inliers[i].queryIdx;
00422 int i1 = inliers[i].trainIdx;
00423
00424 if (matched0[i0]) continue;
00425 if (matched1[i1]) continue;
00426
00427 if (f0.goodPts[i0] == 0) continue;
00428
00429 matched0[i0] = true;
00430 matched1[i1] = true;
00431
00432 int pti;
00433
00434 if (f0.ipts[i0] < 0 && f1.ipts[i1] < 0)
00435 {
00436 pti = sba.tracks.size();
00437 f0.ipts[i0] = pti;
00438 f1.ipts[i1] = pti;
00439
00440 Vector4d pt;
00441 pt.head(3) = f2w*f0.pts[i0];
00442 pt(3) = 1.0;
00443 sba.addPoint(pt);
00444 if (ipts)
00445 ipts->push_back(-1);
00446
00447 Vector3d ipt = getProjection(f0, i0);
00448 sba.addProj(ndi0, pti, ipt, stereo);
00449
00450
00451 ipt = getProjection(f1, i1);
00452 sba.addProj(ndi1, pti, ipt, stereo);
00453 }
00454
00455 else if (f0.ipts[i0] >= 0 && f1.ipts[i1] >= 0)
00456 {
00457 if (f0.ipts[i0] != f1.ipts[i1])
00458 {
00459 int tri = sba.mergeTracksSt(f0.ipts[i0],f1.ipts[i1]);
00460 if (tri >= 0)
00461 {
00462
00463 ProjMap &prjs = sba.tracks[tri].projections;
00464 for(ProjMap::iterator itr = prjs.begin(); itr != prjs.end(); itr++)
00465 {
00466 Proj &prj = itr->second;
00467 if (tri == f0.ipts[i0])
00468 substPointRef(frames[prj.ndi].ipts, tri, f1.ipts[i1]);
00469 else
00470 substPointRef(frames[prj.ndi].ipts, tri, f0.ipts[i0]);
00471 }
00472 }
00473 }
00474 }
00475
00476 else if (f1.ipts[i1] < 0)
00477 {
00478 pti = f0.ipts[i0];
00479 f1.ipts[i1] = pti;
00480
00481
00482 Vector3d ipt = getProjection(f1, i1);
00483 sba.addProj(ndi1, pti, ipt, stereo);
00484 }
00485 else if (f0.ipts[i0] < 0)
00486 {
00487 pti = f1.ipts[i1];
00488 f0.ipts[i0] = pti;
00489
00490
00491 Vector3d ipt = getProjection(f0, i0);
00492 sba.addProj(ndi0, pti, ipt, stereo);
00493 }
00494 }
00495 }
00496
00497
00498 void addPointCloudProjections(fc::Frame &f0, fc::Frame &f1,
00499 SysSBA &sba, const std::vector<cv::DMatch> &inliers,
00500 const Matrix<double,3,4>& f2w_frame0,
00501 const Matrix<double,3,4>& f2w_frame1,
00502 int ndi0, int ndi1, std::vector<int>* ipts)
00503 {
00504
00505 double covariance = 1.0;
00506 Matrix3d covar;
00507 covar << covariance, 0, 0,
00508 0, covariance, 0,
00509 0, 0, covariance;
00510
00511 covariance = 100.0;
00512 Matrix3d cv2;
00513 cv2 << covariance, 0, 0,
00514 0, covariance, 0,
00515 0, 0, covariance;
00516
00517 for (int i=0; i<(int)inliers.size(); i++)
00518 {
00519 int i0 = inliers[i].queryIdx;
00520 int i1 = inliers[i].trainIdx;
00521
00522 int pti;
00523
00524 if (f0.pl_ipts[i0] < 0)
00525 {
00526 pti = sba.tracks.size();
00527 f0.pl_ipts[i0] = pti;
00528
00529 Vector4d pt;
00530 pt.head<3>() = f2w_frame0*f0.pl_pts[i0];
00531 pt(3) = 1.0;
00532
00533
00534
00535 sba.addPoint(pt);
00536 if (ipts)
00537 ipts->push_back(-1);
00538
00539 sba.addStereoProj(ndi0, pti, f0.pl_kpts[i0]);
00540 sba.setProjCovariance(ndi0, pti, cv2);
00541 }
00542 if (f1.pl_ipts[i1] < 0)
00543 {
00544 pti = sba.tracks.size();
00545 f1.pl_ipts[i1] = pti;
00546
00547 Vector4d pt;
00548 pt.head<3>() = f2w_frame1*f1.pl_pts[i1];
00549 pt(3) = 1.0;
00550
00551
00552
00553 sba.addPoint(pt);
00554 if (ipts)
00555 ipts->push_back(-1);
00556
00557 sba.addStereoProj(ndi1, pti, f1.pl_kpts[i1]);
00558 sba.setProjCovariance(ndi1, pti, cv2);
00559 }
00560
00561
00562
00563
00564 Vector3d normal0 = f0.pl_normals[i0].head<3>();
00565 Vector3d normal1 = f1.pl_normals[i1].head<3>();
00566
00567
00568 sba.addPointPlaneMatch(ndi0, f0.pl_ipts[i0], normal0, ndi1, f1.pl_ipts[i1], normal1);
00569
00570
00571 sba.setProjCovariance(ndi1, f0.pl_ipts[i0], covar);
00572 sba.setProjCovariance(ndi0, f1.pl_ipts[i1], covar);
00573 }
00574 }
00575
00576 Vector3d getProjection(fc::Frame &frame, int index)
00577 {
00578 Vector3d proj;
00579 proj(0) = frame.kpts[index].pt.x;
00580 proj(1) = frame.kpts[index].pt.y;
00581 proj(2) = proj(0)-frame.disps[index];
00582 return proj;
00583 }
00584
00585
00586 void substPointRef(std::vector<int> &ipts, int tri0, int tri1)
00587 {
00588 for (int i=0; i<(int)ipts.size(); i++)
00589 {
00590 if (ipts[i] == tri1)
00591 ipts[i] = tri0;
00592 }
00593 }
00594
00595 }
00596