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 " --inc Incremental optimization. \n" 66 " --stats Show available statistics \"Statistic/Id\" to plot or get localization statistics (if path is a file). \n" 68 " --invert When reading many databases, put all curves from a same \n" 69 " database in same figure, instead of all same curves from \n" 70 " different database in same figure. When reading a single \n" 71 " database, the inverse will be done. \n" 72 " --ids Use IDs for x axis instead of time in the figures. \n" 73 " --start # Start from this node ID for the figures.\n" 74 " --export Export figures' data to txt files.\n" 75 " --export_prefix Prefix to filenames of exported figures' data (default is \"Stat\").\n" 77 " --report Export all evaluation statistics values in report.txt \n" 78 " --loc [#] Show localization statistics for each \"Statistic/Id\" per\n" 79 " session. Optionally set number 1=min,2=max,4=mean,8=stddev,16=total,32=nonnull%%\n" 80 " to show cumulative results on console.\n" 81 " --loc_delay # Delay to split sessions for localization statistics (default 60 seconds)\n" 82 " (it is a mask, we can combine those numbers, e.g., 63 for all) \n" 83 " --ignore_inter_nodes Ignore intermediate poses and statistics.\n" 84 " --udebug Show debug log.\n" 85 " --help,-h Show usage\n\n");
97 values.
total = array.size();
101 for(
size_t j=0; j<array.size(); ++j)
130 QApplication
app(argc, argv);
133 bool outputLatex =
false;
134 bool outputScaled =
false;
135 bool outputPoses =
false;
136 bool outputKittiError =
false;
137 bool outputRelativeError =
false;
138 bool outputReport =
false;
139 bool outputLoopAccuracy =
false;
140 bool incrementalOptimization =
false;
141 bool showAvailableStats =
false;
142 bool invertFigures =
false;
143 bool ignoreInterNodes =
false;
146 bool exportFigures =
false;
147 std::string exportPrefix =
"Stat";
150 std::vector<std::string> statsToShow;
152 std::map<std::string, UPlot*> figures;
154 for(
int i=1; i<argc; ++i)
156 if(strcmp(argv[i],
"--help") == 0 || strcmp(argv[i],
"--h") == 0)
160 else if(strcmp(argv[i],
"--udebug") == 0)
164 else if(strcmp(argv[i],
"--latex") == 0)
168 else if(strcmp(argv[i],
"--kitti") == 0)
170 outputKittiError =
true;
172 else if(strcmp(argv[i],
"--relative") == 0)
174 outputRelativeError =
true;
176 else if(strcmp(argv[i],
"--scale") == 0)
180 else if(strcmp(argv[i],
"--poses") == 0)
184 else if(strcmp(argv[i],
"--loop") == 0)
186 outputLoopAccuracy =
true;
188 else if(strcmp(argv[i],
"--report") == 0)
192 else if(strcmp(argv[i],
"--inc") == 0)
194 incrementalOptimization =
true;
196 else if(strcmp(argv[i],
"--stats") == 0)
198 showAvailableStats =
true;
200 else if(strcmp(argv[i],
"--invert") == 0)
202 invertFigures =
true;
204 else if(strcmp(argv[i],
"--ids") == 0)
208 else if(strcmp(argv[i],
"--ignore_inter_nodes") == 0)
210 ignoreInterNodes =
true;
212 else if(strcmp(argv[i],
"--export") == 0)
214 exportFigures =
true;
216 else if(strcmp(argv[i],
"--export_prefix") == 0)
221 exportPrefix = argv[i];
222 printf(
"Export prefix=%s (--export_prefix)\n", exportPrefix.c_str());
226 printf(
"Missing value for \"--export_prefix\" option.\n");
230 else if(strcmp(argv[i],
"--loc") == 0)
237 showLoc = atoi(argv[i]);
238 printf(
"Localization statistics=%d (--loc)\n", showLoc);
244 printf(
"Localization statistics (--loc)\n");
249 printf(
"Missing type for \"--loc\" option.\n");
253 else if(strcmp(argv[i],
"--loc_delay") == 0)
258 locDelay = atof(argv[i]);
259 printf(
"Localization delay=%fs (--loc_delay)\n", locDelay);
263 printf(
"Missing value for \"--loc_delay\" option.\n");
267 else if(strcmp(argv[i],
"--start") == 0)
272 startId = atoi(argv[i]);
273 printf(
"Figures will be plotted from id=%d (--start)\n", startId);
277 printf(
"Missing id for \"--start\" option.\n");
284 statsToShow.push_back(argv[i]);
288 std::string path = argv[argc-1];
293 invertFigures = !invertFigures;
295 std::map<std::string, std::vector<std::pair<std::string, std::vector<LocStats> > > > localizationMultiStats;
296 for(
size_t i=0; i<statsToShow.size(); ++i)
298 std::string figureTitle = statsToShow[i];
302 printf(
"Plot %s\n", figureTitle.c_str());
304 fig->resize(QSize(640,480));
305 fig->setWindowTitle(figureTitle.c_str());
308 fig->setXLabel(
"Node ID");
312 fig->setXLabel(
"Time (s)");
314 figures.insert(std::make_pair(figureTitle, fig));
317 if(showLoc & 0b111111)
319 localizationMultiStats.insert(std::make_pair(figureTitle, std::vector<std::pair<std::string, std::vector<LocStats> > >()));
327 std::string fileName;
328 std::list<std::string> paths;
329 paths.push_back(path);
330 std::vector<std::map<std::string, std::vector<float> > > outputLatexStatistics;
331 std::map<std::string, std::vector<float> > outputLatexStatisticsMap;
332 bool odomRAMSet =
false;
333 std::set<std::string> topDirs;
336 std::string currentPath = paths.front();
339 bool currentPathIsDatabase =
false;
344 currentPathIsDatabase=
true;
345 printf(
"Database: %s\n", currentPath.c_str());
352 std::list<std::string> subDirs;
353 if(!currentPathIsDatabase)
355 printf(
"Directory: %s\n", currentPath.c_str());
356 std::list<std::string> fileNames = currentDir.
getFileNames();
359 for(std::list<std::string>::iterator iter = fileNames.begin(); iter!=fileNames.end(); ++iter)
361 topDirs.insert(currentPath+
"/"+*iter);
366 if(topDirs.find(currentPath) != topDirs.end())
368 if(outputLatexStatisticsMap.size())
370 outputLatexStatistics.push_back(outputLatexStatisticsMap);
371 outputLatexStatisticsMap.clear();
378 while(currentPathIsDatabase || !(fileName = currentDir.
getNextFileName()).empty())
380 int startIdPerDb = startId;
383 std::string filePath;
384 if(currentPathIsDatabase)
386 filePath = currentPath;
407 std::map<int, std::pair<std::map<std::string, float>,
double> > stats = driver->
getAllStatistics();
408 std::map<int, Transform> odomPoses, gtPoses;
409 std::map<int, double> odomStamps;
410 std::vector<float> cameraTime;
411 cameraTime.reserve(ids.size());
412 std::vector<float> odomTime;
413 odomTime.reserve(ids.size());
414 std::vector<float> slamTime;
415 slamTime.reserve(ids.size());
418 float maxOdomRAM = -1;
419 float maxMapRAM = -1;
421 if(currentPathIsDatabase && showAvailableStats)
423 std::map<std::string, int> availableStats;
424 for(std::set<int>::iterator iter=ids.begin(); iter!=ids.end(); ++iter)
426 if(stats.find(*iter) != stats.end())
428 for(std::map<std::string, float>::iterator jter=stats.at(*iter).first.begin(); jter!=stats.at(*iter).first.end(); ++jter)
430 if(availableStats.find(jter->first) != availableStats.end())
432 ++availableStats.at(jter->first);
436 availableStats.insert(std::make_pair(jter->first, 1));
441 printf(
"Showing available statistics in \"%s\":\n", filePath.c_str());
442 for(std::map<std::string, int>::iterator iter=availableStats.begin(); iter!=availableStats.end(); ++iter)
444 printf(
"%s (%d)\n", iter->first.c_str(), iter->second);
450 std::map<std::string, UPlotCurve*> curves;
451 if(statsToShow.empty())
453 for(std::map<std::string, UPlot*>::iterator iter=figures.begin(); iter!=figures.end(); ++iter)
455 curves.insert(std::make_pair(iter->first, iter->second->addCurve(filePath.c_str())));
456 if(!localizationMultiStats.empty())
457 localizationMultiStats.at(iter->first).push_back(std::make_pair(fileName, std::vector<LocStats>()));
463 fig->setWindowTitle(filePath.c_str());
472 if(!figures.insert(std::make_pair(filePath.c_str(), fig)).second)
475 printf(
"Figure %s already added!\n", filePath.c_str());
479 for(
size_t i=0; i<statsToShow.size(); ++i)
481 curves.insert(std::make_pair(statsToShow[i], fig->
addCurve(statsToShow[i].c_str())));
482 if(!localizationMultiStats.empty())
483 localizationMultiStats.at(statsToShow[i]).push_back(std::make_pair(fileName, std::vector<LocStats>()));
488 for(
size_t i=0; i<statsToShow.size(); ++i)
490 if(!localizationMultiStats.empty())
491 localizationMultiStats.at(statsToShow[i]).push_back(std::make_pair(fileName, std::vector<LocStats>()));
496 std::set<int> mappingSessionIds;
497 if(!localizationMultiStats.empty())
502 for(std::map<int, Transform>::iterator iter=poses.begin(); iter!=poses.end(); ++iter)
509 std::vector<float> v;
511 if(driver->
getNodeInfo(iter->first, p, m, w, l, s, gt, v, gps, sensors))
513 mappingSessionIds.insert(m);
519 startIdPerDb = poses.rbegin()->first+1;
524 std::map<std::string, std::vector<float> > localizationSessionStats;
525 double previousStamp = 0.0;
526 for(std::set<int>::iterator iter=ids.begin(); iter!=ids.end(); ++iter)
533 std::vector<float> v;
535 if(driver->
getNodeInfo(*iter, p, m, w, l, s, gt, v, gps, sensors))
537 odomPoses.insert(std::make_pair(*iter, p));
538 odomStamps.insert(std::make_pair(*iter, s));
541 gtPoses.insert(std::make_pair(*iter, gt));
544 if(!localizationMultiStats.empty() && mappingSessionIds.find(m) != mappingSessionIds.end())
549 if(*iter >= startIdPerDb &&
uContains(stats, *iter))
551 const std::map<std::string, float> & stat = stats.at(*iter).first;
552 if(
uContains(stat, Statistics::kGtTranslational_rmse()))
554 rmse = stat.at(Statistics::kGtTranslational_rmse());
555 if(maxRMSE==-1 || maxRMSE < rmse)
560 if(
uContains(stat, std::string(
"Camera/TotalTime/ms")))
562 cameraTime.push_back(stat.at(std::string(
"Camera/TotalTime/ms")));
564 if(
uContains(stat, std::string(
"Odometry/TotalTime/ms")))
566 odomTime.push_back(stat.at(std::string(
"Odometry/TotalTime/ms")));
568 else if(
uContains(stat, std::string(
"Odometry/TimeEstimation/ms")))
570 odomTime.push_back(stat.at(std::string(
"Odometry/TimeEstimation/ms")));
573 if(
uContains(stat, std::string(
"RtabmapROS/TotalTime/ms")))
577 slamTime.push_back(stat.at(
"RtabmapROS/TotalTime/ms"));
580 else if(
uContains(stat, Statistics::kTimingTotal()))
584 slamTime.push_back(stat.at(Statistics::kTimingTotal()));
588 if(
uContains(stat, std::string(Statistics::kMemoryRAM_usage())))
590 float ram = stat.at(Statistics::kMemoryRAM_usage());
591 if(maxMapRAM==-1 || maxMapRAM < ram)
596 if(
uContains(stat, std::string(
"Odometry/RAM_usage/MB")))
598 float ram = stat.at(
"Odometry/RAM_usage/MB");
599 if(maxOdomRAM==-1 || maxOdomRAM < ram)
606 for(std::map<std::string, UPlotCurve*>::iterator jter=curves.begin(); jter!=curves.end(); ++jter)
609 for(std::map<std::string, std::vector<std::pair<std::string, std::vector<LocStats> > > >::iterator jter=localizationMultiStats.begin();
610 jter!=localizationMultiStats.end();
616 double y = stat.at(jter->first);
623 jter->second->addValue(x,y);
626 if(!localizationMultiStats.empty())
628 if(previousStamp > 0 && fabs(s - previousStamp) > locDelay &&
uContains(localizationSessionStats, jter->first))
631 for(std::map<std::string, std::vector<float> >::iterator kter=localizationSessionStats.begin(); kter!=localizationSessionStats.end(); ++kter)
634 localizationMultiStats.at(kter->first).rbegin()->second.push_back(values);
635 localizationSessionStats.at(kter->first).clear();
641 if(!
uContains(localizationSessionStats, jter->first))
643 localizationSessionStats.insert(std::make_pair(jter->first, std::vector<float>()));
645 localizationSessionStats.at(jter->first).push_back(y);
654 for(std::map<std::string, std::vector<std::pair<std::string, std::vector<LocStats> > > >::iterator jter=localizationMultiStats.begin();
655 jter!=localizationMultiStats.end();
658 if(
uContains(localizationSessionStats, jter->first) &&
659 !localizationSessionStats.at(jter->first).empty())
663 localizationMultiStats.at(jter->first).rbegin()->second.push_back(values);
667 std::multimap<int, Link> links;
668 std::multimap<int, Link> allLinks;
670 std::multimap<int, Link> loopClosureLinks;
671 for(std::multimap<int, Link>::iterator jter=allLinks.begin(); jter!=allLinks.end(); ++jter)
673 if(jter->second.from() == jter->second.to() ||
graph::findLink(links, jter->second.from(), jter->second.to(),
true) == links.end())
679 graph::findLink(loopClosureLinks, jter->second.from(), jter->second.to()) == loopClosureLinks.end())
681 loopClosureLinks.insert(*jter);
685 float bestScale = 1.0f;
687 float bestRMSEAng = -1;
688 float bestVoRMSE = -1;
690 float kitti_t_err = 0.0f;
691 float kitti_r_err = 0.0f;
692 float relative_t_err = 0.0f;
693 float relative_r_err = 0.0f;
694 float loop_t_err = 0.0f;
695 float loop_r_err = 0.0f;
699 std::map<int, Transform> posesOut;
700 std::multimap<int, Link> linksOut;
701 int firstId = *ids.begin();
703 bool useOdomGravity = Parameters::defaultMemUseOdomGravity();
707 for(std::map<int, Transform>::iterator iter=odomPoses.begin(); iter!=odomPoses.end(); ++iter)
709 links.insert(std::make_pair(iter->first,
Link(iter->first, iter->first,
Link::kGravity, iter->second)));
712 std::map<int, Transform> posesWithLandmarks = odomPoses;
714 for(std::multimap<int, Link>::iterator iter=links.begin(); iter!=links.end(); ++iter)
718 UASSERT(iter->second.from() > 0 && iter->second.to() < 0);
719 if(posesWithLandmarks.find(iter->second.from()) != posesWithLandmarks.end() && posesWithLandmarks.find(iter->second.to()) == posesWithLandmarks.end())
721 posesWithLandmarks.insert(std::make_pair(iter->second.to(), posesWithLandmarks.at(iter->second.from())*iter->second.transform()));
725 optimizer->
getConnectedGraph(firstId, posesWithLandmarks, links, posesOut, linksOut);
726 std::list<std::map<int, Transform> > intermediateGraphes;
727 std::map<int, Transform> poses = optimizer->
optimize(firstId, posesOut, linksOut, incrementalOptimization?&intermediateGraphes:0);
731 UWARN(
"Optimization failed! Try incremental optimization...");
735 UERROR(
"Incremental optimization also failed! Only original RMSE will be shown.");
740 UWARN(
"Incremental optimization succeeded!");
747 std::map<int, Transform>::iterator iter=poses.begin();
748 while(iter!=poses.end() && iter->first < 0)
753 std::map<int, Transform> groundTruth;
754 for(std::map<int, Transform>::const_iterator iter=poses.begin(); iter!=poses.end(); ++iter)
756 if(gtPoses.find(iter->first) != gtPoses.end())
758 groundTruth.insert(*gtPoses.find(iter->first));
762 outputScaled = outputScaled && groundTruth.size();
765 std::map<int, Transform> scaledPoses;
766 std::map<int, Transform> scaledOdomPoses;
768 for(std::map<int, Transform>::iterator iter=poses.begin(); iter!=poses.end(); ++iter)
774 scaledPoses.insert(std::make_pair(iter->first, t));
776 UASSERT(posesOut.find(iter->first)!=posesOut.end());
777 t = posesOut.at(iter->first).
clone();
781 scaledOdomPoses.insert(std::make_pair(iter->first, t));
784 float translational_rmse = 0.0f;
785 float translational_mean = 0.0f;
786 float translational_median = 0.0f;
787 float translational_std = 0.0f;
788 float translational_min = 0.0f;
789 float translational_max = 0.0f;
790 float rotational_rmse = 0.0f;
791 float rotational_mean = 0.0f;
792 float rotational_median = 0.0f;
793 float rotational_std = 0.0f;
794 float rotational_min = 0.0f;
795 float rotational_max = 0.0f;
802 translational_median,
812 float translational_rmse_vo = translational_rmse;
819 translational_median,
830 if(bestRMSE!=-1 && translational_rmse > bestRMSE)
834 bestRMSE = translational_rmse;
835 bestVoRMSE = translational_rmse_vo;
836 bestRMSEAng = rotational_rmse;
838 bestGtToMap = gtToMap;
846 for(std::map<int, Transform>::iterator iter=poses.begin(); iter!=poses.end(); ++iter)
848 iter->second.
x()*=bestScale;
849 iter->second.y()*=bestScale;
850 iter->second.z()*=bestScale;
851 iter->second = bestGtToMap * iter->second;
854 if(outputRelativeError)
856 if(groundTruth.size() == poses.size())
863 std::vector<Transform> gtPoses;
864 std::vector<Transform> rPoses;
865 for(std::map<int, Transform>::iterator iter=poses.begin(); iter!=poses.end(); ++iter)
867 if(groundTruth.find(iter->first) != groundTruth.end())
869 gtPoses.push_back(groundTruth.at(iter->first));
870 rPoses.push_back(poses.at(iter->first));
882 if(groundTruth.size() == poses.size())
889 printf(
"Cannot compute KITTI statistics as optimized poses and ground truth don't have the same size (%d vs %d).\n",
890 (
int)poses.size(), (int)groundTruth.size());
898 dbName = dbName.substr(0, dbName.size()-3);
900 std::multimap<int, Link> dummyLinks;
901 std::map<int, double> stamps;
902 if(!outputKittiError)
904 for(std::map<int, Transform>::iterator iter=poses.begin(); iter!=poses.end(); ++iter)
906 UASSERT(odomStamps.find(iter->first) != odomStamps.end());
907 stamps.insert(*odomStamps.find(iter->first));
912 printf(
"Could not export the poses to \"%s\"!?!\n", path.c_str());
918 if(!outputKittiError)
920 for(std::map<int, Transform>::iterator iter=odomPoses.begin(); iter!=odomPoses.end(); ++iter)
922 UASSERT(odomStamps.find(iter->first) != odomStamps.end());
923 stamps.insert(*odomStamps.find(iter->first));
928 printf(
"Could not export the odometry to \"%s\"!?!\n", path.c_str());
932 if(groundTruth.size())
936 if(!outputKittiError)
938 for(std::map<int, Transform>::iterator iter=groundTruth.begin(); iter!=groundTruth.end(); ++iter)
940 UASSERT(odomStamps.find(iter->first) != odomStamps.end());
941 stamps.insert(*odomStamps.find(iter->first));
946 printf(
"Could not export the ground truth to \"%s\"!?!\n", path.c_str());
953 bool fillHeader =
false;
954 std::ifstream
f(
"report.csv");
960 std::ofstream myfile;
961 myfile.open(
"report.csv", std::fstream::in | std::fstream::out |
std::fstream::app);
964 myfile <<
"Rosbag name"<<
";"<<
"error linear (m)"<<
";"<<
"error linear max (m)"<<
";"<<
"error linear odom (m)"<<
";" 965 <<
"error angular"<<
";" 966 <<
"Slam avg (hz)"<<
";"<<
"Slam max (hz)"<<
";" 967 <<
"Odom avg (hz)"<<
";"<<
"Odom max (hz)"<<std::endl;
970 myfile <<fileName.c_str()<<
";" 975 <<(1/(
uMean(slamTime)/1000.0))<<
";" 976 <<(1/(
uMax(slamTime)/1000.0))<<
";" 977 <<(1/(
uMean(odomTime)/1000.0))<<
";" 978 <<(1/(
uMax(odomTime)/1000.0))<<
";"<<std::endl;
982 if(outputLoopAccuracy && !groundTruth.empty() && !linksOut.empty())
984 float sumDist = 0.0f;
985 float sumAngle = 0.0f;
987 for(std::multimap<int, Link>::iterator iter=loopClosureLinks.begin(); iter!=loopClosureLinks.end(); ++iter)
989 if( groundTruth.find(iter->second.from())!=groundTruth.end() &&
990 groundTruth.find(iter->second.to())!=groundTruth.end())
992 Transform gtLink = groundTruth.at(iter->second.from()).
inverse()*groundTruth.at(iter->second.to());
993 const Transform & t = iter->second.transform();
1000 sumAngle += diff.getAngle();
1006 loop_t_err = sumDist/float(count);
1007 loop_r_err = sumAngle/float(count);
1008 loop_r_err *= 180/CV_PI;
1013 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",
1021 !outputKittiError?
"":
uFormat(
", KITTI: t_err=%.2f%% r_err=%.2f deg/100m", kitti_t_err, kitti_r_err*100).c_str(),
1022 !outputRelativeError?
"":
uFormat(
", Relative: t_err=%.3fm r_err=%.2f deg", relative_t_err, relative_r_err).c_str(),
1023 !localizationMultiStats.empty()?
"loc":
"slam",
1024 (int)
uMean(slamTime), (int)
uMax(slamTime),
1025 (int)loopClosureLinks.size(),
1026 !outputLoopAccuracy?
"":
uFormat(
" (t_err=%.3fm r_err=%.2f deg)", loop_t_err, loop_r_err).c_str(),
1027 (int)
uMean(odomTime), (int)
uMax(odomTime),
1028 (int)
uMean(cameraTime),
1029 maxOdomRAM!=-1.0f?
uFormat(
"RAM odom=%dMB ", (
int)maxOdomRAM).c_str():
"",
1034 std::vector<float> stats;
1035 stats.push_back(ids.size());
1036 stats.push_back(bestRMSE);
1037 stats.push_back(maxRMSE);
1038 stats.push_back(bestRMSEAng);
1039 stats.push_back(
uMean(odomTime));
1040 stats.push_back(
uMean(slamTime));
1041 stats.push_back(
uMax(slamTime));
1042 stats.push_back(maxOdomRAM);
1043 stats.push_back(maxMapRAM);
1044 outputLatexStatisticsMap.insert(std::make_pair(filePath, stats));
1046 if(maxOdomRAM != -1.0
f)
1055 else if(
uSplit(fileName,
'.').size() == 1)
1060 currentPathIsDatabase =
false;
1063 if(!localizationMultiStats.empty() && showLoc!=-1)
1065 printf(
"---Localization results---\n");
1066 std::string prefix =
"header={";
1067 printf(
"%s", prefix.c_str());
1068 for(std::vector<std::pair<std::string, std::vector<LocStats> > >::iterator iter=localizationMultiStats.begin()->second.begin();
1069 iter!=localizationMultiStats.begin()->second.end();)
1071 if(iter!=localizationMultiStats.begin()->second.begin())
1073 printf(
"%s", std::string(prefix.size(),
' ').c_str());
1075 printf(
"%s", iter->first.c_str());
1077 if(iter!=localizationMultiStats.begin()->second.end())
1085 for(std::map<std::string, std::vector<std::pair<std::string, std::vector<LocStats> > > >::iterator iter=localizationMultiStats.begin();
1086 iter!=localizationMultiStats.end();
1089 printf(
"%s\n", iter->first.c_str());
1090 for(
int k=0; k<6; ++k)
1092 if(showLoc & (0x1 << k))
1094 std::string prefix =
uFormat(
" %s=[",
1101 printf(
"%s", prefix.c_str());
1102 for(std::vector<std::pair<std::string, std::vector<LocStats> > >::iterator jter=iter->second.begin(); jter!=iter->second.end();)
1104 if(jter!=iter->second.begin())
1106 printf(
"%s", std::string(prefix.size(),
' ').c_str());
1108 for(
size_t j=0; j<jter->second.size(); ++j)
1113 k==0?jter->second[j].min:
1114 k==1?jter->second[j].max:
1115 k==2?jter->second[j].mean:
1116 jter->second[j].stddev);
1120 printf(
"%d",jter->second[j].total);
1124 printf(
"%.2f", (jter->second[j].nonNull*100));
1126 if(j+1 < jter->second.size())
1132 if(jter!=iter->second.end())
1140 iter->second.clear();
1144 for(std::list<std::string>::iterator iter=subDirs.begin(); iter!=subDirs.end(); ++iter)
1146 paths.push_front(*iter);
1149 if(outputLatexStatisticsMap.size() && paths.empty())
1151 outputLatexStatistics.push_back(outputLatexStatisticsMap);
1152 outputLatexStatisticsMap.clear();
1156 if(outputLatex && outputLatexStatistics.size())
1158 printf(
"\nLaTeX output:\n----------------\n");
1159 printf(
"\\begin{table*}[!t]\n");
1160 printf(
"\\caption{$t_{end}$ is the absolute translational RMSE value at the end " 1161 "of the experiment as $ATE_{max}$ is the maximum during the experiment. " 1162 "$r_{end}$ is rotational RMSE value at the end of the experiment. " 1163 "$o_{avg}$ and $m_{avg}$ are the average computational time " 1164 "for odometry (front-end) and map update (back-end). " 1165 "$m_{avg}$ is the maximum computational time for map update. " 1166 "$O_{end}$ and $M_{end}$ are the RAM usage at the end of the experiment " 1167 "for odometry and map management respectively.}\n");
1168 printf(
"\\label{}\n");
1169 printf(
"\\centering\n");
1172 printf(
"\\begin{tabular}{l|c|c|c|c|c|c|c|c|c}\n");
1173 printf(
"\\cline{2-10}\n");
1174 printf(
" & Size & $t_{end}$ & $t_{max}$ & $r_{end}$ & $o_{avg}$ & $m_{avg}$ & $m_{max}$ & $O_{end}$ & $M_{end}$ \\\\\n");
1175 printf(
" & (nodes) & (m) & (m) & (deg) & (ms) & (ms) & (ms) & (MB) & (MB) \\\\\n");
1179 printf(
"\\begin{tabular}{l|c|c|c|c|c|c|c|c}\n");
1180 printf(
"\\cline{2-9}\n");
1181 printf(
" & Size & $t_{end}$ & $t_{max}$ & $r_{end}$ & $o_{avg}$ & $m_{avg}$ & $m_{max}$ & $M_{end}$ \\\\\n");
1182 printf(
" & (nodes) & (m) & (m) & (deg) & (ms) & (ms) & (ms) & (MB) \\\\\n");
1185 printf(
"\\hline\n");
1187 for(
unsigned int j=0; j<outputLatexStatistics.size(); ++j)
1189 if(outputLatexStatistics[j].size())
1191 std::vector<int> lowestIndex;
1192 if(outputLatexStatistics[j].size() > 1)
1194 std::vector<float> lowestValue(outputLatexStatistics[j].begin()->second.size(),-1);
1195 lowestIndex = std::vector<int>(lowestValue.size(),0);
1197 for(std::map<std::string, std::vector<float> >::iterator iter=outputLatexStatistics[j].begin(); iter!=outputLatexStatistics[j].end(); ++iter)
1199 UASSERT(lowestValue.size() == iter->second.size());
1200 for(
unsigned int i=0; i<iter->second.size(); ++i)
1202 if(lowestValue[i] == -1 || (iter->second[i]>0.0f && lowestValue[i]>iter->second[i]))
1204 lowestValue[i] = iter->second[i];
1205 lowestIndex[i] = index;
1213 for(std::map<std::string, std::vector<float> >::iterator iter=outputLatexStatistics[j].begin(); iter!=outputLatexStatistics[j].end(); ++iter)
1215 UASSERT(iter->second.size() == 9);
1216 printf(
"%s & ",
uReplaceChar(iter->first.c_str(),
'_',
'-').c_str());
1217 printf(
"%d & ", (
int)iter->second[0]);
1218 printf(
"%s%.3f%s & ", lowestIndex.size()&&lowestIndex[1]==index?
"\\textbf{":
"", iter->second[1], lowestIndex.size()&&lowestIndex[1]==index?
"}":
"");
1219 printf(
"%s%.3f%s & ", lowestIndex.size()&&lowestIndex[2]==index?
"\\textbf{":
"", iter->second[2], lowestIndex.size()&&lowestIndex[2]==index?
"}":
"");
1220 printf(
"%s%.2f%s & ", lowestIndex.size()&&lowestIndex[3]==index?
"\\textbf{":
"", iter->second[3], lowestIndex.size()&&lowestIndex[3]==index?
"}":
"");
1221 printf(
"%s%d%s & ", lowestIndex.size()&&lowestIndex[4]==index?
"\\textbf{":
"", (int)iter->second[4], lowestIndex.size()&&lowestIndex[4]==index?
"}":
"");
1222 printf(
"%s%d%s & ", lowestIndex.size()&&lowestIndex[5]==index?
"\\textbf{":
"", (int)iter->second[5], lowestIndex.size()&&lowestIndex[5]==index?
"}":
"");
1223 printf(
"%s%d%s & ", lowestIndex.size()&&lowestIndex[6]==index?
"\\textbf{":
"", (int)iter->second[6], lowestIndex.size()&&lowestIndex[6]==index?
"}":
"");
1226 printf(
"%s%d%s & ", lowestIndex.size()&&lowestIndex[7]==index?
"\\textbf{":
"", (int)iter->second[7], lowestIndex.size()&&lowestIndex[7]==index?
"}":
"");
1228 printf(
"%s%d%s ", lowestIndex.size()&&lowestIndex[8]==index?
"\\textbf{":
"", (int)iter->second[8], lowestIndex.size()&&lowestIndex[8]==index?
"}":
"");
1232 printf(
"\\hline\n");
1237 printf(
"\\end{tabular}\n");
1238 printf(
"\\end{table*}\n----------------\n");
1243 for(std::map<std::string, UPlot*>::iterator iter=figures.begin(); iter!=figures.end(); ++iter)
1247 iter->second->frameData();
1251 QString
data = iter->second->getAllCurveDataAsText();
1254 QString filePath = QString(exportPrefix.c_str()) + (exportPrefix.empty()?
"":
"-") + iter->second->windowTitle().replace(
'/',
"-") +
".txt";
1255 QFile file(filePath);
1256 if(file.open(QIODevice::Text | QIODevice::WriteOnly))
1258 file.write(data.toUtf8());
1260 printf(
"Exported \"%s\".\n", filePath.toStdString().c_str());
1264 printf(
"ERROR: could not open file \"%s\" for writing!\n", filePath.toStdString().c_str());
1270 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)
std::multimap< int, Link >::iterator RTABMAP_EXP findLink(std::multimap< int, Link > &links, int from, int to, bool checkBothWays=true, Link::Type type=Link::kUndef)
void uMinMax(const T *v, unsigned int size, T &min, T &max, unsigned int &indexMin, unsigned int &indexMax)
GLM_FUNC_DECL vecType< T, P > sqrt(vecType< T, P > const &x)
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)
const std::list< std::string > & getFileNames() const
static LocStats from(const std::vector< float > &array)
std::map< int, Transform > loadOptimizedPoses(Transform *lastlocalizationPose=0) const
bool openConnection(const std::string &url, bool overwritten=false)
void getAllLinks(std::multimap< int, Link > &links, bool ignoreNullLinks=true, bool withLandmarks=false) const
#define UASSERT(condition)
Wrappers of STL for convenient functions.
std::list< std::string > uSplit(const std::string &str, char separator=' ')
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)
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
UPlotCurve * addCurve(const QString &curveName, const QColor &color=QColor())
void closeConnection(bool save=true, const std::string &outputUrl="")
void getAllNodeIds(std::set< int > &ids, bool ignoreChildren=false, bool ignoreBadSignatures=false, bool ignoreIntermediateNodes=false) const
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)
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)
static ULogger::Level level()
bool uIsNumber(const std::string &str)
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, bool adjustPosesWithConstraints=true) const
bool uContains(const std::list< V > &list, const V &value)
std::map< int, std::pair< std::map< std::string, float >, double > > getAllStatistics() const
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())
T uMax(const T *v, unsigned int size, unsigned int &index)
void setXLabel(const QString &text)
std::vector< V > uValues(const std::multimap< K, V > &mm)
std::string getNextFileName()
void RTABMAP_EXP calcRelativeErrors(const std::vector< Transform > &poses_gt, const std::vector< Transform > &poses_result, float &t_err, float &r_err)
ULogger class and convenient macros.
ParametersMap getLastParameters() const
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)