run_mono.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002 * Software License Agreement (BSD License)
00003 *
00004 *  Copyright (c) 2009, Willow Garage, Inc.
00005 *  All rights reserved.
00006 *
00007 *  Redistribution and use in source and binary forms, with or without
00008 *  modification, are permitted provided that the following conditions
00009 *  are met:
00010 *
00011 *   * Redistributions of source code must retain the above copyright
00012 *     notice, this list of conditions and the following disclaimer.
00013 *   * Redistributions in binary form must reproduce the above
00014 *     copyright notice, this list of conditions and the following
00015 *     disclaimer in the documentation and/or other materials provided
00016 *     with the distribution.
00017 *   * Neither the name of the Willow Garage nor the names of its
00018 *     contributors may be used to endorse or promote products derived
00019 *     from this software without specific prior written permission.
00020 *
00021 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032 *  POSSIBILITY OF SUCH DAMAGE.
00033 *********************************************************************/
00034 
00035 
00036 //
00037 // runs a sequence of stereo images into an SBA engine
00038 // visualize in rviz
00039 //
00040 
00041 #include <ros/ros.h>
00042 #include <visualization_msgs/Marker.h>
00043 #include <visualization_msgs/MarkerArray.h>
00044 #include <geometry_msgs/Point.h>
00045 
00046 #include <vslam_system/vo.h>
00047 #include <vslam_system/place_recognizer.h>
00048 #include <posest/pe2d.h>
00049 #include <sba/sba.h>
00050 #include <frame_common/frame.h>
00051 #include <boost/shared_ptr.hpp>
00052 #include <cstdio>
00053 #include <fstream>
00054 #include <dirent.h>
00055 #include <fnmatch.h>
00056 
00057 #include <opencv/highgui.h>
00058 #include <opencv2/nonfree/nonfree.hpp>
00059 
00060 using namespace std;
00061 using namespace sba;
00062 using namespace frame_common;
00063 using namespace Eigen;
00064 using namespace vslam;
00065 
00066 // visual output of matches
00067 #define VISMATCH
00068 
00069 // elapsed time in milliseconds
00070 #include <sys/time.h>
00071 static double mstime()
00072 {
00073   timeval tv;
00074   gettimeofday(&tv,NULL);
00075   long long ts = tv.tv_sec;
00076   ts *= 1000000;
00077   ts += tv.tv_usec;
00078   return (double)ts*.001;
00079 }
00080 
00081 // Names of left and right files in directory (with wildcards)
00082 char *lreg, *rreg, *dreg;
00083 
00084 // Filters for scandir
00085 int getleft(struct dirent const *entry)
00086 {
00087   if (!fnmatch(lreg,entry->d_name,0))
00088     return 1;
00089   return 0;
00090 }
00091 
00092 int getright(struct dirent const *entry)
00093 {
00094   if (!fnmatch(rreg,entry->d_name,0))
00095     return 1;
00096   return 0;
00097 }
00098 
00099 
00100 int getidir(struct dirent const *entry)
00101 {
00102   if (!fnmatch(dreg,entry->d_name,0))
00103     return 1;
00104   return 0;
00105 }
00106 
00107 
00108 
00109 // draw the graph on rviz
00110 void
00111 drawgraph(SysSBA &sba, SysSPA &spa, ros::Publisher &cam_pub, ros::Publisher &pt_pub, int dec,
00112           ros::Publisher &cst_pub, ros::Publisher &link_pub)
00113 {
00114   visualization_msgs::Marker cammark, ptmark, cstmark;
00115   cammark.header.frame_id = "/pgraph";
00116   cammark.header.stamp = ros::Time();
00117   cammark.ns = "pgraph";
00118   cammark.id = 0;
00119   cammark.action = visualization_msgs::Marker::ADD;
00120   cammark.pose.position.x = 0;
00121   cammark.pose.position.y = 0;
00122   cammark.pose.position.z = 0;
00123   cammark.pose.orientation.x = 0.0;
00124   cammark.pose.orientation.y = 0.0;
00125   cammark.pose.orientation.z = 0.0;
00126   cammark.pose.orientation.w = 1.0;
00127   cammark.scale.x = 0.02;
00128   cammark.scale.y = 0.02;
00129   cammark.scale.z = 0.02;
00130   cammark.color.r = 0.0f;
00131   cammark.color.g = 1.0f;
00132   cammark.color.b = 1.0f;
00133   cammark.color.a = 1.0f;
00134   cammark.lifetime = ros::Duration();
00135   cammark.type = visualization_msgs::Marker::LINE_LIST;
00136 
00137   ptmark = cammark;
00138   ptmark.color.r = 1.0f;
00139   ptmark.color.g = 0.0f;
00140   ptmark.color.b = 0.0f;
00141   ptmark.color.a = 0.5f;
00142   ptmark.scale.x = 0.2;
00143   ptmark.scale.y = 0.2;
00144   ptmark.scale.z = 0.2;
00145   ptmark.type = visualization_msgs::Marker::POINTS;
00146 
00147   cstmark = cammark;
00148   cstmark.color.r = 1.0f;
00149   cstmark.color.g = 1.0f;
00150   cstmark.color.b = 0.0f;
00151   cstmark.color.a = 1.0f;
00152   cstmark.scale.x = 0.06;
00153   cstmark.scale.y = 0.2;
00154   cstmark.scale.z = 0.2;
00155   cstmark.type = visualization_msgs::Marker::LINE_LIST;
00156 
00157 
00158   // draw points, decimated
00159   int npts = sba.tracks.size();
00160 
00161   cout << "Number of points to draw: " << npts << endl;
00162   if (npts <= 0) return;
00163 
00164 
00165   ptmark.points.resize(npts/dec+1);
00166   for (int i=0, ii=0; i<npts; i+=dec, ii++)
00167     {
00168       Vector4d &pt = sba.tracks[i].point;
00169       ptmark.points[ii].x = pt(0);
00170       ptmark.points[ii].y = pt(2);
00171       ptmark.points[ii].z = -pt(1);
00172 
00173 //      printf("%f %f %f\n", pt(0), pt(1), pt(2));
00174     }
00175 
00176   // draw cameras
00177   int ncams = sba.nodes.size();
00178   cammark.points.resize(ncams*6);
00179   for (int i=0, ii=0; i<ncams; i++)
00180     {
00181       Node &nd = sba.nodes[i];
00182       Vector3d opt;
00183       Matrix<double,3,4> tr;
00184       transformF2W(tr,nd.trans,Quaternion<double>(nd.qrot));
00185 
00186       printf("camera transform: %f %f %f\n", nd.trans.x(),
00187              nd.trans.y(), nd.trans.z());
00188       cammark.points[ii].x = nd.trans.x();
00189       cammark.points[ii].y = nd.trans.z();
00190       cammark.points[ii++].z = -nd.trans.y();
00191       opt = tr*Vector4d(0,0,0.3,1);
00192       cammark.points[ii].x = opt.x();
00193       cammark.points[ii].y = opt.z();
00194       cammark.points[ii++].z = -opt.y();
00195 
00196       cammark.points[ii].x = nd.trans.x();
00197       cammark.points[ii].y = nd.trans.z();
00198       cammark.points[ii++].z = -nd.trans.y();
00199       opt = tr*Vector4d(0.2,0,0,1);
00200       cammark.points[ii].x = opt.x();
00201       cammark.points[ii].y = opt.z();
00202       cammark.points[ii++].z = -opt.y();
00203 
00204       cammark.points[ii].x = nd.trans.x();
00205       cammark.points[ii].y = nd.trans.z();
00206       cammark.points[ii++].z = -nd.trans.y();
00207       opt = tr*Vector4d(0,0.1,0,1);
00208       cammark.points[ii].x = opt.x();
00209       cammark.points[ii].y = opt.z();
00210       cammark.points[ii++].z = -opt.y();
00211     }
00212 
00213   // draw SPA constraints
00214   int ncons = spa.p2cons.size();
00215   cstmark.points.resize(ncons*6);
00216 
00217   for (int i=0, ii=0; i<ncons; i++)
00218     {
00219       ConP2 &con = spa.p2cons[i];
00220       Node &nd0 = spa.nodes[con.ndr];
00221       Node &nd1 = spa.nodes[con.nd1];
00222 
00223       Node &nd = spa.nodes[i];
00224       Vector3d opt;
00225       Matrix<double,3,4> tr;
00226       transformF2W(tr,nd.trans,Quaternion<double>(nd.qrot));
00227 
00228       cstmark.points[ii].x = nd.trans.x();
00229       cstmark.points[ii].y = nd.trans.z();
00230       cstmark.points[ii++].z = -nd.trans.y();
00231       opt = tr*Vector4d(0,0,0.3,1);
00232       cstmark.points[ii].x = opt.x();
00233       cstmark.points[ii].y = opt.z();
00234       cstmark.points[ii++].z = -opt.y();
00235 
00236       cstmark.points[ii].x = nd.trans.x();
00237       cstmark.points[ii].y = nd.trans.z();
00238       cstmark.points[ii++].z = -nd.trans.y();
00239       opt = tr*Vector4d(0.2,0,0,1);
00240       cstmark.points[ii].x = opt.x();
00241       cstmark.points[ii].y = opt.z();
00242       cstmark.points[ii++].z = -opt.y();
00243 
00244       cstmark.points[ii].x = nd.trans.x();
00245       cstmark.points[ii].y = nd.trans.z();
00246       cstmark.points[ii++].z = -nd.trans.y();
00247       opt = tr*Vector4d(0,0.1,0,1);
00248       cstmark.points[ii].x = opt.x();
00249       cstmark.points[ii].y = opt.z();
00250       cstmark.points[ii++].z = -opt.y();
00251 
00252 #if 0
00253       cstmark.points[ii].x = nd0.trans.x();
00254       cstmark.points[ii].y= nd0.trans.z();
00255       cstmark.points[ii++].z = -nd0.trans.y();
00256       cstmark.points[ii].x = nd1.trans.x();
00257       cstmark.points[ii].y = nd1.trans.z();
00258       cstmark.points[ii++].z = -nd1.trans.y();
00259 #endif
00260     }
00261 
00262   cam_pub.publish(cammark);
00263   pt_pub.publish(ptmark);
00264   cst_pub.publish(cstmark);
00265 
00266 #if 0
00267   cv::namedWindow("1", 1);
00268   cv::waitKey();
00269 #endif
00270 }
00271 
00272 
00273 
00274 // main loop
00275 
00276 // parameters
00277 //  max distance, angle between keyframes
00278 //  min inliers between keyframes
00279 
00280 double maxdist = 0.5;//0.05;           // meters
00281 double maxang  = 10.0;          // degrees
00282 int mininls    = 30;          // depends on number of points, no?
00283 int ndi = 0;                    // current keyframe index
00284 
00285 int main(int argc, char** argv)
00286 {
00287   if (argc < 5)
00288     {
00289       printf("Args are: <param file> <image dir> <left image file template> <right image file template> \n");
00290       exit(0);
00291     }
00292 
00293   // get camera parameters, in the form: fx fy cx cy tx
00294   fstream fstr;
00295   fstr.open(argv[1],fstream::in);
00296   if (!fstr.is_open())
00297     {
00298       printf("Can't open camera file %s\n",argv[1]);
00299       exit(0);
00300     }
00301   CamParams camp;
00302   fstr >> camp.fx;
00303   fstr >> camp.fy;
00304   fstr >> camp.cx;
00305   fstr >> camp.cy;
00306   fstr >> camp.tx;
00307 
00308   cout << "Cam params: " << camp.fx << " " << camp.fy << " " << camp.cx
00309        << " " << camp.cy << " " << camp.tx << endl;
00310 
00311 
00312   // set up directories
00313   struct dirent **lims, **rims, **dirs;
00314   int nlim, nrim, ndirs;
00315   string dname = argv[2];
00316   if (!dname.compare(dname.size()-1,1,"/")) // see if slash at end
00317     dname.erase(dname.size()-1);
00318 
00319   string dirfn = dname.substr(dname.rfind("/")+1);
00320   string tdir = dname.substr(0,dname.rfind("/")+1);
00321   cout << "Top directory is " << tdir << endl;
00322   cout << "Search directory name is " << dirfn << endl;
00323   dreg = (char *)dirfn.c_str();
00324 
00325   ndirs = scandir(tdir.c_str(),&dirs,getidir,alphasort);
00326   printf("Found %d directories\n", ndirs);
00327   printf("%s\n",dirs[0]->d_name);
00328 
00329   // set up structures
00330   cout << "Setting up frame processing..." << flush;
00331   FrameProc fp(15);//18);             // can be slow, setting up Calonder tree
00332   fp.setFrameDetector(cv::Ptr<cv::FeatureDetector>(new cv::SurfFeatureDetector(200)));
00333   cout << "done" << endl;
00334   vector<Frame, Eigen::aligned_allocator<Frame> > frames; // stereo image frames in system
00335 
00336   SysSBA sba;                   // SBA system
00337   sba.useCholmod(false);
00338 
00339   SysSPA spa;                   // SPA system
00340   int spaFrameId = -1;          // current frame of SPA system
00341   int ndi0 = 0;                 // current node of SPA system
00342   
00343   // VO processor
00344   voSt vo(boost::shared_ptr<pe::PoseEstimator>(new pe::PoseEstimator2d), 40,10,mininls,maxdist,maxang); // 40 frames, 10 fixed
00345 
00346   std::vector<const Frame*> place_matches;
00348   pe::PoseEstimator3d pe(1000,true,10.0,3.0,3.0);
00349   pe.wx = 92;
00350   pe.wy = 48;
00351 
00352   // set up markers for visualization
00353   ros::init(argc, argv, "VisBundler");
00354   ros::NodeHandle nh ("~");
00355   ros::Publisher pt_pub = nh.advertise<visualization_msgs::Marker>("points", 0);
00356   ros::Publisher cam_pub = nh.advertise<visualization_msgs::Marker>("cameras", 0);
00357   ros::Publisher cst_pub = nh.advertise<visualization_msgs::Marker>("constraints", 0);
00358   ros::Publisher link_pub = nh.advertise<visualization_msgs::Marker>("links", 0);
00359 
00360   // for RANSAC
00361   srand(mstime());
00362 
00363   // window
00364 #ifdef VISMATCH
00365   const std::string window_name = "VO tracks";
00366   cv::namedWindow(window_name,0);
00367   cv::Mat display;
00368 #endif
00369 
00370   int iter = 0;
00371   lreg = argv[3];
00372   rreg = argv[4];
00373 
00374   // loop over directories
00375   for (int dd=0; dd<ndirs; dd++)
00376     {
00377       char dir[2048];
00378       sprintf(dir,"%s%s",tdir.c_str(),dirs[dd]->d_name);
00379       printf("Current directory: %s\n", dir);
00380 
00381       // get left/right image file names, sorted
00382       nlim = scandir(dir,&lims,getleft,alphasort);
00383       printf("Found %d left images\n", nlim);
00384       printf("%s\n",lims[0]->d_name);
00385 
00386       nrim = scandir(dir,&rims,getright,alphasort);
00387       printf("Found %d right images\n", nrim);
00388       printf("%s\n",rims[0]->d_name);
00389 
00390       if (nlim != nrim)
00391         {
00392           printf("Number of left/right images does not match: %d vs. %d\n", nlim, nrim);
00393           exit(0);
00394         }
00395 
00396       const int init_min_frame_count = 5;
00397 
00398       // loop over each stereo pair, adding it to the system
00399       bool ret = false;
00400       for (int ii=0; ii<nlim; iter++, ii += ret ? 5 : 1)
00401         {
00402           if(ii > 0 && ii < init_min_frame_count)
00403           {
00404             continue;
00405           }
00406 
00407           // Load images
00408           char fn[2048];
00409           sprintf(fn,"%s/%s",dir,lims[ii]->d_name);
00410           cv::Mat image1 = cv::imread(fn,0);
00411           sprintf(fn,"%s/%s",dir,rims[ii]->d_name);
00412           cv::Mat image1r = cv::imread(fn,0);
00413 
00414 
00415           if (image1.rows == 0 || image1r.rows == 0)
00416             exit(0);
00417 
00418           double t0 = mstime();
00419           Frame f1;             // next frame
00420           f1.setCamParams(camp); // this sets the projection and reprojection matrices
00421 
00422           fp.setMonoFrame(f1,image1);
00423           f1.frameId = sba.nodes.size(); // index
00424 //          f1.img = cv::Mat();   // remove the images
00425           f1.imgRight = cv::Mat();
00426 
00427           // VO
00428           cout << "calling vo::addFrame" << endl;
00429           ret = vo.addFrame(f1);
00430 
00431           // grow full SBA
00432           if (ret)
00433           {
00434             frames.push_back(f1);
00435             if(frames.size() > 1)
00436             {
00437               Frame& _fs = frames.back();
00438               Frame& _f0 = *(frames.end() - 2);
00439 
00440               if(vo.pose_estimator_->getMethod() == pe::PoseEstimator::SFM)
00441               {
00442 //                assert(frames.size() == 2);
00443                 cout << "frames.size() " << frames.size() << endl;
00444                 frames[0].pts = (vo.frames.end() - 2)->pts;
00445                 frames[0].goodPts = (vo.frames.end() - 2)->goodPts;
00446               }
00447 
00448               int count = 0;
00449               for(size_t i = 0; i < _f0.goodPts.size(); i++)
00450               {
00451                 if(_f0.goodPts[i]) count++;
00452               }
00453               printf("The number of good points: %d\n", count);
00454             }
00455             //              if(frames.size() > 1)
00456             {
00457               vo.transferLatestFrame(frames,sba);
00458             }
00459           }
00460 
00461           if (frames.size() > 1 && vo.pose_estimator_->inliers.size() < mininls)
00462             cout << endl << "******** Bad image match: " << fn << endl << endl;
00463 
00464 //          cv::waitKey();
00465 
00466           if (ret)
00467             {
00468               int n = sba.nodes.size();
00469               int np = sba.tracks.size();
00470 
00471               // draw graph
00472               cout << "drawing with " << n << " nodes and " << np << " points..." << endl << endl;
00473 #if 1
00474               if (n%2 == 0)
00475                 drawgraph(sba,spa,cam_pub,pt_pub,1,cst_pub,link_pub); // every nth point
00476 #endif
00477 
00478 #if 1
00479               int nnsba = 10;
00480               if (n > 4 && n%nnsba == 0)
00481                 {
00482                   cout << "Running large SBA" << endl;
00483 //                  sba.doSBA(3,1.0e-4,0);
00484                 }
00485 #endif
00486             }
00487 
00488 #ifdef VISMATCH
00489           // Visualize
00490           if (ret || 1)
00491             {
00492               drawVOtracks(image1,vo.frames,display);
00493               cv::imshow(window_name, display);
00494               cv::waitKey(10);
00495             }
00496 #endif
00497 
00498           if (!nh.ok())
00499             return 0;
00500         }
00501     }
00502   return 0;
00503 }


vslam_system
Author(s): Kurt Konolige, Patrick Mihelich, Helen Oleynikova
autogenerated on Thu Jan 2 2014 12:12:31