42 #include <pcl/common/common.h>
52 "rtabmap-kitti_dataset [options] path\n"
53 " path Folder of the sequence (e.g., \"~/KITTI/dataset/sequences/07\")\n"
54 " containing least calib.txt, times.txt, image_0 and image_1 folders.\n"
55 " Optional image_2, image_3 and velodyne folders.\n"
56 " --output Output directory. By default, results are saved in \"path\".\n"
57 " --output_name Output database name (default \"rtabmap\").\n"
58 " --gt \"path\" Ground truth path (e.g., ~/KITTI/devkit/cpp/data/odometry/poses/07.txt)\n"
59 " --quiet Don't show log messages and iteration updates.\n"
60 " --color Use color images for stereo (image_2 and image_3 folders).\n"
61 " --height Add car's height to camera local transform (1.67m).\n"
62 " --disp Generate full disparity.\n"
63 " --exposure_comp Do exposure compensation between left and right images.\n"
64 " --scan Include velodyne scan in node's data (use --scan_only to ignore image data).\n"
65 " --scan_step # Scan downsample step (default=1).\n"
66 " --scan_voxel #.# Scan voxel size (default 0.5 m).\n"
67 " --scan_k Scan normal K (default 0).\n"
68 " --scan_radius Scan normal radius (default 0).\n\n"
71 " $ rtabmap-kitti_dataset \\\n"
72 " --Rtabmap/PublishRAMUsage true\\\n"
73 " --Rtabmap/DetectionRate 2\\\n"
74 " --Rtabmap/CreateIntermediateNodes true\\\n"
75 " --RGBD/LinearUpdate 0\\\n"
76 " --GFTT/QualityLevel 0.01\\\n"
77 " --GFTT/MinDistance 7\\\n"
78 " --OdomF2M/MaxSize 3000\\\n"
79 " --Mem/STMSize 30\\\n"
80 " --Kp/MaxFeatures 750\\\n"
81 " --Vis/MaxFeatures 1500\\\n"
82 " --gt \"~/KITTI/devkit/cpp/data/odometry/poses/07.txt\"\\\n"
91 printf(
"\nSignal %d caught...\n", sig);
107 std::string outputName =
"rtabmap";
113 bool exposureCompensation =
false;
115 float scanVoxel = 0.5f;
117 float scanNormalRadius = 0.0f;
118 bool scanOnly =
false;
127 for(
int i=1;
i<argc; ++
i)
129 if(std::strcmp(
argv[
i],
"--output") == 0)
133 else if(std::strcmp(
argv[
i],
"--output_name") == 0)
135 outputName =
argv[++
i];
137 else if(std::strcmp(
argv[
i],
"--quiet") == 0)
141 else if(std::strcmp(
argv[
i],
"--scan_step") == 0)
143 scanStep = atoi(
argv[++
i]);
146 printf(
"scan_step should be > 0\n");
150 else if(std::strcmp(
argv[
i],
"--scan_voxel") == 0)
152 scanVoxel = atof(
argv[++
i]);
155 printf(
"scan_voxel should be >= 0.0\n");
159 else if(std::strcmp(
argv[
i],
"--scan_k") == 0)
161 scanNormalK = atoi(
argv[++
i]);
164 printf(
"scanNormalK should be >= 0\n");
168 else if(std::strcmp(
argv[
i],
"--scan_radius") == 0)
170 scanNormalRadius = atof(
argv[++
i]);
171 if(scanNormalRadius < 0.0
f)
173 printf(
"scanNormalRadius should be >= 0\n");
177 else if(std::strcmp(
argv[
i],
"--scan_only") == 0)
179 scan = scanOnly =
true;
181 else if(std::strcmp(
argv[
i],
"--gt") == 0)
185 else if(std::strcmp(
argv[
i],
"--color") == 0)
189 else if(std::strcmp(
argv[
i],
"--height") == 0)
193 else if(std::strcmp(
argv[
i],
"--scan") == 0)
197 else if(std::strcmp(
argv[
i],
"--disp") == 0)
201 else if(std::strcmp(
argv[
i],
"--exposure_comp") == 0)
203 exposureCompensation =
true;
219 parameters.insert(
ParametersPair(Parameters::kRtabmapWorkingDirectory(), output));
220 parameters.insert(
ParametersPair(Parameters::kRtabmapPublishRAMUsage(),
"true"));
226 UWARN(
"Sequence number \"%s\" should be between 0 and 21 (official KITTI datasets).",
seq.c_str());
229 std::string pathLeftImages =
path+(color?
"/image_2":
"/image_0");
230 std::string pathRightImages =
path+(color?
"/image_3":
"/image_1");
231 std::string pathCalib =
path+
"/calib.txt";
232 std::string pathTimes =
path+
"/times.txt";
233 std::string pathScan;
236 " Sequence number: %s\n"
237 " Sequence path: %s\n"
241 " right images: %s\n"
248 pathLeftImages.c_str(),
249 pathRightImages.c_str(),
258 UWARN(
"Ground truth file path doesn't exist: \"%s\", benchmark values won't be computed.", gtPath.c_str());
263 printf(
" Ground Truth: %s\n", gtPath.c_str());
266 printf(
" Exposure Compensation: %s\n", exposureCompensation?
"true":
"false");
267 printf(
" Disparity: %s\n", disp?
"true":
"false");
270 pathScan =
path+
"/velodyne";
271 printf(
" Scan: %s\n", pathScan.c_str());
272 printf(
" Scan only: %s\n", scanOnly?
"true":
"false");
273 printf(
" Scan step: %d\n", scanStep);
274 printf(
" Scan voxel: %fm\n", scanVoxel);
275 printf(
" Scan normal k: %d\n", scanNormalK);
276 printf(
" Scan normal radius: %f\n", scanNormalRadius);
281 pFile = fopen(pathCalib.c_str(),
"r");
284 UERROR(
"Cannot open calibration file \"%s\"", pathCalib.c_str());
287 cv::Mat_<double>
P0(3,4);
288 cv::Mat_<double> P1(3,4);
289 cv::Mat_<double> P2(3,4);
290 cv::Mat_<double> P3(3,4);
291 if(fscanf (pFile,
"%*s %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf",
292 &
P0(0, 0), &
P0(0, 1), &
P0(0, 2), &
P0(0, 3),
293 &
P0(1, 0), &
P0(1, 1), &
P0(1, 2), &
P0(1, 3),
294 &
P0(2, 0), &
P0(2, 1), &
P0(2, 2), &
P0(2, 3)) != 12)
296 UERROR(
"Failed to parse calibration file \"%s\"", pathCalib.c_str());
299 if(fscanf (pFile,
"%*s %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf",
300 &P1(0, 0), &P1(0, 1), &P1(0, 2), &P1(0, 3),
301 &P1(1, 0), &P1(1, 1), &P1(1, 2), &P1(1, 3),
302 &P1(2, 0), &P1(2, 1), &P1(2, 2), &P1(2, 3)) != 12)
304 UERROR(
"Failed to parse calibration file \"%s\"", pathCalib.c_str());
307 if(fscanf (pFile,
"%*s %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf",
308 &P2(0, 0), &P2(0, 1), &P2(0, 2), &P2(0, 3),
309 &P2(1, 0), &P2(1, 1), &P2(1, 2), &P2(1, 3),
310 &P2(2, 0), &P2(2, 1), &P2(2, 2), &P2(2, 3)) != 12)
312 UERROR(
"Failed to parse calibration file \"%s\"", pathCalib.c_str());
315 if(fscanf (pFile,
"%*s %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf",
316 &P3(0, 0), &P3(0, 1), &P3(0, 2), &P3(0, 3),
317 &P3(1, 0), &P3(1, 1), &P3(1, 2), &P3(1, 3),
318 &P3(2, 0), &P3(2, 1), &P3(2, 2), &P3(2, 3)) != 12)
320 UERROR(
"Failed to parse calibration file \"%s\"", pathCalib.c_str());
330 UERROR(
"Failed to read first image of \"%s\"", firstImage.c_str());
335 image.size(),
P0.colRange(0,3), cv::Mat(), cv::Mat(),
P0,
336 image.size(), P1.colRange(0,3), cv::Mat(), cv::Mat(), P1,
337 cv::Mat(), cv::Mat(), cv::Mat(), cv::Mat());
338 if(!
model.save(output,
true))
340 UERROR(
"Could not save calibration!");
343 printf(
"Saved calibration \"%s\" to \"%s\"\n", (outputName+
"_calib").
c_str(), output.c_str());
345 if(!parameters.empty())
347 printf(
"Parameters:\n");
348 for(ParametersMap::iterator
iter=parameters.begin();
iter!=parameters.end(); ++
iter)
350 printf(
" %s=%s\n",
iter->first.c_str(),
iter->second.c_str());
354 printf(
"RTAB-Map version: %s\n", RTABMAP_VERSION);
362 Transform opticalRotation(0,0,1,0, -1,0,0,color?-0.06:0, 0,-1,0,height?1.67:0.0);
378 if(exposureCompensation)
390 if(!pathScan.empty())
395 Transform(-0.27
f, 0.0
f, 0.08+(height?1.67
f:0.0
f), 0.0f, 0.0f, 0.0f));
407 float detectionRate = Parameters::defaultRtabmapDetectionRate();
408 bool intermediateNodes = Parameters::defaultRtabmapCreateIntermediateNodes();
409 int odomStrategy = Parameters::defaultOdomStrategy();
411 Parameters::parse(parameters, Parameters::kRtabmapDetectionRate(), detectionRate);
412 Parameters::parse(parameters, Parameters::kRtabmapCreateIntermediateNodes(), intermediateNodes);
415 int mapUpdate = detectionRate>0?10 / detectionRate:1;
421 std::string databasePath = output+
"/"+outputName+
".db";
423 if(cameraThread.
camera()->
init(output, outputName+
"_calib"))
427 printf(
"Processing %d images...\n", totalImages);
430 odomParameters.erase(Parameters::kRtabmapPublishRAMUsage());
433 rtabmap.init(parameters, databasePath);
445 int odomKeyFrames = 0;
462 if(odomStrategy == 2)
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));
496 externalStats.insert(std::make_pair(
"Camera/ScanFromDepth/ms", cameraInfo.
timeScanFromDepth*1000.0f));
497 externalStats.insert(std::make_pair(
"Camera/TotalTime/ms", cameraInfo.
timeTotal*1000.0f));
498 externalStats.insert(std::make_pair(
"Camera/UndistortDepth/ms", cameraInfo.
timeUndistortDepth*1000.0f));
500 externalStats.insert(std::make_pair(
"Odometry/LocalBundle/ms", odomInfo.
localBundleTime*1000.0f));
501 externalStats.insert(std::make_pair(
"Odometry/LocalBundleConstraints/", odomInfo.
localBundleConstraints));
502 externalStats.insert(std::make_pair(
"Odometry/LocalBundleOutliers/", odomInfo.
localBundleOutliers));
503 externalStats.insert(std::make_pair(
"Odometry/TotalTime/ms", odomInfo.
timeEstimation*1000.0f));
504 externalStats.insert(std::make_pair(
"Odometry/Registration/ms", odomInfo.
reg.
totalTime*1000.0f));
505 externalStats.insert(std::make_pair(
"Odometry/Speed/kph", speed));
506 externalStats.insert(std::make_pair(
"Odometry/Inliers/", odomInfo.
reg.
inliers));
507 externalStats.insert(std::make_pair(
"Odometry/Features/", odomInfo.
features));
508 externalStats.insert(std::make_pair(
"Odometry/DistanceTravelled/m", odomInfo.
distanceTravelled));
509 externalStats.insert(std::make_pair(
"Odometry/KeyFrameAdded/", odomInfo.
keyFrameAdded));
510 externalStats.insert(std::make_pair(
"Odometry/LocalKeyFrames/", odomInfo.
localKeyFrames));
511 externalStats.insert(std::make_pair(
"Odometry/LocalMapSize/", odomInfo.
localMapSize));
512 externalStats.insert(std::make_pair(
"Odometry/LocalScanMapSize/", odomInfo.
localScanMapSize));
515 rtabmap.process(
data, pose, covariance,
e.velocity(), externalStats);
516 covariance = cv::Mat();
520 if(!quiet || iteration == totalImages)
522 double slamTime =
timer.ticks();
525 if(
rtabmap.getStatistics().data().find(Statistics::kGtTranslational_rmse()) !=
rtabmap.getStatistics().data().end())
527 rmse =
rtabmap.getStatistics().data().at(Statistics::kGtTranslational_rmse());
530 if(
data.keypoints().size() == 0 &&
data.laserScanRaw().size())
536 printf(
"Iteration %d/%d: speed=%dkm/h camera=%dms, odom(quality=%f, kfs=%d)=%dms, slam=%dms, rmse=%fm",
541 printf(
"Iteration %d/%d: speed=%dkm/h camera=%dms, odom(quality=%f, kfs=%d)=%dms, slam=%dms",
551 printf(
"Iteration %d/%d: speed=%dkm/h camera=%dms, odom(quality=%d/%d, kfs=%d)=%dms, slam=%dms, rmse=%fm",
556 printf(
"Iteration %d/%d: speed=%dkm/h camera=%dms, odom(quality=%d/%d, kfs=%d)=%dms, slam=%dms",
560 if(processData &&
rtabmap.getLoopClosureId()>0)
566 else if(iteration % (totalImages/10) == 0)
577 printf(
"Total time=%fs\n", totalTime.
ticks());
583 printf(
"Saving trajectory ...\n");
584 std::map<int, Transform> poses;
585 std::multimap<int, Link> links;
586 rtabmap.getGraph(poses, links,
true,
true);
587 std::string pathTrajectory = output+
"/"+outputName+
"_poses.txt";
590 printf(
"Saving %s... done!\n", pathTrajectory.c_str());
594 printf(
"Saving %s... failed!\n", pathTrajectory.c_str());
600 std::map<int, Transform> groundTruth;
602 for(std::map<int, Transform>::const_iterator
iter=poses.begin();
iter!=poses.end(); ++
iter)
608 std::vector<float>
v;
611 rtabmap.getMemory()->getNodeInfo(
iter->first, o,
m,
w, l,
s, gtPose,
v, gps, sensors,
true);
614 groundTruth.insert(std::make_pair(
iter->first, gtPose));
622 printf(
"Ground truth comparison:\n");
623 printf(
" KITTI t_err = %f %%\n", t_err);
624 printf(
" KITTI r_err = %f deg/m\n", r_err);
627 float translational_rmse = 0.0f;
628 float translational_mean = 0.0f;
629 float translational_median = 0.0f;
630 float translational_std = 0.0f;
631 float translational_min = 0.0f;
632 float translational_max = 0.0f;
633 float rotational_rmse = 0.0f;
634 float rotational_mean = 0.0f;
635 float rotational_median = 0.0f;
636 float rotational_std = 0.0f;
637 float rotational_min = 0.0f;
638 float rotational_max = 0.0f;
644 translational_median,
655 printf(
" translational_rmse= %f m\n", translational_rmse);
656 printf(
" rotational_rmse= %f deg\n", rotational_rmse);
659 std::string pathErrors = output+
"/"+outputName+
"_rmse.txt";
660 pFile = fopen(pathErrors.c_str(),
"w");
663 UERROR(
"could not save RMSE results to \"%s\"", pathErrors.c_str());
665 fprintf(pFile,
"Ground truth comparison:\n");
666 fprintf(pFile,
" KITTI t_err = %f %%\n", t_err);
667 fprintf(pFile,
" KITTI r_err = %f deg/m\n", r_err);
668 fprintf(pFile,
" translational_rmse= %f\n", translational_rmse);
669 fprintf(pFile,
" translational_mean= %f\n", translational_mean);
670 fprintf(pFile,
" translational_median= %f\n", translational_median);
671 fprintf(pFile,
" translational_std= %f\n", translational_std);
672 fprintf(pFile,
" translational_min= %f\n", translational_min);
673 fprintf(pFile,
" translational_max= %f\n", translational_max);
674 fprintf(pFile,
" rotational_rmse= %f\n", rotational_rmse);
675 fprintf(pFile,
" rotational_mean= %f\n", rotational_mean);
676 fprintf(pFile,
" rotational_median= %f\n", rotational_median);
677 fprintf(pFile,
" rotational_std= %f\n", rotational_std);
678 fprintf(pFile,
" rotational_min= %f\n", rotational_min);
679 fprintf(pFile,
" rotational_max= %f\n", rotational_max);
685 UERROR(
"Camera init failed!");
688 printf(
"Saving rtabmap database (with all statistics) to \"%s\"\n", (output+
"/"+outputName+
".db").
c_str());
690 " $ rtabmap-databaseViewer %s\n\n", (output+
"/"+outputName+
".db").
c_str());