ndt_map_builder.hpp
Go to the documentation of this file.
00001 #include <pointcloud_vrml/pointcloud_utils.h>
00002 #include <Eigen/Eigen>
00003 
00004 #include "pcl/point_cloud.h"
00005 #include "pcl/io/pcd_io.h"
00006 #include "pcl/features/feature.h"
00007 #include "pcl/registration/icp.h"
00008 #include "pcl/filters/voxel_grid.h"
00009 
00010 namespace lslgeneric
00011 {
00012 
00013 //ICP wrapper
00014 template <typename PointT>
00015 bool NDTMapBuilder<PointT>::matchICP(pcl::PointCloud<PointT> &target,  pcl::PointCloud<PointT> &source,
00016                                      Eigen::Transform<double,3,Eigen::Affine,Eigen::ColMajor> &Tout, double &finalscore)
00017 {
00018 
00019     typename pcl::PointCloud<PointT>::Ptr cloud_in (new pcl::PointCloud<PointT>);
00020     typename pcl::PointCloud<PointT>::Ptr cloud_out (new pcl::PointCloud<PointT>);
00021 
00022     typename pcl::PointCloud<PointT>::ConstPtr m (new pcl::PointCloud<PointT>(source) );
00023     typename pcl::PointCloud<PointT>::ConstPtr f (new pcl::PointCloud<PointT>(target) );
00024 
00025     typename pcl::VoxelGrid<PointT> gr1;
00026     typename pcl::VoxelGrid<PointT> gr2;
00027     gr1.setLeafSize(0.1,0.1,0.1);
00028     gr2.setLeafSize(0.1,0.1,0.1);
00029 
00030     gr1.setInputCloud(m);
00031     gr2.setInputCloud(f);
00032 
00033     cloud_in->height = 1;
00034     cloud_in->width = cloud_in->points.size();
00035     cloud_out->height = 1;
00036     cloud_out->width = cloud_out->points.size();
00037     cloud_in->is_dense = false;
00038     cloud_out->is_dense = false;
00039 
00040     gr1.filter(*cloud_in);
00041     gr2.filter(*cloud_out);
00042 
00043     pcl::IterativeClosestPoint<PointT, PointT> icp;
00044 
00045     icp.setMaximumIterations(1000);
00046     std::cout<<"max itr are "<<icp.getMaximumIterations()<<std::endl;
00047     icp.setInputCloud(cloud_in);
00048     icp.setInputTarget(cloud_out);
00049 
00050     icp.setRANSACOutlierRejectionThreshold (2);
00051     icp.setMaxCorrespondenceDistance(10);
00052     icp.setTransformationEpsilon(0.00001);
00053     pcl::PointCloud<PointT> Final;
00054     icp.align(Final);
00055 
00056     //finalscore is the sum of square error. we want to minimize it...
00057     finalscore = icp.getFitnessScore();
00058     Tout = (icp.getFinalTransformation()).template cast<double>();
00059     return icp.hasConverged();
00060 }
00061 
00062 
00063 template <typename PointT>
00064 bool NDTMapBuilder<PointT>::addScan(pcl::PointCloud<PointT> scan, int id)
00065 {
00066     //if first scan, add to vertices.
00067     if(id == -1)   //automatic IDs
00068     {
00069         id = vertices.size();
00070     }
00071 
00072     if(id == 0)
00073     {
00074         MapVertex<PointT> mv;
00075         mv.scan = scan;
00076         mv.pose.setIdentity();
00077         mv.id = id;
00078 
00079         vertices.push_back(mv);
00080         return true;
00081     }
00082 
00083     //find last added scan
00084     if(id-1 <0 || id-1 > vertices.size())
00085         return false;
00086 
00087     std::cout<<"Matching scans with ids "<<vertices.back().id<<" and "<<id<<std::endl;
00088     //try to match them, obtain relative pose
00089     Eigen::Transform<double,3,Eigen::Affine,Eigen::ColMajor> T, Tout, Tndt;
00090     Eigen::Matrix<double,6,6> cov;
00091     bool succ = false;
00092     struct timeval tv_start, tv_end;
00093     double bestscore = INT_MAX;
00094     double finalscore;
00095     double time_match = 0;
00096     Tout.setIdentity();
00097 
00098 
00099     lslgeneric::NDTMap<PointT> fixed(&tr);
00100     fixed.loadPointCloud(vertices.back().scan);
00101     lslgeneric::NDTMap<PointT> moving(&tr);
00102     moving.loadPointCloud(scan);
00103 
00104     moving.computeNDTCells();
00105     fixed.computeNDTCells();
00106 
00107     lslgeneric::NDTHistogram<PointT> fixedH(fixed);
00108     lslgeneric::NDTHistogram<PointT> movingH(moving);
00109 
00110     movingH.bestFitToHistogram(fixedH,T);
00111     pcl::PointCloud<PointT> cloud3;
00112 
00113     //check in between the top 3 histogram positions and the no initial guess solutions
00114     //such a good place for some threads! TODO
00115     for(int q=0; q<4; q++)
00116     {
00117         if(!doHistogram && q != 3) continue;
00118         if(q!=3)
00119         {
00120             movingH.getTransform(q,T);
00121         }
00122         else
00123         {
00124             T.setIdentity();
00125         }
00126 //      cout<<"T init "<<T.translation().transpose()<<" r "<<T.rotation().eulerAngles(0,1,2).transpose()<<endl;
00127         Tndt.setIdentity();
00128         cloud3 = lslgeneric::transformPointCloud(T,scan);
00129 
00130         bool ret;
00131         gettimeofday(&tv_start,NULL);
00132         if(isF2F)
00133         {
00134             ret = matcherF2F->match(vertices.back().scan,cloud3,Tndt);
00135             finalscore = matcherF2F->finalscore;
00136         }
00137         else if(isP2F)
00138         {
00139             ret = matcherP2F->match(vertices.back().scan,cloud3,Tndt);
00140             finalscore = matcherP2F->finalscore;
00141         }
00142         else
00143         {
00144             //icp
00145             ret = this->matchICP(vertices.back().scan,cloud3,Tndt,finalscore);
00146         }
00147         gettimeofday(&tv_end,NULL);
00148 
00149         if(finalscore < bestscore)
00150         {
00151             Tout = Tndt*T;
00152             bestscore = finalscore;
00153             if(isF2F)
00154             {
00155                 //matcherF2F->covariance(vertices.back().scan,cloud3,Tndt,cov);
00156             }
00157             else if(isP2F)
00158             {
00159                 //matcherP2F->covariance(vertices.back().scan,cloud3,Tndt,cov);
00160             }
00161             else
00162             {
00163                 cov.setIdentity();
00164                 cov = 0.1*cov;
00165             }
00166             std::cout<<"score = "<<bestscore<<"best is "<<q<<std::endl;
00167         }
00168         std::cout<<"T fin "<<Tout.translation().transpose()<<" r "<<Tout.rotation().eulerAngles(0,1,2).transpose()<<std::endl;
00169         time_match += (tv_end.tv_sec-tv_start.tv_sec)*1000.+(tv_end.tv_usec-tv_start.tv_usec)/1000.;
00170     }
00171 
00172     std::cout<<" TIME: (MATCHING ONLY) "<< time_match << std::endl;
00173 
00174 
00175     //best fit pose is stored in Tout
00176     //add vertex with global pose calculated based on pose of previous scan.
00177     MapVertex<PointT> vert;
00178     vert.scan = scan;
00179     vert.pose = vertices.back().pose*Tout;
00180     vert.id = id;
00181     vert.hist = movingH;
00182     vert.timeRegistration = time_match;
00183 //      (tv_end.tv_sec-tv_start.tv_sec)*1000.+(tv_end.tv_usec-tv_start.tv_usec)/1000.;
00184 
00185     //add edge with covariance and relative pose
00186     MapEdge edge;
00187     edge.idFirst = vertices.back().id;
00188     edge.idSecond = id;
00189     edge.relative_pose = Tout;
00190     edge.covariance = cov;
00191 
00192     //add them
00193     vertices.push_back(vert);
00194     edges.push_back(edge);
00195 
00196     //go through all previous scans and check for similarity
00197 #if 0
00198     for(int i=0; i<vertices.size()-2; i++)
00199     {
00200         //lslgeneric::NDTMap f(&tr);
00201         //f.loadPointCloud(vertices[i].scan);
00202         //f.computeNDTCells();
00203         lslgeneric::NDTHistogram<PointT> fH = vertices[i].hist;
00204 
00205         //compare fH and movingH
00206         double sim = movingH.getSimilarity(fH);
00207 
00208         if(sim < 0.22)
00209         {
00210             //try to match
00211             std::cout<<"Trying to match.. "<<id<<" to "<<vertices[i].id<<" at i "<<i<<" scan similarity "<<sim<<std::endl;
00212             //check score of match, if good --- add new constraint in the edge graph
00213             /*bestscore = INT_MAX;
00214             for(int q=0; q<1; q++) {
00215             if(q!=3) {
00216                 movingH.getTransform(q,T);
00217             } else {
00218                 T.setIdentity();
00219             }
00220             pcl::PointCloud<PointT> cloud3 = lslgeneric::transformPointCloud(T,scan);
00221             bool ret = matcherF2F->match(vertices[i].scan,cloud3,Tndt);
00222             finalscore = matcherF2F->finalscore;
00223             if(finalscore < bestscore) {
00224                 Tout = Tndt*T;
00225                 bestscore = finalscore;
00226                 matcherF2F->covariance(vertices.back().scan,cloud3,Tndt,cov);
00227                 cout<<"score = "<<bestscore<<"best is "<<q<<endl;
00228             }
00229             }*/
00230 
00231             movingH.getTransform(0,T);
00232             pcl::PointCloud<PointT> cloud3 = lslgeneric::transformPointCloud(T,scan);
00233 
00234             bool ret;
00235             if(isF2F)
00236             {
00237                 ret = matcherF2F->match(vertices[i].scan,cloud3,Tndt);
00238                 finalscore = matcherF2F->finalscore;
00239             }
00240             else if(isP2F)
00241             {
00242                 finalscore = 0;
00243             }
00244             else
00245             {
00246                 //icp
00247                 finalscore = 0;
00248             }
00249 
00250             if(finalscore < -0.8)
00251             {
00252                 std::cout<<"NEW EDGE!\n";
00253                 //add edge with covariance and relative pose
00254                 edge.idFirst = vertices[i].id;
00255                 edge.idSecond = id;
00256                 edge.relative_pose = Tout;
00257                 edge.covariance = cov;
00258                 edges.insert(edges.begin(),edge);
00259             }
00260         }
00261     }
00262 #endif
00263 
00264 }
00265 
00266 template <typename PointT>
00267 void NDTMapBuilder<PointT>::saveG2OlogFile(const char* fname)
00268 {
00269     //open file
00270     FILE *fout = fopen(fname,"w");
00271     Eigen::Matrix<double,6,6> eye;
00272     eye.setIdentity();
00273     double reg = 1e-4;
00274 
00275     //go through verices and dump them -- these are the "initial guess"
00276     for(int i=0; i<vertices.size(); i++)
00277     {
00278         Eigen::Vector3d t = vertices[i].pose.translation();
00279         Eigen::Quaternion<double> q;
00280         q = vertices[i].pose.rotation();
00281         fprintf(fout,"VERTEX_SE3:QUAT %d %lf %lf %lf %lf %lf %lf %lf\n",vertices[i].id,
00282                 t(0),t(1),t(2),q.x(),q.y(),q.z(),q.w());
00283     }
00284 
00285     //go through edges and dump them
00286     for(int i=0; i<edges.size(); i++)
00287     {
00288         Eigen::Vector3d t = edges[i].relative_pose.translation();
00289         Eigen::Quaterniond q;
00290         q = edges[i].relative_pose.rotation();
00291         fprintf(fout,"EDGE_SE3:QUAT %d %d %lf %lf %lf %lf %lf %lf %lf ",edges[i].idFirst,edges[i].idSecond,
00292                 t(0),t(1),t(2),q.x(),q.y(),q.z(),q.w());
00293 
00294         Eigen::Matrix<double,6,6> information = (edges[i].covariance+reg*eye).inverse();
00295         for(int p=0; p<6; p++)
00296         {
00297             for(int q=p; q<6; q++)
00298             {
00299                 fprintf(fout,"%lf ",information(p,q));
00300             }
00301         }
00302         fprintf(fout,"\n");
00303     }
00304     fclose(fout);
00305 }
00306 
00307 template <typename PointT>
00308 void NDTMapBuilder<PointT>::saveDatlogFile(const char* fname)
00309 {
00310     //open file
00311     FILE *fout = fopen(fname,"w");
00312 
00313     //go through verices and dump them -- these are the "initial guess"
00314     for(int i=0; i<vertices.size(); i++)
00315     {
00316         Eigen::Vector3d t = vertices[i].pose.translation();
00317         Eigen::Quaternion<double> q;
00318         q = vertices[i].pose.rotation();
00319         fprintf(fout,"%d %lf %lf %lf %lf %lf %lf %lf\n",vertices[i].id,
00320                 t(0),t(1),t(2),q.x(),q.y(),q.z(),q.w());
00321     }
00322     fclose(fout);
00323 
00324     char fn[500];
00325     snprintf(fn,499,"%s.times",fname);
00326 
00327     fout = fopen(fn,"w");
00328     fprintf(fout,"Tr = [");
00329     for( int i=1; i<vertices.size(); i++)
00330     {
00331         fprintf(fout,"%lf ",vertices[i].timeRegistration);
00332     }
00333     fprintf(fout,"];\n");
00334 
00335     fclose(fout);
00336 }
00337 
00338 template <typename PointT>
00339 void NDTMapBuilder<PointT>::printNodePositions()
00340 {
00341     //go through verices and dump them
00342     for(int i=0; i<vertices.size(); i++)
00343     {
00344         std::cout<<vertices[i].pose.translation().transpose()<<" "<<vertices[i].pose.rotation().eulerAngles(0,1,2)<<std::endl;
00345     }
00346 }
00347 
00348 template <typename PointT>
00349 void NDTMapBuilder<PointT>::theMotherOfAllPointClouds(const char* fname)
00350 {
00351     //go through and dump stuff
00352     FILE *fout = fopen(fname,"w");
00353     fprintf(fout,"#VRML V2.0 utf8\n");
00354     for( int i=0; i<vertices.size(); i++)
00355     {
00356         pcl::PointCloud<PointT> cloud3 = lslgeneric::transformPointCloud(vertices[i].pose,vertices[i].scan);
00357         pcl::PointCloud<PointT> cloud3SS;
00358         for(int q=0; q<cloud3.points.size(); q++)
00359         {
00360             if(q%10 == 0) cloud3SS.points.push_back(cloud3.points[q]);
00361         }
00362 
00363         //ODD = green, even = white
00364         if(i%2)
00365         {
00366             //green = target
00367             lslgeneric::writeToVRML(fout,cloud3SS,Eigen::Vector3d(0,1,0));
00368         }
00369         else
00370         {
00371             //white = final
00372             lslgeneric::writeToVRML(fout,cloud3SS,Eigen::Vector3d(1,1,1));
00373         }
00374     }
00375     fclose(fout);
00376 
00377 }
00378 }


ndt_map_builder
Author(s): Todor Stoyanov
autogenerated on Mon Oct 6 2014 03:20:19