44 #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"));
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>();
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();
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);
290 printf(
"baseToImu=%s\n", baseToImu.
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;
336 imu_file.open(pathImu.c_str());
337 if (!imu_file.good()) {
338 UERROR(
"no imu file found at %s",pathImu.c_str());
341 int number_of_lines = 0;
342 while (std::getline(imu_file, line))
344 printf(
"No. IMU measurements: %d\n", number_of_lines-1);
345 if (number_of_lines - 1 <= 0) {
346 UERROR(
"no imu messages present in %s", pathImu.c_str());
351 imu_file.seekg(0, std::ios::beg);
352 std::getline(imu_file, line);
356 if(
seq.compare(
"MH_01_easy") == 0)
358 printf(
"MH_01_easy detected with MSCFK odometry, ignoring first moving 440 images...\n");
361 else if(
seq.compare(
"MH_02_easy") == 0)
363 printf(
"MH_02_easy detected with MSCFK odometry, ignoring first moving 525 images...\n");
366 else if(
seq.compare(
"MH_03_medium") == 0)
368 printf(
"MH_03_medium detected with MSCFK odometry, ignoring first moving 210 images...\n");
371 else if(
seq.compare(
"MH_04_difficult") == 0)
373 printf(
"MH_04_difficult detected with MSCFK odometry, ignoring first moving 250 images...\n");
376 else if(
seq.compare(
"MH_05_difficult") == 0)
378 printf(
"MH_05_difficult detected with MSCFK odometry, ignoring first moving 310 images...\n");
386 rtabmap.init(parameters, databasePath);
395 double start =
data.stamp();
401 int odomKeyFrames = 0;
406 double t_imu = start;
409 if (!std::getline(imu_file, line)) {
410 std::cout << std::endl <<
"Finished parsing IMU." << std::endl << std::flush;
414 std::stringstream
stream(line);
417 std::string nanoseconds =
s.substr(
s.size() - 9, 9);
418 std::string seconds =
s.substr(0,
s.size() - 9);
421 for (
int j = 0;
j < 3; ++
j) {
427 for (
int j = 0;
j < 3; ++
j) {
434 if (t_imu - start + 1 > 0) {
436 SensorData dataImu(
IMU(gyr, cv::Mat(3,3,CV_64FC1), acc, cv::Mat(3,3,CV_64FC1), baseToImu), 0, t_imu);
441 }
while (t_imu <=
data.stamp());
466 bool processData =
true;
467 if(iteration % mapUpdate != 0)
471 data.setFeatures(std::vector<cv::KeyPoint>(), std::vector<cv::Point3f>(), cv::Mat());
472 processData = intermediateNodes;
474 if(covariance.empty() || odomInfo.
reg.
covariance.at<
double>(0,0) > covariance.at<
double>(0,0))
482 std::map<std::string, float> externalStats;
484 externalStats.insert(std::make_pair(
"Camera/BilateralFiltering/ms", cameraInfo.
timeBilateralFiltering*1000.0f));
485 externalStats.insert(std::make_pair(
"Camera/Capture/ms", cameraInfo.
timeCapture*1000.0f));
486 externalStats.insert(std::make_pair(
"Camera/Disparity/ms", cameraInfo.
timeDisparity*1000.0f));
487 externalStats.insert(std::make_pair(
"Camera/ImageDecimation/ms", cameraInfo.
timeImageDecimation*1000.0f));
488 externalStats.insert(std::make_pair(
"Camera/Mirroring/ms", cameraInfo.
timeMirroring*1000.0f));
491 externalStats.insert(std::make_pair(
"Camera/ScanFromDepth/ms", cameraInfo.
timeScanFromDepth*1000.0f));
492 externalStats.insert(std::make_pair(
"Camera/TotalTime/ms", cameraInfo.
timeTotal*1000.0f));
493 externalStats.insert(std::make_pair(
"Camera/UndistortDepth/ms", cameraInfo.
timeUndistortDepth*1000.0f));
495 externalStats.insert(std::make_pair(
"Odometry/LocalBundle/ms", odomInfo.
localBundleTime*1000.0f));
496 externalStats.insert(std::make_pair(
"Odometry/LocalBundleConstraints/", odomInfo.
localBundleConstraints));
497 externalStats.insert(std::make_pair(
"Odometry/LocalBundleOutliers/", odomInfo.
localBundleOutliers));
498 externalStats.insert(std::make_pair(
"Odometry/TotalTime/ms", odomInfo.
timeEstimation*1000.0f));
499 externalStats.insert(std::make_pair(
"Odometry/Registration/ms", odomInfo.
reg.
totalTime*1000.0f));
500 externalStats.insert(std::make_pair(
"Odometry/Inliers/", odomInfo.
reg.
inliers));
501 externalStats.insert(std::make_pair(
"Odometry/Features/", odomInfo.
features));
502 externalStats.insert(std::make_pair(
"Odometry/DistanceTravelled/m", odomInfo.
distanceTravelled));
503 externalStats.insert(std::make_pair(
"Odometry/KeyFrameAdded/", odomInfo.
keyFrameAdded));
504 externalStats.insert(std::make_pair(
"Odometry/LocalKeyFrames/", odomInfo.
localKeyFrames));
505 externalStats.insert(std::make_pair(
"Odometry/LocalMapSize/", odomInfo.
localMapSize));
506 externalStats.insert(std::make_pair(
"Odometry/LocalScanMapSize/", odomInfo.
localScanMapSize));
509 rtabmap.process(
data, pose, covariance,
e.velocity(), externalStats);
510 covariance = cv::Mat();
514 if(!quiet || iteration == totalImages)
516 double slamTime =
timer.ticks();
519 if(
rtabmap.getStatistics().data().find(Statistics::kGtTranslational_rmse()) !=
rtabmap.getStatistics().data().end())
521 rmse =
rtabmap.getStatistics().data().at(Statistics::kGtTranslational_rmse());
524 if(
data.keypoints().size() == 0 &&
data.laserScanRaw().size())
528 printf(
"Iteration %d/%d: camera=%dms, odom(quality=%f, kfs=%d)=%dms, slam=%dms, rmse=%fm",
533 printf(
"Iteration %d/%d: camera=%dms, odom(quality=%f, kfs=%d)=%dms, slam=%dms",
541 printf(
"Iteration %d/%d: camera=%dms, odom(quality=%d/%d, kfs=%d)=%dms, slam=%dms, rmse=%fm",
546 printf(
"Iteration %d/%d: camera=%dms, odom(quality=%d/%d, kfs=%d)=%dms, slam=%dms",
550 if(processData &&
rtabmap.getLoopClosureId()>0)
556 else if(iteration % (totalImages/10) == 0)
567 printf(
"Total time=%fs\n", totalTime.
ticks());
573 printf(
"Saving trajectory ...\n");
574 std::map<int, Transform> poses;
575 std::map<int, Transform> vo_poses;
576 std::multimap<int, Link> links;
577 std::map<int, Signature> signatures;
578 std::map<int, double> stamps;
579 rtabmap.getGraph(vo_poses, links,
false,
true);
581 rtabmap.getGraph(poses, links,
true,
true, &signatures);
582 for(std::map<int, Signature>::iterator
iter=signatures.begin();
iter!=signatures.end(); ++
iter)
584 stamps.insert(std::make_pair(
iter->first,
iter->second.getStamp()));
586 std::string pathTrajectory = output+
"/"+outputName+
"_poses.txt";
589 printf(
"Saving %s... done!\n", pathTrajectory.c_str());
593 printf(
"Saving %s... failed!\n", pathTrajectory.c_str());
599 std::map<int, Transform> groundTruth;
601 for(std::map<int, Transform>::const_iterator
iter=poses.begin();
iter!=poses.end(); ++
iter)
607 std::vector<float>
v;
610 rtabmap.getMemory()->getNodeInfo(
iter->first, o,
m,
w, l,
s, gtPose,
v, gps, sensors,
true);
613 groundTruth.insert(std::make_pair(
iter->first, gtPose));
618 float translational_rmse = 0.0f;
619 float translational_mean = 0.0f;
620 float translational_median = 0.0f;
621 float translational_std = 0.0f;
622 float translational_min = 0.0f;
623 float translational_max = 0.0f;
624 float rotational_rmse = 0.0f;
625 float rotational_mean = 0.0f;
626 float rotational_median = 0.0f;
627 float rotational_std = 0.0f;
628 float rotational_min = 0.0f;
629 float rotational_max = 0.0f;
636 translational_median,
646 float translational_rmse_vo = translational_rmse;
647 float rotational_rmse_vo = rotational_rmse;
654 translational_median,
665 printf(
" translational_rmse= %f m (vo = %f m)\n", translational_rmse, translational_rmse_vo);
666 printf(
" rotational_rmse= %f deg (vo = %f deg)\n", rotational_rmse, rotational_rmse_vo);
669 std::string pathErrors = output+
"/"+outputName+
"_rmse.txt";
670 pFile = fopen(pathErrors.c_str(),
"w");
673 UERROR(
"could not save RMSE results to \"%s\"", pathErrors.c_str());
675 fprintf(pFile,
"Ground truth comparison:\n");
676 fprintf(pFile,
" translational_rmse= %f\n", translational_rmse);
677 fprintf(pFile,
" translational_mean= %f\n", translational_mean);
678 fprintf(pFile,
" translational_median= %f\n", translational_median);
679 fprintf(pFile,
" translational_std= %f\n", translational_std);
680 fprintf(pFile,
" translational_min= %f\n", translational_min);
681 fprintf(pFile,
" translational_max= %f\n", translational_max);
682 fprintf(pFile,
" rotational_rmse= %f\n", rotational_rmse);
683 fprintf(pFile,
" rotational_mean= %f\n", rotational_mean);
684 fprintf(pFile,
" rotational_median= %f\n", rotational_median);
685 fprintf(pFile,
" rotational_std= %f\n", rotational_std);
686 fprintf(pFile,
" rotational_min= %f\n", rotational_min);
687 fprintf(pFile,
" rotational_max= %f\n", rotational_max);
693 UERROR(
"Camera init failed!");
696 printf(
"Saving rtabmap database (with all statistics) to \"%s\"\n", (output+
"/"+outputName+
".db").
c_str());
698 " $ rtabmap-databaseViewer %s\n\n", (output+
"/"+outputName+
".db").
c_str());