Added Ground truth import GPS format. Alignement between estimated and ground truth poses is done with SVD.

This commit is contained in:
matlabbe
2016-01-15 17:05:55 -05:00
parent 2d6965aa4b
commit 35b722ba08
9 changed files with 175 additions and 63 deletions

View File

@@ -293,19 +293,19 @@ bool CameraImages::init(const std::string & calibrationFolder, const std::string
UERROR("Cannot read ground truth file \"%s\".", groundTruthPath_.c_str());
success = false;
}
else if(_groundTruthFormat != 1 && poses.size() != this->imagesCount())
else if((_groundTruthFormat != 1 && _groundTruthFormat != 5) && poses.size() != this->imagesCount())
{
UERROR("The ground truth count is not the same as the images (%d vs %d)! Please remove "
"the ground truth file path if you don't want to use it (current file path=%s).",
(int)poses.size(), this->imagesCount(), groundTruthPath_.c_str());
success = false;
}
else if(_groundTruthFormat == 1 && stamps_.size() == 0)
else if((_groundTruthFormat == 1 || _groundTruthFormat == 5) && stamps_.size() == 0)
{
UERROR("When using rgbd-slam format for ground truth, images must have timestamps!");
UERROR("When using RGBD-SLAM and GPS formats for ground truth, images must have timestamps!");
success = false;
}
else if(_groundTruthFormat == 1)
else if(_groundTruthFormat == 1 || _groundTruthFormat == 5)
{
UDEBUG("");
//Match ground truth values with images
@@ -317,10 +317,12 @@ bool CameraImages::init(const std::string & calibrationFolder, const std::string
}
std::vector<double> values = uValues(stamps);
int validPoses = 0;
for(std::list<double>::iterator ster=stamps_.begin(); ster!=stamps_.end(); ++ster)
{
Transform pose; // null transform
std::map<double, int>::iterator endIter = stampsToIds.lower_bound(*ster);
bool warned = false;
if(endIter != stampsToIds.end())
{
if(endIter->first == *ster)
@@ -335,21 +337,37 @@ bool CameraImages::init(const std::string & calibrationFolder, const std::string
double stampBeg = beginIter->first;
double stampEnd = endIter->first;
UASSERT(stampEnd > stampBeg && *ster>stampBeg && *ster < stampEnd);
float t = (*ster - stampBeg) / (stampEnd-stampBeg);
Transform & ta = poses.at(beginIter->second);
Transform & tb = poses.at(endIter->second);
if(!ta.isNull() && !tb.isNull())
if(stampEnd - stampBeg > 10.0)
{
pose = ta.interpolate(t, tb);
warned = true;
UDEBUG("Cannot interpolate ground truth pose for stamp %f between %f and %f (>10 sec)",
*ster,
stampBeg,
stampEnd);
}
else
{
float t = (*ster - stampBeg) / (stampEnd-stampBeg);
Transform & ta = poses.at(beginIter->second);
Transform & tb = poses.at(endIter->second);
if(!ta.isNull() && !tb.isNull())
{
++validPoses;
pose = ta.interpolate(t, tb);
}
}
}
}
if(pose.isNull())
if(pose.isNull() && !warned)
{
UWARN("Ground truth pose not found for stamp %f", *ster);
UDEBUG("Ground truth pose not found for stamp %f", *ster);
}
groundTruth_.push_back(pose);
}
if(validPoses != (int)stamps.size())
{
UWARN("%d valid ground truth poses of %d stamps", validPoses, (int)stamps_.size());
}
}
else
{

View File

@@ -153,7 +153,7 @@ bool exportPoses(
bool importPoses(
const std::string & filePath,
int format, // 0=Raw, 1=RGBD-SLAM, 2=KITTI, 3=TORO, 4=g2o
int format, // 0=Raw, 1=RGBD-SLAM, 2=KITTI, 3=TORO, 4=g2o, 5=GPS (t,x,y)
std::map<int, Transform> & poses,
std::multimap<int, Link> * constraints, // optional for formats 3 and 4
std::map<int, double> * stamps) // optional for format 1
@@ -197,7 +197,49 @@ bool importPoses(
continue;
}
if(format == 1) // rgbd-slam format
if(format == 5) // GPS format
{
std::vector<std::string> strList = uListToVector(uSplit(str));
if(strList.size() == 3 || strList.size() == 4)
{
if( uIsNumber(uReplaceChar(strList[0], ' ', "")) &&
uIsNumber(uReplaceChar(strList[1], ' ', "")) &&
uIsNumber(uReplaceChar(strList[2], ' ', "")) &&
(strList.size()==3 || uIsNumber(uReplaceChar(strList[3], ' ', ""))))
{
double stamp = uStr2Double(uReplaceChar(strList[0], ' ', ""));
double x = uStr2Double(uReplaceChar(strList[1], ' ', ""));
double y = uStr2Double(uReplaceChar(strList[2], ' ', ""));
if(stamps)
{
stamps->insert(std::make_pair(id, stamp));
}
float yaw = 0.0f;
if(strList.size()==4)
{
yaw = uStr2Double(uReplaceChar(strList[3], ' ', ""));
}
else if(uContains(poses, id-1))
{
// set yaw depending on successive poses
Transform & previousPose = poses.at(id-1);
yaw = atan2(y-previousPose.y(),x-previousPose.x());
previousPose = Transform(previousPose.x(), previousPose.y(), yaw);
}
poses.insert(std::make_pair(id, Transform(x,y,0,0,0,yaw)));
}
else
{
UDEBUG("Not valid values detected: \"%s\"", str.c_str());
}
}
else
{
UERROR("Error parsing \"%s\" with GPS format (should have 3 values: stamp x y)", str.c_str());
}
}
else if(format == 1) // rgbd-slam format
{
std::list<std::string> strList = uSplit(str);
if(strList.size() == 8)
@@ -210,21 +252,24 @@ bool importPoses(
{
UWARN("Null transform read!? line parsed: \"%s\"", str.c_str());
}
if(stamps)
else
{
stamps->insert(std::make_pair(id, stamp));
if(stamps)
{
stamps->insert(std::make_pair(id, stamp));
}
// we need to remove optical rotation
// z pointing front, x left, y down
Transform t( 0, 0, 1, 0,
-1, 0, 0, 0,
0,-1, 0, 0);
pose = t * pose * t.inverse();
t = Transform( 0, 0, 1, 0,
0, -1, 0, 0,
1, 0, 0, 0);
pose = t*pose;
poses.insert(std::make_pair(id, pose));
}
// we need to remove optical rotation
// z pointing front, x left, y down
Transform t( 0, 0, 1, 0,
-1, 0, 0, 0,
0,-1, 0, 0);
pose = t * pose * t.inverse();
t = Transform( 0, 0, 1, 0,
0, -1, 0, 0,
1, 0, 0, 0);
pose = t*pose;
poses.insert(std::make_pair(id, pose));
}
else
{

View File

@@ -33,6 +33,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <pcl/registration/icp.h>
#include <pcl/registration/transformation_estimation_2D.h>
#include <pcl/registration/transformation_estimation_svd.h>
#include <pcl/sample_consensus/sac_model_registration.h>
#include <pcl/sample_consensus/ransac.h>
#include <rtabmap/utilite/ULogger.h>
@@ -43,6 +44,19 @@ namespace rtabmap
namespace util3d
{
// Get transform from cloud2 to cloud1
Transform transformFromXYZCorrespondencesSVD(
const pcl::PointCloud<pcl::PointXYZ> & cloud1,
const pcl::PointCloud<pcl::PointXYZ> & cloud2)
{
pcl::registration::TransformationEstimationSVD<pcl::PointXYZ, pcl::PointXYZ> svd;
// Perform the alignment
Eigen::Matrix4f matrix;
svd.estimateRigidTransformation(cloud1, cloud2, matrix);
return Transform::fromEigen4f(matrix);
}
// Get transform from cloud2 to cloud1
Transform transformFromXYZCorrespondences(
const pcl::PointCloud<pcl::PointXYZ>::ConstPtr & cloud1,