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 " -odom_input_guess Forward input database's odometry (if exists) as guess when recompting odometry.\n"
79 " -odom_lin_var #.# Override computed odometry linear covariance."
80 " -odom_ang_var #.# Override computed odometry angular covariance."
81 " -start # Start from this node ID.\n"
82 " -stop # Last node to process.\n"
83 " -start_s # Start from this map session ID.\n"
84 " -stop_s # Last map session to process.\n"
85 " -a Append mode: if Mem/IncrementalMemory is true, RTAB-Map is initialized with the first input database,\n"
86 " then next databases are reprocessed on top of the first one.\n"
87 " -cam # Camera index to stream. Ignored if a database doesn't contain multi-camera data. Can also be multiple \n"
88 " indices split by spaces in a string like \"0 2\" to stream cameras 0 and 2 only.\n"
89 " -cam_tf \"x y z roll pitch yaw\" Camera local transform override(s) without optical rotation. For multi-cameras, \n"
90 " use a \";\" between each transform.\n"
91 " -cam_tf_lens_offset #.# Override camera local transform with an y-axis offset before optical rotation. \n"
92 " If -cam_tf is also used, it is combined before optical rotation. For multi-cameras,\n"
93 " -cam_tf should be also used, and explicitly enumerate offsets if they are different, \n"
94 " e.g., \"0.05 0.075\" for two cameras setup.\n"
95 " -nolandmark Don't republish landmarks contained in input database.\n"
96 " -nopriors Don't republish priors contained in input database.\n"
97 " -pub_loops Republish loop closures contained in input database.\n"
98 " -loc_null On localization mode, reset localization pose to null and map correction to identity between sessions.\n"
99 " -gt When reprocessing a single database, load its original optimized graph, then \n"
100 " set it as ground truth for output database. If there was a ground truth in the input database, it will be ignored.\n"
101 " -g2 Assemble 2D occupancy grid map and save it to \"[output]_map.pgm\". Use with -db to save in database.\n"
102 " -g3 Assemble 3D cloud map and save it to \"[output]_map.pcd\".\n"
103 " -o2 Assemble OctoMap 2D projection and save it to \"[output]_octomap.pgm\". Use with -db to save in database.\n"
104 " -o3 Assemble OctoMap 3D cloud and save it to \"[output]_octomap.pcd\".\n"
105 " -db Save assembled 2D occupancy grid in database instead of a file.\n"
106 " -p Save odometry and localization poses (*.g2o).\n"
107 " -scan_from_depth Generate scans from depth images (overwrite previous\n"
108 " scans if they exist).\n"
109 " -scan_downsample # Downsample input scans.\n"
110 " -scan_range_min #.# Filter input scans with minimum range (m).\n"
111 " -scan_range_max #.# Filter input scans with maximum range (m).\n"
112 " -scan_voxel_size #.# Voxel filter input scans (m).\n"
113 " -scan_normal_k # Compute input scan normals (k-neighbors approach).\n"
114 " -scan_normal_radius #.# Compute input scan normals (radius(m)-neighbors approach).\n\n"
124 printf(
"\nSignal %d caught...\n", sig);
154 printf(
"Average localization time = %f ms (stddev=%f ms)\n",
m, stddev);
176 stddevA =
sqrt(varA);
178 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);
189 printf(
"Average distance from previous localization = %f m (stddev=%f m)\n",
m, stddev);
200 printf(
"Average odometry distances = %f m (stddev=%f m)\n",
m, stddev);
205 std::string outputPath = outputDatabasePath.substr(0, outputDatabasePath.size()-3);
210 printf(
"Exported %s and %s\n", oName.c_str(), lName.c_str());
239 for(
int i=1;
i<argc; ++
i)
241 if(strcmp(
argv[
i],
"--help") == 0)
254 bool save2DMap =
false;
255 bool assemble2dMap =
false;
256 bool assemble3dMap =
false;
257 bool assemble2dOctoMap =
false;
258 bool assemble3dOctoMap =
false;
259 bool useDatabaseRate =
false;
260 bool useDefaultParameters =
false;
261 bool recomputeOdometry =
false;
262 bool useInputOdometryAsGuess =
false;
263 double odomLinVarOverride = 0.0;
264 double odomAngVarOverride = 0.0;
269 bool appendMode =
false;
270 std::vector<unsigned int> cameraIndices;
271 std::vector<Transform> cameraLocalTransformOverrides;
272 std::vector<float> cameraLocalTransformOffsetOverrides;
273 int framesToSkip = 0;
274 bool ignoreLandmarks =
false;
275 bool ignorePriors =
false;
276 bool republishLoopClosures =
false;
277 bool locNull =
false;
278 bool originalGraphAsGT =
false;
279 bool scanFromDepth =
false;
280 int scanDecimation = 1;
281 float scanRangeMin = 0.0f;
282 float scanRangeMax = 0.0f;
283 float scanVoxelSize = 0;
285 float scanNormalRadius = 0.0f;
287 for(
int i=1;
i<argc-2; ++
i)
289 if(strcmp(
argv[
i],
"-r") == 0 || strcmp(
argv[
i],
"--r") == 0)
291 useDatabaseRate =
true;
292 printf(
"Using database stamps as input rate.\n");
294 else if (strcmp(
argv[
i],
"-c") == 0 || strcmp(
argv[
i],
"--c") == 0)
300 printf(
"Using %d parameters from config file \"%s\"\n", (
int)configParameters.size(),
argv[
i]);
302 else if(
i < argc - 2)
304 printf(
"Config file \"%s\" is not valid or doesn't exist!\n",
argv[
i]);
309 printf(
"Config file is not set!\n");
313 else if(strcmp(
argv[
i],
"-default") == 0 || strcmp(
argv[
i],
"--default") == 0)
315 useDefaultParameters =
true;
316 printf(
"Using default parameters.\n");
318 else if(strcmp(
argv[
i],
"-odom") == 0 || strcmp(
argv[
i],
"--odom") == 0)
320 recomputeOdometry =
true;
322 else if(strcmp(
argv[
i],
"-odom_input_guess") == 0 || strcmp(
argv[
i],
"--odom_input_guess") == 0)
324 useInputOdometryAsGuess =
true;
326 else if (strcmp(
argv[
i],
"-odom_lin_var") == 0 || strcmp(
argv[
i],
"--odom_lin_var") == 0)
332 printf(
"Odometry linear variance overriden to = %f.\n", odomLinVarOverride);
336 printf(
"-odom_lin_var option requires a value\n");
340 else if (strcmp(
argv[
i],
"-odom_ang_var") == 0 || strcmp(
argv[
i],
"--odom_ang_var") == 0)
346 printf(
"Odometry angular variance overriden to = %f.\n", odomAngVarOverride);
350 printf(
"-odom_ang_var option requires a value\n");
354 else if (strcmp(
argv[
i],
"-start") == 0 || strcmp(
argv[
i],
"--start") == 0)
359 startId = atoi(
argv[
i]);
360 printf(
"Start at node ID = %d.\n", startId);
364 printf(
"-start option requires a value\n");
368 else if (strcmp(
argv[
i],
"-stop") == 0 || strcmp(
argv[
i],
"--stop") == 0)
373 stopId = atoi(
argv[
i]);
374 printf(
"Stop at node ID = %d.\n", stopId);
378 printf(
"-stop option requires a value\n");
382 else if (strcmp(
argv[
i],
"-start_s") == 0 || strcmp(
argv[
i],
"--start_s") == 0)
387 startMapId = atoi(
argv[
i]);
388 printf(
"Start at map session ID = %d.\n", startMapId);
392 printf(
"-start_s option requires a value\n");
396 else if (strcmp(
argv[
i],
"-stop_s") == 0 || strcmp(
argv[
i],
"--stop_s") == 0)
401 stopMapId = atoi(
argv[
i]);
402 printf(
"Stop at map session ID = %d.\n", stopMapId);
406 printf(
"-stop option requires a value\n");
410 else if (strcmp(
argv[
i],
"-a") == 0 || strcmp(
argv[
i],
"--a") == 0)
413 printf(
"Append mode enabled (initialize with first database then reprocess next ones)\n");
415 else if (strcmp(
argv[
i],
"-cam") == 0 || strcmp(
argv[
i],
"--cam") == 0)
420 std::list<std::string> indicesStr =
uSplit(
argv[
i],
' ');
421 for(std::list<std::string>::iterator
iter=indicesStr.begin();
iter!=indicesStr.end(); ++
iter)
424 printf(
"Camera index = %d.\n", cameraIndices.back());
429 printf(
"-cam option requires a value\n");
433 else if (strcmp(
argv[
i],
"-cam_tf") == 0 || strcmp(
argv[
i],
"--cam_tf") == 0)
438 std::list<std::string> tfStr =
uSplit(
argv[
i],
';');
439 for(std::list<std::string>::iterator
iter=tfStr.begin();
iter!=tfStr.end(); ++
iter)
442 printf(
"Camera transform = %s\n", cameraLocalTransformOverrides.back().prettyPrint().c_str());
447 printf(
"-cam option requires a value\n");
451 else if (strcmp(
argv[
i],
"-cam_tf_lens_offset") == 0 || strcmp(
argv[
i],
"--cam_tf_lens_offset") == 0)
456 std::list<std::string> offsetStr =
uSplit(
argv[
i],
' ');
457 for(std::list<std::string>::iterator
iter=offsetStr.begin();
iter!=offsetStr.end(); ++
iter)
460 printf(
"Camera offset = %f\n", cameraLocalTransformOffsetOverrides.back());
465 printf(
"-cam option requires a value\n");
469 else if (strcmp(
argv[
i],
"-skip") == 0 || strcmp(
argv[
i],
"--skip") == 0)
474 framesToSkip = atoi(
argv[
i]);
475 printf(
"Will skip %d frames.\n", framesToSkip);
479 printf(
"-skip option requires a value\n");
483 else if(strcmp(
argv[
i],
"-nolandmark") == 0 || strcmp(
argv[
i],
"--nolandmark") == 0)
485 ignoreLandmarks =
true;
486 printf(
"Ignoring landmarks from input database (-nolandmark option).\n");
488 else if(strcmp(
argv[
i],
"-nopriors") == 0 || strcmp(
argv[
i],
"--nopriors") == 0)
491 printf(
"Ignoring priors from input database (-nopriors option).\n");
493 else if(strcmp(
argv[
i],
"-pub_loops") == 0 || strcmp(
argv[
i],
"--pub_loops") == 0)
495 republishLoopClosures =
true;
496 printf(
"Republish loop closures from input database (-pub_loops option).\n");
498 else if(strcmp(
argv[
i],
"-loc_null") == 0 || strcmp(
argv[
i],
"--loc_null") == 0)
501 printf(
"In localization mode, when restarting a new session, the current localization pose is set to null (-loc_null option).\n");
503 else if(strcmp(
argv[
i],
"-gt") == 0 || strcmp(
argv[
i],
"--gt") == 0)
505 originalGraphAsGT =
true;
506 printf(
"Original graph is used as ground truth for output database (-gt option).\n");
508 else if(strcmp(
argv[
i],
"-p") == 0 || strcmp(
argv[
i],
"--p") == 0)
511 printf(
"Odometry trajectory and localization poses will be exported in g2o format (-p option).\n");
513 else if(strcmp(
argv[
i],
"-db") == 0 || strcmp(
argv[
i],
"--db") == 0)
516 printf(
"2D occupancy grid will be saved in database (-db option).\n");
518 else if(strcmp(
argv[
i],
"-g2") == 0 || strcmp(
argv[
i],
"--g2") == 0)
520 assemble2dMap =
true;
521 printf(
"2D occupancy grid will be assembled (-g2 option).\n");
523 else if(strcmp(
argv[
i],
"-g3") == 0 || strcmp(
argv[
i],
"--g3") == 0)
525 assemble3dMap =
true;
526 printf(
"3D cloud map will be assembled (-g3 option).\n");
528 else if(strcmp(
argv[
i],
"-o2") == 0 || strcmp(
argv[
i],
"--o2") == 0)
530 #ifdef RTABMAP_OCTOMAP
531 assemble2dOctoMap =
true;
532 printf(
"OctoMap will be assembled (-o2 option).\n");
534 printf(
"RTAB-Map is not built with OctoMap support, cannot set -o2 option!\n");
537 else if(strcmp(
argv[
i],
"-o3") == 0 || strcmp(
argv[
i],
"--o3") == 0)
539 #ifdef RTABMAP_OCTOMAP
540 assemble3dOctoMap =
true;
541 printf(
"OctoMap will be assembled (-o3 option).\n");
543 printf(
"RTAB-Map is not built with OctoMap support, cannot set -o3 option!\n");
546 else if (strcmp(
argv[
i],
"-scan_from_depth") == 0 || strcmp(
argv[
i],
"--scan_from_depth") == 0)
548 scanFromDepth =
true;
550 else if (strcmp(
argv[
i],
"-scan_downsample") == 0 || strcmp(
argv[
i],
"--scan_downsample") == 0 ||
551 strcmp(
argv[
i],
"-scan_decimation") == 0 || strcmp(
argv[
i],
"--scan_decimation") == 0)
556 scanDecimation = atoi(
argv[
i]);
557 printf(
"Scan from depth decimation = %d.\n", scanDecimation);
561 printf(
"-scan_downsample option requires 1 value\n");
565 else if (strcmp(
argv[
i],
"-scan_range_min") == 0 || strcmp(
argv[
i],
"--scan_range_min") == 0)
570 scanRangeMin = atof(
argv[
i]);
571 printf(
"Scan range min = %f m.\n", scanRangeMin);
575 printf(
"-scan_range_min option requires 1 value\n");
579 else if (strcmp(
argv[
i],
"-scan_range_max") == 0 || strcmp(
argv[
i],
"--scan_range_max") == 0)
584 scanRangeMax = atof(
argv[
i]);
585 printf(
"Scan range max = %f m.\n", scanRangeMax);
589 printf(
"-scan_range_max option requires 1 value\n");
593 else if (strcmp(
argv[
i],
"-scan_voxel_size") == 0 || strcmp(
argv[
i],
"--scan_voxel_size") == 0)
598 scanVoxelSize = atof(
argv[
i]);
599 printf(
"Scan voxel size = %f m.\n", scanVoxelSize);
603 printf(
"-scan_voxel_size option requires 1 value\n");
607 else if (strcmp(
argv[
i],
"-scan_normal_k") == 0 || strcmp(
argv[
i],
"--scan_normal_k") == 0)
612 scanNormalK = atoi(
argv[
i]);
613 printf(
"Scan normal k = %d.\n", scanNormalK);
617 printf(
"-scan_normal_k option requires 1 value\n");
621 else if (strcmp(
argv[
i],
"-scan_normal_radius") == 0 || strcmp(
argv[
i],
"--scan_normal_radius") == 0)
626 scanNormalRadius = atof(
argv[
i]);
627 printf(
"Scan normal radius = %f m.\n", scanNormalRadius);
631 printf(
"-scan_normal_radius option requires 1 value\n");
640 std::list<std::string> databases =
uSplit(inputDatabasePath,
';');
641 if (databases.empty())
643 printf(
"No input database \"%s\" detected!\n", inputDatabasePath.c_str());
646 for (std::list<std::string>::iterator
iter = databases.begin();
iter != databases.end(); ++
iter)
650 printf(
"Input database \"%s\" doesn't exist!\n",
iter->c_str());
653 printf(
"Did you mean \"%s\"?\n",
uReplaceChar(inputDatabasePath,
':',
";").
c_str());
660 printf(
"File \"%s\" is not a database format (*.db)!\n",
iter->c_str());
667 printf(
"File \"%s\" is not a database format (*.db)!\n", outputDatabasePath.c_str());
680 printf(
"Failed opening input database!\n");
686 std::string targetVersion;
687 if(!useDefaultParameters)
691 parameters.insert(
ParametersPair(Parameters::kDbTargetVersion(), targetVersion));
692 if(parameters.empty())
694 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());
698 if(customParameters.size())
700 printf(
"Custom parameters:\n");
701 for(ParametersMap::iterator
iter=customParameters.begin();
iter!=customParameters.end(); ++
iter)
703 printf(
" %s %s\n",
uPad(
iter->first+
" =", 25).c_str(),
iter->second.c_str());
707 bool useOdomFeatures = Parameters::defaultMemUseOdomFeatures();
708 if((configParameters.find(Parameters::kKpDetectorStrategy())!=configParameters.end() ||
709 configParameters.find(Parameters::kVisFeatureType())!=configParameters.end() ||
710 customParameters.find(Parameters::kKpDetectorStrategy())!=customParameters.end() ||
711 customParameters.find(Parameters::kVisFeatureType())!=customParameters.end()) &&
712 configParameters.find(Parameters::kMemUseOdomFeatures())==configParameters.end() &&
713 customParameters.find(Parameters::kMemUseOdomFeatures())==customParameters.end())
715 Parameters::parse(parameters, Parameters::kMemUseOdomFeatures(), useOdomFeatures);
718 printf(
"[Warning] %s and/or %s are overwritten but parameter %s is true in the opened database. "
719 "Setting it to false for convenience to use the new selected feature detector. Set %s "
720 "explicitly to suppress this warning.\n",
721 Parameters::kKpDetectorStrategy().
c_str(),
722 Parameters::kVisFeatureType().
c_str(),
723 Parameters::kMemUseOdomFeatures().
c_str(),
724 Parameters::kMemUseOdomFeatures().
c_str());
726 useOdomFeatures =
false;
730 if(useOdomFeatures && databases.size() > 1 &&
731 configParameters.find(Parameters::kMemUseOdomFeatures())==configParameters.end() &&
732 customParameters.find(Parameters::kMemUseOdomFeatures())==customParameters.end())
734 printf(
"[Warning] Parameter %s is set to false for convenience as "
735 "there are more than one input database (which could "
736 "contain different features). Set %s "
737 "explicitly to suppress this warning.\n",
738 Parameters::kMemUseOdomFeatures().
c_str(),
739 Parameters::kMemUseOdomFeatures().
c_str());
740 useOdomFeatures =
false;
743 if(republishLoopClosures)
745 if(databases.size() > 1)
747 printf(
"[Warning] \"pub_loops\" option cannot be used with multiple databases input. "
748 "Disabling \"pub_loops\" to avoid mismatched loop closue ids.\n");
749 republishLoopClosures =
false;
753 bool generateIds = Parameters::defaultMemGenerateIds();
759 if(configParameters.find(Parameters::kMemGenerateIds())!=configParameters.end() ||
760 customParameters.find(Parameters::kMemGenerateIds())!=customParameters.end())
762 printf(
"[Warning] \"pub_loops\" option is used but parameter %s is set to true in custom arguments. "
763 "Disabling \"pub_loops\" to avoid mismatched loop closure ids.\n",
764 Parameters::kMemGenerateIds().
c_str());
765 republishLoopClosures =
false;
769 printf(
"[Warning] \"pub_loops\" option is used but parameter %s is true in the opened database. "
770 "Setting parameter %s to false for convenience so that republished loop closure ids match.\n",
771 Parameters::kMemGenerateIds().
c_str(),
772 Parameters::kMemGenerateIds().
c_str());
778 uInsert(parameters, configParameters);
779 uInsert(parameters, customParameters);
781 bool incrementalMemory = Parameters::defaultMemIncrementalMemory();
782 Parameters::parse(parameters, Parameters::kMemIncrementalMemory(), incrementalMemory);
784 bool intermediateNodes = Parameters::defaultRtabmapCreateIntermediateNodes();
785 Parameters::parse(parameters, Parameters::kRtabmapCreateIntermediateNodes(), intermediateNodes);
789 dbDriver->
getAllNodeIds(ids,
false,
false, !intermediateNodes);
792 printf(
"Input database doesn't have any nodes saved in it.\n");
797 if(!((!incrementalMemory || appendMode) && databases.size() > 1))
799 totalIds = ids.size();
802 std::map<int, Transform> gt;
803 if(databases.size() == 1 && originalGraphAsGT)
811 for (std::list<std::string>::iterator
iter = ++databases.begin();
iter != databases.end(); ++
iter)
815 printf(
"Failed opening input database!\n");
820 dbDriver->
getAllNodeIds(ids,
false,
false, !intermediateNodes);
821 totalIds += ids.size();
828 printf(
"Set working directory to \"%s\".\n", workingDirectory.c_str());
829 if(!targetVersion.empty())
831 printf(
"Target database version: \"%s\" (set explicitly --%s \"\" to output with latest version.\n", targetVersion.c_str(), Parameters::kDbTargetVersion().c_str());
836 if((!incrementalMemory || appendMode ) && databases.size() > 1)
838 UFile::copy(databases.front(), outputDatabasePath);
839 if(!incrementalMemory)
841 printf(
"Parameter \"%s\" is set to false, initializing RTAB-Map with \"%s\" for localization...\n", Parameters::kMemIncrementalMemory().
c_str(), databases.front().c_str());
843 databases.pop_front();
844 inputDatabasePath =
uJoin(databases,
";");
848 rtabmap.init(parameters, outputDatabasePath);
850 if(!incrementalMemory && locNull)
855 bool rgbdEnabled = Parameters::defaultRGBDEnabled();
857 bool odometryIgnored = !rgbdEnabled;
859 if(!cameraLocalTransformOffsetOverrides.empty())
861 if(!cameraLocalTransformOverrides.empty() && cameraLocalTransformOffsetOverrides.size() > 1 && cameraLocalTransformOffsetOverrides.size() != cameraLocalTransformOverrides.size())
863 printf(
"Error: -cam_tf_lens_offset size (%ld) is not equal to -cam_tf argument (%ld). "
864 "-cam_tf_lens_offset should be one to affect all cameras or same size than -cam_tf argument.\n",
865 cameraLocalTransformOffsetOverrides.size(), cameraLocalTransformOverrides.size());
869 if(cameraLocalTransformOverrides.empty())
871 if(cameraLocalTransformOffsetOverrides.size() > 1)
873 printf(
"Error: -cam_tf_lens_offset size (%ld) should be one if -cam_tf is not set.\n",
874 cameraLocalTransformOffsetOverrides.size());
880 for(
size_t i=0;
i<cameraLocalTransformOverrides.size(); ++
i)
882 float offset = cameraLocalTransformOffsetOverrides.
size()==1?cameraLocalTransformOffsetOverrides[0]:cameraLocalTransformOffsetOverrides[
i];
884 printf(
"Overriding camera's local transform %ld to %s (offset=%f)\n",
i, cameraLocalTransformOverrides[
i].prettyPrint().
c_str(),
offset);
890 useDatabaseRate?-1:0,
903 cameraLocalTransformOverrides);
909 #ifdef RTABMAP_OCTOMAP
910 OctoMap octomap(&mapCache, parameters);
912 CloudMap cloudMap(&mapCache, parameters);
914 float linearUpdate = Parameters::defaultRGBDLinearUpdate();
915 float angularUpdate = Parameters::defaultRGBDAngularUpdate();
920 float rtabmapUpdateRate = Parameters::defaultRtabmapDetectionRate();
921 double lastUpdateStamp = 0;
922 if(recomputeOdometry)
926 printf(
"odom option is set but %s parameter is false, odometry won't be recomputed...\n", Parameters::kRGBDEnabled().
c_str());
927 recomputeOdometry =
false;
931 printf(
"Odometry will be recomputed (odom option is set)\n");
932 Parameters::parse(parameters, Parameters::kRtabmapDetectionRate(), rtabmapUpdateRate);
933 if(rtabmapUpdateRate!=0)
935 rtabmapUpdateRate = 1.0f/rtabmapUpdateRate;
941 printf(
"Reprocessing data of \"%s\"...\n", inputDatabasePath.c_str());
942 std::map<std::string, float> globalMapStats;
947 camThread.
setScanParameters(scanFromDepth, scanDecimation, scanRangeMin, scanRangeMax, scanVoxelSize, scanNormalK, scanNormalRadius);
955 cv::Mat odomCovariance;
956 bool inMotion =
true;
959 if(recomputeOdometry)
963 previousOdomPose =
info.odomPose;
966 if(odomLinVarOverride > 0.0)
968 odomInfo.
reg.
covariance.at<
double>(0,0) = odomLinVarOverride;
969 odomInfo.
reg.
covariance.at<
double>(1,1) = odomLinVarOverride;
970 odomInfo.
reg.
covariance.at<
double>(2,2) = odomLinVarOverride;
972 if(odomAngVarOverride > 0.0)
974 odomInfo.
reg.
covariance.at<
double>(3,3) = odomAngVarOverride;
975 odomInfo.
reg.
covariance.at<
double>(4,4) = odomAngVarOverride;
976 odomInfo.
reg.
covariance.at<
double>(5,5) = odomAngVarOverride;
983 if(odomCovariance.empty() || odomInfo.
reg.
covariance.at<
double>(0,0) > odomCovariance.at<
double>(0,0))
989 printf(
"Processed %d/%d frames (visual=%s lidar=%s lost=%s)... odometry = %dms\n",
994 odomInfo.
lost?
"true":
"false",
996 if(lastUpdateStamp > 0.0 && (
data.stamp() < lastUpdateStamp + rtabmapUpdateRate || framesToSkip>0))
1000 int skippedFrames = framesToSkip;
1001 while(skippedFrames-- > 0)
1017 info.odomPose = pose;
1018 info.odomCovariance = odomCovariance;
1019 odomCovariance = cv::Mat();
1020 lastUpdateStamp =
data.stamp();
1027 if(!odometryIgnored &&
info.odomPose.isNull())
1029 printf(
"Skipping node %d as it doesn't have odometry pose set.\n",
data.id());
1033 if(!odometryIgnored && !
info.odomCovariance.empty() &&
info.odomCovariance.at<
double>(0,0)>=9999)
1035 printf(
"High variance detected, triggering a new map...\n");
1036 if(!incrementalMemory && processed>0)
1039 lastLocalizationOdomPose =
info.odomPose;
1042 if(!incrementalMemory && locNull)
1049 if(originalGraphAsGT)
1057 printf(
"Failed processing node %d.\n",
data.id());
1058 globalMapStats.clear();
1062 if(republishLoopClosures && dbReader->
driver())
1064 std::multimap<int, Link> links;
1066 for(std::multimap<int, Link>::iterator
iter=links.begin();
iter!=links.end(); ++
iter)
1074 if(!
iter->second.transform().isNull() &&
1075 rtabmap.getMemory()->getWorkingMem().find(
iter->second.to()) !=
rtabmap.getMemory()->getWorkingMem().end() &&
1078 printf(
"Added link %d->%d from input database.\n",
iter->second.from(),
iter->second.to());
1084 if(assemble2dMap || assemble3dMap || assemble2dOctoMap || assemble3dOctoMap)
1086 globalMapStats.clear();
1087 double timeRtabmap =
t.ticks();
1088 double timeUpdateInit = 0.0;
1089 double timeUpdateGrid = 0.0;
1090 double timeUpdateCloudMap = 0.0;
1091 #ifdef RTABMAP_OCTOMAP
1092 double timeUpdateOctoMap = 0.0;
1095 if(
stats.poses().size() &&
stats.getLastSignatureData().id())
1097 int id =
stats.poses().rbegin()->first;
1098 if(
id ==
stats.getLastSignatureData().id() &&
1099 stats.getLastSignatureData().sensorData().gridCellSize() > 0.0f)
1101 bool updateGridMap =
false;
1102 bool updateOctoMap =
false;
1103 bool updateCloudMap =
false;
1106 updateGridMap =
true;
1110 updateCloudMap =
true;
1112 #ifdef RTABMAP_OCTOMAP
1113 if((assemble2dOctoMap || assemble3dOctoMap) && octomap.
addedNodes().find(
id) == octomap.
addedNodes().end())
1115 updateOctoMap =
true;
1118 if(updateGridMap || updateOctoMap || updateCloudMap)
1120 cv::Mat ground, obstacles,
empty;
1121 stats.getLastSignatureData().sensorData().uncompressDataConst(0, 0, 0, 0, &ground, &obstacles, &
empty);
1122 float cellSize =
stats.getLastSignatureData().sensorData().gridCellSize();
1123 const cv::Point3f & viewpoint =
stats.getLastSignatureData().sensorData().gridViewPoint();
1125 timeUpdateInit =
t.ticks();
1127 mapCache.
add(
id, ground, obstacles,
empty, cellSize, viewpoint);
1132 timeUpdateGrid =
t.ticks() + timeUpdateInit;
1137 timeUpdateCloudMap =
t.ticks() + timeUpdateInit;
1139 #ifdef RTABMAP_OCTOMAP
1143 timeUpdateOctoMap =
t.ticks() + timeUpdateInit;
1150 globalMapStats.insert(std::make_pair(std::string(
"GlobalGrid/GridUpdate/ms"), timeUpdateGrid*1000.0
f));
1151 globalMapStats.insert(std::make_pair(std::string(
"GlobalGrid/CloudUpdate/ms"), timeUpdateCloudMap*1000.0
f));
1152 #ifdef RTABMAP_OCTOMAP
1154 double timePub2dOctoMap = 0.0;
1155 double timePub3dOctoMap = 0.0;
1156 if(assemble2dOctoMap)
1158 float xMin, yMin,
size;
1160 timePub2dOctoMap =
t.ticks();
1162 if(assemble3dOctoMap)
1165 timePub3dOctoMap =
t.ticks();
1168 globalMapStats.insert(std::make_pair(std::string(
"GlobalGrid/OctoMapUpdate/ms"), timeUpdateOctoMap*1000.0
f));
1169 globalMapStats.insert(std::make_pair(std::string(
"GlobalGrid/OctoMapProjection/ms"), timePub2dOctoMap*1000.0
f));
1170 globalMapStats.insert(std::make_pair(std::string(
"GlobalGrid/OctomapToCloud/ms"), timePub3dOctoMap*1000.0
f));
1171 globalMapStats.insert(std::make_pair(std::string(
"GlobalGrid/TotalWithRtabmap/ms"), (timeUpdateGrid+timeUpdateCloudMap+timeUpdateOctoMap+timePub2dOctoMap+timePub3dOctoMap+timeRtabmap)*1000.0
f));
1173 globalMapStats.insert(std::make_pair(std::string(
"GlobalGrid/TotalWithRtabmap/ms"), (timeUpdateGrid+timeUpdateCloudMap+timeRtabmap)*1000.0
f));
1180 int refId =
stats.refImageId();
1181 bool rejected =
uValue(
stats.data(), rtabmap::Statistics::kLoopRejectedHypothesis(), 0.0f) != 0.0f;
1182 int loopId =
stats.loopClosureId() > 0?
stats.loopClosureId():
stats.proximityDetectionId() > 0?
stats.proximityDetectionId() :0;
1183 int landmarkId = rejected?0:(
int)
uValue(
stats.data(), rtabmap::Statistics::kLoopLandmark_detected(), 0.0f);
1184 int refMapId =
stats.refImageMapId();
1193 if(
stats.loopClosureId()>0)
1205 int loopMapId =
stats.loopClosureId() > 0?
stats.loopClosureMapId():
stats.proximityDetectionMapId();
1206 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);
1208 else if(landmarkId != 0)
1210 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);
1214 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));
1218 if(!incrementalMemory &&
1219 !lastLocalizationOdomPose.
isNull() &&
1220 !
info.odomPose.isNull())
1222 if(loopId>0 || landmarkId != 0)
1225 lastLocalizationOdomPose =
info.odomPose;
1228 if(!incrementalMemory)
1230 float totalTime =
uValue(
stats.data(), rtabmap::Statistics::kTimingTotal(), 0.0f);
1232 if(
stats.data().find(Statistics::kLoopOdom_correction_norm()) !=
stats.data().end())
1252 if(framesToSkip>0 && !recomputeOdometry)
1254 int skippedFrames = framesToSkip;
1255 while(skippedFrames-- > 0)
1259 if(!odometryIgnored && !
info.odomCovariance.empty() &&
info.odomCovariance.at<
double>(0,0)>=9999)
1261 printf(
"High variance detected, triggering a new map...\n");
1262 if(!incrementalMemory && processed>0)
1265 lastLocalizationOdomPose =
info.odomPose;
1280 if(!incrementalMemory &&
1282 !
info.odomPose.isNull())
1294 int databasesMerged = 0;
1295 if(!incrementalMemory)
1303 if(databases.size()>1)
1305 std::map<int, Transform> poses;
1306 std::multimap<int, Link> constraints;
1307 rtabmap.getGraph(poses, constraints, 0, 1, 0,
false,
false,
false,
false,
false,
false);
1308 std::set<int> mapIds;
1309 for(std::map<int, Transform>::iterator
iter=poses.begin();
iter!=poses.end(); ++
iter)
1312 if((
id=
rtabmap.getMemory()->getMapId(
iter->first,
true))>=0)
1317 databasesMerged = mapIds.size();
1321 printf(
"Closing database \"%s\"...\n", outputDatabasePath.c_str());
1323 printf(
"Closing database \"%s\"... done!\n", outputDatabasePath.c_str());
1329 std::string outputPath = outputDatabasePath.substr(0, outputDatabasePath.size()-3) +
"_map.pgm";
1331 cv::Mat map = grid.
getMap(xMin, yMin);
1340 printf(
"Saving occupancy grid to database... done!\n");
1346 cv::Mat map8U(map.rows, map.cols, CV_8U);
1348 for (
int i = 0;
i < map.rows; ++
i)
1350 for (
int j = 0;
j < map.cols; ++
j)
1352 char v = map.at<
char>(
i,
j);
1366 map8U.at<
unsigned char>(
i,
j) = gray;
1370 if(cv::imwrite(outputPath, map8U))
1372 printf(
"Saving occupancy grid \"%s\"... done!\n", outputPath.c_str());
1376 printf(
"Saving occupancy grid \"%s\"... failed!\n", outputPath.c_str());
1382 printf(
"2D map is empty! Cannot save it!\n");
1387 std::string outputPath = outputDatabasePath.substr(0, outputDatabasePath.size()-3) +
"_obstacles.pcd";
1388 if(pcl::io::savePCDFileBinary(outputPath, *cloudMap.
getMapObstacles()) == 0)
1390 printf(
"Saving 3d obstacles \"%s\"... done!\n", outputPath.c_str());
1394 printf(
"Saving 3d obstacles \"%s\"... failed!\n", outputPath.c_str());
1398 outputPath = outputDatabasePath.substr(0, outputDatabasePath.size()-3) +
"_ground.pcd";
1399 if(pcl::io::savePCDFileBinary(outputPath, *cloudMap.
getMapGround()) == 0)
1401 printf(
"Saving 3d ground \"%s\"... done!\n", outputPath.c_str());
1405 printf(
"Saving 3d ground \"%s\"... failed!\n", outputPath.c_str());
1410 outputPath = outputDatabasePath.substr(0, outputDatabasePath.size()-3) +
"_empty.pcd";
1411 if(pcl::io::savePCDFileBinary(outputPath, *cloudMap.
getMapEmptyCells()) == 0)
1413 printf(
"Saving 3d empty cells \"%s\"... done!\n", outputPath.c_str());
1417 printf(
"Saving 3d empty cells \"%s\"... failed!\n", outputPath.c_str());
1421 #ifdef RTABMAP_OCTOMAP
1422 if(assemble2dOctoMap)
1424 std::string outputPath = outputDatabasePath.substr(0, outputDatabasePath.size()-3) +
"_octomap.pgm";
1425 float xMin,yMin,cellSize;
1434 driver->
save2DMap(map, xMin, yMin, cellSize);
1435 printf(
"Saving occupancy grid to database... done!\n");
1441 cv::Mat map8U(map.rows, map.cols, CV_8U);
1443 for (
int i = 0;
i < map.rows; ++
i)
1445 for (
int j = 0;
j < map.cols; ++
j)
1447 char v = map.at<
char>(
i,
j);
1461 map8U.at<
unsigned char>(
i,
j) = gray;
1464 if(cv::imwrite(outputPath, map8U))
1466 printf(
"Saving octomap 2D projection \"%s\"... done!\n", outputPath.c_str());
1470 printf(
"Saving octomap 2D projection \"%s\"... failed!\n", outputPath.c_str());
1476 printf(
"OctoMap 2D projection map is empty! Cannot save it!\n");
1479 if(assemble3dOctoMap)
1481 std::string outputPath = outputDatabasePath.substr(0, outputDatabasePath.size()-3) +
"_octomap_occupied.pcd";
1482 std::vector<int> obstacles, emptySpace, ground;
1483 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud = octomap.
createCloud(0, &obstacles, &emptySpace, &ground);
1484 if(pcl::io::savePCDFile(outputPath, *cloud, obstacles,
true) == 0)
1486 printf(
"Saving obstacles cloud \"%s\"... done!\n", outputPath.c_str());
1490 printf(
"Saving obstacles cloud \"%s\"... failed!\n", outputPath.c_str());
1494 outputPath = outputDatabasePath.substr(0, outputDatabasePath.size()-3) +
"_octomap_ground.pcd";
1495 if(pcl::io::savePCDFile(outputPath, *cloud, ground,
true) == 0)
1497 printf(
"Saving empty space cloud \"%s\"... done!\n", outputPath.c_str());
1501 printf(
"Saving empty space cloud \"%s\"... failed!\n", outputPath.c_str());
1504 if(emptySpace.size())
1506 outputPath = outputDatabasePath.substr(0, outputDatabasePath.size()-3) +
"_octomap_empty.pcd";
1507 if(pcl::io::savePCDFile(outputPath, *cloud, emptySpace,
true) == 0)
1509 printf(
"Saving empty space cloud \"%s\"... done!\n", outputPath.c_str());
1513 printf(
"Saving empty space cloud \"%s\"... failed!\n", outputPath.c_str());
1519 return databasesMerged;