mirror of
https://github.com/introlab/rtabmap_ros.git
synced 2026-10-04 08:47:45 +08:00
0.13.0 Database: Added velocity field to Node table, renamed Map_Node_Word table to Feature, added information_matrix field to Link table (replacing rot_variance and trans_variance). Added graph::calcKittiSequenceErrors().Added "Mem/IntermediateNodeDataKept" parameter (default false). Updated all interfaces using rotVariance and transVariance values with covariance matrix instead. g2o SBA: always use covariance in links. kitti-dataset tool: added --disp option and kitti statistics are shown at the end. StatsToolBox: units can have "/".
This commit is contained in:
+2
-2
@@ -20,8 +20,8 @@ SET(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake_modules")
|
|||||||
# VERSION
|
# VERSION
|
||||||
#######################
|
#######################
|
||||||
SET(RTABMAP_MAJOR_VERSION 0)
|
SET(RTABMAP_MAJOR_VERSION 0)
|
||||||
SET(RTABMAP_MINOR_VERSION 12)
|
SET(RTABMAP_MINOR_VERSION 13)
|
||||||
SET(RTABMAP_PATCH_VERSION 5)
|
SET(RTABMAP_PATCH_VERSION 0)
|
||||||
SET(RTABMAP_VERSION
|
SET(RTABMAP_VERSION
|
||||||
${RTABMAP_MAJOR_VERSION}.${RTABMAP_MINOR_VERSION}.${RTABMAP_PATCH_VERSION})
|
${RTABMAP_MAJOR_VERSION}.${RTABMAP_MINOR_VERSION}.${RTABMAP_PATCH_VERSION})
|
||||||
|
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ public:
|
|||||||
void loadNodeData(std::list<Signature *> & signatures, bool images = true, bool scan = true, bool userData = true, bool occupancyGrid = true) const;
|
void loadNodeData(std::list<Signature *> & signatures, bool images = true, bool scan = true, bool userData = true, bool occupancyGrid = true) const;
|
||||||
void getNodeData(int signatureId, SensorData & data, bool images = true, bool scan = true, bool userData = true, bool occupancyGrid = true) const;
|
void getNodeData(int signatureId, SensorData & data, bool images = true, bool scan = true, bool userData = true, bool occupancyGrid = true) const;
|
||||||
bool getCalibration(int signatureId, std::vector<CameraModel> & models, StereoCameraModel & stereoModel) const;
|
bool getCalibration(int signatureId, std::vector<CameraModel> & models, StereoCameraModel & stereoModel) const;
|
||||||
bool getNodeInfo(int signatureId, Transform & pose, int & mapId, int & weight, std::string & label, double & stamp, Transform & groundTruthPose) const;
|
bool getNodeInfo(int signatureId, Transform & pose, int & mapId, int & weight, std::string & label, double & stamp, Transform & groundTruthPose, std::vector<float> & velocity) const;
|
||||||
void loadLinks(int signatureId, std::map<int, Link> & links, Link::Type type = Link::kUndef) const;
|
void loadLinks(int signatureId, std::map<int, Link> & links, Link::Type type = Link::kUndef) const;
|
||||||
void getWeight(int signatureId, int & weight) const;
|
void getWeight(int signatureId, int & weight) const;
|
||||||
void getAllNodeIds(std::set<int> & ids, bool ignoreChildren = false, bool ignoreBadSignatures = false) const;
|
void getAllNodeIds(std::set<int> & ids, bool ignoreChildren = false, bool ignoreBadSignatures = false) const;
|
||||||
@@ -197,7 +197,7 @@ private:
|
|||||||
|
|
||||||
virtual void loadNodeDataQuery(std::list<Signature *> & signatures, bool images=true, bool scan=true, bool userData=true, bool occupancyGrid=true) const = 0;
|
virtual void loadNodeDataQuery(std::list<Signature *> & signatures, bool images=true, bool scan=true, bool userData=true, bool occupancyGrid=true) const = 0;
|
||||||
virtual bool getCalibrationQuery(int signatureId, std::vector<CameraModel> & models, StereoCameraModel & stereoModel) const = 0;
|
virtual bool getCalibrationQuery(int signatureId, std::vector<CameraModel> & models, StereoCameraModel & stereoModel) const = 0;
|
||||||
virtual bool getNodeInfoQuery(int signatureId, Transform & pose, int & mapId, int & weight, std::string & label, double & stamp, Transform & groundTruthPose) const = 0;
|
virtual bool getNodeInfoQuery(int signatureId, Transform & pose, int & mapId, int & weight, std::string & label, double & stamp, Transform & groundTruthPose, std::vector<float> & velocity) const = 0;
|
||||||
virtual void getAllNodeIdsQuery(std::set<int> & ids, bool ignoreChildren, bool ignoreBadSignatures) const = 0;
|
virtual void getAllNodeIdsQuery(std::set<int> & ids, bool ignoreChildren, bool ignoreBadSignatures) const = 0;
|
||||||
virtual void getAllLinksQuery(std::multimap<int, Link> & links, bool ignoreNullLinks) const = 0;
|
virtual void getAllLinksQuery(std::multimap<int, Link> & links, bool ignoreNullLinks) const = 0;
|
||||||
virtual void getLastIdQuery(const std::string & tableName, int & id) const = 0;
|
virtual void getLastIdQuery(const std::string & tableName, int & id) const = 0;
|
||||||
|
|||||||
@@ -58,6 +58,20 @@ bool RTABMAP_EXP importPoses(
|
|||||||
std::multimap<int, Link> * constraints = 0, // optional for formats 3 and 4
|
std::multimap<int, Link> * constraints = 0, // optional for formats 3 and 4
|
||||||
std::map<int, double> * stamps = 0); // optional for format 1
|
std::map<int, double> * stamps = 0); // optional for format 1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute translation and rotation errors for KITTI datasets.
|
||||||
|
* See http://www.cvlibs.net/datasets/kitti/eval_odometry.php.
|
||||||
|
* @param poses_gt, Ground Truth poses
|
||||||
|
* @param poses_result, Estimated poses
|
||||||
|
* @param t_err, Output translation error (%)
|
||||||
|
* @param r_err, Output rotation error (deg/m)
|
||||||
|
*/
|
||||||
|
void RTABMAP_EXP calcKittiSequenceErrors(
|
||||||
|
const std::vector<Transform> &poses_gt,
|
||||||
|
const std::vector<Transform> &poses_result,
|
||||||
|
float & t_err,
|
||||||
|
float & r_err);
|
||||||
|
|
||||||
std::multimap<int, Link>::iterator RTABMAP_EXP findLink(
|
std::multimap<int, Link>::iterator RTABMAP_EXP findLink(
|
||||||
std::multimap<int, Link> & links,
|
std::multimap<int, Link> & links,
|
||||||
int from,
|
int from,
|
||||||
@@ -205,6 +219,10 @@ float RTABMAP_EXP computePathLength(
|
|||||||
unsigned int fromIndex = 0,
|
unsigned int fromIndex = 0,
|
||||||
unsigned int toIndex = 0);
|
unsigned int toIndex = 0);
|
||||||
|
|
||||||
|
// assuming they are all linked in map order
|
||||||
|
float RTABMAP_EXP computePathLength(
|
||||||
|
const std::map<int, Transform> & path);
|
||||||
|
|
||||||
std::list<std::map<int, Transform> > RTABMAP_EXP getPaths(
|
std::list<std::map<int, Transform> > RTABMAP_EXP getPaths(
|
||||||
std::map<int, Transform> poses,
|
std::map<int, Transform> poses,
|
||||||
const std::multimap<int, Link> & links);
|
const std::multimap<int, Link> & links);
|
||||||
|
|||||||
@@ -52,14 +52,7 @@ public:
|
|||||||
int to,
|
int to,
|
||||||
Type type,
|
Type type,
|
||||||
const Transform & transform,
|
const Transform & transform,
|
||||||
const cv::Mat & infMatrix = cv::Mat::eye(6,6,CV_64FC1),
|
const cv::Mat & infMatrix = cv::Mat::eye(6,6,CV_64FC1), // information matrix: inverse of covariance matrix
|
||||||
const cv::Mat & userData = cv::Mat());
|
|
||||||
Link(int from,
|
|
||||||
int to,
|
|
||||||
Type type,
|
|
||||||
const Transform & transform,
|
|
||||||
double rotVariance,
|
|
||||||
double transVariance,
|
|
||||||
const cv::Mat & userData = cv::Mat());
|
const cv::Mat & userData = cv::Mat());
|
||||||
|
|
||||||
bool isValid() const {return from_ > 0 && to_ > 0 && !transform_.isNull() && type_!=kUndef;}
|
bool isValid() const {return from_ > 0 && to_ > 0 && !transform_.isNull() && type_!=kUndef;}
|
||||||
@@ -87,7 +80,6 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void setInfMatrix(const cv::Mat & infMatrix);
|
void setInfMatrix(const cv::Mat & infMatrix);
|
||||||
void setVariance(double rotVariance, double transVariance);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int from_;
|
int from_;
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ public:
|
|||||||
bool update(const SensorData & data,
|
bool update(const SensorData & data,
|
||||||
const Transform & pose,
|
const Transform & pose,
|
||||||
const cv::Mat & covariance,
|
const cv::Mat & covariance,
|
||||||
|
const std::vector<float> & velocity = std::vector<float>(), // vx,vy,vz,vroll,vpitch,vyaw
|
||||||
Statistics * stats = 0);
|
Statistics * stats = 0);
|
||||||
bool init(const std::string & dbUrl,
|
bool init(const std::string & dbUrl,
|
||||||
bool dbOverwritten = false,
|
bool dbOverwritten = false,
|
||||||
@@ -153,6 +154,7 @@ public:
|
|||||||
std::string & label,
|
std::string & label,
|
||||||
double & stamp,
|
double & stamp,
|
||||||
Transform & groundTruth,
|
Transform & groundTruth,
|
||||||
|
std::vector<float> & velocity,
|
||||||
bool lookInDatabase = false) const;
|
bool lookInDatabase = false) const;
|
||||||
cv::Mat getImageCompressed(int signatureId) const;
|
cv::Mat getImageCompressed(int signatureId) const;
|
||||||
SensorData getNodeData(int nodeId, bool uncompressedData = false) const;
|
SensorData getNodeData(int nodeId, bool uncompressedData = false) const;
|
||||||
@@ -244,6 +246,7 @@ private:
|
|||||||
bool _rawDescriptorsKept;
|
bool _rawDescriptorsKept;
|
||||||
bool _saveDepth16Format;
|
bool _saveDepth16Format;
|
||||||
bool _notLinkedNodesKeptInDb;
|
bool _notLinkedNodesKeptInDb;
|
||||||
|
bool _saveIntermediateNodeData;
|
||||||
bool _incrementalMemory;
|
bool _incrementalMemory;
|
||||||
bool _reduceGraph;
|
bool _reduceGraph;
|
||||||
int _maxStMemSize;
|
int _maxStMemSize;
|
||||||
|
|||||||
@@ -39,53 +39,29 @@ namespace rtabmap {
|
|||||||
class OdometryEvent : public UEvent
|
class OdometryEvent : public UEvent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static cv::Mat generateCovarianceMatrix(float rotVariance, float transVariance)
|
OdometryEvent()
|
||||||
{
|
|
||||||
UASSERT(uIsFinite(rotVariance) && rotVariance>0);
|
|
||||||
UASSERT(uIsFinite(transVariance) && transVariance>0);
|
|
||||||
cv::Mat covariance = cv::Mat::eye(6,6,CV_64FC1);
|
|
||||||
covariance.at<double>(0,0) = transVariance;
|
|
||||||
covariance.at<double>(1,1) = transVariance;
|
|
||||||
covariance.at<double>(2,2) = transVariance;
|
|
||||||
covariance.at<double>(3,3) = rotVariance;
|
|
||||||
covariance.at<double>(4,4) = rotVariance;
|
|
||||||
covariance.at<double>(5,5) = rotVariance;
|
|
||||||
return covariance;
|
|
||||||
}
|
|
||||||
public:
|
|
||||||
OdometryEvent() :
|
|
||||||
_covariance(cv::Mat::eye(6,6,CV_64FC1))
|
|
||||||
{
|
{
|
||||||
|
_info.covariance = cv::Mat::eye(6,6,CV_64FC1);
|
||||||
}
|
}
|
||||||
OdometryEvent(
|
OdometryEvent(
|
||||||
const SensorData & data,
|
const SensorData & data,
|
||||||
const Transform & pose,
|
const Transform & pose,
|
||||||
const cv::Mat & covariance = cv::Mat::eye(6,6,CV_64FC1),
|
|
||||||
const OdometryInfo & info = OdometryInfo()) :
|
const OdometryInfo & info = OdometryInfo()) :
|
||||||
_data(data),
|
_data(data),
|
||||||
_pose(pose),
|
_pose(pose),
|
||||||
_info(info)
|
_info(info)
|
||||||
{
|
{
|
||||||
UASSERT(covariance.cols == 6 && covariance.rows == 6 && covariance.type() == CV_64FC1);
|
if(_info.covariance.empty())
|
||||||
UASSERT_MSG(uIsFinite(covariance.at<double>(0,0)) && covariance.at<double>(0,0)>0, "Transitional variance should not be null! (set to 1 if unknown)");
|
{
|
||||||
UASSERT_MSG(uIsFinite(covariance.at<double>(1,1)) && covariance.at<double>(1,1)>0, "Transitional variance should not be null! (set to 1 if unknown)");
|
_info.covariance = cv::Mat::eye(6,6,CV_64FC1);
|
||||||
UASSERT_MSG(uIsFinite(covariance.at<double>(2,2)) && covariance.at<double>(2,2)>0, "Transitional variance should not be null! (set to 1 if unknown)");
|
}
|
||||||
UASSERT_MSG(uIsFinite(covariance.at<double>(3,3)) && covariance.at<double>(3,3)>0, "Rotational variance should not be null! (set to 1 if unknown)");
|
UASSERT(_info.covariance.cols == 6 && _info.covariance.rows == 6 && _info.covariance.type() == CV_64FC1);
|
||||||
UASSERT_MSG(uIsFinite(covariance.at<double>(4,4)) && covariance.at<double>(4,4)>0, "Rotational variance should not be null! (set to 1 if unknown)");
|
UASSERT_MSG(uIsFinite(_info.covariance.at<double>(0,0)) && _info.covariance.at<double>(0,0)>0, "Transitional variance should not be null! (set to 1 if unknown)");
|
||||||
UASSERT_MSG(uIsFinite(covariance.at<double>(5,5)) && covariance.at<double>(5,5)>0, "Rotational variance should not be null! (set to 1 if unknown)");
|
UASSERT_MSG(uIsFinite(_info.covariance.at<double>(1,1)) && _info.covariance.at<double>(1,1)>0, "Transitional variance should not be null! (set to 1 if unknown)");
|
||||||
_covariance = covariance;
|
UASSERT_MSG(uIsFinite(_info.covariance.at<double>(2,2)) && _info.covariance.at<double>(2,2)>0, "Transitional variance should not be null! (set to 1 if unknown)");
|
||||||
}
|
UASSERT_MSG(uIsFinite(_info.covariance.at<double>(3,3)) && _info.covariance.at<double>(3,3)>0, "Rotational variance should not be null! (set to 1 if unknown)");
|
||||||
OdometryEvent(
|
UASSERT_MSG(uIsFinite(_info.covariance.at<double>(4,4)) && _info.covariance.at<double>(4,4)>0, "Rotational variance should not be null! (set to 1 if unknown)");
|
||||||
const SensorData & data,
|
UASSERT_MSG(uIsFinite(_info.covariance.at<double>(5,5)) && _info.covariance.at<double>(5,5)>0, "Rotational variance should not be null! (set to 1 if unknown)");
|
||||||
const Transform & pose,
|
|
||||||
double rotVariance = 1.0,
|
|
||||||
double transVariance = 1.0,
|
|
||||||
const OdometryInfo & info = OdometryInfo()) :
|
|
||||||
_data(data),
|
|
||||||
_pose(pose),
|
|
||||||
_covariance(generateCovarianceMatrix(rotVariance, transVariance)),
|
|
||||||
_info(info)
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
virtual ~OdometryEvent() {}
|
virtual ~OdometryEvent() {}
|
||||||
virtual std::string getClassName() const {return "OdometryEvent";}
|
virtual std::string getClassName() const {return "OdometryEvent";}
|
||||||
@@ -93,15 +69,29 @@ public:
|
|||||||
SensorData & data() {return _data;}
|
SensorData & data() {return _data;}
|
||||||
const SensorData & data() const {return _data;}
|
const SensorData & data() const {return _data;}
|
||||||
const Transform & pose() const {return _pose;}
|
const Transform & pose() const {return _pose;}
|
||||||
const cv::Mat & covariance() const {return _covariance;}
|
const cv::Mat & covariance() const {return _info.covariance;}
|
||||||
|
std::vector<float> velocity() const {
|
||||||
|
if(_info.interval>0.0)
|
||||||
|
{
|
||||||
|
std::vector<float> velocity(6,0);
|
||||||
|
float x,y,z,roll,pitch,yaw;
|
||||||
|
_info.transform.getTranslationAndEulerAngles(x,y,z,roll,pitch,yaw);
|
||||||
|
velocity[0] = x/_info.interval;
|
||||||
|
velocity[1] = y/_info.interval;
|
||||||
|
velocity[2] = z/_info.interval;
|
||||||
|
velocity[3] = roll/_info.interval;
|
||||||
|
velocity[4] = pitch/_info.interval;
|
||||||
|
velocity[5] = yaw/_info.interval;
|
||||||
|
}
|
||||||
|
return std::vector<float>();
|
||||||
|
}
|
||||||
const OdometryInfo & info() const {return _info;}
|
const OdometryInfo & info() const {return _info;}
|
||||||
double rotVariance() const {return uMax3(_covariance.at<double>(3,3), _covariance.at<double>(4,4), _covariance.at<double>(5,5));}
|
double rotVariance() const {return uMax3(_info.covariance.at<double>(3,3), _info.covariance.at<double>(4,4), _info.covariance.at<double>(5,5));}
|
||||||
double transVariance() const {return uMax3(_covariance.at<double>(0,0), _covariance.at<double>(1,1), _covariance.at<double>(2,2));}
|
double transVariance() const {return uMax3(_info.covariance.at<double>(0,0), _info.covariance.at<double>(1,1), _info.covariance.at<double>(2,2));}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SensorData _data;
|
SensorData _data;
|
||||||
Transform _pose;
|
Transform _pose;
|
||||||
cv::Mat _covariance;
|
|
||||||
OdometryInfo _info;
|
OdometryInfo _info;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -42,8 +42,6 @@ public:
|
|||||||
matches(0),
|
matches(0),
|
||||||
inliers(0),
|
inliers(0),
|
||||||
icpInliersRatio(0.0f),
|
icpInliersRatio(0.0f),
|
||||||
varianceLin(0.0f),
|
|
||||||
varianceAng(0.0f),
|
|
||||||
features(0),
|
features(0),
|
||||||
localMapSize(0),
|
localMapSize(0),
|
||||||
localScanMapSize(0),
|
localScanMapSize(0),
|
||||||
@@ -67,8 +65,7 @@ public:
|
|||||||
output.matches = matches;
|
output.matches = matches;
|
||||||
output.inliers = inliers;
|
output.inliers = inliers;
|
||||||
output.icpInliersRatio = icpInliersRatio;
|
output.icpInliersRatio = icpInliersRatio;
|
||||||
output.varianceLin = varianceLin;
|
output.covariance = covariance.clone();
|
||||||
output.varianceAng = varianceAng;
|
|
||||||
output.features = features;
|
output.features = features;
|
||||||
output.localMapSize = localMapSize;
|
output.localMapSize = localMapSize;
|
||||||
output.localScanMapSize = localScanMapSize;
|
output.localScanMapSize = localScanMapSize;
|
||||||
@@ -80,6 +77,7 @@ public:
|
|||||||
output.timeEstimation = timeEstimation;
|
output.timeEstimation = timeEstimation;
|
||||||
output.timeParticleFiltering = timeParticleFiltering;
|
output.timeParticleFiltering = timeParticleFiltering;
|
||||||
output.stamp = stamp;
|
output.stamp = stamp;
|
||||||
|
output.interval = interval;
|
||||||
output.transform = transform;
|
output.transform = transform;
|
||||||
output.transformFiltered = transformFiltered;
|
output.transformFiltered = transformFiltered;
|
||||||
output.transformGroundTruth = transformGroundTruth;
|
output.transformGroundTruth = transformGroundTruth;
|
||||||
@@ -92,8 +90,7 @@ public:
|
|||||||
int matches;
|
int matches;
|
||||||
int inliers;
|
int inliers;
|
||||||
float icpInliersRatio;
|
float icpInliersRatio;
|
||||||
float varianceLin;
|
cv::Mat covariance;
|
||||||
float varianceAng;
|
|
||||||
int features;
|
int features;
|
||||||
int localMapSize;
|
int localMapSize;
|
||||||
int localScanMapSize;
|
int localScanMapSize;
|
||||||
|
|||||||
@@ -197,6 +197,7 @@ class RTABMAP_EXP Parameters
|
|||||||
RTABMAP_PARAM(Mem, MapLabelsAdded, bool, true, "Create map labels. The first node of a map will be labelled as \"map#\" where # is the map ID.");
|
RTABMAP_PARAM(Mem, MapLabelsAdded, bool, true, "Create map labels. The first node of a map will be labelled as \"map#\" where # is the map ID.");
|
||||||
RTABMAP_PARAM(Mem, SaveDepth16Format, bool, false, "Save depth image into 16 bits format to reduce memory used. Warning: values over ~65 meters are ignored (maximum 65535 millimeters).");
|
RTABMAP_PARAM(Mem, SaveDepth16Format, bool, false, "Save depth image into 16 bits format to reduce memory used. Warning: values over ~65 meters are ignored (maximum 65535 millimeters).");
|
||||||
RTABMAP_PARAM(Mem, NotLinkedNodesKept, bool, true, "Keep not linked nodes in db (rehearsed nodes and deleted nodes).");
|
RTABMAP_PARAM(Mem, NotLinkedNodesKept, bool, true, "Keep not linked nodes in db (rehearsed nodes and deleted nodes).");
|
||||||
|
RTABMAP_PARAM(Mem, IntermediateNodeDataKept, bool, false, "Keep intermediate node data in db.");
|
||||||
RTABMAP_PARAM(Mem, STMSize, unsigned int, 10, "Short-term memory size.");
|
RTABMAP_PARAM(Mem, STMSize, unsigned int, 10, "Short-term memory size.");
|
||||||
RTABMAP_PARAM(Mem, IncrementalMemory, bool, true, "SLAM mode, otherwise it is Localization mode.");
|
RTABMAP_PARAM(Mem, IncrementalMemory, bool, true, "SLAM mode, otherwise it is Localization mode.");
|
||||||
RTABMAP_PARAM(Mem, ReduceGraph, bool, false, "Reduce graph. Merge nodes when loop closures are added (ignoring those with user data set).");
|
RTABMAP_PARAM(Mem, ReduceGraph, bool, false, "Reduce graph. Merge nodes when loop closures are added (ignoring those with user data set).");
|
||||||
|
|||||||
@@ -35,8 +35,6 @@ class RegistrationInfo
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RegistrationInfo() :
|
RegistrationInfo() :
|
||||||
varianceLin(0),
|
|
||||||
varianceAng(0),
|
|
||||||
inliers(0),
|
inliers(0),
|
||||||
matches(0),
|
matches(0),
|
||||||
icpInliersRatio(0),
|
icpInliersRatio(0),
|
||||||
@@ -45,8 +43,7 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
float varianceLin;
|
cv::Mat covariance;
|
||||||
float varianceAng;
|
|
||||||
std::string rejectedMsg;
|
std::string rejectedMsg;
|
||||||
|
|
||||||
// RegistrationVis
|
// RegistrationVis
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ public:
|
|||||||
const SensorData & data,
|
const SensorData & data,
|
||||||
Transform odomPose,
|
Transform odomPose,
|
||||||
const cv::Mat & odomCovariance = cv::Mat::eye(6,6,CV_64FC1),
|
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>());
|
const std::map<std::string, float> & externalStats = std::map<std::string, float>());
|
||||||
// for convenience
|
// for convenience
|
||||||
bool process(
|
bool process(
|
||||||
@@ -78,6 +79,7 @@ public:
|
|||||||
Transform odomPose,
|
Transform odomPose,
|
||||||
float odomLinearVariance,
|
float odomLinearVariance,
|
||||||
float odomAngularVariance,
|
float odomAngularVariance,
|
||||||
|
const std::vector<float> & odomVelocity = std::vector<float>(),
|
||||||
const std::map<std::string, float> & externalStats = std::map<std::string, float>());
|
const std::map<std::string, float> & externalStats = std::map<std::string, float>());
|
||||||
// for convenience, loop closure detection only
|
// for convenience, loop closure detection only
|
||||||
bool process(
|
bool process(
|
||||||
|
|||||||
@@ -125,8 +125,7 @@ private:
|
|||||||
Rtabmap * _rtabmap;
|
Rtabmap * _rtabmap;
|
||||||
bool _paused;
|
bool _paused;
|
||||||
Transform lastPose_;
|
Transform lastPose_;
|
||||||
double _rotVariance;
|
cv::Mat covariance_;
|
||||||
double _transVariance;
|
|
||||||
|
|
||||||
cv::Mat _userData;
|
cv::Mat _userData;
|
||||||
UMutex _userDataMutex;
|
UMutex _userDataMutex;
|
||||||
|
|||||||
@@ -115,11 +115,21 @@ public:
|
|||||||
void setWords3(const std::multimap<int, cv::Point3f> & words3) {_words3 = words3;}
|
void setWords3(const std::multimap<int, cv::Point3f> & words3) {_words3 = words3;}
|
||||||
void setPose(const Transform & pose) {_pose = pose;}
|
void setPose(const Transform & pose) {_pose = pose;}
|
||||||
void setGroundTruthPose(const Transform & pose) {_groundTruthPose = pose;}
|
void setGroundTruthPose(const Transform & pose) {_groundTruthPose = pose;}
|
||||||
|
void setVelocity(float vx, float vy, float vz, float vroll, float vpitch, float vyaw) {
|
||||||
|
_velocity = std::vector<float>(6,0);
|
||||||
|
_velocity[0]=vx;
|
||||||
|
_velocity[1]=vy;
|
||||||
|
_velocity[2]=vz;
|
||||||
|
_velocity[3]=vroll;
|
||||||
|
_velocity[4]=vpitch;
|
||||||
|
_velocity[5]=vyaw;
|
||||||
|
}
|
||||||
|
|
||||||
const std::multimap<int, cv::Point3f> & getWords3() const {return _words3;}
|
const std::multimap<int, cv::Point3f> & getWords3() const {return _words3;}
|
||||||
const Transform & getPose() const {return _pose;}
|
const Transform & getPose() const {return _pose;}
|
||||||
cv::Mat getPoseCovariance() const;
|
cv::Mat getPoseCovariance() const;
|
||||||
const Transform & getGroundTruthPose() const {return _groundTruthPose;}
|
const Transform & getGroundTruthPose() const {return _groundTruthPose;}
|
||||||
|
const std::vector<float> & getVelocity() const {return _velocity;}
|
||||||
|
|
||||||
SensorData & sensorData() {return _sensorData;}
|
SensorData & sensorData() {return _sensorData;}
|
||||||
const SensorData & sensorData() const {return _sensorData;}
|
const SensorData & sensorData() const {return _sensorData;}
|
||||||
@@ -147,6 +157,7 @@ private:
|
|||||||
|
|
||||||
Transform _pose;
|
Transform _pose;
|
||||||
Transform _groundTruthPose;
|
Transform _groundTruthPose;
|
||||||
|
std::vector<float> _velocity;
|
||||||
|
|
||||||
SensorData _sensorData;
|
SensorData _sensorData;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ Transform RTABMAP_EXP estimateMotion3DTo2D(
|
|||||||
int pnpRefineIterations = 1,
|
int pnpRefineIterations = 1,
|
||||||
const Transform & guess = Transform::getIdentity(),
|
const Transform & guess = Transform::getIdentity(),
|
||||||
const std::map<int, cv::Point3f> & words3B = std::map<int, cv::Point3f>(),
|
const std::map<int, cv::Point3f> & words3B = std::map<int, cv::Point3f>(),
|
||||||
double * varianceOut = 0, // mean reproj error if words3B is not set
|
cv::Mat * covariance = 0, // mean reproj error if words3B is not set
|
||||||
std::vector<int> * matchesOut = 0,
|
std::vector<int> * matchesOut = 0,
|
||||||
std::vector<int> * inliersOut = 0);
|
std::vector<int> * inliersOut = 0);
|
||||||
|
|
||||||
@@ -61,7 +61,7 @@ Transform RTABMAP_EXP estimateMotion3DTo3D(
|
|||||||
double inliersDistance = 0.1,
|
double inliersDistance = 0.1,
|
||||||
int iterations = 100,
|
int iterations = 100,
|
||||||
int refineIterations = 5,
|
int refineIterations = 5,
|
||||||
double * varianceOut = 0,
|
cv::Mat * covariance = 0,
|
||||||
std::vector<int> * matchesOut = 0,
|
std::vector<int> * matchesOut = 0,
|
||||||
std::vector<int> * inliersOut = 0);
|
std::vector<int> * inliersOut = 0);
|
||||||
|
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ Transform RTABMAP_EXP transformFromXYZCorrespondences(
|
|||||||
int refineModelIterations = 10,
|
int refineModelIterations = 10,
|
||||||
double refineModelSigma = 3.0,
|
double refineModelSigma = 3.0,
|
||||||
std::vector<int> * inliers = 0,
|
std::vector<int> * inliers = 0,
|
||||||
double * variance = 0);
|
cv::Mat * variance = 0);
|
||||||
|
|
||||||
void RTABMAP_EXP computeVarianceAndCorrespondences(
|
void RTABMAP_EXP computeVarianceAndCorrespondences(
|
||||||
const pcl::PointCloud<pcl::PointNormal>::ConstPtr & cloudA,
|
const pcl::PointCloud<pcl::PointNormal>::ConstPtr & cloudA,
|
||||||
|
|||||||
@@ -639,7 +639,8 @@ bool DBDriver::getNodeInfo(
|
|||||||
int & weight,
|
int & weight,
|
||||||
std::string & label,
|
std::string & label,
|
||||||
double & stamp,
|
double & stamp,
|
||||||
Transform & groundTruthPose) const
|
Transform & groundTruthPose,
|
||||||
|
std::vector<float> & velocity) const
|
||||||
{
|
{
|
||||||
bool found = false;
|
bool found = false;
|
||||||
// look in the trash
|
// look in the trash
|
||||||
@@ -659,7 +660,7 @@ bool DBDriver::getNodeInfo(
|
|||||||
if(!found)
|
if(!found)
|
||||||
{
|
{
|
||||||
_dbSafeAccessMutex.lock();
|
_dbSafeAccessMutex.lock();
|
||||||
found = this->getNodeInfoQuery(signatureId, pose, mapId, weight, label, stamp, groundTruthPose);
|
found = this->getNodeInfoQuery(signatureId, pose, mapId, weight, label, stamp, groundTruthPose, velocity);
|
||||||
_dbSafeAccessMutex.unlock();
|
_dbSafeAccessMutex.unlock();
|
||||||
}
|
}
|
||||||
return found;
|
return found;
|
||||||
|
|||||||
+236
-67
@@ -864,6 +864,7 @@ void DBDriverSqlite3::loadNodeDataQuery(std::list<Signature *> & signatures, boo
|
|||||||
if(uStrNumCmp(_version, "0.11.10") >= 0)
|
if(uStrNumCmp(_version, "0.11.10") >= 0)
|
||||||
{
|
{
|
||||||
std::stringstream fields;
|
std::stringstream fields;
|
||||||
|
|
||||||
if(images)
|
if(images)
|
||||||
{
|
{
|
||||||
fields << "image, depth, calibration";
|
fields << "image, depth, calibration";
|
||||||
@@ -1442,7 +1443,8 @@ bool DBDriverSqlite3::getNodeInfoQuery(int signatureId,
|
|||||||
int & weight,
|
int & weight,
|
||||||
std::string & label,
|
std::string & label,
|
||||||
double & stamp,
|
double & stamp,
|
||||||
Transform & groundTruthPose) const
|
Transform & groundTruthPose,
|
||||||
|
std::vector<float> & velocity) const
|
||||||
{
|
{
|
||||||
bool found = false;
|
bool found = false;
|
||||||
if(_ppDb && signatureId)
|
if(_ppDb && signatureId)
|
||||||
@@ -1451,7 +1453,14 @@ bool DBDriverSqlite3::getNodeInfoQuery(int signatureId,
|
|||||||
sqlite3_stmt * ppStmt = 0;
|
sqlite3_stmt * ppStmt = 0;
|
||||||
std::stringstream query;
|
std::stringstream query;
|
||||||
|
|
||||||
if(uStrNumCmp(_version, "0.11.1") >= 0)
|
if(uStrNumCmp(_version, "0.13.0") >= 0)
|
||||||
|
{
|
||||||
|
query << "SELECT pose, map_id, weight, label, stamp, ground_truth_pose, velocity "
|
||||||
|
"FROM Node "
|
||||||
|
"WHERE id = " << signatureId <<
|
||||||
|
";";
|
||||||
|
}
|
||||||
|
else if(uStrNumCmp(_version, "0.11.1") >= 0)
|
||||||
{
|
{
|
||||||
query << "SELECT pose, map_id, weight, label, stamp, ground_truth_pose "
|
query << "SELECT pose, map_id, weight, label, stamp, ground_truth_pose "
|
||||||
"FROM Node "
|
"FROM Node "
|
||||||
@@ -1503,15 +1512,26 @@ bool DBDriverSqlite3::getNodeInfoQuery(int signatureId,
|
|||||||
label = reinterpret_cast<const char*>(p); // label
|
label = reinterpret_cast<const char*>(p); // label
|
||||||
}
|
}
|
||||||
stamp = sqlite3_column_double(ppStmt, index++); // stamp
|
stamp = sqlite3_column_double(ppStmt, index++); // stamp
|
||||||
}
|
|
||||||
|
|
||||||
if(uStrNumCmp(_version, "0.11.1") >= 0)
|
if(uStrNumCmp(_version, "0.11.1") >= 0)
|
||||||
{
|
|
||||||
data = sqlite3_column_blob(ppStmt, index); // ground_truh_pose
|
|
||||||
dataSize = sqlite3_column_bytes(ppStmt, index++);
|
|
||||||
if((unsigned int)dataSize == groundTruthPose.size()*sizeof(float) && data)
|
|
||||||
{
|
{
|
||||||
memcpy(groundTruthPose.data(), data, dataSize);
|
data = sqlite3_column_blob(ppStmt, index); // ground_truth_pose
|
||||||
|
dataSize = sqlite3_column_bytes(ppStmt, index++);
|
||||||
|
if((unsigned int)dataSize == groundTruthPose.size()*sizeof(float) && data)
|
||||||
|
{
|
||||||
|
memcpy(groundTruthPose.data(), data, dataSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(uStrNumCmp(_version, "0.13.0") >= 0)
|
||||||
|
{
|
||||||
|
velocity.resize(6,0);
|
||||||
|
data = sqlite3_column_blob(ppStmt, index); // velocity
|
||||||
|
dataSize = sqlite3_column_bytes(ppStmt, index++);
|
||||||
|
if((unsigned int)dataSize == velocity.size()*sizeof(float) && data)
|
||||||
|
{
|
||||||
|
memcpy(velocity.data(), data, dataSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1546,7 +1566,14 @@ void DBDriverSqlite3::getAllNodeIdsQuery(std::set<int> & ids, bool ignoreChildre
|
|||||||
}
|
}
|
||||||
if(ignoreBadSignatures)
|
if(ignoreBadSignatures)
|
||||||
{
|
{
|
||||||
query << "WHERE id in (select node_id from Map_Node_Word) ";
|
if(uStrNumCmp(_version, "0.13.0") >= 0)
|
||||||
|
{
|
||||||
|
query << "WHERE id in (select node_id from Feature) ";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
query << "WHERE id in (select node_id from Map_Node_Word) ";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
query << "ORDER BY id";
|
query << "ORDER BY id";
|
||||||
|
|
||||||
@@ -1581,7 +1608,11 @@ void DBDriverSqlite3::getAllLinksQuery(std::multimap<int, Link> & links, bool ig
|
|||||||
sqlite3_stmt * ppStmt = 0;
|
sqlite3_stmt * ppStmt = 0;
|
||||||
std::stringstream query;
|
std::stringstream query;
|
||||||
|
|
||||||
if(uStrNumCmp(_version, "0.10.10") >= 0)
|
if(uStrNumCmp(_version, "0.13.0") >= 0)
|
||||||
|
{
|
||||||
|
query << "SELECT from_id, to_id, type, transform, information_matrix, user_data FROM Link ORDER BY from_id, to_id";
|
||||||
|
}
|
||||||
|
else if(uStrNumCmp(_version, "0.10.10") >= 0)
|
||||||
{
|
{
|
||||||
query << "SELECT from_id, to_id, type, transform, rot_variance, trans_variance, user_data FROM Link ORDER BY from_id, to_id";
|
query << "SELECT from_id, to_id, type, transform, rot_variance, trans_variance, user_data FROM Link ORDER BY from_id, to_id";
|
||||||
}
|
}
|
||||||
@@ -1604,8 +1635,6 @@ void DBDriverSqlite3::getAllLinksQuery(std::multimap<int, Link> & links, bool ig
|
|||||||
int fromId = -1;
|
int fromId = -1;
|
||||||
int toId = -1;
|
int toId = -1;
|
||||||
int type = Link::kUndef;
|
int type = Link::kUndef;
|
||||||
float rotVariance = 1.0f;
|
|
||||||
float transVariance = 1.0f;
|
|
||||||
const void * data = 0;
|
const void * data = 0;
|
||||||
int dataSize = 0;
|
int dataSize = 0;
|
||||||
|
|
||||||
@@ -1634,10 +1663,28 @@ void DBDriverSqlite3::getAllLinksQuery(std::multimap<int, Link> & links, bool ig
|
|||||||
|
|
||||||
if(!ignoreNullLinks || !transform.isNull())
|
if(!ignoreNullLinks || !transform.isNull())
|
||||||
{
|
{
|
||||||
|
cv::Mat informationMatrix = cv::Mat::eye(6,6,CV_64FC1);
|
||||||
if(uStrNumCmp(_version, "0.8.4") >= 0)
|
if(uStrNumCmp(_version, "0.8.4") >= 0)
|
||||||
{
|
{
|
||||||
rotVariance = sqlite3_column_double(ppStmt, index++);
|
if(uStrNumCmp(_version, "0.13.0") >= 0)
|
||||||
transVariance = sqlite3_column_double(ppStmt, index++);
|
{
|
||||||
|
data = sqlite3_column_blob(ppStmt, index);
|
||||||
|
dataSize = sqlite3_column_bytes(ppStmt, index++);
|
||||||
|
UASSERT(dataSize==36*sizeof(double) && data);
|
||||||
|
informationMatrix = cv::Mat(6, 6, CV_64FC1, (void *)data).clone(); // information_matrix
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
double rotVariance = sqlite3_column_double(ppStmt, index++);
|
||||||
|
double transVariance = sqlite3_column_double(ppStmt, index++);
|
||||||
|
UASSERT(rotVariance > 0.0 && transVariance>0.0);
|
||||||
|
informationMatrix.at<double>(0,0) = 1.0/transVariance;
|
||||||
|
informationMatrix.at<double>(1,1) = 1.0/transVariance;
|
||||||
|
informationMatrix.at<double>(2,2) = 1.0/transVariance;
|
||||||
|
informationMatrix.at<double>(3,3) = 1.0/rotVariance;
|
||||||
|
informationMatrix.at<double>(4,4) = 1.0/rotVariance;
|
||||||
|
informationMatrix.at<double>(5,5) = 1.0/rotVariance;
|
||||||
|
}
|
||||||
|
|
||||||
cv::Mat userDataCompressed;
|
cv::Mat userDataCompressed;
|
||||||
if(uStrNumCmp(_version, "0.10.10") >= 0)
|
if(uStrNumCmp(_version, "0.10.10") >= 0)
|
||||||
@@ -1651,17 +1698,19 @@ void DBDriverSqlite3::getAllLinksQuery(std::multimap<int, Link> & links, bool ig
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
links.insert(links.end(), std::make_pair(fromId, Link(fromId, toId, (Link::Type)type, transform, rotVariance, transVariance, userDataCompressed)));
|
links.insert(links.end(), std::make_pair(fromId, Link(fromId, toId, (Link::Type)type, transform, informationMatrix, userDataCompressed)));
|
||||||
}
|
}
|
||||||
else if(uStrNumCmp(_version, "0.7.4") >= 0)
|
else if(uStrNumCmp(_version, "0.7.4") >= 0)
|
||||||
{
|
{
|
||||||
rotVariance = transVariance = sqlite3_column_double(ppStmt, index++);
|
double variance = sqlite3_column_double(ppStmt, index++);
|
||||||
links.insert(links.end(), std::make_pair(fromId, Link(fromId, toId, (Link::Type)type, transform, rotVariance, transVariance)));
|
UASSERT(variance>0.0);
|
||||||
|
informationMatrix *= 1.0/variance;
|
||||||
|
links.insert(links.end(), std::make_pair(fromId, Link(fromId, toId, (Link::Type)type, transform, informationMatrix)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// neighbor is 0, loop closures are 1 and 2 (child)
|
// neighbor is 0, loop closures are 1 and 2 (child)
|
||||||
links.insert(links.end(), std::make_pair(fromId, Link(fromId, toId, type==0?Link::kNeighbor:Link::kGlobalClosure, transform, rotVariance, transVariance)));
|
links.insert(links.end(), std::make_pair(fromId, Link(fromId, toId, type==0?Link::kNeighbor:Link::kGlobalClosure, transform, informationMatrix)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1726,14 +1775,18 @@ void DBDriverSqlite3::getInvertedIndexNiQuery(int nodeId, int & ni) const
|
|||||||
sqlite3_stmt * ppStmt = 0;
|
sqlite3_stmt * ppStmt = 0;
|
||||||
std::stringstream query;
|
std::stringstream query;
|
||||||
|
|
||||||
// Create a new entry in table Signature
|
if(uStrNumCmp(_version, "0.13.0") >= 0)
|
||||||
query << "SELECT count(word_id) "
|
{
|
||||||
<< "FROM Map_Node_Word "
|
query << "SELECT count(word_id) "
|
||||||
<< "WHERE node_id=" << nodeId << ";";
|
<< "FROM Feature "
|
||||||
|
<< "WHERE node_id=" << nodeId << ";";
|
||||||
//query.append("COMMIT;");
|
}
|
||||||
|
else
|
||||||
//ULOGGER_DEBUG("DBDriverSqlite3::getSurfNi() Execute query : %s", query.toStdString().c_str());
|
{
|
||||||
|
query << "SELECT count(word_id) "
|
||||||
|
<< "FROM Map_Node_Word "
|
||||||
|
<< "WHERE node_id=" << nodeId << ";";
|
||||||
|
}
|
||||||
|
|
||||||
rc = sqlite3_prepare_v2(_ppDb, query.str().c_str(), -1, &ppStmt, 0);
|
rc = sqlite3_prepare_v2(_ppDb, query.str().c_str(), -1, &ppStmt, 0);
|
||||||
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
|
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
|
||||||
@@ -1879,7 +1932,13 @@ void DBDriverSqlite3::loadSignaturesQuery(const std::list<int> & ids, std::list<
|
|||||||
unsigned int loaded = 0;
|
unsigned int loaded = 0;
|
||||||
|
|
||||||
// Load nodes information
|
// Load nodes information
|
||||||
if(uStrNumCmp(_version, "0.11.1") >= 0)
|
if(uStrNumCmp(_version, "0.13.0") >= 0)
|
||||||
|
{
|
||||||
|
query << "SELECT id, map_id, weight, pose, stamp, label, ground_truth_pose, velocity "
|
||||||
|
<< "FROM Node "
|
||||||
|
<< "WHERE id=?;";
|
||||||
|
}
|
||||||
|
else if(uStrNumCmp(_version, "0.11.1") >= 0)
|
||||||
{
|
{
|
||||||
query << "SELECT id, map_id, weight, pose, stamp, label, ground_truth_pose "
|
query << "SELECT id, map_id, weight, pose, stamp, label, ground_truth_pose "
|
||||||
<< "FROM Node "
|
<< "FROM Node "
|
||||||
@@ -1914,6 +1973,7 @@ void DBDriverSqlite3::loadSignaturesQuery(const std::list<int> & ids, std::list<
|
|||||||
int weight = 0;
|
int weight = 0;
|
||||||
Transform pose;
|
Transform pose;
|
||||||
Transform groundTruthPose;
|
Transform groundTruthPose;
|
||||||
|
std::vector<float> velocity;
|
||||||
const void * data = 0;
|
const void * data = 0;
|
||||||
int dataSize = 0;
|
int dataSize = 0;
|
||||||
std::string label;
|
std::string label;
|
||||||
@@ -1942,15 +2002,26 @@ void DBDriverSqlite3::loadSignaturesQuery(const std::list<int> & ids, std::list<
|
|||||||
{
|
{
|
||||||
label = reinterpret_cast<const char*>(p);
|
label = reinterpret_cast<const char*>(p);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if(uStrNumCmp(_version, "0.11.1") >= 0)
|
if(uStrNumCmp(_version, "0.11.1") >= 0)
|
||||||
{
|
|
||||||
data = sqlite3_column_blob(ppStmt, index); // ground_truth_pose
|
|
||||||
dataSize = sqlite3_column_bytes(ppStmt, index++);
|
|
||||||
if((unsigned int)dataSize == groundTruthPose.size()*sizeof(float) && data)
|
|
||||||
{
|
{
|
||||||
memcpy(groundTruthPose.data(), data, dataSize);
|
data = sqlite3_column_blob(ppStmt, index); // ground_truth_pose
|
||||||
|
dataSize = sqlite3_column_bytes(ppStmt, index++);
|
||||||
|
if((unsigned int)dataSize == groundTruthPose.size()*sizeof(float) && data)
|
||||||
|
{
|
||||||
|
memcpy(groundTruthPose.data(), data, dataSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(uStrNumCmp(_version, "0.13.0") >= 0)
|
||||||
|
{
|
||||||
|
velocity.resize(6,0);
|
||||||
|
data = sqlite3_column_blob(ppStmt, index); // velocity
|
||||||
|
dataSize = sqlite3_column_bytes(ppStmt, index++);
|
||||||
|
if((unsigned int)dataSize == velocity.size()*sizeof(float) && data)
|
||||||
|
{
|
||||||
|
memcpy(velocity.data(), data, dataSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1970,6 +2041,10 @@ void DBDriverSqlite3::loadSignaturesQuery(const std::list<int> & ids, std::list<
|
|||||||
label,
|
label,
|
||||||
pose,
|
pose,
|
||||||
groundTruthPose);
|
groundTruthPose);
|
||||||
|
if(velocity.size() == 6)
|
||||||
|
{
|
||||||
|
s->setVelocity(velocity[0], velocity[1], velocity[2], velocity[3], velocity[4], velocity[5]);
|
||||||
|
}
|
||||||
s->setSaved(true);
|
s->setSaved(true);
|
||||||
nodes.push_back(s);
|
nodes.push_back(s);
|
||||||
++loaded;
|
++loaded;
|
||||||
@@ -1992,7 +2067,13 @@ void DBDriverSqlite3::loadSignaturesQuery(const std::list<int> & ids, std::list<
|
|||||||
|
|
||||||
// Prepare the query... Get the map from signature and visual words
|
// Prepare the query... Get the map from signature and visual words
|
||||||
std::stringstream query2;
|
std::stringstream query2;
|
||||||
if(uStrNumCmp(_version, "0.12.0") >= 0)
|
if(uStrNumCmp(_version, "0.13.0") >= 0)
|
||||||
|
{
|
||||||
|
query2 << "SELECT word_id, pos_x, pos_y, size, dir, response, octave, depth_x, depth_y, depth_z, descriptor_size, descriptor "
|
||||||
|
"FROM Feature "
|
||||||
|
"WHERE node_id = ? ";
|
||||||
|
}
|
||||||
|
else if(uStrNumCmp(_version, "0.12.0") >= 0)
|
||||||
{
|
{
|
||||||
query2 << "SELECT word_id, pos_x, pos_y, size, dir, response, octave, depth_x, depth_y, depth_z, descriptor_size, descriptor "
|
query2 << "SELECT word_id, pos_x, pos_y, size, dir, response, octave, depth_x, depth_y, depth_z, descriptor_size, descriptor "
|
||||||
"FROM Map_Node_Word "
|
"FROM Map_Node_Word "
|
||||||
@@ -2485,7 +2566,11 @@ void DBDriverSqlite3::loadLinksQuery(
|
|||||||
sqlite3_stmt * ppStmt = 0;
|
sqlite3_stmt * ppStmt = 0;
|
||||||
std::stringstream query;
|
std::stringstream query;
|
||||||
|
|
||||||
if(uStrNumCmp(_version, "0.10.10") >= 0)
|
if(uStrNumCmp(_version, "0.13.0") >= 0)
|
||||||
|
{
|
||||||
|
query << "SELECT to_id, type, transform, information_matrix, user_data FROM Link ";
|
||||||
|
}
|
||||||
|
else if(uStrNumCmp(_version, "0.10.10") >= 0)
|
||||||
{
|
{
|
||||||
query << "SELECT to_id, type, transform, rot_variance, trans_variance, user_data FROM Link ";
|
query << "SELECT to_id, type, transform, rot_variance, trans_variance, user_data FROM Link ";
|
||||||
}
|
}
|
||||||
@@ -2524,8 +2609,6 @@ void DBDriverSqlite3::loadLinksQuery(
|
|||||||
|
|
||||||
int toId = -1;
|
int toId = -1;
|
||||||
int type = Link::kUndef;
|
int type = Link::kUndef;
|
||||||
float rotVariance = 1.0f;
|
|
||||||
float transVariance = 1.0f;
|
|
||||||
const void * data = 0;
|
const void * data = 0;
|
||||||
int dataSize = 0;
|
int dataSize = 0;
|
||||||
|
|
||||||
@@ -2551,10 +2634,28 @@ void DBDriverSqlite3::loadLinksQuery(
|
|||||||
UERROR("Error while loading link transform from %d to %d! Setting to null...", signatureId, toId);
|
UERROR("Error while loading link transform from %d to %d! Setting to null...", signatureId, toId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cv::Mat informationMatrix = cv::Mat::eye(6,6,CV_64FC1);
|
||||||
if(uStrNumCmp(_version, "0.8.4") >= 0)
|
if(uStrNumCmp(_version, "0.8.4") >= 0)
|
||||||
{
|
{
|
||||||
rotVariance = sqlite3_column_double(ppStmt, index++);
|
if(uStrNumCmp(_version, "0.13.0") >= 0)
|
||||||
transVariance = sqlite3_column_double(ppStmt, index++);
|
{
|
||||||
|
data = sqlite3_column_blob(ppStmt, index);
|
||||||
|
dataSize = sqlite3_column_bytes(ppStmt, index++);
|
||||||
|
UASSERT(dataSize==36*sizeof(double) && data);
|
||||||
|
informationMatrix = cv::Mat(6, 6, CV_64FC1, (void *)data).clone(); // information_matrix
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
double rotVariance = sqlite3_column_double(ppStmt, index++);
|
||||||
|
double transVariance = sqlite3_column_double(ppStmt, index++);
|
||||||
|
UASSERT(rotVariance > 0.0 && transVariance>0.0);
|
||||||
|
informationMatrix.at<double>(0,0) = 1.0/transVariance;
|
||||||
|
informationMatrix.at<double>(1,1) = 1.0/transVariance;
|
||||||
|
informationMatrix.at<double>(2,2) = 1.0/transVariance;
|
||||||
|
informationMatrix.at<double>(3,3) = 1.0/rotVariance;
|
||||||
|
informationMatrix.at<double>(4,4) = 1.0/rotVariance;
|
||||||
|
informationMatrix.at<double>(5,5) = 1.0/rotVariance;
|
||||||
|
}
|
||||||
|
|
||||||
cv::Mat userDataCompressed;
|
cv::Mat userDataCompressed;
|
||||||
if(uStrNumCmp(_version, "0.10.10") >= 0)
|
if(uStrNumCmp(_version, "0.10.10") >= 0)
|
||||||
@@ -2568,17 +2669,19 @@ void DBDriverSqlite3::loadLinksQuery(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
neighbors.insert(neighbors.end(), std::make_pair(toId, Link(signatureId, toId, (Link::Type)type, transform, rotVariance, transVariance, userDataCompressed)));
|
neighbors.insert(neighbors.end(), std::make_pair(toId, Link(signatureId, toId, (Link::Type)type, transform, informationMatrix, userDataCompressed)));
|
||||||
}
|
}
|
||||||
else if(uStrNumCmp(_version, "0.7.4") >= 0)
|
else if(uStrNumCmp(_version, "0.7.4") >= 0)
|
||||||
{
|
{
|
||||||
rotVariance = transVariance = sqlite3_column_double(ppStmt, index++);
|
double variance = sqlite3_column_double(ppStmt, index++);
|
||||||
neighbors.insert(neighbors.end(), std::make_pair(toId, Link(signatureId, toId, (Link::Type)type, transform, rotVariance, transVariance)));
|
UASSERT(variance>0.0);
|
||||||
|
informationMatrix *= 1.0/variance;
|
||||||
|
neighbors.insert(neighbors.end(), std::make_pair(toId, Link(signatureId, toId, (Link::Type)type, transform, informationMatrix)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// neighbor is 0, loop closures are 1 and 2 (child)
|
// neighbor is 0, loop closures are 1 and 2 (child)
|
||||||
neighbors.insert(neighbors.end(), std::make_pair(toId, Link(signatureId, toId, type==0?Link::kNeighbor:Link::kGlobalClosure, transform, rotVariance, transVariance)));
|
neighbors.insert(neighbors.end(), std::make_pair(toId, Link(signatureId, toId, type==0?Link::kNeighbor:Link::kGlobalClosure, transform, informationMatrix)));
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = sqlite3_step(ppStmt);
|
rc = sqlite3_step(ppStmt);
|
||||||
@@ -2608,7 +2711,13 @@ void DBDriverSqlite3::loadLinksQuery(std::list<Signature *> & signatures) const
|
|||||||
std::stringstream query;
|
std::stringstream query;
|
||||||
int totalLinksLoaded = 0;
|
int totalLinksLoaded = 0;
|
||||||
|
|
||||||
if(uStrNumCmp(_version, "0.10.10") >= 0)
|
if(uStrNumCmp(_version, "0.13.0") >= 0)
|
||||||
|
{
|
||||||
|
query << "SELECT to_id, type, information_matrix, user_data, transform FROM Link "
|
||||||
|
<< "WHERE from_id = ? "
|
||||||
|
<< "ORDER BY to_id";
|
||||||
|
}
|
||||||
|
else if(uStrNumCmp(_version, "0.10.10") >= 0)
|
||||||
{
|
{
|
||||||
query << "SELECT to_id, type, rot_variance, trans_variance, user_data, transform FROM Link "
|
query << "SELECT to_id, type, rot_variance, trans_variance, user_data, transform FROM Link "
|
||||||
<< "WHERE from_id = ? "
|
<< "WHERE from_id = ? "
|
||||||
@@ -2644,8 +2753,6 @@ void DBDriverSqlite3::loadLinksQuery(std::list<Signature *> & signatures) const
|
|||||||
|
|
||||||
int toId = -1;
|
int toId = -1;
|
||||||
int linkType = -1;
|
int linkType = -1;
|
||||||
float rotVariance = 1.0f;
|
|
||||||
float transVariance = 1.0f;
|
|
||||||
std::list<Link> links;
|
std::list<Link> links;
|
||||||
const void * data = 0;
|
const void * data = 0;
|
||||||
int dataSize = 0;
|
int dataSize = 0;
|
||||||
@@ -2659,10 +2766,28 @@ void DBDriverSqlite3::loadLinksQuery(std::list<Signature *> & signatures) const
|
|||||||
toId = sqlite3_column_int(ppStmt, index++);
|
toId = sqlite3_column_int(ppStmt, index++);
|
||||||
linkType = sqlite3_column_int(ppStmt, index++);
|
linkType = sqlite3_column_int(ppStmt, index++);
|
||||||
cv::Mat userDataCompressed;
|
cv::Mat userDataCompressed;
|
||||||
|
cv::Mat informationMatrix = cv::Mat::eye(6,6,CV_64FC1);
|
||||||
if(uStrNumCmp(_version, "0.8.4") >= 0)
|
if(uStrNumCmp(_version, "0.8.4") >= 0)
|
||||||
{
|
{
|
||||||
rotVariance = sqlite3_column_double(ppStmt, index++);
|
if(uStrNumCmp(_version, "0.13.0") >= 0)
|
||||||
transVariance = sqlite3_column_double(ppStmt, index++);
|
{
|
||||||
|
data = sqlite3_column_blob(ppStmt, index);
|
||||||
|
dataSize = sqlite3_column_bytes(ppStmt, index++);
|
||||||
|
UASSERT(dataSize==36*sizeof(double) && data);
|
||||||
|
informationMatrix = cv::Mat(6, 6, CV_64FC1, (void *)data).clone(); // information_matrix
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
double rotVariance = sqlite3_column_double(ppStmt, index++);
|
||||||
|
double transVariance = sqlite3_column_double(ppStmt, index++);
|
||||||
|
UASSERT(rotVariance > 0.0 && transVariance>0.0);
|
||||||
|
informationMatrix.at<double>(0,0) = 1.0/transVariance;
|
||||||
|
informationMatrix.at<double>(1,1) = 1.0/transVariance;
|
||||||
|
informationMatrix.at<double>(2,2) = 1.0/transVariance;
|
||||||
|
informationMatrix.at<double>(3,3) = 1.0/rotVariance;
|
||||||
|
informationMatrix.at<double>(4,4) = 1.0/rotVariance;
|
||||||
|
informationMatrix.at<double>(5,5) = 1.0/rotVariance;
|
||||||
|
}
|
||||||
|
|
||||||
if(uStrNumCmp(_version, "0.10.10") >= 0)
|
if(uStrNumCmp(_version, "0.10.10") >= 0)
|
||||||
{
|
{
|
||||||
@@ -2677,7 +2802,9 @@ void DBDriverSqlite3::loadLinksQuery(std::list<Signature *> & signatures) const
|
|||||||
}
|
}
|
||||||
else if(uStrNumCmp(_version, "0.7.4") >= 0)
|
else if(uStrNumCmp(_version, "0.7.4") >= 0)
|
||||||
{
|
{
|
||||||
rotVariance = transVariance = sqlite3_column_double(ppStmt, index++);
|
double variance = sqlite3_column_double(ppStmt, index++);
|
||||||
|
UASSERT(variance>0.0);
|
||||||
|
informationMatrix *= 1.0/variance;
|
||||||
}
|
}
|
||||||
|
|
||||||
//transform
|
//transform
|
||||||
@@ -2697,11 +2824,11 @@ void DBDriverSqlite3::loadLinksQuery(std::list<Signature *> & signatures) const
|
|||||||
{
|
{
|
||||||
if(uStrNumCmp(_version, "0.7.4") >= 0)
|
if(uStrNumCmp(_version, "0.7.4") >= 0)
|
||||||
{
|
{
|
||||||
links.push_back(Link((*iter)->id(), toId, (Link::Type)linkType, transform, rotVariance, transVariance, userDataCompressed));
|
links.push_back(Link((*iter)->id(), toId, (Link::Type)linkType, transform, informationMatrix, userDataCompressed));
|
||||||
}
|
}
|
||||||
else // neighbor is 0, loop closures are 1 and 2 (child)
|
else // neighbor is 0, loop closures are 1 and 2 (child)
|
||||||
{
|
{
|
||||||
links.push_back(Link((*iter)->id(), toId, linkType == 0?Link::kNeighbor:Link::kGlobalClosure, transform, rotVariance, transVariance, userDataCompressed));
|
links.push_back(Link((*iter)->id(), toId, linkType == 0?Link::kNeighbor:Link::kGlobalClosure, transform, informationMatrix, userDataCompressed));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -2960,7 +3087,7 @@ void DBDriverSqlite3::saveQuery(const std::list<Signature *> & signatures) const
|
|||||||
UDEBUG("Time=%fs", timer.ticks());
|
UDEBUG("Time=%fs", timer.ticks());
|
||||||
|
|
||||||
|
|
||||||
// Create new entries in table Map_Word_Node
|
// Create new entries in table Feature
|
||||||
query = queryStepKeypoint();
|
query = queryStepKeypoint();
|
||||||
rc = sqlite3_prepare_v2(_ppDb, query.c_str(), -1, &ppStmt, 0);
|
rc = sqlite3_prepare_v2(_ppDb, query.c_str(), -1, &ppStmt, 0);
|
||||||
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
|
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
|
||||||
@@ -3296,7 +3423,11 @@ void DBDriverSqlite3::addStatisticsQuery(const Statistics & statistics) const
|
|||||||
|
|
||||||
std::string DBDriverSqlite3::queryStepNode() const
|
std::string DBDriverSqlite3::queryStepNode() const
|
||||||
{
|
{
|
||||||
if(uStrNumCmp(_version, "0.11.1") >= 0)
|
if(uStrNumCmp(_version, "0.13.0") >= 0)
|
||||||
|
{
|
||||||
|
return "INSERT INTO Node(id, map_id, weight, pose, stamp, label, ground_truth_pose, velocity) VALUES(?,?,?,?,?,?,?,?);";
|
||||||
|
}
|
||||||
|
else if(uStrNumCmp(_version, "0.11.1") >= 0)
|
||||||
{
|
{
|
||||||
return "INSERT INTO Node(id, map_id, weight, pose, stamp, label, ground_truth_pose) VALUES(?,?,?,?,?,?,?);";
|
return "INSERT INTO Node(id, map_id, weight, pose, stamp, label, ground_truth_pose) VALUES(?,?,?,?,?,?,?);";
|
||||||
}
|
}
|
||||||
@@ -3353,6 +3484,26 @@ void DBDriverSqlite3::stepNode(sqlite3_stmt * ppStmt, const Signature * s) const
|
|||||||
if(uStrNumCmp(_version, "0.10.1") >= 0)
|
if(uStrNumCmp(_version, "0.10.1") >= 0)
|
||||||
{
|
{
|
||||||
// ignore user_data
|
// ignore user_data
|
||||||
|
|
||||||
|
if(uStrNumCmp(_version, "0.11.1") >= 0)
|
||||||
|
{
|
||||||
|
rc = sqlite3_bind_blob(ppStmt, index++, s->getGroundTruthPose().data(), s->getGroundTruthPose().size()*sizeof(float), SQLITE_STATIC);
|
||||||
|
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
|
||||||
|
|
||||||
|
if(uStrNumCmp(_version, "0.13.0") >= 0)
|
||||||
|
{
|
||||||
|
if(s->getVelocity().empty())
|
||||||
|
{
|
||||||
|
rc = sqlite3_bind_null(ppStmt, index++);
|
||||||
|
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rc = sqlite3_bind_blob(ppStmt, index++, s->getVelocity().data(), s->getVelocity().size()*sizeof(float), SQLITE_STATIC);
|
||||||
|
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if(uStrNumCmp(_version, "0.8.8") >= 0)
|
else if(uStrNumCmp(_version, "0.8.8") >= 0)
|
||||||
{
|
{
|
||||||
@@ -3367,13 +3518,6 @@ void DBDriverSqlite3::stepNode(sqlite3_stmt * ppStmt, const Signature * s) const
|
|||||||
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
|
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(uStrNumCmp(_version, "0.11.1") >= 0)
|
|
||||||
{
|
|
||||||
rc = sqlite3_bind_blob(ppStmt, index++, s->getGroundTruthPose().data(), s->getGroundTruthPose().size()*sizeof(float), SQLITE_STATIC);
|
|
||||||
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//step
|
//step
|
||||||
rc=sqlite3_step(ppStmt);
|
rc=sqlite3_step(ppStmt);
|
||||||
@@ -3822,7 +3966,11 @@ void DBDriverSqlite3::stepSensorData(sqlite3_stmt * ppStmt,
|
|||||||
|
|
||||||
std::string DBDriverSqlite3::queryStepLinkUpdate() const
|
std::string DBDriverSqlite3::queryStepLinkUpdate() const
|
||||||
{
|
{
|
||||||
if(uStrNumCmp(_version, "0.10.10") >= 0)
|
if(uStrNumCmp(_version, "0.13.0") >= 0)
|
||||||
|
{
|
||||||
|
return "UPDATE Link SET type=?, information_matrix=?, transform=?, user_data=? WHERE from_id=? AND to_id = ?;";
|
||||||
|
}
|
||||||
|
else if(uStrNumCmp(_version, "0.10.10") >= 0)
|
||||||
{
|
{
|
||||||
return "UPDATE Link SET type=?, rot_variance=?, trans_variance=?, transform=?, user_data=? WHERE from_id=? AND to_id = ?;";
|
return "UPDATE Link SET type=?, rot_variance=?, trans_variance=?, transform=?, user_data=? WHERE from_id=? AND to_id = ?;";
|
||||||
}
|
}
|
||||||
@@ -3842,7 +3990,11 @@ std::string DBDriverSqlite3::queryStepLinkUpdate() const
|
|||||||
std::string DBDriverSqlite3::queryStepLink() const
|
std::string DBDriverSqlite3::queryStepLink() const
|
||||||
{
|
{
|
||||||
// from_id, to_id are at the end to match the update query above
|
// from_id, to_id are at the end to match the update query above
|
||||||
if(uStrNumCmp(_version, "0.10.10") >= 0)
|
if(uStrNumCmp(_version, "0.13.0") >= 0)
|
||||||
|
{
|
||||||
|
return "INSERT INTO Link(type, information_matrix, transform, user_data, from_id, to_id) VALUES(?,?,?,?,?,?);";
|
||||||
|
}
|
||||||
|
else if(uStrNumCmp(_version, "0.10.10") >= 0)
|
||||||
{
|
{
|
||||||
return "INSERT INTO Link(type, rot_variance, trans_variance, transform, user_data, from_id, to_id) VALUES(?,?,?,?,?,?,?);";
|
return "INSERT INTO Link(type, rot_variance, trans_variance, transform, user_data, from_id, to_id) VALUES(?,?,?,?,?,?,?);";
|
||||||
}
|
}
|
||||||
@@ -3881,7 +4033,13 @@ void DBDriverSqlite3::stepLink(
|
|||||||
rc = sqlite3_bind_int(ppStmt, index++, link.type());
|
rc = sqlite3_bind_int(ppStmt, index++, link.type());
|
||||||
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
|
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
|
||||||
|
|
||||||
if(uStrNumCmp(_version, "0.8.4") >= 0)
|
if(uStrNumCmp(_version, "0.13.0") >= 0)
|
||||||
|
{
|
||||||
|
// information_matrix
|
||||||
|
rc = sqlite3_bind_blob(ppStmt, index++, link.infMatrix().data, (int)link.infMatrix().total()*sizeof(double), SQLITE_STATIC);
|
||||||
|
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
|
||||||
|
}
|
||||||
|
else if(uStrNumCmp(_version, "0.8.4") >= 0)
|
||||||
{
|
{
|
||||||
rc = sqlite3_bind_double(ppStmt, index++, link.rotVariance());
|
rc = sqlite3_bind_double(ppStmt, index++, link.rotVariance());
|
||||||
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
|
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
|
||||||
@@ -3925,7 +4083,14 @@ void DBDriverSqlite3::stepLink(
|
|||||||
|
|
||||||
std::string DBDriverSqlite3::queryStepWordsChanged() const
|
std::string DBDriverSqlite3::queryStepWordsChanged() const
|
||||||
{
|
{
|
||||||
return "UPDATE Map_Node_Word SET word_id = ? WHERE word_id = ? AND node_id = ?;";
|
if(uStrNumCmp(_version, "0.13.0") >= 0)
|
||||||
|
{
|
||||||
|
return "UPDATE Feature SET word_id = ? WHERE word_id = ? AND node_id = ?;";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return "UPDATE Map_Node_Word SET word_id = ? WHERE word_id = ? AND node_id = ?;";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
void DBDriverSqlite3::stepWordsChanged(sqlite3_stmt * ppStmt, int nodeId, int oldWordId, int newWordId) const
|
void DBDriverSqlite3::stepWordsChanged(sqlite3_stmt * ppStmt, int nodeId, int oldWordId, int newWordId) const
|
||||||
{
|
{
|
||||||
@@ -3951,7 +4116,11 @@ void DBDriverSqlite3::stepWordsChanged(sqlite3_stmt * ppStmt, int nodeId, int ol
|
|||||||
|
|
||||||
std::string DBDriverSqlite3::queryStepKeypoint() const
|
std::string DBDriverSqlite3::queryStepKeypoint() const
|
||||||
{
|
{
|
||||||
if(uStrNumCmp(_version, "0.12.0") >= 0)
|
if(uStrNumCmp(_version, "0.13.0") >= 0)
|
||||||
|
{
|
||||||
|
return "INSERT INTO Feature(node_id, word_id, pos_x, pos_y, size, dir, response, octave, depth_x, depth_y, depth_z, descriptor_size, descriptor) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?);";
|
||||||
|
}
|
||||||
|
else if(uStrNumCmp(_version, "0.12.0") >= 0)
|
||||||
{
|
{
|
||||||
return "INSERT INTO Map_Node_Word(node_id, word_id, pos_x, pos_y, size, dir, response, octave, depth_x, depth_y, depth_z, descriptor_size, descriptor) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?);";
|
return "INSERT INTO Map_Node_Word(node_id, word_id, pos_x, pos_y, size, dir, response, octave, depth_x, depth_y, depth_z, descriptor_size, descriptor) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?);";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ private:
|
|||||||
|
|
||||||
virtual void loadNodeDataQuery(std::list<Signature *> & signatures, bool images=true, bool scan=true, bool userData=true, bool occupancyGrid=true) const;
|
virtual void loadNodeDataQuery(std::list<Signature *> & signatures, bool images=true, bool scan=true, bool userData=true, bool occupancyGrid=true) const;
|
||||||
virtual bool getCalibrationQuery(int signatureId, std::vector<CameraModel> & models, StereoCameraModel & stereoModel) const;
|
virtual bool getCalibrationQuery(int signatureId, std::vector<CameraModel> & models, StereoCameraModel & stereoModel) const;
|
||||||
virtual bool getNodeInfoQuery(int signatureId, Transform & pose, int & mapId, int & weight, std::string & label, double & stamp, Transform & groundTruthPose) const;
|
virtual bool getNodeInfoQuery(int signatureId, Transform & pose, int & mapId, int & weight, std::string & label, double & stamp, Transform & groundTruthPose, std::vector<float> & velocity) const;
|
||||||
virtual void getAllNodeIdsQuery(std::set<int> & ids, bool ignoreChildren, bool ignoreBadSignatures) const;
|
virtual void getAllNodeIdsQuery(std::set<int> & ids, bool ignoreChildren, bool ignoreBadSignatures) const;
|
||||||
virtual void getAllLinksQuery(std::multimap<int, Link> & links, bool ignoreNullLinks) const;
|
virtual void getAllLinksQuery(std::multimap<int, Link> & links, bool ignoreNullLinks) const;
|
||||||
virtual void getLastIdQuery(const std::string & tableName, int & id) const;
|
virtual void getLastIdQuery(const std::string & tableName, int & id) const;
|
||||||
|
|||||||
@@ -267,7 +267,8 @@ SensorData DBReader::captureImage(CameraInfo * info)
|
|||||||
double stamp;
|
double stamp;
|
||||||
int mapId;
|
int mapId;
|
||||||
Transform localTransform, pose, groundTruth;
|
Transform localTransform, pose, groundTruth;
|
||||||
_dbDriver->getNodeInfo(*_currentId, pose, mapId, weight, label, stamp, groundTruth);
|
std::vector<float> velocity;
|
||||||
|
_dbDriver->getNodeInfo(*_currentId, pose, mapId, weight, label, stamp, groundTruth, velocity);
|
||||||
if(previousStamp && stamp && stamp > previousStamp)
|
if(previousStamp && stamp && stamp > previousStamp)
|
||||||
{
|
{
|
||||||
delay = stamp - previousStamp;
|
delay = stamp - previousStamp;
|
||||||
@@ -320,7 +321,8 @@ SensorData DBReader::getNextData(CameraInfo * info)
|
|||||||
std::string label;
|
std::string label;
|
||||||
double stamp;
|
double stamp;
|
||||||
Transform groundTruth;
|
Transform groundTruth;
|
||||||
_dbDriver->getNodeInfo(*_currentId, pose, mapId, weight, label, stamp, groundTruth);
|
std::vector<float> velocity;
|
||||||
|
_dbDriver->getNodeInfo(*_currentId, pose, mapId, weight, label, stamp, groundTruth, velocity);
|
||||||
|
|
||||||
cv::Mat infMatrix = cv::Mat::eye(6,6,CV_64FC1);
|
cv::Mat infMatrix = cv::Mat::eye(6,6,CV_64FC1);
|
||||||
if(!_odometryIgnored)
|
if(!_odometryIgnored)
|
||||||
|
|||||||
@@ -425,6 +425,124 @@ bool importPoses(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// KITTI evaluation
|
||||||
|
float lengths[] = {100,200,300,400,500,600,700,800};
|
||||||
|
int32_t num_lengths = 8;
|
||||||
|
|
||||||
|
struct errors {
|
||||||
|
int32_t first_frame;
|
||||||
|
float r_err;
|
||||||
|
float t_err;
|
||||||
|
float len;
|
||||||
|
float speed;
|
||||||
|
errors (int32_t first_frame,float r_err,float t_err,float len,float speed) :
|
||||||
|
first_frame(first_frame),r_err(r_err),t_err(t_err),len(len),speed(speed) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<float> trajectoryDistances (const std::vector<Transform> &poses) {
|
||||||
|
std::vector<float> dist;
|
||||||
|
dist.push_back(0);
|
||||||
|
for (int32_t i=1; i<poses.size(); i++) {
|
||||||
|
Transform P1 = poses[i-1];
|
||||||
|
Transform P2 = poses[i];
|
||||||
|
float dx = P1.x()-P2.x();
|
||||||
|
float dy = P1.y()-P2.y();
|
||||||
|
float dz = P1.z()-P2.z();
|
||||||
|
dist.push_back(dist[i-1]+sqrt(dx*dx+dy*dy+dz*dz));
|
||||||
|
}
|
||||||
|
return dist;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t lastFrameFromSegmentLength(std::vector<float> &dist,int32_t first_frame,float len) {
|
||||||
|
for (int32_t i=first_frame; i<dist.size(); i++)
|
||||||
|
if (dist[i]>dist[first_frame]+len)
|
||||||
|
return i;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float rotationError(const Transform &pose_error) {
|
||||||
|
float a = pose_error(0,0);
|
||||||
|
float b = pose_error(1,1);
|
||||||
|
float c = pose_error(2,2);
|
||||||
|
float d = 0.5*(a+b+c-1.0);
|
||||||
|
return std::acos(std::max(std::min(d,1.0f),-1.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float translationError(const Transform &pose_error) {
|
||||||
|
float dx = pose_error.x();
|
||||||
|
float dy = pose_error.y();
|
||||||
|
float dz = pose_error.z();
|
||||||
|
return sqrt(dx*dx+dy*dy+dz*dz);
|
||||||
|
}
|
||||||
|
|
||||||
|
void calcKittiSequenceErrors (
|
||||||
|
const std::vector<Transform> &poses_gt,
|
||||||
|
const std::vector<Transform> &poses_result,
|
||||||
|
float & t_err,
|
||||||
|
float & r_err) {
|
||||||
|
|
||||||
|
UASSERT(poses_gt.size() == poses_result.size());
|
||||||
|
|
||||||
|
// error vector
|
||||||
|
std::vector<errors> err;
|
||||||
|
|
||||||
|
// parameters
|
||||||
|
int32_t step_size = 10; // every second
|
||||||
|
|
||||||
|
// pre-compute distances (from ground truth as reference)
|
||||||
|
std::vector<float> dist = trajectoryDistances(poses_gt);
|
||||||
|
|
||||||
|
// for all start positions do
|
||||||
|
for (int32_t first_frame=0; first_frame<poses_gt.size(); first_frame+=step_size) {
|
||||||
|
|
||||||
|
// for all segment lengths do
|
||||||
|
for (int32_t i=0; i<num_lengths; i++) {
|
||||||
|
|
||||||
|
// current length
|
||||||
|
float len = lengths[i];
|
||||||
|
|
||||||
|
// compute last frame
|
||||||
|
int32_t last_frame = lastFrameFromSegmentLength(dist,first_frame,len);
|
||||||
|
|
||||||
|
// continue, if sequence not long enough
|
||||||
|
if (last_frame==-1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// compute rotational and translational errors
|
||||||
|
Transform pose_delta_gt = poses_gt[first_frame].inverse()*poses_gt[last_frame];
|
||||||
|
Transform pose_delta_result = poses_result[first_frame].inverse()*poses_result[last_frame];
|
||||||
|
Transform pose_error = pose_delta_result.inverse()*pose_delta_gt;
|
||||||
|
float r_err = rotationError(pose_error);
|
||||||
|
float t_err = translationError(pose_error);
|
||||||
|
|
||||||
|
// compute speed
|
||||||
|
float num_frames = (float)(last_frame-first_frame+1);
|
||||||
|
float speed = len/(0.1*num_frames);
|
||||||
|
|
||||||
|
// write to file
|
||||||
|
err.push_back(errors(first_frame,r_err/len,t_err/len,len,speed));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t_err = 0;
|
||||||
|
r_err = 0;
|
||||||
|
|
||||||
|
// for all errors do => compute sum of t_err, r_err
|
||||||
|
for (std::vector<errors>::iterator it=err.begin(); it!=err.end(); it++)
|
||||||
|
{
|
||||||
|
t_err += it->t_err;
|
||||||
|
r_err += it->r_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// save errors
|
||||||
|
float num = err.size();
|
||||||
|
t_err /= num;
|
||||||
|
r_err /= num;
|
||||||
|
t_err *= 100.0f; // Translation error (%)
|
||||||
|
r_err *= 180/CV_PI; // Rotation error (deg/m)
|
||||||
|
}
|
||||||
|
// KITTI evaluation end
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////
|
////////////////////////////////////////////
|
||||||
// Graph utilities
|
// Graph utilities
|
||||||
@@ -1636,6 +1754,29 @@ float computePathLength(
|
|||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float computePathLength(
|
||||||
|
const std::map<int, Transform> & path)
|
||||||
|
{
|
||||||
|
float length = 0.0f;
|
||||||
|
if(path.size() > 1)
|
||||||
|
{
|
||||||
|
float x=0, y=0, z=0;
|
||||||
|
std::map<int, Transform>::const_iterator iter=path.begin();
|
||||||
|
Transform previousPose = iter->second;
|
||||||
|
++iter;
|
||||||
|
for(; iter!=path.end(); ++iter)
|
||||||
|
{
|
||||||
|
const Transform & currentPose = iter->second;
|
||||||
|
x += fabs(previousPose.x() - currentPose.x());
|
||||||
|
y += fabs(previousPose.y() - currentPose.y());
|
||||||
|
z += fabs(previousPose.z() - currentPose.z());
|
||||||
|
previousPose = currentPose;
|
||||||
|
}
|
||||||
|
length = sqrt(x*x + y*y + z*z);
|
||||||
|
}
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
// return all paths linked only by neighbor links
|
// return all paths linked only by neighbor links
|
||||||
std::list<std::map<int, Transform> > getPaths(
|
std::list<std::map<int, Transform> > getPaths(
|
||||||
std::map<int, Transform> poses,
|
std::map<int, Transform> poses,
|
||||||
|
|||||||
+7
-40
@@ -28,6 +28,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
#include "rtabmap/core/Link.h"
|
#include "rtabmap/core/Link.h"
|
||||||
#include <rtabmap/utilite/ULogger.h>
|
#include <rtabmap/utilite/ULogger.h>
|
||||||
#include <rtabmap/utilite/UMath.h>
|
#include <rtabmap/utilite/UMath.h>
|
||||||
|
#include <rtabmap/utilite/UConversion.h>
|
||||||
#include <rtabmap/core/Compression.h>
|
#include <rtabmap/core/Compression.h>
|
||||||
|
|
||||||
namespace rtabmap {
|
namespace rtabmap {
|
||||||
@@ -61,29 +62,6 @@ Link::Link(int from,
|
|||||||
_userDataRaw = userData;
|
_userDataRaw = userData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Link::Link(int from,
|
|
||||||
int to,
|
|
||||||
Type type,
|
|
||||||
const Transform & transform,
|
|
||||||
double rotVariance,
|
|
||||||
double transVariance,
|
|
||||||
const cv::Mat & userData) :
|
|
||||||
from_(from),
|
|
||||||
to_(to),
|
|
||||||
transform_(transform),
|
|
||||||
type_(type)
|
|
||||||
{
|
|
||||||
setVariance(rotVariance, transVariance);
|
|
||||||
|
|
||||||
if(userData.type() == CV_8UC1) // Bytes
|
|
||||||
{
|
|
||||||
_userDataCompressed = userData; // assume compressed
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_userDataRaw = userData;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
double Link::rotVariance() const
|
double Link::rotVariance() const
|
||||||
{
|
{
|
||||||
@@ -100,25 +78,14 @@ double Link::transVariance() const
|
|||||||
|
|
||||||
void Link::setInfMatrix(const cv::Mat & infMatrix) {
|
void Link::setInfMatrix(const cv::Mat & infMatrix) {
|
||||||
UASSERT(infMatrix.cols == 6 && infMatrix.rows == 6 && infMatrix.type() == CV_64FC1);
|
UASSERT(infMatrix.cols == 6 && infMatrix.rows == 6 && infMatrix.type() == CV_64FC1);
|
||||||
UASSERT_MSG(uIsFinite(infMatrix.at<double>(0,0)) && infMatrix.at<double>(0,0)>0, "Transitional information should not be null! (set to 1 if unknown)");
|
UASSERT_MSG(uIsFinite(infMatrix.at<double>(0,0)) && infMatrix.at<double>(0,0)>0, uFormat("Linear information should not be null! Value=%f (set to 1 if unknown).", infMatrix.at<double>(0,0)).c_str());
|
||||||
UASSERT_MSG(uIsFinite(infMatrix.at<double>(1,1)) && infMatrix.at<double>(1,1)>0, "Transitional information should not be null! (set to 1 if unknown)");
|
UASSERT_MSG(uIsFinite(infMatrix.at<double>(1,1)) && infMatrix.at<double>(1,1)>0, uFormat("Linear information should not be null! Value=%f (set to 1 if unknown).", infMatrix.at<double>(1,1)).c_str());
|
||||||
UASSERT_MSG(uIsFinite(infMatrix.at<double>(2,2)) && infMatrix.at<double>(2,2)>0, "Transitional information should not be null! (set to 1 if unknown)");
|
UASSERT_MSG(uIsFinite(infMatrix.at<double>(2,2)) && infMatrix.at<double>(2,2)>0, uFormat("Linear information should not be null! Value=%f (set to 1 if unknown).", infMatrix.at<double>(2,2)).c_str());
|
||||||
UASSERT_MSG(uIsFinite(infMatrix.at<double>(3,3)) && infMatrix.at<double>(3,3)>0, "Rotational information should not be null! (set to 1 if unknown)");
|
UASSERT_MSG(uIsFinite(infMatrix.at<double>(3,3)) && infMatrix.at<double>(3,3)>0, uFormat("Angular information should not be null! Value=%f (set to 1 if unknown).", infMatrix.at<double>(3,3)).c_str());
|
||||||
UASSERT_MSG(uIsFinite(infMatrix.at<double>(4,4)) && infMatrix.at<double>(4,4)>0, "Rotational information should not be null! (set to 1 if unknown)");
|
UASSERT_MSG(uIsFinite(infMatrix.at<double>(4,4)) && infMatrix.at<double>(4,4)>0, uFormat("Angular information should not be null! Value=%f (set to 1 if unknown).", infMatrix.at<double>(4,4)).c_str());
|
||||||
UASSERT_MSG(uIsFinite(infMatrix.at<double>(5,5)) && infMatrix.at<double>(5,5)>0, "Rotational information should not be null! (set to 1 if unknown)");
|
UASSERT_MSG(uIsFinite(infMatrix.at<double>(5,5)) && infMatrix.at<double>(5,5)>0, uFormat("Angular information should not be null! Value=%f (set to 1 if unknown).", infMatrix.at<double>(5,5)).c_str());
|
||||||
infMatrix_ = infMatrix;
|
infMatrix_ = infMatrix;
|
||||||
}
|
}
|
||||||
void Link::setVariance(double rotVariance, double transVariance) {
|
|
||||||
UASSERT(uIsFinite(rotVariance) && rotVariance>0);
|
|
||||||
UASSERT(uIsFinite(transVariance) && transVariance>0);
|
|
||||||
infMatrix_ = cv::Mat::eye(6,6,CV_64FC1);
|
|
||||||
infMatrix_.at<double>(0,0) = 1.0/transVariance;
|
|
||||||
infMatrix_.at<double>(1,1) = 1.0/transVariance;
|
|
||||||
infMatrix_.at<double>(2,2) = 1.0/transVariance;
|
|
||||||
infMatrix_.at<double>(3,3) = 1.0/rotVariance;
|
|
||||||
infMatrix_.at<double>(4,4) = 1.0/rotVariance;
|
|
||||||
infMatrix_.at<double>(5,5) = 1.0/rotVariance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Link::uncompressUserData()
|
void Link::uncompressUserData()
|
||||||
{
|
{
|
||||||
|
|||||||
+28
-15
@@ -74,6 +74,7 @@ Memory::Memory(const ParametersMap & parameters) :
|
|||||||
_rawDescriptorsKept(Parameters::defaultMemRawDescriptorsKept()),
|
_rawDescriptorsKept(Parameters::defaultMemRawDescriptorsKept()),
|
||||||
_saveDepth16Format(Parameters::defaultMemSaveDepth16Format()),
|
_saveDepth16Format(Parameters::defaultMemSaveDepth16Format()),
|
||||||
_notLinkedNodesKeptInDb(Parameters::defaultMemNotLinkedNodesKept()),
|
_notLinkedNodesKeptInDb(Parameters::defaultMemNotLinkedNodesKept()),
|
||||||
|
_saveIntermediateNodeData(Parameters::defaultMemIntermediateNodeDataKept()),
|
||||||
_incrementalMemory(Parameters::defaultMemIncrementalMemory()),
|
_incrementalMemory(Parameters::defaultMemIncrementalMemory()),
|
||||||
_reduceGraph(Parameters::defaultMemReduceGraph()),
|
_reduceGraph(Parameters::defaultMemReduceGraph()),
|
||||||
_maxStMemSize(Parameters::defaultMemSTMSize()),
|
_maxStMemSize(Parameters::defaultMemSTMSize()),
|
||||||
@@ -425,6 +426,7 @@ void Memory::parseParameters(const ParametersMap & parameters)
|
|||||||
Parameters::parse(parameters, Parameters::kMemSaveDepth16Format(), _saveDepth16Format);
|
Parameters::parse(parameters, Parameters::kMemSaveDepth16Format(), _saveDepth16Format);
|
||||||
Parameters::parse(parameters, Parameters::kMemReduceGraph(), _reduceGraph);
|
Parameters::parse(parameters, Parameters::kMemReduceGraph(), _reduceGraph);
|
||||||
Parameters::parse(parameters, Parameters::kMemNotLinkedNodesKept(), _notLinkedNodesKeptInDb);
|
Parameters::parse(parameters, Parameters::kMemNotLinkedNodesKept(), _notLinkedNodesKeptInDb);
|
||||||
|
Parameters::parse(parameters, Parameters::kMemIntermediateNodeDataKept(), _saveIntermediateNodeData);
|
||||||
Parameters::parse(parameters, Parameters::kMemRehearsalIdUpdatedToNewOne(), _idUpdatedToNewOneRehearsal);
|
Parameters::parse(parameters, Parameters::kMemRehearsalIdUpdatedToNewOne(), _idUpdatedToNewOneRehearsal);
|
||||||
Parameters::parse(parameters, Parameters::kMemGenerateIds(), _generateIds);
|
Parameters::parse(parameters, Parameters::kMemGenerateIds(), _generateIds);
|
||||||
Parameters::parse(parameters, Parameters::kMemBadSignaturesIgnored(), _badSignaturesIgnored);
|
Parameters::parse(parameters, Parameters::kMemBadSignaturesIgnored(), _badSignaturesIgnored);
|
||||||
@@ -580,13 +582,14 @@ bool Memory::update(
|
|||||||
const SensorData & data,
|
const SensorData & data,
|
||||||
Statistics * stats)
|
Statistics * stats)
|
||||||
{
|
{
|
||||||
return update(data, Transform(), cv::Mat(), stats);
|
return update(data, Transform(), cv::Mat(), std::vector<float>(), stats);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Memory::update(
|
bool Memory::update(
|
||||||
const SensorData & data,
|
const SensorData & data,
|
||||||
const Transform & pose,
|
const Transform & pose,
|
||||||
const cv::Mat & covariance,
|
const cv::Mat & covariance,
|
||||||
|
const std::vector<float> & velocity,
|
||||||
Statistics * stats)
|
Statistics * stats)
|
||||||
{
|
{
|
||||||
UDEBUG("");
|
UDEBUG("");
|
||||||
@@ -613,6 +616,10 @@ bool Memory::update(
|
|||||||
UERROR("Failed to create a signature...");
|
UERROR("Failed to create a signature...");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if(velocity.size()==6)
|
||||||
|
{
|
||||||
|
signature->setVelocity(velocity[0], velocity[1], velocity[2], velocity[3], velocity[4], velocity[5]);
|
||||||
|
}
|
||||||
|
|
||||||
t=timer.ticks()*1000;
|
t=timer.ticks()*1000;
|
||||||
if(stats) stats->addStatistic(Statistics::kTimingMemSignature_creation(), t);
|
if(stats) stats->addStatistic(Statistics::kTimingMemSignature_creation(), t);
|
||||||
@@ -2265,10 +2272,11 @@ Transform Memory::computeTransform(
|
|||||||
else if(info && !transform.isIdentity())
|
else if(info && !transform.isIdentity())
|
||||||
{
|
{
|
||||||
//normalize variance
|
//normalize variance
|
||||||
info->varianceLin *= transform.getNorm();
|
info->covariance *= transform.getNorm();
|
||||||
info->varianceAng *= transform.getAngle();
|
if(info->covariance.at<double>(0,0) < 0.0001)
|
||||||
info->varianceLin = info->varianceLin>0.0f?info->varianceLin:0.0001f; // epsilon if exact transform
|
{
|
||||||
info->varianceAng = info->varianceAng>0.0f?info->varianceAng:0.0001f; // epsilon if exact transform
|
info->covariance = cv::Mat::eye(6,6,CV_64FC1)*0.0001; // epsilon if exact transform
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2321,10 +2329,11 @@ Transform Memory::computeIcpTransform(
|
|||||||
if(!t.isNull() && !t.isIdentity() && info)
|
if(!t.isNull() && !t.isIdentity() && info)
|
||||||
{
|
{
|
||||||
// normalize variance
|
// normalize variance
|
||||||
info->varianceLin *= t.getNorm();
|
info->covariance *= t.getNorm();
|
||||||
info->varianceAng *= t.getAngle();
|
if(info->covariance.at<double>(0,0)<=0.0)
|
||||||
info->varianceLin = info->varianceLin>0.0f?info->varianceLin:0.0001f; // epsilon if exact transform
|
{
|
||||||
info->varianceAng = info->varianceAng>0.0f?info->varianceAng:0.0001f; // epsilon if exact transform
|
info->covariance = cv::Mat::eye(6,6,CV_64FC1)*0.0001; // epsilon if exact transform
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -2875,7 +2884,7 @@ bool Memory::rehearsalMerge(int oldId, int newId)
|
|||||||
newS->setLabel(oldS->getLabel());
|
newS->setLabel(oldS->getLabel());
|
||||||
oldS->setLabel("");
|
oldS->setLabel("");
|
||||||
oldS->removeLinks(); // remove all links
|
oldS->removeLinks(); // remove all links
|
||||||
oldS->addLink(Link(oldS->id(), newS->id(), Link::kGlobalClosure, Transform(), 1, 1)); // to keep track of the merged location
|
oldS->addLink(Link(oldS->id(), newS->id(), Link::kGlobalClosure, Transform(), cv::Mat::eye(6,6,CV_64FC1))); // to keep track of the merged location
|
||||||
|
|
||||||
// Set old image to new signature
|
// Set old image to new signature
|
||||||
this->copyData(oldS, newS);
|
this->copyData(oldS, newS);
|
||||||
@@ -2890,7 +2899,7 @@ bool Memory::rehearsalMerge(int oldId, int newId)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
newS->addLink(Link(newS->id(), oldS->id(), Link::kGlobalClosure, Transform() , 1, 1)); // to keep track of the merged location
|
newS->addLink(Link(newS->id(), oldS->id(), Link::kGlobalClosure, Transform() , cv::Mat::eye(6,6,CV_64FC1))); // to keep track of the merged location
|
||||||
|
|
||||||
// update weight
|
// update weight
|
||||||
oldS->setWeight(newS->getWeight() + 1 + oldS->getWeight());
|
oldS->setWeight(newS->getWeight() + 1 + oldS->getWeight());
|
||||||
@@ -2949,7 +2958,8 @@ Transform Memory::getOdomPose(int signatureId, bool lookInDatabase) const
|
|||||||
int mapId, weight;
|
int mapId, weight;
|
||||||
std::string label;
|
std::string label;
|
||||||
double stamp;
|
double stamp;
|
||||||
getNodeInfo(signatureId, pose, mapId, weight, label, stamp, groundTruth, lookInDatabase);
|
std::vector<float> velocity;
|
||||||
|
getNodeInfo(signatureId, pose, mapId, weight, label, stamp, groundTruth, velocity, lookInDatabase);
|
||||||
return pose;
|
return pose;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2959,7 +2969,8 @@ Transform Memory::getGroundTruthPose(int signatureId, bool lookInDatabase) const
|
|||||||
int mapId, weight;
|
int mapId, weight;
|
||||||
std::string label;
|
std::string label;
|
||||||
double stamp;
|
double stamp;
|
||||||
getNodeInfo(signatureId, pose, mapId, weight, label, stamp, groundTruth, lookInDatabase);
|
std::vector<float> velocity;
|
||||||
|
getNodeInfo(signatureId, pose, mapId, weight, label, stamp, groundTruth, velocity, lookInDatabase);
|
||||||
return groundTruth;
|
return groundTruth;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2970,6 +2981,7 @@ bool Memory::getNodeInfo(int signatureId,
|
|||||||
std::string & label,
|
std::string & label,
|
||||||
double & stamp,
|
double & stamp,
|
||||||
Transform & groundTruth,
|
Transform & groundTruth,
|
||||||
|
std::vector<float> & velocity,
|
||||||
bool lookInDatabase) const
|
bool lookInDatabase) const
|
||||||
{
|
{
|
||||||
const Signature * s = this->getSignature(signatureId);
|
const Signature * s = this->getSignature(signatureId);
|
||||||
@@ -2981,11 +2993,12 @@ bool Memory::getNodeInfo(int signatureId,
|
|||||||
label = s->getLabel();
|
label = s->getLabel();
|
||||||
stamp = s->getStamp();
|
stamp = s->getStamp();
|
||||||
groundTruth = s->getGroundTruthPose();
|
groundTruth = s->getGroundTruthPose();
|
||||||
|
velocity = s->getVelocity();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if(lookInDatabase && _dbDriver)
|
else if(lookInDatabase && _dbDriver)
|
||||||
{
|
{
|
||||||
return _dbDriver->getNodeInfo(signatureId, odomPose, mapId, weight, label, stamp, groundTruth);
|
return _dbDriver->getNodeInfo(signatureId, odomPose, mapId, weight, label, stamp, groundTruth, velocity);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -3669,7 +3682,7 @@ Signature * Memory::createSignature(const SensorData & data, const Transform & p
|
|||||||
}
|
}
|
||||||
|
|
||||||
Signature * s;
|
Signature * s;
|
||||||
if(this->isBinDataKept() && !isIntermediateNode)
|
if(this->isBinDataKept() && (!isIntermediateNode || _saveIntermediateNodeData))
|
||||||
{
|
{
|
||||||
UDEBUG("Bin data kept: rgb=%d, depth=%d, scan=%d, userData=%d",
|
UDEBUG("Bin data kept: rgb=%d, depth=%d, scan=%d, userData=%d",
|
||||||
image.empty()?0:1,
|
image.empty()?0:1,
|
||||||
|
|||||||
@@ -529,10 +529,11 @@ Transform Odometry::process(SensorData & data, const Transform & guessIn, Odomet
|
|||||||
info->distanceTravelled = distanceTravelled_;
|
info->distanceTravelled = distanceTravelled_;
|
||||||
}
|
}
|
||||||
|
|
||||||
info->varianceLin *= t.getNorm();
|
info->covariance *= t.getNorm();
|
||||||
info->varianceAng *= t.getAngle();
|
if(info->covariance.at<double>(0,0)<=0.0)
|
||||||
info->varianceLin = info->varianceLin>0.0f?info->varianceLin:0.0001f; // epsilon if exact transform
|
{
|
||||||
info->varianceAng = info->varianceAng>0.0f?info->varianceAng:0.0001f; // epsilon if exact transform
|
info->covariance = cv::Mat::eye(6,6,CV_64FC1)*0.0001; // epsilon if exact transform
|
||||||
|
}
|
||||||
|
|
||||||
return _pose *= t; // update
|
return _pose *= t; // update
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -168,8 +168,7 @@ Transform OdometryF2F::computeTransform(
|
|||||||
//return Identity
|
//return Identity
|
||||||
output = Transform::getIdentity();
|
output = Transform::getIdentity();
|
||||||
// a very high variance tells that the new pose is not linked with the previous one
|
// a very high variance tells that the new pose is not linked with the previous one
|
||||||
regInfo.varianceLin = 9999;
|
regInfo.covariance = cv::Mat::eye(6,6,CV_64FC1)*9999.0;
|
||||||
regInfo.varianceAng = 9999;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!output.isNull())
|
if(!output.isNull())
|
||||||
@@ -245,8 +244,7 @@ Transform OdometryF2F::computeTransform(
|
|||||||
if(info)
|
if(info)
|
||||||
{
|
{
|
||||||
info->type = 1;
|
info->type = 1;
|
||||||
info->varianceLin = regInfo.varianceLin;
|
info->covariance = regInfo.covariance;
|
||||||
info->varianceAng = regInfo.varianceAng;
|
|
||||||
info->inliers = regInfo.inliers;
|
info->inliers = regInfo.inliers;
|
||||||
info->icpInliersRatio = regInfo.icpInliersRatio;
|
info->icpInliersRatio = regInfo.icpInliersRatio;
|
||||||
info->matches = regInfo.matches;
|
info->matches = regInfo.matches;
|
||||||
|
|||||||
@@ -250,7 +250,8 @@ Transform OdometryF2M::computeTransform(
|
|||||||
UASSERT_MSG(bundlePoses.find(lastFrame_->id()) == bundlePoses.end(),
|
UASSERT_MSG(bundlePoses.find(lastFrame_->id()) == bundlePoses.end(),
|
||||||
uFormat("Frame %d already added! Make sure the input frames have unique IDs!", lastFrame_->id()).c_str());
|
uFormat("Frame %d already added! Make sure the input frames have unique IDs!", lastFrame_->id()).c_str());
|
||||||
|
|
||||||
bundleLinks.insert(std::make_pair(bundlePoses_.rbegin()->first, Link(bundlePoses_.rbegin()->first, lastFrame_->id(), Link::kNeighbor, bundlePoses_.rbegin()->second.inverse()*transform, regInfo.varianceAng, regInfo.varianceLin)));
|
regInfo.covariance *= transform.getNorm();
|
||||||
|
bundleLinks.insert(std::make_pair(bundlePoses_.rbegin()->first, Link(bundlePoses_.rbegin()->first, lastFrame_->id(), Link::kNeighbor, bundlePoses_.rbegin()->second.inverse()*transform, regInfo.covariance.inv())));
|
||||||
bundlePoses.insert(std::make_pair(lastFrame_->id(), transform));
|
bundlePoses.insert(std::make_pair(lastFrame_->id(), transform));
|
||||||
|
|
||||||
UDEBUG("Fill matches (%d)", (int)regInfo.inliersIDs.size());
|
UDEBUG("Fill matches (%d)", (int)regInfo.inliersIDs.size());
|
||||||
@@ -735,8 +736,7 @@ Transform OdometryF2M::computeTransform(
|
|||||||
data.setFeatures(lastFrame_->sensorData().keypoints(), lastFrame_->sensorData().keypoints3D(), lastFrame_->sensorData().descriptors());
|
data.setFeatures(lastFrame_->sensorData().keypoints(), lastFrame_->sensorData().keypoints3D(), lastFrame_->sensorData().descriptors());
|
||||||
|
|
||||||
// a very high variance tells that the new pose is not linked with the previous one
|
// a very high variance tells that the new pose is not linked with the previous one
|
||||||
regInfo.varianceLin = 9999;
|
regInfo.covariance = cv::Mat::eye(6,6,CV_64FC1)*9999.0;
|
||||||
regInfo.varianceAng = 9999;
|
|
||||||
|
|
||||||
bool frameValid = false;
|
bool frameValid = false;
|
||||||
Transform newFramePose = this->getPose(); // initial pose may be not identity...
|
Transform newFramePose = this->getPose(); // initial pose may be not identity...
|
||||||
@@ -874,8 +874,7 @@ Transform OdometryF2M::computeTransform(
|
|||||||
|
|
||||||
if(info)
|
if(info)
|
||||||
{
|
{
|
||||||
info->varianceLin = regInfo.varianceLin;
|
info->covariance = regInfo.covariance;
|
||||||
info->varianceAng = regInfo.varianceAng;
|
|
||||||
info->inliers = regInfo.inliers;
|
info->inliers = regInfo.inliers;
|
||||||
info->matches = regInfo.matches;
|
info->matches = regInfo.matches;
|
||||||
info->icpInliersRatio = regInfo.icpInliersRatio;
|
info->icpInliersRatio = regInfo.icpInliersRatio;
|
||||||
@@ -899,8 +898,8 @@ Transform OdometryF2M::computeTransform(
|
|||||||
nFeatures,
|
nFeatures,
|
||||||
regInfo.inliers,
|
regInfo.inliers,
|
||||||
regInfo.matches,
|
regInfo.matches,
|
||||||
regInfo.varianceLin,
|
regInfo.covariance.at<double>(0,0),
|
||||||
regInfo.varianceAng,
|
regInfo.covariance.at<double>(5,5),
|
||||||
regPipeline_->isImageRequired()?(int)map_->getWords3().size():0,
|
regPipeline_->isImageRequired()?(int)map_->getWords3().size():0,
|
||||||
regPipeline_->isScanRequired()?(int)map_->sensorData().laserScanRaw().cols:0);
|
regPipeline_->isScanRequired()?(int)map_->sensorData().laserScanRaw().cols:0);
|
||||||
|
|
||||||
|
|||||||
@@ -976,8 +976,7 @@ Transform OdometryMono::computeTransform(SensorData & data, const Transform & gu
|
|||||||
if(info)
|
if(info)
|
||||||
{
|
{
|
||||||
// a very high variance tells that the new pose is not linked with the previous one
|
// a very high variance tells that the new pose is not linked with the previous one
|
||||||
info->varianceLin = 9999;
|
info->covariance = cv::Mat::eye(6,6,CV_64FC1)*9999.0;
|
||||||
info->varianceAng = 9999;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate kpts
|
// generate kpts
|
||||||
|
|||||||
@@ -102,10 +102,8 @@ void OdometryThread::mainLoop()
|
|||||||
OdometryInfo info;
|
OdometryInfo info;
|
||||||
Transform pose = _odometry->process(data, &info);
|
Transform pose = _odometry->process(data, &info);
|
||||||
// a null pose notify that odometry could not be computed
|
// a null pose notify that odometry could not be computed
|
||||||
double varianceLin = info.varianceLin>0?info.varianceLin:1;
|
|
||||||
double varianceAng = info.varianceAng>0?info.varianceAng:1;
|
|
||||||
UDEBUG("Odom pose = %s", pose.prettyPrint().c_str());
|
UDEBUG("Odom pose = %s", pose.prettyPrint().c_str());
|
||||||
this->post(new OdometryEvent(data, pose, varianceAng, varianceLin, info));
|
this->post(new OdometryEvent(data, pose, info));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -665,10 +665,7 @@ std::map<int, Transform> OptimizerG2O::optimizeBA(
|
|||||||
UASSERT(!iter->second.transform().isNull());
|
UASSERT(!iter->second.transform().isNull());
|
||||||
|
|
||||||
Eigen::Matrix<double, 6, 6> information = Eigen::Matrix<double, 6, 6>::Identity();
|
Eigen::Matrix<double, 6, 6> information = Eigen::Matrix<double, 6, 6>::Identity();
|
||||||
if(!isCovarianceIgnored())
|
memcpy(information.data(), iter->second.infMatrix().data, iter->second.infMatrix().total()*sizeof(double));
|
||||||
{
|
|
||||||
memcpy(information.data(), iter->second.infMatrix().data, iter->second.infMatrix().total()*sizeof(double));
|
|
||||||
}
|
|
||||||
|
|
||||||
// between cameras, not base_link
|
// between cameras, not base_link
|
||||||
Transform camLink = models.at(id1).localTransform().inverse()*iter->second.transform()*models.at(id2).localTransform();
|
Transform camLink = models.at(id1).localTransform().inverse()*iter->second.transform()*models.at(id2).localTransform();
|
||||||
@@ -777,7 +774,7 @@ std::map<int, Transform> OptimizerG2O::optimizeBA(
|
|||||||
|
|
||||||
UASSERT(optimizer.verifyInformationMatrices());
|
UASSERT(optimizer.verifyInformationMatrices());
|
||||||
|
|
||||||
UINFO("g2o optimizing begin (max iterations=%d, epsilon=%f robustKernel=%f)", iterations(), this->epsilon(), robustKernelDelta_);
|
UINFO("g2o optimizing begin (max iterations=%d, robustKernel=%f)", iterations(), robustKernelDelta_);
|
||||||
|
|
||||||
int it = 0;
|
int it = 0;
|
||||||
UTimer timer;
|
UTimer timer;
|
||||||
|
|||||||
@@ -446,22 +446,20 @@ bool OptimizerTORO::loadGraph(
|
|||||||
float roll = uStr2Float(strList[6]);
|
float roll = uStr2Float(strList[6]);
|
||||||
float pitch = uStr2Float(strList[7]);
|
float pitch = uStr2Float(strList[7]);
|
||||||
float yaw = uStr2Float(strList[8]);
|
float yaw = uStr2Float(strList[8]);
|
||||||
float infR = uStr2Float(strList[9]);
|
cv::Mat informationMatrix(6,6,CV_64FC1);
|
||||||
float infP = uStr2Float(strList[15]);
|
informationMatrix.at<double>(3,3) = uStr2Float(strList[9]);
|
||||||
float infW = uStr2Float(strList[20]);
|
informationMatrix.at<double>(4,4) = uStr2Float(strList[15]);
|
||||||
UASSERT_MSG(infR > 0 && infP > 0 && infW > 0, uFormat("Information matrix should not be null! line=\"%s\"", line).c_str());
|
informationMatrix.at<double>(5,5) = uStr2Float(strList[20]);
|
||||||
float rotVariance = infR<=infP && infR<=infW?infR:infP<=infW?infP:infW; // maximum variance
|
UASSERT_MSG(informationMatrix.at<double>(3,3) > 0.0 && informationMatrix.at<double>(4,4) > 0.0 && informationMatrix.at<double>(5,5) > 0.0, uFormat("Information matrix should not be null! line=\"%s\"", line).c_str());
|
||||||
float infX = uStr2Float(strList[24]);
|
informationMatrix.at<double>(0,0) = uStr2Float(strList[24]);
|
||||||
float infY = uStr2Float(strList[27]);
|
informationMatrix.at<double>(1,1) = uStr2Float(strList[27]);
|
||||||
float infZ = uStr2Float(strList[29]);
|
informationMatrix.at<double>(2,2) = uStr2Float(strList[29]);
|
||||||
UASSERT_MSG(infX > 0 && infY > 0 && infZ > 0, uFormat("Information matrix should not be null! line=\"%s\"", line).c_str());
|
UASSERT_MSG(informationMatrix.at<double>(0,0) > 0.0 && informationMatrix.at<double>(1,1) > 0.0 && informationMatrix.at<double>(2,2) > 0.0, uFormat("Information matrix should not be null! line=\"%s\"", line).c_str());
|
||||||
float transVariance = 1.0f/(infX<=infY && infX<=infZ?infX:infY<=infW?infY:infZ); // maximum variance
|
|
||||||
UINFO("id=%d rotV=%f transV=%f", idFrom, rotVariance, transVariance);
|
|
||||||
Transform transform(x, y, z, roll, pitch, yaw);
|
Transform transform(x, y, z, roll, pitch, yaw);
|
||||||
if(poses.find(idFrom) != poses.end() && poses.find(idTo) != poses.end())
|
if(poses.find(idFrom) != poses.end() && poses.find(idTo) != poses.end())
|
||||||
{
|
{
|
||||||
//Link type is unknown
|
//Link type is unknown
|
||||||
Link link(idFrom, idTo, Link::kUndef, transform, rotVariance, transVariance);
|
Link link(idFrom, idTo, Link::kUndef, transform, informationMatrix);
|
||||||
edgeConstraints.insert(std::pair<int, Link>(idFrom, link));
|
edgeConstraints.insert(std::pair<int, Link>(idFrom, link));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -740,16 +740,19 @@ void Parameters::readINI(const std::string & configFile, ParametersMap & paramet
|
|||||||
addParameter = oldIter->second.first;
|
addParameter = oldIter->second.first;
|
||||||
if(addParameter)
|
if(addParameter)
|
||||||
{
|
{
|
||||||
key = oldIter->second.second;
|
if(parameters.find(oldIter->second.second) == parameters.end())
|
||||||
UWARN("Parameter migration from \"%s\" to \"%s\" (value=%s, default=%s).",
|
{
|
||||||
oldIter->first.c_str(), oldIter->second.second.c_str(), iter->second, Parameters::getDefaultParameters().at(oldIter->second.second).c_str());
|
key = oldIter->second.second;
|
||||||
|
UWARN("Parameter migration from \"%s\" to \"%s\" (value=%s, default=%s).",
|
||||||
|
oldIter->first.c_str(), oldIter->second.second.c_str(), iter->second, Parameters::getDefaultParameters().at(oldIter->second.second).c_str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if(oldIter->second.second.empty())
|
else if(oldIter->second.second.empty())
|
||||||
{
|
{
|
||||||
UWARN("Parameter \"%s\" doesn't exist anymore.",
|
UWARN("Parameter \"%s\" doesn't exist anymore.",
|
||||||
oldIter->first.c_str());
|
oldIter->first.c_str());
|
||||||
}
|
}
|
||||||
else
|
else if(parameters.find(oldIter->second.second) == parameters.end())
|
||||||
{
|
{
|
||||||
UWARN("Parameter \"%s\" (value=%s) doesn't exist anymore, you may want to use this similar parameter \"%s (default=%s): %s\".",
|
UWARN("Parameter \"%s\" (value=%s) doesn't exist anymore, you may want to use this similar parameter \"%s (default=%s): %s\".",
|
||||||
oldIter->first.c_str(), iter->second, oldIter->second.second.c_str(), Parameters::getDefaultParameters().at(oldIter->second.second).c_str(), Parameters::getDescription(oldIter->second.second).c_str());
|
oldIter->first.c_str(), iter->second, oldIter->second.second.c_str(), Parameters::getDefaultParameters().at(oldIter->second.second).c_str(), Parameters::getDescription(oldIter->second.second).c_str());
|
||||||
|
|||||||
@@ -197,16 +197,16 @@ Transform Registration::computeTransformationMod(
|
|||||||
{
|
{
|
||||||
if(info.icpInliersRatio)
|
if(info.icpInliersRatio)
|
||||||
{
|
{
|
||||||
info.varianceLin = info.icpInliersRatio > 0?1.0/double(info.icpInliersRatio):1.0;
|
info.covariance = cv::Mat::eye(6,6,CV_64FC1)*(info.icpInliersRatio > 0?1.0/double(info.icpInliersRatio):1.0);
|
||||||
info.varianceAng = info.icpInliersRatio > 0?1.0/double(info.icpInliersRatio):1.0;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
info.varianceLin = info.inliers > 0?1.0f/float(info.inliers):1.0f;
|
info.covariance = cv::Mat::eye(6,6,CV_64FC1)*(info.inliers > 0?1.0/double(info.inliers):1.0);
|
||||||
info.varianceAng = info.inliers > 0?1.0f/float(info.inliers):1.0f;
|
}
|
||||||
|
if(info.covariance.at<double>(0,0)<0.0001)
|
||||||
|
{
|
||||||
|
info.covariance =cv::Mat::eye(6,6,CV_64FC1)*0.0001; // epsilon if exact transform
|
||||||
}
|
}
|
||||||
info.varianceLin = info.varianceLin>0.0f?info.varianceLin:0.0001f; // epsilon if exact transform
|
|
||||||
info.varianceAng = info.varianceAng>0.0f?info.varianceAng:0.0001f; // epsilon if exact transform
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(child_)
|
if(child_)
|
||||||
|
|||||||
@@ -360,8 +360,7 @@ Transform RegistrationIcp::computeTransformationImpl(
|
|||||||
info.icpTranslation,
|
info.icpTranslation,
|
||||||
info.icpRotation);
|
info.icpRotation);
|
||||||
|
|
||||||
info.varianceLin = variance>0.0f?variance:0.0001; // epsilon if exact transform
|
info.covariance = cv::Mat::eye(6,6,CV_64FC1)*(variance>0.0001?variance:0.0001); // epsilon if exact transform
|
||||||
info.varianceAng = variance>0.0f?variance:0.0001; // epsilon if exact transform
|
|
||||||
info.icpInliersRatio = correspondencesRatio;
|
info.icpInliersRatio = correspondencesRatio;
|
||||||
|
|
||||||
if(correspondencesRatio < _correspondenceRatio)
|
if(correspondencesRatio < _correspondenceRatio)
|
||||||
|
|||||||
@@ -1045,7 +1045,7 @@ Transform RegistrationVis::computeTransformationImpl(
|
|||||||
// Motion estimation
|
// Motion estimation
|
||||||
/////////////////////
|
/////////////////////
|
||||||
Transform transform;
|
Transform transform;
|
||||||
float variance = 1.0f;
|
cv::Mat covariance = cv::Mat::eye(6,6,CV_64FC1);
|
||||||
int inliersCount = 0;
|
int inliersCount = 0;
|
||||||
int matchesCount = 0;
|
int matchesCount = 0;
|
||||||
if(toSignature.getWords().size())
|
if(toSignature.getWords().size())
|
||||||
@@ -1053,7 +1053,9 @@ Transform RegistrationVis::computeTransformationImpl(
|
|||||||
Transform transforms[2];
|
Transform transforms[2];
|
||||||
std::vector<int> inliers[2];
|
std::vector<int> inliers[2];
|
||||||
std::vector<int> matches[2];
|
std::vector<int> matches[2];
|
||||||
double variances[2] = {1.0f};
|
cv::Mat covariances[2];
|
||||||
|
covariances[0] = cv::Mat::eye(6,6,CV_64FC1);
|
||||||
|
covariances[1] = cv::Mat::eye(6,6,CV_64FC1);
|
||||||
for(int dir=0; dir<(!_forwardEstimateOnly?2:1); ++dir)
|
for(int dir=0; dir<(!_forwardEstimateOnly?2:1); ++dir)
|
||||||
{
|
{
|
||||||
// A to B
|
// A to B
|
||||||
@@ -1086,6 +1088,7 @@ Transform RegistrationVis::computeTransformationImpl(
|
|||||||
|
|
||||||
// we only need the camera transform, send guess words3 for scale estimation
|
// we only need the camera transform, send guess words3 for scale estimation
|
||||||
Transform cameraTransform;
|
Transform cameraTransform;
|
||||||
|
double variance = 1.0f;
|
||||||
std::map<int, cv::Point3f> inliers3D = util3d::generateWords3DMono(
|
std::map<int, cv::Point3f> inliers3D = util3d::generateWords3DMono(
|
||||||
uMultimapToMapUnique(signatureA->getWords()),
|
uMultimapToMapUnique(signatureA->getWords()),
|
||||||
uMultimapToMapUnique(signatureB->getWords()),
|
uMultimapToMapUnique(signatureB->getWords()),
|
||||||
@@ -1098,21 +1101,21 @@ Transform RegistrationVis::computeTransformationImpl(
|
|||||||
1.0f,
|
1.0f,
|
||||||
0.99f,
|
0.99f,
|
||||||
uMultimapToMapUnique(signatureA->getWords3()), // for scale estimation
|
uMultimapToMapUnique(signatureA->getWords3()), // for scale estimation
|
||||||
&variances[dir]);
|
&variance);
|
||||||
|
covariances[dir] *= variance;
|
||||||
inliers[dir] = uKeys(inliers3D);
|
inliers[dir] = uKeys(inliers3D);
|
||||||
|
|
||||||
if(!cameraTransform.isNull())
|
if(!cameraTransform.isNull())
|
||||||
{
|
{
|
||||||
if((int)inliers3D.size() >= _minInliers)
|
if((int)inliers3D.size() >= _minInliers)
|
||||||
{
|
{
|
||||||
if(variances[dir] <= _epipolarGeometryVar)
|
if(variance <= _epipolarGeometryVar)
|
||||||
{
|
{
|
||||||
transforms[dir] = cameraTransform;
|
transforms[dir] = cameraTransform;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
msg = uFormat("Variance is too high! (max inlier distance=%f, variance=%f)", _epipolarGeometryVar, variances[dir]);
|
msg = uFormat("Variance is too high! (max inlier distance=%f, variance=%f)", _epipolarGeometryVar, variance);
|
||||||
UINFO(msg.c_str());
|
UINFO(msg.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1175,7 +1178,7 @@ Transform RegistrationVis::computeTransformationImpl(
|
|||||||
_PnPRefineIterations,
|
_PnPRefineIterations,
|
||||||
dir==0?(!guess.isNull()?guess:Transform::getIdentity()):!transforms[0].isNull()?transforms[0].inverse():(!guess.isNull()?guess.inverse():Transform::getIdentity()),
|
dir==0?(!guess.isNull()?guess:Transform::getIdentity()):!transforms[0].isNull()?transforms[0].inverse():(!guess.isNull()?guess.inverse():Transform::getIdentity()),
|
||||||
uMultimapToMapUnique(signatureB->getWords3()),
|
uMultimapToMapUnique(signatureB->getWords3()),
|
||||||
varianceFromInliersCount()?0:&variances[dir],
|
varianceFromInliersCount()?0:&covariances[dir],
|
||||||
&matchesV,
|
&matchesV,
|
||||||
&inliersV);
|
&inliersV);
|
||||||
inliers[dir] = inliersV;
|
inliers[dir] = inliersV;
|
||||||
@@ -1212,7 +1215,7 @@ Transform RegistrationVis::computeTransformationImpl(
|
|||||||
_inlierDistance,
|
_inlierDistance,
|
||||||
_iterations,
|
_iterations,
|
||||||
_refineIterations,
|
_refineIterations,
|
||||||
&variances[dir],
|
&covariances[dir],
|
||||||
&matchesV,
|
&matchesV,
|
||||||
&inliersV);
|
&inliersV);
|
||||||
inliers[dir] = inliersV;
|
inliers[dir] = inliersV;
|
||||||
@@ -1288,10 +1291,10 @@ Transform RegistrationVis::computeTransformationImpl(
|
|||||||
poses.insert(std::make_pair(1, Transform::getIdentity()));
|
poses.insert(std::make_pair(1, Transform::getIdentity()));
|
||||||
poses.insert(std::make_pair(2, transforms[0]));
|
poses.insert(std::make_pair(2, transforms[0]));
|
||||||
|
|
||||||
links.insert(std::make_pair(1, Link(1, 2, Link::kNeighbor, transforms[0], variances[0], variances[0])));
|
links.insert(std::make_pair(1, Link(1, 2, Link::kNeighbor, transforms[0], (covariances[0]*transforms[0].getNorm()).inv())));
|
||||||
if(!transforms[1].isNull() && inliers[1].size())
|
if(!transforms[1].isNull() && inliers[1].size())
|
||||||
{
|
{
|
||||||
links.insert(std::make_pair(2, Link(2, 1, Link::kNeighbor, transforms[1], variances[1], variances[1])));
|
links.insert(std::make_pair(2, Link(2, 1, Link::kNeighbor, transforms[1], (covariances[1]*transforms[1].getNorm()).inv())));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<int, Transform> optimizedPoses;
|
std::map<int, Transform> optimizedPoses;
|
||||||
@@ -1422,18 +1425,18 @@ Transform RegistrationVis::computeTransformationImpl(
|
|||||||
if(transforms[0].isNull())
|
if(transforms[0].isNull())
|
||||||
{
|
{
|
||||||
transform = transforms[1];
|
transform = transforms[1];
|
||||||
variance = variances[1];
|
covariance = covariances[1];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
transform = transforms[0].interpolate(0.5f, transforms[1]);
|
transform = transforms[0].interpolate(0.5f, transforms[1]);
|
||||||
variance = (variances[0]+variances[1])/2.0f;
|
covariance = (covariances[0]+covariances[1])/2.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
transform = transforms[0];
|
transform = transforms[0];
|
||||||
variance = variances[0];
|
covariance = covariances[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(toSignature.sensorData().isValid())
|
else if(toSignature.sensorData().isValid())
|
||||||
@@ -1447,8 +1450,7 @@ Transform RegistrationVis::computeTransformationImpl(
|
|||||||
info.inliers = inliersCount;
|
info.inliers = inliersCount;
|
||||||
info.matches = matchesCount;
|
info.matches = matchesCount;
|
||||||
info.rejectedMsg = msg;
|
info.rejectedMsg = msg;
|
||||||
info.varianceLin = variance>0.0f?variance:0.0001f; // epsilon if exact transform
|
info.covariance = covariance.at<double>(0,0)>0.0001?covariance:cv::Mat::eye(6,6,CV_64FC1)*0.0001; // epsilon if exact transform
|
||||||
info.varianceAng = info.varianceLin;
|
|
||||||
|
|
||||||
UDEBUG("transform=%s", transform.prettyPrint().c_str());
|
UDEBUG("transform=%s", transform.prettyPrint().c_str());
|
||||||
return transform;
|
return transform;
|
||||||
|
|||||||
+49
-30
@@ -768,7 +768,8 @@ void Rtabmap::exportPoses(const std::string & path, bool optimized, bool global,
|
|||||||
int m, w;
|
int m, w;
|
||||||
std::string l;
|
std::string l;
|
||||||
double stamp = 0.0;
|
double stamp = 0.0;
|
||||||
_memory->getNodeInfo(iter->first, o, m, w, l, stamp, g, true);
|
std::vector<float> v;
|
||||||
|
_memory->getNodeInfo(iter->first, o, m, w, l, stamp, g, v, true);
|
||||||
stamps.insert(std::make_pair(iter->first, stamp));
|
stamps.insert(std::make_pair(iter->first, stamp));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -827,6 +828,7 @@ bool Rtabmap::process(
|
|||||||
Transform odomPose,
|
Transform odomPose,
|
||||||
float odomLinearVariance,
|
float odomLinearVariance,
|
||||||
float odomAngularVariance,
|
float odomAngularVariance,
|
||||||
|
const std::vector<float> & odomVelocity,
|
||||||
const std::map<std::string, float> & externalStats)
|
const std::map<std::string, float> & externalStats)
|
||||||
{
|
{
|
||||||
if(!odomPose.isNull())
|
if(!odomPose.isNull())
|
||||||
@@ -841,12 +843,13 @@ bool Rtabmap::process(
|
|||||||
covariance.at<double>(3,3) = odomAngularVariance;
|
covariance.at<double>(3,3) = odomAngularVariance;
|
||||||
covariance.at<double>(4,4) = odomAngularVariance;
|
covariance.at<double>(4,4) = odomAngularVariance;
|
||||||
covariance.at<double>(5,5) = odomAngularVariance;
|
covariance.at<double>(5,5) = odomAngularVariance;
|
||||||
return process(data, odomPose, covariance, externalStats);
|
return process(data, odomPose, covariance, odomVelocity, externalStats);
|
||||||
}
|
}
|
||||||
bool Rtabmap::process(
|
bool Rtabmap::process(
|
||||||
const SensorData & data,
|
const SensorData & data,
|
||||||
Transform odomPose,
|
Transform odomPose,
|
||||||
const cv::Mat & odomCovariance,
|
const cv::Mat & odomCovariance,
|
||||||
|
const std::vector<float> & odomVelocity,
|
||||||
const std::map<std::string, float> & externalStats)
|
const std::map<std::string, float> & externalStats)
|
||||||
{
|
{
|
||||||
UDEBUG("");
|
UDEBUG("");
|
||||||
@@ -985,14 +988,14 @@ bool Rtabmap::process(
|
|||||||
ULOGGER_INFO("Updating memory...");
|
ULOGGER_INFO("Updating memory...");
|
||||||
if(_rgbdSlamMode)
|
if(_rgbdSlamMode)
|
||||||
{
|
{
|
||||||
if(!_memory->update(data, odomPose, odomCovariance, &statistics_))
|
if(!_memory->update(data, odomPose, odomCovariance, odomVelocity, &statistics_))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(!_memory->update(data, Transform(), cv::Mat(), &statistics_))
|
if(!_memory->update(data, Transform(), cv::Mat(), std::vector<float>(), &statistics_))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1076,7 +1079,7 @@ bool Rtabmap::process(
|
|||||||
{
|
{
|
||||||
// set small variance
|
// set small variance
|
||||||
UDEBUG("Set small variance. The robot is not moving.");
|
UDEBUG("Set small variance. The robot is not moving.");
|
||||||
_memory->updateLink(Link(oldId, signature->id(), signature->getLinks().begin()->second.type(), guess, 0.0001, 0.0001));
|
_memory->updateLink(Link(oldId, signature->id(), signature->getLinks().begin()->second.type(), guess, cv::Mat::eye(6,6,CV_64FC1)*1000));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -1094,12 +1097,12 @@ bool Rtabmap::process(
|
|||||||
UINFO("Odometry refining: update neighbor link (%d->%d, variance:lin=%f, ang=%f) from %s to %s",
|
UINFO("Odometry refining: update neighbor link (%d->%d, variance:lin=%f, ang=%f) from %s to %s",
|
||||||
oldId,
|
oldId,
|
||||||
signature->id(),
|
signature->id(),
|
||||||
info.varianceLin,
|
info.covariance.at<double>(0,0),
|
||||||
info.varianceAng,
|
info.covariance.at<double>(5,5),
|
||||||
guess.prettyPrint().c_str(),
|
guess.prettyPrint().c_str(),
|
||||||
t.prettyPrint().c_str());
|
t.prettyPrint().c_str());
|
||||||
UASSERT(info.varianceLin > 0.0 && info.varianceAng > 0.0);
|
UASSERT(info.covariance.at<double>(0,0) > 0.0 && info.covariance.at<double>(5,5) > 0.0);
|
||||||
_memory->updateLink(Link(oldId, signature->id(), signature->getLinks().begin()->second.type(), t, info.varianceAng, info.varianceLin));
|
_memory->updateLink(Link(oldId, signature->id(), signature->getLinks().begin()->second.type(), t, info.covariance.inv()));
|
||||||
|
|
||||||
if(_optimizeFromGraphEnd)
|
if(_optimizeFromGraphEnd)
|
||||||
{
|
{
|
||||||
@@ -1120,9 +1123,9 @@ bool Rtabmap::process(
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
UINFO("Odometry refining rejected: %s", info.rejectedMsg.c_str());
|
UINFO("Odometry refining rejected: %s", info.rejectedMsg.c_str());
|
||||||
if(info.varianceLin > 0 && info.varianceAng > 0)
|
if(info.covariance.at<double>(0,0) > 0.0 && info.covariance.at<double>(5,5) > 0.0)
|
||||||
{
|
{
|
||||||
_memory->updateLink(Link(oldId, signature->id(), signature->getLinks().begin()->second.type(), guess, sqrt(info.varianceAng), sqrt(info.varianceLin)));
|
_memory->updateLink(Link(oldId, signature->id(), signature->getLinks().begin()->second.type(), guess, (info.covariance*100.0).inv()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
statistics_.addStatistic(Statistics::kNeighborLinkRefiningAccepted(), !t.isNull()?1.0f:0);
|
statistics_.addStatistic(Statistics::kNeighborLinkRefiningAccepted(), !t.isNull()?1.0f:0);
|
||||||
@@ -1265,8 +1268,8 @@ bool Rtabmap::process(
|
|||||||
*iter,
|
*iter,
|
||||||
transform.prettyPrint().c_str());
|
transform.prettyPrint().c_str());
|
||||||
// Add a loop constraint
|
// Add a loop constraint
|
||||||
UASSERT(info.varianceLin > 0.0 && info.varianceAng > 0.0);
|
UASSERT(info.covariance.at<double>(0,0) > 0.0 && info.covariance.at<double>(5,5) > 0.0);
|
||||||
if(_memory->addLink(Link(signature->id(), *iter, Link::kLocalTimeClosure, transform, info.varianceAng, info.varianceLin)))
|
if(_memory->addLink(Link(signature->id(), *iter, Link::kLocalTimeClosure, transform, info.covariance.inv())))
|
||||||
{
|
{
|
||||||
++proximityDetectionsInTimeFound;
|
++proximityDetectionsInTimeFound;
|
||||||
UINFO("Local loop closure found between %d and %d with t=%s",
|
UINFO("Local loop closure found between %d and %d with t=%s",
|
||||||
@@ -1822,7 +1825,7 @@ bool Rtabmap::process(
|
|||||||
//Compute transform if metric data are present
|
//Compute transform if metric data are present
|
||||||
Transform transform;
|
Transform transform;
|
||||||
RegistrationInfo info;
|
RegistrationInfo info;
|
||||||
info.varianceLin = info.varianceAng = 1.0f;
|
info.covariance = cv::Mat::eye(6,6,CV_64FC1);
|
||||||
if(_rgbdSlamMode)
|
if(_rgbdSlamMode)
|
||||||
{
|
{
|
||||||
transform = _memory->computeTransform(_loopClosureHypothesis.first, signature->id(), Transform(), &info);
|
transform = _memory->computeTransform(_loopClosureHypothesis.first, signature->id(), Transform(), &info);
|
||||||
@@ -1842,8 +1845,8 @@ bool Rtabmap::process(
|
|||||||
if(!rejectedHypothesis)
|
if(!rejectedHypothesis)
|
||||||
{
|
{
|
||||||
// Make the new one the parent of the old one
|
// Make the new one the parent of the old one
|
||||||
UASSERT(info.varianceLin > 0.0 && info.varianceAng > 0.0);
|
UASSERT(info.covariance.at<double>(0,0) > 0.0 && info.covariance.at<double>(5,5) > 0.0);
|
||||||
rejectedHypothesis = !_memory->addLink(Link(signature->id(), _loopClosureHypothesis.first, Link::kGlobalClosure, transform, info.varianceAng, info.varianceLin));
|
rejectedHypothesis = !_memory->addLink(Link(signature->id(), _loopClosureHypothesis.first, Link::kGlobalClosure, transform, info.covariance.inv()));
|
||||||
if(!rejectedHypothesis)
|
if(!rejectedHypothesis)
|
||||||
{
|
{
|
||||||
loopClosureLinksAdded.push_back(std::make_pair(signature->id(), _loopClosureHypothesis.first));
|
loopClosureLinksAdded.push_back(std::make_pair(signature->id(), _loopClosureHypothesis.first));
|
||||||
@@ -1948,8 +1951,8 @@ bool Rtabmap::process(
|
|||||||
signature->id(),
|
signature->id(),
|
||||||
nearestId,
|
nearestId,
|
||||||
transform.prettyPrint().c_str());
|
transform.prettyPrint().c_str());
|
||||||
UASSERT(info.varianceLin > 0.0 && info.varianceAng > 0.0);
|
UASSERT(info.covariance.at<double>(0,0) > 0.0 && info.covariance.at<double>(5,5) > 0.0);
|
||||||
_memory->addLink(Link(signature->id(), nearestId, Link::kLocalSpaceClosure, transform, info.varianceAng, info.varianceLin));
|
_memory->addLink(Link(signature->id(), nearestId, Link::kLocalSpaceClosure, transform, info.covariance.inv()));
|
||||||
loopClosureLinksAdded.push_back(std::make_pair(signature->id(), nearestId));
|
loopClosureLinksAdded.push_back(std::make_pair(signature->id(), nearestId));
|
||||||
|
|
||||||
if(loopClosureVisualInliers == 0)
|
if(loopClosureVisualInliers == 0)
|
||||||
@@ -2077,8 +2080,8 @@ bool Rtabmap::process(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// set Identify covariance for laser scan matching only
|
// set Identify covariance for laser scan matching only
|
||||||
UASSERT(info.varianceLin>0.0 && info.varianceAng>0.0);
|
UASSERT(info.covariance.at<double>(0,0) > 0.0 && info.covariance.at<double>(5,5) > 0.0);
|
||||||
_memory->addLink(Link(signature->id(), nearestId, Link::kLocalSpaceClosure, transform, sqrt(info.varianceAng), sqrt(info.varianceLin), scanMatchingIds));
|
_memory->addLink(Link(signature->id(), nearestId, Link::kLocalSpaceClosure, transform, (info.covariance*100.0).inv(), scanMatchingIds));
|
||||||
loopClosureLinksAdded.push_back(std::make_pair(signature->id(), nearestId));
|
loopClosureLinksAdded.push_back(std::make_pair(signature->id(), nearestId));
|
||||||
|
|
||||||
++proximityDetectionsAddedByICPOnly;
|
++proximityDetectionsAddedByICPOnly;
|
||||||
@@ -2130,7 +2133,7 @@ bool Rtabmap::process(
|
|||||||
|
|
||||||
if(_localRadius == 0.0f || virtualLoop.getNorm() < _localRadius)
|
if(_localRadius == 0.0f || virtualLoop.getNorm() < _localRadius)
|
||||||
{
|
{
|
||||||
_memory->addLink(Link(signature->id(), _path[_pathCurrentIndex].first, Link::kVirtualClosure, virtualLoop, 100, 100)); // set high variance
|
_memory->addLink(Link(signature->id(), _path[_pathCurrentIndex].first, Link::kVirtualClosure, virtualLoop, cv::Mat::eye(6,6,CV_64FC1)*0.01)); // set high variance
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -2649,8 +2652,8 @@ bool Rtabmap::process(
|
|||||||
std::string label;
|
std::string label;
|
||||||
double stamp = 0;
|
double stamp = 0;
|
||||||
Transform groundTruth;
|
Transform groundTruth;
|
||||||
std::vector<unsigned char> userData;
|
std::vector<float> velocity;
|
||||||
_memory->getNodeInfo(iter->first, odomPoseLocal, mapId, weight, label, stamp, groundTruth, false);
|
_memory->getNodeInfo(iter->first, odomPoseLocal, mapId, weight, label, stamp, groundTruth, velocity, false);
|
||||||
signatures.insert(std::make_pair(iter->first,
|
signatures.insert(std::make_pair(iter->first,
|
||||||
Signature(iter->first,
|
Signature(iter->first,
|
||||||
mapId,
|
mapId,
|
||||||
@@ -2659,6 +2662,10 @@ bool Rtabmap::process(
|
|||||||
label,
|
label,
|
||||||
odomPoseLocal,
|
odomPoseLocal,
|
||||||
groundTruth)));
|
groundTruth)));
|
||||||
|
if(!velocity.empty())
|
||||||
|
{
|
||||||
|
signatures.at(iter->first).setVelocity(velocity[0], velocity[1], velocity[2], velocity[3], velocity[4], velocity[5]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
localGraphSize = (int)poses.size();
|
localGraphSize = (int)poses.size();
|
||||||
if(!lastSignatureLocalizedPose.isNull())
|
if(!lastSignatureLocalizedPose.isNull())
|
||||||
@@ -3327,7 +3334,8 @@ void Rtabmap::get3DMap(
|
|||||||
std::string label;
|
std::string label;
|
||||||
double stamp = 0;
|
double stamp = 0;
|
||||||
Transform groundTruth;
|
Transform groundTruth;
|
||||||
_memory->getNodeInfo(*iter, odomPoseLocal, mapId, weight, label, stamp, groundTruth, true);
|
std::vector<float> velocity;
|
||||||
|
_memory->getNodeInfo(*iter, odomPoseLocal, mapId, weight, label, stamp, groundTruth, velocity, true);
|
||||||
SensorData data = _memory->getNodeData(*iter);
|
SensorData data = _memory->getNodeData(*iter);
|
||||||
data.setId(*iter);
|
data.setId(*iter);
|
||||||
std::multimap<int, cv::KeyPoint> words;
|
std::multimap<int, cv::KeyPoint> words;
|
||||||
@@ -3346,6 +3354,10 @@ void Rtabmap::get3DMap(
|
|||||||
signatures.at(*iter).setWords(words);
|
signatures.at(*iter).setWords(words);
|
||||||
signatures.at(*iter).setWords3(words3);
|
signatures.at(*iter).setWords3(words3);
|
||||||
signatures.at(*iter).setWordsDescriptors(wordsDescriptors);
|
signatures.at(*iter).setWordsDescriptors(wordsDescriptors);
|
||||||
|
if(!velocity.empty())
|
||||||
|
{
|
||||||
|
signatures.at(*iter).setVelocity(velocity[0], velocity[1], velocity[2], velocity[3], velocity[4], velocity[5]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(_memory && (_memory->getStMem().size() || _memory->getWorkingMem().size() > 1))
|
else if(_memory && (_memory->getStMem().size() || _memory->getWorkingMem().size() > 1))
|
||||||
@@ -3397,7 +3409,8 @@ void Rtabmap::getGraph(
|
|||||||
std::string label;
|
std::string label;
|
||||||
double stamp = 0;
|
double stamp = 0;
|
||||||
Transform groundTruth;
|
Transform groundTruth;
|
||||||
_memory->getNodeInfo(iter->first, odomPoseLocal, mapId, weight, label, stamp, groundTruth, global);
|
std::vector<float> velocity;
|
||||||
|
_memory->getNodeInfo(iter->first, odomPoseLocal, mapId, weight, label, stamp, groundTruth, velocity, global);
|
||||||
signatures->insert(std::make_pair(iter->first,
|
signatures->insert(std::make_pair(iter->first,
|
||||||
Signature(iter->first,
|
Signature(iter->first,
|
||||||
mapId,
|
mapId,
|
||||||
@@ -3420,6 +3433,11 @@ void Rtabmap::getGraph(
|
|||||||
_memory->getNodeCalibration(iter->first, models, stereoModel);
|
_memory->getNodeCalibration(iter->first, models, stereoModel);
|
||||||
signatures->at(iter->first).sensorData().setCameraModels(models);
|
signatures->at(iter->first).sensorData().setCameraModels(models);
|
||||||
signatures->at(iter->first).sensorData().setStereoCameraModel(stereoModel);
|
signatures->at(iter->first).sensorData().setStereoCameraModel(stereoModel);
|
||||||
|
|
||||||
|
if(!velocity.empty())
|
||||||
|
{
|
||||||
|
signatures->at(iter->first).setVelocity(velocity[0], velocity[1], velocity[2], velocity[3], velocity[4], velocity[5]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3534,7 +3552,7 @@ int Rtabmap::detectMoreLoopClosures(float clusterRadius, float clusterAngle, int
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::multimap<int, Link> linksIn = links;
|
std::multimap<int, Link> linksIn = links;
|
||||||
linksIn.insert(std::make_pair(from, Link(from, to, Link::kUserClosure, t, info.varianceAng, info.varianceLin)));
|
linksIn.insert(std::make_pair(from, Link(from, to, Link::kUserClosure, t, info.covariance.inv())));
|
||||||
const Link * maxLinearLink = 0;
|
const Link * maxLinearLink = 0;
|
||||||
const Link * maxAngularLink = 0;
|
const Link * maxAngularLink = 0;
|
||||||
float maxLinearError = 0.0f;
|
float maxLinearError = 0.0f;
|
||||||
@@ -3627,8 +3645,9 @@ int Rtabmap::detectMoreLoopClosures(float clusterRadius, float clusterAngle, int
|
|||||||
UINFO("Added new loop closure between %d and %d.", from, to);
|
UINFO("Added new loop closure between %d and %d.", from, to);
|
||||||
addedLinks.insert(from);
|
addedLinks.insert(from);
|
||||||
addedLinks.insert(to);
|
addedLinks.insert(to);
|
||||||
links.insert(std::make_pair(from, Link(from, to, Link::kUserClosure, t, info.varianceAng, info.varianceLin)));
|
cv::Mat inf = info.covariance.inv();
|
||||||
loopClosuresAdded.push_back(Link(from, to, Link::kUserClosure, t, info.varianceAng, info.varianceLin));
|
links.insert(std::make_pair(from, Link(from, to, Link::kUserClosure, t, inf)));
|
||||||
|
loopClosuresAdded.push_back(Link(from, to, Link::kUserClosure, t, inf));
|
||||||
UINFO("Detected loop closure %d->%d! (%d/%d)", from, to, i+1, (int)clusters.size());
|
UINFO("Detected loop closure %d->%d! (%d/%d)", from, to, i+1, (int)clusters.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3712,7 +3731,7 @@ int Rtabmap::refineLinks()
|
|||||||
|
|
||||||
if(!t.isNull())
|
if(!t.isNull())
|
||||||
{
|
{
|
||||||
linksRefined.push_back(Link(from, to, iter->second.type(), t, info.varianceAng, info.varianceLin));
|
linksRefined.push_back(Link(from, to, iter->second.type(), t, info.covariance.inv()));
|
||||||
UINFO("Refined link %d->%d! (%d/%d)", from, to, ++i, (int)links.size());
|
UINFO("Refined link %d->%d! (%d/%d)", from, to, ++i, (int)links.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4104,7 +4123,7 @@ void Rtabmap::updateGoalIndex()
|
|||||||
if(!s->hasLink(_path[i-1].first) && _memory->getSignature(_path[i-1].first) != 0)
|
if(!s->hasLink(_path[i-1].first) && _memory->getSignature(_path[i-1].first) != 0)
|
||||||
{
|
{
|
||||||
Transform virtualLoop = _path[i].second.inverse() * _path[i-1].second;
|
Transform virtualLoop = _path[i].second.inverse() * _path[i-1].second;
|
||||||
_memory->addLink(Link(_path[i].first, _path[i-1].first, Link::kVirtualClosure, virtualLoop, 100, 100)); // on the optimized path
|
_memory->addLink(Link(_path[i].first, _path[i-1].first, Link::kVirtualClosure, virtualLoop, cv::Mat::eye(6,6,CV_64FC1)*0.01)); // on the optimized path
|
||||||
UINFO("Added Virtual link between %d and %d", _path[i-1].first, _path[i].first);
|
UINFO("Added Virtual link between %d and %d", _path[i-1].first, _path[i].first);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,9 +51,7 @@ RtabmapThread::RtabmapThread(Rtabmap * rtabmap) :
|
|||||||
_previousStamp(0.0),
|
_previousStamp(0.0),
|
||||||
_rtabmap(rtabmap),
|
_rtabmap(rtabmap),
|
||||||
_paused(false),
|
_paused(false),
|
||||||
lastPose_(Transform::getIdentity()),
|
lastPose_(Transform::getIdentity())
|
||||||
_rotVariance(0),
|
|
||||||
_transVariance(0)
|
|
||||||
|
|
||||||
{
|
{
|
||||||
UASSERT(rtabmap != 0);
|
UASSERT(rtabmap != 0);
|
||||||
@@ -88,8 +86,7 @@ void RtabmapThread::clearBufferedData()
|
|||||||
{
|
{
|
||||||
_dataBuffer.clear();
|
_dataBuffer.clear();
|
||||||
lastPose_.setIdentity();
|
lastPose_.setIdentity();
|
||||||
_rotVariance = 0;
|
covariance_ = cv::Mat();
|
||||||
_transVariance = 0;
|
|
||||||
_previousStamp = 0;
|
_previousStamp = 0;
|
||||||
}
|
}
|
||||||
_dataMutex.unlock();
|
_dataMutex.unlock();
|
||||||
@@ -338,7 +335,9 @@ bool RtabmapThread::handleEvent(UEvent* event)
|
|||||||
{
|
{
|
||||||
if (!e->info().odomPose.isNull() || (_rtabmap->getMemory() && !_rtabmap->getMemory()->isIncremental()))
|
if (!e->info().odomPose.isNull() || (_rtabmap->getMemory() && !_rtabmap->getMemory()->isIncremental()))
|
||||||
{
|
{
|
||||||
this->addData(OdometryEvent(e->data(), e->info().odomPose, e->info().odomCovariance));
|
OdometryInfo infoCov;
|
||||||
|
infoCov.covariance = e->info().odomCovariance;
|
||||||
|
this->addData(OdometryEvent(e->data(), e->info().odomPose, infoCov));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -347,7 +346,9 @@ bool RtabmapThread::handleEvent(UEvent* event)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this->addData(OdometryEvent(e->data(), e->info().odomPose, e->info().odomCovariance));
|
OdometryInfo infoCov;
|
||||||
|
infoCov.covariance = e->info().odomCovariance;
|
||||||
|
this->addData(OdometryEvent(e->data(), e->info().odomPose, infoCov));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -531,7 +532,7 @@ void RtabmapThread::process()
|
|||||||
if(_rtabmap->getMemory())
|
if(_rtabmap->getMemory())
|
||||||
{
|
{
|
||||||
bool wasPlanning = _rtabmap->getPath().size()>0;
|
bool wasPlanning = _rtabmap->getPath().size()>0;
|
||||||
if(_rtabmap->process(data.data(), data.pose(), data.covariance()))
|
if(_rtabmap->process(data.data(), data.pose(), data.covariance(), data.velocity()))
|
||||||
{
|
{
|
||||||
Statistics stats = _rtabmap->getStatistics();
|
Statistics stats = _rtabmap->getStatistics();
|
||||||
stats.addStatistic(Statistics::kMemoryImages_buffered(), (float)_dataBuffer.size());
|
stats.addStatistic(Statistics::kMemoryImages_buffered(), (float)_dataBuffer.size());
|
||||||
@@ -569,8 +570,6 @@ void RtabmapThread::addData(const OdometryEvent & odomEvent)
|
|||||||
}
|
}
|
||||||
if(!lastPose_.isIdentity() &&
|
if(!lastPose_.isIdentity() &&
|
||||||
(odomEvent.pose().isIdentity() ||
|
(odomEvent.pose().isIdentity() ||
|
||||||
odomEvent.info().varianceLin>=9999 ||
|
|
||||||
odomEvent.info().varianceAng>=9999 ||
|
|
||||||
odomEvent.rotVariance()>=9999 ||
|
odomEvent.rotVariance()>=9999 ||
|
||||||
odomEvent.transVariance()>=9999))
|
odomEvent.transVariance()>=9999))
|
||||||
{
|
{
|
||||||
@@ -580,25 +579,21 @@ void RtabmapThread::addData(const OdometryEvent & odomEvent)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
UWARN("Odometry is reset (high variance (%f/%f >=9999 detected). Increment map id!",
|
UWARN("Odometry is reset (high variance (%f/%f >=9999 detected). Increment map id!", odomEvent.transVariance(), odomEvent.rotVariance());
|
||||||
odomEvent.info().varianceLin>odomEvent.transVariance()?odomEvent.info().varianceLin:odomEvent.transVariance(),
|
|
||||||
odomEvent.info().varianceAng>odomEvent.rotVariance()?odomEvent.info().varianceAng:odomEvent.rotVariance());
|
|
||||||
}
|
}
|
||||||
pushNewState(kStateTriggeringMap);
|
pushNewState(kStateTriggeringMap);
|
||||||
_rotVariance = 0;
|
covariance_ = cv::Mat();
|
||||||
_transVariance = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double maxRotVar = odomEvent.rotVariance();
|
double maxRotVar = odomEvent.rotVariance();
|
||||||
double maxTransVar = odomEvent.transVariance();
|
double maxTransVar = odomEvent.transVariance();
|
||||||
// FIXME: should merge the transformations/variances like Link::merge();
|
if(maxRotVar != 1.0f && maxTransVar != 1.0f && !covariance_.empty())
|
||||||
if(maxRotVar != 1.0f)
|
|
||||||
{
|
{
|
||||||
_rotVariance += maxRotVar;
|
covariance_ = (covariance_.inv() + odomEvent.covariance().inv()).inv();
|
||||||
}
|
}
|
||||||
if(maxTransVar != 1.0f)
|
else
|
||||||
{
|
{
|
||||||
_transVariance += maxTransVar;
|
covariance_ = odomEvent.covariance();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ignoreFrame && !_createIntermediateNodes)
|
if(ignoreFrame && !_createIntermediateNodes)
|
||||||
@@ -614,31 +609,28 @@ void RtabmapThread::addData(const OdometryEvent & odomEvent)
|
|||||||
lastPose_ = odomEvent.pose();
|
lastPose_ = odomEvent.pose();
|
||||||
|
|
||||||
bool notify = true;
|
bool notify = true;
|
||||||
|
|
||||||
if(_rotVariance <= 0)
|
if(covariance_.empty())
|
||||||
{
|
{
|
||||||
_rotVariance = 1.0;
|
covariance_ = cv::Mat::eye(6,6,CV_64FC1);
|
||||||
}
|
|
||||||
if(_transVariance <= 0)
|
|
||||||
{
|
|
||||||
_transVariance = 1.0;
|
|
||||||
}
|
}
|
||||||
|
OdometryInfo odomInfo = odomEvent.info().copyWithoutData();
|
||||||
|
odomInfo.covariance = covariance_;
|
||||||
if(ignoreFrame)
|
if(ignoreFrame)
|
||||||
{
|
{
|
||||||
// set negative id so rtabmap will detect it as an intermediate node
|
// set negative id so rtabmap will detect it as an intermediate node
|
||||||
SensorData tmp = odomEvent.data();
|
SensorData tmp = odomEvent.data();
|
||||||
tmp.setId(-1);
|
tmp.setId(-1);
|
||||||
tmp.setFeatures(std::vector<cv::KeyPoint>(), std::vector<cv::Point3f>(), cv::Mat());// remove features
|
tmp.setFeatures(std::vector<cv::KeyPoint>(), std::vector<cv::Point3f>(), cv::Mat());// remove features
|
||||||
_dataBuffer.push_back(OdometryEvent(tmp, odomEvent.pose(), _rotVariance, _transVariance));
|
_dataBuffer.push_back(OdometryEvent(tmp, odomEvent.pose(), odomInfo));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_dataBuffer.push_back(OdometryEvent(odomEvent.data(), odomEvent.pose(), _rotVariance, _transVariance));
|
_dataBuffer.push_back(OdometryEvent(odomEvent.data(), odomEvent.pose(), odomInfo));
|
||||||
}
|
}
|
||||||
UINFO("Added data %d (variance=%f)", odomEvent.data().id(), _rotVariance);
|
UINFO("Added data %d", odomEvent.data().id());
|
||||||
|
|
||||||
_rotVariance = 0;
|
covariance_ = cv::Mat();
|
||||||
_transVariance = 0;
|
|
||||||
while(_dataBufferMaxSize > 0 && _dataBuffer.size() > _dataBufferMaxSize)
|
while(_dataBufferMaxSize > 0 && _dataBuffer.size() > _dataBufferMaxSize)
|
||||||
{
|
{
|
||||||
if(_rate > 0.0f)
|
if(_rate > 0.0f)
|
||||||
|
|||||||
@@ -18,8 +18,9 @@ CREATE TABLE Node (
|
|||||||
map_id INTEGER NOT NULL,
|
map_id INTEGER NOT NULL,
|
||||||
weight INTEGER,
|
weight INTEGER,
|
||||||
stamp FLOAT,
|
stamp FLOAT,
|
||||||
pose BLOB,
|
pose BLOB, -- 3x4 float
|
||||||
ground_truth_pose BLOB,
|
ground_truth_pose BLOB, -- 3x4 float
|
||||||
|
velocity BLOB, -- 6 float (vx,vy,vz,vroll,vpitch,vyaw) m/s and rad/s
|
||||||
label TEXT,
|
label TEXT,
|
||||||
|
|
||||||
time_enter DATE,
|
time_enter DATE,
|
||||||
@@ -51,9 +52,8 @@ CREATE TABLE Link (
|
|||||||
from_id INTEGER NOT NULL,
|
from_id INTEGER NOT NULL,
|
||||||
to_id INTEGER NOT NULL,
|
to_id INTEGER NOT NULL,
|
||||||
type INTEGER NOT NULL, -- neighbor=0, loop=1, child=2
|
type INTEGER NOT NULL, -- neighbor=0, loop=1, child=2
|
||||||
rot_variance FLOAT NOT NULL,
|
information_matrix BLOB NOT NULL, -- 6x6 double (inverse covariance)
|
||||||
trans_variance FLOAT NOT NULL,
|
transform BLOB, -- 3x4 float
|
||||||
transform BLOB,
|
|
||||||
user_data BLOB, -- compressed data (User data)
|
user_data BLOB, -- compressed data (User data)
|
||||||
FOREIGN KEY (from_id) REFERENCES Node(id),
|
FOREIGN KEY (from_id) REFERENCES Node(id),
|
||||||
FOREIGN KEY (to_id) REFERENCES Node(id)
|
FOREIGN KEY (to_id) REFERENCES Node(id)
|
||||||
@@ -68,7 +68,7 @@ CREATE TABLE Word (
|
|||||||
PRIMARY KEY (id)
|
PRIMARY KEY (id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE Map_Node_Word (
|
CREATE TABLE Feature (
|
||||||
node_id INTEGER NOT NULL,
|
node_id INTEGER NOT NULL,
|
||||||
word_id INTEGER NOT NULL,
|
word_id INTEGER NOT NULL,
|
||||||
pos_x FLOAT NOT NULL,
|
pos_x FLOAT NOT NULL,
|
||||||
@@ -111,10 +111,10 @@ CREATE TABLE Admin (
|
|||||||
-- *******************************************************************
|
-- *******************************************************************
|
||||||
-- TRIGGERS
|
-- TRIGGERS
|
||||||
-- *******************************************************************
|
-- *******************************************************************
|
||||||
CREATE TRIGGER insert_Map_Node_Word BEFORE INSERT ON Map_Node_Word
|
CREATE TRIGGER insert_Feature BEFORE INSERT ON Feature
|
||||||
WHEN NOT EXISTS (SELECT Node.id FROM Node WHERE Node.id = NEW.node_id)
|
WHEN NOT EXISTS (SELECT Node.id FROM Node WHERE Node.id = NEW.node_id)
|
||||||
BEGIN
|
BEGIN
|
||||||
SELECT RAISE(ABORT, 'Foreign key constraint failed in Map_Node_Word table');
|
SELECT RAISE(ABORT, 'Foreign key constraint failed in Feature table');
|
||||||
END;
|
END;
|
||||||
|
|
||||||
-- Creating a trigger for time_enter
|
-- Creating a trigger for time_enter
|
||||||
@@ -137,7 +137,7 @@ END;
|
|||||||
-- INDEXES
|
-- INDEXES
|
||||||
-- *******************************************************************
|
-- *******************************************************************
|
||||||
CREATE UNIQUE INDEX IDX_Node_id on Node (id);
|
CREATE UNIQUE INDEX IDX_Node_id on Node (id);
|
||||||
CREATE INDEX IDX_Map_Node_Word_node_id on Map_Node_Word (node_id);
|
CREATE INDEX IDX_Feature_node_id on Feature (node_id);
|
||||||
CREATE INDEX IDX_Link_from_id on Link (from_id);
|
CREATE INDEX IDX_Link_from_id on Link (from_id);
|
||||||
CREATE UNIQUE INDEX IDX_node_label on Node (label);
|
CREATE UNIQUE INDEX IDX_node_label on Node (label);
|
||||||
CREATE UNIQUE INDEX IDX_Statistics_id on Statistics (id);
|
CREATE UNIQUE INDEX IDX_Statistics_id on Statistics (id);
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ Transform estimateMotion3DTo2D(
|
|||||||
int refineIterations,
|
int refineIterations,
|
||||||
const Transform & guess,
|
const Transform & guess,
|
||||||
const std::map<int, cv::Point3f> & words3B,
|
const std::map<int, cv::Point3f> & words3B,
|
||||||
double * varianceOut,
|
cv::Mat * covariance,
|
||||||
std::vector<int> * matchesOut,
|
std::vector<int> * matchesOut,
|
||||||
std::vector<int> * inliersOut)
|
std::vector<int> * inliersOut)
|
||||||
{
|
{
|
||||||
@@ -65,9 +65,9 @@ Transform estimateMotion3DTo2D(
|
|||||||
Transform transform;
|
Transform transform;
|
||||||
std::vector<int> matches, inliers;
|
std::vector<int> matches, inliers;
|
||||||
|
|
||||||
if(varianceOut)
|
if(covariance)
|
||||||
{
|
{
|
||||||
*varianceOut = 1.0;
|
*covariance = cv::Mat::eye(6,6,CV_64FC1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// find correspondences
|
// find correspondences
|
||||||
@@ -138,7 +138,7 @@ Transform estimateMotion3DTo2D(
|
|||||||
transform = (cameraModel.localTransform() * pnp).inverse();
|
transform = (cameraModel.localTransform() * pnp).inverse();
|
||||||
|
|
||||||
// compute variance (like in PCL computeVariance() method of sac_model.h)
|
// compute variance (like in PCL computeVariance() method of sac_model.h)
|
||||||
if(varianceOut && words3B.size())
|
if(covariance && words3B.size())
|
||||||
{
|
{
|
||||||
std::vector<float> errorSqrdDists(inliers.size());
|
std::vector<float> errorSqrdDists(inliers.size());
|
||||||
oi = 0;
|
oi = 0;
|
||||||
@@ -162,10 +162,10 @@ Transform estimateMotion3DTo2D(
|
|||||||
{
|
{
|
||||||
std::sort(errorSqrdDists.begin(), errorSqrdDists.end());
|
std::sort(errorSqrdDists.begin(), errorSqrdDists.end());
|
||||||
double median_error_sqr = (double)errorSqrdDists[errorSqrdDists.size () >> 1];
|
double median_error_sqr = (double)errorSqrdDists[errorSqrdDists.size () >> 1];
|
||||||
*varianceOut = 2.1981 * median_error_sqr;
|
*covariance *= 2.1981 * median_error_sqr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(varianceOut)
|
else if(covariance)
|
||||||
{
|
{
|
||||||
// compute variance, which is the rms of reprojection errors
|
// compute variance, which is the rms of reprojection errors
|
||||||
std::vector<cv::Point2f> imagePointsReproj;
|
std::vector<cv::Point2f> imagePointsReproj;
|
||||||
@@ -175,7 +175,7 @@ Transform estimateMotion3DTo2D(
|
|||||||
{
|
{
|
||||||
err += uNormSquared(imagePoints.at(inliers[i]).x - imagePointsReproj.at(inliers[i]).x, imagePoints.at(inliers[i]).y - imagePointsReproj.at(inliers[i]).y);
|
err += uNormSquared(imagePoints.at(inliers[i]).x - imagePointsReproj.at(inliers[i]).x, imagePoints.at(inliers[i]).y - imagePointsReproj.at(inliers[i]).y);
|
||||||
}
|
}
|
||||||
*varianceOut = std::sqrt(err/float(inliers.size()));
|
*covariance *= std::sqrt(err/float(inliers.size()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -203,7 +203,7 @@ Transform estimateMotion3DTo3D(
|
|||||||
double inliersDistance,
|
double inliersDistance,
|
||||||
int iterations,
|
int iterations,
|
||||||
int refineIterations,
|
int refineIterations,
|
||||||
double * varianceOut,
|
cv::Mat * covariance,
|
||||||
std::vector<int> * matchesOut,
|
std::vector<int> * matchesOut,
|
||||||
std::vector<int> * inliersOut)
|
std::vector<int> * inliersOut)
|
||||||
{
|
{
|
||||||
@@ -222,9 +222,9 @@ Transform estimateMotion3DTo3D(
|
|||||||
UASSERT(inliers1.size() == inliers2.size());
|
UASSERT(inliers1.size() == inliers2.size());
|
||||||
UDEBUG("Unique correspondences = %d", (int)inliers1.size());
|
UDEBUG("Unique correspondences = %d", (int)inliers1.size());
|
||||||
|
|
||||||
if(varianceOut)
|
if(covariance)
|
||||||
{
|
{
|
||||||
*varianceOut = 1.0;
|
*covariance = cv::Mat::eye(6,6,CV_64FC1);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<int> inliers;
|
std::vector<int> inliers;
|
||||||
@@ -251,7 +251,7 @@ Transform estimateMotion3DTo3D(
|
|||||||
refineIterations,
|
refineIterations,
|
||||||
3.0,
|
3.0,
|
||||||
&inliers,
|
&inliers,
|
||||||
varianceOut);
|
covariance);
|
||||||
|
|
||||||
if(!t.isNull() && (int)inliers.size() >= minInliers)
|
if(!t.isNull() && (int)inliers.size() >= minInliers)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -66,15 +66,15 @@ Transform transformFromXYZCorrespondences(
|
|||||||
int refineIterations,
|
int refineIterations,
|
||||||
double refineSigma,
|
double refineSigma,
|
||||||
std::vector<int> * inliersOut,
|
std::vector<int> * inliersOut,
|
||||||
double * varianceOut)
|
cv::Mat * covariance)
|
||||||
{
|
{
|
||||||
//NOTE: this method is a mix of two methods:
|
//NOTE: this method is a mix of two methods:
|
||||||
// - getRemainingCorrespondences() in pcl/registration/impl/correspondence_rejection_sample_consensus.hpp
|
// - getRemainingCorrespondences() in pcl/registration/impl/correspondence_rejection_sample_consensus.hpp
|
||||||
// - refineModel() in pcl/sample_consensus/sac.h
|
// - refineModel() in pcl/sample_consensus/sac.h
|
||||||
|
|
||||||
if(varianceOut)
|
if(covariance)
|
||||||
{
|
{
|
||||||
*varianceOut = 1.0;
|
*covariance = cv::Mat::eye(6,6,CV_64FC1);
|
||||||
}
|
}
|
||||||
Transform transform;
|
Transform transform;
|
||||||
if(cloud1->size() >=3 && cloud1->size() == cloud2->size())
|
if(cloud1->size() >=3 && cloud1->size() == cloud2->size())
|
||||||
@@ -199,9 +199,9 @@ Transform transformFromXYZCorrespondences(
|
|||||||
{
|
{
|
||||||
*inliersOut = inliers;
|
*inliersOut = inliers;
|
||||||
}
|
}
|
||||||
if(varianceOut)
|
if(covariance)
|
||||||
{
|
{
|
||||||
*varianceOut = model->computeVariance();
|
*covariance *= model->computeVariance();
|
||||||
}
|
}
|
||||||
|
|
||||||
// get best transformation
|
// get best transformation
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
#include <pcl/point_types.h>
|
#include <pcl/point_types.h>
|
||||||
|
|
||||||
#include <rtabmap/core/Link.h>
|
#include <rtabmap/core/Link.h>
|
||||||
|
#include <rtabmap/core/Signature.h>
|
||||||
|
|
||||||
class Ui_DatabaseViewer;
|
class Ui_DatabaseViewer;
|
||||||
class QGraphicsScene;
|
class QGraphicsScene;
|
||||||
@@ -88,9 +89,12 @@ private slots:
|
|||||||
void generateGraph();
|
void generateGraph();
|
||||||
void exportDatabase();
|
void exportDatabase();
|
||||||
void extractImages();
|
void extractImages();
|
||||||
|
void exportPosesRaw();
|
||||||
|
void exportPosesRGBDSLAM();
|
||||||
|
void exportPosesKITTI();
|
||||||
|
void exportPosesTORO();
|
||||||
|
void exportPosesG2O();
|
||||||
void generateLocalGraph();
|
void generateLocalGraph();
|
||||||
void generateTOROGraph();
|
|
||||||
void generateG2OGraph();
|
|
||||||
void regenerateLocalMaps();
|
void regenerateLocalMaps();
|
||||||
void regenerateCurrentLocalMaps();
|
void regenerateCurrentLocalMaps();
|
||||||
void view3DMap();
|
void view3DMap();
|
||||||
@@ -145,10 +149,8 @@ private:
|
|||||||
void updateConstraintView(
|
void updateConstraintView(
|
||||||
const rtabmap::Link & link,
|
const rtabmap::Link & link,
|
||||||
bool updateImageSliders = true,
|
bool updateImageSliders = true,
|
||||||
const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloudFrom = pcl::PointCloud<pcl::PointXYZ>::Ptr(new pcl::PointCloud<pcl::PointXYZ>),
|
const Signature & signatureFrom = Signature(0),
|
||||||
const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloudTo = pcl::PointCloud<pcl::PointXYZ>::Ptr(new pcl::PointCloud<pcl::PointXYZ>),
|
const Signature & signatureTo = Signature(0));
|
||||||
const pcl::PointCloud<pcl::PointXYZ>::Ptr & scanFrom = pcl::PointCloud<pcl::PointXYZ>::Ptr(new pcl::PointCloud<pcl::PointXYZ>),
|
|
||||||
const pcl::PointCloud<pcl::PointXYZ>::Ptr & scanTo = pcl::PointCloud<pcl::PointXYZ>::Ptr(new pcl::PointCloud<pcl::PointXYZ>));
|
|
||||||
void updateConstraintButtons();
|
void updateConstraintButtons();
|
||||||
Link findActiveLink(int from, int to);
|
Link findActiveLink(int from, int to);
|
||||||
bool containsLink(
|
bool containsLink(
|
||||||
@@ -160,6 +162,7 @@ private:
|
|||||||
void updateLoopClosuresSlider(int from = 0, int to = 0);
|
void updateLoopClosuresSlider(int from = 0, int to = 0);
|
||||||
void refineConstraint(int from, int to, bool silent);
|
void refineConstraint(int from, int to, bool silent);
|
||||||
bool addConstraint(int from, int to, bool silent);
|
bool addConstraint(int from, int to, bool silent);
|
||||||
|
void exportPoses(int format);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui_DatabaseViewer * ui_;
|
Ui_DatabaseViewer * ui_;
|
||||||
|
|||||||
+423
-437
File diff suppressed because it is too large
Load Diff
+17
-14
@@ -811,10 +811,12 @@ bool MainWindow::handleEvent(UEvent* anEvent)
|
|||||||
emit cameraInfoReceived(cameraEvent->info());
|
emit cameraInfoReceived(cameraEvent->info());
|
||||||
if (_odomThread == 0 && _camera->camera()->odomProvided() && _preferencesDialog->isRGBDMode())
|
if (_odomThread == 0 && _camera->camera()->odomProvided() && _preferencesDialog->isRGBDMode())
|
||||||
{
|
{
|
||||||
|
OdometryInfo odomInfo;
|
||||||
|
odomInfo.covariance = cameraEvent->info().odomCovariance;
|
||||||
if (!_processingOdometry && !_processingStatistics)
|
if (!_processingOdometry && !_processingStatistics)
|
||||||
{
|
{
|
||||||
_processingOdometry = true; // if we receive too many odometry events!
|
_processingOdometry = true; // if we receive too many odometry events!
|
||||||
OdometryEvent tmp(cameraEvent->data(), cameraEvent->info().odomPose, cameraEvent->info().odomCovariance);
|
OdometryEvent tmp(cameraEvent->data(), cameraEvent->info().odomPose, odomInfo);
|
||||||
emit odometryReceived(tmp, false);
|
emit odometryReceived(tmp, false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -824,7 +826,7 @@ bool MainWindow::handleEvent(UEvent* anEvent)
|
|||||||
data.setCameraModels(cameraEvent->data().cameraModels());
|
data.setCameraModels(cameraEvent->data().cameraModels());
|
||||||
data.setStereoCameraModel(cameraEvent->data().stereoCameraModel());
|
data.setStereoCameraModel(cameraEvent->data().stereoCameraModel());
|
||||||
data.setGroundTruth(cameraEvent->data().groundTruth());
|
data.setGroundTruth(cameraEvent->data().groundTruth());
|
||||||
OdometryEvent tmp(data, cameraEvent->info().odomPose, cameraEvent->info().odomCovariance);
|
OdometryEvent tmp(data, cameraEvent->info().odomPose, odomInfo);
|
||||||
emit odometryReceived(tmp, true);
|
emit odometryReceived(tmp, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -845,7 +847,7 @@ bool MainWindow::handleEvent(UEvent* anEvent)
|
|||||||
data.setCameraModels(odomEvent->data().cameraModels());
|
data.setCameraModels(odomEvent->data().cameraModels());
|
||||||
data.setStereoCameraModel(odomEvent->data().stereoCameraModel());
|
data.setStereoCameraModel(odomEvent->data().stereoCameraModel());
|
||||||
data.setGroundTruth(odomEvent->data().groundTruth());
|
data.setGroundTruth(odomEvent->data().groundTruth());
|
||||||
OdometryEvent tmp(data, odomEvent->pose(), odomEvent->covariance(), odomEvent->info().copyWithoutData());
|
OdometryEvent tmp(data, odomEvent->pose(), odomEvent->info().copyWithoutData());
|
||||||
emit odometryReceived(tmp, true);
|
emit odometryReceived(tmp, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1302,10 +1304,10 @@ void MainWindow::processOdometry(const rtabmap::OdometryEvent & odom, bool dataI
|
|||||||
_ui->statsToolBox->updateStat("Odometry/ICPInliersRatio/", _preferencesDialog->isTimeUsedInFigures()?odom.data().stamp()-_firstStamp:(float)odom.data().id(), (float)odom.info().icpInliersRatio, _preferencesDialog->isCacheSavedInFigures());
|
_ui->statsToolBox->updateStat("Odometry/ICPInliersRatio/", _preferencesDialog->isTimeUsedInFigures()?odom.data().stamp()-_firstStamp:(float)odom.data().id(), (float)odom.info().icpInliersRatio, _preferencesDialog->isCacheSavedInFigures());
|
||||||
_ui->statsToolBox->updateStat("Odometry/Matches/", _preferencesDialog->isTimeUsedInFigures()?odom.data().stamp()-_firstStamp:(float)odom.data().id(), (float)odom.info().matches, _preferencesDialog->isCacheSavedInFigures());
|
_ui->statsToolBox->updateStat("Odometry/Matches/", _preferencesDialog->isTimeUsedInFigures()?odom.data().stamp()-_firstStamp:(float)odom.data().id(), (float)odom.info().matches, _preferencesDialog->isCacheSavedInFigures());
|
||||||
_ui->statsToolBox->updateStat("Odometry/MatchesRatio/", _preferencesDialog->isTimeUsedInFigures()?odom.data().stamp()-_firstStamp:(float)odom.data().id(), odom.info().features<=0?0.0f:float(odom.info().matches)/float(odom.info().features), _preferencesDialog->isCacheSavedInFigures());
|
_ui->statsToolBox->updateStat("Odometry/MatchesRatio/", _preferencesDialog->isTimeUsedInFigures()?odom.data().stamp()-_firstStamp:(float)odom.data().id(), odom.info().features<=0?0.0f:float(odom.info().matches)/float(odom.info().features), _preferencesDialog->isCacheSavedInFigures());
|
||||||
_ui->statsToolBox->updateStat("Odometry/StdDevLin/", _preferencesDialog->isTimeUsedInFigures()?odom.data().stamp()-_firstStamp:(float)odom.data().id(), sqrt((float)odom.info().varianceLin), _preferencesDialog->isCacheSavedInFigures());
|
_ui->statsToolBox->updateStat("Odometry/StdDevLin/", _preferencesDialog->isTimeUsedInFigures()?odom.data().stamp()-_firstStamp:(float)odom.data().id(), sqrt((float)odom.info().covariance.at<double>(0,0)), _preferencesDialog->isCacheSavedInFigures());
|
||||||
_ui->statsToolBox->updateStat("Odometry/VarianceLin/", _preferencesDialog->isTimeUsedInFigures()?odom.data().stamp()-_firstStamp:(float)odom.data().id(), (float)odom.info().varianceLin, _preferencesDialog->isCacheSavedInFigures());
|
_ui->statsToolBox->updateStat("Odometry/VarianceLin/", _preferencesDialog->isTimeUsedInFigures()?odom.data().stamp()-_firstStamp:(float)odom.data().id(), (float)odom.info().covariance.at<double>(0,0), _preferencesDialog->isCacheSavedInFigures());
|
||||||
_ui->statsToolBox->updateStat("Odometry/StdDevAng/", _preferencesDialog->isTimeUsedInFigures()?odom.data().stamp()-_firstStamp:(float)odom.data().id(), sqrt((float)odom.info().varianceAng), _preferencesDialog->isCacheSavedInFigures());
|
_ui->statsToolBox->updateStat("Odometry/StdDevAng/", _preferencesDialog->isTimeUsedInFigures()?odom.data().stamp()-_firstStamp:(float)odom.data().id(), sqrt((float)odom.info().covariance.at<double>(5,5)), _preferencesDialog->isCacheSavedInFigures());
|
||||||
_ui->statsToolBox->updateStat("Odometry/VarianceAng/", _preferencesDialog->isTimeUsedInFigures()?odom.data().stamp()-_firstStamp:(float)odom.data().id(), (float)odom.info().varianceAng, _preferencesDialog->isCacheSavedInFigures());
|
_ui->statsToolBox->updateStat("Odometry/VarianceAng/", _preferencesDialog->isTimeUsedInFigures()?odom.data().stamp()-_firstStamp:(float)odom.data().id(), (float)odom.info().covariance.at<double>(5,5), _preferencesDialog->isCacheSavedInFigures());
|
||||||
_ui->statsToolBox->updateStat("Odometry/TimeEstimation/ms", _preferencesDialog->isTimeUsedInFigures()?odom.data().stamp()-_firstStamp:(float)odom.data().id(), (float)odom.info().timeEstimation*1000.0f, _preferencesDialog->isCacheSavedInFigures());
|
_ui->statsToolBox->updateStat("Odometry/TimeEstimation/ms", _preferencesDialog->isTimeUsedInFigures()?odom.data().stamp()-_firstStamp:(float)odom.data().id(), (float)odom.info().timeEstimation*1000.0f, _preferencesDialog->isCacheSavedInFigures());
|
||||||
_ui->statsToolBox->updateStat("Odometry/TimeFiltering/ms", _preferencesDialog->isTimeUsedInFigures()?odom.data().stamp()-_firstStamp:(float)odom.data().id(), (float)odom.info().timeParticleFiltering*1000.0f, _preferencesDialog->isCacheSavedInFigures());
|
_ui->statsToolBox->updateStat("Odometry/TimeFiltering/ms", _preferencesDialog->isTimeUsedInFigures()?odom.data().stamp()-_firstStamp:(float)odom.data().id(), (float)odom.info().timeParticleFiltering*1000.0f, _preferencesDialog->isCacheSavedInFigures());
|
||||||
_ui->statsToolBox->updateStat("Odometry/Features/", _preferencesDialog->isTimeUsedInFigures()?odom.data().stamp()-_firstStamp:(float)odom.data().id(), (float)odom.info().features, _preferencesDialog->isCacheSavedInFigures());
|
_ui->statsToolBox->updateStat("Odometry/Features/", _preferencesDialog->isTimeUsedInFigures()?odom.data().stamp()-_firstStamp:(float)odom.data().id(), (float)odom.info().features, _preferencesDialog->isCacheSavedInFigures());
|
||||||
@@ -5068,10 +5070,11 @@ void MainWindow::postProcessing()
|
|||||||
if(!transform.isIdentity())
|
if(!transform.isIdentity())
|
||||||
{
|
{
|
||||||
// normalize variance
|
// normalize variance
|
||||||
info.varianceLin *= transform.getNorm();
|
info.covariance *= transform.getNorm();
|
||||||
info.varianceAng *= transform.getAngle();
|
if(info.covariance.at<double>(0,0)<=0.0)
|
||||||
info.varianceLin = info.varianceLin>0.0f?info.varianceLin:0.0001f; // epsilon if exact transform
|
{
|
||||||
info.varianceAng = info.varianceAng>0.0f?info.varianceAng:0.0001f; // epsilon if exact transform
|
info.covariance = cv::Mat::eye(6,6,CV_64FC1)*0.0001; // epsilon if exact transform
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//optimize the graph to see if the new constraint is globally valid
|
//optimize the graph to see if the new constraint is globally valid
|
||||||
@@ -5090,7 +5093,7 @@ void MainWindow::postProcessing()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::multimap<int, Link> linksIn = _currentLinksMap;
|
std::multimap<int, Link> linksIn = _currentLinksMap;
|
||||||
linksIn.insert(std::make_pair(from, Link(from, to, Link::kUserClosure, transform, info.varianceAng, info.varianceLin)));
|
linksIn.insert(std::make_pair(from, Link(from, to, Link::kUserClosure, transform, info.covariance.inv())));
|
||||||
const Link * maxLinearLink = 0;
|
const Link * maxLinearLink = 0;
|
||||||
const Link * maxAngularLink = 0;
|
const Link * maxAngularLink = 0;
|
||||||
float maxLinearError = 0.0f;
|
float maxLinearError = 0.0f;
|
||||||
@@ -5186,7 +5189,7 @@ void MainWindow::postProcessing()
|
|||||||
addedLinks.insert(from);
|
addedLinks.insert(from);
|
||||||
addedLinks.insert(to);
|
addedLinks.insert(to);
|
||||||
|
|
||||||
_currentLinksMap.insert(std::make_pair(from, Link(from, to, Link::kUserClosure, transform, info.varianceAng, info.varianceLin)));
|
_currentLinksMap.insert(std::make_pair(from, Link(from, to, Link::kUserClosure, transform, info.covariance.inv())));
|
||||||
++loopClosuresAdded;
|
++loopClosuresAdded;
|
||||||
_initProgressDialog->appendText(tr("Detected loop closure %1->%2! (%3/%4)").arg(from).arg(to).arg(i+1).arg(clusters.size()));
|
_initProgressDialog->appendText(tr("Detected loop closure %1->%2! (%3/%4)").arg(from).arg(to).arg(i+1).arg(clusters.size()));
|
||||||
QApplication::processEvents();
|
QApplication::processEvents();
|
||||||
@@ -5282,7 +5285,7 @@ void MainWindow::postProcessing()
|
|||||||
|
|
||||||
if(!transform.isNull())
|
if(!transform.isNull())
|
||||||
{
|
{
|
||||||
Link newLink(from, to, iter->second.type(), transform, info.varianceAng, info.varianceLin);
|
Link newLink(from, to, iter->second.type(), transform, info.covariance.inv());
|
||||||
iter->second = newLink;
|
iter->second = newLink;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -613,6 +613,7 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
|
|||||||
// Memory
|
// Memory
|
||||||
_ui->general_checkBox_keepRawData->setObjectName(Parameters::kMemImageKept().c_str());
|
_ui->general_checkBox_keepRawData->setObjectName(Parameters::kMemImageKept().c_str());
|
||||||
_ui->general_checkBox_keepBinaryData->setObjectName(Parameters::kMemBinDataKept().c_str());
|
_ui->general_checkBox_keepBinaryData->setObjectName(Parameters::kMemBinDataKept().c_str());
|
||||||
|
_ui->general_checkBox_saveIntermediateNodeData->setObjectName(Parameters::kMemIntermediateNodeDataKept().c_str());
|
||||||
_ui->general_checkBox_keepDescriptors->setObjectName(Parameters::kMemRawDescriptorsKept().c_str());
|
_ui->general_checkBox_keepDescriptors->setObjectName(Parameters::kMemRawDescriptorsKept().c_str());
|
||||||
_ui->general_checkBox_saveDepth16bits->setObjectName(Parameters::kMemSaveDepth16Format().c_str());
|
_ui->general_checkBox_saveDepth16bits->setObjectName(Parameters::kMemSaveDepth16Format().c_str());
|
||||||
_ui->general_checkBox_compressionParallelized->setObjectName(Parameters::kMemCompressionParallelized().c_str());
|
_ui->general_checkBox_compressionParallelized->setObjectName(Parameters::kMemCompressionParallelized().c_str());
|
||||||
|
|||||||
@@ -319,6 +319,10 @@ void StatsToolBox::updateStat(const QString & statFullName, const std::vector<fl
|
|||||||
grp = list.at(0);
|
grp = list.at(0);
|
||||||
name = list.at(1);
|
name = list.at(1);
|
||||||
unit = list.at(2);
|
unit = list.at(2);
|
||||||
|
for(int i=3; i<list.size(); ++i)
|
||||||
|
{
|
||||||
|
unit += "/" + list.at(i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if(list.size() == 2)
|
else if(list.size() == 2)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -52,8 +52,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>381</width>
|
<width>408</width>
|
||||||
<height>196</height>
|
<height>208</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout" columnstretch="0,1">
|
<layout class="QGridLayout" name="gridLayout" columnstretch="0,1">
|
||||||
@@ -210,8 +210,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>381</width>
|
<width>408</width>
|
||||||
<height>196</height>
|
<height>208</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout_2" columnstretch="0,1">
|
<layout class="QGridLayout" name="gridLayout_2" columnstretch="0,1">
|
||||||
@@ -484,13 +484,23 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>1547</width>
|
<width>1547</width>
|
||||||
<height>25</height>
|
<height>22</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QMenu" name="menuFile">
|
<widget class="QMenu" name="menuFile">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>File</string>
|
<string>File</string>
|
||||||
</property>
|
</property>
|
||||||
|
<widget class="QMenu" name="menuExport_poses">
|
||||||
|
<property name="title">
|
||||||
|
<string>Export poses...</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionRaw_format_txt"/>
|
||||||
|
<addaction name="actionRGBD_SLAM_format_txt"/>
|
||||||
|
<addaction name="actionKITTI_format_txt"/>
|
||||||
|
<addaction name="actionTORO_graph"/>
|
||||||
|
<addaction name="actionG2o_g2o"/>
|
||||||
|
</widget>
|
||||||
<addaction name="actionOpen_database"/>
|
<addaction name="actionOpen_database"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="actionSave_config"/>
|
<addaction name="actionSave_config"/>
|
||||||
@@ -499,6 +509,7 @@
|
|||||||
<addaction name="actionExport_3D_laser_scans_ply_pcd"/>
|
<addaction name="actionExport_3D_laser_scans_ply_pcd"/>
|
||||||
<addaction name="actionExport"/>
|
<addaction name="actionExport"/>
|
||||||
<addaction name="actionExtract_images"/>
|
<addaction name="actionExtract_images"/>
|
||||||
|
<addaction name="menuExport_poses"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="actionQuit"/>
|
<addaction name="actionQuit"/>
|
||||||
</widget>
|
</widget>
|
||||||
@@ -508,8 +519,6 @@
|
|||||||
</property>
|
</property>
|
||||||
<addaction name="actionGenerate_graph_dot"/>
|
<addaction name="actionGenerate_graph_dot"/>
|
||||||
<addaction name="actionGenerate_local_graph_dot"/>
|
<addaction name="actionGenerate_local_graph_dot"/>
|
||||||
<addaction name="actionGenerate_TORO_graph_graph"/>
|
|
||||||
<addaction name="actionGenerate_g2o_graph_g2o"/>
|
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="actionDetect_more_loop_closures"/>
|
<addaction name="actionDetect_more_loop_closures"/>
|
||||||
<addaction name="actionRefine_all_neighbor_links"/>
|
<addaction name="actionRefine_all_neighbor_links"/>
|
||||||
@@ -1010,8 +1019,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>339</width>
|
<width>324</width>
|
||||||
<height>186</height>
|
<height>188</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<attribute name="label">
|
<attribute name="label">
|
||||||
@@ -1146,8 +1155,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>326</width>
|
<width>280</width>
|
||||||
<height>609</height>
|
<height>666</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<attribute name="label">
|
<attribute name="label">
|
||||||
@@ -1509,8 +1518,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>339</width>
|
<width>201</width>
|
||||||
<height>173</height>
|
<height>126</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<attribute name="label">
|
<attribute name="label">
|
||||||
@@ -1609,8 +1618,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>326</width>
|
<width>186</width>
|
||||||
<height>249</height>
|
<height>496</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<attribute name="label">
|
<attribute name="label">
|
||||||
@@ -2155,11 +2164,6 @@
|
|||||||
<string>View 3D map...</string>
|
<string>View 3D map...</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionGenerate_TORO_graph_graph">
|
|
||||||
<property name="text">
|
|
||||||
<string>Generate TORO graph (*.graph)...</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="actionRefine_all_neighbor_links">
|
<action name="actionRefine_all_neighbor_links">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Refine all neighbor links...</string>
|
<string>Refine all neighbor links...</string>
|
||||||
@@ -2191,11 +2195,6 @@
|
|||||||
<string>Reset link and grid map changes</string>
|
<string>Reset link and grid map changes</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionGenerate_g2o_graph_g2o">
|
|
||||||
<property name="text">
|
|
||||||
<string>Generate g2o graph (*.g2o)...</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="actionView_3D_laser_scans">
|
<action name="actionView_3D_laser_scans">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>View 2D-3D laser scans...</string>
|
<string>View 2D-3D laser scans...</string>
|
||||||
@@ -2237,17 +2236,48 @@
|
|||||||
<string>Restore default GUI settings</string>
|
<string>Restore default GUI settings</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionRaw_format_txt">
|
||||||
|
<property name="text">
|
||||||
|
<string>Raw format (*.txt)</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionRGBD_SLAM_format_txt">
|
||||||
|
<property name="text">
|
||||||
|
<string>RGBD-SLAM format (*.txt)</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionKITTI_format_txt">
|
||||||
|
<property name="text">
|
||||||
|
<string>KITTI format (*.txt)</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionTORO_graph">
|
||||||
|
<property name="text">
|
||||||
|
<string>TORO (*.graph)</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionG2o_g2o">
|
||||||
|
<property name="text">
|
||||||
|
<string>g2o (*.g2o)</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
<class>rtabmap::ImageView</class>
|
<class>rtabmap::ImageView</class>
|
||||||
<extends>QWidget</extends>
|
<extends>QWidget</extends>
|
||||||
<header>rtabmap/gui/ImageView.h</header>
|
<header>../include/rtabmap/gui/ImageView.h</header>
|
||||||
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>rtabmap::StatsToolBox</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header>../include/rtabmap/gui/StatsToolBox.h</header>
|
||||||
|
<container>1</container>
|
||||||
</customwidget>
|
</customwidget>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
<class>rtabmap::GraphViewer</class>
|
<class>rtabmap::GraphViewer</class>
|
||||||
<extends>QGraphicsView</extends>
|
<extends>QGraphicsView</extends>
|
||||||
<header>rtabmap/gui/GraphViewer.h</header>
|
<header>../include/rtabmap/gui/GraphViewer.h</header>
|
||||||
</customwidget>
|
</customwidget>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
<class>rtabmap::ParametersToolBox</class>
|
<class>rtabmap::ParametersToolBox</class>
|
||||||
@@ -2255,12 +2285,6 @@
|
|||||||
<header>ParametersToolBox.h</header>
|
<header>ParametersToolBox.h</header>
|
||||||
<container>1</container>
|
<container>1</container>
|
||||||
</customwidget>
|
</customwidget>
|
||||||
<customwidget>
|
|
||||||
<class>rtabmap::StatsToolBox</class>
|
|
||||||
<extends>QWidget</extends>
|
|
||||||
<header>rtabmap/gui/StatsToolBox.h</header>
|
|
||||||
<container>1</container>
|
|
||||||
</customwidget>
|
|
||||||
</customwidgets>
|
</customwidgets>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections/>
|
<connections/>
|
||||||
|
|||||||
+195
-159
@@ -63,9 +63,9 @@
|
|||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>-667</y>
|
||||||
<width>673</width>
|
<width>673</width>
|
||||||
<height>2718</height>
|
<height>2747</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_16">
|
<layout class="QVBoxLayout" name="verticalLayout_16">
|
||||||
@@ -86,7 +86,7 @@
|
|||||||
<enum>QFrame::Raised</enum>
|
<enum>QFrame::Raised</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="currentIndex">
|
<property name="currentIndex">
|
||||||
<number>13</number>
|
<number>18</number>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="page_22">
|
<widget class="QWidget" name="page_22">
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_29" stretch="0,1">
|
<layout class="QVBoxLayout" name="verticalLayout_29" stretch="0,1">
|
||||||
@@ -6124,7 +6124,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="15" column="0">
|
<item row="16" column="0">
|
||||||
<widget class="QSpinBox" name="general_spinBox_laserScanDownsample">
|
<widget class="QSpinBox" name="general_spinBox_laserScanDownsample">
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
@@ -6140,7 +6140,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="10" column="1">
|
<item row="11" column="1">
|
||||||
<widget class="QLabel" name="label_retrieved_12">
|
<widget class="QLabel" name="label_retrieved_12">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Raw descriptors kept in memory.</string>
|
<string>Raw descriptors kept in memory.</string>
|
||||||
@@ -6153,7 +6153,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="10" column="0">
|
<item row="11" column="0">
|
||||||
<widget class="QCheckBox" name="general_checkBox_keepDescriptors">
|
<widget class="QCheckBox" name="general_checkBox_keepDescriptors">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string/>
|
<string/>
|
||||||
@@ -6163,7 +6163,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="13" column="1">
|
<item row="14" column="1">
|
||||||
<widget class="QLabel" name="label_retrieved_13">
|
<widget class="QLabel" name="label_retrieved_13">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Image pre decimation. This option can be used to reduce image size before features extraction. Negative decimation is done from RGB size instead of depth size (if depth is smaller than RGB, it may be interpolated depending of the decimation value).</string>
|
<string>Image pre decimation. This option can be used to reduce image size before features extraction. Negative decimation is done from RGB size instead of depth size (if depth is smaller than RGB, it may be interpolated depending of the decimation value).</string>
|
||||||
@@ -6222,7 +6222,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="11" column="1">
|
<item row="12" column="1">
|
||||||
<widget class="QLabel" name="label_retrieved_9">
|
<widget class="QLabel" name="label_retrieved_9">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Save depth image into 16 bits format to reduce memory used. Warning: values over ~65 meters are ignored (maximum 65535 millimeters).</string>
|
<string>Save depth image into 16 bits format to reduce memory used. Warning: values over ~65 meters are ignored (maximum 65535 millimeters).</string>
|
||||||
@@ -6235,7 +6235,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="14" column="0">
|
<item row="15" column="0">
|
||||||
<widget class="QSpinBox" name="spinBox_imagePostDecimation">
|
<widget class="QSpinBox" name="spinBox_imagePostDecimation">
|
||||||
<property name="minimum">
|
<property name="minimum">
|
||||||
<number>-16</number>
|
<number>-16</number>
|
||||||
@@ -6281,7 +6281,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="14" column="1">
|
<item row="15" column="1">
|
||||||
<widget class="QLabel" name="label_retrieved_6">
|
<widget class="QLabel" name="label_retrieved_6">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Image post decimation. This option can be used to save images in lower resolution (size/decimation). It is done on the original image. Negative decimation is done from RGB size instead of depth size (if depth is smaller than RGB, it may be interpolated depending of the decimation value).</string>
|
<string>Image post decimation. This option can be used to save images in lower resolution (size/decimation). It is done on the original image. Negative decimation is done from RGB size instead of depth size (if depth is smaller than RGB, it may be interpolated depending of the decimation value).</string>
|
||||||
@@ -6307,7 +6307,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="15" column="1">
|
<item row="16" column="1">
|
||||||
<widget class="QLabel" name="label_retrieved_8">
|
<widget class="QLabel" name="label_retrieved_8">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>If > 1, downsample the laser scans when creating a location. This feature can be used to save laser scans already downsampled.</string>
|
<string>If > 1, downsample the laser scans when creating a location. This feature can be used to save laser scans already downsampled.</string>
|
||||||
@@ -6320,7 +6320,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="11" column="0">
|
<item row="12" column="0">
|
||||||
<widget class="QCheckBox" name="general_checkBox_saveDepth16bits">
|
<widget class="QCheckBox" name="general_checkBox_saveDepth16bits">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string/>
|
<string/>
|
||||||
@@ -6330,7 +6330,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="13" column="0">
|
<item row="14" column="0">
|
||||||
<widget class="QSpinBox" name="spinBox_imagePreDecimation">
|
<widget class="QSpinBox" name="spinBox_imagePreDecimation">
|
||||||
<property name="minimum">
|
<property name="minimum">
|
||||||
<number>-16</number>
|
<number>-16</number>
|
||||||
@@ -6340,7 +6340,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="16" column="0">
|
<item row="17" column="0">
|
||||||
<widget class="QSpinBox" name="general_spinBox_laserScanNormalK">
|
<widget class="QSpinBox" name="general_spinBox_laserScanNormalK">
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
@@ -6359,7 +6359,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="16" column="1">
|
<item row="17" column="1">
|
||||||
<widget class="QLabel" name="label_retrieved_14">
|
<widget class="QLabel" name="label_retrieved_14">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>If > 0 and laser scans are 3D without normals, normals will be computed with K search neighbors when creating a signature.</string>
|
<string>If > 0 and laser scans are 3D without normals, normals will be computed with K search neighbors when creating a signature.</string>
|
||||||
@@ -6372,7 +6372,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="12" column="1">
|
<item row="13" column="1">
|
||||||
<widget class="QLabel" name="label_retrieved_15">
|
<widget class="QLabel" name="label_retrieved_15">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Multi-threaded compression.</string>
|
<string>Multi-threaded compression.</string>
|
||||||
@@ -6385,7 +6385,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="12" column="0">
|
<item row="13" column="0">
|
||||||
<widget class="QCheckBox" name="general_checkBox_compressionParallelized">
|
<widget class="QCheckBox" name="general_checkBox_compressionParallelized">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string/>
|
<string/>
|
||||||
@@ -6395,6 +6395,29 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="10" column="1">
|
||||||
|
<widget class="QLabel" name="label_retrieved_16">
|
||||||
|
<property name="text">
|
||||||
|
<string>Save intermediate node data.</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="textInteractionFlags">
|
||||||
|
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="10" column="0">
|
||||||
|
<widget class="QCheckBox" name="general_checkBox_saveIntermediateNodeData">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
@@ -10058,7 +10081,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
|
|||||||
<item row="4" column="1">
|
<item row="4" column="1">
|
||||||
<widget class="QLabel" name="label_357">
|
<widget class="QLabel" name="label_357">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>[Visual] Local bundle adjustment. See Optimizer panel. This will not work with Optical Flow correspondences strategy is selected in Visual Registration panel.</string>
|
<string>[Visual] Local bundle adjustment. See Optimizer panel. This will not work if Optical Flow correspondences strategy is selected in Visual Registration panel.</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="wordWrap">
|
<property name="wordWrap">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
@@ -12299,153 +12322,166 @@ Lower the ratio -> higher the precision. 0 means disabled, matching the neare
|
|||||||
<property name="title">
|
<property name="title">
|
||||||
<string>g2o</string>
|
<string>g2o</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout_70" columnstretch="0,1">
|
<layout class="QVBoxLayout" name="verticalLayout_117">
|
||||||
<item row="1" column="0">
|
<item>
|
||||||
<widget class="QComboBox" name="comboBox_g2o_optimizer">
|
<layout class="QGridLayout" name="gridLayout_70" columnstretch="0,1">
|
||||||
<item>
|
<item row="0" column="0">
|
||||||
<property name="text">
|
<widget class="QComboBox" name="comboBox_g2o_solver">
|
||||||
<string>Levenberg</string>
|
<item>
|
||||||
</property>
|
<property name="text">
|
||||||
|
<string>CSparse</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>PCG</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Cholmod</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Eigen</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item row="0" column="1">
|
||||||
<property name="text">
|
<widget class="QLabel" name="label_107">
|
||||||
<string>Gauss Newton</string>
|
<property name="text">
|
||||||
</property>
|
<string>Solver.</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</widget>
|
<item row="1" column="0">
|
||||||
</item>
|
<widget class="QComboBox" name="comboBox_g2o_optimizer">
|
||||||
<item row="0" column="0">
|
<item>
|
||||||
<widget class="QComboBox" name="comboBox_g2o_solver">
|
<property name="text">
|
||||||
<item>
|
<string>Levenberg</string>
|
||||||
<property name="text">
|
</property>
|
||||||
<string>CSparse</string>
|
</item>
|
||||||
</property>
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Gauss Newton</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item row="1" column="1">
|
||||||
<property name="text">
|
<widget class="QLabel" name="label_138">
|
||||||
<string>PCG</string>
|
<property name="text">
|
||||||
</property>
|
<string>Optimization algorithm.</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
</layout>
|
||||||
<property name="text">
|
|
||||||
<string>Cholmod</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>Eigen</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
</widget>
|
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0">
|
<item>
|
||||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_g2o_pixelVariance">
|
<widget class="QGroupBox" name="groupBox_20">
|
||||||
<property name="decimals">
|
<property name="title">
|
||||||
<number>2</number>
|
<string>Bundle Adjustement</string>
|
||||||
</property>
|
|
||||||
<property name="minimum">
|
|
||||||
<double>0.010000000000000</double>
|
|
||||||
</property>
|
|
||||||
<property name="maximum">
|
|
||||||
<double>999.000000000000000</double>
|
|
||||||
</property>
|
|
||||||
<property name="singleStep">
|
|
||||||
<double>0.001000000000000</double>
|
|
||||||
</property>
|
|
||||||
<property name="value">
|
|
||||||
<double>0.010000000000000</double>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="1">
|
|
||||||
<widget class="QLabel" name="label_107">
|
|
||||||
<property name="text">
|
|
||||||
<string>Solver.</string>
|
|
||||||
</property>
|
|
||||||
<property name="wordWrap">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="1">
|
|
||||||
<widget class="QLabel" name="label_138">
|
|
||||||
<property name="text">
|
|
||||||
<string>Optimization algorithm.</string>
|
|
||||||
</property>
|
|
||||||
<property name="wordWrap">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="1">
|
|
||||||
<widget class="QLabel" name="label_148">
|
|
||||||
<property name="text">
|
|
||||||
<string>Pixel variance used for bundle adjustment.</string>
|
|
||||||
</property>
|
|
||||||
<property name="wordWrap">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="1">
|
|
||||||
<widget class="QLabel" name="label_350">
|
|
||||||
<property name="text">
|
|
||||||
<string>Robust kernel delta used for bundle adjustment (0 means don't use robust kernel). Observations with chi2 over this threshold will be ignored in the second optimization pass.</string>
|
|
||||||
</property>
|
|
||||||
<property name="wordWrap">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="0">
|
|
||||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_g2o_robustKernelDelta">
|
|
||||||
<property name="decimals">
|
|
||||||
<number>3</number>
|
|
||||||
</property>
|
|
||||||
<property name="minimum">
|
|
||||||
<double>0.000000000000000</double>
|
|
||||||
</property>
|
|
||||||
<property name="maximum">
|
|
||||||
<double>999.000000000000000</double>
|
|
||||||
</property>
|
|
||||||
<property name="singleStep">
|
|
||||||
<double>1.000000000000000</double>
|
|
||||||
</property>
|
|
||||||
<property name="value">
|
|
||||||
<double>5.991000000000000</double>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="4" column="0">
|
|
||||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_g2o_baseline">
|
|
||||||
<property name="suffix">
|
|
||||||
<string> m</string>
|
|
||||||
</property>
|
|
||||||
<property name="decimals">
|
|
||||||
<number>4</number>
|
|
||||||
</property>
|
|
||||||
<property name="minimum">
|
|
||||||
<double>0.000000000000000</double>
|
|
||||||
</property>
|
|
||||||
<property name="maximum">
|
|
||||||
<double>9.000000000000000</double>
|
|
||||||
</property>
|
|
||||||
<property name="singleStep">
|
|
||||||
<double>0.010000000000000</double>
|
|
||||||
</property>
|
|
||||||
<property name="value">
|
|
||||||
<double>0.075000000000000</double>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="4" column="1">
|
|
||||||
<widget class="QLabel" name="label_352">
|
|
||||||
<property name="text">
|
|
||||||
<string>When doing bundle adjustment with RGB-D data, we can set a fake baseline to do stereo bundle adjustment (if 0, mono bundle adjustment is done). For stereo data, the baseline in the calibration is used directly.</string>
|
|
||||||
</property>
|
|
||||||
<property name="wordWrap">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_84" columnstretch="0,1">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QDoubleSpinBox" name="doubleSpinBox_g2o_pixelVariance">
|
||||||
|
<property name="decimals">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<double>0.010000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<double>999.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="singleStep">
|
||||||
|
<double>0.001000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<double>0.010000000000000</double>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLabel" name="label_148">
|
||||||
|
<property name="text">
|
||||||
|
<string>Pixel variance used for bundle adjustment.</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QDoubleSpinBox" name="doubleSpinBox_g2o_robustKernelDelta">
|
||||||
|
<property name="decimals">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<double>0.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<double>999.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="singleStep">
|
||||||
|
<double>1.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<double>5.991000000000000</double>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLabel" name="label_350">
|
||||||
|
<property name="text">
|
||||||
|
<string>Robust kernel delta used for bundle adjustment (0 means don't use robust kernel). Observations with chi2 over this threshold will be ignored in the second optimization pass.</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QDoubleSpinBox" name="doubleSpinBox_g2o_baseline">
|
||||||
|
<property name="suffix">
|
||||||
|
<string> m</string>
|
||||||
|
</property>
|
||||||
|
<property name="decimals">
|
||||||
|
<number>4</number>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<double>0.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<double>9.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="singleStep">
|
||||||
|
<double>0.010000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<double>0.075000000000000</double>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QLabel" name="label_352">
|
||||||
|
<property name="text">
|
||||||
|
<string>When doing bundle adjustment with RGB-D data, we can set a fake baseline to do stereo bundle adjustment (if 0, mono bundle adjustment is done). For stereo data, the baseline in the calibration is used directly.</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
|
|||||||
+178
-152
@@ -31,6 +31,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
#include "rtabmap/core/CameraThread.h"
|
#include "rtabmap/core/CameraThread.h"
|
||||||
#include "rtabmap/core/Graph.h"
|
#include "rtabmap/core/Graph.h"
|
||||||
#include "rtabmap/core/OdometryInfo.h"
|
#include "rtabmap/core/OdometryInfo.h"
|
||||||
|
#include "rtabmap/core/OdometryEvent.h"
|
||||||
|
#include "rtabmap/core/Memory.h"
|
||||||
#include "rtabmap/core/util3d_registration.h"
|
#include "rtabmap/core/util3d_registration.h"
|
||||||
#include "rtabmap/utilite/UConversion.h"
|
#include "rtabmap/utilite/UConversion.h"
|
||||||
#include "rtabmap/utilite/UDirectory.h"
|
#include "rtabmap/utilite/UDirectory.h"
|
||||||
@@ -53,6 +55,7 @@ void showUsage()
|
|||||||
" --output Output directory. By default, results are saved in \"path\".\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"
|
" --gt \"path\" Ground truth path (e.g., ~/KITTI/devkit/cpp/data/odometry/poses/07.txt)\n"
|
||||||
" --color Use color images for stereo (image_2 and image_3 folders).\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"
|
" --scan Include velodyne scan in node's data.\n"
|
||||||
" --scan_step # Scan downsample step (default=10).\n"
|
" --scan_step # Scan downsample step (default=10).\n"
|
||||||
" --scan_voxel #.# Scan voxel size (default 0.3 m).\n"
|
" --scan_voxel #.# Scan voxel size (default 0.3 m).\n"
|
||||||
@@ -97,6 +100,7 @@ int main(int argc, char * argv[])
|
|||||||
int mapUpdate = 10;
|
int mapUpdate = 10;
|
||||||
bool color = false;
|
bool color = false;
|
||||||
bool scan = false;
|
bool scan = false;
|
||||||
|
bool disp = false;
|
||||||
int scanStep = 10;
|
int scanStep = 10;
|
||||||
float scanVoxel = 0.3f;
|
float scanVoxel = 0.3f;
|
||||||
int scanNormalK = 20;
|
int scanNormalK = 20;
|
||||||
@@ -159,7 +163,11 @@ int main(int argc, char * argv[])
|
|||||||
}
|
}
|
||||||
else if(std::strcmp(argv[i], "--scan") == 0)
|
else if(std::strcmp(argv[i], "--scan") == 0)
|
||||||
{
|
{
|
||||||
color = true;
|
scan = true;
|
||||||
|
}
|
||||||
|
else if(std::strcmp(argv[i], "--disp") == 0)
|
||||||
|
{
|
||||||
|
disp = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
parameters = Parameters::parseArguments(argc, argv);
|
parameters = Parameters::parseArguments(argc, argv);
|
||||||
@@ -173,6 +181,7 @@ int main(int argc, char * argv[])
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
output = uReplaceChar(output, '~', UDirectory::homeDir());
|
output = uReplaceChar(output, '~', UDirectory::homeDir());
|
||||||
|
UDirectory::makeDir(output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,6 +223,10 @@ int main(int argc, char * argv[])
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(disp)
|
||||||
|
{
|
||||||
|
printf(" Disparity: %s\n", disp?"true":"false");
|
||||||
|
}
|
||||||
if(scan)
|
if(scan)
|
||||||
{
|
{
|
||||||
pathScan = path+"/velodyne";
|
pathScan = path+"/velodyne";
|
||||||
@@ -291,6 +304,10 @@ int main(int argc, char * argv[])
|
|||||||
0.0f,
|
0.0f,
|
||||||
opticalRotation), parameters);
|
opticalRotation), parameters);
|
||||||
((CameraStereoImages*)cameraThread.camera())->setTimestamps(false, pathTimes, false);
|
((CameraStereoImages*)cameraThread.camera())->setTimestamps(false, pathTimes, false);
|
||||||
|
if(disp)
|
||||||
|
{
|
||||||
|
cameraThread.setStereoToDepth(true);
|
||||||
|
}
|
||||||
if(!gtPath.empty())
|
if(!gtPath.empty())
|
||||||
{
|
{
|
||||||
((CameraStereoImages*)cameraThread.camera())->setGroundTruthPath(gtPath, 2);
|
((CameraStereoImages*)cameraThread.camera())->setGroundTruthPath(gtPath, 2);
|
||||||
@@ -327,6 +344,7 @@ int main(int argc, char * argv[])
|
|||||||
/////////////////////////////
|
/////////////////////////////
|
||||||
// Processing dataset begin
|
// Processing dataset begin
|
||||||
/////////////////////////////
|
/////////////////////////////
|
||||||
|
cv::Mat covariance;
|
||||||
while(data.isValid() && g_forever)
|
while(data.isValid() && g_forever)
|
||||||
{
|
{
|
||||||
std::map<std::string, float> externalStats;
|
std::map<std::string, float> externalStats;
|
||||||
@@ -347,8 +365,10 @@ int main(int argc, char * argv[])
|
|||||||
Transform pose = odom.process(data, &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/LocalBundle/ms", odomInfo.localBundleTime*1000.0f));
|
||||||
externalStats.insert(std::make_pair("Odometry/TotalTime/ms", odomInfo.timeEstimation*1000.0f));
|
externalStats.insert(std::make_pair("Odometry/TotalTime/ms", odomInfo.timeEstimation*1000.0f));
|
||||||
float speed = odomInfo.transform.x()/odomInfo.interval*3.6;
|
float speed = 0.0f;
|
||||||
externalStats.insert(std::make_pair("Odometry/Speed/ms", speed));
|
if(odomInfo.interval>0.0)
|
||||||
|
speed = odomInfo.transform.x()/odomInfo.interval*3.6;
|
||||||
|
externalStats.insert(std::make_pair("Odometry/Speed/kph", speed));
|
||||||
externalStats.insert(std::make_pair("Odometry/Inliers/ms", odomInfo.inliers));
|
externalStats.insert(std::make_pair("Odometry/Inliers/ms", odomInfo.inliers));
|
||||||
externalStats.insert(std::make_pair("Odometry/Features/ms", odomInfo.features));
|
externalStats.insert(std::make_pair("Odometry/Features/ms", odomInfo.features));
|
||||||
|
|
||||||
@@ -360,11 +380,21 @@ int main(int argc, char * argv[])
|
|||||||
data.setFeatures(std::vector<cv::KeyPoint>(), std::vector<cv::Point3f>(), cv::Mat());// remove features
|
data.setFeatures(std::vector<cv::KeyPoint>(), std::vector<cv::Point3f>(), cv::Mat());// remove features
|
||||||
processData = intermediateNodes;
|
processData = intermediateNodes;
|
||||||
}
|
}
|
||||||
|
if(covariance.empty())
|
||||||
|
{
|
||||||
|
covariance = odomInfo.covariance;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
covariance = (covariance.inv() + odomInfo.covariance.inv()).inv();
|
||||||
|
}
|
||||||
|
|
||||||
timer.restart();
|
timer.restart();
|
||||||
if(processData)
|
if(processData)
|
||||||
{
|
{
|
||||||
rtabmap.process(data, pose, odomInfo.varianceLin, odomInfo.varianceAng, externalStats);
|
OdometryEvent e(SensorData(), Transform(), odomInfo);
|
||||||
|
rtabmap.process(data, pose, covariance, e.velocity(), externalStats);
|
||||||
|
covariance = cv::Mat();
|
||||||
}
|
}
|
||||||
double slamTime = timer.ticks();
|
double slamTime = timer.ticks();
|
||||||
|
|
||||||
@@ -400,161 +430,157 @@ int main(int argc, char * argv[])
|
|||||||
{
|
{
|
||||||
// Log ground truth statistics (in TUM's RGBD-SLAM format)
|
// Log ground truth statistics (in TUM's RGBD-SLAM format)
|
||||||
std::map<int, Transform> groundTruth;
|
std::map<int, Transform> groundTruth;
|
||||||
graph::importPoses(gtPath, 2, groundTruth);
|
|
||||||
if(poses.size() == groundTruth.size())
|
//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)
|
||||||
{
|
{
|
||||||
//align with ground truth for more meaningful results
|
Transform o, gtPose;
|
||||||
pcl::PointCloud<pcl::PointXYZ> cloud1, cloud2;
|
int m,w;
|
||||||
cloud1.resize(poses.size());
|
std::string l;
|
||||||
cloud2.resize(poses.size());
|
double s;
|
||||||
int oi = 0;
|
std::vector<float> v;
|
||||||
int idFirst = 0;
|
rtabmap.getMemory()->getNodeInfo(iter->first, o, m, w, l, s, gtPose, v, true);
|
||||||
for(std::map<int, Transform>::const_iterator iter=groundTruth.begin(); iter!=groundTruth.end(); ++iter)
|
if(!gtPose.isNull())
|
||||||
{
|
{
|
||||||
std::map<int, Transform>::iterator iter2 = poses.find(iter->first);
|
groundTruth.insert(std::make_pair(iter->first, gtPose));
|
||||||
if(iter2!=poses.end())
|
if(oi==0)
|
||||||
{
|
{
|
||||||
if(oi==0)
|
idFirst = iter->first;
|
||||||
{
|
|
||||||
idFirst = iter->first;
|
|
||||||
}
|
|
||||||
cloud1[oi] = pcl::PointXYZ(iter->second.x(), iter->second.y(), iter->second.z());
|
|
||||||
cloud2[oi++] = pcl::PointXYZ(iter2->second.x(), iter2->second.y(), iter2->second.z());
|
|
||||||
}
|
}
|
||||||
}
|
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);
|
|
||||||
|
|
||||||
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;
|
|
||||||
float translational_min = 0.0f;
|
|
||||||
float translational_max = 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)
|
|
||||||
{
|
|
||||||
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("Ground truth comparison:\n");
|
|
||||||
printf(" translational_rmse= %f\n", translational_rmse);
|
|
||||||
printf(" translational_mean= %f\n", translational_mean);
|
|
||||||
printf(" translational_median= %f\n", translational_median);
|
|
||||||
printf(" translational_std= %f\n", translational_std);
|
|
||||||
printf(" translational_min= %f\n", translational_min);
|
|
||||||
printf(" translational_max= %f\n", translational_max);
|
|
||||||
printf(" rotational_rmse= %f\n", rotational_rmse);
|
|
||||||
printf(" rotational_mean= %f\n", rotational_mean);
|
|
||||||
printf(" rotational_median= %f\n", rotational_median);
|
|
||||||
printf(" rotational_std= %f\n", rotational_std);
|
|
||||||
printf(" rotational_min= %f\n", rotational_min);
|
|
||||||
printf(" rotational_max= %f\n", rotational_max);
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
// compute KITTI statistics before aligning the poses
|
||||||
|
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);
|
||||||
|
|
||||||
|
Transform t = Transform::getIdentity();
|
||||||
|
if(oi>5)
|
||||||
{
|
{
|
||||||
UWARN("Cannot compute ground truth statistics, the computed poses (%d) are not the same size as the ground truth (%d). Make sure to use option \"--Rtabmap/CreateIntermediateNodes true\".");
|
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;
|
||||||
|
float translational_min = 0.0f;
|
||||||
|
float translational_max = 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)
|
||||||
|
{
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user