mirror of
https://github.com/introlab/rtabmap.git
synced 2026-09-02 01:20:25 +08:00
0.15: statistics are now compressed in database. Eigen issue: using linear() instead of rotation() to get rotation from affine3f. Increased loading speed of statistics in DatabaseViewer. Added graph:calcRMSE().
This commit is contained in:
@@ -54,6 +54,7 @@ void showUsage()
|
||||
" Optional image_2, image_3 and velodyne folders.\n"
|
||||
" --output Output directory. By default, results are saved in \"path\".\n"
|
||||
" --gt \"path\" Ground truth path (e.g., ~/KITTI/devkit/cpp/data/odometry/poses/07.txt)\n"
|
||||
" --quiet Don't show log messages and iteration updates.\n"
|
||||
" --color Use color images for stereo (image_2 and image_3 folders).\n"
|
||||
" --disp Generate full disparity.\n"
|
||||
" --scan Include velodyne scan in node's data.\n"
|
||||
@@ -107,6 +108,7 @@ int main(int argc, char * argv[])
|
||||
int scanNormalK = 20;
|
||||
float scanNormalRadius = 0.0f;
|
||||
std::string gtPath;
|
||||
bool quiet = false;
|
||||
if(argc < 2)
|
||||
{
|
||||
showUsage();
|
||||
@@ -119,6 +121,10 @@ int main(int argc, char * argv[])
|
||||
{
|
||||
output = argv[++i];
|
||||
}
|
||||
else if(std::strcmp(argv[i], "--quiet") == 0)
|
||||
{
|
||||
quiet = true;
|
||||
}
|
||||
else if(std::strcmp(argv[i], "--map_update") == 0)
|
||||
{
|
||||
mapUpdate = atoi(argv[++i]);
|
||||
@@ -258,6 +264,7 @@ int main(int argc, char * argv[])
|
||||
printf(" %s=%s\n", iter->first.c_str(), iter->second.c_str());
|
||||
}
|
||||
}
|
||||
printf("RTAB-Map version: %s\n", RTABMAP_VERSION);
|
||||
|
||||
// convert calib.txt to rtabmap format (yaml)
|
||||
FILE * pFile = 0;
|
||||
@@ -324,6 +331,12 @@ int main(int argc, char * argv[])
|
||||
}
|
||||
printf("Saved calibration \"%s\" to \"%s\"\n", ("rtabmap_calib"+seq).c_str(), output.c_str());
|
||||
|
||||
|
||||
if(quiet)
|
||||
{
|
||||
ULogger::setLevel(ULogger::kError);
|
||||
}
|
||||
|
||||
// We use CameraThread only to use postUpdate() method
|
||||
Transform opticalRotation(0,0,1,0, -1,0,0,color?-0.06:0, 0,-1,0,0);
|
||||
CameraThread cameraThread(new
|
||||
@@ -362,6 +375,8 @@ int main(int argc, char * argv[])
|
||||
{
|
||||
int totalImages = (int)((CameraStereoImages*)cameraThread.camera())->filenames().size();
|
||||
|
||||
printf("Processing %d images...\n", totalImages);
|
||||
|
||||
OdometryF2M odom(parameters);
|
||||
Rtabmap rtabmap;
|
||||
rtabmap.init(parameters, databasePath);
|
||||
@@ -395,6 +410,8 @@ int main(int argc, char * argv[])
|
||||
OdometryInfo odomInfo;
|
||||
Transform pose = odom.process(data, &odomInfo);
|
||||
externalStats.insert(std::make_pair("Odometry/LocalBundle/ms", odomInfo.localBundleTime*1000.0f));
|
||||
externalStats.insert(std::make_pair("Odometry/LocalBundleConstraints/", odomInfo.localBundleConstraints));
|
||||
externalStats.insert(std::make_pair("Odometry/LocalBundleOutliers/", odomInfo.localBundleOutliers));
|
||||
externalStats.insert(std::make_pair("Odometry/TotalTime/ms", odomInfo.timeEstimation*1000.0f));
|
||||
float speed = 0.0f;
|
||||
if(odomInfo.interval>0.0)
|
||||
@@ -402,6 +419,11 @@ int main(int argc, char * argv[])
|
||||
externalStats.insert(std::make_pair("Odometry/Speed/kph", speed));
|
||||
externalStats.insert(std::make_pair("Odometry/Inliers/", odomInfo.reg.inliers));
|
||||
externalStats.insert(std::make_pair("Odometry/Features/", odomInfo.features));
|
||||
externalStats.insert(std::make_pair("Odometry/DistanceTravelled/m", odomInfo.distanceTravelled));
|
||||
externalStats.insert(std::make_pair("Odometry/KeyFrameAdded/", odomInfo.keyFrameAdded));
|
||||
externalStats.insert(std::make_pair("Odometry/LocalKeyFrames/", odomInfo.localKeyFrames));
|
||||
externalStats.insert(std::make_pair("Odometry/LocalMapSize/", odomInfo.localMapSize));
|
||||
externalStats.insert(std::make_pair("Odometry/LocalScanMapSize/", odomInfo.localScanMapSize));
|
||||
|
||||
bool processData = true;
|
||||
if(iteration % mapUpdate != 0)
|
||||
@@ -427,16 +449,34 @@ int main(int argc, char * argv[])
|
||||
rtabmap.process(data, pose, covariance, e.velocity(), externalStats);
|
||||
covariance = cv::Mat();
|
||||
}
|
||||
double slamTime = timer.ticks();
|
||||
|
||||
++iteration;
|
||||
printf("Iteration %d/%d: speed=%dkm/h camera=%dms, odom(quality=%d/%d)=%dms, slam=%dms",
|
||||
iteration, totalImages, int(speed), int(cameraInfo.timeTotal*1000.0f), odomInfo.reg.inliers, odomInfo.features, int(odomInfo.timeEstimation*1000.0f), int(slamTime*1000.0f));
|
||||
if(processData && rtabmap.getLoopClosureId()>0)
|
||||
if(!quiet)
|
||||
{
|
||||
printf(" *");
|
||||
double slamTime = timer.ticks();
|
||||
|
||||
float rmse = -1;
|
||||
if(rtabmap.getStatistics().data().find(Statistics::kGtTranslational_rmse()) != rtabmap.getStatistics().data().end())
|
||||
{
|
||||
rmse = rtabmap.getStatistics().data().at(Statistics::kGtTranslational_rmse());
|
||||
}
|
||||
|
||||
++iteration;
|
||||
if(rmse >= 0.0f)
|
||||
{
|
||||
printf("Iteration %d/%d: speed=%dkm/h camera=%dms, odom(quality=%d/%d)=%dms, slam=%dms, rmse=%fm",
|
||||
iteration, totalImages, int(speed), int(cameraInfo.timeTotal*1000.0f), odomInfo.reg.inliers, odomInfo.features, int(odomInfo.timeEstimation*1000.0f), int(slamTime*1000.0f), rmse);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Iteration %d/%d: speed=%dkm/h camera=%dms, odom(quality=%d/%d)=%dms, slam=%dms",
|
||||
iteration, totalImages, int(speed), int(cameraInfo.timeTotal*1000.0f), odomInfo.reg.inliers, odomInfo.features, int(odomInfo.timeEstimation*1000.0f), int(slamTime*1000.0f));
|
||||
}
|
||||
if(processData && rtabmap.getLoopClosureId()>0)
|
||||
{
|
||||
printf(" *");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
cameraInfo = CameraInfo();
|
||||
timer.restart();
|
||||
@@ -464,15 +504,9 @@ int main(int argc, char * argv[])
|
||||
|
||||
if(!gtPath.empty())
|
||||
{
|
||||
// Log ground truth statistics (in TUM's RGBD-SLAM format)
|
||||
// Log ground truth statistics
|
||||
std::map<int, Transform> groundTruth;
|
||||
|
||||
//align with ground truth for more meaningful results
|
||||
pcl::PointCloud<pcl::PointXYZ> cloud1, cloud2;
|
||||
cloud1.resize(poses.size());
|
||||
cloud2.resize(poses.size());
|
||||
int oi = 0;
|
||||
int idFirst = 0;
|
||||
for(std::map<int, Transform>::const_iterator iter=poses.begin(); iter!=poses.end(); ++iter)
|
||||
{
|
||||
Transform o, gtPose;
|
||||
@@ -485,16 +519,10 @@ int main(int argc, char * argv[])
|
||||
if(!gtPose.isNull())
|
||||
{
|
||||
groundTruth.insert(std::make_pair(iter->first, gtPose));
|
||||
if(oi==0)
|
||||
{
|
||||
idFirst = iter->first;
|
||||
}
|
||||
cloud1[oi] = pcl::PointXYZ(gtPose.x(), gtPose.y(), gtPose.z());
|
||||
cloud2[oi++] = pcl::PointXYZ(iter->second.x(), iter->second.y(), iter->second.z());
|
||||
}
|
||||
}
|
||||
|
||||
// compute KITTI statistics before aligning the poses
|
||||
// compute KITTI statistics
|
||||
float t_err = 0.0f;
|
||||
float r_err = 0.0f;
|
||||
graph::calcKittiSequenceErrors(uValues(groundTruth), uValues(poses), t_err, r_err);
|
||||
@@ -502,123 +530,59 @@ int main(int argc, char * argv[])
|
||||
printf(" KITTI t_err = %f %%\n", t_err);
|
||||
printf(" KITTI r_err = %f deg/m\n", r_err);
|
||||
|
||||
Transform t = Transform::getIdentity();
|
||||
if(oi>5)
|
||||
{
|
||||
cloud1.resize(oi);
|
||||
cloud2.resize(oi);
|
||||
|
||||
t = util3d::transformFromXYZCorrespondencesSVD(cloud2, cloud1);
|
||||
}
|
||||
else if(idFirst)
|
||||
{
|
||||
t = groundTruth.at(idFirst) * poses.at(idFirst).inverse();
|
||||
}
|
||||
if(!t.isIdentity())
|
||||
{
|
||||
for(std::map<int, Transform>::iterator iter=poses.begin(); iter!=poses.end(); ++iter)
|
||||
{
|
||||
iter->second = t * iter->second;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<float> translationalErrors(poses.size());
|
||||
std::vector<float> rotationalErrors(poses.size());
|
||||
float sumTranslationalErrors = 0.0f;
|
||||
float sumRotationalErrors = 0.0f;
|
||||
float sumSqrdTranslationalErrors = 0.0f;
|
||||
float sumSqrdRotationalErrors = 0.0f;
|
||||
float radToDegree = 180.0f / M_PI;
|
||||
// compute RMSE statistics
|
||||
float translational_rmse = 0.0f;
|
||||
float translational_mean = 0.0f;
|
||||
float translational_median = 0.0f;
|
||||
float translational_std = 0.0f;
|
||||
float translational_min = 0.0f;
|
||||
float translational_max = 0.0f;
|
||||
float rotational_rmse = 0.0f;
|
||||
float rotational_mean = 0.0f;
|
||||
float rotational_median = 0.0f;
|
||||
float rotational_std = 0.0f;
|
||||
float rotational_min = 0.0f;
|
||||
float rotational_max = 0.0f;
|
||||
oi=0;
|
||||
for(std::map<int, Transform>::iterator iter=poses.begin(); iter!=poses.end(); ++iter)
|
||||
graph::calcRMSE(
|
||||
groundTruth,
|
||||
poses,
|
||||
translational_rmse,
|
||||
translational_mean,
|
||||
translational_median,
|
||||
translational_std,
|
||||
translational_min,
|
||||
translational_max,
|
||||
rotational_rmse,
|
||||
rotational_mean,
|
||||
rotational_median,
|
||||
rotational_std,
|
||||
rotational_min,
|
||||
rotational_max);
|
||||
|
||||
printf(" translational_rmse= %f m\n", translational_rmse);
|
||||
printf(" rotational_rmse= %f deg\n", rotational_rmse);
|
||||
|
||||
pFile = 0;
|
||||
std::string pathErrors = output+"/rtabmap_rmse"+seq+".txt";
|
||||
pFile = fopen(pathErrors.c_str(),"w");
|
||||
if(!pFile)
|
||||
{
|
||||
std::map<int, Transform>::const_iterator jter = groundTruth.find(iter->first);
|
||||
if(jter!=groundTruth.end())
|
||||
{
|
||||
Eigen::Vector3f vA = iter->second.toEigen3f().rotation()*Eigen::Vector3f(1,0,0);
|
||||
Eigen::Vector3f vB = jter->second.toEigen3f().rotation()*Eigen::Vector3f(1,0,0);
|
||||
double a = pcl::getAngle3D(Eigen::Vector4f(vA[0], vA[1], vA[2], 0), Eigen::Vector4f(vB[0], vB[1], vB[2], 0));
|
||||
rotationalErrors[oi] = a*radToDegree;
|
||||
translationalErrors[oi] = iter->second.getDistance(jter->second);
|
||||
|
||||
sumTranslationalErrors+=translationalErrors[oi];
|
||||
sumSqrdTranslationalErrors+=translationalErrors[oi]*translationalErrors[oi];
|
||||
sumRotationalErrors+=rotationalErrors[oi];
|
||||
sumSqrdRotationalErrors+=rotationalErrors[oi]*rotationalErrors[oi];
|
||||
|
||||
if(oi == 0)
|
||||
{
|
||||
translational_min = translational_max = translationalErrors[oi];
|
||||
rotational_min = rotational_max = rotationalErrors[oi];
|
||||
}
|
||||
else
|
||||
{
|
||||
if(translationalErrors[oi] < translational_min)
|
||||
{
|
||||
translational_min = translationalErrors[oi];
|
||||
}
|
||||
else if(translationalErrors[oi] > translational_max)
|
||||
{
|
||||
translational_max = translationalErrors[oi];
|
||||
}
|
||||
|
||||
if(rotationalErrors[oi] < rotational_min)
|
||||
{
|
||||
rotational_min = rotationalErrors[oi];
|
||||
}
|
||||
else if(rotationalErrors[oi] > rotational_max)
|
||||
{
|
||||
rotational_max = rotationalErrors[oi];
|
||||
}
|
||||
}
|
||||
|
||||
++oi;
|
||||
}
|
||||
}
|
||||
translationalErrors.resize(oi);
|
||||
rotationalErrors.resize(oi);
|
||||
if(oi)
|
||||
{
|
||||
float total = float(oi);
|
||||
float translational_rmse = std::sqrt(sumSqrdTranslationalErrors/total);
|
||||
float translational_mean = sumTranslationalErrors/total;
|
||||
float translational_median = translationalErrors[oi/2];
|
||||
float translational_std = std::sqrt(uVariance(translationalErrors, translational_mean));
|
||||
|
||||
float rotational_rmse = std::sqrt(sumSqrdRotationalErrors/total);
|
||||
float rotational_mean = sumRotationalErrors/total;
|
||||
float rotational_median = rotationalErrors[oi/2];
|
||||
float rotational_std = std::sqrt(uVariance(rotationalErrors, rotational_mean));
|
||||
|
||||
printf(" translational_rmse= %f\n", translational_rmse);
|
||||
printf(" rotational_rmse= %f\n", rotational_rmse);
|
||||
|
||||
pFile = 0;
|
||||
std::string pathErrors = output+"/rtabmap_rmse"+seq+".txt";
|
||||
pFile = fopen(pathErrors.c_str(),"w");
|
||||
if(!pFile)
|
||||
{
|
||||
UERROR("could not save RMSE results to \"%s\"", pathErrors.c_str());
|
||||
}
|
||||
fprintf(pFile, "Ground truth comparison:\n");
|
||||
fprintf(pFile, " translational_rmse= %f\n", translational_rmse);
|
||||
fprintf(pFile, " translational_mean= %f\n", translational_mean);
|
||||
fprintf(pFile, " translational_median= %f\n", translational_median);
|
||||
fprintf(pFile, " translational_std= %f\n", translational_std);
|
||||
fprintf(pFile, " translational_min= %f\n", translational_min);
|
||||
fprintf(pFile, " translational_max= %f\n", translational_max);
|
||||
fprintf(pFile, " rotational_rmse= %f\n", rotational_rmse);
|
||||
fprintf(pFile, " rotational_mean= %f\n", rotational_mean);
|
||||
fprintf(pFile, " rotational_median= %f\n", rotational_median);
|
||||
fprintf(pFile, " rotational_std= %f\n", rotational_std);
|
||||
fprintf(pFile, " rotational_min= %f\n", rotational_min);
|
||||
fprintf(pFile, " rotational_max= %f\n", rotational_max);
|
||||
fclose(pFile);
|
||||
UERROR("could not save RMSE results to \"%s\"", pathErrors.c_str());
|
||||
}
|
||||
fprintf(pFile, "Ground truth comparison:\n");
|
||||
fprintf(pFile, " translational_rmse= %f\n", translational_rmse);
|
||||
fprintf(pFile, " translational_mean= %f\n", translational_mean);
|
||||
fprintf(pFile, " translational_median= %f\n", translational_median);
|
||||
fprintf(pFile, " translational_std= %f\n", translational_std);
|
||||
fprintf(pFile, " translational_min= %f\n", translational_min);
|
||||
fprintf(pFile, " translational_max= %f\n", translational_max);
|
||||
fprintf(pFile, " rotational_rmse= %f\n", rotational_rmse);
|
||||
fprintf(pFile, " rotational_mean= %f\n", rotational_mean);
|
||||
fprintf(pFile, " rotational_median= %f\n", rotational_median);
|
||||
fprintf(pFile, " rotational_std= %f\n", rotational_std);
|
||||
fprintf(pFile, " rotational_min= %f\n", rotational_min);
|
||||
fprintf(pFile, " rotational_max= %f\n", rotational_max);
|
||||
fclose(pFile);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -55,6 +55,7 @@ void showUsage()
|
||||
" https://gist.github.com/matlabbe/484134a2d9da8ad425362c6669824798). If \n"
|
||||
" \"groundtruth.txt\" is found in the sequence folder, they will be saved in the database.\n"
|
||||
" --output Output directory. By default, results are saved in \"path\".\n\n"
|
||||
" --quiet Don't show log messages and iteration updates.\n"
|
||||
"%s\n"
|
||||
"Example:\n\n"
|
||||
" $ rtabmap-rgbd_dataset \\\n"
|
||||
@@ -89,6 +90,7 @@ int main(int argc, char * argv[])
|
||||
ParametersMap parameters;
|
||||
std::string path;
|
||||
std::string output;
|
||||
bool quiet = false;
|
||||
if(argc < 2)
|
||||
{
|
||||
showUsage();
|
||||
@@ -101,6 +103,10 @@ int main(int argc, char * argv[])
|
||||
{
|
||||
output = argv[++i];
|
||||
}
|
||||
else if(std::strcmp(argv[i], "--quiet") == 0)
|
||||
{
|
||||
quiet = true;
|
||||
}
|
||||
}
|
||||
parameters = Parameters::parseArguments(argc, argv);
|
||||
path = argv[argc-1];
|
||||
@@ -126,6 +132,11 @@ int main(int argc, char * argv[])
|
||||
pathGt.clear();
|
||||
}
|
||||
|
||||
if(quiet)
|
||||
{
|
||||
ULogger::setLevel(ULogger::kError);
|
||||
}
|
||||
|
||||
printf("Paths:\n"
|
||||
" Dataset path: %s\n"
|
||||
" RGB path: %s\n"
|
||||
@@ -147,8 +158,9 @@ int main(int argc, char * argv[])
|
||||
printf(" %s=%s\n", iter->first.c_str(), iter->second.c_str());
|
||||
}
|
||||
}
|
||||
printf("RTAB-Map version: %s\n", RTABMAP_VERSION);
|
||||
|
||||
// setup calibraiton file
|
||||
// setup calibration file
|
||||
CameraModel model;
|
||||
std::string sequenceName = UFile(path).getName();
|
||||
Transform opticalRotation(0,0,1,0, -1,0,0,0, 0,-1,0,0);
|
||||
@@ -191,6 +203,8 @@ int main(int argc, char * argv[])
|
||||
{
|
||||
int totalImages = (int)((CameraRGBDImages*)cameraThread.camera())->filenames().size();
|
||||
|
||||
printf("Processing %d images...\n", totalImages);
|
||||
|
||||
OdometryF2M odom(parameters);
|
||||
Rtabmap rtabmap;
|
||||
rtabmap.init(parameters, databasePath);
|
||||
@@ -265,16 +279,34 @@ int main(int argc, char * argv[])
|
||||
rtabmap.process(data, pose, covariance, e.velocity(), externalStats);
|
||||
covariance = cv::Mat();
|
||||
}
|
||||
double slamTime = timer.ticks();
|
||||
|
||||
++iteration;
|
||||
printf("Iteration %d/%d: camera=%dms, odom(quality=%d/%d)=%dms, slam=%dms",
|
||||
iteration, totalImages, int(cameraInfo.timeTotal*1000.0f), odomInfo.reg.inliers, odomInfo.features, int(odomInfo.timeEstimation*1000.0f), int(slamTime*1000.0f));
|
||||
if(processData && rtabmap.getLoopClosureId()>0)
|
||||
if(!quiet)
|
||||
{
|
||||
printf(" *");
|
||||
double slamTime = timer.ticks();
|
||||
|
||||
float rmse = -1;
|
||||
if(rtabmap.getStatistics().data().find(Statistics::kGtTranslational_rmse()) != rtabmap.getStatistics().data().end())
|
||||
{
|
||||
rmse = rtabmap.getStatistics().data().at(Statistics::kGtTranslational_rmse());
|
||||
}
|
||||
|
||||
++iteration;
|
||||
if(rmse >= 0.0f)
|
||||
{
|
||||
printf("Iteration %d/%d: camera=%dms, odom(quality=%d/%d)=%dms, slam=%dms, rmse=%fm",
|
||||
iteration, totalImages, int(cameraInfo.timeTotal*1000.0f), odomInfo.reg.inliers, odomInfo.features, int(odomInfo.timeEstimation*1000.0f), int(slamTime*1000.0f), rmse);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Iteration %d/%d: camera=%dms, odom(quality=%d/%d)=%dms, slam=%dms",
|
||||
iteration, totalImages, int(cameraInfo.timeTotal*1000.0f), odomInfo.reg.inliers, odomInfo.features, int(odomInfo.timeEstimation*1000.0f), int(slamTime*1000.0f));
|
||||
}
|
||||
if(processData && rtabmap.getLoopClosureId()>0)
|
||||
{
|
||||
printf(" *");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
cameraInfo = CameraInfo();
|
||||
timer.restart();
|
||||
@@ -302,15 +334,9 @@ int main(int argc, char * argv[])
|
||||
|
||||
if(!pathGt.empty())
|
||||
{
|
||||
// Log ground truth statistics (in TUM's RGBD-SLAM format)
|
||||
// Log ground truth statistics
|
||||
std::map<int, Transform> groundTruth;
|
||||
|
||||
//align with ground truth for more meaningful results
|
||||
pcl::PointCloud<pcl::PointXYZ> cloud1, cloud2;
|
||||
cloud1.resize(poses.size());
|
||||
cloud2.resize(poses.size());
|
||||
int oi = 0;
|
||||
int idFirst = 0;
|
||||
for(std::map<int, Transform>::const_iterator iter=poses.begin(); iter!=poses.end(); ++iter)
|
||||
{
|
||||
Transform o, gtPose;
|
||||
@@ -323,132 +349,70 @@ int main(int argc, char * argv[])
|
||||
if(!gtPose.isNull())
|
||||
{
|
||||
groundTruth.insert(std::make_pair(iter->first, gtPose));
|
||||
if(oi==0)
|
||||
{
|
||||
idFirst = iter->first;
|
||||
}
|
||||
cloud1[oi] = pcl::PointXYZ(gtPose.x(), gtPose.y(), gtPose.z());
|
||||
cloud2[oi++] = pcl::PointXYZ(iter->second.x(), iter->second.y(), iter->second.z());
|
||||
}
|
||||
}
|
||||
|
||||
Transform t = Transform::getIdentity();
|
||||
if(oi>5)
|
||||
{
|
||||
cloud1.resize(oi);
|
||||
cloud2.resize(oi);
|
||||
// compute KITTI statistics
|
||||
float t_err = 0.0f;
|
||||
float r_err = 0.0f;
|
||||
graph::calcKittiSequenceErrors(uValues(groundTruth), uValues(poses), t_err, r_err);
|
||||
printf("Ground truth comparison:\n");
|
||||
printf(" KITTI t_err = %f %%\n", t_err);
|
||||
printf(" KITTI r_err = %f deg/m\n", r_err);
|
||||
|
||||
t = util3d::transformFromXYZCorrespondencesSVD(cloud2, cloud1);
|
||||
}
|
||||
else if(idFirst)
|
||||
{
|
||||
t = groundTruth.at(idFirst) * poses.at(idFirst).inverse();
|
||||
}
|
||||
if(!t.isIdentity())
|
||||
{
|
||||
for(std::map<int, Transform>::iterator iter=poses.begin(); iter!=poses.end(); ++iter)
|
||||
{
|
||||
iter->second = t * iter->second;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<float> translationalErrors(poses.size());
|
||||
std::vector<float> rotationalErrors(poses.size());
|
||||
float sumTranslationalErrors = 0.0f;
|
||||
float sumRotationalErrors = 0.0f;
|
||||
float sumSqrdTranslationalErrors = 0.0f;
|
||||
float sumSqrdRotationalErrors = 0.0f;
|
||||
float radToDegree = 180.0f / M_PI;
|
||||
// compute RMSE statistics
|
||||
float translational_rmse = 0.0f;
|
||||
float translational_mean = 0.0f;
|
||||
float translational_median = 0.0f;
|
||||
float translational_std = 0.0f;
|
||||
float translational_min = 0.0f;
|
||||
float translational_max = 0.0f;
|
||||
float rotational_rmse = 0.0f;
|
||||
float rotational_mean = 0.0f;
|
||||
float rotational_median = 0.0f;
|
||||
float rotational_std = 0.0f;
|
||||
float rotational_min = 0.0f;
|
||||
float rotational_max = 0.0f;
|
||||
oi=0;
|
||||
for(std::map<int, Transform>::iterator iter=poses.begin(); iter!=poses.end(); ++iter)
|
||||
graph::calcRMSE(
|
||||
groundTruth,
|
||||
poses,
|
||||
translational_rmse,
|
||||
translational_mean,
|
||||
translational_median,
|
||||
translational_std,
|
||||
translational_min,
|
||||
translational_max,
|
||||
rotational_rmse,
|
||||
rotational_mean,
|
||||
rotational_median,
|
||||
rotational_std,
|
||||
rotational_min,
|
||||
rotational_max);
|
||||
|
||||
printf(" translational_rmse= %f m\n", translational_rmse);
|
||||
printf(" rotational_rmse= %f deg\n", rotational_rmse);
|
||||
|
||||
FILE * pFile = 0;
|
||||
std::string pathErrors = output+"/rtabmap_rmse.txt";
|
||||
pFile = fopen(pathErrors.c_str(),"w");
|
||||
if(!pFile)
|
||||
{
|
||||
std::map<int, Transform>::const_iterator jter = groundTruth.find(iter->first);
|
||||
if(jter!=groundTruth.end())
|
||||
{
|
||||
Eigen::Vector3f vA = iter->second.toEigen3f().rotation()*Eigen::Vector3f(1,0,0);
|
||||
Eigen::Vector3f vB = jter->second.toEigen3f().rotation()*Eigen::Vector3f(1,0,0);
|
||||
double a = pcl::getAngle3D(Eigen::Vector4f(vA[0], vA[1], vA[2], 0), Eigen::Vector4f(vB[0], vB[1], vB[2], 0));
|
||||
rotationalErrors[oi] = a*radToDegree;
|
||||
translationalErrors[oi] = iter->second.getDistance(jter->second);
|
||||
|
||||
sumTranslationalErrors+=translationalErrors[oi];
|
||||
sumSqrdTranslationalErrors+=translationalErrors[oi]*translationalErrors[oi];
|
||||
sumRotationalErrors+=rotationalErrors[oi];
|
||||
sumSqrdRotationalErrors+=rotationalErrors[oi]*rotationalErrors[oi];
|
||||
|
||||
if(oi == 0)
|
||||
{
|
||||
translational_min = translational_max = translationalErrors[oi];
|
||||
rotational_min = rotational_max = rotationalErrors[oi];
|
||||
}
|
||||
else
|
||||
{
|
||||
if(translationalErrors[oi] < translational_min)
|
||||
{
|
||||
translational_min = translationalErrors[oi];
|
||||
}
|
||||
else if(translationalErrors[oi] > translational_max)
|
||||
{
|
||||
translational_max = translationalErrors[oi];
|
||||
}
|
||||
|
||||
if(rotationalErrors[oi] < rotational_min)
|
||||
{
|
||||
rotational_min = rotationalErrors[oi];
|
||||
}
|
||||
else if(rotationalErrors[oi] > rotational_max)
|
||||
{
|
||||
rotational_max = rotationalErrors[oi];
|
||||
}
|
||||
}
|
||||
|
||||
++oi;
|
||||
}
|
||||
}
|
||||
translationalErrors.resize(oi);
|
||||
rotationalErrors.resize(oi);
|
||||
if(oi)
|
||||
{
|
||||
float total = float(oi);
|
||||
float translational_rmse = std::sqrt(sumSqrdTranslationalErrors/total);
|
||||
float translational_mean = sumTranslationalErrors/total;
|
||||
float translational_median = translationalErrors[oi/2];
|
||||
float translational_std = std::sqrt(uVariance(translationalErrors, translational_mean));
|
||||
|
||||
float rotational_rmse = std::sqrt(sumSqrdRotationalErrors/total);
|
||||
float rotational_mean = sumRotationalErrors/total;
|
||||
float rotational_median = rotationalErrors[oi/2];
|
||||
float rotational_std = std::sqrt(uVariance(rotationalErrors, rotational_mean));
|
||||
|
||||
printf(" translational_rmse= %f\n", translational_rmse);
|
||||
printf(" rotational_rmse= %f\n", rotational_rmse);
|
||||
|
||||
FILE * pFile = 0;
|
||||
std::string pathErrors = output+"/rtabmap_rmse.txt";
|
||||
pFile = fopen(pathErrors.c_str(),"w");
|
||||
if(!pFile)
|
||||
{
|
||||
UERROR("could not save RMSE results to \"%s\"", pathErrors.c_str());
|
||||
}
|
||||
fprintf(pFile, "Ground truth comparison:\n");
|
||||
fprintf(pFile, " translational_rmse= %f\n", translational_rmse);
|
||||
fprintf(pFile, " translational_mean= %f\n", translational_mean);
|
||||
fprintf(pFile, " translational_median= %f\n", translational_median);
|
||||
fprintf(pFile, " translational_std= %f\n", translational_std);
|
||||
fprintf(pFile, " translational_min= %f\n", translational_min);
|
||||
fprintf(pFile, " translational_max= %f\n", translational_max);
|
||||
fprintf(pFile, " rotational_rmse= %f\n", rotational_rmse);
|
||||
fprintf(pFile, " rotational_mean= %f\n", rotational_mean);
|
||||
fprintf(pFile, " rotational_median= %f\n", rotational_median);
|
||||
fprintf(pFile, " rotational_std= %f\n", rotational_std);
|
||||
fprintf(pFile, " rotational_min= %f\n", rotational_min);
|
||||
fprintf(pFile, " rotational_max= %f\n", rotational_max);
|
||||
fclose(pFile);
|
||||
UERROR("could not save RMSE results to \"%s\"", pathErrors.c_str());
|
||||
}
|
||||
fprintf(pFile, "Ground truth comparison:\n");
|
||||
fprintf(pFile, " translational_rmse= %f\n", translational_rmse);
|
||||
fprintf(pFile, " translational_mean= %f\n", translational_mean);
|
||||
fprintf(pFile, " translational_median= %f\n", translational_median);
|
||||
fprintf(pFile, " translational_std= %f\n", translational_std);
|
||||
fprintf(pFile, " translational_min= %f\n", translational_min);
|
||||
fprintf(pFile, " translational_max= %f\n", translational_max);
|
||||
fprintf(pFile, " rotational_rmse= %f\n", rotational_rmse);
|
||||
fprintf(pFile, " rotational_mean= %f\n", rotational_mean);
|
||||
fprintf(pFile, " rotational_median= %f\n", rotational_median);
|
||||
fprintf(pFile, " rotational_std= %f\n", rotational_std);
|
||||
fprintf(pFile, " rotational_min= %f\n", rotational_min);
|
||||
fprintf(pFile, " rotational_max= %f\n", rotational_max);
|
||||
fclose(pFile);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user