45 #include <pcl/common/common.h> 46 #include <yaml-cpp/yaml.h> 56 "rtabmap-kitti_dataset [options] path\n" 57 " path Folder of the sequence (e.g., \"~/EuRoC/V1_03_difficult\")\n" 58 " containing least mav0/cam0/sensor.yaml, mav0/cam1/sensor.yaml and \n" 59 " mav0/cam0/data and mav0/cam1/data folders.\n" 60 " --output Output directory. By default, results are saved in \"path\".\n" 61 " --output_name Output database name (default \"rtabmap\").\n" 62 " --quiet Don't show log messages and iteration updates.\n" 63 " --exposure_comp Do exposure compensation between left and right images.\n" 64 " --disp Generate full disparity.\n" 65 " --raw Use raw images (not rectified, this only works with okvis, msckf or vins odometry).\n" 66 " --imu # IMU filter: 0=madgwick, 1=complementary (default).\n" 69 " $ rtabmap-euroc_dataset \\\n" 70 " --Rtabmap/PublishRAMUsage true\\\n" 71 " --Rtabmap/DetectionRate 2\\\n" 72 " --RGBD/LinearUpdate 0\\\n" 73 " --Mem/STMSize 30\\\n" 82 printf(
"\nSignal %d caught...\n", sig);
98 std::string outputName =
"rtabmap";
102 bool exposureCompensation =
false;
111 for(
int i=1; i<argc; ++i)
113 if(std::strcmp(argv[i],
"--output") == 0)
117 else if(std::strcmp(argv[i],
"--output_name") == 0)
119 outputName = argv[++i];
121 else if(std::strcmp(argv[i],
"--quiet") == 0)
125 else if(std::strcmp(argv[i],
"--disp") == 0)
129 else if(std::strcmp(argv[i],
"--raw") == 0)
133 else if(std::strcmp(argv[i],
"--imu") == 0)
135 imuFilter = atoi(argv[++i]);
137 else if(std::strcmp(argv[i],
"--exposure_comp") == 0)
139 exposureCompensation =
true;
155 parameters.insert(
ParametersPair(Parameters::kRtabmapWorkingDirectory(), output));
156 parameters.insert(
ParametersPair(Parameters::kRtabmapPublishRAMUsage(),
"true"));
159 parameters.insert(
ParametersPair(Parameters::kRtabmapImagesAlreadyRectified(),
"false"));
163 seq =
uSplit(path,
'/').back();
164 std::string pathLeftImages = path+
"/mav0/cam0/data";
165 std::string pathRightImages = path+
"/mav0/cam1/data";
166 std::string pathCalibLeft = path+
"/mav0/cam0/sensor.yaml";
167 std::string pathCalibRight = path+
"/mav0/cam1/sensor.yaml";
168 std::string pathGt = path+
"/mav0/state_groundtruth_estimate0/data.csv";
169 std::string pathImu = path+
"/mav0/imu0/data.csv";
172 UWARN(
"Ground truth file path doesn't exist: \"%s\", benchmark values won't be computed.", pathGt.c_str());
177 " Sequence number: %s\n" 178 " Sequence path: %s\n" 182 " right images: %s\n" 184 " right calib: %s\n",
189 pathLeftImages.c_str(),
190 pathRightImages.c_str(),
191 pathCalibLeft.c_str(),
192 pathCalibRight.c_str());
195 printf(
" Ground truth: %s\n", pathGt.c_str());
199 printf(
" IMU: %s\n", pathImu.c_str());
200 printf(
" IMU Filter: %d\n", imuFilter);
203 printf(
" Exposure Compensation: %s\n", exposureCompensation?
"true":
"false");
204 printf(
" Disparity: %s\n", disp?
"true":
"false");
205 printf(
" Raw images: %s\n", raw?
"true (Rtabmap/ImagesAlreadyRectified set to false)":
"false");
207 if(!parameters.empty())
209 printf(
"Parameters:\n");
210 for(ParametersMap::iterator iter=parameters.begin(); iter!=parameters.end(); ++iter)
212 printf(
" %s=%s\n", iter->first.c_str(), iter->second.c_str());
215 printf(
"RTAB-Map version: %s\n", RTABMAP_VERSION);
217 std::vector<CameraModel> models;
219 for(
int k=0; k<2; ++k)
222 std::string calibPath = k==0?pathCalibLeft:pathCalibRight;
223 YAML::Node
config = YAML::LoadFile(calibPath);
226 UERROR(
"Cannot open calibration file \"%s\"", calibPath.c_str());
230 YAML::Node T_BS = config[
"T_BS"];
231 YAML::Node data = T_BS[
"data"];
233 rateHz = config[
"rate_hz"].as<
int>();
234 YAML::Node resolution = config[
"resolution"];
235 UASSERT(resolution.size() == 2);
236 YAML::Node intrinsics = config[
"intrinsics"];
237 UASSERT(intrinsics.size() == 4);
238 YAML::Node distortion_coefficients = config[
"distortion_coefficients"];
239 UASSERT(distortion_coefficients.size() == 4 || distortion_coefficients.size() == 5 || distortion_coefficients.size() == 8);
241 cv::Mat K = cv::Mat::eye(3, 3, CV_64FC1);
242 K.at<
double>(0,0) = intrinsics[0].as<double>();
243 K.at<
double>(1,1) = intrinsics[1].as<double>();
244 K.at<
double>(0,2) = intrinsics[2].as<double>();
245 K.at<
double>(1,2) = intrinsics[3].as<double>();
246 cv::Mat R = cv::Mat::eye(3, 3, CV_64FC1);
247 cv::Mat P = cv::Mat::zeros(3, 4, CV_64FC1);
248 K.copyTo(cv::Mat(P, cv::Range(0,3), cv::Range(0,3)));
250 cv::Mat D = cv::Mat::zeros(1, distortion_coefficients.size(), CV_64FC1);
251 for(
unsigned int i=0; i<distortion_coefficients.size(); ++i)
253 D.at<
double>(i) = distortion_coefficients[i].as<double>();
256 Transform t(data[0].as<float>(), data[1].as<float>(), data[2].as<float>(), data[3].as<float>(),
257 data[4].as<float>(), data[5].as<float>(), data[6].as<float>(), data[7].as<float>(),
258 data[8].as<float>(), data[9].as<float>(), data[10].as<float>(), data[11].as<float>());
260 models.push_back(
CameraModel(outputName+
"_calib", cv::Size(resolution[0].as<int>(),resolution[1].as<int>()), K, D, R, P, t));
261 UASSERT(models.back().isValidForRectification());
264 int odomStrategy = Parameters::defaultOdomStrategy();
267 StereoCameraModel model(outputName+
"_calib", models[0], models[1], models[1].localTransform().
inverse() * models[0].localTransform());
268 if(!model.
save(output,
false))
270 UERROR(
"Could not save calibration!");
273 printf(
"Saved calibration \"%s\" to \"%s\"\n", (outputName+
"_calib").c_str(), output.c_str());
282 Transform baseToImu(0,0,1,0, 0,-1,0,0, 1,0,0,0);
289 baseToImu*models[0].localTransform()), parameters);
290 printf(
"baseToImu=%s\n", baseToImu.
prettyPrint().c_str());
291 std::cout<<
"baseToCam0:\n" << baseToImu*models[0].localTransform() << std::endl;
292 printf(
"baseToCam0=%s\n", (baseToImu*models[0].localTransform()).prettyPrint().c_str());
293 printf(
"imuToCam0=%s\n", models[0].localTransform().prettyPrint().c_str());
294 printf(
"imuToCam1=%s\n", models[1].localTransform().prettyPrint().c_str());
296 if(exposureCompensation)
309 float detectionRate = Parameters::defaultRtabmapDetectionRate();
310 bool intermediateNodes = Parameters::defaultRtabmapCreateIntermediateNodes();
311 Parameters::parse(parameters, Parameters::kRtabmapDetectionRate(), detectionRate);
312 Parameters::parse(parameters, Parameters::kRtabmapCreateIntermediateNodes(), intermediateNodes);
314 int mapUpdate = rateHz / detectionRate;
320 std::string databasePath = output+
"/"+outputName+
".db";
322 if(cameraThread.
camera()->
init(output, outputName+
"_calib"))
326 printf(
"Processing %d images...\n", totalImages);
329 odomParameters.erase(Parameters::kRtabmapPublishRAMUsage());
332 std::ifstream imu_file;
337 imu_file.open(pathImu.c_str());
338 if (!imu_file.good()) {
339 UERROR(
"no imu file found at %s",pathImu.c_str());
342 int number_of_lines = 0;
343 while (std::getline(imu_file, line))
345 printf(
"No. IMU measurements: %d\n", number_of_lines-1);
346 if (number_of_lines - 1 <= 0) {
347 UERROR(
"no imu messages present in %s", pathImu.c_str());
352 imu_file.seekg(0, std::ios::beg);
353 std::getline(imu_file, line);
357 if(seq.compare(
"MH_01_easy") == 0)
359 printf(
"MH_01_easy detected with MSCFK odometry, ignoring first moving 440 images...\n");
362 else if(seq.compare(
"MH_02_easy") == 0)
364 printf(
"MH_02_easy detected with MSCFK odometry, ignoring first moving 525 images...\n");
367 else if(seq.compare(
"MH_03_medium") == 0)
369 printf(
"MH_03_medium detected with MSCFK odometry, ignoring first moving 210 images...\n");
372 else if(seq.compare(
"MH_04_difficult") == 0)
374 printf(
"MH_04_difficult detected with MSCFK odometry, ignoring first moving 250 images...\n");
377 else if(seq.compare(
"MH_05_difficult") == 0)
379 printf(
"MH_05_difficult detected with MSCFK odometry, ignoring first moving 310 images...\n");
388 rtabmap.
init(parameters, databasePath);
397 double start = data.
stamp();
403 int odomKeyFrames = 0;
410 double t_imu = start;
413 if (!std::getline(imu_file, line)) {
414 std::cout << std::endl <<
"Finished parsing IMU." << std::endl << std::flush;
418 std::stringstream stream(line);
420 std::getline(stream, s,
',');
421 std::string nanoseconds = s.substr(s.size() - 9, 9);
422 std::string seconds = s.substr(0, s.size() - 9);
425 for (
int j = 0; j < 3; ++j) {
426 std::getline(stream, s,
',');
431 for (
int j = 0; j < 3; ++j) {
432 std::getline(stream, s,
',');
438 if (t_imu - start + 1 > 0) {
440 SensorData dataImu(
IMU(gyr, cv::Mat(3,3,CV_64FC1), acc, cv::Mat(3,3,CV_64FC1), baseToImu), 0, t_imu);
445 }
while (t_imu <= data.
stamp());
471 bool processData =
true;
472 if(iteration % mapUpdate != 0)
476 data.
setFeatures(std::vector<cv::KeyPoint>(), std::vector<cv::Point3f>(), cv::Mat());
477 processData = intermediateNodes;
479 if(covariance.empty() || odomInfo.
reg.
covariance.at<
double>(0,0) > covariance.at<
double>(0,0))
487 std::map<std::string, float> externalStats;
489 externalStats.insert(std::make_pair(
"Camera/BilateralFiltering/ms", cameraInfo.
timeBilateralFiltering*1000.0f));
490 externalStats.insert(std::make_pair(
"Camera/Capture/ms", cameraInfo.
timeCapture*1000.0f));
491 externalStats.insert(std::make_pair(
"Camera/Disparity/ms", cameraInfo.
timeDisparity*1000.0f));
492 externalStats.insert(std::make_pair(
"Camera/ImageDecimation/ms", cameraInfo.
timeImageDecimation*1000.0f));
493 externalStats.insert(std::make_pair(
"Camera/Mirroring/ms", cameraInfo.
timeMirroring*1000.0f));
495 externalStats.insert(std::make_pair(
"Camera/ScanFromDepth/ms", cameraInfo.
timeScanFromDepth*1000.0f));
496 externalStats.insert(std::make_pair(
"Camera/TotalTime/ms", cameraInfo.
timeTotal*1000.0f));
497 externalStats.insert(std::make_pair(
"Camera/UndistortDepth/ms", cameraInfo.
timeUndistortDepth*1000.0f));
499 externalStats.insert(std::make_pair(
"Odometry/LocalBundle/ms", odomInfo.
localBundleTime*1000.0f));
500 externalStats.insert(std::make_pair(
"Odometry/LocalBundleConstraints/", odomInfo.
localBundleConstraints));
501 externalStats.insert(std::make_pair(
"Odometry/LocalBundleOutliers/", odomInfo.
localBundleOutliers));
502 externalStats.insert(std::make_pair(
"Odometry/TotalTime/ms", odomInfo.
timeEstimation*1000.0f));
503 externalStats.insert(std::make_pair(
"Odometry/Registration/ms", odomInfo.
reg.
totalTime*1000.0f));
504 externalStats.insert(std::make_pair(
"Odometry/Inliers/", odomInfo.
reg.
inliers));
505 externalStats.insert(std::make_pair(
"Odometry/Features/", odomInfo.
features));
506 externalStats.insert(std::make_pair(
"Odometry/DistanceTravelled/m", odomInfo.
distanceTravelled));
507 externalStats.insert(std::make_pair(
"Odometry/KeyFrameAdded/", odomInfo.
keyFrameAdded));
508 externalStats.insert(std::make_pair(
"Odometry/LocalKeyFrames/", odomInfo.
localKeyFrames));
509 externalStats.insert(std::make_pair(
"Odometry/LocalMapSize/", odomInfo.
localMapSize));
510 externalStats.insert(std::make_pair(
"Odometry/LocalScanMapSize/", odomInfo.
localScanMapSize));
514 covariance = cv::Mat();
518 if(!quiet || iteration == totalImages)
520 double slamTime = timer.
ticks();
532 printf(
"Iteration %d/%d: camera=%dms, odom(quality=%f, kfs=%d)=%dms, slam=%dms, rmse=%fm",
537 printf(
"Iteration %d/%d: camera=%dms, odom(quality=%f, kfs=%d)=%dms, slam=%dms",
545 printf(
"Iteration %d/%d: camera=%dms, odom(quality=%d/%d, kfs=%d)=%dms, slam=%dms, rmse=%fm",
550 printf(
"Iteration %d/%d: camera=%dms, odom(quality=%d/%d, kfs=%d)=%dms, slam=%dms",
560 else if(iteration % (totalImages/10) == 0)
571 printf(
"Total time=%fs\n", totalTime.
ticks());
577 printf(
"Saving trajectory ...\n");
578 std::map<int, Transform> poses;
579 std::map<int, Transform> vo_poses;
580 std::multimap<int, Link> links;
581 std::map<int, Signature> signatures;
582 std::map<int, double> stamps;
583 rtabmap.
getGraph(vo_poses, links,
false,
true);
585 rtabmap.
getGraph(poses, links,
true,
true, &signatures);
586 for(std::map<int, Signature>::iterator iter=signatures.begin(); iter!=signatures.end(); ++iter)
588 stamps.insert(std::make_pair(iter->first, iter->second.getStamp()));
590 std::string pathTrajectory = output+
"/"+outputName+
"_poses.txt";
593 printf(
"Saving %s... done!\n", pathTrajectory.c_str());
597 printf(
"Saving %s... failed!\n", pathTrajectory.c_str());
603 std::map<int, Transform> groundTruth;
605 for(std::map<int, Transform>::const_iterator iter=poses.begin(); iter!=poses.end(); ++iter)
611 std::vector<float> v;
614 rtabmap.
getMemory()->
getNodeInfo(iter->first, o, m, w, l, s, gtPose, v, gps, sensors,
true);
617 groundTruth.insert(std::make_pair(iter->first, gtPose));
622 float translational_rmse = 0.0f;
623 float translational_mean = 0.0f;
624 float translational_median = 0.0f;
625 float translational_std = 0.0f;
626 float translational_min = 0.0f;
627 float translational_max = 0.0f;
628 float rotational_rmse = 0.0f;
629 float rotational_mean = 0.0f;
630 float rotational_median = 0.0f;
631 float rotational_std = 0.0f;
632 float rotational_min = 0.0f;
633 float rotational_max = 0.0f;
640 translational_median,
650 float translational_rmse_vo = translational_rmse;
651 float rotational_rmse_vo = rotational_rmse;
658 translational_median,
669 printf(
" translational_rmse= %f m (vo = %f m)\n", translational_rmse, translational_rmse_vo);
670 printf(
" rotational_rmse= %f deg (vo = %f deg)\n", rotational_rmse, rotational_rmse_vo);
673 std::string pathErrors = output+
"/"+outputName+
"_rmse.txt";
674 pFile = fopen(pathErrors.c_str(),
"w");
677 UERROR(
"could not save RMSE results to \"%s\"", pathErrors.c_str());
679 fprintf(pFile,
"Ground truth comparison:\n");
680 fprintf(pFile,
" translational_rmse= %f\n", translational_rmse);
681 fprintf(pFile,
" translational_mean= %f\n", translational_mean);
682 fprintf(pFile,
" translational_median= %f\n", translational_median);
683 fprintf(pFile,
" translational_std= %f\n", translational_std);
684 fprintf(pFile,
" translational_min= %f\n", translational_min);
685 fprintf(pFile,
" translational_max= %f\n", translational_max);
686 fprintf(pFile,
" rotational_rmse= %f\n", rotational_rmse);
687 fprintf(pFile,
" rotational_mean= %f\n", rotational_mean);
688 fprintf(pFile,
" rotational_median= %f\n", rotational_median);
689 fprintf(pFile,
" rotational_std= %f\n", rotational_std);
690 fprintf(pFile,
" rotational_min= %f\n", rotational_min);
691 fprintf(pFile,
" rotational_max= %f\n", rotational_max);
697 UERROR(
"Camera init failed!");
700 printf(
"Saving rtabmap database (with all statistics) to \"%s\"\n", (output+
"/"+outputName+
".db").c_str());
702 " $ rtabmap-databaseViewer %s\n\n", (output+
"/"+outputName+
".db").c_str());
int UTILITE_EXP uStr2Int(const std::string &str)
static std::string homeDir()
static bool parse(const ParametersMap ¶meters, const std::string &key, bool &value)
static bool makeDir(const std::string &dirPath)
void setStereoExposureCompensation(bool enabled)
double UTILITE_EXP uStr2Double(const std::string &str)
static const char * showUsage()
std::pair< std::string, std::string > ParametersPair
static ParametersMap parseArguments(int argc, char *argv[], bool onlyParameters=false)
static int erase(const std::string &filePath)
GLM_FUNC_DECL genType e()
std::map< std::string, std::string > ParametersMap
void init(const ParametersMap ¶meters, const std::string &databasePath="", bool loadDatabaseParameters=false)
const std::vector< cv::KeyPoint > & keypoints() const
Basic mathematics functions.
Some conversion functions.
const LaserScan & laserScanRaw() const
int localBundleConstraints
static void setLevel(ULogger::Level level)
Transform process(SensorData &data, OdometryInfo *info=0)
void getGraph(std::map< int, Transform > &poses, std::multimap< int, Link > &constraints, bool optimized, bool global, std::map< int, Signature > *signatures=0, bool withImages=false, bool withScan=false, bool withUserData=false, bool withGrid=false, bool withWords=true, bool withGlobalDescriptors=true) const
std::list< std::string > uSplit(const std::string &str, char separator= ' ')
virtual bool init(const std::string &calibrationFolder=".", const std::string &cameraName="")=0
#define UASSERT(condition)
SensorData takeImage(CameraInfo *info=0)
Wrappers of STL for convenient functions.
const std::map< std::string, float > & data() const
float timeStereoExposureCompensation
static Odometry * create(const ParametersMap ¶meters=ParametersMap())
bool getNodeInfo(int signatureId, Transform &odomPose, int &mapId, int &weight, std::string &label, double &stamp, Transform &groundTruth, std::vector< float > &velocity, GPS &gps, EnvSensors &sensors, bool lookInDatabase=false) const
int getLoopClosureId() const
Transform RTABMAP_EXP calcRMSE(const std::map< int, Transform > &groundTruth, const std::map< int, Transform > &poses, float &translational_rmse, float &translational_mean, float &translational_median, float &translational_std, float &translational_min, float &translational_max, float &rotational_rmse, float &rotational_mean, float &rotational_median, float &rotational_std, float &rotational_min, float &rotational_max)
const Statistics & getStatistics() const
static void setType(Type type, const std::string &fileName=kDefaultLogFileName, bool append=true)
bool process(const SensorData &data, Transform odomPose, const cv::Mat &odomCovariance=cv::Mat::eye(6, 6, CV_64FC1), const std::vector< float > &odomVelocity=std::vector< float >(), const std::map< std::string, float > &externalStats=std::map< std::string, float >())
Main loop of rtabmap.
std::string UTILITE_EXP uReplaceChar(const std::string &str, char before, char after)
bool save(const std::string &directory, bool ignoreStereoTransform=true) 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())
void setStereoToDepth(bool enabled)
void postUpdate(SensorData *data, CameraInfo *info=0) const
const Memory * getMemory() const
float timeImageDecimation
int main(int argc, char *argv[])
std::vector< float > velocity() const
std::map< EnvSensor::Type, EnvSensor > EnvSensors
float timeBilateralFiltering
virtual bool canProcessIMU() const
void setFeatures(const std::vector< cv::KeyPoint > &keypoints, const std::vector< cv::Point3f > &keypoints3D, const cv::Mat &descriptors)
GLM_FUNC_DECL matType< T, P > inverse(matType< T, P > const &m)
void enableIMUFiltering(int filteringStrategy=1, const ParametersMap ¶meters=ParametersMap())