44 #include <pcl/common/common.h> 45 #include <yaml-cpp/yaml.h> 55 "rtabmap-kitti_dataset [options] path\n" 56 " path Folder of the sequence (e.g., \"~/EuRoC/V1_03_difficult\")\n" 57 " containing least mav0/cam0/sensor.yaml, mav0/cam1/sensor.yaml and \n" 58 " mav0/cam0/data and mav0/cam1/data folders.\n" 59 " --output Output directory. By default, results are saved in \"path\".\n" 60 " --output_name Output database name (default \"rtabmap\").\n" 61 " --quiet Don't show log messages and iteration updates.\n" 62 " --exposure_comp Do exposure compensation between left and right images.\n" 63 " --disp Generate full disparity.\n" 64 " --raw Use raw images (not rectified, this only works with okvis and msckf odometry).\n" 67 " $ rtabmap-euroc_dataset \\\n" 68 " --Rtabmap/PublishRAMUsage true\\\n" 69 " --Rtabmap/DetectionRate 2\\\n" 70 " --RGBD/LinearUpdate 0\\\n" 71 " --Mem/STMSize 30\\\n" 80 printf(
"\nSignal %d caught...\n", sig);
84 int main(
int argc,
char * argv[])
96 std::string outputName =
"rtabmap";
100 bool exposureCompensation =
false;
108 for(
int i=1; i<argc; ++i)
110 if(std::strcmp(argv[i],
"--output") == 0)
114 else if(std::strcmp(argv[i],
"--output_name") == 0)
116 outputName = argv[++i];
118 else if(std::strcmp(argv[i],
"--quiet") == 0)
122 else if(std::strcmp(argv[i],
"--disp") == 0)
126 else if(std::strcmp(argv[i],
"--raw") == 0)
130 else if(std::strcmp(argv[i],
"--exposure_comp") == 0)
132 exposureCompensation =
true;
148 parameters.insert(
ParametersPair(Parameters::kRtabmapWorkingDirectory(), output));
149 parameters.insert(
ParametersPair(Parameters::kRtabmapPublishRAMUsage(),
"true"));
152 parameters.insert(
ParametersPair(Parameters::kRtabmapImagesAlreadyRectified(),
"false"));
156 seq =
uSplit(path,
'/').back();
157 std::string pathLeftImages = path+
"/mav0/cam0/data";
158 std::string pathRightImages = path+
"/mav0/cam1/data";
159 std::string pathCalibLeft = path+
"/mav0/cam0/sensor.yaml";
160 std::string pathCalibRight = path+
"/mav0/cam1/sensor.yaml";
161 std::string pathGt = path+
"/mav0/state_groundtruth_estimate0/data.csv";
162 std::string pathImu = path+
"/mav0/imu0/data.csv";
165 UWARN(
"Ground truth file path doesn't exist: \"%s\", benchmark values won't be computed.", pathGt.c_str());
170 " Sequence number: %s\n" 171 " Sequence path: %s\n" 175 " right images: %s\n" 177 " right calib: %s\n",
182 pathLeftImages.c_str(),
183 pathRightImages.c_str(),
184 pathCalibLeft.c_str(),
185 pathCalibRight.c_str());
188 printf(
" Ground truth: %s\n", pathGt.c_str());
192 printf(
" IMU: %s\n", pathImu.c_str());
195 printf(
" Exposure Compensation: %s\n", exposureCompensation?
"true":
"false");
196 printf(
" Disparity: %s\n", disp?
"true":
"false");
197 printf(
" Raw images: %s\n", raw?
"true (Rtabmap/ImagesAlreadyRectified set to false)":
"false");
199 if(!parameters.empty())
201 printf(
"Parameters:\n");
202 for(ParametersMap::iterator iter=parameters.begin(); iter!=parameters.end(); ++iter)
204 printf(
" %s=%s\n", iter->first.c_str(), iter->second.c_str());
207 printf(
"RTAB-Map version: %s\n", RTABMAP_VERSION);
209 std::vector<CameraModel> models;
211 for(
int k=0; k<2; ++k)
214 std::string calibPath = k==0?pathCalibLeft:pathCalibRight;
215 YAML::Node
config = YAML::LoadFile(calibPath);
218 UERROR(
"Cannot open calibration file \"%s\"", calibPath.c_str());
222 YAML::Node T_BS = config[
"T_BS"];
223 YAML::Node data = T_BS[
"data"];
225 rateHz = config[
"rate_hz"].as<
int>();
226 YAML::Node resolution = config[
"resolution"];
227 UASSERT(resolution.size() == 2);
228 YAML::Node intrinsics = config[
"intrinsics"];
229 UASSERT(intrinsics.size() == 4);
230 YAML::Node distortion_coefficients = config[
"distortion_coefficients"];
231 UASSERT(distortion_coefficients.size() == 4 || distortion_coefficients.size() == 5 || distortion_coefficients.size() == 8);
233 cv::Mat K = cv::Mat::eye(3, 3, CV_64FC1);
234 K.at<
double>(0,0) = intrinsics[0].as<double>();
235 K.at<
double>(1,1) = intrinsics[1].as<double>();
236 K.at<
double>(0,2) = intrinsics[2].as<double>();
237 K.at<
double>(1,2) = intrinsics[3].as<double>();
238 cv::Mat R = cv::Mat::eye(3, 3, CV_64FC1);
239 cv::Mat P = cv::Mat::zeros(3, 4, CV_64FC1);
240 K.copyTo(cv::Mat(P, cv::Range(0,3), cv::Range(0,3)));
242 cv::Mat D = cv::Mat::zeros(1, distortion_coefficients.size(), CV_64FC1);
243 for(
unsigned int i=0; i<distortion_coefficients.size(); ++i)
245 D.at<
double>(i) = distortion_coefficients[i].as<double>();
248 Transform t(data[0].as<float>(), data[1].as<float>(), data[2].as<float>(), data[3].as<float>(),
249 data[4].as<float>(), data[5].as<float>(), data[6].as<float>(), data[7].as<float>(),
250 data[8].as<float>(), data[9].as<float>(), data[10].as<float>(), data[11].as<float>());
252 models.push_back(
CameraModel(outputName+
"_calib", cv::Size(resolution[0].as<int>(),resolution[1].as<int>()), K, D, R, P, t));
253 UASSERT(models.back().isValidForRectification());
256 StereoCameraModel model(outputName+
"_calib", models[0], models[1], models[1].localTransform().
inverse() * models[0].localTransform());
257 if(!model.save(output,
false))
259 UERROR(
"Could not save calibration!");
262 printf(
"Saved calibration \"%s\" to \"%s\"\n", (outputName+
"_calib").c_str(), output.c_str());
271 Transform baseToImu(0,0,1,0, 0,-1,0,0, 1,0,0,0);
278 baseToImu*models[0].localTransform()), parameters);
279 printf(
"baseToImu=%s\n", baseToImu.
prettyPrint().c_str());
280 std::cout<<
"baseToCam0:\n" << baseToImu*models[0].localTransform() << std::endl;
281 printf(
"baseToCam0=%s\n", (baseToImu*models[0].localTransform()).prettyPrint().c_str());
282 printf(
"imuToCam0=%s\n", models[0].localTransform().prettyPrint().c_str());
283 printf(
"imuToCam1=%s\n", models[1].localTransform().prettyPrint().c_str());
285 if(exposureCompensation)
298 float detectionRate = Parameters::defaultRtabmapDetectionRate();
299 bool intermediateNodes = Parameters::defaultRtabmapCreateIntermediateNodes();
300 int odomStrategy = Parameters::defaultOdomStrategy();
302 Parameters::parse(parameters, Parameters::kRtabmapDetectionRate(), detectionRate);
303 Parameters::parse(parameters, Parameters::kRtabmapCreateIntermediateNodes(), intermediateNodes);
305 int mapUpdate = rateHz / detectionRate;
311 std::ifstream imu_file;
316 imu_file.open(pathImu.c_str());
317 if (!imu_file.good()) {
318 UERROR(
"no imu file found at %s",pathImu.c_str());
321 int number_of_lines = 0;
322 while (std::getline(imu_file, line))
324 printf(
"No. IMU measurements: %d\n", number_of_lines-1);
325 if (number_of_lines - 1 <= 0) {
326 UERROR(
"no imu messages present in %s", pathImu.c_str());
331 imu_file.seekg(0, std::ios::beg);
332 std::getline(imu_file, line);
336 if(seq.compare(
"MH_01_easy") == 0)
338 printf(
"MH_01_easy detected with MSCFK odometry, ignoring first moving 440 images...\n");
341 else if(seq.compare(
"MH_02_easy") == 0)
343 printf(
"MH_02_easy detected with MSCFK odometry, ignoring first moving 525 images...\n");
346 else if(seq.compare(
"MH_03_medium") == 0)
348 printf(
"MH_03_medium detected with MSCFK odometry, ignoring first moving 210 images...\n");
351 else if(seq.compare(
"MH_04_difficult") == 0)
353 printf(
"MH_04_difficult detected with MSCFK odometry, ignoring first moving 250 images...\n");
356 else if(seq.compare(
"MH_05_difficult") == 0)
358 printf(
"MH_05_difficult detected with MSCFK odometry, ignoring first moving 310 images...\n");
365 std::string databasePath = output+
"/"+outputName+
".db";
367 if(cameraThread.
camera()->
init(output, outputName+
"_calib"))
371 printf(
"Processing %d images...\n", totalImages);
374 odomParameters.erase(Parameters::kRtabmapPublishRAMUsage());
377 rtabmap.
init(parameters, databasePath);
386 double start = data.
stamp();
392 int odomKeyFrames = 0;
399 double t_imu = start;
402 if (!std::getline(imu_file, line)) {
403 std::cout << std::endl <<
"Finished parsing IMU." << std::endl << std::flush;
407 std::stringstream stream(line);
409 std::getline(stream, s,
',');
410 std::string nanoseconds = s.substr(s.size() - 9, 9);
411 std::string seconds = s.substr(0, s.size() - 9);
414 for (
int j = 0; j < 3; ++j) {
415 std::getline(stream, s,
',');
420 for (
int j = 0; j < 3; ++j) {
421 std::getline(stream, s,
',');
427 if (t_imu - start + 1 > 0) {
428 SensorData dataImu(
IMU(gyr, cv::Mat(3,3,CV_64FC1), acc, cv::Mat(3,3,CV_64FC1), baseToImu), 0, t_imu);
434 }
while (t_imu <= data.
stamp());
468 bool processData =
true;
469 if(iteration % mapUpdate != 0)
473 data.
setFeatures(std::vector<cv::KeyPoint>(), std::vector<cv::Point3f>(), cv::Mat());
474 processData = intermediateNodes;
476 if(covariance.empty() || odomInfo.
reg.
covariance.at<
double>(0,0) > covariance.at<
double>(0,0))
484 std::map<std::string, float> externalStats;
486 externalStats.insert(std::make_pair(
"Camera/BilateralFiltering/ms", cameraInfo.
timeBilateralFiltering*1000.0f));
487 externalStats.insert(std::make_pair(
"Camera/Capture/ms", cameraInfo.
timeCapture*1000.0f));
488 externalStats.insert(std::make_pair(
"Camera/Disparity/ms", cameraInfo.
timeDisparity*1000.0f));
489 externalStats.insert(std::make_pair(
"Camera/ImageDecimation/ms", cameraInfo.
timeImageDecimation*1000.0f));
490 externalStats.insert(std::make_pair(
"Camera/Mirroring/ms", cameraInfo.
timeMirroring*1000.0f));
492 externalStats.insert(std::make_pair(
"Camera/ScanFromDepth/ms", cameraInfo.
timeScanFromDepth*1000.0f));
493 externalStats.insert(std::make_pair(
"Camera/TotalTime/ms", cameraInfo.
timeTotal*1000.0f));
494 externalStats.insert(std::make_pair(
"Camera/UndistortDepth/ms", cameraInfo.
timeUndistortDepth*1000.0f));
496 externalStats.insert(std::make_pair(
"Odometry/LocalBundle/ms", odomInfo.
localBundleTime*1000.0f));
497 externalStats.insert(std::make_pair(
"Odometry/LocalBundleConstraints/", odomInfo.
localBundleConstraints));
498 externalStats.insert(std::make_pair(
"Odometry/LocalBundleOutliers/", odomInfo.
localBundleOutliers));
499 externalStats.insert(std::make_pair(
"Odometry/TotalTime/ms", odomInfo.
timeEstimation*1000.0f));
500 externalStats.insert(std::make_pair(
"Odometry/Registration/ms", odomInfo.
reg.
totalTime*1000.0f));
501 externalStats.insert(std::make_pair(
"Odometry/Inliers/", odomInfo.
reg.
inliers));
502 externalStats.insert(std::make_pair(
"Odometry/Features/", odomInfo.
features));
503 externalStats.insert(std::make_pair(
"Odometry/DistanceTravelled/m", odomInfo.
distanceTravelled));
504 externalStats.insert(std::make_pair(
"Odometry/KeyFrameAdded/", odomInfo.
keyFrameAdded));
505 externalStats.insert(std::make_pair(
"Odometry/LocalKeyFrames/", odomInfo.
localKeyFrames));
506 externalStats.insert(std::make_pair(
"Odometry/LocalMapSize/", odomInfo.
localMapSize));
507 externalStats.insert(std::make_pair(
"Odometry/LocalScanMapSize/", odomInfo.
localScanMapSize));
511 covariance = cv::Mat();
515 if(!quiet || iteration == totalImages)
517 double slamTime = timer.
ticks();
529 printf(
"Iteration %d/%d: camera=%dms, odom(quality=%f, kfs=%d)=%dms, slam=%dms, rmse=%fm",
534 printf(
"Iteration %d/%d: camera=%dms, odom(quality=%f, kfs=%d)=%dms, slam=%dms",
542 printf(
"Iteration %d/%d: camera=%dms, odom(quality=%d/%d, kfs=%d)=%dms, slam=%dms, rmse=%fm",
547 printf(
"Iteration %d/%d: camera=%dms, odom(quality=%d/%d, kfs=%d)=%dms, slam=%dms",
557 else if(iteration % (totalImages/10) == 0)
568 printf(
"Total time=%fs\n", totalTime.
ticks());
574 printf(
"Saving trajectory ...\n");
575 std::map<int, Transform> poses;
576 std::map<int, Transform> vo_poses;
577 std::multimap<int, Link> links;
578 std::map<int, Signature> signatures;
579 std::map<int, double> stamps;
580 rtabmap.
getGraph(vo_poses, links,
false,
true);
582 rtabmap.
getGraph(poses, links,
true,
true, &signatures);
583 for(std::map<int, Signature>::iterator iter=signatures.begin(); iter!=signatures.end(); ++iter)
585 stamps.insert(std::make_pair(iter->first, iter->second.getStamp()));
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;
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 def)\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());
int UTILITE_EXP uStr2Int(const std::string &str)
static std::string homeDir()
static bool parse(const ParametersMap ¶meters, const std::string &key, bool &value)
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 >(), bool g2oRobust=false)
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
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)
void getGraph(std::map< int, Transform > &poses, std::multimap< int, Link > &constraints, bool optimized, bool global, std::map< int, Signature > *signatures=0)
Transform process(SensorData &data, OdometryInfo *info=0)
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
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.
static Odometry * create(const ParametersMap ¶meters)
std::string UTILITE_EXP uReplaceChar(const std::string &str, char before, char after)
void init(const ParametersMap ¶meters, const std::string &databasePath="")
void setStereoToDepth(bool enabled)
void postUpdate(SensorData *data, CameraInfo *info=0) const
bool getNodeInfo(int signatureId, Transform &odomPose, int &mapId, int &weight, std::string &label, double &stamp, Transform &groundTruth, std::vector< float > &velocity, GPS &gps, bool lookInDatabase=false) const
const Memory * getMemory() const
float timeImageDecimation
int main(int argc, char *argv[])
std::vector< float > velocity() const
float timeBilateralFiltering
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)