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();
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);
416 std::getline(stream, s,
',');
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) {
422 std::getline(stream, s,
',');
427 for (
int j = 0; j < 3; ++j) {
428 std::getline(stream, s,
',');
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));
490 externalStats.insert(std::make_pair(
"Camera/ScanFromDepth/ms", cameraInfo.
timeScanFromDepth*1000.0f));
491 externalStats.insert(std::make_pair(
"Camera/TotalTime/ms", cameraInfo.
timeTotal*1000.0f));
492 externalStats.insert(std::make_pair(
"Camera/UndistortDepth/ms", cameraInfo.
timeUndistortDepth*1000.0f));
494 externalStats.insert(std::make_pair(
"Odometry/LocalBundle/ms", odomInfo.
localBundleTime*1000.0f));
495 externalStats.insert(std::make_pair(
"Odometry/LocalBundleConstraints/", odomInfo.
localBundleConstraints));
496 externalStats.insert(std::make_pair(
"Odometry/LocalBundleOutliers/", odomInfo.
localBundleOutliers));
497 externalStats.insert(std::make_pair(
"Odometry/TotalTime/ms", odomInfo.
timeEstimation*1000.0f));
498 externalStats.insert(std::make_pair(
"Odometry/Registration/ms", odomInfo.
reg.
totalTime*1000.0f));
499 externalStats.insert(std::make_pair(
"Odometry/Inliers/", odomInfo.
reg.
inliers));
500 externalStats.insert(std::make_pair(
"Odometry/Features/", odomInfo.
features));
501 externalStats.insert(std::make_pair(
"Odometry/DistanceTravelled/m", odomInfo.
distanceTravelled));
502 externalStats.insert(std::make_pair(
"Odometry/KeyFrameAdded/", odomInfo.
keyFrameAdded));
503 externalStats.insert(std::make_pair(
"Odometry/LocalKeyFrames/", odomInfo.
localKeyFrames));
504 externalStats.insert(std::make_pair(
"Odometry/LocalMapSize/", odomInfo.
localMapSize));
505 externalStats.insert(std::make_pair(
"Odometry/LocalScanMapSize/", odomInfo.
localScanMapSize));
509 covariance = cv::Mat();
513 if(!quiet || iteration == totalImages)
515 double slamTime = timer.
ticks();
527 printf(
"Iteration %d/%d: camera=%dms, odom(quality=%f, kfs=%d)=%dms, slam=%dms, rmse=%fm",
532 printf(
"Iteration %d/%d: camera=%dms, odom(quality=%f, kfs=%d)=%dms, slam=%dms",
540 printf(
"Iteration %d/%d: camera=%dms, odom(quality=%d/%d, kfs=%d)=%dms, slam=%dms, rmse=%fm",
545 printf(
"Iteration %d/%d: camera=%dms, odom(quality=%d/%d, kfs=%d)=%dms, slam=%dms",
555 else if(iteration % (totalImages/10) == 0)
566 printf(
"Total time=%fs\n", totalTime.
ticks());
572 printf(
"Saving trajectory ...\n");
573 std::map<int, Transform> poses;
574 std::map<int, Transform> vo_poses;
575 std::multimap<int, Link> links;
576 std::map<int, Signature> signatures;
577 std::map<int, double> stamps;
578 rtabmap.
getGraph(vo_poses, links,
false,
true);
580 rtabmap.
getGraph(poses, links,
true,
true, &signatures);
581 for(std::map<int, Signature>::iterator iter=signatures.begin(); iter!=signatures.end(); ++iter)
583 stamps.insert(std::make_pair(iter->first, iter->second.getStamp()));
585 std::string pathTrajectory = output+
"/"+outputName+
"_poses.txt";
588 printf(
"Saving %s... done!\n", pathTrajectory.c_str());
592 printf(
"Saving %s... failed!\n", pathTrajectory.c_str());
598 std::map<int, Transform> groundTruth;
600 for(std::map<int, Transform>::const_iterator iter=poses.begin(); iter!=poses.end(); ++iter)
606 std::vector<float> v;
609 rtabmap.
getMemory()->
getNodeInfo(iter->first, o, m, w, l, s, gtPose, v, gps, sensors,
true);
612 groundTruth.insert(std::make_pair(iter->first, gtPose));
617 float translational_rmse = 0.0f;
618 float translational_mean = 0.0f;
619 float translational_median = 0.0f;
620 float translational_std = 0.0f;
621 float translational_min = 0.0f;
622 float translational_max = 0.0f;
623 float rotational_rmse = 0.0f;
624 float rotational_mean = 0.0f;
625 float rotational_median = 0.0f;
626 float rotational_std = 0.0f;
627 float rotational_min = 0.0f;
628 float rotational_max = 0.0f;
635 translational_median,
645 float translational_rmse_vo = translational_rmse;
646 float rotational_rmse_vo = rotational_rmse;
653 translational_median,
664 printf(
" translational_rmse= %f m (vo = %f m)\n", translational_rmse, translational_rmse_vo);
665 printf(
" rotational_rmse= %f deg (vo = %f deg)\n", rotational_rmse, rotational_rmse_vo);
668 std::string pathErrors = output+
"/"+outputName+
"_rmse.txt";
669 pFile = fopen(pathErrors.c_str(),
"w");
672 UERROR(
"could not save RMSE results to \"%s\"", pathErrors.c_str());
674 fprintf(pFile,
"Ground truth comparison:\n");
675 fprintf(pFile,
" translational_rmse= %f\n", translational_rmse);
676 fprintf(pFile,
" translational_mean= %f\n", translational_mean);
677 fprintf(pFile,
" translational_median= %f\n", translational_median);
678 fprintf(pFile,
" translational_std= %f\n", translational_std);
679 fprintf(pFile,
" translational_min= %f\n", translational_min);
680 fprintf(pFile,
" translational_max= %f\n", translational_max);
681 fprintf(pFile,
" rotational_rmse= %f\n", rotational_rmse);
682 fprintf(pFile,
" rotational_mean= %f\n", rotational_mean);
683 fprintf(pFile,
" rotational_median= %f\n", rotational_median);
684 fprintf(pFile,
" rotational_std= %f\n", rotational_std);
685 fprintf(pFile,
" rotational_min= %f\n", rotational_min);
686 fprintf(pFile,
" rotational_max= %f\n", rotational_max);
692 UERROR(
"Camera init failed!");
695 printf(
"Saving rtabmap database (with all statistics) to \"%s\"\n", (output+
"/"+outputName+
".db").c_str());
697 " $ rtabmap-databaseViewer %s\n\n", (output+
"/"+outputName+
".db").c_str());
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 UTILITE_EXP uStr2Int(const std::string &str)
static std::string homeDir()
bool save(const std::string &directory, bool ignoreStereoTransform=true) const
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()
const Statistics & getStatistics() const
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
void init(const ParametersMap ¶meters, const std::string &databasePath="", bool loadDatabaseParameters=false)
Basic mathematics functions.
Some conversion functions.
int localBundleConstraints
static void setLevel(ULogger::Level level)
static Transform opticalRotation()
Transform process(SensorData &data, OdometryInfo *info=0)
const std::map< std::string, float > & data() const
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.
std::list< std::string > uSplit(const std::string &str, char separator=' ')
float timeStereoExposureCompensation
static Odometry * create(const ParametersMap ¶meters=ParametersMap())
const Memory * getMemory() const
void enableIMUFiltering(int filteringStrategy=1, const ParametersMap ¶meters=ParametersMap(), bool baseFrameConversion=false)
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)
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 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())
std::vector< float > velocity() const
void postUpdate(SensorData *data, CameraInfo *info=0) const
void setStereoToDepth(bool enabled)
const LaserScan & laserScanRaw() const
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
float timeImageDecimation
int main(int argc, char *argv[])
std::map< EnvSensor::Type, EnvSensor > EnvSensors
float timeBilateralFiltering
void setFeatures(const std::vector< cv::KeyPoint > &keypoints, const std::vector< cv::Point3f > &keypoints3D, const cv::Mat &descriptors)
int getLoopClosureId() const
GLM_FUNC_DECL matType< T, P > inverse(matType< T, P > const &m)