31 #ifdef RTABMAP_OCTOMAP
49 #include <pcl/io/pcd_io.h>
57 " rtabmap-reprocess [options] \"input.db\" \"output.db\"\n"
58 " rtabmap-reprocess [options] \"input1.db;input2.db;input3.db\" \"output.db\"\n"
60 " For the second example, only parameters from the first database are used.\n"
61 " If Mem/IncrementalMemory is false, RTAB-Map is initialized with the first input database,\n"
62 " then localization-only is done with next databases against the first one.\n"
63 " To see warnings when loop closures are rejected, add \"--uwarn\" argument.\n"
64 " To upgrade version of an old database to newest version:\n"
65 " rtabmap-reprocess --Db/TargetVersion \"\" \"input.db\" \"output.db\"\n"
68 " -r Use database stamps as input rate.\n"
69 " -skip # Skip # frames after each processed frame (default 0=don't skip any frames).\n"
70 " -c \"path.ini\" Configuration file, overwriting parameters read \n"
71 " from the database. If custom parameters are also set as \n"
72 " arguments, they overwrite those in config file and the database.\n"
73 " -default Input database's parameters are ignored, using default ones instead.\n"
74 " -odom Recompute odometry. See \"Odom/\" parameters with --params. If -skip option\n"
75 " is used, it will be applied to odometry frames, not rtabmap frames. Multi-session\n"
76 " cannot be detected in this mode (assuming the database contains continuous frames\n"
77 " of a single session).\n"
78 " -start # Start from this node ID.\n"
79 " -stop # Last node to process.\n"
80 " -start_s # Start from this map session ID.\n"
81 " -stop_s # Last map session to process.\n"
82 " -a Append mode: if Mem/IncrementalMemory is true, RTAB-Map is initialized with the first input database,\n"
83 " then next databases are reprocessed on top of the first one.\n"
84 " -cam # Camera index to stream. Ignored if a database doesn't contain multi-camera data.\n"
85 " -nolandmark Don't republish landmarks contained in input database.\n"
86 " -nopriors Don't republish priors contained in input database.\n"
87 " -pub_loops Republish loop closures contained in input database.\n"
88 " -loc_null On localization mode, reset localization pose to null and map correction to identity between sessions.\n"
89 " -gt When reprocessing a single database, load its original optimized graph, then \n"
90 " set it as ground truth for output database. If there was a ground truth in the input database, it will be ignored.\n"
91 " -g2 Assemble 2D occupancy grid map and save it to \"[output]_map.pgm\". Use with -db to save in database.\n"
92 " -g3 Assemble 3D cloud map and save it to \"[output]_map.pcd\".\n"
93 " -o2 Assemble OctoMap 2D projection and save it to \"[output]_octomap.pgm\". Use with -db to save in database.\n"
94 " -o3 Assemble OctoMap 3D cloud and save it to \"[output]_octomap.pcd\".\n"
95 " -db Save assembled 2D occupancy grid in database instead of a file.\n"
96 " -p Save odometry and localization poses (*.g2o).\n"
97 " -scan_from_depth Generate scans from depth images (overwrite previous\n"
98 " scans if they exist).\n"
99 " -scan_downsample # Downsample input scans.\n"
100 " -scan_range_min #.# Filter input scans with minimum range (m).\n"
101 " -scan_range_max #.# Filter input scans with maximum range (m).\n"
102 " -scan_voxel_size #.# Voxel filter input scans (m).\n"
103 " -scan_normal_k # Compute input scan normals (k-neighbors approach).\n"
104 " -scan_normal_radius #.# Compute input scan normals (radius(m)-neighbors approach).\n\n"
114 printf(
"\nSignal %d caught...\n", sig);
144 printf(
"Average localization time = %f ms (stddev=%f ms)\n",
m, stddev);
166 stddevA =
sqrt(varA);
168 printf(
"Average localization variations = %f m, %f deg (stddev=%f m, %f deg) (max=%f m, %f deg)\n",
m, mA, stddev, stddevA,
max, maxA);
179 printf(
"Average distance from previous localization = %f m (stddev=%f m)\n",
m, stddev);
190 printf(
"Average odometry distances = %f m (stddev=%f m)\n",
m, stddev);
195 std::string outputPath = outputDatabasePath.substr(0, outputDatabasePath.size()-3);
200 printf(
"Exported %s and %s\n", oName.c_str(), lName.c_str());
235 bool save2DMap =
false;
236 bool assemble2dMap =
false;
237 bool assemble3dMap =
false;
238 bool assemble2dOctoMap =
false;
239 bool assemble3dOctoMap =
false;
240 bool useDatabaseRate =
false;
241 bool useDefaultParameters =
false;
242 bool recomputeOdometry =
false;
247 bool appendMode =
false;
248 int cameraIndex = -1;
249 int framesToSkip = 0;
250 bool ignoreLandmarks =
false;
251 bool ignorePriors =
false;
252 bool republishLoopClosures =
false;
253 bool locNull =
false;
254 bool originalGraphAsGT =
false;
255 bool scanFromDepth =
false;
256 int scanDecimation = 1;
257 float scanRangeMin = 0.0f;
258 float scanRangeMax = 0.0f;
259 float scanVoxelSize = 0;
261 float scanNormalRadius = 0.0f;
263 for(
int i=1;
i<argc-2; ++
i)
265 if(strcmp(
argv[
i],
"-r") == 0 || strcmp(
argv[
i],
"--r") == 0)
267 useDatabaseRate =
true;
268 printf(
"Using database stamps as input rate.\n");
270 else if (strcmp(
argv[
i],
"-c") == 0 || strcmp(
argv[
i],
"--c") == 0)
276 printf(
"Using %d parameters from config file \"%s\"\n", (
int)configParameters.size(),
argv[
i]);
278 else if(
i < argc - 2)
280 printf(
"Config file \"%s\" is not valid or doesn't exist!\n",
argv[
i]);
285 printf(
"Config file is not set!\n");
289 else if(strcmp(
argv[
i],
"-default") == 0 || strcmp(
argv[
i],
"--default") == 0)
291 useDefaultParameters =
true;
292 printf(
"Using default parameters.\n");
294 else if(strcmp(
argv[
i],
"-odom") == 0 || strcmp(
argv[
i],
"--odom") == 0)
296 recomputeOdometry =
true;
298 else if (strcmp(
argv[
i],
"-start") == 0 || strcmp(
argv[
i],
"--start") == 0)
303 startId = atoi(
argv[
i]);
304 printf(
"Start at node ID = %d.\n", startId);
308 printf(
"-start option requires a value\n");
312 else if (strcmp(
argv[
i],
"-stop") == 0 || strcmp(
argv[
i],
"--stop") == 0)
317 stopId = atoi(
argv[
i]);
318 printf(
"Stop at node ID = %d.\n", stopId);
322 printf(
"-stop option requires a value\n");
326 else if (strcmp(
argv[
i],
"-start_s") == 0 || strcmp(
argv[
i],
"--start_s") == 0)
331 startMapId = atoi(
argv[
i]);
332 printf(
"Start at map session ID = %d.\n", startMapId);
336 printf(
"-start_s option requires a value\n");
340 else if (strcmp(
argv[
i],
"-stop_s") == 0 || strcmp(
argv[
i],
"--stop_s") == 0)
345 stopMapId = atoi(
argv[
i]);
346 printf(
"Stop at map session ID = %d.\n", stopMapId);
350 printf(
"-stop option requires a value\n");
354 else if (strcmp(
argv[
i],
"-a") == 0 || strcmp(
argv[
i],
"--a") == 0)
357 printf(
"Append mode enabled (initialize with first database then reprocess next ones)\n");
359 else if (strcmp(
argv[
i],
"-cam") == 0 || strcmp(
argv[
i],
"--cam") == 0)
364 cameraIndex = atoi(
argv[
i]);
365 printf(
"Camera index = %d.\n", cameraIndex);
369 printf(
"-cam option requires a value\n");
373 else if (strcmp(
argv[
i],
"-skip") == 0 || strcmp(
argv[
i],
"--skip") == 0)
378 framesToSkip = atoi(
argv[
i]);
379 printf(
"Will skip %d frames.\n", framesToSkip);
383 printf(
"-skip option requires a value\n");
387 else if(strcmp(
argv[
i],
"-nolandmark") == 0 || strcmp(
argv[
i],
"--nolandmark") == 0)
389 ignoreLandmarks =
true;
390 printf(
"Ignoring landmarks from input database (-nolandmark option).\n");
392 else if(strcmp(
argv[
i],
"-nopriors") == 0 || strcmp(
argv[
i],
"--nopriors") == 0)
395 printf(
"Ignoring priors from input database (-nopriors option).\n");
397 else if(strcmp(
argv[
i],
"-pub_loops") == 0 || strcmp(
argv[
i],
"--pub_loops") == 0)
399 republishLoopClosures =
true;
400 printf(
"Republish loop closures from input database (-pub_loops option).\n");
402 else if(strcmp(
argv[
i],
"-loc_null") == 0 || strcmp(
argv[
i],
"--loc_null") == 0)
405 printf(
"In localization mode, when restarting a new session, the current localization pose is set to null (-loc_null option).\n");
407 else if(strcmp(
argv[
i],
"-gt") == 0 || strcmp(
argv[
i],
"--gt") == 0)
409 originalGraphAsGT =
true;
410 printf(
"Original graph is used as ground truth for output database (-gt option).\n");
412 else if(strcmp(
argv[
i],
"-p") == 0 || strcmp(
argv[
i],
"--p") == 0)
415 printf(
"Odometry trajectory and localization poses will be exported in g2o format (-p option).\n");
417 else if(strcmp(
argv[
i],
"-db") == 0 || strcmp(
argv[
i],
"--db") == 0)
420 printf(
"2D occupancy grid will be saved in database (-db option).\n");
422 else if(strcmp(
argv[
i],
"-g2") == 0 || strcmp(
argv[
i],
"--g2") == 0)
424 assemble2dMap =
true;
425 printf(
"2D occupancy grid will be assembled (-g2 option).\n");
427 else if(strcmp(
argv[
i],
"-g3") == 0 || strcmp(
argv[
i],
"--g3") == 0)
429 assemble3dMap =
true;
430 printf(
"3D cloud map will be assembled (-g3 option).\n");
432 else if(strcmp(
argv[
i],
"-o2") == 0 || strcmp(
argv[
i],
"--o2") == 0)
434 #ifdef RTABMAP_OCTOMAP
435 assemble2dOctoMap =
true;
436 printf(
"OctoMap will be assembled (-o2 option).\n");
438 printf(
"RTAB-Map is not built with OctoMap support, cannot set -o2 option!\n");
441 else if(strcmp(
argv[
i],
"-o3") == 0 || strcmp(
argv[
i],
"--o3") == 0)
443 #ifdef RTABMAP_OCTOMAP
444 assemble3dOctoMap =
true;
445 printf(
"OctoMap will be assembled (-o3 option).\n");
447 printf(
"RTAB-Map is not built with OctoMap support, cannot set -o3 option!\n");
450 else if (strcmp(
argv[
i],
"-scan_from_depth") == 0 || strcmp(
argv[
i],
"--scan_from_depth") == 0)
452 scanFromDepth =
true;
454 else if (strcmp(
argv[
i],
"-scan_downsample") == 0 || strcmp(
argv[
i],
"--scan_downsample") == 0 ||
455 strcmp(
argv[
i],
"-scan_decimation") == 0 || strcmp(
argv[
i],
"--scan_decimation") == 0)
460 scanDecimation = atoi(
argv[
i]);
461 printf(
"Scan from depth decimation = %d.\n", scanDecimation);
465 printf(
"-scan_downsample option requires 1 value\n");
469 else if (strcmp(
argv[
i],
"-scan_range_min") == 0 || strcmp(
argv[
i],
"--scan_range_min") == 0)
474 scanRangeMin = atof(
argv[
i]);
475 printf(
"Scan range min = %f m.\n", scanRangeMin);
479 printf(
"-scan_range_min option requires 1 value\n");
483 else if (strcmp(
argv[
i],
"-scan_range_max") == 0 || strcmp(
argv[
i],
"--scan_range_max") == 0)
488 scanRangeMax = atof(
argv[
i]);
489 printf(
"Scan range max = %f m.\n", scanRangeMax);
493 printf(
"-scan_range_max option requires 1 value\n");
497 else if (strcmp(
argv[
i],
"-scan_voxel_size") == 0 || strcmp(
argv[
i],
"--scan_voxel_size") == 0)
502 scanVoxelSize = atof(
argv[
i]);
503 printf(
"Scan voxel size = %f m.\n", scanVoxelSize);
507 printf(
"-scan_voxel_size option requires 1 value\n");
511 else if (strcmp(
argv[
i],
"-scan_normal_k") == 0 || strcmp(
argv[
i],
"--scan_normal_k") == 0)
516 scanNormalK = atoi(
argv[
i]);
517 printf(
"Scan normal k = %d.\n", scanNormalK);
521 printf(
"-scan_normal_k option requires 1 value\n");
525 else if (strcmp(
argv[
i],
"-scan_normal_radius") == 0 || strcmp(
argv[
i],
"--scan_normal_radius") == 0)
530 scanNormalRadius = atof(
argv[
i]);
531 printf(
"Scan normal radius = %f m.\n", scanNormalRadius);
535 printf(
"-scan_normal_radius option requires 1 value\n");
544 std::list<std::string> databases =
uSplit(inputDatabasePath,
';');
545 if (databases.empty())
547 printf(
"No input database \"%s\" detected!\n", inputDatabasePath.c_str());
550 for (std::list<std::string>::iterator
iter = databases.begin();
iter != databases.end(); ++
iter)
554 printf(
"Input database \"%s\" doesn't exist!\n",
iter->c_str());
560 printf(
"File \"%s\" is not a database format (*.db)!\n",
iter->c_str());
567 printf(
"File \"%s\" is not a database format (*.db)!\n", outputDatabasePath.c_str());
580 printf(
"Failed opening input database!\n");
586 std::string targetVersion;
587 if(!useDefaultParameters)
591 parameters.insert(
ParametersPair(Parameters::kDbTargetVersion(), targetVersion));
592 if(parameters.empty())
594 printf(
"WARNING: Failed getting parameters from database, reprocessing will be done with default parameters! Database version may be too old (%s).\n", dbDriver->
getDatabaseVersion().c_str());
598 if(customParameters.size())
600 printf(
"Custom parameters:\n");
601 for(ParametersMap::iterator
iter=customParameters.begin();
iter!=customParameters.end(); ++
iter)
603 printf(
" %s %s\n",
uPad(
iter->first+
" =", 25).c_str(),
iter->second.c_str());
607 bool useOdomFeatures = Parameters::defaultMemUseOdomFeatures();
608 if((configParameters.find(Parameters::kKpDetectorStrategy())!=configParameters.end() ||
609 configParameters.find(Parameters::kVisFeatureType())!=configParameters.end() ||
610 customParameters.find(Parameters::kKpDetectorStrategy())!=customParameters.end() ||
611 customParameters.find(Parameters::kVisFeatureType())!=customParameters.end()) &&
612 configParameters.find(Parameters::kMemUseOdomFeatures())==configParameters.end() &&
613 customParameters.find(Parameters::kMemUseOdomFeatures())==customParameters.end())
615 Parameters::parse(parameters, Parameters::kMemUseOdomFeatures(), useOdomFeatures);
618 printf(
"[Warning] %s and/or %s are overwritten but parameter %s is true in the opened database. "
619 "Setting it to false for convenience to use the new selected feature detector. Set %s "
620 "explicitly to suppress this warning.\n",
621 Parameters::kKpDetectorStrategy().
c_str(),
622 Parameters::kVisFeatureType().
c_str(),
623 Parameters::kMemUseOdomFeatures().
c_str(),
624 Parameters::kMemUseOdomFeatures().
c_str());
626 useOdomFeatures =
false;
630 if(useOdomFeatures && databases.size() > 1 &&
631 configParameters.find(Parameters::kMemUseOdomFeatures())==configParameters.end() &&
632 customParameters.find(Parameters::kMemUseOdomFeatures())==customParameters.end())
634 printf(
"[Warning] Parameter %s is set to false for convenience as "
635 "there are more than one input database (which could "
636 "contain different features). Set %s "
637 "explicitly to suppress this warning.\n",
638 Parameters::kMemUseOdomFeatures().
c_str(),
639 Parameters::kMemUseOdomFeatures().
c_str());
640 useOdomFeatures =
false;
643 if(republishLoopClosures)
645 if(databases.size() > 1)
647 printf(
"[Warning] \"pub_loops\" option cannot be used with multiple databases input. "
648 "Disabling \"pub_loops\" to avoid mismatched loop closue ids.\n");
649 republishLoopClosures =
false;
653 bool generateIds = Parameters::defaultMemGenerateIds();
659 if(configParameters.find(Parameters::kMemGenerateIds())!=configParameters.end() ||
660 customParameters.find(Parameters::kMemGenerateIds())!=customParameters.end())
662 printf(
"[Warning] \"pub_loops\" option is used but parameter %s is set to true in custom arguments. "
663 "Disabling \"pub_loops\" to avoid mismatched loop closure ids.\n",
664 Parameters::kMemGenerateIds().
c_str());
665 republishLoopClosures =
false;
669 printf(
"[Warning] \"pub_loops\" option is used but parameter %s is true in the opened database. "
670 "Setting parameter %s to false for convenience so that republished loop closure ids match.\n",
671 Parameters::kMemGenerateIds().
c_str(),
672 Parameters::kMemGenerateIds().
c_str());
678 uInsert(parameters, configParameters);
679 uInsert(parameters, customParameters);
681 bool incrementalMemory = Parameters::defaultMemIncrementalMemory();
682 Parameters::parse(parameters, Parameters::kMemIncrementalMemory(), incrementalMemory);
684 bool intermediateNodes = Parameters::defaultRtabmapCreateIntermediateNodes();
685 Parameters::parse(parameters, Parameters::kRtabmapCreateIntermediateNodes(), intermediateNodes);
689 dbDriver->
getAllNodeIds(ids,
false,
false, !intermediateNodes);
692 printf(
"Input database doesn't have any nodes saved in it.\n");
697 if(!((!incrementalMemory || appendMode) && databases.size() > 1))
699 totalIds = ids.size();
702 std::map<int, Transform> gt;
703 if(databases.size() == 1 && originalGraphAsGT)
711 for (std::list<std::string>::iterator
iter = ++databases.begin();
iter != databases.end(); ++
iter)
715 printf(
"Failed opening input database!\n");
720 dbDriver->
getAllNodeIds(ids,
false,
false, !intermediateNodes);
721 totalIds += ids.size();
729 totalIds/=framesToSkip+1;
733 printf(
"Set working directory to \"%s\".\n", workingDirectory.c_str());
734 if(!targetVersion.empty())
736 printf(
"Target database version: \"%s\" (set explicitly --%s \"\" to output with latest version.\n", targetVersion.c_str(), Parameters::kDbTargetVersion().c_str());
741 if((!incrementalMemory || appendMode ) && databases.size() > 1)
743 UFile::copy(databases.front(), outputDatabasePath);
744 if(!incrementalMemory)
746 printf(
"Parameter \"%s\" is set to false, initializing RTAB-Map with \"%s\" for localization...\n", Parameters::kMemIncrementalMemory().
c_str(), databases.front().c_str());
748 databases.pop_front();
749 inputDatabasePath =
uJoin(databases,
";");
753 rtabmap.init(parameters, outputDatabasePath);
755 if(!incrementalMemory && locNull)
760 bool rgbdEnabled = Parameters::defaultRGBDEnabled();
762 bool odometryIgnored = !rgbdEnabled;
766 useDatabaseRate?-1:0,
784 #ifdef RTABMAP_OCTOMAP
785 OctoMap octomap(&mapCache, parameters);
787 CloudMap cloudMap(&mapCache, parameters);
789 float linearUpdate = Parameters::defaultRGBDLinearUpdate();
790 float angularUpdate = Parameters::defaultRGBDAngularUpdate();
795 float rtabmapUpdateRate = Parameters::defaultRtabmapDetectionRate();
796 double lastUpdateStamp = 0;
797 if(recomputeOdometry)
801 printf(
"odom option is set but %s parameter is false, odometry won't be recomputed...\n", Parameters::kRGBDEnabled().
c_str());
802 recomputeOdometry =
false;
806 printf(
"Odometry will be recomputed (odom option is set)\n");
807 Parameters::parse(parameters, Parameters::kRtabmapDetectionRate(), rtabmapUpdateRate);
808 if(rtabmapUpdateRate!=0)
810 rtabmapUpdateRate = 1.0f/rtabmapUpdateRate;
816 printf(
"Reprocessing data of \"%s\"...\n", inputDatabasePath.c_str());
817 std::map<std::string, float> globalMapStats;
822 camThread.
setScanParameters(scanFromDepth, scanDecimation, scanRangeMin, scanRangeMax, scanVoxelSize, scanNormalK, scanNormalRadius);
829 bool inMotion =
true;
832 if(recomputeOdometry)
836 printf(
"Processed %d/%d frames (visual=%d/%d lidar=%f lost=%s)... odometry = %dms\n",
842 odomInfo.
lost?
"true":
"false",
844 if(lastUpdateStamp > 0.0 &&
data.stamp() < lastUpdateStamp + rtabmapUpdateRate)
848 int skippedFrames = framesToSkip;
849 while(skippedFrames-- > 0)
865 info.odomPose = pose;
867 lastUpdateStamp =
data.stamp();
872 if(!odometryIgnored &&
info.odomPose.isNull())
874 printf(
"Skipping node %d as it doesn't have odometry pose set.\n",
data.id());
878 if(!odometryIgnored && !
info.odomCovariance.empty() &&
info.odomCovariance.at<
double>(0,0)>=9999)
880 printf(
"High variance detected, triggering a new map...\n");
881 if(!incrementalMemory && processed>0)
884 lastLocalizationOdomPose =
info.odomPose;
887 if(!incrementalMemory && locNull)
894 if(originalGraphAsGT)
902 printf(
"Failed processing node %d.\n",
data.id());
903 globalMapStats.clear();
907 if(republishLoopClosures && dbReader->
driver())
909 std::multimap<int, Link> links;
911 for(std::multimap<int, Link>::iterator
iter=links.begin();
iter!=links.end(); ++
iter)
919 if(!
iter->second.transform().isNull() &&
920 rtabmap.getMemory()->getWorkingMem().find(
iter->second.to()) !=
rtabmap.getMemory()->getWorkingMem().end() &&
923 printf(
"Added link %d->%d from input database.\n",
iter->second.from(),
iter->second.to());
929 if(assemble2dMap || assemble3dMap || assemble2dOctoMap || assemble3dOctoMap)
931 globalMapStats.clear();
932 double timeRtabmap =
t.ticks();
933 double timeUpdateInit = 0.0;
934 double timeUpdateGrid = 0.0;
935 double timeUpdateCloudMap = 0.0;
936 #ifdef RTABMAP_OCTOMAP
937 double timeUpdateOctoMap = 0.0;
940 if(
stats.poses().size() &&
stats.getLastSignatureData().id())
942 int id =
stats.poses().rbegin()->first;
943 if(
id ==
stats.getLastSignatureData().id() &&
944 stats.getLastSignatureData().sensorData().gridCellSize() > 0.0f)
946 bool updateGridMap =
false;
947 bool updateOctoMap =
false;
948 bool updateCloudMap =
false;
951 updateGridMap =
true;
955 updateCloudMap =
true;
957 #ifdef RTABMAP_OCTOMAP
958 if((assemble2dOctoMap || assemble3dOctoMap) && octomap.
addedNodes().find(
id) == octomap.
addedNodes().end())
960 updateOctoMap =
true;
963 if(updateGridMap || updateOctoMap || updateCloudMap)
965 cv::Mat ground, obstacles,
empty;
966 stats.getLastSignatureData().sensorData().uncompressDataConst(0, 0, 0, 0, &ground, &obstacles, &
empty);
967 float cellSize =
stats.getLastSignatureData().sensorData().gridCellSize();
968 const cv::Point3f & viewpoint =
stats.getLastSignatureData().sensorData().gridViewPoint();
970 timeUpdateInit =
t.ticks();
972 mapCache.
add(
id, ground, obstacles,
empty, cellSize, viewpoint);
977 timeUpdateGrid =
t.ticks() + timeUpdateInit;
982 timeUpdateCloudMap =
t.ticks() + timeUpdateInit;
984 #ifdef RTABMAP_OCTOMAP
988 timeUpdateOctoMap =
t.ticks() + timeUpdateInit;
995 globalMapStats.insert(std::make_pair(std::string(
"GlobalGrid/GridUpdate/ms"), timeUpdateGrid*1000.0
f));
996 globalMapStats.insert(std::make_pair(std::string(
"GlobalGrid/CloudUpdate/ms"), timeUpdateCloudMap*1000.0
f));
997 #ifdef RTABMAP_OCTOMAP
999 double timePub2dOctoMap = 0.0;
1000 double timePub3dOctoMap = 0.0;
1001 if(assemble2dOctoMap)
1003 float xMin, yMin,
size;
1005 timePub2dOctoMap =
t.ticks();
1007 if(assemble3dOctoMap)
1010 timePub3dOctoMap =
t.ticks();
1013 globalMapStats.insert(std::make_pair(std::string(
"GlobalGrid/OctoMapUpdate/ms"), timeUpdateOctoMap*1000.0
f));
1014 globalMapStats.insert(std::make_pair(std::string(
"GlobalGrid/OctoMapProjection/ms"), timePub2dOctoMap*1000.0
f));
1015 globalMapStats.insert(std::make_pair(std::string(
"GlobalGrid/OctomapToCloud/ms"), timePub3dOctoMap*1000.0
f));
1016 globalMapStats.insert(std::make_pair(std::string(
"GlobalGrid/TotalWithRtabmap/ms"), (timeUpdateGrid+timeUpdateCloudMap+timeUpdateOctoMap+timePub2dOctoMap+timePub3dOctoMap+timeRtabmap)*1000.0
f));
1018 globalMapStats.insert(std::make_pair(std::string(
"GlobalGrid/TotalWithRtabmap/ms"), (timeUpdateGrid+timeUpdateCloudMap+timeRtabmap)*1000.0
f));
1025 int refId =
stats.refImageId();
1026 int loopId =
stats.loopClosureId() > 0?
stats.loopClosureId():
stats.proximityDetectionId() > 0?
stats.proximityDetectionId() :0;
1027 int landmarkId = (
int)
uValue(
stats.data(), rtabmap::Statistics::kLoopLandmark_detected(), 0.0f);
1028 int refMapId =
stats.refImageMapId();
1037 if(
stats.loopClosureId()>0)
1049 int loopMapId =
stats.loopClosureId() > 0?
stats.loopClosureMapId():
stats.proximityDetectionMapId();
1050 printf(
"Processed %d/%d nodes [id=%d map=%d opt_graph=%d]... %dms %s on %d [%d]\n", ++processed, totalIds, refId, refMapId,
int(
stats.poses().size()),
int(iterationTime.
ticks() * 1000),
stats.loopClosureId() > 0?
"Loop":
"Prox", loopId, loopMapId);
1052 else if(landmarkId != 0)
1054 printf(
"Processed %d/%d nodes [id=%d map=%d opt_graph=%d]... %dms Loop on landmark %d\n", ++processed, totalIds, refId, refMapId,
int(
stats.poses().size()),
int(iterationTime.
ticks() * 1000), landmarkId);
1058 printf(
"Processed %d/%d nodes [id=%d map=%d opt_graph=%d]... %dms\n", ++processed, totalIds, refId, refMapId,
int(
stats.poses().size()),
int(iterationTime.
ticks() * 1000));
1062 if(!incrementalMemory &&
1063 !lastLocalizationOdomPose.
isNull() &&
1064 !
info.odomPose.isNull())
1066 if(loopId>0 || landmarkId != 0)
1069 lastLocalizationOdomPose =
info.odomPose;
1072 if(!incrementalMemory)
1074 float totalTime =
uValue(
stats.data(), rtabmap::Statistics::kTimingTotal(), 0.0f);
1076 if(
stats.data().find(Statistics::kLoopOdom_correction_norm()) !=
stats.data().end())
1096 if(framesToSkip>0 && !recomputeOdometry)
1098 int skippedFrames = framesToSkip;
1099 while(skippedFrames-- > 0)
1103 if(!odometryIgnored && !
info.odomCovariance.empty() &&
info.odomCovariance.at<
double>(0,0)>=9999)
1105 printf(
"High variance detected, triggering a new map...\n");
1106 if(!incrementalMemory && processed>0)
1109 lastLocalizationOdomPose =
info.odomPose;
1124 if(!incrementalMemory &&
1126 !
info.odomPose.isNull())
1138 int databasesMerged = 0;
1139 if(!incrementalMemory)
1147 if(databases.size()>1)
1149 std::map<int, Transform> poses;
1150 std::multimap<int, Link> constraints;
1151 rtabmap.getGraph(poses, constraints, 0, 1, 0,
false,
false,
false,
false,
false,
false);
1152 std::set<int> mapIds;
1153 for(std::map<int, Transform>::iterator
iter=poses.begin();
iter!=poses.end(); ++
iter)
1156 if((
id=
rtabmap.getMemory()->getMapId(
iter->first,
true))>=0)
1161 databasesMerged = mapIds.size();
1165 printf(
"Closing database \"%s\"...\n", outputDatabasePath.c_str());
1167 printf(
"Closing database \"%s\"... done!\n", outputDatabasePath.c_str());
1173 std::string outputPath = outputDatabasePath.substr(0, outputDatabasePath.size()-3) +
"_map.pgm";
1175 cv::Mat map = grid.
getMap(xMin, yMin);
1184 printf(
"Saving occupancy grid to database... done!\n");
1190 cv::Mat map8U(map.rows, map.cols, CV_8U);
1192 for (
int i = 0;
i < map.rows; ++
i)
1194 for (
int j = 0;
j < map.cols; ++
j)
1196 char v = map.at<
char>(
i,
j);
1210 map8U.at<
unsigned char>(
i,
j) = gray;
1214 if(cv::imwrite(outputPath, map8U))
1216 printf(
"Saving occupancy grid \"%s\"... done!\n", outputPath.c_str());
1220 printf(
"Saving occupancy grid \"%s\"... failed!\n", outputPath.c_str());
1226 printf(
"2D map is empty! Cannot save it!\n");
1231 std::string outputPath = outputDatabasePath.substr(0, outputDatabasePath.size()-3) +
"_obstacles.pcd";
1232 if(pcl::io::savePCDFileBinary(outputPath, *cloudMap.
getMapObstacles()) == 0)
1234 printf(
"Saving 3d obstacles \"%s\"... done!\n", outputPath.c_str());
1238 printf(
"Saving 3d obstacles \"%s\"... failed!\n", outputPath.c_str());
1242 outputPath = outputDatabasePath.substr(0, outputDatabasePath.size()-3) +
"_ground.pcd";
1243 if(pcl::io::savePCDFileBinary(outputPath, *cloudMap.
getMapGround()) == 0)
1245 printf(
"Saving 3d ground \"%s\"... done!\n", outputPath.c_str());
1249 printf(
"Saving 3d ground \"%s\"... failed!\n", outputPath.c_str());
1254 outputPath = outputDatabasePath.substr(0, outputDatabasePath.size()-3) +
"_empty.pcd";
1255 if(pcl::io::savePCDFileBinary(outputPath, *cloudMap.
getMapEmptyCells()) == 0)
1257 printf(
"Saving 3d empty cells \"%s\"... done!\n", outputPath.c_str());
1261 printf(
"Saving 3d empty cells \"%s\"... failed!\n", outputPath.c_str());
1265 #ifdef RTABMAP_OCTOMAP
1266 if(assemble2dOctoMap)
1268 std::string outputPath = outputDatabasePath.substr(0, outputDatabasePath.size()-3) +
"_octomap.pgm";
1269 float xMin,yMin,cellSize;
1278 driver->
save2DMap(map, xMin, yMin, cellSize);
1279 printf(
"Saving occupancy grid to database... done!\n");
1285 cv::Mat map8U(map.rows, map.cols, CV_8U);
1287 for (
int i = 0;
i < map.rows; ++
i)
1289 for (
int j = 0;
j < map.cols; ++
j)
1291 char v = map.at<
char>(
i,
j);
1305 map8U.at<
unsigned char>(
i,
j) = gray;
1308 if(cv::imwrite(outputPath, map8U))
1310 printf(
"Saving octomap 2D projection \"%s\"... done!\n", outputPath.c_str());
1314 printf(
"Saving octomap 2D projection \"%s\"... failed!\n", outputPath.c_str());
1320 printf(
"OctoMap 2D projection map is empty! Cannot save it!\n");
1323 if(assemble3dOctoMap)
1325 std::string outputPath = outputDatabasePath.substr(0, outputDatabasePath.size()-3) +
"_octomap_occupied.pcd";
1326 std::vector<int> obstacles, emptySpace, ground;
1327 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud = octomap.
createCloud(0, &obstacles, &emptySpace, &ground);
1328 if(pcl::io::savePCDFile(outputPath, *cloud, obstacles,
true) == 0)
1330 printf(
"Saving obstacles cloud \"%s\"... done!\n", outputPath.c_str());
1334 printf(
"Saving obstacles cloud \"%s\"... failed!\n", outputPath.c_str());
1338 outputPath = outputDatabasePath.substr(0, outputDatabasePath.size()-3) +
"_octomap_ground.pcd";
1339 if(pcl::io::savePCDFile(outputPath, *cloud, ground,
true) == 0)
1341 printf(
"Saving empty space cloud \"%s\"... done!\n", outputPath.c_str());
1345 printf(
"Saving empty space cloud \"%s\"... failed!\n", outputPath.c_str());
1348 if(emptySpace.size())
1350 outputPath = outputDatabasePath.substr(0, outputDatabasePath.size()-3) +
"_octomap_empty.pcd";
1351 if(pcl::io::savePCDFile(outputPath, *cloud, emptySpace,
true) == 0)
1353 printf(
"Saving empty space cloud \"%s\"... done!\n", outputPath.c_str());
1357 printf(
"Saving empty space cloud \"%s\"... failed!\n", outputPath.c_str());
1363 return databasesMerged;