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


ndt_map_builder
Author(s): Todor Stoyanov
autogenerated on Wed Aug 26 2015 15:25:12