42 #include <QApplication> 51 "rtabmap-report [\"Statistic/Id\"] [options] path\n" 53 "[Not built with Qt, statistics cannot be plotted]\n" 55 " path Directory containing rtabmap databases or path of a database.\n" 57 " --latex Print table formatted in LaTeX with results.\n" 58 " --kitti Compute error based on KITTI benchmark.\n" 59 " --relative Compute relative motion error between poses.\n" 60 " --loop Compute relative motion error of loop closures.\n" 61 " --scale Find the best scale for the map against the ground truth\n" 62 " and compute error based on the scaled path.\n" 63 " --poses Export poses to [path]_poses.txt, ground truth to [path]_gt.txt\n" 64 " and valid ground truth indices to [path]_indices.txt \n" 65 " --stats Show available statistics \"Statistic/Id\" to plot or get localization statistics (if path is a file). \n" 67 " --invert When reading many databases, put all curves from a same \n" 68 " database in same figure, instead of all same curves from \n" 69 " different database in same figure. When reading a single \n" 70 " database, the inverse will be done. \n" 71 " --ids Use IDs for x axis instead of time in the figures. \n" 72 " --start # Start from this node ID for the figures.\n" 73 " --export Export figures' data to txt files.\n" 74 " --export_prefix Prefix to filenames of exported figures' data (default is \"Stat\").\n" 76 " --report Export all evaluation statistics values in report.txt \n" 77 " --loc # Show localization statistics for each \"Statistic/Id\" per\n" 78 " session for 1=min,2=max,4=mean,8=stddev,16=total,32=nonnull%%\n" 79 " --loc_delay # Delay to split sessions for localization statistics (default 60 seconds)\n" 80 " (it is a mask, we can combine those numbers, e.g., 63 for all) \n" 81 " --help Show usage\n\n");
93 values.
total = array.size();
97 for(
size_t j=0; j<array.size(); ++j)
126 QApplication
app(argc, argv);
129 bool outputLatex =
false;
130 bool outputScaled =
false;
131 bool outputPoses =
false;
132 bool outputKittiError =
false;
133 bool outputRelativeError =
false;
134 bool outputReport =
false;
135 bool outputLoopAccuracy =
false;
136 bool showAvailableStats =
false;
137 bool invertFigures =
false;
140 bool exportFigures =
false;
141 std::string exportPrefix =
"Stat";
144 std::vector<std::string> statsToShow;
146 std::map<std::string, UPlot*> figures;
148 for(
int i=1; i<argc-1; ++i)
150 if(strcmp(argv[i],
"--help") == 0)
154 else if(strcmp(argv[i],
"--latex") == 0)
158 else if(strcmp(argv[i],
"--kitti") == 0)
160 outputKittiError =
true;
162 else if(strcmp(argv[i],
"--relative") == 0)
164 outputRelativeError =
true;
166 else if(strcmp(argv[i],
"--scale") == 0)
170 else if(strcmp(argv[i],
"--poses") == 0)
174 else if(strcmp(argv[i],
"--loop") == 0)
176 outputLoopAccuracy =
true;
178 else if(strcmp(argv[i],
"--report") == 0)
182 else if(strcmp(argv[i],
"--stats") == 0)
184 showAvailableStats =
true;
186 else if(strcmp(argv[i],
"--invert") == 0)
188 invertFigures =
true;
190 else if(strcmp(argv[i],
"--ids") == 0)
194 else if(strcmp(argv[i],
"--export") == 0)
196 exportFigures =
true;
198 else if(strcmp(argv[i],
"--export_prefix") == 0)
203 exportPrefix = argv[i];
204 printf(
"Export prefix=%s (--export_prefix)\n", exportPrefix.c_str());
208 printf(
"Missing value for \"--export_prefix\" option.\n");
212 else if(strcmp(argv[i],
"--loc") == 0)
217 showLoc = atoi(argv[i]);
218 printf(
"Localization statistics=%d (--loc)\n", showLoc);
222 printf(
"Missing type for \"--loc\" option.\n");
226 else if(strcmp(argv[i],
"--loc_delay") == 0)
231 locDelay = atof(argv[i]);
232 printf(
"Localization delay=%fs (--loc_delay)\n", locDelay);
236 printf(
"Missing value for \"--loc_delay\" option.\n");
240 else if(strcmp(argv[i],
"--start") == 0)
245 startId = atoi(argv[i]);
246 printf(
"Figures will be plotted from id=%d (--start)\n", startId);
250 printf(
"Missing id for \"--start\" option.\n");
257 statsToShow.push_back(argv[i]);
261 std::string path = argv[argc-1];
266 invertFigures = !invertFigures;
268 std::map<std::string, std::vector<std::pair<std::string, std::vector<LocStats> > > > localizationMultiStats;
269 for(
size_t i=0; i<statsToShow.size(); ++i)
271 std::string figureTitle = statsToShow[i];
275 printf(
"Plot %s\n", figureTitle.c_str());
277 fig->resize(QSize(640,480));
278 fig->setWindowTitle(figureTitle.c_str());
281 fig->setXLabel(
"Node ID");
285 fig->setXLabel(
"Time (s)");
287 figures.insert(std::make_pair(figureTitle, fig));
290 if(showLoc & 0b111111)
292 localizationMultiStats.insert(std::make_pair(figureTitle, std::vector<std::pair<std::string, std::vector<LocStats> > >()));
300 std::string fileName;
301 std::list<std::string> paths;
302 paths.push_back(path);
303 std::vector<std::map<std::string, std::vector<float> > > outputLatexStatistics;
304 std::map<std::string, std::vector<float> > outputLatexStatisticsMap;
305 bool odomRAMSet =
false;
306 std::set<std::string> topDirs;
309 std::string currentPath = paths.front();
312 bool currentPathIsDatabase =
false;
317 currentPathIsDatabase=
true;
318 printf(
"Database: %s\n", currentPath.c_str());
325 std::list<std::string> subDirs;
326 if(!currentPathIsDatabase)
328 printf(
"Directory: %s\n", currentPath.c_str());
329 std::list<std::string> fileNames = currentDir.
getFileNames();
332 for(std::list<std::string>::iterator iter = fileNames.begin(); iter!=fileNames.end(); ++iter)
334 topDirs.insert(currentPath+
"/"+*iter);
339 if(topDirs.find(currentPath) != topDirs.end())
341 if(outputLatexStatisticsMap.size())
343 outputLatexStatistics.push_back(outputLatexStatisticsMap);
344 outputLatexStatisticsMap.clear();
351 while(currentPathIsDatabase || !(fileName = currentDir.
getNextFileName()).empty())
353 int startIdPerDb = startId;
356 std::string filePath;
357 if(currentPathIsDatabase)
359 filePath = currentPath;
376 std::map<int, std::pair<std::map<std::string, float>,
double> > stats = driver->
getAllStatistics();
377 std::map<int, Transform> odomPoses, gtPoses;
378 std::map<int, double> odomStamps;
379 std::vector<float> cameraTime;
380 cameraTime.reserve(ids.size());
381 std::vector<float> odomTime;
382 odomTime.reserve(ids.size());
383 std::vector<float> slamTime;
384 slamTime.reserve(ids.size());
387 float maxOdomRAM = -1;
388 float maxMapRAM = -1;
390 if(currentPathIsDatabase && showAvailableStats)
392 std::map<std::string, int> availableStats;
393 for(std::set<int>::iterator iter=ids.begin(); iter!=ids.end(); ++iter)
395 if(stats.find(*iter) != stats.end())
397 for(std::map<std::string, float>::iterator jter=stats.at(*iter).first.begin(); jter!=stats.at(*iter).first.end(); ++jter)
399 if(availableStats.find(jter->first) != availableStats.end())
401 ++availableStats.at(jter->first);
405 availableStats.insert(std::make_pair(jter->first, 1));
410 printf(
"Showing available statistics in \"%s\":\n", filePath.c_str());
411 for(std::map<std::string, int>::iterator iter=availableStats.begin(); iter!=availableStats.end(); ++iter)
413 printf(
"%s (%d)\n", iter->first.c_str(), iter->second);
419 std::map<std::string, UPlotCurve*> curves;
420 if(statsToShow.empty())
422 for(std::map<std::string, UPlot*>::iterator iter=figures.begin(); iter!=figures.end(); ++iter)
424 curves.insert(std::make_pair(iter->first, iter->second->addCurve(filePath.c_str())));
425 if(!localizationMultiStats.empty())
426 localizationMultiStats.at(iter->first).push_back(std::make_pair(fileName, std::vector<LocStats>()));
432 fig->setWindowTitle(filePath.c_str());
441 if(!figures.insert(std::make_pair(filePath.c_str(), fig)).second)
444 printf(
"Figure %s already added!\n", filePath.c_str());
448 for(
size_t i=0; i<statsToShow.size(); ++i)
450 curves.insert(std::make_pair(statsToShow[i], fig->
addCurve(statsToShow[i].c_str())));
451 if(!localizationMultiStats.empty())
452 localizationMultiStats.at(statsToShow[i]).push_back(std::make_pair(fileName, std::vector<LocStats>()));
457 for(
size_t i=0; i<statsToShow.size(); ++i)
459 if(!localizationMultiStats.empty())
460 localizationMultiStats.at(statsToShow[i]).push_back(std::make_pair(fileName, std::vector<LocStats>()));
465 std::set<int> mappingSessionIds;
466 if(!localizationMultiStats.empty())
471 for(std::map<int, Transform>::iterator iter=poses.begin(); iter!=poses.end(); ++iter)
478 std::vector<float> v;
480 if(driver->
getNodeInfo(iter->first, p, m, w, l, s, gt, v, gps, sensors))
482 mappingSessionIds.insert(m);
488 startIdPerDb = poses.rbegin()->first+1;
493 std::map<std::string, std::vector<float> > localizationSessionStats;
494 double previousStamp = 0.0;
495 for(std::set<int>::iterator iter=ids.begin(); iter!=ids.end(); ++iter)
502 std::vector<float> v;
504 if(driver->
getNodeInfo(*iter, p, m, w, l, s, gt, v, gps, sensors))
506 odomPoses.insert(std::make_pair(*iter, p));
507 odomStamps.insert(std::make_pair(*iter, s));
510 gtPoses.insert(std::make_pair(*iter, gt));
513 if(!localizationMultiStats.empty() && mappingSessionIds.find(m) != mappingSessionIds.end())
518 if(*iter >= startIdPerDb &&
uContains(stats, *iter))
520 const std::map<std::string, float> & stat = stats.at(*iter).first;
521 if(
uContains(stat, Statistics::kGtTranslational_rmse()))
523 rmse = stat.at(Statistics::kGtTranslational_rmse());
524 if(maxRMSE==-1 || maxRMSE < rmse)
529 if(
uContains(stat, std::string(
"Camera/TotalTime/ms")))
531 cameraTime.push_back(stat.at(std::string(
"Camera/TotalTime/ms")));
533 if(
uContains(stat, std::string(
"Odometry/TotalTime/ms")))
535 odomTime.push_back(stat.at(std::string(
"Odometry/TotalTime/ms")));
537 else if(
uContains(stat, std::string(
"Odometry/TimeEstimation/ms")))
539 odomTime.push_back(stat.at(std::string(
"Odometry/TimeEstimation/ms")));
542 if(
uContains(stat, std::string(
"RtabmapROS/TotalTime/ms")))
546 slamTime.push_back(stat.at(
"RtabmapROS/TotalTime/ms"));
549 else if(
uContains(stat, Statistics::kTimingTotal()))
553 slamTime.push_back(stat.at(Statistics::kTimingTotal()));
557 if(
uContains(stat, std::string(Statistics::kMemoryRAM_usage())))
559 float ram = stat.at(Statistics::kMemoryRAM_usage());
560 if(maxMapRAM==-1 || maxMapRAM < ram)
565 if(
uContains(stat, std::string(
"Odometry/RAM_usage/MB")))
567 float ram = stat.at(
"Odometry/RAM_usage/MB");
568 if(maxOdomRAM==-1 || maxOdomRAM < ram)
575 for(std::map<std::string, UPlotCurve*>::iterator jter=curves.begin(); jter!=curves.end(); ++jter)
578 for(std::map<std::string, std::vector<std::pair<std::string, std::vector<LocStats> > > >::iterator jter=localizationMultiStats.begin();
579 jter!=localizationMultiStats.end();
585 double y = stat.at(jter->first);
592 jter->second->addValue(x,y);
595 if(!localizationMultiStats.empty())
597 if(previousStamp > 0 && fabs(s - previousStamp) > locDelay &&
uContains(localizationSessionStats, jter->first))
600 for(std::map<std::string, std::vector<float> >::iterator kter=localizationSessionStats.begin(); kter!=localizationSessionStats.end(); ++kter)
603 localizationMultiStats.at(kter->first).rbegin()->second.push_back(values);
604 localizationSessionStats.at(kter->first).clear();
610 if(!
uContains(localizationSessionStats, jter->first))
612 localizationSessionStats.insert(std::make_pair(jter->first, std::vector<float>()));
614 localizationSessionStats.at(jter->first).push_back(y);
623 for(std::map<std::string, std::vector<std::pair<std::string, std::vector<LocStats> > > >::iterator jter=localizationMultiStats.begin();
624 jter!=localizationMultiStats.end();
627 if(
uContains(localizationSessionStats, jter->first) &&
628 !localizationSessionStats.at(jter->first).empty())
632 localizationMultiStats.at(jter->first).rbegin()->second.push_back(values);
636 std::multimap<int, Link> links;
637 std::multimap<int, Link> allLinks;
639 std::multimap<int, Link> loopClosureLinks;
640 for(std::multimap<int, Link>::iterator jter=allLinks.begin(); jter!=allLinks.end(); ++jter)
642 if(jter->second.from() == jter->second.to() ||
graph::findLink(links, jter->second.from(), jter->second.to(),
true) == links.end())
648 graph::findLink(loopClosureLinks, jter->second.from(), jter->second.to()) == loopClosureLinks.end())
650 loopClosureLinks.insert(*jter);
654 float bestScale = 1.0f;
656 float bestRMSEAng = -1;
657 float bestVoRMSE = -1;
659 float kitti_t_err = 0.0f;
660 float kitti_r_err = 0.0f;
661 float relative_t_err = 0.0f;
662 float relative_r_err = 0.0f;
663 float loop_t_err = 0.0f;
664 float loop_r_err = 0.0f;
668 std::map<int, Transform> posesOut;
669 std::multimap<int, Link> linksOut;
670 int firstId = *ids.begin();
672 bool useOdomGravity = Parameters::defaultMemUseOdomGravity();
676 for(std::map<int, Transform>::iterator iter=odomPoses.begin(); iter!=odomPoses.end(); ++iter)
678 links.insert(std::make_pair(iter->first,
Link(iter->first, iter->first,
Link::kGravity, iter->second)));
683 std::map<int, Transform> poses = optimizer->
optimize(firstId, posesOut, linksOut);
687 UWARN(
"Optimization failed! Try incremental optimization...");
691 UERROR(
"Incremental optimization also failed! Only original RMSE will be shown.");
696 UWARN(
"Incremental optimization succeeded!");
702 std::map<int, Transform> groundTruth;
703 for(std::map<int, Transform>::const_iterator iter=poses.begin(); iter!=poses.end(); ++iter)
705 if(gtPoses.find(iter->first) != gtPoses.end())
707 groundTruth.insert(*gtPoses.find(iter->first));
711 outputScaled = outputScaled && groundTruth.size();
714 std::map<int, Transform> scaledPoses;
715 std::map<int, Transform> scaledOdomPoses;
717 for(std::map<int, Transform>::iterator iter=poses.begin(); iter!=poses.end(); ++iter)
723 scaledPoses.insert(std::make_pair(iter->first, t));
725 UASSERT(posesOut.find(iter->first)!=posesOut.end());
726 t = posesOut.at(iter->first).
clone();
730 scaledOdomPoses.insert(std::make_pair(iter->first, t));
733 float translational_rmse = 0.0f;
734 float translational_mean = 0.0f;
735 float translational_median = 0.0f;
736 float translational_std = 0.0f;
737 float translational_min = 0.0f;
738 float translational_max = 0.0f;
739 float rotational_rmse = 0.0f;
740 float rotational_mean = 0.0f;
741 float rotational_median = 0.0f;
742 float rotational_std = 0.0f;
743 float rotational_min = 0.0f;
744 float rotational_max = 0.0f;
751 translational_median,
761 float translational_rmse_vo = translational_rmse;
768 translational_median,
779 if(bestRMSE!=-1 && translational_rmse > bestRMSE)
783 bestRMSE = translational_rmse;
784 bestVoRMSE = translational_rmse_vo;
785 bestRMSEAng = rotational_rmse;
787 bestGtToMap = gtToMap;
795 for(std::map<int, Transform>::iterator iter=poses.begin(); iter!=poses.end(); ++iter)
797 iter->second.
x()*=bestScale;
798 iter->second.y()*=bestScale;
799 iter->second.z()*=bestScale;
800 iter->second = bestGtToMap * iter->second;
803 if(outputRelativeError)
805 if(groundTruth.size() == poses.size())
812 std::vector<Transform> gtPoses;
813 std::vector<Transform> rPoses;
814 for(std::map<int, Transform>::iterator iter=poses.begin(); iter!=poses.end(); ++iter)
816 if(groundTruth.find(iter->first) != groundTruth.end())
818 gtPoses.push_back(groundTruth.at(iter->first));
819 rPoses.push_back(poses.at(iter->first));
831 if(groundTruth.size() == poses.size())
838 printf(
"Cannot compute KITTI statistics as optimized poses and ground truth don't have the same size (%d vs %d).\n",
839 (
int)poses.size(), (int)groundTruth.size());
847 dbName = dbName.substr(0, dbName.size()-3);
849 std::multimap<int, Link> dummyLinks;
850 std::map<int, double> stamps;
851 if(!outputKittiError)
853 for(std::map<int, Transform>::iterator iter=poses.begin(); iter!=poses.end(); ++iter)
855 UASSERT(odomStamps.find(iter->first) != odomStamps.end());
856 stamps.insert(*odomStamps.find(iter->first));
861 printf(
"Could not export the poses to \"%s\"!?!\n", path.c_str());
867 if(!outputKittiError)
869 for(std::map<int, Transform>::iterator iter=odomPoses.begin(); iter!=odomPoses.end(); ++iter)
871 UASSERT(odomStamps.find(iter->first) != odomStamps.end());
872 stamps.insert(*odomStamps.find(iter->first));
877 printf(
"Could not export the ground truth to \"%s\"!?!\n", path.c_str());
881 if(groundTruth.size())
885 if(!outputKittiError)
887 for(std::map<int, Transform>::iterator iter=groundTruth.begin(); iter!=groundTruth.end(); ++iter)
889 UASSERT(odomStamps.find(iter->first) != odomStamps.end());
890 stamps.insert(*odomStamps.find(iter->first));
895 printf(
"Could not export the ground truth to \"%s\"!?!\n", path.c_str());
902 bool fillHeader =
false;
903 std::ifstream
f(
"report.csv");
909 std::ofstream myfile;
910 myfile.open(
"report.csv", std::fstream::in | std::fstream::out |
std::fstream::app);
913 myfile <<
"Rosbag name"<<
";"<<
"error linear (m)"<<
";"<<
"error linear max (m)"<<
";"<<
"error linear odom (m)"<<
";" 914 <<
"error angular"<<
";" 915 <<
"Slam avg (hz)"<<
";"<<
"Slam max (hz)"<<
";" 916 <<
"Odom avg (hz)"<<
";"<<
"Odom max (hz)"<<std::endl;
919 myfile <<fileName.c_str()<<
";" 924 <<(1/(
uMean(slamTime)/1000.0))<<
";" 925 <<(1/(
uMax(slamTime)/1000.0))<<
";" 926 <<(1/(
uMean(odomTime)/1000.0))<<
";" 927 <<(1/(
uMax(odomTime)/1000.0))<<
";"<<std::endl;
931 if(outputLoopAccuracy && !groundTruth.empty() && !linksOut.empty())
933 float sumDist = 0.0f;
934 float sumAngle = 0.0f;
936 for(std::multimap<int, Link>::iterator iter=loopClosureLinks.begin(); iter!=loopClosureLinks.end(); ++iter)
938 if( groundTruth.find(iter->second.from())!=groundTruth.end() &&
939 groundTruth.find(iter->second.to())!=groundTruth.end())
941 Transform gtLink = groundTruth.at(iter->second.from()).
inverse()*groundTruth.at(iter->second.to());
942 const Transform & t = iter->second.transform();
949 sumAngle += diff.getAngle();
955 loop_t_err = sumDist/float(count);
956 loop_r_err = sumAngle/float(count);
957 loop_r_err *= 180/CV_PI;
962 printf(
" %s (%d, s=%.3f):\terror lin=%.3fm (max=%.3fm, odom=%.3fm) ang=%.1fdeg%s%s, %s: avg=%dms (max=%dms) loops=%d%s, odom: avg=%dms (max=%dms), camera: avg=%dms, %smap=%dMB\n",
970 !outputKittiError?
"":
uFormat(
", KITTI: t_err=%.2f%% r_err=%.2f deg/100m", kitti_t_err, kitti_r_err*100).c_str(),
971 !outputRelativeError?
"":
uFormat(
", Relative: t_err=%.3fm r_err=%.2f deg", relative_t_err, relative_r_err).c_str(),
972 !localizationMultiStats.empty()?
"loc":
"slam",
973 (int)
uMean(slamTime), (int)
uMax(slamTime),
974 (int)loopClosureLinks.size(),
975 !outputLoopAccuracy?
"":
uFormat(
" (t_err=%.3fm r_err=%.2f deg)", loop_t_err, loop_r_err).c_str(),
976 (int)
uMean(odomTime), (int)
uMax(odomTime),
977 (int)
uMean(cameraTime),
978 maxOdomRAM!=-1.0f?
uFormat(
"RAM odom=%dMB ", (
int)maxOdomRAM).c_str():
"",
983 std::vector<float> stats;
984 stats.push_back(ids.size());
985 stats.push_back(bestRMSE);
986 stats.push_back(maxRMSE);
987 stats.push_back(bestRMSEAng);
988 stats.push_back(
uMean(odomTime));
989 stats.push_back(
uMean(slamTime));
990 stats.push_back(
uMax(slamTime));
991 stats.push_back(maxOdomRAM);
992 stats.push_back(maxMapRAM);
993 outputLatexStatisticsMap.insert(std::make_pair(filePath, stats));
995 if(maxOdomRAM != -1.0
f)
1004 else if(
uSplit(fileName,
'.').size() == 1)
1009 currentPathIsDatabase =
false;
1012 if(!localizationMultiStats.empty())
1014 printf(
"---Localization results---\n");
1015 std::string prefix =
"header={";
1016 printf(
"%s", prefix.c_str());
1017 for(std::vector<std::pair<std::string, std::vector<LocStats> > >::iterator iter=localizationMultiStats.begin()->second.begin();
1018 iter!=localizationMultiStats.begin()->second.end();)
1020 if(iter!=localizationMultiStats.begin()->second.begin())
1022 printf(
"%s", std::string(prefix.size(),
' ').c_str());
1024 printf(
"%s", iter->first.c_str());
1026 if(iter!=localizationMultiStats.begin()->second.end())
1034 for(std::map<std::string, std::vector<std::pair<std::string, std::vector<LocStats> > > >::iterator iter=localizationMultiStats.begin();
1035 iter!=localizationMultiStats.end();
1038 printf(
"%s\n", iter->first.c_str());
1039 for(
int k=0; k<6; ++k)
1041 if(showLoc & (0x1 << k))
1043 std::string prefix =
uFormat(
" %s=[",
1050 printf(
"%s", prefix.c_str());
1051 for(std::vector<std::pair<std::string, std::vector<LocStats> > >::iterator jter=iter->second.begin(); jter!=iter->second.end();)
1053 if(jter!=iter->second.begin())
1055 printf(
"%s", std::string(prefix.size(),
' ').c_str());
1057 for(
size_t j=0; j<jter->second.size(); ++j)
1062 k==0?jter->second[j].min:
1063 k==1?jter->second[j].max:
1064 k==2?jter->second[j].mean:
1065 jter->second[j].stddev);
1069 printf(
"%d",jter->second[j].total);
1073 printf(
"%.2f", (jter->second[j].nonNull*100));
1075 if(j+1 < jter->second.size())
1081 if(jter!=iter->second.end())
1089 iter->second.clear();
1092 for(std::list<std::string>::iterator iter=subDirs.begin(); iter!=subDirs.end(); ++iter)
1094 paths.push_front(*iter);
1097 if(outputLatexStatisticsMap.size() && paths.empty())
1099 outputLatexStatistics.push_back(outputLatexStatisticsMap);
1100 outputLatexStatisticsMap.clear();
1104 if(outputLatex && outputLatexStatistics.size())
1106 printf(
"\nLaTeX output:\n----------------\n");
1107 printf(
"\\begin{table*}[!t]\n");
1108 printf(
"\\caption{$t_{end}$ is the absolute translational RMSE value at the end " 1109 "of the experiment as $ATE_{max}$ is the maximum during the experiment. " 1110 "$r_{end}$ is rotational RMSE value at the end of the experiment. " 1111 "$o_{avg}$ and $m_{avg}$ are the average computational time " 1112 "for odometry (front-end) and map update (back-end). " 1113 "$m_{avg}$ is the maximum computational time for map update. " 1114 "$O_{end}$ and $M_{end}$ are the RAM usage at the end of the experiment " 1115 "for odometry and map management respectively.}\n");
1116 printf(
"\\label{}\n");
1117 printf(
"\\centering\n");
1120 printf(
"\\begin{tabular}{l|c|c|c|c|c|c|c|c|c}\n");
1121 printf(
"\\cline{2-10}\n");
1122 printf(
" & Size & $t_{end}$ & $t_{max}$ & $r_{end}$ & $o_{avg}$ & $m_{avg}$ & $m_{max}$ & $O_{end}$ & $M_{end}$ \\\\\n");
1123 printf(
" & (nodes) & (m) & (m) & (deg) & (ms) & (ms) & (ms) & (MB) & (MB) \\\\\n");
1127 printf(
"\\begin{tabular}{l|c|c|c|c|c|c|c|c}\n");
1128 printf(
"\\cline{2-9}\n");
1129 printf(
" & Size & $t_{end}$ & $t_{max}$ & $r_{end}$ & $o_{avg}$ & $m_{avg}$ & $m_{max}$ & $M_{end}$ \\\\\n");
1130 printf(
" & (nodes) & (m) & (m) & (deg) & (ms) & (ms) & (ms) & (MB) \\\\\n");
1133 printf(
"\\hline\n");
1135 for(
unsigned int j=0; j<outputLatexStatistics.size(); ++j)
1137 if(outputLatexStatistics[j].size())
1139 std::vector<int> lowestIndex;
1140 if(outputLatexStatistics[j].size() > 1)
1142 std::vector<float> lowestValue(outputLatexStatistics[j].begin()->second.size(),-1);
1143 lowestIndex = std::vector<int>(lowestValue.size(),0);
1145 for(std::map<std::string, std::vector<float> >::iterator iter=outputLatexStatistics[j].begin(); iter!=outputLatexStatistics[j].end(); ++iter)
1147 UASSERT(lowestValue.size() == iter->second.size());
1148 for(
unsigned int i=0; i<iter->second.size(); ++i)
1150 if(lowestValue[i] == -1 || (iter->second[i]>0.0f && lowestValue[i]>iter->second[i]))
1152 lowestValue[i] = iter->second[i];
1153 lowestIndex[i] = index;
1161 for(std::map<std::string, std::vector<float> >::iterator iter=outputLatexStatistics[j].begin(); iter!=outputLatexStatistics[j].end(); ++iter)
1163 UASSERT(iter->second.size() == 9);
1164 printf(
"%s & ",
uReplaceChar(iter->first.c_str(),
'_',
'-').c_str());
1165 printf(
"%d & ", (
int)iter->second[0]);
1166 printf(
"%s%.3f%s & ", lowestIndex.size()&&lowestIndex[1]==index?
"\\textbf{":
"", iter->second[1], lowestIndex.size()&&lowestIndex[1]==index?
"}":
"");
1167 printf(
"%s%.3f%s & ", lowestIndex.size()&&lowestIndex[2]==index?
"\\textbf{":
"", iter->second[2], lowestIndex.size()&&lowestIndex[2]==index?
"}":
"");
1168 printf(
"%s%.2f%s & ", lowestIndex.size()&&lowestIndex[3]==index?
"\\textbf{":
"", iter->second[3], lowestIndex.size()&&lowestIndex[3]==index?
"}":
"");
1169 printf(
"%s%d%s & ", lowestIndex.size()&&lowestIndex[4]==index?
"\\textbf{":
"", (int)iter->second[4], lowestIndex.size()&&lowestIndex[4]==index?
"}":
"");
1170 printf(
"%s%d%s & ", lowestIndex.size()&&lowestIndex[5]==index?
"\\textbf{":
"", (int)iter->second[5], lowestIndex.size()&&lowestIndex[5]==index?
"}":
"");
1171 printf(
"%s%d%s & ", lowestIndex.size()&&lowestIndex[6]==index?
"\\textbf{":
"", (int)iter->second[6], lowestIndex.size()&&lowestIndex[6]==index?
"}":
"");
1174 printf(
"%s%d%s & ", lowestIndex.size()&&lowestIndex[7]==index?
"\\textbf{":
"", (int)iter->second[7], lowestIndex.size()&&lowestIndex[7]==index?
"}":
"");
1176 printf(
"%s%d%s ", lowestIndex.size()&&lowestIndex[8]==index?
"\\textbf{":
"", (int)iter->second[8], lowestIndex.size()&&lowestIndex[8]==index?
"}":
"");
1180 printf(
"\\hline\n");
1185 printf(
"\\end{tabular}\n");
1186 printf(
"\\end{table*}\n----------------\n");
1191 for(std::map<std::string, UPlot*>::iterator iter=figures.begin(); iter!=figures.end(); ++iter)
1195 iter->second->frameData();
1199 QString data = iter->second->getAllCurveDataAsText();
1202 QString filePath = QString(exportPrefix.c_str()) + (exportPrefix.empty()?
"":
"-") + iter->second->windowTitle().replace(
'/',
"-") +
".txt";
1203 QFile file(filePath);
1204 if(file.open(QIODevice::Text | QIODevice::WriteOnly))
1206 file.write(data.toUtf8());
1208 printf(
"Exported \"%s\".\n", filePath.toStdString().c_str());
1212 printf(
"ERROR: could not open file \"%s\" for writing!\n", filePath.toStdString().c_str());
1218 iter->second->show();
static std::string homeDir()
T uVariance(const T *v, unsigned int size, T meanV)
static bool parse(const ParametersMap ¶meters, const std::string &key, bool &value)
T uMean(const T *v, unsigned int size)
void uMinMax(const T *v, unsigned int size, T &min, T &max, unsigned int &indexMin, unsigned int &indexMax)
const std::list< std::string > & getFileNames() const
GLM_FUNC_DECL vecType< T, P > sqrt(vecType< T, P > const &x)
void getAllNodeIds(std::set< int > &ids, bool ignoreChildren=false, bool ignoreBadSignatures=false) const
static std::string getDir(const std::string &filePath)
static std::string separator()
std::map< std::string, std::string > ParametersMap
Basic mathematics functions.
std::string getExtension()
static void setLevel(ULogger::Level level)
static LocStats from(const std::vector< float > &array)
std::list< std::string > uSplit(const std::string &str, char separator= ' ')
bool openConnection(const std::string &url, bool overwritten=false)
#define UASSERT(condition)
Wrappers of STL for convenient functions.
std::map< int, Transform > optimizeIncremental(int rootId, const std::map< int, Transform > &poses, const std::multimap< int, Link > &constraints, std::list< std::map< int, Transform > > *intermediateGraphes=0, double *finalError=0, int *iterationsDone=0)
void getAllLinks(std::multimap< int, Link > &links, bool ignoreNullLinks=true, bool withLandmarks=false) const
UPlotCurve * addCurve(const QString &curveName, const QColor &color=QColor())
void closeConnection(bool save=true, const std::string &outputUrl="")
std::map< int, Transform > optimize(int rootId, const std::map< int, Transform > &poses, const std::multimap< int, Link > &constraints, std::list< std::map< int, Transform > > *intermediateGraphes=0, double *finalError=0, int *iterationsDone=0)
std::map< int, std::pair< std::map< std::string, float >, double > > getAllStatistics() const
Transform RTABMAP_EXP calcRMSE(const std::map< int, Transform > &groundTruth, const std::map< int, Transform > &poses, float &translational_rmse, float &translational_mean, float &translational_median, float &translational_std, float &translational_min, float &translational_max, float &rotational_rmse, float &rotational_mean, float &rotational_median, float &rotational_std, float &rotational_min, float &rotational_max)
static void setType(Type type, const std::string &fileName=kDefaultLogFileName, bool append=true)
std::string UTILITE_EXP uReplaceChar(const std::string &str, char before, char after)
bool uContains(const std::list< V > &list, const V &value)
bool RTABMAP_EXP exportPoses(const std::string &filePath, int format, const std::map< int, Transform > &poses, const std::multimap< int, Link > &constraints=std::multimap< int, Link >(), const std::map< int, double > &stamps=std::map< int, double >(), const ParametersMap ¶meters=ParametersMap())
static DBDriver * create(const ParametersMap ¶meters=ParametersMap())
bool getNodeInfo(int signatureId, Transform &pose, int &mapId, int &weight, std::string &label, double &stamp, Transform &groundTruthPose, std::vector< float > &velocity, GPS &gps, EnvSensors &sensors) const
T uMax(const T *v, unsigned int size, unsigned int &index)
void getConnectedGraph(int fromId, const std::map< int, Transform > &posesIn, const std::multimap< int, Link > &linksIn, std::map< int, Transform > &posesOut, std::multimap< int, Link > &linksOut) const
void setXLabel(const QString &text)
std::vector< V > uValues(const std::multimap< K, V > &mm)
std::string getNextFileName()
std::multimap< int, Link >::iterator RTABMAP_EXP findLink(std::multimap< int, Link > &links, int from, int to, bool checkBothWays=true)
void RTABMAP_EXP calcRelativeErrors(const std::vector< Transform > &poses_gt, const std::vector< Transform > &poses_result, float &t_err, float &r_err)
ParametersMap getLastParameters() const
ULogger class and convenient macros.
static bool exists(const std::string &dirPath)
int main(int argc, char *argv[])
std::map< EnvSensor::Type, EnvSensor > EnvSensors
std::string UTILITE_EXP uFormat(const char *fmt,...)
static Optimizer * create(const ParametersMap ¶meters)
void RTABMAP_EXP calcKittiSequenceErrors(const std::vector< Transform > &poses_gt, const std::vector< Transform > &poses_result, float &t_err, float &r_err)
GLM_FUNC_DECL matType< T, P > inverse(matType< T, P > const &m)
std::map< int, Transform > loadOptimizedPoses(Transform *lastlocalizationPose=0) const