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