Update 0.15.4.

Parameters:
-Added "GridGlobal/MaxNodes=0", "Rtabmap/PublishRAMUsage=false", "Mem/DepthAsMask=true", "Kp/FlannRebalancingFactor=2.0", "Vis/DepthAsMask=true".
-Modified "Kp/DetectorStrategy=6", "Kp/MaxFeatures=500",  "Mem/UseOdomFeatures=true", "GFTT/QualityLevel=0.001", "GFTT/MinDistance=3", "RGBD/OptimizeMaxError=1", "RGBD/ProximityPathFilteringRadius=1", "Odom/GuessMotion=true", "Odom/VisKeyFrameThr=150", "OdomF2M/BundleAdjustment=1", "Vis/Iterations=300" if built with g2o, "OdomF2M/BundleAdjustmentMaxFrames=10", "OdomFovis/MinFeaturesForEstimate=20", "OdomORBSLAM2/MapSize=3000", "Reg/RepeatOnce=true", "Vis/PnPRefineIterations=0" if built with g2o, "Vis/CorGuessMatchToProjection=true", "Vis/BundleAdjustment=1" if built with g2o, "Icp/MaxCorrespondenceDistance=0.1", "Icp/PointToPlaneK=5", "Icp/PointToPlaneRadius=1", "Icp/PM=true" if built with libpointmatcher, "Stereo/MaxLevel=5", "Stereo/MinDisparity=0.5".

BayesFilter: optimized prediction matrix update. Use of new argument "ignoreLocalSpaceLoopIds" of Memory::getNeighborsId() to ignore loop closure link by space in prediction update.
CameraThread: Added stereo exposure compensation option.
CameraRGB: Added forceGroundNormalsUp option and added support of ground truth from EuRoC dataset.
Statistics: Added "Memory/RAM_usage/MB".
Transform: Added clone() method to do deep copy.
Graph::importPoses(): EuRoC format support (9).
Rtabmap: Local visual loop closures are now identified as GlobalClosure link type.
OccupancyGrid/OctoMap: updated how cache is used (old node retrieved can be re-added to map without re-assembling the whole map).
OdometryF2F: when using ICP, increasing correspondence distance for first two frames. If Vis/CorType=1 and registration fails, second guess without motion is done with Vis/CorType=0.
OdometryF2M/RegVis: updated how features are removed from the map, using new projectedIDs filled in RegistrationInfo by RegistrationVis.
OdometryORBSLAM2: Maximum size of the feature map can be set with "OdomORBSLAM2/MapSize" parameter.
CloudViewer: fixed opengl camera drifting in follow mode.
DatabaseViewer: Added optimization scale option. ConstraintsView: hide loop closure links if type is ignored in gui parameters.
MainWindow: Support of "GridGlobal/MaxNodes" parameters when updating the maps.
UPlot: don't show ellipses when not in graphics view mode, updated how "random" colors are attributed to curves
Added rtabmap-euroc_dataset tool. Updated rtabmap-kitti_dataset and rtabmap-rgbd_dataset tools.
Added rtabmap-reprocess tool.
This commit is contained in:
matlabbe
2018-02-01 22:17:46 -05:00
parent 9f80f4ac42
commit 977d21eed5
76 changed files with 3844 additions and 1307 deletions
+1 -1
View File
@@ -21,7 +21,7 @@ SET(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake_modules")
####################### #######################
SET(RTABMAP_MAJOR_VERSION 0) SET(RTABMAP_MAJOR_VERSION 0)
SET(RTABMAP_MINOR_VERSION 15) SET(RTABMAP_MINOR_VERSION 15)
SET(RTABMAP_PATCH_VERSION 3) SET(RTABMAP_PATCH_VERSION 4)
SET(RTABMAP_VERSION SET(RTABMAP_VERSION
${RTABMAP_MAJOR_VERSION}.${RTABMAP_MINOR_VERSION}.${RTABMAP_PATCH_VERSION}) ${RTABMAP_MAJOR_VERSION}.${RTABMAP_MINOR_VERSION}.${RTABMAP_PATCH_VERSION})
+5 -3
View File
@@ -33,6 +33,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <opencv2/core/core.hpp> #include <opencv2/core/core.hpp>
#include <list> #include <list>
#include <set> #include <set>
#include <unordered_map>
#include "rtabmap/utilite/UEventsHandler.h" #include "rtabmap/utilite/UEventsHandler.h"
#include "rtabmap/core/Parameters.h" #include "rtabmap/core/Parameters.h"
@@ -59,18 +60,18 @@ public:
const std::vector<double> & getPredictionLC() const; // {Vp, Lc, l1, l2, l3, l4...} const std::vector<double> & getPredictionLC() const; // {Vp, Lc, l1, l2, l3, l4...}
std::string getPredictionLCStr() const; // for convenience {Vp, Lc, l1, l2, l3, l4...} std::string getPredictionLCStr() const; // for convenience {Vp, Lc, l1, l2, l3, l4...}
cv::Mat generatePrediction(const Memory * memory, const std::vector<int> & ids) const; cv::Mat generatePrediction(const Memory * memory, const std::vector<int> & ids);
private: private:
cv::Mat updatePrediction(const cv::Mat & oldPrediction, cv::Mat updatePrediction(const cv::Mat & oldPrediction,
const Memory * memory, const Memory * memory,
const std::vector<int> & oldIds, const std::vector<int> & oldIds,
const std::vector<int> & newIds) const; const std::vector<int> & newIds);
void updatePosterior(const Memory * memory, const std::vector<int> & likelihoodIds); void updatePosterior(const Memory * memory, const std::vector<int> & likelihoodIds);
float addNeighborProb(cv::Mat & prediction, float addNeighborProb(cv::Mat & prediction,
unsigned int col, unsigned int col,
const std::map<int, int> & neighbors, const std::map<int, int> & neighbors,
const std::map<int, int> & idToIndexMap) const; const std::unordered_map<int, int> & idToIndex) const;
void normalize(cv::Mat & prediction, unsigned int index, float addedProbabilitiesSum, bool virtualPlaceUsed) const; void normalize(cv::Mat & prediction, unsigned int index, float addedProbabilitiesSum, bool virtualPlaceUsed) const;
private: private:
@@ -80,6 +81,7 @@ private:
std::vector<double> _predictionLC; // {Vp, Lc, l1, l2, l3, l4...} std::vector<double> _predictionLC; // {Vp, Lc, l1, l2, l3, l4...}
bool _fullPredictionUpdate; bool _fullPredictionUpdate;
float _totalPredictionLCValues; float _totalPredictionLCValues;
std::map<int, std::map<int, int> > _neighborsIndex;
}; };
} // namespace rtabmap } // namespace rtabmap
@@ -59,6 +59,7 @@ public:
float timeCapture; float timeCapture;
float timeDisparity; float timeDisparity;
float timeMirroring; float timeMirroring;
float timeStereoExposureCompensation;
float timeImageDecimation; float timeImageDecimation;
float timeScanFromDepth; float timeScanFromDepth;
float timeUndistortDepth; float timeUndistortDepth;
+4 -1
View File
@@ -87,7 +87,8 @@ public:
float voxelSize = 0.0f, float voxelSize = 0.0f,
int normalsK = 0, // compute normals if > 0 int normalsK = 0, // compute normals if > 0
float normalsRadius = 0, // compute normals if > 0 float normalsRadius = 0, // compute normals if > 0
const Transform & localTransform=Transform::getIdentity()) const Transform & localTransform=Transform::getIdentity(),
bool forceGroundNormalsUp = false)
{ {
_scanPath = dir; _scanPath = dir;
_scanLocalTransform = localTransform; _scanLocalTransform = localTransform;
@@ -96,6 +97,7 @@ public:
_scanNormalsK = normalsK; _scanNormalsK = normalsK;
_scanNormalsRadius = normalsRadius; _scanNormalsRadius = normalsRadius;
_scanVoxelSize = voxelSize; _scanVoxelSize = voxelSize;
_scanForceGroundNormalsUp = forceGroundNormalsUp;
} }
void setDepthFromScan(bool enabled, int fillHoles = 1, bool fillHolesFromBorder = false) void setDepthFromScan(bool enabled, int fillHoles = 1, bool fillHolesFromBorder = false)
@@ -161,6 +163,7 @@ private:
float _scanVoxelSize; float _scanVoxelSize;
int _scanNormalsK; int _scanNormalsK;
float _scanNormalsRadius; float _scanNormalsRadius;
bool _scanForceGroundNormalsUp;
bool _depthFromScan; bool _depthFromScan;
int _depthFromScanFillHoles; // <0:horizontal 0:disabled >0:vertical int _depthFromScanFillHoles; // <0:horizontal 0:disabled >0:vertical
@@ -60,6 +60,7 @@ public:
virtual ~CameraThread(); virtual ~CameraThread();
void setMirroringEnabled(bool enabled) {_mirroring = enabled;} void setMirroringEnabled(bool enabled) {_mirroring = enabled;}
void setStereoExposureCompensation(bool enabled) {_stereoExposureCompensation = enabled;}
void setColorOnly(bool colorOnly) {_colorOnly = colorOnly;} void setColorOnly(bool colorOnly) {_colorOnly = colorOnly;}
void setImageDecimation(int decimation) {_imageDecimation = decimation;} void setImageDecimation(int decimation) {_imageDecimation = decimation;}
void setStereoToDepth(bool enabled) {_stereoToDepth = enabled;} void setStereoToDepth(bool enabled) {_stereoToDepth = enabled;}
@@ -100,6 +101,7 @@ private:
private: private:
Camera * _camera; Camera * _camera;
bool _mirroring; bool _mirroring;
bool _stereoExposureCompensation;
bool _colorOnly; bool _colorOnly;
int _imageDecimation; int _imageDecimation;
bool _stereoToDepth; bool _stereoToDepth;
+9 -4
View File
@@ -49,21 +49,25 @@ public:
// Note that useDistanceL1 doesn't have any effect if LSH is used // Note that useDistanceL1 doesn't have any effect if LSH is used
void buildLinearIndex( void buildLinearIndex(
const cv::Mat & features, const cv::Mat & features,
bool useDistanceL1 = false); bool useDistanceL1 = false,
float rebalancingFactor = 2.0f);
void buildKDTreeIndex( void buildKDTreeIndex(
const cv::Mat & features, const cv::Mat & features,
int trees = 4, int trees = 4,
bool useDistanceL1 = false); bool useDistanceL1 = false,
float rebalancingFactor = 2.0f);
void buildKDTreeSingleIndex( void buildKDTreeSingleIndex(
const cv::Mat & features, const cv::Mat & features,
int leafMaxSize = 10, int leafMaxSize = 10,
bool reorder = true, bool reorder = true,
bool useDistanceL1 = false); bool useDistanceL1 = false,
float rebalancingFactor = 2.0f);
void buildLSHIndex( void buildLSHIndex(
const cv::Mat & features, const cv::Mat & features,
unsigned int table_number = 12, unsigned int table_number = 12,
unsigned int key_size = 20, unsigned int key_size = 20,
unsigned int multi_probe_level = 2); unsigned int multi_probe_level = 2,
float rebalancingFactor = 2.0f);
bool isBuilt(); bool isBuilt();
@@ -102,6 +106,7 @@ private:
int featuresDim_; int featuresDim_;
bool isLSH_; bool isLSH_;
bool useDistanceL1_; // true=EUCLEDIAN_L2 false=MANHATTAN_L1 bool useDistanceL1_; // true=EUCLEDIAN_L2 false=MANHATTAN_L1
float rebalancingFactor_;
// keep feature in memory until the tree is rebuilt // keep feature in memory until the tree is rebuilt
// (in case the word is deleted when removed from the VWDictionary) // (in case the word is deleted when removed from the VWDictionary)
+7
View File
@@ -123,6 +123,8 @@ std::multimap<int, int>::const_iterator RTABMAP_EXP findLink(
int to, int to,
bool checkBothWays = true); bool checkBothWays = true);
std::multimap<int, Link> RTABMAP_EXP filterDuplicateLinks(
const std::multimap<int, Link> & links);
std::multimap<int, Link> RTABMAP_EXP filterLinks( std::multimap<int, Link> RTABMAP_EXP filterLinks(
const std::multimap<int, Link> & links, const std::multimap<int, Link> & links,
Link::Type filteredType); Link::Type filteredType);
@@ -227,6 +229,11 @@ int RTABMAP_EXP findNearestNode(
const std::map<int, rtabmap::Transform> & nodes, const std::map<int, rtabmap::Transform> & nodes,
const rtabmap::Transform & targetPose); const rtabmap::Transform & targetPose);
std::vector<int> RTABMAP_EXP findNearestNodes(
const std::map<int, rtabmap::Transform> & nodes,
const rtabmap::Transform & targetPose,
int k);
/** /**
* Get nodes near the query * Get nodes near the query
* @param nodeId the query id * @param nodeId the query id
+3
View File
@@ -127,6 +127,7 @@ public:
bool incrementMarginOnLoop = false, bool incrementMarginOnLoop = false,
bool ignoreLoopIds = false, bool ignoreLoopIds = false,
bool ignoreIntermediateNodes = false, bool ignoreIntermediateNodes = false,
bool ignoreLocalSpaceLoopIds = false,
const std::set<int> & nodesSet = std::set<int>(), const std::set<int> & nodesSet = std::set<int>(),
double * dbAccessTime = 0) const; double * dbAccessTime = 0) const;
std::map<int, float> getNeighborsIdRadius( std::map<int, float> getNeighborsIdRadius(
@@ -281,6 +282,7 @@ private:
bool _generateIds; bool _generateIds;
bool _badSignaturesIgnored; bool _badSignaturesIgnored;
bool _mapLabelsAdded; bool _mapLabelsAdded;
bool _depthAsMask;
int _imagePreDecimation; int _imagePreDecimation;
int _imagePostDecimation; int _imagePostDecimation;
bool _compressionParallelized; bool _compressionParallelized;
@@ -295,6 +297,7 @@ private:
bool _useOdometryFeatures; bool _useOdometryFeatures;
bool _createOccupancyGrid; bool _createOccupancyGrid;
int _visMaxFeatures; int _visMaxFeatures;
int _visCorType;
int _idCount; int _idCount;
int _idMapCount; int _idMapCount;
+9 -2
View File
@@ -44,6 +44,7 @@ public:
void parseParameters(const ParametersMap & parameters); void parseParameters(const ParametersMap & parameters);
void setCellSize(float cellSize); void setCellSize(float cellSize);
float getCellSize() const {return cellSize_;} float getCellSize() const {return cellSize_;}
void setCloudAssembling(bool enabled);
float getMinMapSize() const {return minMapSize_;} float getMinMapSize() const {return minMapSize_;}
bool isGridFromDepth() const {return occupancyFromCloud_;} bool isGridFromDepth() const {return occupancyFromCloud_;}
bool isFullUpdate() const {return fullUpdate_;} bool isFullUpdate() const {return fullUpdate_;}
@@ -73,7 +74,9 @@ public:
const cv::Mat & ground, const cv::Mat & ground,
const cv::Mat & obstacles); const cv::Mat & obstacles);
void update(const std::map<int, Transform> & poses); void update(const std::map<int, Transform> & poses);
const cv::Mat getMap(float & xMin, float & yMin) const; cv::Mat getMap(float & xMin, float & yMin) const;
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & getMapGround() const {return assembledGround_;}
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & getMapObstacles() const {return assembledObstacles_;}
private: private:
ParametersMap parameters_; ParametersMap parameters_;
@@ -109,13 +112,17 @@ private:
bool erode_; bool erode_;
float footprintRadius_; float footprintRadius_;
std::map<int, std::pair<cv::Mat, cv::Mat> > cache_; std::map<int, std::pair<cv::Mat, cv::Mat> > cache_; //<node id, <ground, obstacles> >
cv::Mat map_; cv::Mat map_;
cv::Mat mapInfo_; cv::Mat mapInfo_;
std::map<int, std::pair<int, int> > cellCount_; //<node Id, cells> std::map<int, std::pair<int, int> > cellCount_; //<node Id, cells>
float xMin_; float xMin_;
float yMin_; float yMin_;
std::map<int, Transform> addedNodes_; std::map<int, Transform> addedNodes_;
bool cloudAssembling_;
pcl::PointCloud<pcl::PointXYZRGB>::Ptr assembledGround_;
pcl::PointCloud<pcl::PointXYZRGB>::Ptr assembledObstacles_;
}; };
} }
+3 -1
View File
@@ -37,6 +37,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <pcl/point_types.h> #include <pcl/point_types.h>
#include <rtabmap/core/Transform.h> #include <rtabmap/core/Transform.h>
#include <rtabmap/core/Parameters.h>
#include <map> #include <map>
#include <string> #include <string>
@@ -57,7 +58,8 @@ public:
class RTABMAP_EXP OctoMap { class RTABMAP_EXP OctoMap {
public: public:
OctoMap(float voxelSize = 0.1f, float occupancyThr = 0.5f, bool fullUpdate = false); OctoMap(const ParametersMap & parameters, float occupancyThr = 0.5f);
OctoMap(float cellSize = 0.1f, float occupancyThr = 0.5f, bool fullUpdate = false);
const std::map<int, Transform> & addedNodes() const {return addedNodes_;} const std::map<int, Transform> & addedNodes() const {return addedNodes_;}
void addToCache(int nodeId, void addToCache(int nodeId,
+1
View File
@@ -93,6 +93,7 @@ private:
float _kalmanMeasurementNoise; float _kalmanMeasurementNoise;
int _imageDecimation; int _imageDecimation;
bool _alignWithGround; bool _alignWithGround;
bool _publishRAMUsage;
Transform _pose; Transform _pose;
int _resetCurrentCount; int _resetCurrentCount;
double previousStamp_; double previousStamp_;
@@ -59,6 +59,7 @@ private:
Registration * registrationPipeline_; Registration * registrationPipeline_;
Signature refFrame_; Signature refFrame_;
Transform lastKeyFramePose_; Transform lastKeyFramePose_;
ParametersMap parameters_;
}; };
} }
@@ -71,6 +71,7 @@ private:
Registration * regPipeline_; Registration * regPipeline_;
Signature * map_; Signature * map_;
Signature * lastFrame_; Signature * lastFrame_;
int lastFrameOldestNewId_;
std::vector<std::pair<pcl::PointCloud<pcl::PointNormal>::Ptr, pcl::IndicesPtr> > scansBuffer_; std::vector<std::pair<pcl::PointCloud<pcl::PointNormal>::Ptr, pcl::IndicesPtr> > scansBuffer_;
std::map<int, std::map<int, cv::Point3f> > bundleWordReferences_; //<WordId, <FrameId, pt2D+depth>> std::map<int, std::map<int, cv::Point3f> > bundleWordReferences_; //<WordId, <FrameId, pt2D+depth>>
@@ -54,6 +54,7 @@ public:
stamp(0), stamp(0),
interval(0), interval(0),
distanceTravelled(0.0f), distanceTravelled(0.0f),
memoryUsage(0),
type(0) type(0)
{} {}
@@ -80,6 +81,7 @@ public:
output.transformFiltered = transformFiltered; output.transformFiltered = transformFiltered;
output.transformGroundTruth = transformGroundTruth; output.transformGroundTruth = transformGroundTruth;
output.distanceTravelled = distanceTravelled; output.distanceTravelled = distanceTravelled;
output.memoryUsage = memoryUsage;
output.type = type; output.type = type;
return output; return output;
} }
@@ -104,6 +106,7 @@ public:
Transform transformFiltered; Transform transformFiltered;
Transform transformGroundTruth; Transform transformGroundTruth;
float distanceTravelled; float distanceTravelled;
int memoryUsage; //MB
int type; int type;
+52 -24
View File
@@ -172,6 +172,7 @@ class RTABMAP_EXP Parameters
RTABMAP_PARAM(Rtabmap, PublishLastSignature, bool, true, "Publishing last signature."); RTABMAP_PARAM(Rtabmap, PublishLastSignature, bool, true, "Publishing last signature.");
RTABMAP_PARAM(Rtabmap, PublishPdf, bool, true, "Publishing pdf."); RTABMAP_PARAM(Rtabmap, PublishPdf, bool, true, "Publishing pdf.");
RTABMAP_PARAM(Rtabmap, PublishLikelihood, bool, true, "Publishing likelihood."); RTABMAP_PARAM(Rtabmap, PublishLikelihood, bool, true, "Publishing likelihood.");
RTABMAP_PARAM(Rtabmap, PublishRAMUsage, bool, false, "Publishing RAM usage in statistics (may add a small overhead to get info from the system).");
RTABMAP_PARAM(Rtabmap, ComputeRMSE, bool, true, "Compute root mean square error (RMSE) and publish it in statistics, if ground truth is provided."); RTABMAP_PARAM(Rtabmap, ComputeRMSE, bool, true, "Compute root mean square error (RMSE) and publish it in statistics, if ground truth is provided.");
RTABMAP_PARAM(Rtabmap, TimeThr, float, 0, "Maximum time allowed for the detector (ms) (0 means infinity)."); RTABMAP_PARAM(Rtabmap, TimeThr, float, 0, "Maximum time allowed for the detector (ms) (0 means infinity).");
RTABMAP_PARAM(Rtabmap, MemoryThr, int, 0, "Maximum signatures in the Working Memory (ms) (0 means infinity)."); RTABMAP_PARAM(Rtabmap, MemoryThr, int, 0, "Maximum signatures in the Working Memory (ms) (0 means infinity).");
@@ -208,6 +209,7 @@ class RTABMAP_EXP Parameters
RTABMAP_PARAM(Mem, GenerateIds, bool, true, "True=Generate location IDs, False=use input image IDs."); RTABMAP_PARAM(Mem, GenerateIds, bool, true, "True=Generate location IDs, False=use input image IDs.");
RTABMAP_PARAM(Mem, BadSignaturesIgnored, bool, false, "Bad signatures are ignored."); RTABMAP_PARAM(Mem, BadSignaturesIgnored, bool, false, "Bad signatures are ignored.");
RTABMAP_PARAM(Mem, InitWMWithAllNodes, bool, false, "Initialize the Working Memory with all nodes in Long-Term Memory. When false, it is initialized with nodes of the previous session."); RTABMAP_PARAM(Mem, InitWMWithAllNodes, bool, false, "Initialize the Working Memory with all nodes in Long-Term Memory. When false, it is initialized with nodes of the previous session.");
RTABMAP_PARAM(Mem, DepthAsMask, bool, true, "Use depth image as mask when extracting features for vocabulary.");
RTABMAP_PARAM(Mem, ImagePreDecimation, int, 1, "Image decimation (>=1) 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)."); RTABMAP_PARAM(Mem, ImagePreDecimation, int, 1, "Image decimation (>=1) 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).");
RTABMAP_PARAM(Mem, ImagePostDecimation, int, 1, "Image decimation (>=1) of saved data in created signatures (after features extraction). Decimation is done from 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)."); RTABMAP_PARAM(Mem, ImagePostDecimation, int, 1, "Image decimation (>=1) of saved data in created signatures (after features extraction). Decimation is done from 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).");
RTABMAP_PARAM(Mem, CompressionParallelized, bool, true, "Compression of sensor data is multi-threaded."); RTABMAP_PARAM(Mem, CompressionParallelized, bool, true, "Compression of sensor data is multi-threaded.");
@@ -215,21 +217,27 @@ class RTABMAP_EXP Parameters
RTABMAP_PARAM(Mem, LaserScanVoxelSize, float, 0.0, uFormat("If > 0 m, voxel filtering is done on laser scans when creating a signature. If the laser scan had normals, they will be removed. To recompute the normals, make sure to use \"%s\" or \"%s\" parameters.", kMemLaserScanNormalK().c_str(), kMemLaserScanNormalRadius().c_str()).c_str()); RTABMAP_PARAM(Mem, LaserScanVoxelSize, float, 0.0, uFormat("If > 0 m, voxel filtering is done on laser scans when creating a signature. If the laser scan had normals, they will be removed. To recompute the normals, make sure to use \"%s\" or \"%s\" parameters.", kMemLaserScanNormalK().c_str(), kMemLaserScanNormalRadius().c_str()).c_str());
RTABMAP_PARAM(Mem, LaserScanNormalK, int, 0, "If > 0 and laser scans don't have normals, normals will be computed with K search neighbors when creating a signature."); RTABMAP_PARAM(Mem, LaserScanNormalK, int, 0, "If > 0 and laser scans don't have normals, normals will be computed with K search neighbors when creating a signature.");
RTABMAP_PARAM(Mem, LaserScanNormalRadius, int, 0, "If > 0 m and laser scans don't have normals, normals will be computed with radius search neighbors when creating a signature."); RTABMAP_PARAM(Mem, LaserScanNormalRadius, int, 0, "If > 0 m and laser scans don't have normals, normals will be computed with radius search neighbors when creating a signature.");
RTABMAP_PARAM(Mem, UseOdomFeatures, bool, false, "Use odometry features."); RTABMAP_PARAM(Mem, UseOdomFeatures, bool, true, "Use odometry features.");
// KeypointMemory (Keypoint-based) // KeypointMemory (Keypoint-based)
RTABMAP_PARAM(Kp, NNStrategy, int, 1, "kNNFlannNaive=0, kNNFlannKdTree=1, kNNFlannLSH=2, kNNBruteForce=3, kNNBruteForceGPU=4"); RTABMAP_PARAM(Kp, NNStrategy, int, 1, "kNNFlannNaive=0, kNNFlannKdTree=1, kNNFlannLSH=2, kNNBruteForce=3, kNNBruteForceGPU=4");
RTABMAP_PARAM(Kp, IncrementalDictionary, bool, true, ""); RTABMAP_PARAM(Kp, IncrementalDictionary, bool, true, "");
RTABMAP_PARAM(Kp, IncrementalFlann, bool, true, "When using FLANN based strategy, add/remove points to its index without always rebuilding the index (the index is built only when the dictionary doubles in size)."); RTABMAP_PARAM(Kp, IncrementalFlann, bool, true, uFormat("When using FLANN based strategy, add/remove points to its index without always rebuilding the index (the index is built only when the dictionary increases of the factor \"%s\" in size).", kKpFlannRebalancingFactor().c_str()));
RTABMAP_PARAM(Kp, FlannRebalancingFactor, float, 2.0, uFormat("Factor used when rebuilding the incremental FLANN index (see \"%s\"). Set <=1 to disable.", kKpIncrementalFlann().c_str()));
RTABMAP_PARAM(Kp, MaxDepth, float, 0, "Filter extracted keypoints by depth (0=inf)."); RTABMAP_PARAM(Kp, MaxDepth, float, 0, "Filter extracted keypoints by depth (0=inf).");
RTABMAP_PARAM(Kp, MinDepth, float, 0, "Filter extracted keypoints by depth."); RTABMAP_PARAM(Kp, MinDepth, float, 0, "Filter extracted keypoints by depth.");
RTABMAP_PARAM(Kp, MaxFeatures, int, 400, "Maximum features extracted from the images (0 means not bounded, <0 means no extraction)."); RTABMAP_PARAM(Kp, MaxFeatures, int, 500, "Maximum features extracted from the images (0 means not bounded, <0 means no extraction).");
RTABMAP_PARAM(Kp, BadSignRatio, float, 0.5, "Bad signature ratio (less than Ratio x AverageWordsPerImage = bad)."); RTABMAP_PARAM(Kp, BadSignRatio, float, 0.5, "Bad signature ratio (less than Ratio x AverageWordsPerImage = bad).");
RTABMAP_PARAM(Kp, NndrRatio, float, 0.8, "NNDR ratio (A matching pair is detected, if its distance is closer than X times the distance of the second nearest neighbor.)"); RTABMAP_PARAM(Kp, NndrRatio, float, 0.8, "NNDR ratio (A matching pair is detected, if its distance is closer than X times the distance of the second nearest neighbor.)");
#ifdef RTABMAP_NONFREE #ifndef RTABMAP_NONFREE
RTABMAP_PARAM(Kp, DetectorStrategy, int, 0, "0=SURF 1=SIFT 2=ORB 3=FAST/FREAK 4=FAST/BRIEF 5=GFTT/FREAK 6=GFTT/BRIEF 7=BRISK 8=GFTT/ORB 9=KAZE."); #ifdef RTABMAP_OPENCV3
// OpenCV 3 without xFeatures2D module doesn't have BRIEF
RTABMAP_PARAM(Kp, DetectorStrategy, int, 8, "0=SURF 1=SIFT 2=ORB 3=FAST/FREAK 4=FAST/BRIEF 5=GFTT/FREAK 6=GFTT/BRIEF 7=BRISK 8=GFTT/ORB 9=KAZE.");
#else #else
RTABMAP_PARAM(Kp, DetectorStrategy, int, 2, "0=SURF 1=SIFT 2=ORB 3=FAST/FREAK 4=FAST/BRIEF 5=GFTT/FREAK 6=GFTT/BRIEF 7=BRISK 8=GFTT/ORB 9=KAZE."); RTABMAP_PARAM(Kp, DetectorStrategy, int, 6, "0=SURF 1=SIFT 2=ORB 3=FAST/FREAK 4=FAST/BRIEF 5=GFTT/FREAK 6=GFTT/BRIEF 7=BRISK 8=GFTT/ORB 9=KAZE.");
#endif
#else
RTABMAP_PARAM(Kp, DetectorStrategy, int, 6, "0=SURF 1=SIFT 2=ORB 3=FAST/FREAK 4=FAST/BRIEF 5=GFTT/FREAK 6=GFTT/BRIEF 7=BRISK 8=GFTT/ORB 9=KAZE.");
#endif #endif
RTABMAP_PARAM(Kp, TfIdfLikelihoodUsed, bool, true, "Use of the td-idf strategy to compute the likelihood."); RTABMAP_PARAM(Kp, TfIdfLikelihoodUsed, bool, true, "Use of the td-idf strategy to compute the likelihood.");
RTABMAP_PARAM(Kp, Parallelized, bool, true, "If the dictionary update and signature creation were parallelized."); RTABMAP_PARAM(Kp, Parallelized, bool, true, "If the dictionary update and signature creation were parallelized.");
@@ -275,8 +283,8 @@ class RTABMAP_EXP Parameters
RTABMAP_PARAM(FAST, GridRows, int, 4, "Grid rows (0 to disable). Adapts the detector to partition the source image into a grid and detect points in each cell."); RTABMAP_PARAM(FAST, GridRows, int, 4, "Grid rows (0 to disable). Adapts the detector to partition the source image into a grid and detect points in each cell.");
RTABMAP_PARAM(FAST, GridCols, int, 4, "Grid cols (0 to disable). Adapts the detector to partition the source image into a grid and detect points in each cell."); RTABMAP_PARAM(FAST, GridCols, int, 4, "Grid cols (0 to disable). Adapts the detector to partition the source image into a grid and detect points in each cell.");
RTABMAP_PARAM(GFTT, QualityLevel, double, 0.01, ""); RTABMAP_PARAM(GFTT, QualityLevel, double, 0.001, "");
RTABMAP_PARAM(GFTT, MinDistance, double, 5, ""); RTABMAP_PARAM(GFTT, MinDistance, double, 3, "");
RTABMAP_PARAM(GFTT, BlockSize, int, 3, ""); RTABMAP_PARAM(GFTT, BlockSize, int, 3, "");
RTABMAP_PARAM(GFTT, UseHarrisDetector, bool, false, ""); RTABMAP_PARAM(GFTT, UseHarrisDetector, bool, false, "");
RTABMAP_PARAM(GFTT, K, double, 0.04, ""); RTABMAP_PARAM(GFTT, K, double, 0.04, "");
@@ -325,7 +333,7 @@ class RTABMAP_EXP Parameters
RTABMAP_PARAM(RGBD, AngularSpeedUpdate, float, 0.0, "Maximum angular speed (rad/s) to update the map (0 means not limit)."); RTABMAP_PARAM(RGBD, AngularSpeedUpdate, float, 0.0, "Maximum angular speed (rad/s) to update the map (0 means not limit).");
RTABMAP_PARAM(RGBD, NewMapOdomChangeDistance, float, 0, "A new map is created if a change of odometry translation greater than X m is detected (0 m = disabled)."); RTABMAP_PARAM(RGBD, NewMapOdomChangeDistance, float, 0, "A new map is created if a change of odometry translation greater than X m is detected (0 m = disabled).");
RTABMAP_PARAM(RGBD, OptimizeFromGraphEnd, bool, false, "Optimize graph from the newest node. If false, the graph is optimized from the oldest node of the current graph (this adds an overhead computation to detect to oldest node of the current graph, but it can be useful to preserve the map referential from the oldest node). Warning when set to false: when some nodes are transferred, the first referential of the local map may change, resulting in momentary changes in robot/map position (which are annoying in teleoperation)."); RTABMAP_PARAM(RGBD, OptimizeFromGraphEnd, bool, false, "Optimize graph from the newest node. If false, the graph is optimized from the oldest node of the current graph (this adds an overhead computation to detect to oldest node of the current graph, but it can be useful to preserve the map referential from the oldest node). Warning when set to false: when some nodes are transferred, the first referential of the local map may change, resulting in momentary changes in robot/map position (which are annoying in teleoperation).");
RTABMAP_PARAM(RGBD, OptimizeMaxError, float, 1, uFormat("Reject loop closures if optimization error ratio is greater than this value (0=disabled). Ratio is computed as absolute error over standard deviation of each link. This will help to detect when a wrong loop closure is added to the graph. Not compatible with \"%s\" if enabled.", kOptimizerRobust().c_str())); RTABMAP_PARAM(RGBD, OptimizeMaxError, float, 1.0, uFormat("Reject loop closures if optimization error ratio is greater than this value (0=disabled). Ratio is computed as absolute error over standard deviation of each link. This will help to detect when a wrong loop closure is added to the graph. Not compatible with \"%s\" if enabled.", kOptimizerRobust().c_str()));
RTABMAP_PARAM(RGBD, GoalReachedRadius, float, 0.5, "Goal reached radius (m)."); RTABMAP_PARAM(RGBD, GoalReachedRadius, float, 0.5, "Goal reached radius (m).");
RTABMAP_PARAM(RGBD, PlanStuckIterations, int, 0, "Mark the current goal node on the path as unreachable if it is not updated after X iterations (0=disabled). If all upcoming nodes on the path are unreachabled, the plan fails."); RTABMAP_PARAM(RGBD, PlanStuckIterations, int, 0, "Mark the current goal node on the path as unreachable if it is not updated after X iterations (0=disabled). If all upcoming nodes on the path are unreachabled, the plan fails.");
RTABMAP_PARAM(RGBD, PlanLinearVelocity, float, 0, "Linear velocity (m/sec) used to compute path weights."); RTABMAP_PARAM(RGBD, PlanLinearVelocity, float, 0, "Linear velocity (m/sec) used to compute path weights.");
@@ -344,7 +352,7 @@ class RTABMAP_EXP Parameters
RTABMAP_PARAM(RGBD, ProximityBySpace, bool, true, "Detection over locations (in Working Memory) near in space."); RTABMAP_PARAM(RGBD, ProximityBySpace, bool, true, "Detection over locations (in Working Memory) near in space.");
RTABMAP_PARAM(RGBD, ProximityMaxGraphDepth, int, 50, "Maximum depth from the current/last loop closure location and the local loop closure hypotheses. Set 0 to ignore."); RTABMAP_PARAM(RGBD, ProximityMaxGraphDepth, int, 50, "Maximum depth from the current/last loop closure location and the local loop closure hypotheses. Set 0 to ignore.");
RTABMAP_PARAM(RGBD, ProximityMaxPaths, int, 3, "Maximum paths compared (from the most recent) for proximity detection by space. 0 means no limit."); RTABMAP_PARAM(RGBD, ProximityMaxPaths, int, 3, "Maximum paths compared (from the most recent) for proximity detection by space. 0 means no limit.");
RTABMAP_PARAM(RGBD, ProximityPathFilteringRadius, float, 0.5, "Path filtering radius to reduce the number of nodes to compare in a path. A path should also be inside that radius to be considered for proximity detection."); RTABMAP_PARAM(RGBD, ProximityPathFilteringRadius, float, 1, "Path filtering radius to reduce the number of nodes to compare in a path. A path should also be inside that radius to be considered for proximity detection.");
RTABMAP_PARAM(RGBD, ProximityPathMaxNeighbors, int, 0, "Maximum neighbor nodes compared on each path. Set to 0 to disable merging the laser scans."); RTABMAP_PARAM(RGBD, ProximityPathMaxNeighbors, int, 0, "Maximum neighbor nodes compared on each path. Set to 0 to disable merging the laser scans.");
RTABMAP_PARAM(RGBD, ProximityPathRawPosesUsed, bool, true, "When comparing to a local path, merge the scan using the odometry poses (with neighbor link optimizations) instead of the ones in the optimized local graph."); RTABMAP_PARAM(RGBD, ProximityPathRawPosesUsed, bool, true, "When comparing to a local path, merge the scan using the odometry poses (with neighbor link optimizations) instead of the ones in the optimized local graph.");
RTABMAP_PARAM(RGBD, ProximityAngle, float, 45, "Maximum angle (degrees) for visual proximity detection."); RTABMAP_PARAM(RGBD, ProximityAngle, float, 45, "Maximum angle (degrees) for visual proximity detection.");
@@ -395,9 +403,9 @@ class RTABMAP_EXP Parameters
RTABMAP_PARAM(Odom, ParticleLambdaR, float, 100, "Lambda of rotational components (roll,pitch,yaw)."); RTABMAP_PARAM(Odom, ParticleLambdaR, float, 100, "Lambda of rotational components (roll,pitch,yaw).");
RTABMAP_PARAM(Odom, KalmanProcessNoise, float, 0.001, "Process noise covariance value."); RTABMAP_PARAM(Odom, KalmanProcessNoise, float, 0.001, "Process noise covariance value.");
RTABMAP_PARAM(Odom, KalmanMeasurementNoise, float, 0.01, "Process measurement covariance value."); RTABMAP_PARAM(Odom, KalmanMeasurementNoise, float, 0.01, "Process measurement covariance value.");
RTABMAP_PARAM(Odom, GuessMotion, bool, false, "Guess next transformation from the last motion computed."); RTABMAP_PARAM(Odom, GuessMotion, bool, true, "Guess next transformation from the last motion computed.");
RTABMAP_PARAM(Odom, KeyFrameThr, float, 0.3, "[Visual] Create a new keyframe when the number of inliers drops under this ratio of features in last frame. Setting the value to 0 means that a keyframe is created for each processed frame."); RTABMAP_PARAM(Odom, KeyFrameThr, float, 0.3, "[Visual] Create a new keyframe when the number of inliers drops under this ratio of features in last frame. Setting the value to 0 means that a keyframe is created for each processed frame.");
RTABMAP_PARAM(Odom, VisKeyFrameThr, int, 100, "[Visual] Create a new keyframe when the number of inliers drops under this threshold. Setting the value to 0 means that a keyframe is created for each processed frame."); RTABMAP_PARAM(Odom, VisKeyFrameThr, int, 150, "[Visual] Create a new keyframe when the number of inliers drops under this threshold. Setting the value to 0 means that a keyframe is created for each processed frame.");
RTABMAP_PARAM(Odom, ScanKeyFrameThr, float, 0.9, "[Geometry] Create a new keyframe when the number of ICP inliers drops under this ratio of points in last frame's scan. Setting the value to 0 means that a keyframe is created for each processed frame."); RTABMAP_PARAM(Odom, ScanKeyFrameThr, float, 0.9, "[Geometry] Create a new keyframe when the number of ICP inliers drops under this ratio of points in last frame's scan. Setting the value to 0 means that a keyframe is created for each processed frame.");
RTABMAP_PARAM(Odom, ImageDecimation, int, 1, "Decimation of the images before registration. 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)."); RTABMAP_PARAM(Odom, ImageDecimation, int, 1, "Decimation of the images before registration. 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).");
RTABMAP_PARAM(Odom, AlignWithGround, bool, false, "Align odometry with the ground on initialization."); RTABMAP_PARAM(Odom, AlignWithGround, bool, false, "Align odometry with the ground on initialization.");
@@ -408,8 +416,12 @@ class RTABMAP_EXP Parameters
RTABMAP_PARAM(OdomF2M, ScanMaxSize, int, 2000, "[Geometry] Maximum local scan map size."); RTABMAP_PARAM(OdomF2M, ScanMaxSize, int, 2000, "[Geometry] Maximum local scan map size.");
RTABMAP_PARAM(OdomF2M, ScanSubtractRadius, float, 0.05, "[Geometry] Radius used to filter points of a new added scan to local map. This could match the voxel size of the scans."); RTABMAP_PARAM(OdomF2M, ScanSubtractRadius, float, 0.05, "[Geometry] Radius used to filter points of a new added scan to local map. This could match the voxel size of the scans.");
RTABMAP_PARAM(OdomF2M, ScanSubtractAngle, float, 45, uFormat("[Geometry] Max angle (degrees) used to filter points of a new added scan to local map (when \"%s\">0). 0 means any angle.", kOdomF2MScanSubtractRadius().c_str()).c_str()); RTABMAP_PARAM(OdomF2M, ScanSubtractAngle, float, 45, uFormat("[Geometry] Max angle (degrees) used to filter points of a new added scan to local map (when \"%s\">0). 0 means any angle.", kOdomF2MScanSubtractRadius().c_str()).c_str());
#if defined(RTABMAP_G2O) || defined(RTABMAP_ORB_SLAM2)
RTABMAP_PARAM(OdomF2M, BundleAdjustment, int, 1, "Local bundle adjustment: 0=disabled, 1=g2o, 2=cvsba.");
#else
RTABMAP_PARAM(OdomF2M, BundleAdjustment, int, 0, "Local bundle adjustment: 0=disabled, 1=g2o, 2=cvsba."); RTABMAP_PARAM(OdomF2M, BundleAdjustment, int, 0, "Local bundle adjustment: 0=disabled, 1=g2o, 2=cvsba.");
RTABMAP_PARAM(OdomF2M, BundleAdjustmentMaxFrames, int, 0, "Maximum frames used for bundle adjustment (0=inf or all current frames in the local map)."); #endif
RTABMAP_PARAM(OdomF2M, BundleAdjustmentMaxFrames, int, 10, "Maximum frames used for bundle adjustment (0=inf or all current frames in the local map).");
// Odometry Mono // Odometry Mono
RTABMAP_PARAM(OdomMono, InitMinFlow, float, 100, "Minimum optical flow required for the initialization step."); RTABMAP_PARAM(OdomMono, InitMinFlow, float, 100, "Minimum optical flow required for the initialization step.");
@@ -435,7 +447,7 @@ class RTABMAP_EXP Parameters
RTABMAP_PARAM(OdomFovis, InlierMaxReprojectionError, double, 1.5, "The maximum image-space reprojection error (in pixels) a feature match is allowed to have and still be considered an inlier in the set of features used for motion estimation."); RTABMAP_PARAM(OdomFovis, InlierMaxReprojectionError, double, 1.5, "The maximum image-space reprojection error (in pixels) a feature match is allowed to have and still be considered an inlier in the set of features used for motion estimation.");
RTABMAP_PARAM(OdomFovis, CliqueInlierThreshold, double, 0.1, "See Howard's greedy max-clique algorithm for determining the maximum set of mutually consisten feature matches. This specifies the compatibility threshold, in meters."); RTABMAP_PARAM(OdomFovis, CliqueInlierThreshold, double, 0.1, "See Howard's greedy max-clique algorithm for determining the maximum set of mutually consisten feature matches. This specifies the compatibility threshold, in meters.");
RTABMAP_PARAM(OdomFovis, MinFeaturesForEstimate, int, 10, "Minimum number of features in the inlier set for the motion estimate to be considered valid."); RTABMAP_PARAM(OdomFovis, MinFeaturesForEstimate, int, 20, "Minimum number of features in the inlier set for the motion estimate to be considered valid.");
RTABMAP_PARAM(OdomFovis, MaxMeanReprojectionError, double, 10.0, "Maximum mean reprojection error over the inlier feature matches for the motion estimate to be considered valid."); RTABMAP_PARAM(OdomFovis, MaxMeanReprojectionError, double, 10.0, "Maximum mean reprojection error over the inlier feature matches for the motion estimate to be considered valid.");
RTABMAP_PARAM(OdomFovis, UseSubpixelRefinement, bool, true, "Specifies whether or not to refine feature matches to subpixel resolution."); RTABMAP_PARAM(OdomFovis, UseSubpixelRefinement, bool, true, "Specifies whether or not to refine feature matches to subpixel resolution.");
RTABMAP_PARAM(OdomFovis, FeatureSearchWindow, int, 25, "Specifies the size of the search window to apply when searching for feature matches across time frames. The search is conducted around the feature location predicted by the initial rotation estimate."); RTABMAP_PARAM(OdomFovis, FeatureSearchWindow, int, 25, "Specifies the size of the search window to apply when searching for feature matches across time frames. The search is conducted around the feature location predicted by the initial rotation estimate.");
@@ -470,9 +482,10 @@ class RTABMAP_EXP Parameters
RTABMAP_PARAM(OdomORBSLAM2, ThDepth, double, 40.0, "Close/Far threshold. Baseline times."); RTABMAP_PARAM(OdomORBSLAM2, ThDepth, double, 40.0, "Close/Far threshold. Baseline times.");
RTABMAP_PARAM(OdomORBSLAM2, Fps, float, 0.0, "Camera FPS."); RTABMAP_PARAM(OdomORBSLAM2, Fps, float, 0.0, "Camera FPS.");
RTABMAP_PARAM(OdomORBSLAM2, MaxFeatures, int, 1000, "Maximum ORB features extracted per frame."); RTABMAP_PARAM(OdomORBSLAM2, MaxFeatures, int, 1000, "Maximum ORB features extracted per frame.");
RTABMAP_PARAM(OdomORBSLAM2, MapSize, int, 3000, "Maximum size of the feature map (0 means infinite).");
// Common registration parameters // Common registration parameters
RTABMAP_PARAM(Reg, RepeatOnce, bool, false, "Do a second registration with the output of the first registration as guess. Only done if no guess was provided for the first registration. It can be useful if the registration approach used can use a guess to get better matches."); RTABMAP_PARAM(Reg, RepeatOnce, bool, true, "Do a second registration with the output of the first registration as guess. Only done if no guess was provided for the first registration (like on loop closure). It can be useful if the registration approach used can use a guess to get better matches.");
RTABMAP_PARAM(Reg, Strategy, int, 0, "0=Vis, 1=Icp, 2=VisIcp"); RTABMAP_PARAM(Reg, Strategy, int, 0, "0=Vis, 1=Icp, 2=VisIcp");
RTABMAP_PARAM(Reg, Force3DoF, bool, false, "Force 3 degrees-of-freedom transform (3Dof: x,y and yaw). Parameters z, roll and pitch will be set to 0."); RTABMAP_PARAM(Reg, Force3DoF, bool, false, "Force 3 degrees-of-freedom transform (3Dof: x,y and yaw). Parameters z, roll and pitch will be set to 0.");
@@ -483,10 +496,15 @@ class RTABMAP_EXP Parameters
RTABMAP_PARAM(Vis, RefineIterations, int, 5, uFormat("[%s = 0] Number of iterations used to refine the transformation found by RANSAC. 0 means that the transformation is not refined.", kVisEstimationType().c_str())); RTABMAP_PARAM(Vis, RefineIterations, int, 5, uFormat("[%s = 0] Number of iterations used to refine the transformation found by RANSAC. 0 means that the transformation is not refined.", kVisEstimationType().c_str()));
RTABMAP_PARAM(Vis, PnPReprojError, float, 2, uFormat("[%s = 1] PnP reprojection error.", kVisEstimationType().c_str())); RTABMAP_PARAM(Vis, PnPReprojError, float, 2, uFormat("[%s = 1] PnP reprojection error.", kVisEstimationType().c_str()));
RTABMAP_PARAM(Vis, PnPFlags, int, 0, uFormat("[%s = 1] PnP flags: 0=Iterative, 1=EPNP, 2=P3P", kVisEstimationType().c_str())); RTABMAP_PARAM(Vis, PnPFlags, int, 0, uFormat("[%s = 1] PnP flags: 0=Iterative, 1=EPNP, 2=P3P", kVisEstimationType().c_str()));
RTABMAP_PARAM(Vis, PnPRefineIterations, int, 1, uFormat("[%s = 1] Refine iterations.", kVisEstimationType().c_str())); #if defined(RTABMAP_G2O) || defined(RTABMAP_ORB_SLAM2)
RTABMAP_PARAM(Vis, PnPRefineIterations, int, 0, uFormat("[%s = 1] Refine iterations. Set to 0 if \"%s\" is also used.", kVisEstimationType().c_str(), kVisBundleAdjustment().c_str()));
#else
RTABMAP_PARAM(Vis, PnPRefineIterations, int, 1, uFormat("[%s = 1] Refine iterations. Set to 0 if \"%s\" is also used.", kVisEstimationType().c_str(), kVisBundleAdjustment().c_str()));
#endif
RTABMAP_PARAM(Vis, EpipolarGeometryVar, float, 0.02, uFormat("[%s = 2] Epipolar geometry maximum variance to accept the transformation.", kVisEstimationType().c_str())); RTABMAP_PARAM(Vis, EpipolarGeometryVar, float, 0.02, uFormat("[%s = 2] Epipolar geometry maximum variance to accept the transformation.", kVisEstimationType().c_str()));
RTABMAP_PARAM(Vis, MinInliers, int, 20, "Minimum feature correspondences to compute/accept the transformation."); RTABMAP_PARAM(Vis, MinInliers, int, 20, "Minimum feature correspondences to compute/accept the transformation.");
RTABMAP_PARAM(Vis, Iterations, int, 100, "Maximum iterations to compute the transform."); RTABMAP_PARAM(Vis, Iterations, int, 300, "Maximum iterations to compute the transform.");
#ifndef RTABMAP_NONFREE #ifndef RTABMAP_NONFREE
#ifdef RTABMAP_OPENCV3 #ifdef RTABMAP_OPENCV3
// OpenCV 3 without xFeatures2D module doesn't have BRIEF // OpenCV 3 without xFeatures2D module doesn't have BRIEF
@@ -500,6 +518,7 @@ class RTABMAP_EXP Parameters
RTABMAP_PARAM(Vis, MaxFeatures, int, 1000, "0 no limits."); RTABMAP_PARAM(Vis, MaxFeatures, int, 1000, "0 no limits.");
RTABMAP_PARAM(Vis, MaxDepth, float, 0, "Max depth of the features (0 means no limit)."); RTABMAP_PARAM(Vis, MaxDepth, float, 0, "Max depth of the features (0 means no limit).");
RTABMAP_PARAM(Vis, MinDepth, float, 0, "Min depth of the features (0 means no limit)."); RTABMAP_PARAM(Vis, MinDepth, float, 0, "Min depth of the features (0 means no limit).");
RTABMAP_PARAM(Vis, DepthAsMask, bool, true, "Use depth image as mask when extracting features.");
RTABMAP_PARAM_STR(Vis, RoiRatios, "0.0 0.0 0.0 0.0", "Region of interest ratios [left, right, top, bottom]."); RTABMAP_PARAM_STR(Vis, RoiRatios, "0.0 0.0 0.0 0.0", "Region of interest ratios [left, right, top, bottom].");
RTABMAP_PARAM(Vis, SubPixWinSize, int, 3, "See cv::cornerSubPix()."); RTABMAP_PARAM(Vis, SubPixWinSize, int, 3, "See cv::cornerSubPix().");
RTABMAP_PARAM(Vis, SubPixIterations, int, 0, "See cv::cornerSubPix(). 0 disables sub pixel refining."); RTABMAP_PARAM(Vis, SubPixIterations, int, 0, "See cv::cornerSubPix(). 0 disables sub pixel refining.");
@@ -510,29 +529,37 @@ class RTABMAP_EXP Parameters
RTABMAP_PARAM(Vis, CorNNType, int, 1, uFormat("[%s=0] kNNFlannNaive=0, kNNFlannKdTree=1, kNNFlannLSH=2, kNNBruteForce=3, kNNBruteForceGPU=4. Used for features matching approach.", kVisCorType().c_str())); RTABMAP_PARAM(Vis, CorNNType, int, 1, uFormat("[%s=0] kNNFlannNaive=0, kNNFlannKdTree=1, kNNFlannLSH=2, kNNBruteForce=3, kNNBruteForceGPU=4. Used for features matching approach.", kVisCorType().c_str()));
RTABMAP_PARAM(Vis, CorNNDR, float, 0.6, uFormat("[%s=0] NNDR: nearest neighbor distance ratio. Used for features matching approach.", kVisCorType().c_str())); RTABMAP_PARAM(Vis, CorNNDR, float, 0.6, uFormat("[%s=0] NNDR: nearest neighbor distance ratio. Used for features matching approach.", kVisCorType().c_str()));
RTABMAP_PARAM(Vis, CorGuessWinSize, int, 20, uFormat("[%s=0] Matching window size (pixels) around projected points when a guess transform is provided to find correspondences. 0 means disabled.", kVisCorType().c_str())); RTABMAP_PARAM(Vis, CorGuessWinSize, int, 20, uFormat("[%s=0] Matching window size (pixels) around projected points when a guess transform is provided to find correspondences. 0 means disabled.", kVisCorType().c_str()));
RTABMAP_PARAM(Vis, CorGuessMatchToProjection, bool, true, uFormat("[%s=0] Match frame's corners to source's projected points (when guess transform is provided) instead of projected points to frame's corners.", kVisCorType().c_str())); RTABMAP_PARAM(Vis, CorGuessMatchToProjection, bool, false, uFormat("[%s=0] Match frame's corners to source's projected points (when guess transform is provided) instead of projected points to frame's corners.", kVisCorType().c_str()));
RTABMAP_PARAM(Vis, CorFlowWinSize, int, 16, uFormat("[%s=1] See cv::calcOpticalFlowPyrLK(). Used for optical flow approach.", kVisCorType().c_str())); RTABMAP_PARAM(Vis, CorFlowWinSize, int, 16, uFormat("[%s=1] See cv::calcOpticalFlowPyrLK(). Used for optical flow approach.", kVisCorType().c_str()));
RTABMAP_PARAM(Vis, CorFlowIterations, int, 30, uFormat("[%s=1] See cv::calcOpticalFlowPyrLK(). Used for optical flow approach.", kVisCorType().c_str())); RTABMAP_PARAM(Vis, CorFlowIterations, int, 30, uFormat("[%s=1] See cv::calcOpticalFlowPyrLK(). Used for optical flow approach.", kVisCorType().c_str()));
RTABMAP_PARAM(Vis, CorFlowEps, float, 0.01, uFormat("[%s=1] See cv::calcOpticalFlowPyrLK(). Used for optical flow approach.", kVisCorType().c_str())); RTABMAP_PARAM(Vis, CorFlowEps, float, 0.01, uFormat("[%s=1] See cv::calcOpticalFlowPyrLK(). Used for optical flow approach.", kVisCorType().c_str()));
RTABMAP_PARAM(Vis, CorFlowMaxLevel, int, 3, uFormat("[%s=1] See cv::calcOpticalFlowPyrLK(). Used for optical flow approach.", kVisCorType().c_str())); RTABMAP_PARAM(Vis, CorFlowMaxLevel, int, 3, uFormat("[%s=1] See cv::calcOpticalFlowPyrLK(). Used for optical flow approach.", kVisCorType().c_str()));
#if defined(RTABMAP_G2O) || defined(RTABMAP_ORB_SLAM2)
RTABMAP_PARAM(Vis, BundleAdjustment, int, 1, "Optimization with bundle adjustment: 0=disabled, 1=g2o, 2=cvsba.");
#else
RTABMAP_PARAM(Vis, BundleAdjustment, int, 0, "Optimization with bundle adjustment: 0=disabled, 1=g2o, 2=cvsba."); RTABMAP_PARAM(Vis, BundleAdjustment, int, 0, "Optimization with bundle adjustment: 0=disabled, 1=g2o, 2=cvsba.");
#endif
// ICP registration parameters // ICP registration parameters
RTABMAP_PARAM(Icp, MaxTranslation, float, 0.2, "Maximum ICP translation correction accepted (m)."); RTABMAP_PARAM(Icp, MaxTranslation, float, 0.2, "Maximum ICP translation correction accepted (m).");
RTABMAP_PARAM(Icp, MaxRotation, float, 0.78, "Maximum ICP rotation correction accepted (rad)."); RTABMAP_PARAM(Icp, MaxRotation, float, 0.78, "Maximum ICP rotation correction accepted (rad).");
RTABMAP_PARAM(Icp, VoxelSize, float, 0.0, "Uniform sampling voxel size (0=disabled)."); RTABMAP_PARAM(Icp, VoxelSize, float, 0.0, "Uniform sampling voxel size (0=disabled).");
RTABMAP_PARAM(Icp, DownsamplingStep, int, 1, "Downsampling step size (1=no sampling). This is done before uniform sampling."); RTABMAP_PARAM(Icp, DownsamplingStep, int, 1, "Downsampling step size (1=no sampling). This is done before uniform sampling.");
RTABMAP_PARAM(Icp, MaxCorrespondenceDistance, float, 0.05, "Max distance for point correspondences."); RTABMAP_PARAM(Icp, MaxCorrespondenceDistance, float, 0.1, "Max distance for point correspondences.");
RTABMAP_PARAM(Icp, Iterations, int, 30, "Max iterations."); RTABMAP_PARAM(Icp, Iterations, int, 30, "Max iterations.");
RTABMAP_PARAM(Icp, Epsilon, float, 0, "Set the transformation epsilon (maximum allowable difference between two consecutive transformations) in order for an optimization to be considered as having converged to the final solution."); RTABMAP_PARAM(Icp, Epsilon, float, 0, "Set the transformation epsilon (maximum allowable difference between two consecutive transformations) in order for an optimization to be considered as having converged to the final solution.");
RTABMAP_PARAM(Icp, CorrespondenceRatio, float, 0.2, "Ratio of matching correspondences to accept the transform."); RTABMAP_PARAM(Icp, CorrespondenceRatio, float, 0.2, "Ratio of matching correspondences to accept the transform.");
RTABMAP_PARAM(Icp, PointToPlane, bool, false, "Use point to plane ICP."); RTABMAP_PARAM(Icp, PointToPlane, bool, false, "Use point to plane ICP.");
RTABMAP_PARAM(Icp, PointToPlaneK, int, 20, "Number of neighbors to compute normals for point to plane if the cloud doesn't have already normals."); RTABMAP_PARAM(Icp, PointToPlaneK, int, 5, "Number of neighbors to compute normals for point to plane if the cloud doesn't have already normals.");
RTABMAP_PARAM(Icp, PointToPlaneRadius, float, 0.0, "Search radius to compute normals for point to plane if the cloud doesn't have already normals."); RTABMAP_PARAM(Icp, PointToPlaneRadius, float, 1.0, "Search radius to compute normals for point to plane if the cloud doesn't have already normals.");
RTABMAP_PARAM(Icp, PointToPlaneMinComplexity, float, 0.02, "Minimum structural complexity (0.0=low, 1.0=high) of the scan to do point to plane registration, otherwise point to point registration is done instead."); RTABMAP_PARAM(Icp, PointToPlaneMinComplexity, float, 0.02, "Minimum structural complexity (0.0=low, 1.0=high) of the scan to do point to plane registration, otherwise point to point registration is done instead.");
// libpointmatcher // libpointmatcher
#ifdef RTABMAP_POINTMATCHER
RTABMAP_PARAM(Icp, PM, bool, true, "Use libpointmatcher for ICP registration instead of PCL's implementation.");
#else
RTABMAP_PARAM(Icp, PM, bool, false, "Use libpointmatcher for ICP registration instead of PCL's implementation."); RTABMAP_PARAM(Icp, PM, bool, false, "Use libpointmatcher for ICP registration instead of PCL's implementation.");
#endif
RTABMAP_PARAM_STR(Icp, PMConfig, "", uFormat("Configuration file (*.yaml) used by libpointmatcher. Note that data filters set for libpointmatcher are done after filtering done by rtabmap (i.e., %s, %s), so make sure to disable those in rtabmap if you want to use only those from libpointmatcher. Parameters %s, %s and %s are also ignored if configuration file is set.", kIcpVoxelSize().c_str(), kIcpDownsamplingStep().c_str(), kIcpIterations().c_str(), kIcpEpsilon().c_str(), kIcpMaxCorrespondenceDistance().c_str()).c_str()); RTABMAP_PARAM_STR(Icp, PMConfig, "", uFormat("Configuration file (*.yaml) used by libpointmatcher. Note that data filters set for libpointmatcher are done after filtering done by rtabmap (i.e., %s, %s), so make sure to disable those in rtabmap if you want to use only those from libpointmatcher. Parameters %s, %s and %s are also ignored if configuration file is set.", kIcpVoxelSize().c_str(), kIcpDownsamplingStep().c_str(), kIcpIterations().c_str(), kIcpEpsilon().c_str(), kIcpMaxCorrespondenceDistance().c_str()).c_str());
RTABMAP_PARAM(Icp, PMMatcherKnn, int, 1, "KDTreeMatcher/knn: number of nearest neighbors to consider it the reference. For convenience when configuration file is not set."); RTABMAP_PARAM(Icp, PMMatcherKnn, int, 1, "KDTreeMatcher/knn: number of nearest neighbors to consider it the reference. For convenience when configuration file is not set.");
RTABMAP_PARAM(Icp, PMMatcherEpsilon, float, 0.0, "KDTreeMatcher/epsilon: approximation to use for the nearest-neighbor search. For convenience when configuration file is not set."); RTABMAP_PARAM(Icp, PMMatcherEpsilon, float, 0.0, "KDTreeMatcher/epsilon: approximation to use for the nearest-neighbor search. For convenience when configuration file is not set.");
@@ -542,8 +569,8 @@ class RTABMAP_EXP Parameters
RTABMAP_PARAM(Stereo, WinWidth, int, 15, "Window width."); RTABMAP_PARAM(Stereo, WinWidth, int, 15, "Window width.");
RTABMAP_PARAM(Stereo, WinHeight, int, 3, "Window height."); RTABMAP_PARAM(Stereo, WinHeight, int, 3, "Window height.");
RTABMAP_PARAM(Stereo, Iterations, int, 30, "Maximum iterations."); RTABMAP_PARAM(Stereo, Iterations, int, 30, "Maximum iterations.");
RTABMAP_PARAM(Stereo, MaxLevel, int, 3, "Maximum pyramid level."); RTABMAP_PARAM(Stereo, MaxLevel, int, 5, "Maximum pyramid level.");
RTABMAP_PARAM(Stereo, MinDisparity, float, 1.0, "Minimum disparity."); RTABMAP_PARAM(Stereo, MinDisparity, float, 0.5, "Minimum disparity.");
RTABMAP_PARAM(Stereo, MaxDisparity, float, 128.0, "Maximum disparity."); RTABMAP_PARAM(Stereo, MaxDisparity, float, 128.0, "Maximum disparity.");
RTABMAP_PARAM(Stereo, OpticalFlow, bool, true, "Use optical flow to find stereo correspondences, otherwise a simple block matching approach is used."); RTABMAP_PARAM(Stereo, OpticalFlow, bool, true, "Use optical flow to find stereo correspondences, otherwise a simple block matching approach is used.");
RTABMAP_PARAM(Stereo, SSD, bool, true, uFormat("[%s=false] Use Sum of Squared Differences (SSD) window, otherwise Sum of Absolute Differences (SAD) window is used.", kStereoOpticalFlow().c_str())); RTABMAP_PARAM(Stereo, SSD, bool, true, uFormat("[%s=false] Use Sum of Squared Differences (SSD) window, otherwise Sum of Absolute Differences (SAD) window is used.", kStereoOpticalFlow().c_str()));
@@ -574,7 +601,7 @@ class RTABMAP_EXP Parameters
RTABMAP_PARAM(Grid, NormalsSegmentation, bool, true, "Segment ground from obstacles using point normals, otherwise a fast passthrough is used."); RTABMAP_PARAM(Grid, NormalsSegmentation, bool, true, "Segment ground from obstacles using point normals, otherwise a fast passthrough is used.");
RTABMAP_PARAM(Grid, MaxObstacleHeight, float, 0.0, "Maximum obstacles height (0=disabled)."); RTABMAP_PARAM(Grid, MaxObstacleHeight, float, 0.0, "Maximum obstacles height (0=disabled).");
RTABMAP_PARAM(Grid, MinGroundHeight, float, 0.0, "Minimum ground height (0=disabled)."); RTABMAP_PARAM(Grid, MinGroundHeight, float, 0.0, "Minimum ground height (0=disabled).");
RTABMAP_PARAM(Grid, MaxGroundHeight, float, 0.0, uFormat("Maximum ground height (0=disabled). Should be set if \"%s\" is true.", kGridNormalsSegmentation().c_str())); RTABMAP_PARAM(Grid, MaxGroundHeight, float, 0.0, uFormat("Maximum ground height (0=disabled). Should be set if \"%s\" is false.", kGridNormalsSegmentation().c_str()));
RTABMAP_PARAM(Grid, MaxGroundAngle, float, 45, uFormat("[%s=true] Maximum angle (degrees) between point's normal to ground's normal to label it as ground. Points with higher angle difference are considered as obstacles.", kGridNormalsSegmentation().c_str())); RTABMAP_PARAM(Grid, MaxGroundAngle, float, 45, uFormat("[%s=true] Maximum angle (degrees) between point's normal to ground's normal to label it as ground. Points with higher angle difference are considered as obstacles.", kGridNormalsSegmentation().c_str()));
RTABMAP_PARAM(Grid, NormalK, int, 20, uFormat("[%s=true] K neighbors to compute normals.", kGridNormalsSegmentation().c_str())); RTABMAP_PARAM(Grid, NormalK, int, 20, uFormat("[%s=true] K neighbors to compute normals.", kGridNormalsSegmentation().c_str()));
RTABMAP_PARAM(Grid, ClusterRadius, float, 0.1, uFormat("[%s=true] Cluster maximum radius.", kGridNormalsSegmentation().c_str())); RTABMAP_PARAM(Grid, ClusterRadius, float, 0.1, uFormat("[%s=true] Cluster maximum radius.", kGridNormalsSegmentation().c_str()));
@@ -596,6 +623,7 @@ class RTABMAP_EXP Parameters
RTABMAP_PARAM(GridGlobal, FootprintRadius, float, 0.0, "Footprint radius (m) used to clear all obstacles under the graph."); RTABMAP_PARAM(GridGlobal, FootprintRadius, float, 0.0, "Footprint radius (m) used to clear all obstacles under the graph.");
RTABMAP_PARAM(GridGlobal, MinSize, float, 0.0, "Minimum map size (m)."); RTABMAP_PARAM(GridGlobal, MinSize, float, 0.0, "Minimum map size (m).");
RTABMAP_PARAM(GridGlobal, Eroded, bool, false, "Erode obstacle cells."); RTABMAP_PARAM(GridGlobal, Eroded, bool, false, "Erode obstacle cells.");
RTABMAP_PARAM(GridGlobal, MaxNodes, int, 0, "Maximum nodes assembled in the map starting from the last node (0=unlimited).");
public: public:
virtual ~Parameters(); virtual ~Parameters();
@@ -59,6 +59,8 @@ public:
bool isScanRequired() const; bool isScanRequired() const;
bool isUserDataRequired() const; bool isUserDataRequired() const;
bool canUseGuess() const;
int getMinVisualCorrespondences() const; int getMinVisualCorrespondences() const;
float getMinGeometryCorrespondencesRatio() const; float getMinGeometryCorrespondencesRatio() const;
@@ -100,6 +102,7 @@ protected:
virtual bool isImageRequiredImpl() const {return false;} virtual bool isImageRequiredImpl() const {return false;}
virtual bool isScanRequiredImpl() const {return false;} virtual bool isScanRequiredImpl() const {return false;}
virtual bool isUserDataRequiredImpl() const {return false;} virtual bool isUserDataRequiredImpl() const {return false;}
virtual bool canUseGuessImpl() const {return false;}
virtual int getMinVisualCorrespondencesImpl() const {return 0;} virtual int getMinVisualCorrespondencesImpl() const {return 0;}
virtual float getMinGeometryCorrespondencesRatioImpl() const {return 0.0f;} virtual float getMinGeometryCorrespondencesRatioImpl() const {return 0.0f;}
@@ -52,6 +52,7 @@ protected:
Transform guess, Transform guess,
RegistrationInfo & info) const; RegistrationInfo & info) const;
virtual bool isScanRequiredImpl() const {return true;} virtual bool isScanRequiredImpl() const {return true;}
virtual bool canUseGuessImpl() const {return true;}
virtual float getMinGeometryCorrespondencesRatioImpl() const {return _correspondenceRatio;} virtual float getMinGeometryCorrespondencesRatioImpl() const {return _correspondenceRatio;}
private: private:
@@ -70,6 +70,7 @@ public:
std::vector<int> inliersIDs; std::vector<int> inliersIDs;
int matches; int matches;
std::vector<int> matchesIDs; std::vector<int> matchesIDs;
std::vector<int> projectedIDs; // "From" IDs
// RegistrationIcp // RegistrationIcp
float icpInliersRatio; float icpInliersRatio;
@@ -61,6 +61,7 @@ protected:
RegistrationInfo & info) const; RegistrationInfo & info) const;
virtual bool isImageRequiredImpl() const {return true;} virtual bool isImageRequiredImpl() const {return true;}
virtual bool canUseGuessImpl() const {return _correspondencesApproach != 0 || _guessWinSize>0;}
virtual int getMinVisualCorrespondencesImpl() const {return _minInliers;} virtual int getMinVisualCorrespondencesImpl() const {return _minInliers;}
private: private:
@@ -83,6 +84,7 @@ private:
int _guessWinSize; int _guessWinSize;
bool _guessMatchToProjection; bool _guessMatchToProjection;
int _bundleAdjustment; int _bundleAdjustment;
bool _depthAsMask;
ParametersMap _featureParameters; ParametersMap _featureParameters;
ParametersMap _bundleParameters; ParametersMap _bundleParameters;
+2
View File
@@ -118,6 +118,7 @@ public:
const Statistics & getStatistics() const; const Statistics & getStatistics() const;
//bool getMetricData(int locationId, cv::Mat & rgb, cv::Mat & depth, float & depthConstant, Transform & pose, Transform & localTransform) const; //bool getMetricData(int locationId, cv::Mat & rgb, cv::Mat & depth, float & depthConstant, Transform & pose, Transform & localTransform) const;
const std::map<int, Transform> & getLocalOptimizedPoses() const {return _optimizedPoses;} const std::map<int, Transform> & getLocalOptimizedPoses() const {return _optimizedPoses;}
const std::multimap<int, Link> & getLocalConstraints() const {return _constraints;}
Transform getPose(int locationId) const; Transform getPose(int locationId) const;
Transform getMapCorrection() const {return _mapCorrection;} Transform getMapCorrection() const {return _mapCorrection;}
const Memory * getMemory() const {return _memory;} const Memory * getMemory() const {return _memory;}
@@ -211,6 +212,7 @@ private:
bool _publishLastSignatureData; bool _publishLastSignatureData;
bool _publishPdf; bool _publishPdf;
bool _publishLikelihood; bool _publishLikelihood;
bool _publishRAMUsage;
bool _computeRMSE; bool _computeRMSE;
float _maxTimeAllowed; // in ms float _maxTimeAllowed; // in ms
unsigned int _maxMemoryAllowed; // signatures count in WM unsigned int _maxMemoryAllowed; // signatures count in WM
@@ -103,6 +103,7 @@ class RTABMAP_EXP Statistics
RTABMAP_STATS(Memory, Odometry_variance_ang,); RTABMAP_STATS(Memory, Odometry_variance_ang,);
RTABMAP_STATS(Memory, Odometry_variance_lin,); RTABMAP_STATS(Memory, Odometry_variance_lin,);
RTABMAP_STATS(Memory, Distance_travelled, m); RTABMAP_STATS(Memory, Distance_travelled, m);
RTABMAP_STATS(Memory, RAM_usage, MB);
RTABMAP_STATS(Timing, Memory_update, ms); RTABMAP_STATS(Timing, Memory_update, ms);
RTABMAP_STATS(Timing, Neighbor_link_refining, ms); RTABMAP_STATS(Timing, Neighbor_link_refining, ms);
+2
View File
@@ -56,6 +56,8 @@ public:
// x,y, theta // x,y, theta
Transform(float x, float y, float theta); Transform(float x, float y, float theta);
Transform clone() const;
float r11() const {return data()[0];} float r11() const {return data()[0];}
float r12() const {return data()[1];} float r12() const {return data()[1];}
float r13() const {return data()[2];} float r13() const {return data()[2];}
@@ -114,6 +114,7 @@ private:
bool _newWordsComparedTogether; bool _newWordsComparedTogether;
int _lastWordId; int _lastWordId;
bool useDistanceL1_; bool useDistanceL1_;
float _rebalancingFactor;
FlannIndex * _flannIndex; FlannIndex * _flannIndex;
cv::Mat _dataTree; cv::Mat _dataTree;
NNStrategy _strategy; NNStrategy _strategy;
+6
View File
@@ -74,6 +74,12 @@ pcl::PointXYZ RTABMAP_EXP projectDepthTo3D(
bool smoothing, bool smoothing,
float depthErrorRatio = 0.02f); float depthErrorRatio = 0.02f);
Eigen::Vector3f RTABMAP_EXP projectDepthTo3DRay(
const cv::Size & imageSize,
float x, float y,
float cx, float cy,
float fx, float fy);
RTABMAP_DEPRECATED (pcl::PointCloud<pcl::PointXYZ>::Ptr RTABMAP_EXP cloudFromDepth( RTABMAP_DEPRECATED (pcl::PointCloud<pcl::PointXYZ>::Ptr RTABMAP_EXP cloudFromDepth(
const cv::Mat & imageDepth, const cv::Mat & imageDepth,
float cx, float cy, float cx, float cy,
@@ -304,6 +304,14 @@ pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr RTABMAP_EXP mls(
float dilationVoxelSize = 1.0f, // VOXEL_GRID_DILATION float dilationVoxelSize = 1.0f, // VOXEL_GRID_DILATION
int dilationIterations = 0); // VOXEL_GRID_DILATION int dilationIterations = 0); // VOXEL_GRID_DILATION
void RTABMAP_EXP adjustNormalsToViewPoint(
pcl::PointCloud<pcl::PointNormal>::Ptr & cloud,
const Eigen::Vector3f & viewpoint = Eigen::Vector3f(0,0,0),
bool forceGroundNormalsUp = false);
void RTABMAP_EXP adjustNormalsToViewPoint(
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud,
const Eigen::Vector3f & viewpoint = Eigen::Vector3f(0,0,0),
bool forceGroundNormalsUp = false);
void RTABMAP_EXP adjustNormalsToViewPoints( void RTABMAP_EXP adjustNormalsToViewPoints(
const std::map<int, Transform> & poses, const std::map<int, Transform> & poses,
const pcl::PointCloud<pcl::PointXYZ>::Ptr & rawCloud, const pcl::PointCloud<pcl::PointXYZ>::Ptr & rawCloud,
+85 -67
View File
@@ -30,6 +30,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "rtabmap/core/Signature.h" #include "rtabmap/core/Signature.h"
#include "rtabmap/core/Parameters.h" #include "rtabmap/core/Parameters.h"
#include <iostream> #include <iostream>
#include <set>
#include <unordered_set>
#include "rtabmap/utilite/UtiLite.h" #include "rtabmap/utilite/UtiLite.h"
@@ -125,6 +127,7 @@ void BayesFilter::reset()
{ {
_posterior.clear(); _posterior.clear();
_prediction = cv::Mat(); _prediction = cv::Mat();
_neighborsIndex.clear();
} }
const std::map<int, float> & BayesFilter::computePosterior(const Memory * memory, const std::map<int, float> & likelihood) const std::map<int, float> & BayesFilter::computePosterior(const Memory * memory, const std::map<int, float> & likelihood)
@@ -219,7 +222,7 @@ const std::map<int, float> & BayesFilter::computePosterior(const Memory * memory
return _posterior; return _posterior;
} }
cv::Mat BayesFilter::generatePrediction(const Memory * memory, const std::vector<int> & ids) const cv::Mat BayesFilter::generatePrediction(const Memory * memory, const std::vector<int> & ids)
{ {
if(!_fullPredictionUpdate && !_prediction.empty()) if(!_fullPredictionUpdate && !_prediction.empty())
{ {
@@ -236,12 +239,16 @@ cv::Mat BayesFilter::generatePrediction(const Memory * memory, const std::vector
UTimer timerGlobal; UTimer timerGlobal;
timerGlobal.start(); timerGlobal.start();
std::map<int, int> idToIndexMap; std::unordered_map<int,int> idToIndexMap;
idToIndexMap.reserve(ids.size());
for(unsigned int i=0; i<ids.size(); ++i) for(unsigned int i=0; i<ids.size(); ++i)
{ {
UASSERT_MSG(ids[i] != 0, "Signature id is null ?!?"); if(ids[i]>0)
idToIndexMap.insert(idToIndexMap.end(), std::make_pair(ids[i], i)); {
idToIndexMap[ids[i]] = i;
} }
}
//int rows = prediction.rows; //int rows = prediction.rows;
cv::Mat prediction = cv::Mat::zeros(ids.size(), ids.size(), CV_32FC1); cv::Mat prediction = cv::Mat::zeros(ids.size(), ids.size(), CV_32FC1);
@@ -260,7 +267,13 @@ cv::Mat BayesFilter::generatePrediction(const Memory * memory, const std::vector
// Set high values (gaussians curves) to loop closure neighbors // Set high values (gaussians curves) to loop closure neighbors
// ADD prob for each neighbors // ADD prob for each neighbors
std::map<int, int> neighbors = memory->getNeighborsId(ids[i], _predictionLC.size()-1, 0, false, false, true); std::map<int, int> neighbors = memory->getNeighborsId(ids[i], _predictionLC.size()-1, 0, false, false, true, true);
if(!_fullPredictionUpdate)
{
uInsert(_neighborsIndex, std::make_pair(ids[i], neighbors));
}
std::list<int> idsLoopMargin; std::list<int> idsLoopMargin;
//filter neighbors in STM //filter neighbors in STM
for(std::map<int, int>::iterator iter=neighbors.begin(); iter!=neighbors.end();) for(std::map<int, int>::iterator iter=neighbors.begin(); iter!=neighbors.end();)
@@ -271,7 +284,7 @@ cv::Mat BayesFilter::generatePrediction(const Memory * memory, const std::vector
} }
else else
{ {
if(iter->second == 0) if(iter->second == 0 && idToIndexMap.find(iter->first)!=idToIndexMap.end())
{ {
idsLoopMargin.push_back(iter->first); idsLoopMargin.push_back(iter->first);
} }
@@ -288,10 +301,16 @@ cv::Mat BayesFilter::generatePrediction(const Memory * memory, const std::vector
// same neighbor tree for loop signatures (margin = 0) // same neighbor tree for loop signatures (margin = 0)
for(std::list<int>::iterator iter = idsLoopMargin.begin(); iter!=idsLoopMargin.end(); ++iter) for(std::list<int>::iterator iter = idsLoopMargin.begin(); iter!=idsLoopMargin.end(); ++iter)
{ {
if(!_fullPredictionUpdate)
{
uInsert(_neighborsIndex, std::make_pair(*iter, neighbors));
}
float sum = 0.0f; // sum values added float sum = 0.0f; // sum values added
sum += this->addNeighborProb(prediction, idToIndexMap.at(*iter), neighbors, idToIndexMap); int index = idToIndexMap.at(*iter);
sum += this->addNeighborProb(prediction, index, neighbors, idToIndexMap);
idsDone.insert(*iter); idsDone.insert(*iter);
this->normalize(prediction, idToIndexMap.at(*iter), sum, ids[0]<0); this->normalize(prediction, index, sum, ids[0]<0);
} }
} }
else else
@@ -405,7 +424,7 @@ void BayesFilter::normalize(cv::Mat & prediction, unsigned int index, float adde
cv::Mat BayesFilter::updatePrediction(const cv::Mat & oldPrediction, cv::Mat BayesFilter::updatePrediction(const cv::Mat & oldPrediction,
const Memory * memory, const Memory * memory,
const std::vector<int> & oldIds, const std::vector<int> & oldIds,
const std::vector<int> & newIds) const const std::vector<int> & newIds)
{ {
UTimer timer; UTimer timer;
UDEBUG(""); UDEBUG("");
@@ -417,34 +436,32 @@ cv::Mat BayesFilter::updatePrediction(const cv::Mat & oldPrediction,
oldIds.size() == (unsigned int)oldPrediction.rows); oldIds.size() == (unsigned int)oldPrediction.rows);
cv::Mat prediction = cv::Mat::zeros(newIds.size(), newIds.size(), CV_32FC1); cv::Mat prediction = cv::Mat::zeros(newIds.size(), newIds.size(), CV_32FC1);
UDEBUG("time creating prediction = %fs", timer.restart());
// Create id to index maps // Create id to index maps
std::map<int, int> oldIdToIndexMap; std::unordered_set<int> oldIdsSet(oldIds.begin(), oldIds.end());
std::map<int, int> newIdToIndexMap; UDEBUG("time creating old ids set = %fs", timer.restart());
for(unsigned int i=0; i<oldIds.size() || i<newIds.size(); ++i)
std::unordered_map<int,int> newIdToIndexMap;
newIdToIndexMap.reserve(newIds.size());
for(unsigned int i=0; i<newIds.size(); ++i)
{ {
if(i<oldIds.size()) if(newIds[i]>0)
{ {
UASSERT(oldIds[i]); newIdToIndexMap[newIds[i]] = i;
oldIdToIndexMap.insert(oldIdToIndexMap.end(), std::make_pair(oldIds[i], i));
//UDEBUG("oldIdToIndexMap[%d] = %d", oldIds[i], i);
}
if(i<newIds.size())
{
UASSERT(newIds[i]);
newIdToIndexMap.insert(newIdToIndexMap.end(), std::make_pair(newIds[i], i));
//UDEBUG("newIdToIndexMap[%d] = %d", newIds[i], i);
} }
} }
UDEBUG("time creating id-index maps = %fs", timer.restart());
UDEBUG("time creating id-index vector (size=%d oldIds.back()=%d newIds.back()=%d) = %fs", (int)newIdToIndexMap.size(), oldIds.back(), newIds.back(), timer.restart());
//Get removed ids //Get removed ids
std::set<int> removedIds; std::set<int> removedIds;
for(unsigned int i=0; i<oldIds.size(); ++i) for(unsigned int i=0; i<oldIds.size(); ++i)
{ {
if(!uContains(newIdToIndexMap, oldIds[i])) if(oldIds[i] > 0 && newIdToIndexMap.find(oldIds[i]) == newIdToIndexMap.end())
{ {
removedIds.insert(removedIds.end(), oldIds[i]); removedIds.insert(removedIds.end(), oldIds[i]);
_neighborsIndex.erase(oldIds[i]);
UDEBUG("removed id=%d at oldIndex=%d", oldIds[i], i); UDEBUG("removed id=%d at oldIndex=%d", oldIds[i], i);
} }
} }
@@ -476,16 +493,31 @@ cv::Mat BayesFilter::updatePrediction(const cv::Mat & oldPrediction,
UDEBUG("From removed id %d, %d neighbors to update.", oldIds[i], count); UDEBUG("From removed id %d, %d neighbors to update.", oldIds[i], count);
} }
} }
if(i<newIds.size() && !uContains(oldIdToIndexMap,newIds[i])) if(i<newIds.size() && oldIdsSet.find(newIds[i]) == oldIdsSet.end())
{ {
std::map<int, int> neighbors = memory->getNeighborsId(newIds[i], _predictionLC.size()-1, 0, false, false, true); if(_neighborsIndex.find(newIds[i]) == _neighborsIndex.end())
{
std::map<int, int> neighbors = memory->getNeighborsId(newIds[i], _predictionLC.size()-1, 0, false, false, true, true);
for(std::map<int, int>::iterator iter=neighbors.begin(); iter!=neighbors.end(); ++iter)
{
std::map<int, std::map<int, int> >::iterator jter = _neighborsIndex.find(iter->first);
if(jter != _neighborsIndex.end())
{
uInsert(jter->second, std::make_pair(newIds[i], iter->second));
}
}
_neighborsIndex.insert(std::make_pair(newIds[i], neighbors));
}
const std::map<int, int> & neighbors = _neighborsIndex.at(newIds[i]);
float sum = this->addNeighborProb(prediction, i, neighbors, newIdToIndexMap); float sum = this->addNeighborProb(prediction, i, neighbors, newIdToIndexMap);
this->normalize(prediction, i, sum, newIds[0]<0); this->normalize(prediction, i, sum, newIds[0]<0);
++added; ++added;
int count = 0; int count = 0;
for(std::map<int,int>::iterator iter=neighbors.begin(); iter!=neighbors.end(); ++iter) for(std::map<int,int>::const_iterator iter=neighbors.begin(); iter!=neighbors.end(); ++iter)
{ {
if(uContains(oldIdToIndexMap, iter->first) && if(oldIdsSet.find(iter->first)!=oldIdsSet.end() &&
removedIds.find(iter->first) == removedIds.end()) removedIds.find(iter->first) == removedIds.end())
{ {
idsToUpdate.insert(iter->first); idsToUpdate.insert(iter->first);
@@ -497,51 +529,35 @@ cv::Mat BayesFilter::updatePrediction(const cv::Mat & oldPrediction,
} }
UDEBUG("time getting %d ids to update = %fs", idsToUpdate.size(), timer.restart()); UDEBUG("time getting %d ids to update = %fs", idsToUpdate.size(), timer.restart());
UTimer t1;
double e0=0,e1=0, e2=0, e3=0, e4=0;
// update modified/added ids // update modified/added ids
int modified = 0; int modified = 0;
std::set<int> idsDone;
for(std::set<int>::iterator iter = idsToUpdate.begin(); iter!=idsToUpdate.end(); ++iter) for(std::set<int>::iterator iter = idsToUpdate.begin(); iter!=idsToUpdate.end(); ++iter)
{ {
if(idsDone.find(*iter) == idsDone.end() && *iter > 0) int id = *iter;
if(id > 0 && id<(int)newIdToIndexMap.size())
{ {
std::map<int, int> neighbors = memory->getNeighborsId(*iter, _predictionLC.size()-1, 0, false, false, true); int index = newIdToIndexMap.at(id);
std::list<int> idsLoopMargin; if(index > 0)
//filter neighbors in STM
for(std::map<int, int>::iterator jter=neighbors.begin(); jter!=neighbors.end();)
{ {
if(memory->isInSTM(jter->first)) e0 = t1.ticks();
{ std::map<int, std::map<int, int> >::iterator kter = _neighborsIndex.find(id);
neighbors.erase(jter++); UASSERT_MSG(kter != _neighborsIndex.end(), uFormat("Did not find %d (current index size=%d)", id, (int)_neighborsIndex.size()).c_str());
} const std::map<int, int> & neighbors = kter->second;
else e1+=t1.ticks();
{
if(jter->second == 0)
{
idsLoopMargin.push_back(jter->first);
}
++jter;
}
}
// should at least have 1 id in idsMarginLoop
if(idsLoopMargin.size() == 0)
{
UFATAL("No 0 margin neighbor for signature %d !?!?", *iter);
}
// same neighbor tree for loop signatures (margin = 0)
for(std::list<int>::iterator iter = idsLoopMargin.begin(); iter!=idsLoopMargin.end(); ++iter)
{
int index = newIdToIndexMap.at(*iter);
float sum = this->addNeighborProb(prediction, index, neighbors, newIdToIndexMap); float sum = this->addNeighborProb(prediction, index, neighbors, newIdToIndexMap);
idsDone.insert(*iter); e3+=t1.ticks();
this->normalize(prediction, index, sum, newIds[0]<0); this->normalize(prediction, index, sum, newIds[0]<0);
++modified; ++modified;
e4+=t1.ticks();
} }
} }
} }
UDEBUG("time updating modified/added %d ids = %fs", idsToUpdate.size(), timer.restart()); UDEBUG("time updating modified/added %d ids = %fs (e0=%f e1=%f e2=%f e3=%f e4=%f)", idsToUpdate.size(), timer.restart(), e0, e1, e2, e3, e4);
//UDEBUG("oldIds.size()=%d, oldPrediction.cols=%d, oldPrediction.rows=%d", oldIds.size(), oldPrediction.cols, oldPrediction.rows); //UDEBUG("oldIds.size()=%d, oldPrediction.cols=%d, oldPrediction.rows=%d", oldIds.size(), oldPrediction.cols, oldPrediction.rows);
//UDEBUG("newIdToIndexMap.size()=%d, prediction.cols=%d, prediction.rows=%d", newIdToIndexMap.size(), prediction.cols, prediction.rows); //UDEBUG("newIdToIndexMap.size()=%d, prediction.cols=%d, prediction.rows=%d", newIdToIndexMap.size(), prediction.cols, prediction.rows);
@@ -624,20 +640,22 @@ void BayesFilter::updatePosterior(const Memory * memory, const std::vector<int>
_posterior = newPosterior; _posterior = newPosterior;
} }
float BayesFilter::addNeighborProb(cv::Mat & prediction, unsigned int col, const std::map<int, int> & neighbors, const std::map<int, int> & idToIndexMap) const float BayesFilter::addNeighborProb(cv::Mat & prediction, unsigned int col, const std::map<int, int> & neighbors, const std::unordered_map<int, int> & idToIndex) const
{ {
UASSERT((unsigned int)prediction.cols == idToIndexMap.size() && UASSERT(col < (unsigned int)prediction.cols &&
(unsigned int)prediction.rows == idToIndexMap.size() &&
col < (unsigned int)prediction.cols &&
col < (unsigned int)prediction.rows); col < (unsigned int)prediction.rows);
float sum=0; float sum=0.0f;
float * dataPtr = (float*)prediction.data;
for(std::map<int, int>::const_iterator iter=neighbors.begin(); iter!=neighbors.end(); ++iter) for(std::map<int, int>::const_iterator iter=neighbors.begin(); iter!=neighbors.end(); ++iter)
{ {
int index = uValue(idToIndexMap, iter->first, -1); if(iter->first>=0)
if(index >= 0)
{ {
sum += ((float*)prediction.data)[col + index*prediction.cols] = _predictionLC[iter->second+1]; std::unordered_map<int, int>::const_iterator jter = idToIndex.find(iter->first);
if(jter != idToIndex.end())
{
sum += dataPtr[col + jter->second*prediction.cols] = _predictionLC[iter->second+1];
}
} }
} }
return sum; return sum;
+43 -8
View File
@@ -71,6 +71,7 @@ CameraImages::CameraImages() :
_scanVoxelSize(0.0f), _scanVoxelSize(0.0f),
_scanNormalsK(0), _scanNormalsK(0),
_scanNormalsRadius(0), _scanNormalsRadius(0),
_scanForceGroundNormalsUp(false),
_depthFromScan(false), _depthFromScan(false),
_depthFromScanFillHoles(1), _depthFromScanFillHoles(1),
_depthFromScanFillHolesFromBorder(false), _depthFromScanFillHolesFromBorder(false),
@@ -102,6 +103,7 @@ CameraImages::CameraImages(const std::string & path,
_scanVoxelSize(0.0f), _scanVoxelSize(0.0f),
_scanNormalsK(0), _scanNormalsK(0),
_scanNormalsRadius(0), _scanNormalsRadius(0),
_scanForceGroundNormalsUp(false),
_depthFromScan(false), _depthFromScan(false),
_depthFromScanFillHoles(1), _depthFromScanFillHoles(1),
_depthFromScanFillHolesFromBorder(false), _depthFromScanFillHolesFromBorder(false),
@@ -242,15 +244,43 @@ bool CameraImages::init(const std::string & calibrationFolder, const std::string
const std::list<std::string> & filenames = _dir->getFileNames(); const std::list<std::string> & filenames = _dir->getFileNames();
for(std::list<std::string>::const_iterator iter=filenames.begin(); iter!=filenames.end(); ++iter) for(std::list<std::string>::const_iterator iter=filenames.begin(); iter!=filenames.end(); ++iter)
{ {
// format is text_12234456.12334_text.png // format is text_1223445645.12334_text.png or text_122344564512334_text.png
// If no decimals, 10 first number are the seconds
std::list<std::string> list = uSplit(*iter, '.'); std::list<std::string> list = uSplit(*iter, '.');
if(list.size() == 3) if(list.size() == 3 || list.size() == 2)
{ {
list.pop_back(); // remove extension list.pop_back(); // remove extension
double stamp = 0.0;
if(list.size() == 1)
{
std::list<std::string> numberList = uSplitNumChar(list.front());
for(std::list<std::string>::iterator iter=numberList.begin(); iter!=numberList.end(); ++iter)
{
if(uIsNumber(*iter))
{
std::string decimals;
std::string sec;
if(iter->length()>10)
{
decimals = iter->substr(10, iter->size()-10);
sec = iter->substr(0, 10);
}
else
{
sec = *iter;
}
stamp = uStr2Double(sec + "." + decimals);
break;
}
}
}
else
{
std::string decimals = uSplitNumChar(list.back()).front(); std::string decimals = uSplitNumChar(list.back()).front();
list.pop_back(); list.pop_back();
std::string sec = uSplitNumChar(list.back()).back(); std::string sec = uSplitNumChar(list.back()).back();
double stamp = uStr2Double(sec + "." + decimals); stamp = uStr2Double(sec + "." + decimals);
}
if(stamp > 0.0) if(stamp > 0.0)
{ {
_stamps.push_back(stamp); _stamps.push_back(stamp);
@@ -338,19 +368,19 @@ bool CameraImages::readPoses(std::list<Transform> & outputPoses, std::list<doubl
UERROR("Cannot read pose file \"%s\".", filePath.c_str()); UERROR("Cannot read pose file \"%s\".", filePath.c_str());
return false; return false;
} }
else if((format != 1 && format != 5 && format != 6 && format != 7) && poses.size() != this->imagesCount()) else if((format != 1 && format != 5 && format != 6 && format != 7 && format != 9) && poses.size() != this->imagesCount())
{ {
UERROR("The pose count is not the same as the images (%d vs %d)! Please remove " UERROR("The pose count is not the same as the images (%d vs %d)! Please remove "
"the pose file path if you don't want to use it (current file path=%s).", "the pose file path if you don't want to use it (current file path=%s).",
(int)poses.size(), this->imagesCount(), filePath.c_str()); (int)poses.size(), this->imagesCount(), filePath.c_str());
return false; return false;
} }
else if((format == 1 || format == 5 || format == 6 || format == 7) && inOutStamps.size() == 0) else if((format == 1 || format == 5 || format == 6 || format == 7 || format == 9) && inOutStamps.size() == 0)
{ {
UERROR("When using RGBD-SLAM, GPS, MALAGA and ST LUCIA formats, images must have timestamps!"); UERROR("When using RGBD-SLAM, GPS, MALAGA, ST LUCIA and EuRoC MAV formats, images must have timestamps!");
return false; return false;
} }
else if(format == 1 || format == 5 || format == 6 || format == 7) else if(format == 1 || format == 5 || format == 6 || format == 7 || format == 9)
{ {
UDEBUG(""); UDEBUG("");
//Match ground truth values with images //Match ground truth values with images
@@ -384,7 +414,6 @@ bool CameraImages::readPoses(std::list<Transform> & outputPoses, std::list<doubl
UASSERT(stampEnd > stampBeg && *ster>stampBeg && *ster < stampEnd); UASSERT(stampEnd > stampBeg && *ster>stampBeg && *ster < stampEnd);
if(fabs(*ster-stampEnd) > maxTimeDiff || fabs(*ster-stampBeg) > maxTimeDiff) if(fabs(*ster-stampEnd) > maxTimeDiff || fabs(*ster-stampBeg) > maxTimeDiff)
{ {
warned = true;
if(!warned) if(!warned)
{ {
UWARN("Cannot interpolate pose for stamp %f between %f and %f (> maximum time diff of %f sec)", UWARN("Cannot interpolate pose for stamp %f between %f and %f (> maximum time diff of %f sec)",
@@ -393,6 +422,7 @@ bool CameraImages::readPoses(std::list<Transform> & outputPoses, std::list<doubl
stampEnd, stampEnd,
maxTimeDiff); maxTimeDiff);
} }
warned=true;
} }
else else
{ {
@@ -744,7 +774,12 @@ SensorData CameraImages::captureImage(CameraInfo * info)
pcl::PointCloud<pcl::Normal>::Ptr normals = util3d::computeNormals(cloud, _scanNormalsK, _scanNormalsRadius); pcl::PointCloud<pcl::Normal>::Ptr normals = util3d::computeNormals(cloud, _scanNormalsK, _scanNormalsRadius);
pcl::PointCloud<pcl::PointNormal>::Ptr cloudNormals(new pcl::PointCloud<pcl::PointNormal>); pcl::PointCloud<pcl::PointNormal>::Ptr cloudNormals(new pcl::PointCloud<pcl::PointNormal>);
pcl::concatenateFields(*cloud, *normals, *cloudNormals); pcl::concatenateFields(*cloud, *normals, *cloudNormals);
if(_scanForceGroundNormalsUp)
{
util3d::adjustNormalsToViewPoint(cloudNormals, Eigen::Vector3f(0,0,0), _scanForceGroundNormalsUp);
}
scan = util3d::laserScanFromPointCloud(*cloudNormals, _scanLocalTransform.inverse()); scan = util3d::laserScanFromPointCloud(*cloudNormals, _scanLocalTransform.inverse());
UDEBUG("Normals computed (k=%d radius=%f)", _scanNormalsK, _scanNormalsRadius);
} }
else else
{ {
+31 -2
View File
@@ -36,7 +36,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "rtabmap/core/StereoDense.h" #include "rtabmap/core/StereoDense.h"
#include "rtabmap/core/DBReader.h" #include "rtabmap/core/DBReader.h"
#include "rtabmap/core/clams/discrete_depth_distortion_model.h" #include "rtabmap/core/clams/discrete_depth_distortion_model.h"
#include <opencv2/stitching/detail/exposure_compensate.hpp>
#include <rtabmap/utilite/UTimer.h> #include <rtabmap/utilite/UTimer.h>
#include <rtabmap/utilite/ULogger.h> #include <rtabmap/utilite/ULogger.h>
@@ -49,6 +49,7 @@ namespace rtabmap
CameraThread::CameraThread(Camera * camera, const ParametersMap & parameters) : CameraThread::CameraThread(Camera * camera, const ParametersMap & parameters) :
_camera(camera), _camera(camera),
_mirroring(false), _mirroring(false),
_stereoExposureCompensation(false),
_colorOnly(false), _colorOnly(false),
_imageDecimation(1), _imageDecimation(1),
_stereoToDepth(false), _stereoToDepth(false),
@@ -269,6 +270,33 @@ void CameraThread::postUpdate(SensorData * dataPtr, CameraInfo * info) const
} }
if(info) info->timeMirroring = timer.ticks(); if(info) info->timeMirroring = timer.ticks();
} }
if(_stereoExposureCompensation && !data.imageRaw().empty() && !data.rightRaw().empty())
{
#if CV_MAJOR_VERSION < 3
UWARN("Stereo exposure compensation not implemented for OpenCV version under 3.")
#else
UDEBUG("");
UTimer timer;
cv::Ptr<cv::detail::ExposureCompensator> compensator = cv::detail::ExposureCompensator::createDefault(cv::detail::ExposureCompensator::GAIN);
std::vector<cv::Point> topLeftCorners(2, cv::Point(0,0));
std::vector<cv::UMat> images;
std::vector<cv::UMat> masks(2, cv::UMat(data.imageRaw().size(), CV_8UC1, cv::Scalar(255)));
images.push_back(data.imageRaw().getUMat(cv::ACCESS_READ));
images.push_back(data.rightRaw().getUMat(cv::ACCESS_READ));
compensator->feed(topLeftCorners, images, masks);
cv::Mat img = data.imageRaw().clone();
compensator->apply(0, cv::Point(0,0), img, masks[0]);
data.setImageRaw(img);
img = data.rightRaw().clone();
compensator->apply(1, cv::Point(0,0), img, masks[1]);
data.setDepthOrRightRaw(img);
cv::detail::GainCompensator * gainCompensator = (cv::detail::GainCompensator*)compensator.get();
UDEBUG("gains = %f %f ", gainCompensator->gains()[0], gainCompensator->gains()[1]);
if(info) info->timeStereoExposureCompensation = timer.ticks();
#endif
}
if(_stereoToDepth && !data.imageRaw().empty() && data.stereoCameraModel().isValidForProjection() && !data.rightRaw().empty()) if(_stereoToDepth && !data.imageRaw().empty() && data.stereoCameraModel().isValidForProjection() && !data.rightRaw().empty())
{ {
UDEBUG(""); UDEBUG("");
@@ -284,7 +312,8 @@ void CameraThread::postUpdate(SensorData * dataPtr, CameraInfo * info) const
data.stereoCameraModel().left().cx(), data.stereoCameraModel().left().cx(),
data.stereoCameraModel().left().cy(), data.stereoCameraModel().left().cy(),
data.stereoCameraModel().localTransform(), data.stereoCameraModel().localTransform(),
-data.stereoCameraModel().baseline()*data.stereoCameraModel().left().fx()); -data.stereoCameraModel().baseline()*data.stereoCameraModel().left().fx(),
data.stereoCameraModel().left().imageSize());
data.setCameraModel(model); data.setCameraModel(model);
data.setDepthOrRightRaw(depth); data.setDepthOrRightRaw(depth);
data.setStereoCameraModel(StereoCameraModel()); data.setStereoCameraModel(StereoCameraModel());
+1 -1
View File
@@ -1070,7 +1070,7 @@ cv::Mat DBDriver::loadOptimizedMesh(
std::map<int, Transform> * poses, std::map<int, Transform> * poses,
std::vector<std::vector<std::vector<unsigned int> > > * polygons, std::vector<std::vector<std::vector<unsigned int> > > * polygons,
#if PCL_VERSION_COMPARE(>=, 1, 8, 0) #if PCL_VERSION_COMPARE(>=, 1, 8, 0)
std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f>> > * texCoords, std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > * texCoords,
#else #else
std::vector<std::vector<Eigen::Vector2f> > * texCoords, std::vector<std::vector<Eigen::Vector2f> > * texCoords,
#endif #endif
+19 -10
View File
@@ -38,7 +38,8 @@ FlannIndex::FlannIndex():
featuresType_(0), featuresType_(0),
featuresDim_(0), featuresDim_(0),
isLSH_(false), isLSH_(false),
useDistanceL1_(false) useDistanceL1_(false),
rebalancingFactor_(2.0f)
{ {
} }
FlannIndex::~FlannIndex() FlannIndex::~FlannIndex()
@@ -134,7 +135,8 @@ unsigned int FlannIndex::memoryUsed() const
void FlannIndex::buildLinearIndex( void FlannIndex::buildLinearIndex(
const cv::Mat & features, const cv::Mat & features,
bool useDistanceL1) bool useDistanceL1,
float rebalancingFactor)
{ {
this->release(); this->release();
UASSERT(index_ == 0); UASSERT(index_ == 0);
@@ -142,6 +144,7 @@ void FlannIndex::buildLinearIndex(
featuresType_ = features.type(); featuresType_ = features.type();
featuresDim_ = features.cols; featuresDim_ = features.cols;
useDistanceL1_ = useDistanceL1; useDistanceL1_ = useDistanceL1;
rebalancingFactor_ = rebalancingFactor;
rtflann::LinearIndexParams params; rtflann::LinearIndexParams params;
@@ -180,7 +183,8 @@ void FlannIndex::buildLinearIndex(
void FlannIndex::buildKDTreeIndex( void FlannIndex::buildKDTreeIndex(
const cv::Mat & features, const cv::Mat & features,
int trees, int trees,
bool useDistanceL1) bool useDistanceL1,
float rebalancingFactor)
{ {
this->release(); this->release();
UASSERT(index_ == 0); UASSERT(index_ == 0);
@@ -188,6 +192,7 @@ void FlannIndex::buildKDTreeIndex(
featuresType_ = features.type(); featuresType_ = features.type();
featuresDim_ = features.cols; featuresDim_ = features.cols;
useDistanceL1_ = useDistanceL1; useDistanceL1_ = useDistanceL1;
rebalancingFactor_ = rebalancingFactor;
rtflann::KDTreeIndexParams params(trees); rtflann::KDTreeIndexParams params(trees);
@@ -227,7 +232,8 @@ void FlannIndex::buildKDTreeSingleIndex(
const cv::Mat & features, const cv::Mat & features,
int leafMaxSize, int leafMaxSize,
bool reorder, bool reorder,
bool useDistanceL1) bool useDistanceL1,
float rebalancingFactor)
{ {
this->release(); this->release();
UASSERT(index_ == 0); UASSERT(index_ == 0);
@@ -235,6 +241,7 @@ void FlannIndex::buildKDTreeSingleIndex(
featuresType_ = features.type(); featuresType_ = features.type();
featuresDim_ = features.cols; featuresDim_ = features.cols;
useDistanceL1_ = useDistanceL1; useDistanceL1_ = useDistanceL1;
rebalancingFactor_ = rebalancingFactor;
rtflann::KDTreeSingleIndexParams params(leafMaxSize, reorder); rtflann::KDTreeSingleIndexParams params(leafMaxSize, reorder);
@@ -274,7 +281,8 @@ void FlannIndex::buildLSHIndex(
const cv::Mat & features, const cv::Mat & features,
unsigned int table_number, unsigned int table_number,
unsigned int key_size, unsigned int key_size,
unsigned int multi_probe_level) unsigned int multi_probe_level,
float rebalancingFactor)
{ {
this->release(); this->release();
UASSERT(index_ == 0); UASSERT(index_ == 0);
@@ -282,6 +290,7 @@ void FlannIndex::buildLSHIndex(
featuresType_ = features.type(); featuresType_ = features.type();
featuresDim_ = features.cols; featuresDim_ = features.cols;
useDistanceL1_ = true; useDistanceL1_ = true;
rebalancingFactor_ = rebalancingFactor;
rtflann::Matrix<unsigned char> dataset(features.data, features.rows, features.cols); rtflann::Matrix<unsigned char> dataset(features.data, features.rows, features.cols);
index_ = new rtflann::Index<rtflann::Hamming<unsigned char> >(dataset, rtflann::LshIndexParams(12, 20, 2)); index_ = new rtflann::Index<rtflann::Hamming<unsigned char> >(dataset, rtflann::LshIndexParams(12, 20, 2));
@@ -315,8 +324,8 @@ unsigned int FlannIndex::addPoints(const cv::Mat & features)
rtflann::Index<rtflann::Hamming<unsigned char> > * index = (rtflann::Index<rtflann::Hamming<unsigned char> >*)index_; rtflann::Index<rtflann::Hamming<unsigned char> > * index = (rtflann::Index<rtflann::Hamming<unsigned char> >*)index_;
removedPts = index->removedCount(); removedPts = index->removedCount();
index->addPoints(points, 0); index->addPoints(points, 0);
// Rebuild index if it doubles in size // Rebuild index if it is now X times in size
if(index->sizeAtBuild() * 2 < index->size()+index->removedCount()) if(rebalancingFactor_ > 1.0f && size_t(float(index->sizeAtBuild()) * rebalancingFactor_) < index->size()+index->removedCount())
{ {
UDEBUG("Rebuilding FLANN index: %d -> %d", (int)index->sizeAtBuild(), (int)(index->size()+index->removedCount())); UDEBUG("Rebuilding FLANN index: %d -> %d", (int)index->sizeAtBuild(), (int)(index->size()+index->removedCount()));
index->buildIndex(); index->buildIndex();
@@ -333,7 +342,7 @@ unsigned int FlannIndex::addPoints(const cv::Mat & features)
removedPts = index->removedCount(); removedPts = index->removedCount();
index->addPoints(points, 0); index->addPoints(points, 0);
// Rebuild index if it doubles in size // Rebuild index if it doubles in size
if(index->sizeAtBuild() * 2 < index->size()+index->removedCount()) if(rebalancingFactor_ > 1.0f && size_t(float(index->sizeAtBuild()) * rebalancingFactor_) < index->size()+index->removedCount())
{ {
UDEBUG("Rebuilding FLANN index: %d -> %d", (int)index->sizeAtBuild(), (int)(index->size()+index->removedCount())); UDEBUG("Rebuilding FLANN index: %d -> %d", (int)index->sizeAtBuild(), (int)(index->size()+index->removedCount()));
index->buildIndex(); index->buildIndex();
@@ -347,7 +356,7 @@ unsigned int FlannIndex::addPoints(const cv::Mat & features)
removedPts = index->removedCount(); removedPts = index->removedCount();
index->addPoints(points, 0); index->addPoints(points, 0);
// Rebuild index if it doubles in size // Rebuild index if it doubles in size
if(index->sizeAtBuild() * 2 < index->size()+index->removedCount()) if(rebalancingFactor_ > 1.0f && size_t(float(index->sizeAtBuild()) * rebalancingFactor_) < index->size()+index->removedCount())
{ {
UDEBUG("Rebuilding FLANN index: %d -> %d", (int)index->sizeAtBuild(), (int)(index->size()+index->removedCount())); UDEBUG("Rebuilding FLANN index: %d -> %d", (int)index->sizeAtBuild(), (int)(index->size()+index->removedCount()));
index->buildIndex(); index->buildIndex();
@@ -361,7 +370,7 @@ unsigned int FlannIndex::addPoints(const cv::Mat & features)
removedPts = index->removedCount(); removedPts = index->removedCount();
index->addPoints(points, 0); index->addPoints(points, 0);
// Rebuild index if it doubles in size // Rebuild index if it doubles in size
if(index->sizeAtBuild() * 2 < index->size()+index->removedCount()) if(rebalancingFactor_ > 1.0f && size_t(float(index->sizeAtBuild()) * rebalancingFactor_) < index->size()+index->removedCount())
{ {
UDEBUG("Rebuilding FLANN index: %d -> %d", (int)index->sizeAtBuild(), (int)(index->size()+index->removedCount())); UDEBUG("Rebuilding FLANN index: %d -> %d", (int)index->sizeAtBuild(), (int)(index->size()+index->removedCount()));
index->buildIndex(); index->buildIndex();
+76 -9
View File
@@ -161,10 +161,10 @@ bool exportPoses(
bool importPoses( bool importPoses(
const std::string & filePath, const std::string & filePath,
int format, // 0=Raw, 1=RGBD-SLAM, 2=KITTI, 3=TORO, 4=g2o, 5=NewCollege(t,x,y), 6=Malaga Urban GPS, 7=St Lucia INS, 8=Karlsruhe int format, // 0=Raw, 1=RGBD-SLAM, 2=KITTI, 3=TORO, 4=g2o, 5=NewCollege(t,x,y), 6=Malaga Urban GPS, 7=St Lucia INS, 8=Karlsruhe, 9=EuRoC MAC
std::map<int, Transform> & poses, std::map<int, Transform> & poses,
std::multimap<int, Link> * constraints, // optional for formats 3 and 4 std::multimap<int, Link> * constraints, // optional for formats 3 and 4
std::map<int, double> * stamps) // optional for format 1 std::map<int, double> * stamps) // optional for format 1 and 9
{ {
UDEBUG("%s format=%d", filePath.c_str(), format); UDEBUG("%s format=%d", filePath.c_str(), format);
if(format==3) // TORO if(format==3) // TORO
@@ -202,12 +202,50 @@ bool importPoses(
std::string str; std::string str;
std::getline(file, str); std::getline(file, str);
if(str.size() && str.at(str.size()-1) == '\r')
{
str = str.substr(0, str.size()-1);
}
if(str.empty() || str.at(0) == '#' || str.at(0) == '%') if(str.empty() || str.at(0) == '#' || str.at(0) == '%')
{ {
continue; continue;
} }
if(format == 8) // Karlsruhe format if(format == 9) // EuRoC format
{
std::list<std::string> strList = uSplit(str, ',');
if(strList.size() == 17)
{
double stamp = uStr2Double(strList.front())/1000000000.0;
strList.pop_front();
std::vector<std::string> v = uListToVector(strList);
Transform pose(uStr2Float(v[0]), uStr2Float(v[1]), uStr2Float(v[2]), // x y z
uStr2Float(v[4]), uStr2Float(v[5]), uStr2Float(v[6]), uStr2Float(v[3])); // qw qx qy qz -> qx qy qz qw
if(pose.isNull())
{
UWARN("Null transform read!? line parsed: \"%s\"", str.c_str());
}
else
{
if(stamps)
{
stamps->insert(std::make_pair(id, stamp));
}
// we need to rotate from IMU frame to world frame
Transform t( 0, 0, 1, 0,
0, -1, 0, 0,
1, 0, 0, 0);
pose = pose * t;
poses.insert(std::make_pair(id, pose));
}
}
else
{
UERROR("Error parsing \"%s\" with EuRoC MAV format (should have 17 values: stamp x y z qw qx qy qz vx vy vz vr vp vy ax ay az)", str.c_str());
}
}
else if(format == 8) // Karlsruhe format
{ {
std::vector<std::string> strList = uListToVector(uSplit(str)); std::vector<std::string> strList = uListToVector(uSplit(str));
if(strList.size() == 10) if(strList.size() == 10)
@@ -364,7 +402,7 @@ bool importPoses(
} }
else else
{ {
UERROR("Error parsing \"%s\" with NewCollege format (should have 3 values: stamp x y)", str.c_str()); UERROR("Error parsing \"%s\" with NewCollege format (should have 3 values: stamp x y, found %d)", str.c_str(), (int)strList.size());
} }
} }
else if(format == 1) // rgbd-slam format else if(format == 1) // rgbd-slam format
@@ -911,6 +949,20 @@ std::multimap<int, int>::const_iterator findLink(
return links.end(); return links.end();
} }
std::multimap<int, Link> filterDuplicateLinks(
const std::multimap<int, Link> & links)
{
std::multimap<int, Link> output;
for(std::multimap<int, Link>::const_iterator iter=links.begin(); iter!=links.end(); ++iter)
{
if(graph::findLink(output, iter->second.from(), iter->second.to(), true) == output.end())
{
output.insert(*iter);
}
}
return output;
}
std::multimap<int, Link> filterLinks( std::multimap<int, Link> filterLinks(
const std::multimap<int, Link> & links, const std::multimap<int, Link> & links,
Link::Type filteredType) Link::Type filteredType)
@@ -1820,6 +1872,20 @@ int findNearestNode(
const rtabmap::Transform & targetPose) const rtabmap::Transform & targetPose)
{ {
int id = 0; int id = 0;
std::vector<int> nearestNodes = findNearestNodes(nodes, targetPose, 1);
if(nearestNodes.size())
{
id = nearestNodes[0];
}
return id;
}
std::vector<int> findNearestNodes(
const std::map<int, rtabmap::Transform> & nodes,
const rtabmap::Transform & targetPose,
int k)
{
std::vector<int> nearestIds;
if(nodes.size() && !targetPose.isNull()) if(nodes.size() && !targetPose.isNull())
{ {
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>); pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
@@ -1837,14 +1903,15 @@ int findNearestNode(
std::vector<int> ind; std::vector<int> ind;
std::vector<float> dist; std::vector<float> dist;
pcl::PointXYZ pt(targetPose.x(), targetPose.y(), targetPose.z()); pcl::PointXYZ pt(targetPose.x(), targetPose.y(), targetPose.z());
kdTree->nearestKSearch(pt, 1, ind, dist); kdTree->nearestKSearch(pt, k, ind, dist);
if(ind.size() && dist.size() && ind[0] >= 0)
nearestIds.resize(ind.size());
for(unsigned int i=0; i<ind.size(); ++i)
{ {
//UDEBUG("Nearest node = %d: %f", ids[ind[0]], dist[0]); nearestIds[i] = ids[ind[i]];
id = ids[ind[0]];
} }
} }
return id; return nearestIds;
} }
// return <id, sqrd distance>, excluding query // return <id, sqrd distance>, excluding query
+2 -2
View File
@@ -65,13 +65,13 @@ Link::Link(int from,
double Link::rotVariance() const double Link::rotVariance() const
{ {
double min = uMin3(infMatrix_.at<double>(3,3), infMatrix_.at<double>(4,4), infMatrix_.at<double>(5,5)); double min = uMax3(infMatrix_.at<double>(3,3), infMatrix_.at<double>(4,4), infMatrix_.at<double>(5,5));
UASSERT(min > 0.0); UASSERT(min > 0.0);
return 1.0/min; return 1.0/min;
} }
double Link::transVariance() const double Link::transVariance() const
{ {
double min = uMin3(infMatrix_.at<double>(0,0), infMatrix_.at<double>(1,1), infMatrix_.at<double>(2,2)); double min = uMax3(infMatrix_.at<double>(0,0), infMatrix_.at<double>(1,1), infMatrix_.at<double>(2,2));
UASSERT(min > 0.0); UASSERT(min > 0.0);
return 1.0/min; return 1.0/min;
} }
+92 -57
View File
@@ -84,6 +84,7 @@ Memory::Memory(const ParametersMap & parameters) :
_generateIds(Parameters::defaultMemGenerateIds()), _generateIds(Parameters::defaultMemGenerateIds()),
_badSignaturesIgnored(Parameters::defaultMemBadSignaturesIgnored()), _badSignaturesIgnored(Parameters::defaultMemBadSignaturesIgnored()),
_mapLabelsAdded(Parameters::defaultMemMapLabelsAdded()), _mapLabelsAdded(Parameters::defaultMemMapLabelsAdded()),
_depthAsMask(Parameters::defaultMemDepthAsMask()),
_imagePreDecimation(Parameters::defaultMemImagePreDecimation()), _imagePreDecimation(Parameters::defaultMemImagePreDecimation()),
_imagePostDecimation(Parameters::defaultMemImagePostDecimation()), _imagePostDecimation(Parameters::defaultMemImagePostDecimation()),
_compressionParallelized(Parameters::defaultMemCompressionParallelized()), _compressionParallelized(Parameters::defaultMemCompressionParallelized()),
@@ -98,6 +99,7 @@ Memory::Memory(const ParametersMap & parameters) :
_useOdometryFeatures(Parameters::defaultMemUseOdomFeatures()), _useOdometryFeatures(Parameters::defaultMemUseOdomFeatures()),
_createOccupancyGrid(Parameters::defaultRGBDCreateOccupancyGrid()), _createOccupancyGrid(Parameters::defaultRGBDCreateOccupancyGrid()),
_visMaxFeatures(Parameters::defaultVisMaxFeatures()), _visMaxFeatures(Parameters::defaultVisMaxFeatures()),
_visCorType(Parameters::defaultVisCorType()),
_idCount(kIdStart), _idCount(kIdStart),
_idMapCount(kIdStart), _idMapCount(kIdStart),
_lastSignature(0), _lastSignature(0),
@@ -428,38 +430,49 @@ Memory::~Memory()
void Memory::parseParameters(const ParametersMap & parameters) void Memory::parseParameters(const ParametersMap & parameters)
{ {
uInsert(parameters_, parameters); uInsert(parameters_, parameters);
ParametersMap params = parameters;
UDEBUG(""); UDEBUG("");
ParametersMap::const_iterator iter; ParametersMap::const_iterator iter;
Parameters::parse(parameters, Parameters::kMemBinDataKept(), _binDataKept); Parameters::parse(params, Parameters::kMemBinDataKept(), _binDataKept);
Parameters::parse(parameters, Parameters::kMemRawDescriptorsKept(), _rawDescriptorsKept); Parameters::parse(params, Parameters::kMemRawDescriptorsKept(), _rawDescriptorsKept);
Parameters::parse(parameters, Parameters::kMemSaveDepth16Format(), _saveDepth16Format); Parameters::parse(params, Parameters::kMemSaveDepth16Format(), _saveDepth16Format);
Parameters::parse(parameters, Parameters::kMemReduceGraph(), _reduceGraph); Parameters::parse(params, Parameters::kMemReduceGraph(), _reduceGraph);
Parameters::parse(parameters, Parameters::kMemNotLinkedNodesKept(), _notLinkedNodesKeptInDb); Parameters::parse(params, Parameters::kMemNotLinkedNodesKept(), _notLinkedNodesKeptInDb);
Parameters::parse(parameters, Parameters::kMemIntermediateNodeDataKept(), _saveIntermediateNodeData); Parameters::parse(params, Parameters::kMemIntermediateNodeDataKept(), _saveIntermediateNodeData);
Parameters::parse(parameters, Parameters::kMemRehearsalIdUpdatedToNewOne(), _idUpdatedToNewOneRehearsal); Parameters::parse(params, Parameters::kMemRehearsalIdUpdatedToNewOne(), _idUpdatedToNewOneRehearsal);
Parameters::parse(parameters, Parameters::kMemGenerateIds(), _generateIds); Parameters::parse(params, Parameters::kMemGenerateIds(), _generateIds);
Parameters::parse(parameters, Parameters::kMemBadSignaturesIgnored(), _badSignaturesIgnored); Parameters::parse(params, Parameters::kMemBadSignaturesIgnored(), _badSignaturesIgnored);
Parameters::parse(parameters, Parameters::kMemMapLabelsAdded(), _mapLabelsAdded); Parameters::parse(params, Parameters::kMemMapLabelsAdded(), _mapLabelsAdded);
Parameters::parse(parameters, Parameters::kMemRehearsalSimilarity(), _similarityThreshold); Parameters::parse(params, Parameters::kMemRehearsalSimilarity(), _similarityThreshold);
Parameters::parse(parameters, Parameters::kMemRecentWmRatio(), _recentWmRatio); Parameters::parse(params, Parameters::kMemRecentWmRatio(), _recentWmRatio);
Parameters::parse(parameters, Parameters::kMemTransferSortingByWeightId(), _transferSortingByWeightId); Parameters::parse(params, Parameters::kMemTransferSortingByWeightId(), _transferSortingByWeightId);
Parameters::parse(parameters, Parameters::kMemSTMSize(), _maxStMemSize); Parameters::parse(params, Parameters::kMemSTMSize(), _maxStMemSize);
Parameters::parse(parameters, Parameters::kMemImagePreDecimation(), _imagePreDecimation); Parameters::parse(params, Parameters::kMemDepthAsMask(), _depthAsMask);
Parameters::parse(parameters, Parameters::kMemImagePostDecimation(), _imagePostDecimation); Parameters::parse(params, Parameters::kMemImagePreDecimation(), _imagePreDecimation);
Parameters::parse(parameters, Parameters::kMemCompressionParallelized(), _compressionParallelized); Parameters::parse(params, Parameters::kMemImagePostDecimation(), _imagePostDecimation);
Parameters::parse(parameters, Parameters::kMemLaserScanDownsampleStepSize(), _laserScanDownsampleStepSize); Parameters::parse(params, Parameters::kMemCompressionParallelized(), _compressionParallelized);
Parameters::parse(parameters, Parameters::kMemLaserScanVoxelSize(), _laserScanVoxelSize); Parameters::parse(params, Parameters::kMemLaserScanDownsampleStepSize(), _laserScanDownsampleStepSize);
Parameters::parse(parameters, Parameters::kMemLaserScanNormalK(), _laserScanNormalK); Parameters::parse(params, Parameters::kMemLaserScanVoxelSize(), _laserScanVoxelSize);
Parameters::parse(parameters, Parameters::kMemLaserScanNormalRadius(), _laserScanNormalRadius); Parameters::parse(params, Parameters::kMemLaserScanNormalK(), _laserScanNormalK);
Parameters::parse(parameters, Parameters::kRGBDLoopClosureReextractFeatures(), _reextractLoopClosureFeatures); Parameters::parse(params, Parameters::kMemLaserScanNormalRadius(), _laserScanNormalRadius);
Parameters::parse(parameters, Parameters::kRGBDLinearUpdate(), _rehearsalMaxDistance); Parameters::parse(params, Parameters::kRGBDLoopClosureReextractFeatures(), _reextractLoopClosureFeatures);
Parameters::parse(parameters, Parameters::kRGBDAngularUpdate(), _rehearsalMaxAngle); Parameters::parse(params, Parameters::kRGBDLinearUpdate(), _rehearsalMaxDistance);
Parameters::parse(parameters, Parameters::kMemRehearsalWeightIgnoredWhileMoving(), _rehearsalWeightIgnoredWhileMoving); Parameters::parse(params, Parameters::kRGBDAngularUpdate(), _rehearsalMaxAngle);
Parameters::parse(parameters, Parameters::kMemUseOdomFeatures(), _useOdometryFeatures); Parameters::parse(params, Parameters::kMemRehearsalWeightIgnoredWhileMoving(), _rehearsalWeightIgnoredWhileMoving);
Parameters::parse(parameters, Parameters::kRGBDCreateOccupancyGrid(), _createOccupancyGrid); Parameters::parse(params, Parameters::kMemUseOdomFeatures(), _useOdometryFeatures);
Parameters::parse(parameters, Parameters::kVisMaxFeatures(), _visMaxFeatures); Parameters::parse(params, Parameters::kRGBDCreateOccupancyGrid(), _createOccupancyGrid);
Parameters::parse(params, Parameters::kVisMaxFeatures(), _visMaxFeatures);
Parameters::parse(params, Parameters::kVisCorType(), _visCorType);
if(_visCorType != 0)
{
UWARN("%s is not 0 (Features Matching), the only approach supported for loop closure transformation estimation. Setting to 0...",
Parameters::kVisCorType().c_str());
_visCorType = 0;
uInsert(parameters_, ParametersPair(Parameters::kVisCorType(), "0"));
uInsert(params, ParametersPair(Parameters::kVisCorType(), "0"));
}
UASSERT_MSG(_maxStMemSize >= 0, uFormat("value=%d", _maxStMemSize).c_str()); UASSERT_MSG(_maxStMemSize >= 0, uFormat("value=%d", _maxStMemSize).c_str());
UASSERT_MSG(_similarityThreshold >= 0.0f && _similarityThreshold <= 1.0f, uFormat("value=%f", _similarityThreshold).c_str()); UASSERT_MSG(_similarityThreshold >= 0.0f && _similarityThreshold <= 1.0f, uFormat("value=%f", _similarityThreshold).c_str());
@@ -477,23 +490,23 @@ void Memory::parseParameters(const ParametersMap & parameters)
if(_dbDriver) if(_dbDriver)
{ {
_dbDriver->parseParameters(parameters); _dbDriver->parseParameters(params);
} }
// Keypoint stuff // Keypoint stuff
if(_vwd) if(_vwd)
{ {
_vwd->parseParameters(parameters); _vwd->parseParameters(params);
} }
Parameters::parse(parameters, Parameters::kKpTfIdfLikelihoodUsed(), _tfIdfLikelihoodUsed); Parameters::parse(params, Parameters::kKpTfIdfLikelihoodUsed(), _tfIdfLikelihoodUsed);
Parameters::parse(parameters, Parameters::kKpParallelized(), _parallelized); Parameters::parse(params, Parameters::kKpParallelized(), _parallelized);
Parameters::parse(parameters, Parameters::kKpBadSignRatio(), _badSignRatio); Parameters::parse(params, Parameters::kKpBadSignRatio(), _badSignRatio);
//Keypoint detector //Keypoint detector
UASSERT(_feature2D != 0); UASSERT(_feature2D != 0);
Feature2D::Type detectorStrategy = Feature2D::kFeatureUndef; Feature2D::Type detectorStrategy = Feature2D::kFeatureUndef;
if((iter=parameters.find(Parameters::kKpDetectorStrategy())) != parameters.end()) if((iter=params.find(Parameters::kKpDetectorStrategy())) != params.end())
{ {
detectorStrategy = (Feature2D::Type)std::atoi((*iter).second.c_str()); detectorStrategy = (Feature2D::Type)std::atoi((*iter).second.c_str());
} }
@@ -517,11 +530,11 @@ void Memory::parseParameters(const ParametersMap & parameters)
} }
else if(_feature2D) else if(_feature2D)
{ {
_feature2D->parseParameters(parameters); _feature2D->parseParameters(params);
} }
Registration::Type regStrategy = Registration::kTypeUndef; Registration::Type regStrategy = Registration::kTypeUndef;
if((iter=parameters.find(Parameters::kRegStrategy())) != parameters.end()) if((iter=params.find(Parameters::kRegStrategy())) != params.end())
{ {
regStrategy = (Registration::Type)std::atoi((*iter).second.c_str()); regStrategy = (Registration::Type)std::atoi((*iter).second.c_str());
} }
@@ -538,23 +551,23 @@ void Memory::parseParameters(const ParametersMap & parameters)
} }
else if(_registrationPipeline) else if(_registrationPipeline)
{ {
_registrationPipeline->parseParameters(parameters); _registrationPipeline->parseParameters(params);
} }
if(_registrationIcp) if(_registrationIcp)
{ {
_registrationIcp->parseParameters(parameters); _registrationIcp->parseParameters(params);
} }
if(_occupancy) if(_occupancy)
{ {
_occupancy->parseParameters(parameters); _occupancy->parseParameters(params);
} }
// do this after all parameters are parsed // do this after all params are parsed
// SLAM mode vs Localization mode // SLAM mode vs Localization mode
iter = parameters.find(Parameters::kMemIncrementalMemory()); iter = params.find(Parameters::kMemIncrementalMemory());
if(iter != parameters.end()) if(iter != params.end())
{ {
bool value = uStr2Bool(iter->second.c_str()); bool value = uStr2Bool(iter->second.c_str());
if(value == false && _incrementalMemory) if(value == false && _incrementalMemory)
@@ -578,6 +591,24 @@ void Memory::parseParameters(const ParametersMap & parameters)
} }
_incrementalMemory = value; _incrementalMemory = value;
} }
if(_useOdometryFeatures)
{
int visFeatureType = Parameters::defaultVisFeatureType();
int kpDetectorStrategy = Parameters::defaultKpDetectorStrategy();
Parameters::parse(parameters_, Parameters::kVisFeatureType(), visFeatureType);
Parameters::parse(parameters_, Parameters::kKpDetectorStrategy(), kpDetectorStrategy);
if(visFeatureType != kpDetectorStrategy)
{
UWARN("%s is enabled, but %s and %s parameters are not the same! Disabling %s...",
Parameters::kMemUseOdomFeatures().c_str(),
Parameters::kVisFeatureType().c_str(),
Parameters::kKpDetectorStrategy().c_str(),
Parameters::kMemUseOdomFeatures().c_str());
_useOdometryFeatures = false;
uInsert(parameters_, ParametersPair(Parameters::kMemUseOdomFeatures(), "false"));
}
}
} }
void Memory::preUpdate() void Memory::preUpdate()
@@ -1065,6 +1096,7 @@ std::map<int, int> Memory::getNeighborsId(
bool incrementMarginOnLoop, // default false bool incrementMarginOnLoop, // default false
bool ignoreLoopIds, // default false bool ignoreLoopIds, // default false
bool ignoreIntermediateNodes, // default false bool ignoreIntermediateNodes, // default false
bool ignoreLocalSpaceLoopIds, // default false, ignored if ignoreLoopIds=true
const std::set<int> & nodesSet, const std::set<int> & nodesSet,
double * dbAccessTime double * dbAccessTime
) const ) const
@@ -1150,7 +1182,7 @@ std::map<int, int> Memory::getNeighborsId(
nextMargin.insert(iter->first); nextMargin.insert(iter->first);
} }
} }
else if(!ignoreLoopIds) else if(!ignoreLoopIds && (!ignoreLocalSpaceLoopIds || iter->second.type()!=Link::kLocalSpaceClosure))
{ {
if(incrementMarginOnLoop) if(incrementMarginOnLoop)
{ {
@@ -1709,7 +1741,7 @@ cv::Mat Memory::loadOptimizedMesh(
std::map<int, Transform> * poses, std::map<int, Transform> * poses,
std::vector<std::vector<std::vector<unsigned int> > > * polygons, std::vector<std::vector<std::vector<unsigned int> > > * polygons,
#if PCL_VERSION_COMPARE(>=, 1, 8, 0) #if PCL_VERSION_COMPARE(>=, 1, 8, 0)
std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f>> > * texCoords, std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > * texCoords,
#else #else
std::vector<std::vector<Eigen::Vector2f> > * texCoords, std::vector<std::vector<Eigen::Vector2f> > * texCoords,
#endif #endif
@@ -2277,13 +2309,13 @@ Transform Memory::computeTransform(
// make sure we have all data needed // make sure we have all data needed
// load binary data from database if not in RAM (if image is already here, scan and userData should be or they are null) // load binary data from database if not in RAM (if image is already here, scan and userData should be or they are null)
if(((_reextractLoopClosureFeatures && _registrationPipeline->isImageRequired()) && fromS.sensorData().imageCompressed().empty()) || if((((_reextractLoopClosureFeatures || _visCorType==1) && _registrationPipeline->isImageRequired()) && fromS.sensorData().imageCompressed().empty()) ||
(_registrationPipeline->isScanRequired() && fromS.sensorData().imageCompressed().empty() && fromS.sensorData().laserScanCompressed().empty()) || (_registrationPipeline->isScanRequired() && fromS.sensorData().imageCompressed().empty() && fromS.sensorData().laserScanCompressed().empty()) ||
(_registrationPipeline->isUserDataRequired() && fromS.sensorData().imageCompressed().empty() && fromS.sensorData().userDataCompressed().empty())) (_registrationPipeline->isUserDataRequired() && fromS.sensorData().imageCompressed().empty() && fromS.sensorData().userDataCompressed().empty()))
{ {
fromS.sensorData() = getNodeData(fromS.id()); fromS.sensorData() = getNodeData(fromS.id());
} }
if(((_reextractLoopClosureFeatures && _registrationPipeline->isImageRequired()) && toS.sensorData().imageCompressed().empty()) || if((((_reextractLoopClosureFeatures || _visCorType==1) && _registrationPipeline->isImageRequired()) && toS.sensorData().imageCompressed().empty()) ||
(_registrationPipeline->isScanRequired() && toS.sensorData().imageCompressed().empty() && toS.sensorData().laserScanCompressed().empty()) || (_registrationPipeline->isScanRequired() && toS.sensorData().imageCompressed().empty() && toS.sensorData().laserScanCompressed().empty()) ||
(_registrationPipeline->isUserDataRequired() && toS.sensorData().imageCompressed().empty() && toS.sensorData().userDataCompressed().empty())) (_registrationPipeline->isUserDataRequired() && toS.sensorData().imageCompressed().empty() && toS.sensorData().userDataCompressed().empty()))
{ {
@@ -2292,13 +2324,13 @@ Transform Memory::computeTransform(
// uncompress only what we need // uncompress only what we need
cv::Mat imgBuf, depthBuf, laserBuf, userBuf; cv::Mat imgBuf, depthBuf, laserBuf, userBuf;
fromS.sensorData().uncompressData( fromS.sensorData().uncompressData(
(_reextractLoopClosureFeatures && _registrationPipeline->isImageRequired())?&imgBuf:0, ((_reextractLoopClosureFeatures || _visCorType==1) && _registrationPipeline->isImageRequired())?&imgBuf:0,
(_reextractLoopClosureFeatures && _registrationPipeline->isImageRequired())?&depthBuf:0, ((_reextractLoopClosureFeatures || _visCorType==1) && _registrationPipeline->isImageRequired())?&depthBuf:0,
_registrationPipeline->isScanRequired()?&laserBuf:0, _registrationPipeline->isScanRequired()?&laserBuf:0,
_registrationPipeline->isUserDataRequired()?&userBuf:0); _registrationPipeline->isUserDataRequired()?&userBuf:0);
toS.sensorData().uncompressData( toS.sensorData().uncompressData(
(_reextractLoopClosureFeatures && _registrationPipeline->isImageRequired())?&imgBuf:0, ((_reextractLoopClosureFeatures || _visCorType==1) && _registrationPipeline->isImageRequired())?&imgBuf:0,
(_reextractLoopClosureFeatures && _registrationPipeline->isImageRequired())?&depthBuf:0, ((_reextractLoopClosureFeatures || _visCorType==1) && _registrationPipeline->isImageRequired())?&depthBuf:0,
_registrationPipeline->isScanRequired()?&laserBuf:0, _registrationPipeline->isScanRequired()?&laserBuf:0,
_registrationPipeline->isUserDataRequired()?&userBuf:0); _registrationPipeline->isUserDataRequired()?&userBuf:0);
@@ -2331,11 +2363,14 @@ Transform Memory::computeTransform(
tmpTo.setWordsDescriptors(std::multimap<int, cv::Mat>()); tmpTo.setWordsDescriptors(std::multimap<int, cv::Mat>());
} }
if(guess.isNull() && !_registrationPipeline->isImageRequired()) if(guess.isNull() && (!_registrationPipeline->isImageRequired() || _visCorType==1))
{ {
UDEBUG(""); UDEBUG("");
// no visual in the pipeline, make visual registration for guess // no visual in the pipeline, make visual registration for guess
RegistrationVis regVis(parameters_); // make sure feature matching is used instead of optical flow to compute the guess
ParametersMap parameters = parameters_;
uInsert(parameters, ParametersPair(Parameters::kVisCorType(), "0"));
RegistrationVis regVis(parameters);
guess = regVis.computeTransformation(tmpFrom, tmpTo, guess, info); guess = regVis.computeTransformation(tmpFrom, tmpTo, guess, info);
if(!guess.isNull()) if(!guess.isNull())
{ {
@@ -3399,7 +3434,7 @@ Signature * Memory::createSignature(const SensorData & data, const Transform & p
meanWordsPerLocation = _vwd->getTotalActiveReferences() / treeSize; meanWordsPerLocation = _vwd->getTotalActiveReferences() / treeSize;
} }
if(_parallelized) if(_parallelized && !isIntermediateNode)
{ {
UDEBUG("Start dictionary update thread"); UDEBUG("Start dictionary update thread");
preUpdateThread.start(); preUpdateThread.start();
@@ -3447,7 +3482,7 @@ Signature * Memory::createSignature(const SensorData & data, const Transform & p
} }
cv::Mat depthMask; cv::Mat depthMask;
if(!decimatedData.depthRaw().empty()) if(!decimatedData.depthRaw().empty() && _depthAsMask)
{ {
if(imageMono.rows % decimatedData.depthRaw().rows == 0 && if(imageMono.rows % decimatedData.depthRaw().rows == 0 &&
imageMono.cols % decimatedData.depthRaw().cols == 0 && imageMono.cols % decimatedData.depthRaw().cols == 0 &&
@@ -3607,9 +3642,6 @@ Signature * Memory::createSignature(const SensorData & data, const Transform & p
UDEBUG("Joining dictionary update thread... thread finished!"); UDEBUG("Joining dictionary update thread... thread finished!");
} }
std::list<int> wordIds;
if(descriptors.rows)
{
t = timer.ticks(); t = timer.ticks();
if(stats) stats->addStatistic(Statistics::kTimingMemJoining_dictionary_update(), t*1000.0f); if(stats) stats->addStatistic(Statistics::kTimingMemJoining_dictionary_update(), t*1000.0f);
if(_parallelized) if(_parallelized)
@@ -3621,6 +3653,9 @@ Signature * Memory::createSignature(const SensorData & data, const Transform & p
UDEBUG("time descriptor (%d of size=%d) = %fs", descriptors.rows, descriptors.cols, t); UDEBUG("time descriptor (%d of size=%d) = %fs", descriptors.rows, descriptors.cols, t);
} }
std::list<int> wordIds;
if(descriptors.rows)
{
// In case the number of features we want to do quantization is lower // In case the number of features we want to do quantization is lower
// than extracted ones (that would be used for transform estimation) // than extracted ones (that would be used for transform estimation)
std::vector<bool> inliers; std::vector<bool> inliers;
+105 -14
View File
@@ -70,7 +70,10 @@ OccupancyGrid::OccupancyGrid(const ParametersMap & parameters) :
erode_(Parameters::defaultGridGlobalEroded()), erode_(Parameters::defaultGridGlobalEroded()),
footprintRadius_(Parameters::defaultGridGlobalFootprintRadius()), footprintRadius_(Parameters::defaultGridGlobalFootprintRadius()),
xMin_(0.0f), xMin_(0.0f),
yMin_(0.0f) yMin_(0.0f),
cloudAssembling_(false),
assembledGround_(new pcl::PointCloud<pcl::PointXYZRGB>),
assembledObstacles_(new pcl::PointCloud<pcl::PointXYZRGB>)
{ {
this->parseParameters(parameters); this->parseParameters(parameters);
} }
@@ -198,6 +201,16 @@ void OccupancyGrid::setCellSize(float cellSize)
} }
} }
void OccupancyGrid::setCloudAssembling(bool enabled)
{
cloudAssembling_ = enabled;
if(!cloudAssembling_)
{
assembledGround_->clear();
assembledObstacles_->clear();
}
}
void OccupancyGrid::createLocalMap( void OccupancyGrid::createLocalMap(
const Signature & node, const Signature & node,
cv::Mat & ground, cv::Mat & ground,
@@ -386,9 +399,11 @@ void OccupancyGrid::clear()
xMin_ = 0.0f; xMin_ = 0.0f;
yMin_ = 0.0f; yMin_ = 0.0f;
addedNodes_.clear(); addedNodes_.clear();
assembledGround_->clear();
assembledObstacles_->clear();
} }
const cv::Mat OccupancyGrid::getMap(float & xMin, float & yMin) const cv::Mat OccupancyGrid::getMap(float & xMin, float & yMin) const
{ {
xMin = xMin_; xMin = xMin_;
yMin = yMin_; yMin = yMin_;
@@ -470,6 +485,9 @@ void OccupancyGrid::update(const std::map<int, Transform> & posesIn)
} }
} }
bool assembledGroundUpdated = false;
bool assembledObstaclesUpdated = false;
if(graphOptimized || graphChanged) if(graphOptimized || graphChanged)
{ {
if(graphChanged) if(graphChanged)
@@ -481,6 +499,12 @@ void OccupancyGrid::update(const std::map<int, Transform> & posesIn)
UINFO("Graph optimized!"); UINFO("Graph optimized!");
} }
if(cloudAssembling_)
{
assembledGround_->clear();
assembledObstacles_->clear();
}
if(!fullUpdate_ && !graphChanged && !map_.empty()) // incremental, just move cells if(!fullUpdate_ && !graphChanged && !map_.empty()) // incremental, just move cells
{ {
// 1) recreate all local maps // 1) recreate all local maps
@@ -488,6 +512,8 @@ void OccupancyGrid::update(const std::map<int, Transform> & posesIn)
map_.rows == mapInfo_.rows); map_.rows == mapInfo_.rows);
std::map<int, std::pair<int, int> > tmpIndices; std::map<int, std::pair<int, int> > tmpIndices;
for(std::map<int, std::pair<int, int> >::iterator iter=cellCount_.begin(); iter!=cellCount_.end(); ++iter) for(std::map<int, std::pair<int, int> >::iterator iter=cellCount_.begin(); iter!=cellCount_.end(); ++iter)
{
if(!uContains(cache_, iter->first) && transforms.find(iter->first) != transforms.end())
{ {
if(iter->second.first) if(iter->second.first)
{ {
@@ -499,17 +525,20 @@ void OccupancyGrid::update(const std::map<int, Transform> & posesIn)
} }
tmpIndices.insert(std::make_pair(iter->first, std::make_pair(0,0))); tmpIndices.insert(std::make_pair(iter->first, std::make_pair(0,0)));
} }
for(int y=1; y<map_.rows-1; ++y) }
for(int y=0; y<map_.rows; ++y)
{ {
for(int x=1; x<map_.cols-1; ++x) for(int x=0; x<map_.cols; ++x)
{ {
float * info = mapInfo_.ptr<float>(y,x); float * info = mapInfo_.ptr<float>(y,x);
int nodeId = (int)info[0]; int nodeId = (int)info[0];
if(nodeId > 0 && map_.at<char>(y,x) >= 0) if(nodeId > 0 && map_.at<char>(y,x) >= 0)
{ {
std::map<int, Transform>::iterator tter = transforms.find(nodeId); if(tmpIndices.find(nodeId)!=tmpIndices.end())
if(tter != transforms.end() && !uContains(cache_, nodeId))
{ {
std::map<int, Transform>::iterator tter = transforms.find(nodeId);
UASSERT(tter != transforms.end());
cv::Point3f pt(info[1], info[2], 0.0f); cv::Point3f pt(info[1], info[2], 0.0f);
pt = util3d::transformPoint(pt, tter->second); pt = util3d::transformPoint(pt, tter->second);
@@ -547,8 +576,25 @@ void OccupancyGrid::update(const std::map<int, Transform> & posesIn)
} }
} }
} }
else if(nodeId > 0)
{
UERROR("Cell referred b node %d is unknown!?", nodeId);
} }
} }
}
//verify if all cells were added
for(std::map<int, std::pair<int, int> >::iterator iter=tmpIndices.begin(); iter!=tmpIndices.end(); ++iter)
{
std::map<int, cv::Mat>::iterator jter = emptyLocalMaps.find(iter->first);
UASSERT_MSG((iter->second.first == 0 && (jter==emptyLocalMaps.end() || jter->second.empty())) ||
(iter->second.first != 0 && jter!=emptyLocalMaps.end() && jter->second.cols == iter->second.first),
uFormat("iter->second.first=%d jter->second.cols=%d", iter->second.first, jter!=emptyLocalMaps.end()?jter->second.cols:-1).c_str());
jter = occupiedLocalMaps.find(iter->first);
UASSERT_MSG((iter->second.second == 0 && (jter==occupiedLocalMaps.end() || jter->second.empty())) ||
(iter->second.second != 0 && jter!=occupiedLocalMaps.end() && jter->second.cols == iter->second.second),
uFormat("iter->second.first=%d jter->second.cols=%d", iter->second.first, jter!=emptyLocalMaps.end()?jter->second.cols:-1).c_str());
}
UDEBUG("min (%f,%f) max(%f,%f)", minX, minY, maxX, maxY); UDEBUG("min (%f,%f) max(%f,%f)", minX, minY, maxX, maxY);
} }
@@ -575,12 +621,16 @@ void OccupancyGrid::update(const std::map<int, Transform> & posesIn)
std::list<std::pair<int, Transform> > poses; std::list<std::pair<int, Transform> > poses;
int lastId = addedNodes_.size()?addedNodes_.rbegin()->first:0; int lastId = addedNodes_.size()?addedNodes_.rbegin()->first:0;
UDEBUG("Last id = %d", lastId); UDEBUG("Last id = %d", lastId);
if(lastId >= 0)
// add old poses that were not in the current map (they were just retrieved from LTM)
for(std::map<int, Transform>::const_iterator iter=posesIn.upper_bound(0); iter!=posesIn.end(); ++iter)
{ {
for(std::map<int, Transform>::const_iterator iter=posesIn.upper_bound(lastId); iter!=posesIn.end(); ++iter) if(addedNodes_.find(iter->first) == addedNodes_.end())
{ {
poses.push_back(*iter); poses.push_back(*iter);
} }
}
// insert negative after // insert negative after
for(std::map<int, Transform>::const_iterator iter=posesIn.begin(); iter!=posesIn.end(); ++iter) for(std::map<int, Transform>::const_iterator iter=posesIn.begin(); iter!=posesIn.end(); ++iter)
{ {
@@ -593,7 +643,7 @@ void OccupancyGrid::update(const std::map<int, Transform> & posesIn)
break; break;
} }
} }
}
for(std::list<std::pair<int, Transform> >::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter) for(std::list<std::pair<int, Transform> >::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter)
{ {
UASSERT(!iter->second.isNull()); UASSERT(!iter->second.isNull());
@@ -662,6 +712,12 @@ void OccupancyGrid::update(const std::map<int, Transform> & posesIn)
maxY = vo[1]; maxY = vo[1];
} }
uInsert(emptyLocalMaps, std::make_pair(iter->first, ground)); uInsert(emptyLocalMaps, std::make_pair(iter->first, ground));
if(cloudAssembling_)
{
*assembledGround_ += *util3d::laserScanToPointCloudRGB(pair.first, iter->second, 0, 255, 0);
assembledGroundUpdated = true;
}
} }
//obstacles //obstacles
@@ -698,6 +754,12 @@ void OccupancyGrid::update(const std::map<int, Transform> & posesIn)
maxY = vo[1]; maxY = vo[1];
} }
uInsert(occupiedLocalMaps, std::make_pair(iter->first, obstacles)); uInsert(occupiedLocalMaps, std::make_pair(iter->first, obstacles));
if(cloudAssembling_)
{
*assembledObstacles_ += *util3d::laserScanToPointCloudRGB(pair.second, iter->second, 255, 0, 0);
assembledObstaclesUpdated = true;
}
} }
} }
} }
@@ -770,6 +832,8 @@ void OccupancyGrid::update(const std::map<int, Transform> & posesIn)
newMapSize.height = (yMax - yMin) / cellSize_+0.5f; newMapSize.height = (yMax - yMin) / cellSize_+0.5f;
UDEBUG("%d/%d -> %d/%d", map_.cols, map_.rows, newMapSize.width, newMapSize.height); UDEBUG("%d/%d -> %d/%d", map_.cols, map_.rows, newMapSize.width, newMapSize.height);
UASSERT(newMapSize.width >= map_.cols && newMapSize.height >= map_.rows); UASSERT(newMapSize.width >= map_.cols && newMapSize.height >= map_.rows);
UASSERT(newMapSize.width >= map_.cols+deltaX && newMapSize.height >= map_.rows+deltaY);
UASSERT(deltaX>=0 && deltaY>=0);
map = cv::Mat::ones(newMapSize, CV_8S)*-1; map = cv::Mat::ones(newMapSize, CV_8S)*-1;
mapInfo = cv::Mat::zeros(newMapSize, mapInfo_.type()); mapInfo = cv::Mat::zeros(newMapSize, mapInfo_.type());
map_.copyTo(map(cv::Rect(deltaX, deltaY, map_.cols, map_.rows))); map_.copyTo(map(cv::Rect(deltaX, deltaY, map_.cols, map_.rows)));
@@ -802,8 +866,8 @@ void OccupancyGrid::update(const std::map<int, Transform> & posesIn)
float * ptf = iter->second.ptr<float>(0,i); float * ptf = iter->second.ptr<float>(0,i);
cv::Point2i pt((ptf[0]-xMin)/cellSize_, (ptf[1]-yMin)/cellSize_); cv::Point2i pt((ptf[0]-xMin)/cellSize_, (ptf[1]-yMin)/cellSize_);
UASSERT_MSG(pt.y >=0 && pt.y < map.rows && pt.x >= 0 && pt.x < map.cols, UASSERT_MSG(pt.y >=0 && pt.y < map.rows && pt.x >= 0 && pt.x < map.cols,
uFormat("%d: pt=(%d,%d) map=%dx%d rawPt=(%f,%f) xMin=%f yMin=%f channels=%dvs%d", uFormat("%d: pt=(%d,%d) map=%dx%d rawPt=(%f,%f) xMin=%f yMin=%f channels=%dvs%d (graph modified=%d)",
kter->first, pt.x, pt.y, map.cols, map.rows, ptf[0], ptf[1], xMin, yMin, iter->second.channels(), mapInfo.channels()-1).c_str()); kter->first, pt.x, pt.y, map.cols, map.rows, ptf[0], ptf[1], xMin, yMin, iter->second.channels(), mapInfo.channels()-1, (graphOptimized || graphChanged)?1:0).c_str());
char & value = map.at<char>(pt.y, pt.x); char & value = map.at<char>(pt.y, pt.x);
if(value != -2 && (!incrementalGraphUpdate || value==-1)) if(value != -2 && (!incrementalGraphUpdate || value==-1))
{ {
@@ -912,8 +976,8 @@ void OccupancyGrid::update(const std::map<int, Transform> & posesIn)
float * ptf = jter->second.ptr<float>(0,i); float * ptf = jter->second.ptr<float>(0,i);
cv::Point2i pt((ptf[0]-xMin)/cellSize_, (ptf[1]-yMin)/cellSize_); cv::Point2i pt((ptf[0]-xMin)/cellSize_, (ptf[1]-yMin)/cellSize_);
UASSERT_MSG(pt.y>=0 && pt.y < map.rows && pt.x>=0 && pt.x < map.cols, UASSERT_MSG(pt.y>=0 && pt.y < map.rows && pt.x>=0 && pt.x < map.cols,
uFormat("%d: pt=(%d,%d) map=%dx%d rawPt=(%f,%f) xMin=%f yMin=%f channels=%dvs%d", uFormat("%d: pt=(%d,%d) map=%dx%d rawPt=(%f,%f) xMin=%f yMin=%f channels=%dvs%d (graph modified=%d)",
kter->first, pt.x, pt.y, map.cols, map.rows, ptf[0], ptf[1], xMin, yMin, jter->second.channels(), mapInfo.channels()-1).c_str()); kter->first, pt.x, pt.y, map.cols, map.rows, ptf[0], ptf[1], xMin, yMin, jter->second.channels(), mapInfo.channels()-1, (graphOptimized || graphChanged)?1:0).c_str());
char & value = map.at<char>(pt.y, pt.x); char & value = map.at<char>(pt.y, pt.x);
if(value != -2) if(value != -2)
{ {
@@ -1091,10 +1155,37 @@ void OccupancyGrid::update(const std::map<int, Transform> & posesIn)
} }
} }
if(!fullUpdate_) if(cloudAssembling_)
{
if(assembledGroundUpdated && assembledGround_->size() > 1)
{
assembledGround_ = util3d::voxelize(assembledGround_, cellSize_);
}
if(assembledObstaclesUpdated && assembledGround_->size() > 1)
{
assembledObstacles_ = util3d::voxelize(assembledObstacles_, cellSize_);
}
}
if(!fullUpdate_ && !cloudAssembling_)
{ {
cache_.clear(); cache_.clear();
} }
else
{
//clear only negative ids
for(std::map<int, std::pair<cv::Mat, cv::Mat> >::iterator iter=cache_.begin(); iter!=cache_.end();)
{
if(iter->first < 0)
{
cache_.erase(iter++);
}
else
{
break;
}
}
}
UDEBUG("Occupancy Grid update time = %f s", timer.ticks()); UDEBUG("Occupancy Grid update time = %f s", timer.ticks());
} }
+49 -9
View File
@@ -35,13 +35,26 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace rtabmap { namespace rtabmap {
OctoMap::OctoMap(float voxelSize, float occupancyThr, bool fullUpdate) : OctoMap::OctoMap(const ParametersMap & parameters, float occupancyThr) :
octree_(new octomap::ColorOcTree(voxelSize)), hasColor_(false),
fullUpdate_(Parameters::defaultGridGlobalFullUpdate())
{
float cellSize = Parameters::defaultGridCellSize();
Parameters::parse(parameters, Parameters::kGridCellSize(), cellSize);
UASSERT(cellSize>0.0f);
octree_ = new octomap::ColorOcTree(cellSize);
octree_->setOccupancyThres(occupancyThr);
Parameters::parse(parameters, Parameters::kGridGlobalFullUpdate(), fullUpdate_);
}
OctoMap::OctoMap(float cellSize, float occupancyThr, bool fullUpdate) :
octree_(new octomap::ColorOcTree(cellSize)),
hasColor_(false), hasColor_(false),
fullUpdate_(fullUpdate) fullUpdate_(fullUpdate)
{ {
octree_->setOccupancyThres(occupancyThr); octree_->setOccupancyThres(occupancyThr);
UASSERT(voxelSize>0.0f); UASSERT(cellSize>0.0f);
} }
OctoMap::~OctoMap() OctoMap::~OctoMap()
@@ -174,7 +187,8 @@ void OctoMap::update(const std::map<int, Transform> & poses)
} }
else if(jter == transforms.end() && iter->second.nodeRefId_ > 0) else if(jter == transforms.end() && iter->second.nodeRefId_ > 0)
{ {
UWARN("Could not find a transform for point linked to node %d (transforms=%d)", iter->second.nodeRefId_, (int)transforms.size()); // Note: normal if old nodes were transfered to LTM
//UWARN("Could not find a transform for point linked to node %d (transforms=%d)", iter->second.nodeRefId_, (int)transforms.size());
} }
} }
UDEBUG("%d/%d", copied, (int)occupiedCells_.size()); UDEBUG("%d/%d", copied, (int)occupiedCells_.size());
@@ -191,14 +205,19 @@ void OctoMap::update(const std::map<int, Transform> & poses)
// https://github.com/OctoMap/octomap_mapping/blob/jade-devel/octomap_server/src/OctomapServer.cpp#L356 // https://github.com/OctoMap/octomap_mapping/blob/jade-devel/octomap_server/src/OctomapServer.cpp#L356
// //
std::list<std::pair<int, Transform> > orderedPoses; std::list<std::pair<int, Transform> > orderedPoses;
int lastId = addedNodes_.size()?addedNodes_.rbegin()->first:0; int lastId = addedNodes_.size()?addedNodes_.rbegin()->first:0;
UDEBUG("Last id = %d", lastId); UDEBUG("Last id = %d", lastId);
if(lastId >= 0)
// add old poses that were not in the current map (they were just retrieved from LTM)
for(std::map<int, Transform>::const_iterator iter=poses.upper_bound(0); iter!=poses.end(); ++iter)
{ {
for(std::map<int, Transform>::const_iterator iter=poses.upper_bound(lastId); iter!=poses.end(); ++iter) if(addedNodes_.find(iter->first) == addedNodes_.end())
{ {
orderedPoses.push_back(*iter); orderedPoses.push_back(*iter);
} }
}
// insert negative after // insert negative after
for(std::map<int, Transform>::const_iterator iter=poses.begin(); iter!=poses.end(); ++iter) for(std::map<int, Transform>::const_iterator iter=poses.begin(); iter!=poses.end(); ++iter)
{ {
@@ -211,7 +230,6 @@ void OctoMap::update(const std::map<int, Transform> & poses)
break; break;
} }
} }
}
UDEBUG("orderedPoses = %d", (int)orderedPoses.size()); UDEBUG("orderedPoses = %d", (int)orderedPoses.size());
for(std::list<std::pair<int, Transform> >::const_iterator iter=orderedPoses.begin(); iter!=orderedPoses.end(); ++iter) for(std::list<std::pair<int, Transform> >::const_iterator iter=orderedPoses.begin(); iter!=orderedPoses.end(); ++iter)
@@ -259,7 +277,8 @@ void OctoMap::update(const std::map<int, Transform> & poses)
octomap::point3d point(pt.x, pt.y, pt.z); octomap::point3d point(pt.x, pt.y, pt.z);
// only clear space (ground points) // only clear space (ground points)
if (octree_->computeRayKeys(sensorOrigin, point, keyRay_)) if ((iter->first < 0 || iter->first>lastId) &&
octree_->computeRayKeys(sensorOrigin, point, keyRay_))
{ {
free_cells.insert(keyRay_.begin(), keyRay_.end()); free_cells.insert(keyRay_.begin(), keyRay_.end());
} }
@@ -267,6 +286,16 @@ void OctoMap::update(const std::map<int, Transform> & poses)
octomap::OcTreeKey key; octomap::OcTreeKey key;
if (octree_->coordToKeyChecked(point, key)) if (octree_->coordToKeyChecked(point, key))
{ {
if(iter->first >0 && iter->first<lastId)
{
octomap::ColorOcTreeNode * n = octree_->search(key);
if(n && occupiedCells_.find(n) != occupiedCells_.end() && occupiedCells_.at(n).nodeRefId_ > iter->first)
{
// The cell has been updated from more recent node, don't update the cell
continue;
}
}
ground_cells.insert(key); ground_cells.insert(key);
octomap::ColorOcTreeNode * n = octree_->updateNode(key, false); octomap::ColorOcTreeNode * n = octree_->updateNode(key, false);
@@ -309,7 +338,8 @@ void OctoMap::update(const std::map<int, Transform> & poses)
octomap::point3d point(pt.x, pt.y, pt.z); octomap::point3d point(pt.x, pt.y, pt.z);
// free cells // free cells
if (octree_->computeRayKeys(sensorOrigin, point, keyRay_)) if ((iter->first < 0 || iter->first>lastId) &&
octree_->computeRayKeys(sensorOrigin, point, keyRay_))
{ {
free_cells.insert(keyRay_.begin(), keyRay_.end()); free_cells.insert(keyRay_.begin(), keyRay_.end());
} }
@@ -317,6 +347,16 @@ void OctoMap::update(const std::map<int, Transform> & poses)
octomap::OcTreeKey key; octomap::OcTreeKey key;
if (octree_->coordToKeyChecked(point, key)) if (octree_->coordToKeyChecked(point, key))
{ {
if(iter->first >0 && iter->first<lastId)
{
octomap::ColorOcTreeNode * n = octree_->search(key);
if(n && occupiedCells_.find(n) != occupiedCells_.end() && occupiedCells_.at(n).nodeRefId_ > iter->first)
{
// The cell has been updated from more recent node, don't update the cell
continue;
}
}
occupied_cells.insert(key); occupied_cells.insert(key);
octomap::ColorOcTreeNode * n = octree_->updateNode(key, true); octomap::ColorOcTreeNode * n = octree_->updateNode(key, true);
+8
View File
@@ -39,6 +39,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "rtabmap/utilite/ULogger.h" #include "rtabmap/utilite/ULogger.h"
#include "rtabmap/utilite/UTimer.h" #include "rtabmap/utilite/UTimer.h"
#include "rtabmap/utilite/UConversion.h" #include "rtabmap/utilite/UConversion.h"
#include "rtabmap/utilite/UProcessInfo.h"
#include "rtabmap/core/ParticleFilter.h" #include "rtabmap/core/ParticleFilter.h"
#include "rtabmap/core/util2d.h" #include "rtabmap/core/util2d.h"
@@ -99,6 +100,7 @@ Odometry::Odometry(const rtabmap::ParametersMap & parameters) :
_kalmanMeasurementNoise(Parameters::defaultOdomKalmanMeasurementNoise()), _kalmanMeasurementNoise(Parameters::defaultOdomKalmanMeasurementNoise()),
_imageDecimation(Parameters::defaultOdomImageDecimation()), _imageDecimation(Parameters::defaultOdomImageDecimation()),
_alignWithGround(Parameters::defaultOdomAlignWithGround()), _alignWithGround(Parameters::defaultOdomAlignWithGround()),
_publishRAMUsage(Parameters::defaultRtabmapPublishRAMUsage()),
_pose(Transform::getIdentity()), _pose(Transform::getIdentity()),
_resetCurrentCount(0), _resetCurrentCount(0),
previousStamp_(0), previousStamp_(0),
@@ -125,6 +127,8 @@ Odometry::Odometry(const rtabmap::ParametersMap & parameters) :
Parameters::parse(parameters, Parameters::kOdomKalmanMeasurementNoise(), _kalmanMeasurementNoise); Parameters::parse(parameters, Parameters::kOdomKalmanMeasurementNoise(), _kalmanMeasurementNoise);
Parameters::parse(parameters, Parameters::kOdomImageDecimation(), _imageDecimation); Parameters::parse(parameters, Parameters::kOdomImageDecimation(), _imageDecimation);
Parameters::parse(parameters, Parameters::kOdomAlignWithGround(), _alignWithGround); Parameters::parse(parameters, Parameters::kOdomAlignWithGround(), _alignWithGround);
Parameters::parse(parameters, Parameters::kRtabmapPublishRAMUsage(), _publishRAMUsage);
if(_imageDecimation == 0) if(_imageDecimation == 0)
{ {
_imageDecimation = 1; _imageDecimation = 1;
@@ -398,6 +402,10 @@ Transform Odometry::process(SensorData & data, const Transform & guessIn, Odomet
info->stamp = data.stamp(); info->stamp = data.stamp();
info->interval = dt; info->interval = dt;
info->transform = t; info->transform = t;
if(_publishRAMUsage)
{
info->memoryUsage = UProcessInfo::getMemoryUsage()/(1024*1024);
}
if(!data.groundTruth().isNull()) if(!data.groundTruth().isNull())
{ {
+46
View File
@@ -49,6 +49,8 @@ OdometryF2F::OdometryF2F(const ParametersMap & parameters) :
UASSERT(keyFrameThr_>=0.0f && keyFrameThr_<=1.0f); UASSERT(keyFrameThr_>=0.0f && keyFrameThr_<=1.0f);
UASSERT(visKeyFrameThr_>=0); UASSERT(visKeyFrameThr_>=0);
UASSERT(scanKeyFrameThr_>=0.0f && scanKeyFrameThr_<=1.0f); UASSERT(scanKeyFrameThr_>=0.0f && scanKeyFrameThr_<=1.0f);
parameters_ = parameters;
} }
OdometryF2F::~OdometryF2F() OdometryF2F::~OdometryF2F()
@@ -96,6 +98,24 @@ Transform OdometryF2F::computeTransform(
Signature newFrame(data); Signature newFrame(data);
if(refFrame_.sensorData().isValid()) if(refFrame_.sensorData().isValid())
{ {
float maxCorrespondenceDistance = 0.0f;
float pmOutlierRatio = 0.0f;
if(guess.isNull() &&
!registrationPipeline_->isImageRequired() &&
registrationPipeline_->isScanRequired() &&
this->framesProcessed() < 2)
{
// only on initialization (first frame to register), increase icp max correspondences in case the robot is already moving
maxCorrespondenceDistance = Parameters::defaultIcpMaxCorrespondenceDistance();
pmOutlierRatio = Parameters::defaultIcpPMOutlierRatio();
Parameters::parse(parameters_, Parameters::kIcpMaxCorrespondenceDistance(), maxCorrespondenceDistance);
Parameters::parse(parameters_, Parameters::kIcpPMOutlierRatio(), pmOutlierRatio);
ParametersMap params;
params.insert(ParametersPair(Parameters::kIcpMaxCorrespondenceDistance(), uNumber2Str(maxCorrespondenceDistance*3.0f)));
params.insert(ParametersPair(Parameters::kIcpPMOutlierRatio(), uNumber2Str(0.95f)));
registrationPipeline_->parseParameters(params);
}
Signature tmpRefFrame = refFrame_; Signature tmpRefFrame = refFrame_;
output = registrationPipeline_->computeTransformationMod( output = registrationPipeline_->computeTransformationMod(
tmpRefFrame, tmpRefFrame,
@@ -104,6 +124,15 @@ Transform OdometryF2F::computeTransform(
!guess.isNull()?motionSinceLastKeyFrame*guess:!registrationPipeline_->isImageRequired()&&this->framesProcessed()<2?motionSinceLastKeyFrame:Transform(), !guess.isNull()?motionSinceLastKeyFrame*guess:!registrationPipeline_->isImageRequired()&&this->framesProcessed()<2?motionSinceLastKeyFrame:Transform(),
&regInfo); &regInfo);
if(maxCorrespondenceDistance>0.0f)
{
// set it back
ParametersMap params;
params.insert(ParametersPair(Parameters::kIcpMaxCorrespondenceDistance(), uNumber2Str(maxCorrespondenceDistance)));
params.insert(ParametersPair(Parameters::kIcpPMOutlierRatio(), uNumber2Str(pmOutlierRatio)));
registrationPipeline_->parseParameters(params);
}
if(output.isNull() && !guess.isNull() && registrationPipeline_->isImageRequired()) if(output.isNull() && !guess.isNull() && registrationPipeline_->isImageRequired())
{ {
tmpRefFrame = refFrame_; tmpRefFrame = refFrame_;
@@ -112,12 +141,29 @@ Transform OdometryF2F::computeTransform(
newFrame.setWords3(std::multimap<int, cv::Point3f>()); newFrame.setWords3(std::multimap<int, cv::Point3f>());
newFrame.setWordsDescriptors(std::multimap<int, cv::Mat>()); newFrame.setWordsDescriptors(std::multimap<int, cv::Mat>());
UWARN("Failed to find a transformation with the provided guess (%s), trying again without a guess.", guess.prettyPrint().c_str()); UWARN("Failed to find a transformation with the provided guess (%s), trying again without a guess.", guess.prettyPrint().c_str());
// If optical flow is used, switch temporary to feature matching
int visCorTypeBackup = Parameters::defaultVisCorType();
Parameters::parse(parameters_, Parameters::kVisCorType(), visCorTypeBackup);
if(visCorTypeBackup == 1)
{
ParametersMap params;
params.insert(ParametersPair(Parameters::kVisCorType(), "0"));
registrationPipeline_->parseParameters(params);
}
output = registrationPipeline_->computeTransformationMod( output = registrationPipeline_->computeTransformationMod(
tmpRefFrame, tmpRefFrame,
newFrame, newFrame,
Transform(), // null guess Transform(), // null guess
&regInfo); &regInfo);
if(visCorTypeBackup == 1)
{
ParametersMap params;
params.insert(ParametersPair(Parameters::kVisCorType(), "1"));
registrationPipeline_->parseParameters(params);
}
if(output.isNull()) if(output.isNull())
{ {
UWARN("Trial with no guess still fail."); UWARN("Trial with no guess still fail.");
+110 -37
View File
@@ -167,6 +167,7 @@ void OdometryF2M::reset(const Transform & initialPose)
bundleModels_.clear(); bundleModels_.clear();
bundlePoseReferences_.clear(); bundlePoseReferences_.clear();
bundleSeq_ = 0; bundleSeq_ = 0;
lastFrameOldestNewId_ = 0;
} }
// return not null transform if odometry is correctly computed // return not null transform if odometry is correctly computed
@@ -209,9 +210,33 @@ Transform OdometryF2M::computeTransform(
if((map_->getWords3().size() || !map_->sensorData().laserScanRaw().empty()) && if((map_->getWords3().size() || !map_->sensorData().laserScanRaw().empty()) &&
lastFrame_->sensorData().isValid()) lastFrame_->sensorData().isValid())
{ {
Signature tmpMap = *map_; Signature tmpMap;
Transform transform;
UDEBUG("guess=%s frames=%d image required=%d", guess.prettyPrint().c_str(), this->framesProcessed(), regPipeline_->isImageRequired()?1:0); UDEBUG("guess=%s frames=%d image required=%d", guess.prettyPrint().c_str(), this->framesProcessed(), regPipeline_->isImageRequired()?1:0);
// bundle adjustment stuff if used
std::map<int, cv::Point3f> points3DMap;
std::map<int, Transform> bundlePoses;
std::multimap<int, Link> bundleLinks;
std::map<int, CameraModel> bundleModels;
std::map<int, StereoCameraModel> bundleStereoModels;
for(int guessIteration=0;
guessIteration<(!guess.isNull()&&regPipeline_->isImageRequired()?2:1) && transform.isNull();
++guessIteration)
{
tmpMap = *map_;
// reset matches, but keep already extracted features in lastFrame_->sensorData()
lastFrame_->setWords(std::multimap<int, cv::KeyPoint>());
lastFrame_->setWords3(std::multimap<int, cv::Point3f>());
lastFrame_->setWordsDescriptors(std::multimap<int, cv::Mat>());
points3DMap.clear();
bundlePoses.clear();
bundleLinks.clear();
bundleModels.clear();
bundleStereoModels.clear();
float maxCorrespondenceDistance = 0.0f; float maxCorrespondenceDistance = 0.0f;
float pmOutlierRatio = 0.0f; float pmOutlierRatio = 0.0f;
if(guess.isNull() && if(guess.isNull() &&
@@ -230,11 +255,16 @@ Transform OdometryF2M::computeTransform(
regPipeline_->parseParameters(params); regPipeline_->parseParameters(params);
} }
Transform transform = regPipeline_->computeTransformationMod( if(guessIteration == 1)
{
UWARN("Failed to find a transformation with the provided guess (%s), trying again without a guess.", guess.prettyPrint().c_str());
}
transform = regPipeline_->computeTransformationMod(
tmpMap, tmpMap,
*lastFrame_, *lastFrame_,
// special case for ICP-only odom, set guess to identity if we just started or reset // special case for ICP-only odom, set guess to identity if we just started or reset
!guess.isNull()?this->getPose()*guess:!regPipeline_->isImageRequired()&&this->framesProcessed()<2?this->getPose():Transform(), guessIteration==0 && !guess.isNull()?this->getPose()*guess:!regPipeline_->isImageRequired()&&this->framesProcessed()<2?this->getPose():Transform(),
&regInfo); &regInfo);
if(maxCorrespondenceDistance>0.0f) if(maxCorrespondenceDistance>0.0f)
@@ -246,36 +276,9 @@ Transform OdometryF2M::computeTransform(
regPipeline_->parseParameters(params); regPipeline_->parseParameters(params);
} }
if(transform.isNull() && !guess.isNull() && regPipeline_->isImageRequired())
{
tmpMap = *map_;
// reset matches, but keep already extracted features in lastFrame_->sensorData()
lastFrame_->setWords(std::multimap<int, cv::KeyPoint>());
lastFrame_->setWords3(std::multimap<int, cv::Point3f>());
lastFrame_->setWordsDescriptors(std::multimap<int, cv::Mat>());
UWARN("Failed to find a transformation with the provided guess (%s), trying again without a guess.", guess.prettyPrint().c_str());
transform = regPipeline_->computeTransformationMod(
tmpMap,
*lastFrame_,
Transform(), // null guess
&regInfo);
if(transform.isNull())
{
UWARN("Trial with no guess still fail.");
}
else
{
UWARN("Trial with no guess succeeded.");
}
}
data.setFeatures(lastFrame_->sensorData().keypoints(), lastFrame_->sensorData().keypoints3D(), lastFrame_->sensorData().descriptors()); data.setFeatures(lastFrame_->sensorData().keypoints(), lastFrame_->sensorData().keypoints3D(), lastFrame_->sensorData().descriptors());
UDEBUG("Registration time = %fs", regInfo.totalTime); UDEBUG("Registration time = %fs", regInfo.totalTime);
std::map<int, cv::Point3f> points3DMap;
std::map<int, Transform> bundlePoses;
std::multimap<int, Link> bundleLinks;
std::map<int, CameraModel> bundleModels;
std::map<int, StereoCameraModel> bundleStereoModels;
if(!transform.isNull()) if(!transform.isNull())
{ {
// local bundle adjustment // local bundle adjustment
@@ -414,9 +417,6 @@ Transform OdometryF2M::computeTransform(
{ {
if(!bundlePoses.rbegin()->second.isNull()) if(!bundlePoses.rbegin()->second.isNull())
{ {
transform = bundlePoses.rbegin()->second;
bundleLinks.find(bundlePoses_.rbegin()->first)->second.setTransform(bundlePoses_.rbegin()->second.inverse()*transform);
if(sbaOutliers.size()) if(sbaOutliers.size())
{ {
std::vector<int> newInliers(regInfo.inliersIDs.size()); std::vector<int> newInliers(regInfo.inliersIDs.size());
@@ -433,6 +433,16 @@ Transform OdometryF2M::computeTransform(
regInfo.inliers = (int)newInliers.size(); regInfo.inliers = (int)newInliers.size();
regInfo.inliersIDs = newInliers; regInfo.inliersIDs = newInliers;
} }
if(regInfo.inliers < regPipeline_->getMinVisualCorrespondences())
{
regInfo.rejectedMsg = uFormat("Too low inliers after bundle adjustment: %d<%d", regInfo.inliers, regPipeline_->getMinVisualCorrespondences());
transform.setNull();
}
else
{
transform = bundlePoses.rbegin()->second;
bundleLinks.find(bundlePoses_.rbegin()->first)->second.setTransform(bundlePoses_.rbegin()->second.inverse()*transform);
}
} }
UDEBUG("Local Bundle Adjustment After : %s", transform.prettyPrint().c_str()); UDEBUG("Local Bundle Adjustment After : %s", transform.prettyPrint().c_str());
} }
@@ -443,10 +453,20 @@ Transform OdometryF2M::computeTransform(
} }
} }
if(!transform.isNull())
{
// make it incremental // make it incremental
transform = this->getPose().inverse() * transform; transform = this->getPose().inverse() * transform;
} }
else if(!regInfo.rejectedMsg.empty()) }
if(transform.isNull())
{
if(guessIteration == 1)
{
UWARN("Trial with no guess still fail.");
}
if(!regInfo.rejectedMsg.empty())
{ {
UWARN("Registration failed: \"%s\"", regInfo.rejectedMsg.c_str()); UWARN("Registration failed: \"%s\"", regInfo.rejectedMsg.c_str());
} }
@@ -454,6 +474,12 @@ Transform OdometryF2M::computeTransform(
{ {
UWARN("Unknown registration error"); UWARN("Unknown registration error");
} }
}
else if(guessIteration == 1)
{
UWARN("Trial with no guess succeeded!");
}
}
if(!transform.isNull()) if(!transform.isNull())
{ {
@@ -579,6 +605,8 @@ Transform OdometryF2M::computeTransform(
} }
UDEBUG("newIds=%d", (int)newIds.size()); UDEBUG("newIds=%d", (int)newIds.size());
int lastFrameOldestNewId = lastFrameOldestNewId_;
lastFrameOldestNewId_ = lastFrame_->getWords().size()?lastFrame_->getWords().rbegin()->first:0;
for(std::multimap<float, std::pair<int, std::pair<cv::KeyPoint, std::pair<cv::Point3f, cv::Mat> > > >::reverse_iterator iter=newIds.rbegin(); for(std::multimap<float, std::pair<int, std::pair<cv::KeyPoint, std::pair<cv::Point3f, cv::Mat> > > >::reverse_iterator iter=newIds.rbegin();
iter!=newIds.rend(); iter!=newIds.rend();
++iter) ++iter)
@@ -610,6 +638,10 @@ Transform OdometryF2M::computeTransform(
mapWords.insert(std::make_pair(iter->second.first, iter->second.second.first)); mapWords.insert(std::make_pair(iter->second.first, iter->second.second.first));
mapPoints.insert(std::make_pair(iter->second.first, util3d::transformPoint(iter->second.second.second.first, newFramePose))); mapPoints.insert(std::make_pair(iter->second.first, util3d::transformPoint(iter->second.second.second.first, newFramePose)));
mapDescriptors.insert(std::make_pair(iter->second.first, iter->second.second.second.second)); mapDescriptors.insert(std::make_pair(iter->second.first, iter->second.second.second.second));
if(lastFrameOldestNewId_ > iter->second.first)
{
lastFrameOldestNewId_ = iter->second.first;
}
++added; ++added;
} }
} }
@@ -617,14 +649,55 @@ Transform OdometryF2M::computeTransform(
// remove words in map if max size is reached // remove words in map if max size is reached
if((int)mapPoints.size() > maximumMapSize_) if((int)mapPoints.size() > maximumMapSize_)
{ {
// remove oldest first, keep matched features with their aliases // remove oldest outliers first
std::set<int> matches(regInfo.matchesIDs.begin(), regInfo.matchesIDs.end()); std::set<int> inliers(regInfo.inliersIDs.begin(), regInfo.inliersIDs.end());
std::vector<int> ids = regInfo.matchesIDs;
if(regInfo.projectedIDs.size())
{
ids.resize(ids.size() + regInfo.projectedIDs.size());
int oi=0;
for(unsigned int i=0; i<regInfo.projectedIDs.size(); ++i)
{
if(regInfo.projectedIDs[i]>=lastFrameOldestNewId)
{
ids[regInfo.matchesIDs.size()+oi++] = regInfo.projectedIDs[i];
}
}
ids.resize(regInfo.matchesIDs.size()+oi);
UDEBUG("projected added=%d/%d minLastFrameId=%d", oi, (int)regInfo.projectedIDs.size(), lastFrameOldestNewId);
}
for(unsigned int i=0; i<ids.size() && (int)mapPoints.size() > maximumMapSize_ && mapPoints.size() >= newIds.size(); ++i)
{
int id = ids.at(i);
if(inliers.find(id) == inliers.end())
{
std::map<int, std::map<int, cv::Point3f> >::iterator iterRef = bundleWordReferences_.find(id);
if(iterRef != bundleWordReferences_.end())
{
for(std::map<int, cv::Point3f>::iterator iterFrame = iterRef->second.begin(); iterFrame != iterRef->second.end(); ++iterFrame)
{
if(bundlePoseReferences_.find(iterFrame->first) != bundlePoseReferences_.end())
{
bundlePoseReferences_.at(iterFrame->first) -= 1;
}
}
bundleWordReferences_.erase(iterRef);
}
mapPoints.erase(id);
mapDescriptors.erase(id);
mapWords.erase(id);
++removed;
}
}
// remove oldest first
std::multimap<int, cv::Mat>::iterator iterMapDescriptors = mapDescriptors.begin(); std::multimap<int, cv::Mat>::iterator iterMapDescriptors = mapDescriptors.begin();
std::multimap<int, cv::KeyPoint>::iterator iterMapWords = mapWords.begin(); std::multimap<int, cv::KeyPoint>::iterator iterMapWords = mapWords.begin();
for(std::multimap<int, cv::Point3f>::iterator iter = mapPoints.begin(); for(std::multimap<int, cv::Point3f>::iterator iter = mapPoints.begin();
iter!=mapPoints.end() && (int)mapPoints.size() > maximumMapSize_ && mapPoints.size() >= newIds.size();) iter!=mapPoints.end() && (int)mapPoints.size() > maximumMapSize_ && mapPoints.size() >= newIds.size();)
{ {
if(matches.find(iter->first) == matches.end()) if(inliers.find(iter->first) == inliers.end())
{ {
std::map<int, std::map<int, cv::Point3f> >::iterator iterRef = bundleWordReferences_.find(iter->first); std::map<int, std::map<int, cv::Point3f> >::iterator iterRef = bundleWordReferences_.find(iter->first);
if(iterRef != bundleWordReferences_.end()) if(iterRef != bundleWordReferences_.end())
+6 -1
View File
@@ -143,7 +143,12 @@ Transform OdometryFovis::computeTransform(
data.stereoCameraModel().left().isValidForReprojection() && data.stereoCameraModel().left().isValidForReprojection() &&
data.stereoCameraModel().right().isValidForReprojection()))) data.stereoCameraModel().right().isValidForReprojection())))
{ {
UERROR("Invalid camera model!"); UERROR("Invalid camera model! Mono cameras=%d (reproj=%d), Stereo camera=%d (reproj=%d|%d)",
(int)data.cameraModels().size(),
data.cameraModels().size() && data.cameraModels()[0].isValidForReprojection()?1:0,
data.stereoCameraModel().isValidForProjection()?1:0,
data.stereoCameraModel().left().isValidForReprojection()?1:0,
data.stereoCameraModel().right().isValidForReprojection()?1:0);
return t; return t;
} }
+66 -7
View File
@@ -46,11 +46,14 @@ class Tracker: public Tracking
{ {
public: public:
Tracker(System* pSys, ORBVocabulary* pVoc, FrameDrawer* pFrameDrawer, MapDrawer* pMapDrawer, Map* pMap, Tracker(System* pSys, ORBVocabulary* pVoc, FrameDrawer* pFrameDrawer, MapDrawer* pMapDrawer, Map* pMap,
KeyFrameDatabase* pKFDB, const std::string &strSettingPath, const int sensor) : KeyFrameDatabase* pKFDB, const std::string &strSettingPath, const int sensor, long unsigned int maxFeatureMapSize) :
Tracking(pSys, pVoc, pFrameDrawer, pMapDrawer, pMap, pKFDB, strSettingPath, sensor) Tracking(pSys, pVoc, pFrameDrawer, pMapDrawer, pMap, pKFDB, strSettingPath, sensor),
maxFeatureMapSize_(maxFeatureMapSize)
{ {
} }
private:
long unsigned int maxFeatureMapSize_;
protected: protected:
void Track() void Track()
@@ -248,7 +251,60 @@ protected:
// Check if we need to insert a new keyframe // Check if we need to insert a new keyframe
if(NeedNewKeyFrame()) if(NeedNewKeyFrame())
{
CreateNewKeyFrame(); CreateNewKeyFrame();
}
if(maxFeatureMapSize_ > 0)
{
//limit size of the feature map, keep last X recent ones
if(mpMap->KeyFramesInMap()>1 && mpMap->MapPointsInMap()>maxFeatureMapSize_)
{
std::vector<KeyFrame*> kfs = mpMap->GetAllKeyFrames();
std::map<long unsigned int, KeyFrame*> kfsSorted;
for(unsigned int i=1; i<kfs.size(); ++i)
{
kfsSorted.insert(std::make_pair(kfs[i]->mnId, kfs[i]));
}
KeyFrame * lastFrame = kfsSorted.rbegin()->second;
std::vector<MapPoint*> mapPoints = mpMap->GetAllMapPoints();
std::map<long unsigned int, MapPoint*> mapPointsSorted;
for(unsigned int i=0; i<mapPoints.size(); ++i)
{
mapPointsSorted.insert(std::make_pair(mapPoints[i]->mnId, mapPoints[i]));
}
for(std::map<long unsigned int, MapPoint*>::iterator iter=mapPointsSorted.begin();
iter != mapPointsSorted.end() && mpMap->MapPointsInMap()>maxFeatureMapSize_;
++iter)
{
if(!iter->second->IsInKeyFrame(lastFrame))
{
// FIXME: Memory leak: ORB_SLAM2 doesn't delete after removing from the map...
// Not sure when it is safe to delete it, as if I delete just
// after setting the bad flag, the app crashes.
iter->second->SetBadFlag();
}
}
// remove kfs without observations
for(std::map<long unsigned int, KeyFrame*>::iterator iter=kfsSorted.begin();
iter != kfsSorted.end();
++iter)
{
if(iter->second!=lastFrame && iter->second->GetMapPoints().size()==0)
{
// FIXME: Memory leak: ORB_SLAM2 doesn't delete after removing from the map...
// Not sure when it is safe to delete it, as if I delete just
// after setting the bad flag, the app crashes.
iter->second->SetBadFlag();
}
else
{
break;
}
}
}
}
// We allow points with high innovation (considererd outliers by the Huber Function) // We allow points with high innovation (considererd outliers by the Huber Function)
// pass to the new keyframe, so that bundle adjustment will finally decide // pass to the new keyframe, so that bundle adjustment will finally decide
@@ -466,7 +522,7 @@ public:
if(CheckFinish()) if(CheckFinish())
break; break;
usleep(30000); usleep(1000000); // 1 sec
} }
SetFinish(); SetFinish();
@@ -639,6 +695,9 @@ public:
ofs << "ORBextractor.minThFAST: " << minThFAST << std::endl; ofs << "ORBextractor.minThFAST: " << minThFAST << std::endl;
ofs << std::endl; ofs << std::endl;
int maxFeatureMapSize = rtabmap::Parameters::defaultOdomORBSLAM2MapSize();
rtabmap::Parameters::parse(parameters_, rtabmap::Parameters::kOdomORBSLAM2MapSize(), maxFeatureMapSize);
ofs.close(); ofs.close();
//Create KeyFrame Database //Create KeyFrame Database
@@ -649,7 +708,7 @@ public:
//Initialize the Tracking thread //Initialize the Tracking thread
//(it will live in the main thread of execution, the one that called this constructor) //(it will live in the main thread of execution, the one that called this constructor)
mpTracker = new ORB_SLAM2::Tracker(0, mpVocabulary, 0, 0, mpMap, mpKeyFrameDatabase, configPath, stereo?ORB_SLAM2::System::STEREO:ORB_SLAM2::System::RGBD); mpTracker = new ORB_SLAM2::Tracker(0, mpVocabulary, 0, 0, mpMap, mpKeyFrameDatabase, configPath, stereo?ORB_SLAM2::System::STEREO:ORB_SLAM2::System::RGBD, maxFeatureMapSize);
//Initialize the Local Mapping thread and launch //Initialize the Local Mapping thread and launch
mpLocalMapper = new ORB_SLAM2::LocalMapping(mpMap, false); mpLocalMapper = new ORB_SLAM2::LocalMapping(mpMap, false);
@@ -891,9 +950,9 @@ Transform OdometryORBSLAM2::computeTransform(
covariance.at<double>(0,0) = linearVar; covariance.at<double>(0,0) = linearVar;
covariance.at<double>(1,1) = linearVar; covariance.at<double>(1,1) = linearVar;
covariance.at<double>(2,2) = linearVar; covariance.at<double>(2,2) = linearVar;
covariance.at<double>(3,3) = 0.01; covariance.at<double>(3,3) = 0.0001;
covariance.at<double>(4,4) = 0.01; covariance.at<double>(4,4) = 0.0001;
covariance.at<double>(5,5) = 0.01; covariance.at<double>(5,5) = 0.0001;
} }
} }
+4 -4
View File
@@ -163,10 +163,10 @@ Transform OdometryViso2::computeTransform(
if(viso2_ == 0) if(viso2_ == 0)
{ {
VisualOdometryStereo::parameters params; VisualOdometryStereo::parameters params;
params.base = data.stereoCameraModel().baseline(); params.base = params.match.base = data.stereoCameraModel().baseline();
params.calib.cu = data.stereoCameraModel().left().cx(); params.calib.cu = params.match.cu = data.stereoCameraModel().left().cx();
params.calib.cv = data.stereoCameraModel().left().cy(); params.calib.cv = params.match.cv = data.stereoCameraModel().left().cy();
params.calib.f = data.stereoCameraModel().left().fx(); params.calib.f = params.match.f = data.stereoCameraModel().left().fx();
Parameters::parse(viso2Parameters_, Parameters::kOdomViso2RansacIters(), params.ransac_iters); Parameters::parse(viso2Parameters_, Parameters::kOdomViso2RansacIters(), params.ransac_iters);
Parameters::parse(viso2Parameters_, Parameters::kOdomViso2InlierThreshold(), params.inlier_threshold); Parameters::parse(viso2Parameters_, Parameters::kOdomViso2InlierThreshold(), params.inlier_threshold);
+1 -1
View File
@@ -965,7 +965,7 @@ std::map<int, Transform> OptimizerG2O::optimizeBA(
{ {
if(baseline > 0.0) if(baseline > 0.0)
{ {
UWARN("Stereo camera model detected but current " UDEBUG("Stereo camera model detected but current "
"observation (pt=%d to cam=%d) has null depth (%f m), adding " "observation (pt=%d to cam=%d) has null depth (%f m), adding "
"mono observation instead.", "mono observation instead.",
vpt3d->id()-stepVertexId, camId, depth); vpt3d->id()-stepVertexId, camId, depth);
+2 -1
View File
@@ -172,7 +172,8 @@ rtabmap::ParametersMap Parameters::getDefaultOdometryParameters(bool stereo, boo
(icp && group.compare("Icp") == 0) || (icp && group.compare("Icp") == 0) ||
(vis && Parameters::isFeatureParameter(iter->first)) || (vis && Parameters::isFeatureParameter(iter->first)) ||
group.compare("Reg") == 0 || group.compare("Reg") == 0 ||
(vis && group.compare("Vis") == 0)) (vis && group.compare("Vis") == 0) ||
iter->first.compare(kRtabmapPublishRAMUsage())==0)
{ {
if(stereo) if(stereo)
{ {
+6 -1
View File
@@ -155,7 +155,12 @@ bool databaseRecovery(
} }
else else
{ {
if(!rtabmap.process(data, info.odomPose, info.odomCovariance)) if(!odometryIgnored && !info.odomCovariance.empty() && info.odomCovariance.at<double>(0,0)>=9999)
{
status = uFormat("High variance detected, triggering a new map...");
rtabmap.triggerNewMap();
}
if(!rtabmap.process(data, info.odomPose, info.odomCovariance, info.odomVelocity))
{ {
status = uFormat("Failed processing node %d.", data.id()); status = uFormat("Failed processing node %d.", data.id());
} }
+11 -1
View File
@@ -119,6 +119,16 @@ bool Registration::isUserDataRequired() const
return val; return val;
} }
bool Registration::canUseGuess() const
{
bool val = canUseGuessImpl();
if(!val && child_)
{
val = child_->canUseGuess();
}
return val;
}
int Registration::getMinVisualCorrespondences() const int Registration::getMinVisualCorrespondences() const
{ {
int min = this->getMinVisualCorrespondencesImpl(); int min = this->getMinVisualCorrespondencesImpl();
@@ -197,7 +207,7 @@ Transform Registration::computeTransformationMod(
} }
Transform t = computeTransformationImpl(from, to, guess, info); Transform t = computeTransformationImpl(from, to, guess, info);
if(repeatOnce_ && guess.isNull() && !t.isNull()) if(repeatOnce_ && guess.isNull() && !t.isNull() && this->canUseGuess())
{ {
// redo with guess to get a more accurate transform // redo with guess to get a more accurate transform
t = computeTransformationImpl(from, to, t, info); t = computeTransformationImpl(from, to, t, info);
+47 -27
View File
@@ -67,7 +67,8 @@ RegistrationVis::RegistrationVis(const ParametersMap & parameters, Registration
_nndr(Parameters::defaultVisCorNNDR()), _nndr(Parameters::defaultVisCorNNDR()),
_guessWinSize(Parameters::defaultVisCorGuessWinSize()), _guessWinSize(Parameters::defaultVisCorGuessWinSize()),
_guessMatchToProjection(Parameters::defaultVisCorGuessMatchToProjection()), _guessMatchToProjection(Parameters::defaultVisCorGuessMatchToProjection()),
_bundleAdjustment(Parameters::defaultVisBundleAdjustment()) _bundleAdjustment(Parameters::defaultVisBundleAdjustment()),
_depthAsMask(Parameters::defaultVisDepthAsMask())
{ {
_featureParameters = Parameters::getDefaultParameters(); _featureParameters = Parameters::getDefaultParameters();
uInsert(_featureParameters, ParametersPair(Parameters::kKpNNStrategy(), _featureParameters.at(Parameters::kVisCorNNType()))); uInsert(_featureParameters, ParametersPair(Parameters::kKpNNStrategy(), _featureParameters.at(Parameters::kVisCorNNType())));
@@ -110,6 +111,7 @@ void RegistrationVis::parseParameters(const ParametersMap & parameters)
Parameters::parse(parameters, Parameters::kVisCorGuessWinSize(), _guessWinSize); Parameters::parse(parameters, Parameters::kVisCorGuessWinSize(), _guessWinSize);
Parameters::parse(parameters, Parameters::kVisCorGuessMatchToProjection(), _guessMatchToProjection); Parameters::parse(parameters, Parameters::kVisCorGuessMatchToProjection(), _guessMatchToProjection);
Parameters::parse(parameters, Parameters::kVisBundleAdjustment(), _bundleAdjustment); Parameters::parse(parameters, Parameters::kVisBundleAdjustment(), _bundleAdjustment);
Parameters::parse(parameters, Parameters::kVisDepthAsMask(), _depthAsMask);
uInsert(_bundleParameters, parameters); uInsert(_bundleParameters, parameters);
UASSERT_MSG(_minInliers >= 1, uFormat("value=%d", _minInliers).c_str()); UASSERT_MSG(_minInliers >= 1, uFormat("value=%d", _minInliers).c_str());
@@ -229,6 +231,7 @@ Transform RegistrationVis::computeTransformationImpl(
toSignature.sensorData().imageRaw().rows); toSignature.sensorData().imageRaw().rows);
std::string msg; std::string msg;
info.projectedIDs.clear();
//////////////////// ////////////////////
// Find correspondences // Find correspondences
@@ -288,7 +291,7 @@ Transform RegistrationVis::computeTransformationImpl(
} }
cv::Mat depthMask; cv::Mat depthMask;
if(!fromSignature.sensorData().depthRaw().empty()) if(!fromSignature.sensorData().depthRaw().empty() && _depthAsMask)
{ {
if(imageFrom.rows % fromSignature.sensorData().depthRaw().rows == 0 && if(imageFrom.rows % fromSignature.sensorData().depthRaw().rows == 0 &&
imageFrom.cols % fromSignature.sensorData().depthRaw().cols == 0 && imageFrom.cols % fromSignature.sensorData().depthRaw().cols == 0 &&
@@ -496,7 +499,7 @@ Transform RegistrationVis::computeTransformationImpl(
} }
cv::Mat depthMask; cv::Mat depthMask;
if(!toSignature.sensorData().depthRaw().empty()) if(!toSignature.sensorData().depthRaw().empty() && _depthAsMask)
{ {
if(imageTo.rows % toSignature.sensorData().depthRaw().rows == 0 && if(imageTo.rows % toSignature.sensorData().depthRaw().rows == 0 &&
imageTo.cols % toSignature.sensorData().depthRaw().cols == 0 && imageTo.cols % toSignature.sensorData().depthRaw().cols == 0 &&
@@ -604,14 +607,14 @@ Transform RegistrationVis::computeTransformationImpl(
if(fromSignature.getWords3().size() && kptsFrom.size() != fromSignature.getWords3().size()) if(fromSignature.getWords3().size() && kptsFrom.size() != fromSignature.getWords3().size())
{ {
UWARN("kptsFrom (%d) is not the same size as fromSignature.getWords3() (%d), there " UWARN("kptsFrom (%d) is not the same size as fromSignature.getWords3() (%d), there "
"is maybe a problem with the logic above (getWords3() should be null or equal to kptsfrom).", "is maybe a problem with the logic above (getWords3() should be null or equal to kptsfrom). Regenerating kptsFrom3D...",
kptsFrom.size(), kptsFrom.size(),
fromSignature.getWords3().size()); fromSignature.getWords3().size());
} }
else if(fromSignature.sensorData().keypoints3D().size() && kptsFrom.size() != fromSignature.sensorData().keypoints3D().size()) else if(fromSignature.sensorData().keypoints3D().size() && kptsFrom.size() != fromSignature.sensorData().keypoints3D().size())
{ {
UWARN("kptsFrom (%d) is not the same size as fromSignature.sensorData().keypoints3D() (%d), there " UWARN("kptsFrom (%d) is not the same size as fromSignature.sensorData().keypoints3D() (%d), there "
"is maybe a problem with the logic above (keypoints3D() should be null or equal to kptsfrom).", "is maybe a problem with the logic above (keypoints3D should be null or equal to kptsfrom). Regenerating kptsFrom3D...",
kptsFrom.size(), kptsFrom.size(),
fromSignature.sensorData().keypoints3D().size()); fromSignature.sensorData().keypoints3D().size());
} }
@@ -674,14 +677,14 @@ Transform RegistrationVis::computeTransformationImpl(
if(toSignature.getWords3().size() && kptsTo.size() != toSignature.getWords3().size()) if(toSignature.getWords3().size() && kptsTo.size() != toSignature.getWords3().size())
{ {
UWARN("kptsTo (%d) is not the same size as toSignature.getWords3() (%d), there " UWARN("kptsTo (%d) is not the same size as toSignature.getWords3() (%d), there "
"is maybe a problem with the logic above (getWords3() should be null or equal to kptsTo).", "is maybe a problem with the logic above (getWords3() should be null or equal to kptsTo). Regenerating kptsTo3D...",
(int)kptsTo.size(), (int)kptsTo.size(),
(int)toSignature.getWords3().size()); (int)toSignature.getWords3().size());
} }
else if(toSignature.sensorData().keypoints3D().size() && kptsTo.size() != toSignature.sensorData().keypoints3D().size()) else if(toSignature.sensorData().keypoints3D().size() && kptsTo.size() != toSignature.sensorData().keypoints3D().size())
{ {
UWARN("kptsTo (%d) is not the same size as toSignature.sensorData().keypoints3D() (%d), there " UWARN("kptsTo (%d) is not the same size as toSignature.sensorData().keypoints3D() (%d), there "
"is maybe a problem with the logic above (keypoints3D() should be null or equal to kptsTo).", "is maybe a problem with the logic above (keypoints3D() should be null or equal to kptsTo). Regenerating kptsTo3D...",
(int)kptsTo.size(), (int)kptsTo.size(),
(int)toSignature.sensorData().keypoints3D().size()); (int)toSignature.sensorData().keypoints3D().size());
} }
@@ -961,6 +964,12 @@ Transform RegistrationVis::computeTransformationImpl(
for(unsigned int i = 0; i < cornersProjectedMat.rows; ++i) for(unsigned int i = 0; i < cornersProjectedMat.rows; ++i)
{ {
int matchedIndexFrom = projectedIndexToDescIndex[i]; int matchedIndexFrom = projectedIndexToDescIndex[i];
if(indices[i].size())
{
info.projectedIDs.push_back(orignalWordsFromIds.size()?orignalWordsFromIds[matchedIndexFrom]:matchedIndexFrom);
}
if(util3d::isFinite(kptsFrom3D[matchedIndexFrom])) if(util3d::isFinite(kptsFrom3D[matchedIndexFrom]))
{ {
int matchedIndexTo = -1; int matchedIndexTo = -1;
@@ -973,6 +982,7 @@ Transform RegistrationVis::computeTransformationImpl(
{ {
descriptors.resize(indices[i].size()); descriptors.resize(indices[i].size());
} }
std::list<int> indicesToIgnoretmp;
for(unsigned int j=0; j<indices[i].size(); ++j) for(unsigned int j=0; j<indices[i].size(); ++j)
{ {
int octave = kptsTo[indices[i].at(j)].octave; int octave = kptsTo[indices[i].at(j)].octave;
@@ -981,10 +991,7 @@ Transform RegistrationVis::computeTransformationImpl(
descriptorsTo.row(indices[i].at(j)).copyTo(descriptors.row(oi)); descriptorsTo.row(indices[i].at(j)).copyTo(descriptors.row(oi));
descriptorsIndices[oi++] = indices[i].at(j); descriptorsIndices[oi++] = indices[i].at(j);
if(dists[i].at(j) < radius) indicesToIgnoretmp.push_back(indices[i].at(j));
{
indicesToIgnore.insert(indices[i].at(j));
}
} }
} }
bruteForceDescCopy += bruteForceTimer.ticks(); bruteForceDescCopy += bruteForceTimer.ticks();
@@ -999,6 +1006,8 @@ Transform RegistrationVis::computeTransformationImpl(
if(matches[0].at(0).distance < _nndr * matches[0].at(1).distance) if(matches[0].at(0).distance < _nndr * matches[0].at(1).distance)
{ {
matchedIndexTo = descriptorsIndices.at(matches[0].at(0).trainIdx); matchedIndexTo = descriptorsIndices.at(matches[0].at(0).trainIdx);
indicesToIgnore.insert(indicesToIgnore.begin(), indicesToIgnore.end());
} }
} }
else if(oi == 1) else if(oi == 1)
@@ -1186,6 +1195,8 @@ Transform RegistrationVis::computeTransformationImpl(
cv::Mat covariance = cv::Mat::eye(6,6,CV_64FC1); cv::Mat covariance = cv::Mat::eye(6,6,CV_64FC1);
int inliersCount = 0; int inliersCount = 0;
int matchesCount = 0; int matchesCount = 0;
info.inliersIDs.clear();
info.matchesIDs.clear();
if(toSignature.getWords().size()) if(toSignature.getWords().size())
{ {
Transform transforms[2]; Transform transforms[2];
@@ -1565,22 +1576,6 @@ Transform RegistrationVis::computeTransformationImpl(
!optimizedPoses.rbegin()->second.isNull()) !optimizedPoses.rbegin()->second.isNull())
{ {
UDEBUG("Pose optimization: %s -> %s", transforms[0].prettyPrint().c_str(), optimizedPoses.rbegin()->second.prettyPrint().c_str()); UDEBUG("Pose optimization: %s -> %s", transforms[0].prettyPrint().c_str(), optimizedPoses.rbegin()->second.prettyPrint().c_str());
transforms[0] = optimizedPoses.rbegin()->second;
transforms[1].setNull();
// update 3D points, both from and to signatures
/*std::multimap<int, cv::Point3f> cpyWordsFrom3 = fromSignature.getWords3();
std::multimap<int, cv::Point3f> cpyWordsTo3 = toSignature.getWords3();
Transform invT = transforms[0].inverse();
for(std::map<int, cv::Point3f>::iterator iter=points3DMap.begin(); iter!=points3DMap.end(); ++iter)
{
cpyWordsFrom3.find(iter->first)->second = iter->second;
if(cpyWordsTo3.find(iter->first) != cpyWordsTo3.end())
{
cpyWordsTo3.find(iter->first)->second = util3d::transformPoint(iter->second, invT);
}
}
fromSignature.setWords3(cpyWordsFrom3);
toSignature.setWords3(cpyWordsTo3);*/
if(sbaOutliers.size()) if(sbaOutliers.size())
{ {
@@ -1597,6 +1592,31 @@ Transform RegistrationVis::computeTransformationImpl(
UDEBUG("BA outliers ratio %f", float(sbaOutliers.size())/float(allInliers.size())); UDEBUG("BA outliers ratio %f", float(sbaOutliers.size())/float(allInliers.size()));
allInliers = newInliers; allInliers = newInliers;
} }
if((int)allInliers.size() < _minInliers)
{
msg = uFormat("Not enough inliers after bundle adjustment %d/%d (matches=%d) between %d and %d",
(int)allInliers.size(), _minInliers, fromSignature.id(), toSignature.id());
transforms[0].setNull();
}
else
{
transforms[0] = optimizedPoses.rbegin()->second;
}
transforms[1].setNull();
// update 3D points, both from and to signatures
/*std::multimap<int, cv::Point3f> cpyWordsFrom3 = fromSignature.getWords3();
std::multimap<int, cv::Point3f> cpyWordsTo3 = toSignature.getWords3();
Transform invT = transforms[0].inverse();
for(std::map<int, cv::Point3f>::iterator iter=points3DMap.begin(); iter!=points3DMap.end(); ++iter)
{
cpyWordsFrom3.find(iter->first)->second = iter->second;
if(cpyWordsTo3.find(iter->first) != cpyWordsTo3.end())
{
cpyWordsTo3.find(iter->first)->second = util3d::transformPoint(iter->second, invT);
}
}
fromSignature.setWords3(cpyWordsFrom3);
toSignature.setWords3(cpyWordsTo3);*/
} }
} }
+11 -2
View File
@@ -45,6 +45,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <rtabmap/utilite/UTimer.h> #include <rtabmap/utilite/UTimer.h>
#include <rtabmap/utilite/UConversion.h> #include <rtabmap/utilite/UConversion.h>
#include <rtabmap/utilite/UMath.h> #include <rtabmap/utilite/UMath.h>
#include <rtabmap/utilite/UProcessInfo.h>
#include <pcl/search/kdtree.h> #include <pcl/search/kdtree.h>
#include <pcl/filters/crop_box.h> #include <pcl/filters/crop_box.h>
@@ -79,6 +80,7 @@ Rtabmap::Rtabmap() :
_publishLastSignatureData(Parameters::defaultRtabmapPublishLastSignature()), _publishLastSignatureData(Parameters::defaultRtabmapPublishLastSignature()),
_publishPdf(Parameters::defaultRtabmapPublishPdf()), _publishPdf(Parameters::defaultRtabmapPublishPdf()),
_publishLikelihood(Parameters::defaultRtabmapPublishLikelihood()), _publishLikelihood(Parameters::defaultRtabmapPublishLikelihood()),
_publishRAMUsage(Parameters::defaultRtabmapPublishRAMUsage()),
_computeRMSE(Parameters::defaultRtabmapComputeRMSE()), _computeRMSE(Parameters::defaultRtabmapComputeRMSE()),
_maxTimeAllowed(Parameters::defaultRtabmapTimeThr()), // 700 ms _maxTimeAllowed(Parameters::defaultRtabmapTimeThr()), // 700 ms
_maxMemoryAllowed(Parameters::defaultRtabmapMemoryThr()), // 0=inf _maxMemoryAllowed(Parameters::defaultRtabmapMemoryThr()), // 0=inf
@@ -401,6 +403,7 @@ void Rtabmap::parseParameters(const ParametersMap & parameters)
Parameters::parse(parameters, Parameters::kRtabmapPublishLastSignature(), _publishLastSignatureData); Parameters::parse(parameters, Parameters::kRtabmapPublishLastSignature(), _publishLastSignatureData);
Parameters::parse(parameters, Parameters::kRtabmapPublishPdf(), _publishPdf); Parameters::parse(parameters, Parameters::kRtabmapPublishPdf(), _publishPdf);
Parameters::parse(parameters, Parameters::kRtabmapPublishLikelihood(), _publishLikelihood); Parameters::parse(parameters, Parameters::kRtabmapPublishLikelihood(), _publishLikelihood);
Parameters::parse(parameters, Parameters::kRtabmapPublishRAMUsage(), _publishRAMUsage);
Parameters::parse(parameters, Parameters::kRtabmapComputeRMSE(), _computeRMSE); Parameters::parse(parameters, Parameters::kRtabmapComputeRMSE(), _computeRMSE);
Parameters::parse(parameters, Parameters::kRtabmapTimeThr(), _maxTimeAllowed); Parameters::parse(parameters, Parameters::kRtabmapTimeThr(), _maxTimeAllowed);
Parameters::parse(parameters, Parameters::kRtabmapMemoryThr(), _maxMemoryAllowed); Parameters::parse(parameters, Parameters::kRtabmapMemoryThr(), _maxMemoryAllowed);
@@ -1506,6 +1509,7 @@ bool Rtabmap::process(
true, true,
true, true,
false, false,
true,
std::set<int>(), std::set<int>(),
&timeGetNeighborsTimeDb); &timeGetNeighborsTimeDb);
ULOGGER_DEBUG("neighbors of %d in time = %d", retrievalId, (int)neighbors.size()); ULOGGER_DEBUG("neighbors of %d in time = %d", retrievalId, (int)neighbors.size());
@@ -1561,6 +1565,7 @@ bool Rtabmap::process(
true, true,
false, false,
false, false,
false,
std::set<int>(), std::set<int>(),
&timeGetNeighborsSpaceDb); &timeGetNeighborsSpaceDb);
ULOGGER_DEBUG("neighbors of %d in space = %d", retrievalId, (int)neighbors.size()); ULOGGER_DEBUG("neighbors of %d in space = %d", retrievalId, (int)neighbors.size());
@@ -1975,7 +1980,7 @@ bool Rtabmap::process(
nearestId, nearestId,
transform.prettyPrint().c_str()); transform.prettyPrint().c_str());
UASSERT(info.covariance.at<double>(0,0) > 0.0 && info.covariance.at<double>(5,5) > 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.covariance.inv())); _memory->addLink(Link(signature->id(), nearestId, Link::kGlobalClosure, 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)
@@ -2438,6 +2443,10 @@ bool Rtabmap::process(
statistics_.addStatistic(Statistics::kMemorySmall_movement(), smallDisplacement?1.0f:0); statistics_.addStatistic(Statistics::kMemorySmall_movement(), smallDisplacement?1.0f:0);
statistics_.addStatistic(Statistics::kMemoryDistance_travelled(), _distanceTravelled); statistics_.addStatistic(Statistics::kMemoryDistance_travelled(), _distanceTravelled);
statistics_.addStatistic(Statistics::kMemoryFast_movement(), tooFastMovement?1.0f:0); statistics_.addStatistic(Statistics::kMemoryFast_movement(), tooFastMovement?1.0f:0);
if(_publishRAMUsage)
{
statistics_.addStatistic(Statistics::kMemoryRAM_usage(), UProcessInfo::getMemoryUsage()/(1024*1024));
}
if(_publishLikelihood || _publishPdf) if(_publishLikelihood || _publishPdf)
{ {
@@ -3068,7 +3077,7 @@ std::map<int, std::map<int, Transform> > Rtabmap::getPaths(std::map<int, Transfo
std::map<int, Transform> path; std::map<int, Transform> path;
// select nearest pose and iterate neighbors from there // select nearest pose and iterate neighbors from there
int nearestId = rtabmap::graph::findNearestNode(poses, target); int nearestId = rtabmap::graph::findNearestNode(poses, target);
std::map<int, int> ids = _memory->getNeighborsId(nearestId, maxGraphDepth, 0, true, true, true, nodesSet); std::map<int, int> ids = _memory->getNeighborsId(nearestId, maxGraphDepth, 0, true, true, true, true, nodesSet);
for(std::map<int, int>::iterator iter=ids.begin(); iter!=ids.end(); ++iter) for(std::map<int, int>::iterator iter=ids.begin(); iter!=ids.end(); ++iter)
{ {
+4 -3
View File
@@ -151,9 +151,10 @@ std::vector<cv::Point2f> StereoOpticalFlow::computeCorrespondences(
if(countFlowRejected + countDisparityRejected > (int)status.size()/2) if(countFlowRejected + countDisparityRejected > (int)status.size()/2)
{ {
UWARN("A large number (%d/%d) of stereo correspondences are rejected! " UWARN("A large number (%d/%d) of stereo correspondences are rejected! "
"Optical flow may have failed, images are not calibrated, " "Optical flow may have failed because images are not calibrated, "
"the background is too far (no disparity between the images) or " "the background is too far (no disparity between the images), "
"maximum disparity may be too small (%d).", "maximum disparity may be too small (%f) or that exposure between "
"left and right images is too different.",
countFlowRejected+countDisparityRejected, countFlowRejected+countDisparityRejected,
(int)status.size(), (int)status.size(),
this->maxDisparity()); this->maxDisparity());
+5
View File
@@ -92,6 +92,11 @@ Transform::Transform(float x, float y, float theta)
*this = fromEigen3f(t); *this = fromEigen3f(t);
} }
Transform Transform::clone() const
{
return Transform(data_.clone());
}
bool Transform::isNull() const bool Transform::isNull() const
{ {
return (data_.empty() || return (data_.empty() ||
+8 -6
View File
@@ -64,6 +64,7 @@ VWDictionary::VWDictionary(const ParametersMap & parameters) :
_totalActiveReferences(0), _totalActiveReferences(0),
_incrementalDictionary(Parameters::defaultKpIncrementalDictionary()), _incrementalDictionary(Parameters::defaultKpIncrementalDictionary()),
_incrementalFlann(Parameters::defaultKpIncrementalFlann()), _incrementalFlann(Parameters::defaultKpIncrementalFlann()),
_rebalancingFactor(Parameters::defaultKpFlannRebalancingFactor()),
_nndrRatio(Parameters::defaultKpNndrRatio()), _nndrRatio(Parameters::defaultKpNndrRatio()),
_dictionaryPath(Parameters::defaultKpDictionaryPath()), _dictionaryPath(Parameters::defaultKpDictionaryPath()),
_newWordsComparedTogether(Parameters::defaultKpNewWordsComparedTogether()), _newWordsComparedTogether(Parameters::defaultKpNewWordsComparedTogether()),
@@ -88,6 +89,7 @@ void VWDictionary::parseParameters(const ParametersMap & parameters)
Parameters::parse(parameters, Parameters::kKpNndrRatio(), _nndrRatio); Parameters::parse(parameters, Parameters::kKpNndrRatio(), _nndrRatio);
Parameters::parse(parameters, Parameters::kKpNewWordsComparedTogether(), _newWordsComparedTogether); Parameters::parse(parameters, Parameters::kKpNewWordsComparedTogether(), _newWordsComparedTogether);
Parameters::parse(parameters, Parameters::kKpIncrementalFlann(), _incrementalFlann); Parameters::parse(parameters, Parameters::kKpIncrementalFlann(), _incrementalFlann);
Parameters::parse(parameters, Parameters::kKpFlannRebalancingFactor(), _rebalancingFactor);
UASSERT_MSG(_nndrRatio > 0.0f, uFormat("String=%s value=%f", uContains(parameters, Parameters::kKpNndrRatio())?parameters.at(Parameters::kKpNndrRatio()).c_str():"", _nndrRatio).c_str()); UASSERT_MSG(_nndrRatio > 0.0f, uFormat("String=%s value=%f", uContains(parameters, Parameters::kKpNndrRatio())?parameters.at(Parameters::kKpNndrRatio()).c_str():"", _nndrRatio).c_str());
@@ -363,15 +365,15 @@ void VWDictionary::update()
switch(_strategy) switch(_strategy)
{ {
case kNNFlannNaive: case kNNFlannNaive:
_flannIndex->buildLinearIndex(descriptor, useDistanceL1_); _flannIndex->buildLinearIndex(descriptor, useDistanceL1_, _rebalancingFactor);
break; break;
case kNNFlannKdTree: case kNNFlannKdTree:
UASSERT_MSG(descriptor.type() == CV_32F, "To use KdTree dictionary, float descriptors are required!"); UASSERT_MSG(descriptor.type() == CV_32F, "To use KdTree dictionary, float descriptors are required!");
_flannIndex->buildKDTreeIndex(descriptor, KDTREE_SIZE, useDistanceL1_); _flannIndex->buildKDTreeIndex(descriptor, KDTREE_SIZE, useDistanceL1_, _rebalancingFactor);
break; break;
case kNNFlannLSH: case kNNFlannLSH:
UASSERT_MSG(descriptor.type() == CV_8U, "To use LSH dictionary, binary descriptors are required!"); UASSERT_MSG(descriptor.type() == CV_8U, "To use LSH dictionary, binary descriptors are required!");
_flannIndex->buildLSHIndex(descriptor, 12, 20, 2); _flannIndex->buildLSHIndex(descriptor, 12, 20, 2, _rebalancingFactor);
break; break;
default: default:
UFATAL("Not supposed to be here!"); UFATAL("Not supposed to be here!");
@@ -486,15 +488,15 @@ void VWDictionary::update()
switch(_strategy) switch(_strategy)
{ {
case kNNFlannNaive: case kNNFlannNaive:
_flannIndex->buildLinearIndex(_dataTree, useDistanceL1_); _flannIndex->buildLinearIndex(_dataTree, useDistanceL1_, _rebalancingFactor);
break; break;
case kNNFlannKdTree: case kNNFlannKdTree:
UASSERT_MSG(type == CV_32F, "To use KdTree dictionary, float descriptors are required!"); UASSERT_MSG(type == CV_32F, "To use KdTree dictionary, float descriptors are required!");
_flannIndex->buildKDTreeIndex(_dataTree, KDTREE_SIZE, useDistanceL1_); _flannIndex->buildKDTreeIndex(_dataTree, KDTREE_SIZE, useDistanceL1_, _rebalancingFactor);
break; break;
case kNNFlannLSH: case kNNFlannLSH:
UASSERT_MSG(type == CV_8U, "To use LSH dictionary, binary descriptors are required!"); UASSERT_MSG(type == CV_8U, "To use LSH dictionary, binary descriptors are required!");
_flannIndex->buildLSHIndex(_dataTree, 12, 20, 2); _flannIndex->buildLSHIndex(_dataTree, 12, 20, 2, _rebalancingFactor);
break; break;
default: default:
break; break;
+1 -1
View File
@@ -2019,7 +2019,7 @@ cv::Mat exposureFusion(const std::vector<cv::Mat> & images)
fusion.convertTo(rgb8, CV_8UC3, 255.0); fusion.convertTo(rgb8, CV_8UC3, 255.0);
fusion = rgb8; fusion = rgb8;
#else #else
UWARN("Exposure fusion is only avaiable when rtabmap is built with OpenCV3."); UWARN("Exposure fusion is only available when rtabmap is built with OpenCV3.");
if (images.size()) if (images.size())
{ {
fusion = images[0].clone(); fusion = images[0].clone();
+20
View File
@@ -240,6 +240,26 @@ pcl::PointXYZ projectDepthTo3D(
return pt; return pt;
} }
Eigen::Vector3f projectDepthTo3DRay(
const cv::Size & imageSize,
float x, float y,
float cx, float cy,
float fx, float fy)
{
Eigen::Vector3f ray;
// Use correct principal point from calibration
cx = cx > 0.0f ? cx : float(imageSize.width/2) - 0.5f; //cameraInfo.K.at(2)
cy = cy > 0.0f ? cy : float(imageSize.height/2) - 0.5f; //cameraInfo.K.at(5)
// Fill in XYZ
ray[0] = (x - cx) / fx;
ray[1] = (y - cy) / fy;
ray[2] = 1.0f;
return ray;
}
pcl::PointCloud<pcl::PointXYZ>::Ptr cloudFromDepth( pcl::PointCloud<pcl::PointXYZ>::Ptr cloudFromDepth(
const cv::Mat & imageDepth, const cv::Mat & imageDepth,
float cx, float cy, float cx, float cy,
+1 -1
View File
@@ -156,7 +156,7 @@ Transform estimateMotion3DTo2D(
Eigen::Vector4f v1(objPt.x - transform.x(), objPt.y - transform.y(), objPt.z - transform.z(), 0); Eigen::Vector4f v1(objPt.x - transform.x(), objPt.y - transform.y(), objPt.z - transform.z(), 0);
Eigen::Vector4f v2(newPt.x - transform.x(), newPt.y - transform.y(), newPt.z - transform.z(), 0); Eigen::Vector4f v2(newPt.x - transform.x(), newPt.y - transform.y(), newPt.z - transform.z(), 0);
errorSqrdAngles[oi++] = pcl::getAngle3D(v1, v2)*10.0f; errorSqrdAngles[oi++] = pcl::getAngle3D(v1, v2);
} }
} }
+53
View File
@@ -2629,6 +2629,59 @@ pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr mls(
return cloud_with_normals; return cloud_with_normals;
} }
void adjustNormalsToViewPoint(
pcl::PointCloud<pcl::PointNormal>::Ptr & cloud,
const Eigen::Vector3f & viewpoint,
bool forceGroundNormalsUp)
{
for(unsigned int i=0; i<cloud->size(); ++i)
{
pcl::PointXYZ normal(cloud->points[i].normal_x, cloud->points[i].normal_y, cloud->points[i].normal_z);
if(pcl::isFinite(normal))
{
Eigen::Vector3f v = viewpoint - cloud->points[i].getVector3fMap();
Eigen::Vector3f n(normal.x, normal.y, normal.z);
float result = v.dot(n);
if(result < 0
|| (forceGroundNormalsUp && normal.z < -0.8 && cloud->points[i].normal_z < viewpoint[3])) // some far velodyne rays on road can have normals toward ground
{
//UWARN("Reverse %d of n=%f,%f,%f result=%f", i, cloud->points[i].normal_x, cloud->points[i].normal_y, cloud->points[i].normal_z, result);
//reverse normal
cloud->points[i].normal_x *= -1.0f;
cloud->points[i].normal_y *= -1.0f;
cloud->points[i].normal_z *= -1.0f;
}
}
}
}
void adjustNormalsToViewPoint(
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud,
const Eigen::Vector3f & viewpoint,
bool forceGroundNormalsUp)
{
for(unsigned int i=0; i<cloud->size(); ++i)
{
pcl::PointXYZ normal(cloud->points[i].normal_x, cloud->points[i].normal_y, cloud->points[i].normal_z);
if(pcl::isFinite(normal))
{
Eigen::Vector3f v = viewpoint - cloud->points[i].getVector3fMap();
Eigen::Vector3f n(normal.x, normal.y, normal.z);
float result = v.dot(n);
if(result < 0
|| (forceGroundNormalsUp && normal.z < -0.8 && cloud->points[i].normal_z < viewpoint[3])) // some far velodyne rays on road can have normals toward ground
{
//reverse normal
cloud->points[i].normal_x *= -1.0f;
cloud->points[i].normal_y *= -1.0f;
cloud->points[i].normal_z *= -1.0f;
}
}
}
}
void adjustNormalsToViewPoints( void adjustNormalsToViewPoints(
const std::map<int, Transform> & poses, const std::map<int, Transform> & poses,
const pcl::PointCloud<pcl::PointXYZ>::Ptr & rawCloud, const pcl::PointCloud<pcl::PointXYZ>::Ptr & rawCloud,
+2
View File
@@ -1857,6 +1857,8 @@ void CloudViewer::updateCameraTargetPosition(const Transform & pose)
yAxis[0], yAxis[1], yAxis[2],0, yAxis[0], yAxis[1], yAxis[2],0,
zAxis[0], zAxis[1], zAxis[2],0); zAxis[0], zAxis[1], zAxis[2],0);
PR.normalizeRotation();
Transform P(PR[0], PR[1], PR[2], cameras.front().pos[0], Transform P(PR[0], PR[1], PR[2], cameras.front().pos[0],
PR[4], PR[5], PR[6], cameras.front().pos[1], PR[4], PR[5], PR[6], cameras.front().pos[1],
PR[8], PR[9], PR[10], cameras.front().pos[2]); PR[8], PR[9], PR[10], cameras.front().pos[2]);
+11 -6
View File
@@ -141,9 +141,9 @@ void CreateSimpleCalibrationDialog::updateSaveStatus()
(!ui_->checkBox_stereo->isChecked() || !ui_->lineEdit_RT->text().isEmpty())) (!ui_->checkBox_stereo->isChecked() || !ui_->lineEdit_RT->text().isEmpty()))
{ {
//advanced //advanced
QStringList distorsionsStrListL = ui_->lineEdit_D_l->text().remove('[').remove(']').replace(',',' ').replace(';',' ').trimmed().split(' '); QStringList distorsionsStrListL = ui_->lineEdit_D_l->text().remove('[').remove(']').replace(',',' ').replace(';',' ').simplified().trimmed().split(' ');
QStringList distorsionsStrListR = ui_->lineEdit_D_r->text().remove('[').remove(']').replace(',',' ').replace(';',' ').trimmed().split(' '); QStringList distorsionsStrListR = ui_->lineEdit_D_r->text().remove('[').remove(']').replace(',',' ').replace(';',' ').simplified().trimmed().split(' ');
std::string RT = ui_->lineEdit_RT->text().remove('[').remove(']').replace(',',' ').replace(';',' ').trimmed().toStdString(); std::string RT = ui_->lineEdit_RT->text().remove('[').remove(']').replace(',',' ').replace(';',' ').simplified().trimmed().toStdString();
if((distorsionsStrListL.size() == 4 || distorsionsStrListL.size() == 5 || distorsionsStrListL.size() == 8) && if((distorsionsStrListL.size() == 4 || distorsionsStrListL.size() == 5 || distorsionsStrListL.size() == 8) &&
(!ui_->checkBox_stereo->isChecked() || (distorsionsStrListR.size() == 4 || distorsionsStrListR.size() == 5 || distorsionsStrListR.size() == 8)) && (!ui_->checkBox_stereo->isChecked() || (distorsionsStrListR.size() == 4 || distorsionsStrListR.size() == 5 || distorsionsStrListR.size() == 8)) &&
@@ -192,7 +192,7 @@ void CreateSimpleCalibrationDialog::saveCalibration()
cv::Mat P = cv::Mat::zeros(3, 4, CV_64FC1); cv::Mat P = cv::Mat::zeros(3, 4, CV_64FC1);
K.copyTo(cv::Mat(P, cv::Range(0,3), cv::Range(0,3))); K.copyTo(cv::Mat(P, cv::Range(0,3), cv::Range(0,3)));
QStringList distorsionCoeffs = ui_->lineEdit_D_l->text().remove('[').remove(']').replace(',',' ').replace(';',' ').trimmed().split(' '); QStringList distorsionCoeffs = ui_->lineEdit_D_l->text().remove('[').remove(']').replace(',',' ').replace(';',' ').simplified().trimmed().split(' ');
UASSERT(distorsionCoeffs.size() == 4 || distorsionCoeffs.size() == 5 || distorsionCoeffs.size() == 8); UASSERT(distorsionCoeffs.size() == 4 || distorsionCoeffs.size() == 5 || distorsionCoeffs.size() == 8);
cv::Mat D = cv::Mat::zeros(1, distorsionCoeffs.size(), CV_64FC1); cv::Mat D = cv::Mat::zeros(1, distorsionCoeffs.size(), CV_64FC1);
bool ok; bool ok;
@@ -240,7 +240,7 @@ void CreateSimpleCalibrationDialog::saveCalibration()
cv::Mat P = cv::Mat::zeros(3, 4, CV_64FC1); cv::Mat P = cv::Mat::zeros(3, 4, CV_64FC1);
K.copyTo(cv::Mat(P, cv::Range(0,3), cv::Range(0,3))); K.copyTo(cv::Mat(P, cv::Range(0,3), cv::Range(0,3)));
QStringList distorsionCoeffs = ui_->lineEdit_D_r->text().remove('[').remove(']').replace(',',' ').replace(';',' ').trimmed().split(' '); QStringList distorsionCoeffs = ui_->lineEdit_D_r->text().remove('[').remove(']').replace(',',' ').replace(';',' ').simplified().trimmed().split(' ');
UASSERT(distorsionCoeffs.size() == 4 || distorsionCoeffs.size() == 5 || distorsionCoeffs.size() == 8); UASSERT(distorsionCoeffs.size() == 4 || distorsionCoeffs.size() == 5 || distorsionCoeffs.size() == 8);
cv::Mat D = cv::Mat::zeros(1, distorsionCoeffs.size(), CV_64FC1); cv::Mat D = cv::Mat::zeros(1, distorsionCoeffs.size(), CV_64FC1);
bool ok; bool ok;
@@ -257,8 +257,13 @@ void CreateSimpleCalibrationDialog::saveCalibration()
modelRight = CameraModel(name.toStdString(), cv::Size(width,height), K, D, R, P); modelRight = CameraModel(name.toStdString(), cv::Size(width,height), K, D, R, P);
UASSERT(modelRight.isValidForRectification()); UASSERT(modelRight.isValidForRectification());
UASSERT(Transform::canParseString(ui_->lineEdit_RT->text().remove('[').remove(']').replace(',',' ').replace(';',' ').trimmed().toStdString())); UASSERT(Transform::canParseString(ui_->lineEdit_RT->text().remove('[').remove(']').replace(',',' ').replace(';',' ').simplified().trimmed().toStdString()));
stereoModel = StereoCameraModel(name.toStdString(), modelLeft, modelRight, Transform::fromString(ui_->lineEdit_RT->text().remove('[').remove(']').replace(',',' ').replace(';',' ').trimmed().toStdString())); stereoModel = StereoCameraModel(name.toStdString(), modelLeft, modelRight, Transform::fromString(ui_->lineEdit_RT->text().remove('[').remove(']').replace(',',' ').replace(';',' ').trimmed().toStdString()));
if(stereoModel.baseline() < 0)
{
QMessageBox::warning(this, tr("Save"), tr("Error parsing the extrinsics \"%1\", resulting baseline (%f) is negative!").arg(ui_->lineEdit_RT->text()).arg(stereoModel.baseline()));
return;
}
UASSERT(stereoModel.isValidForRectification()); UASSERT(stereoModel.isValidForRectification());
} }
+68 -70
View File
@@ -320,6 +320,7 @@ DatabaseViewer::DatabaseViewer(const QString & ini, QWidget * parent) :
connect(ui_->checkBox_ignoreLocalLoopTime, SIGNAL(stateChanged(int)), this, SLOT(updateGraphView())); connect(ui_->checkBox_ignoreLocalLoopTime, SIGNAL(stateChanged(int)), this, SLOT(updateGraphView()));
connect(ui_->checkBox_ignoreUserLoop, SIGNAL(stateChanged(int)), this, SLOT(updateGraphView())); connect(ui_->checkBox_ignoreUserLoop, SIGNAL(stateChanged(int)), this, SLOT(updateGraphView()));
connect(ui_->spinBox_optimizationDepth, SIGNAL(editingFinished()), this, SLOT(updateGraphView())); connect(ui_->spinBox_optimizationDepth, SIGNAL(editingFinished()), this, SLOT(updateGraphView()));
connect(ui_->doubleSpinBox_optimizationScale, SIGNAL(editingFinished()), this, SLOT(updateGraphView()));
connect(ui_->checkBox_gridErode, SIGNAL(stateChanged(int)), this, SLOT(updateGrid())); connect(ui_->checkBox_gridErode, SIGNAL(stateChanged(int)), this, SLOT(updateGrid()));
connect(ui_->checkBox_octomap, SIGNAL(stateChanged(int)), this, SLOT(updateGrid())); connect(ui_->checkBox_octomap, SIGNAL(stateChanged(int)), this, SLOT(updateGrid()));
connect(ui_->checkBox_grid_2d, SIGNAL(stateChanged(int)), this, SLOT(updateGrid())); connect(ui_->checkBox_grid_2d, SIGNAL(stateChanged(int)), this, SLOT(updateGrid()));
@@ -354,15 +355,7 @@ DatabaseViewer::DatabaseViewer(const QString & ini, QWidget * parent) :
connect(ui_->checkBox_timeStats, SIGNAL(stateChanged(int)), this, SLOT(configModified())); connect(ui_->checkBox_timeStats, SIGNAL(stateChanged(int)), this, SLOT(configModified()));
connect(ui_->checkBox_timeStats, SIGNAL(stateChanged(int)), this, SLOT(updateStatistics())); connect(ui_->checkBox_timeStats, SIGNAL(stateChanged(int)), this, SLOT(updateStatistics()));
// Graph view // Graph view
connect(ui_->checkBox_spanAllMaps, SIGNAL(stateChanged(int)), this, SLOT(configModified()));
connect(ui_->checkBox_ignorePoseCorrection, SIGNAL(stateChanged(int)), this, SLOT(configModified()));
connect(ui_->checkBox_ignoreGlobalLoop, SIGNAL(stateChanged(int)), this, SLOT(configModified()));
connect(ui_->checkBox_ignoreLocalLoopSpace, SIGNAL(stateChanged(int)), this, SLOT(configModified()));
connect(ui_->checkBox_ignoreLocalLoopTime, SIGNAL(stateChanged(int)), this, SLOT(configModified()));
connect(ui_->checkBox_ignoreUserLoop, SIGNAL(stateChanged(int)), this, SLOT(configModified()));
connect(ui_->spinBox_optimizationDepth, SIGNAL(valueChanged(int)), this, SLOT(configModified()));
connect(ui_->checkBox_gridErode, SIGNAL(stateChanged(int)), this, SLOT(configModified())); connect(ui_->checkBox_gridErode, SIGNAL(stateChanged(int)), this, SLOT(configModified()));
connect(ui_->checkBox_octomap, SIGNAL(stateChanged(int)), this, SLOT(configModified()));
connect(ui_->doubleSpinBox_gainCompensationRadius, SIGNAL(valueChanged(double)), this, SLOT(configModified())); connect(ui_->doubleSpinBox_gainCompensationRadius, SIGNAL(valueChanged(double)), this, SLOT(configModified()));
connect(ui_->doubleSpinBox_voxelSize, SIGNAL(valueChanged(double)), this, SLOT(configModified())); connect(ui_->doubleSpinBox_voxelSize, SIGNAL(valueChanged(double)), this, SLOT(configModified()));
connect(ui_->doubleSpinBox_gridCellSize, SIGNAL(valueChanged(double)), this, SLOT(configModified())); connect(ui_->doubleSpinBox_gridCellSize, SIGNAL(valueChanged(double)), this, SLOT(configModified()));
@@ -484,13 +477,6 @@ void DatabaseViewer::readSettings()
ui_->graphViewer->loadSettings(settings, "GraphView"); ui_->graphViewer->loadSettings(settings, "GraphView");
settings.beginGroup("optimization"); settings.beginGroup("optimization");
ui_->checkBox_spanAllMaps->setChecked(settings.value("spanToAllMaps", ui_->checkBox_spanAllMaps->isChecked()).toBool());
ui_->checkBox_ignorePoseCorrection->setChecked(settings.value("ignorePoseCorrection", ui_->checkBox_ignorePoseCorrection->isChecked()).toBool());
ui_->checkBox_ignoreGlobalLoop->setChecked(settings.value("ignoreGlobalLoop", ui_->checkBox_ignoreGlobalLoop->isChecked()).toBool());
ui_->checkBox_ignoreLocalLoopSpace->setChecked(settings.value("ignoreLocalLoopSpace", ui_->checkBox_ignoreLocalLoopSpace->isChecked()).toBool());
ui_->checkBox_ignoreLocalLoopTime->setChecked(settings.value("ignoreLocalLoopTime", ui_->checkBox_ignoreLocalLoopTime->isChecked()).toBool());
ui_->checkBox_ignoreUserLoop->setChecked(settings.value("ignoreUserLoop", ui_->checkBox_ignoreUserLoop->isChecked()).toBool());
ui_->spinBox_optimizationDepth->setValue(settings.value("depth", ui_->spinBox_optimizationDepth->value()).toInt());
ui_->doubleSpinBox_gainCompensationRadius->setValue(settings.value("gainCompensationRadius", ui_->doubleSpinBox_gainCompensationRadius->value()).toDouble()); ui_->doubleSpinBox_gainCompensationRadius->setValue(settings.value("gainCompensationRadius", ui_->doubleSpinBox_gainCompensationRadius->value()).toDouble());
ui_->doubleSpinBox_voxelSize->setValue(settings.value("voxelSize", ui_->doubleSpinBox_voxelSize->value()).toDouble()); ui_->doubleSpinBox_voxelSize->setValue(settings.value("voxelSize", ui_->doubleSpinBox_voxelSize->value()).toDouble());
@@ -502,10 +488,6 @@ void DatabaseViewer::readSettings()
ui_->doubleSpinBox_posefilteringRadius->setValue(settings.value("poseFilteringRadius", ui_->doubleSpinBox_posefilteringRadius->value()).toDouble()); ui_->doubleSpinBox_posefilteringRadius->setValue(settings.value("poseFilteringRadius", ui_->doubleSpinBox_posefilteringRadius->value()).toDouble());
ui_->doubleSpinBox_posefilteringAngle->setValue(settings.value("poseFilteringAngle", ui_->doubleSpinBox_posefilteringAngle->value()).toDouble()); ui_->doubleSpinBox_posefilteringAngle->setValue(settings.value("poseFilteringAngle", ui_->doubleSpinBox_posefilteringAngle->value()).toDouble());
ui_->checkBox_gridErode->setChecked(settings.value("erode", ui_->checkBox_gridErode->isChecked()).toBool()); ui_->checkBox_gridErode->setChecked(settings.value("erode", ui_->checkBox_gridErode->isChecked()).toBool());
if(ui_->checkBox_octomap->isEnabled())
{
ui_->checkBox_octomap->setChecked(settings.value("octomap", ui_->checkBox_octomap->isChecked()).toBool());
}
settings.endGroup(); settings.endGroup();
settings.beginGroup("mesh"); settings.beginGroup("mesh");
@@ -576,17 +558,6 @@ void DatabaseViewer::writeSettings()
// save optimization settings // save optimization settings
settings.beginGroup("optimization"); settings.beginGroup("optimization");
//settings.setValue("iterations", ui_->spinBox_iterations->value());
settings.setValue("spanToAllMaps", ui_->checkBox_spanAllMaps->isChecked());
//settings.setValue("robust", ui_->checkBox_robust->isChecked());
settings.setValue("ignorePoseCorrection", ui_->checkBox_ignorePoseCorrection->isChecked());
settings.setValue("ignoreGlobalLoop", ui_->checkBox_ignoreGlobalLoop->isChecked());
settings.setValue("ignoreLocalLoopSpace", ui_->checkBox_ignoreLocalLoopSpace->isChecked());
settings.setValue("ignoreLocalLoopTime", ui_->checkBox_ignoreLocalLoopTime->isChecked());
settings.setValue("ignoreUserLoop", ui_->checkBox_ignoreUserLoop->isChecked());
//settings.setValue("strategy", ui_->comboBox_graphOptimizer->currentIndex());
//settings.setValue("slam2d", ui_->checkBox_2dslam->isChecked());
settings.setValue("depth", ui_->spinBox_optimizationDepth->value());
settings.setValue("gainCompensationRadius", ui_->doubleSpinBox_gainCompensationRadius->value()); settings.setValue("gainCompensationRadius", ui_->doubleSpinBox_gainCompensationRadius->value());
settings.setValue("voxelSize", ui_->doubleSpinBox_voxelSize->value()); settings.setValue("voxelSize", ui_->doubleSpinBox_voxelSize->value());
settings.endGroup(); settings.endGroup();
@@ -598,7 +569,6 @@ void DatabaseViewer::writeSettings()
settings.setValue("poseFilteringRadius", ui_->doubleSpinBox_posefilteringRadius->value()); settings.setValue("poseFilteringRadius", ui_->doubleSpinBox_posefilteringRadius->value());
settings.setValue("poseFilteringAngle", ui_->doubleSpinBox_posefilteringAngle->value()); settings.setValue("poseFilteringAngle", ui_->doubleSpinBox_posefilteringAngle->value());
settings.setValue("erode", ui_->checkBox_gridErode->isChecked()); settings.setValue("erode", ui_->checkBox_gridErode->isChecked());
settings.setValue("octomap", ui_->checkBox_octomap->isChecked());
settings.endGroup(); settings.endGroup();
settings.beginGroup("mesh"); settings.beginGroup("mesh");
@@ -666,6 +636,7 @@ void DatabaseViewer::restoreDefaultSettings()
ui_->checkBox_ignoreLocalLoopTime->setChecked(false); ui_->checkBox_ignoreLocalLoopTime->setChecked(false);
ui_->checkBox_ignoreUserLoop->setChecked(false); ui_->checkBox_ignoreUserLoop->setChecked(false);
ui_->spinBox_optimizationDepth->setValue(0); ui_->spinBox_optimizationDepth->setValue(0);
ui_->doubleSpinBox_optimizationScale->setValue(1.0);
ui_->doubleSpinBox_gainCompensationRadius->setValue(0.0); ui_->doubleSpinBox_gainCompensationRadius->setValue(0.0);
ui_->doubleSpinBox_voxelSize->setValue(0.0); ui_->doubleSpinBox_voxelSize->setValue(0.0);
@@ -925,6 +896,10 @@ bool DatabaseViewer::closeDatabase()
ui_->toolBox_statistics->clear(); ui_->toolBox_statistics->clear();
databaseFileName_.clear(); databaseFileName_.clear();
ui_->checkBox_alignPosesWithGroundTruth->setVisible(false); ui_->checkBox_alignPosesWithGroundTruth->setVisible(false);
ui_->doubleSpinBox_optimizationScale->setVisible(false);
ui_->label_scale_title->setVisible(false);
ui_->label_rmse->setVisible(false);
ui_->label_rmse_title->setVisible(false);
ui_->checkBox_ignoreIntermediateNodes->setVisible(false); ui_->checkBox_ignoreIntermediateNodes->setVisible(false);
ui_->label_alignPosesWithGroundTruth->setVisible(false); ui_->label_alignPosesWithGroundTruth->setVisible(false);
ui_->label_optimizeFrom->setText(tr("Optimize from")); ui_->label_optimizeFrom->setText(tr("Optimize from"));
@@ -968,6 +943,7 @@ bool DatabaseViewer::closeDatabase()
ui_->label_timeOptimization->clear(); ui_->label_timeOptimization->clear();
ui_->label_pathLength->clear(); ui_->label_pathLength->clear();
ui_->label_poses->clear(); ui_->label_poses->clear();
ui_->label_rmse->clear();
ui_->spinBox_optimizationsFrom->setEnabled(false); ui_->spinBox_optimizationsFrom->setEnabled(false);
ui_->graphicsView_A->clear(); ui_->graphicsView_A->clear();
@@ -1435,6 +1411,10 @@ void DatabaseViewer::updateIds()
gpsPoses_.clear(); gpsPoses_.clear();
gpsValues_.clear(); gpsValues_.clear();
ui_->checkBox_alignPosesWithGroundTruth->setVisible(false); ui_->checkBox_alignPosesWithGroundTruth->setVisible(false);
ui_->doubleSpinBox_optimizationScale->setVisible(false);
ui_->label_scale_title->setVisible(false);
ui_->label_rmse->setVisible(false);
ui_->label_rmse_title->setVisible(false);
ui_->checkBox_ignoreIntermediateNodes->setVisible(false); ui_->checkBox_ignoreIntermediateNodes->setVisible(false);
ui_->label_alignPosesWithGroundTruth->setVisible(false); ui_->label_alignPosesWithGroundTruth->setVisible(false);
ui_->menuExport_GPS->setEnabled(false); ui_->menuExport_GPS->setEnabled(false);
@@ -1569,6 +1549,10 @@ void DatabaseViewer::updateIds()
if(!groundTruthPoses_.empty() || !gpsPoses_.empty()) if(!groundTruthPoses_.empty() || !gpsPoses_.empty())
{ {
ui_->checkBox_alignPosesWithGroundTruth->setVisible(true); ui_->checkBox_alignPosesWithGroundTruth->setVisible(true);
ui_->doubleSpinBox_optimizationScale->setVisible(true);
ui_->label_scale_title->setVisible(true);
ui_->label_rmse->setVisible(true);
ui_->label_rmse_title->setVisible(true);
ui_->label_alignPosesWithGroundTruth->setVisible(true); ui_->label_alignPosesWithGroundTruth->setVisible(true);
if(!groundTruthPoses_.empty()) if(!groundTruthPoses_.empty())
{ {
@@ -1595,6 +1579,7 @@ void DatabaseViewer::updateIds()
UINFO("Update database info..."); UINFO("Update database info...");
ui_->textEdit_info->clear(); ui_->textEdit_info->clear();
ui_->textEdit_info->append(tr("Path:\t\t%1").arg(dbDriver_->getUrl().c_str()));
ui_->textEdit_info->append(tr("Version:\t\t%1").arg(dbDriver_->getDatabaseVersion().c_str())); ui_->textEdit_info->append(tr("Version:\t\t%1").arg(dbDriver_->getDatabaseVersion().c_str()));
ui_->textEdit_info->append(tr("Sessions:\t\t%1").arg(sessions)); ui_->textEdit_info->append(tr("Sessions:\t\t%1").arg(sessions));
if(hasReducedGraph) if(hasReducedGraph)
@@ -1720,7 +1705,7 @@ void DatabaseViewer::updateIds()
{ {
neighborLinks_.append(iter->second); neighborLinks_.append(iter->second);
} }
else else if(iter->second.type()!=rtabmap::Link::kPosePrior)
{ {
loopLinks_.append(iter->second); loopLinks_.append(iter->second);
} }
@@ -1784,6 +1769,7 @@ void DatabaseViewer::updateStatistics()
std::map<int, std::pair<std::map<std::string, float>, double> > allStats = dbDriver_->getAllStatistics(); std::map<int, std::pair<std::map<std::string, float>, double> > allStats = dbDriver_->getAllStatistics();
std::map<std::string, std::pair<std::vector<float>, std::vector<float> > > allData; std::map<std::string, std::pair<std::vector<float>, std::vector<float> > > allData;
std::map<std::string, int > allDataOi;
for(int i=0; i<ids_.size(); ++i) for(int i=0; i<ids_.size(); ++i)
{ {
@@ -1804,15 +1790,21 @@ void DatabaseViewer::updateStatistics()
{ {
//initialize data vectors //initialize data vectors
allData.insert(std::make_pair(iter->first, std::make_pair(std::vector<float>(ids_.size(), 0.0f), std::vector<float>(ids_.size(), 0.0f) ))); allData.insert(std::make_pair(iter->first, std::make_pair(std::vector<float>(ids_.size(), 0.0f), std::vector<float>(ids_.size(), 0.0f) )));
allDataOi.insert(std::make_pair(iter->first, 0));
} }
allData.at(iter->first).first[i] = ui_->checkBox_timeStats->isChecked()?float(stamp-firstStamp):ids_[i]; int & oi = allDataOi.at(iter->first);
allData.at(iter->first).second[i] = iter->second; allData.at(iter->first).first[oi] = ui_->checkBox_timeStats->isChecked()?float(stamp-firstStamp):ids_[i];
allData.at(iter->first).second[oi] = iter->second;
++oi;
} }
} }
for(std::map<std::string, std::pair<std::vector<float>, std::vector<float> > >::iterator iter=allData.begin(); iter!=allData.end(); ++iter) for(std::map<std::string, std::pair<std::vector<float>, std::vector<float> > >::iterator iter=allData.begin(); iter!=allData.end(); ++iter)
{ {
int oi = allDataOi.at(iter->first);
iter->second.first.resize(oi);
iter->second.second.resize(oi);
ui_->toolBox_statistics->updateStat(iter->first.c_str(), iter->second.first, iter->second.second, true); ui_->toolBox_statistics->updateStat(iter->first.c_str(), iter->second.first, iter->second.second, true);
} }
} }
@@ -3420,16 +3412,7 @@ void DatabaseViewer::updateStereo(const SensorData * data)
UTimer timer; UTimer timer;
ParametersMap parameters = ui_->parameters_toolbox->getParameters(); ParametersMap parameters = ui_->parameters_toolbox->getParameters();
bool opticalFlow = uStr2Bool(parameters.at(Parameters::kStereoOpticalFlow())); Stereo * stereo = Stereo::create(parameters);
Stereo * stereo = 0;
if(opticalFlow)
{
stereo = new StereoOpticalFlow(parameters);
}
else
{
stereo = new Stereo(parameters);
}
// generate kpts // generate kpts
std::vector<cv::KeyPoint> kpts; std::vector<cv::KeyPoint> kpts;
@@ -3576,7 +3559,7 @@ void DatabaseViewer::updateStereo(const SensorData * data)
rightKpts[i].pt.x, rightKpts[i].pt.x,
rightKpts[i].pt.y, rightKpts[i].pt.y,
c, c,
QString("%1: (%2,%3) -> (%4,%5)").arg(i).arg(kpts[i].pt.x).arg(kpts[i].pt.y).arg(rightKpts[i].pt.x).arg(rightKpts[i].pt.y)); QString("%1: (%2,%3) -> (%4,%5) d=%6").arg(i).arg(kpts[i].pt.x).arg(kpts[i].pt.y).arg(rightKpts[i].pt.x).arg(rightKpts[i].pt.y).arg(kpts[i].pt.x - rightKpts[i].pt.x));
} }
} }
ui_->graphicsView_stereo->update(); ui_->graphicsView_stereo->update();
@@ -4329,6 +4312,7 @@ void DatabaseViewer::sliderIterationsValueChanged(int value)
rotational_max); rotational_max);
// ground truth live statistics // ground truth live statistics
ui_->label_rmse->setNum(translational_rmse);
UINFO("translational_rmse=%f", translational_rmse); UINFO("translational_rmse=%f", translational_rmse);
UINFO("translational_mean=%f", translational_mean); UINFO("translational_mean=%f", translational_mean);
UINFO("translational_median=%f", translational_median); UINFO("translational_median=%f", translational_median);
@@ -4611,6 +4595,7 @@ void DatabaseViewer::updateGraphView()
{ {
ui_->label_loopClosures->clear(); ui_->label_loopClosures->clear();
ui_->label_poses->clear(); ui_->label_poses->clear();
ui_->label_rmse->clear();
if(odomPoses_.size()) if(odomPoses_.size())
{ {
@@ -4649,6 +4634,7 @@ void DatabaseViewer::updateGraphView()
ui_->menuExport_poses->setEnabled(true); ui_->menuExport_poses->setEnabled(true);
std::multimap<int, rtabmap::Link> links = links_; std::multimap<int, rtabmap::Link> links = links_;
loopLinks_.clear();
// filter current map if not spanning to all maps // filter current map if not spanning to all maps
if(!ui_->checkBox_spanAllMaps->isChecked() && uContains(mapIds_, fromId) && mapIds_.at(fromId) >= 0) if(!ui_->checkBox_spanAllMaps->isChecked() && uContains(mapIds_, fromId) && mapIds_.at(fromId) >= 0)
@@ -4718,6 +4704,7 @@ void DatabaseViewer::updateGraphView()
links.erase(iter++); links.erase(iter++);
continue; continue;
} }
loopLinks_.push_back(iter->second);
++totalGlobal; ++totalGlobal;
} }
else if(iter->second.type() == Link::kLocalSpaceClosure) else if(iter->second.type() == Link::kLocalSpaceClosure)
@@ -4727,6 +4714,7 @@ void DatabaseViewer::updateGraphView()
links.erase(iter++); links.erase(iter++);
continue; continue;
} }
loopLinks_.push_back(iter->second);
++totalLocalSpace; ++totalLocalSpace;
} }
else if(iter->second.type() == Link::kLocalTimeClosure) else if(iter->second.type() == Link::kLocalTimeClosure)
@@ -4736,6 +4724,7 @@ void DatabaseViewer::updateGraphView()
links.erase(iter++); links.erase(iter++);
continue; continue;
} }
loopLinks_.push_back(iter->second);
++totalLocalTime; ++totalLocalTime;
} }
else if(iter->second.type() == Link::kUserClosure) else if(iter->second.type() == Link::kUserClosure)
@@ -4745,14 +4734,37 @@ void DatabaseViewer::updateGraphView()
links.erase(iter++); links.erase(iter++);
continue; continue;
} }
loopLinks_.push_back(iter->second);
++totalUser; ++totalUser;
} }
else if(iter->second.type() == Link::kPosePrior) else if(iter->second.type() == Link::kPosePrior)
{ {
++totalPriors; ++totalPriors;
} }
else
{
loopLinks_.push_back(iter->second);
}
Transform t = iter->second.transform().clone();
t.x() *= ui_->doubleSpinBox_optimizationScale->value();
t.y() *= ui_->doubleSpinBox_optimizationScale->value();
t.z() *= ui_->doubleSpinBox_optimizationScale->value();
iter->second.setTransform(t);
++iter; ++iter;
} }
ui_->horizontalSlider_loops->blockSignals(true);
if(loopLinks_.size() == 0)
{
ui_->horizontalSlider_loops->setEnabled(false);
}
else
{
ui_->horizontalSlider_loops->setEnabled(true);
ui_->horizontalSlider_loops->setMaximum(loopLinks_.size()-1);
}
ui_->horizontalSlider_loops->setValue(0);
ui_->horizontalSlider_loops->blockSignals(false);
ui_->label_loopClosures->setText(tr("(%1, %2, %3, %4, %5, %6, %7)") ui_->label_loopClosures->setText(tr("(%1, %2, %3, %4, %5, %6, %7)")
.arg(totalNeighbor) .arg(totalNeighbor)
.arg(totalNeighborMerged) .arg(totalNeighborMerged)
@@ -5447,9 +5459,7 @@ bool DatabaseViewer::addConstraint(int from, int to, bool silent)
std::multimap<int, Link> linksIn = updateLinksWithModifications(links_); std::multimap<int, Link> linksIn = updateLinksWithModifications(links_);
linksIn.insert(std::make_pair(newLink.from(), newLink)); linksIn.insert(std::make_pair(newLink.from(), newLink));
const Link * maxLinearLink = 0; const Link * maxLinearLink = 0;
const Link * maxAngularLink = 0; float maxLinearErrorRatio = 0.0f;
float maxLinearError = 0.0f;
float maxAngularError = 0.0f;
Optimizer * optimizer = Optimizer::create(ui_->parameters_toolbox->getParameters()); Optimizer * optimizer = Optimizer::create(ui_->parameters_toolbox->getParameters());
std::map<int, Transform> poses; std::map<int, Transform> poses;
std::multimap<int, Link> links; std::multimap<int, Link> links;
@@ -5480,43 +5490,31 @@ bool DatabaseViewer::addConstraint(int from, int to, bool silent)
fabs(iter->second.transform().x() - t.x()), fabs(iter->second.transform().x() - t.x()),
fabs(iter->second.transform().y() - t.y()), fabs(iter->second.transform().y() - t.y()),
fabs(iter->second.transform().z() - t.z())); fabs(iter->second.transform().z() - t.z()));
Eigen::Vector3f vA = t1.toEigen3f().linear()*Eigen::Vector3f(1,0,0); float stddev = sqrt(iter->second.transVariance());
Eigen::Vector3f vB = t2.toEigen3f().linear()*Eigen::Vector3f(1,0,0); float linearErrorRatio = linearError/stddev;
float angularError = pcl::getAngle3D(Eigen::Vector4f(vA[0], vA[1], vA[2], 0), Eigen::Vector4f(vB[0], vB[1], vB[2], 0)); if(linearErrorRatio > maxLinearErrorRatio)
if(linearError > maxLinearError)
{ {
maxLinearError = linearError; maxLinearErrorRatio = linearErrorRatio;
maxLinearLink = &iter->second; maxLinearLink = &iter->second;
} }
if(angularError > maxAngularError)
{
maxAngularError = angularError;
maxAngularLink = &iter->second;
}
} }
} }
if(maxLinearLink) if(maxLinearLink)
{ {
UINFO("Max optimization linear error = %f m (link %d->%d)", maxLinearError, maxLinearLink->from(), maxLinearLink->to()); UINFO("Max optimization linear error ratio = %f (link %d->%d)", maxLinearErrorRatio, maxLinearLink->from(), maxLinearLink->to());
}
if(maxAngularLink)
{
UINFO("Max optimization angular error = %f deg (link %d->%d)", maxAngularError*180.0f/M_PI, maxAngularLink->from(), maxAngularLink->to());
} }
if(maxLinearError > maxOptimizationError) if(maxLinearErrorRatio > maxOptimizationError)
{ {
msg = uFormat("Rejecting edge %d->%d because " msg = uFormat("Rejecting edge %d->%d because "
"graph error is too large after optimization (%f m for edge %d->%d, %f deg for edge %d->%d). " "graph error is too large after optimization (ratio %f for edge %d->%d, stddev=%f). "
"\"%s\" is %f m.", "\"%s\" is %f.",
newLink.from(), newLink.from(),
newLink.to(), newLink.to(),
maxLinearError, maxLinearErrorRatio,
maxLinearLink->from(), maxLinearLink->from(),
maxLinearLink->to(), maxLinearLink->to(),
maxAngularError*180.0f/M_PI, sqrt(maxLinearLink->transVariance()),
maxAngularLink?maxAngularLink->from():0,
maxAngularLink?maxAngularLink->to():0,
Parameters::kRGBDOptimizeMaxError().c_str(), Parameters::kRGBDOptimizeMaxError().c_str(),
maxOptimizationError); maxOptimizationError);
} }
+35
View File
@@ -932,6 +932,7 @@ void MainWindow::processCameraInfo(const rtabmap::CameraInfo & info)
_ui->statsToolBox->updateStat("Camera/Time decimation/ms", _preferencesDialog->isTimeUsedInFigures()?info.stamp-_firstStamp:(float)info.id, info.timeImageDecimation*1000.0f, _preferencesDialog->isCacheSavedInFigures()); _ui->statsToolBox->updateStat("Camera/Time decimation/ms", _preferencesDialog->isTimeUsedInFigures()?info.stamp-_firstStamp:(float)info.id, info.timeImageDecimation*1000.0f, _preferencesDialog->isCacheSavedInFigures());
_ui->statsToolBox->updateStat("Camera/Time disparity/ms", _preferencesDialog->isTimeUsedInFigures()?info.stamp-_firstStamp:(float)info.id, info.timeDisparity*1000.0f, _preferencesDialog->isCacheSavedInFigures()); _ui->statsToolBox->updateStat("Camera/Time disparity/ms", _preferencesDialog->isTimeUsedInFigures()?info.stamp-_firstStamp:(float)info.id, info.timeDisparity*1000.0f, _preferencesDialog->isCacheSavedInFigures());
_ui->statsToolBox->updateStat("Camera/Time mirroring/ms", _preferencesDialog->isTimeUsedInFigures()?info.stamp-_firstStamp:(float)info.id, info.timeMirroring*1000.0f, _preferencesDialog->isCacheSavedInFigures()); _ui->statsToolBox->updateStat("Camera/Time mirroring/ms", _preferencesDialog->isTimeUsedInFigures()?info.stamp-_firstStamp:(float)info.id, info.timeMirroring*1000.0f, _preferencesDialog->isCacheSavedInFigures());
_ui->statsToolBox->updateStat("Camera/Time exposure compensation/ms", _preferencesDialog->isTimeUsedInFigures()?info.stamp-_firstStamp:(float)info.id, info.timeStereoExposureCompensation*1000.0f, _preferencesDialog->isCacheSavedInFigures());
_ui->statsToolBox->updateStat("Camera/Time scan from depth/ms", _preferencesDialog->isTimeUsedInFigures()?info.stamp-_firstStamp:(float)info.id, info.timeScanFromDepth*1000.0f, _preferencesDialog->isCacheSavedInFigures()); _ui->statsToolBox->updateStat("Camera/Time scan from depth/ms", _preferencesDialog->isTimeUsedInFigures()?info.stamp-_firstStamp:(float)info.id, info.timeScanFromDepth*1000.0f, _preferencesDialog->isCacheSavedInFigures());
emit(cameraInfoProcessed()); emit(cameraInfoProcessed());
@@ -2105,6 +2106,32 @@ void MainWindow::updateMapCloud(
_ui->actionAnchor_clouds_to_ground_truth->setChecked(false); _ui->actionAnchor_clouds_to_ground_truth->setChecked(false);
} }
int maxNodes = uStr2Int(_preferencesDialog->getParameter(Parameters::kGridGlobalMaxNodes()));
if(maxNodes > 0 && poses.size()>1)
{
std::vector<int> nodes = graph::findNearestNodes(poses, poses.rbegin()->second, maxNodes);
std::map<int, Transform> nearestPoses;
nearestPoses.insert(*poses.rbegin());
for(std::vector<int>::iterator iter=nodes.begin(); iter!=nodes.end(); ++iter)
{
std::map<int, Transform>::iterator pter = poses.find(*iter);
if(pter != poses.end())
{
nearestPoses.insert(*pter);
}
}
//add negative...
for(std::map<int, Transform>::iterator iter=poses.begin(); iter!=poses.end(); ++iter)
{
if(iter->first > 0)
{
break;
}
nearestPoses.insert(*iter);
}
poses=nearestPoses;
}
// Map updated! regenerate the assembled cloud, last pose is the new one // Map updated! regenerate the assembled cloud, last pose is the new one
UDEBUG("Update map with %d locations", poses.size()); UDEBUG("Update map with %d locations", poses.size());
QMap<std::string, Transform> viewerClouds = _cloudViewer->getAddedClouds(); QMap<std::string, Transform> viewerClouds = _cloudViewer->getAddedClouds();
@@ -4650,6 +4677,14 @@ void MainWindow::startDetection()
{ {
uInsert(odomParameters, ParametersPair(Parameters::kRegStrategy(), uNumber2Str(_preferencesDialog->getOdomRegistrationApproach()))); uInsert(odomParameters, ParametersPair(Parameters::kRegStrategy(), uNumber2Str(_preferencesDialog->getOdomRegistrationApproach())));
} }
odomParameters.erase(Parameters::kRtabmapPublishRAMUsage()); // as odometry is in the same process than rtabmap, don't get RAM usage in odometry.
int odomStrategy = Parameters::defaultOdomStrategy();
Parameters::parse(odomParameters, Parameters::kOdomStrategy(), odomStrategy);
if(odomStrategy == 1)
{
// Only Frame To Frame supports all VisCorType
odomParameters.insert(ParametersPair(Parameters::kVisCorType(), _preferencesDialog->getParameter(Parameters::kVisCorType())));
}
Odometry * odom = Odometry::create(odomParameters); Odometry * odom = Odometry::create(odomParameters);
_odomThread = new OdometryThread(odom, _preferencesDialog->getOdomBufferSize()); _odomThread = new OdometryThread(odom, _preferencesDialog->getOdomBufferSize());
+36 -22
View File
@@ -451,7 +451,6 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
connect(_ui->groupBox_octomap, SIGNAL(toggled(bool)), this, SLOT(makeObsoleteCloudRenderingPanel())); connect(_ui->groupBox_octomap, SIGNAL(toggled(bool)), this, SLOT(makeObsoleteCloudRenderingPanel()));
connect(_ui->spinBox_octomap_treeDepth, SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteCloudRenderingPanel())); connect(_ui->spinBox_octomap_treeDepth, SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteCloudRenderingPanel()));
connect(_ui->checkBox_octomap_fullUpdate, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteCloudRenderingPanel()));
connect(_ui->checkBox_octomap_2dgrid, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteCloudRenderingPanel())); connect(_ui->checkBox_octomap_2dgrid, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteCloudRenderingPanel()));
connect(_ui->checkBox_octomap_show3dMap, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteCloudRenderingPanel())); connect(_ui->checkBox_octomap_show3dMap, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteCloudRenderingPanel()));
connect(_ui->checkBox_octomap_cubeRendering, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteCloudRenderingPanel())); connect(_ui->checkBox_octomap_cubeRendering, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteCloudRenderingPanel()));
@@ -612,6 +611,8 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
connect(_ui->doubleSpinBox_cameraImages_scanVoxelSize, SIGNAL(valueChanged(double)), this, SLOT(makeObsoleteSourcePanel())); connect(_ui->doubleSpinBox_cameraImages_scanVoxelSize, SIGNAL(valueChanged(double)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->spinBox_cameraImages_scanNormalsK, SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteSourcePanel())); connect(_ui->spinBox_cameraImages_scanNormalsK, SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->doubleSpinBox_cameraImages_scanNormalsRadius, SIGNAL(valueChanged(double)), this, SLOT(makeObsoleteSourcePanel())); connect(_ui->doubleSpinBox_cameraImages_scanNormalsRadius, SIGNAL(valueChanged(double)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->checkBox_cameraImages_scanForceGroundNormalsUp, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
//Rtabmap basic //Rtabmap basic
connect(_ui->general_doubleSpinBox_timeThr, SIGNAL(valueChanged(double)), _ui->general_doubleSpinBox_timeThr_2, SLOT(setValue(double))); connect(_ui->general_doubleSpinBox_timeThr, SIGNAL(valueChanged(double)), _ui->general_doubleSpinBox_timeThr_2, SLOT(setValue(double)));
@@ -641,6 +642,7 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
_ui->general_checkBox_publishPdf->setObjectName(Parameters::kRtabmapPublishPdf().c_str()); _ui->general_checkBox_publishPdf->setObjectName(Parameters::kRtabmapPublishPdf().c_str());
_ui->general_checkBox_publishLikelihood->setObjectName(Parameters::kRtabmapPublishLikelihood().c_str()); _ui->general_checkBox_publishLikelihood->setObjectName(Parameters::kRtabmapPublishLikelihood().c_str());
_ui->general_checkBox_publishRMSE->setObjectName(Parameters::kRtabmapComputeRMSE().c_str()); _ui->general_checkBox_publishRMSE->setObjectName(Parameters::kRtabmapComputeRMSE().c_str());
_ui->general_checkBox_publishRAM->setObjectName(Parameters::kRtabmapPublishRAMUsage().c_str());
_ui->general_checkBox_statisticLogsBufferedInRAM->setObjectName(Parameters::kRtabmapStatisticLogsBufferedInRAM().c_str()); _ui->general_checkBox_statisticLogsBufferedInRAM->setObjectName(Parameters::kRtabmapStatisticLogsBufferedInRAM().c_str());
_ui->groupBox_statistics->setObjectName(Parameters::kRtabmapStatisticLogged().c_str()); _ui->groupBox_statistics->setObjectName(Parameters::kRtabmapStatisticLogged().c_str());
_ui->general_checkBox_statisticLoggedHeaders->setObjectName(Parameters::kRtabmapStatisticLoggedHeaders().c_str()); _ui->general_checkBox_statisticLoggedHeaders->setObjectName(Parameters::kRtabmapStatisticLoggedHeaders().c_str());
@@ -703,10 +705,12 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
_ui->comboBox_dictionary_strategy->setObjectName(Parameters::kKpNNStrategy().c_str()); _ui->comboBox_dictionary_strategy->setObjectName(Parameters::kKpNNStrategy().c_str());
_ui->checkBox_dictionary_incremental->setObjectName(Parameters::kKpIncrementalDictionary().c_str()); _ui->checkBox_dictionary_incremental->setObjectName(Parameters::kKpIncrementalDictionary().c_str());
_ui->checkBox_kp_incrementalFlann->setObjectName(Parameters::kKpIncrementalFlann().c_str()); _ui->checkBox_kp_incrementalFlann->setObjectName(Parameters::kKpIncrementalFlann().c_str());
_ui->surf_doubleSpinBox_rebalancingFactor->setObjectName(Parameters::kKpFlannRebalancingFactor().c_str());
_ui->comboBox_detector_strategy->setObjectName(Parameters::kKpDetectorStrategy().c_str()); _ui->comboBox_detector_strategy->setObjectName(Parameters::kKpDetectorStrategy().c_str());
_ui->surf_doubleSpinBox_nndrRatio->setObjectName(Parameters::kKpNndrRatio().c_str()); _ui->surf_doubleSpinBox_nndrRatio->setObjectName(Parameters::kKpNndrRatio().c_str());
_ui->surf_doubleSpinBox_maxDepth->setObjectName(Parameters::kKpMaxDepth().c_str()); _ui->surf_doubleSpinBox_maxDepth->setObjectName(Parameters::kKpMaxDepth().c_str());
_ui->surf_doubleSpinBox_minDepth->setObjectName(Parameters::kKpMinDepth().c_str()); _ui->surf_doubleSpinBox_minDepth->setObjectName(Parameters::kKpMinDepth().c_str());
_ui->checkBox_memDepthAsMask->setObjectName(Parameters::kMemDepthAsMask().c_str());
_ui->surf_spinBox_wordsPerImageTarget->setObjectName(Parameters::kKpMaxFeatures().c_str()); _ui->surf_spinBox_wordsPerImageTarget->setObjectName(Parameters::kKpMaxFeatures().c_str());
_ui->spinBox_KPGridRows->setObjectName(Parameters::kKpGridRows().c_str()); _ui->spinBox_KPGridRows->setObjectName(Parameters::kKpGridRows().c_str());
_ui->spinBox_KPGridCols->setObjectName(Parameters::kKpGridCols().c_str()); _ui->spinBox_KPGridCols->setObjectName(Parameters::kKpGridCols().c_str());
@@ -861,9 +865,6 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
_ui->loopClosure_pnpReprojError->setObjectName(Parameters::kVisPnPReprojError().c_str()); _ui->loopClosure_pnpReprojError->setObjectName(Parameters::kVisPnPReprojError().c_str());
_ui->loopClosure_pnpFlags->setObjectName(Parameters::kVisPnPFlags().c_str()); _ui->loopClosure_pnpFlags->setObjectName(Parameters::kVisPnPFlags().c_str());
_ui->loopClosure_pnpRefineIterations->setObjectName(Parameters::kVisPnPRefineIterations().c_str()); _ui->loopClosure_pnpRefineIterations->setObjectName(Parameters::kVisPnPRefineIterations().c_str());
_ui->loopClosure_correspondencesType->setObjectName(Parameters::kVisCorType().c_str());
connect(_ui->loopClosure_correspondencesType, SIGNAL(currentIndexChanged(int)), _ui->stackedWidget_loopClosureCorrespondences, SLOT(setCurrentIndex(int)));
_ui->stackedWidget_loopClosureCorrespondences->setCurrentIndex(Parameters::defaultVisCorType());
_ui->reextract_nn->setObjectName(Parameters::kVisCorNNType().c_str()); _ui->reextract_nn->setObjectName(Parameters::kVisCorNNType().c_str());
_ui->reextract_nndrRatio->setObjectName(Parameters::kVisCorNNDR().c_str()); _ui->reextract_nndrRatio->setObjectName(Parameters::kVisCorNNDR().c_str());
_ui->spinBox_visCorGuessWinSize->setObjectName(Parameters::kVisCorGuessWinSize().c_str()); _ui->spinBox_visCorGuessWinSize->setObjectName(Parameters::kVisCorGuessWinSize().c_str());
@@ -874,6 +875,7 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
_ui->reextract_gridcols->setObjectName(Parameters::kVisGridCols().c_str()); _ui->reextract_gridcols->setObjectName(Parameters::kVisGridCols().c_str());
_ui->loopClosure_bowMaxDepth->setObjectName(Parameters::kVisMaxDepth().c_str()); _ui->loopClosure_bowMaxDepth->setObjectName(Parameters::kVisMaxDepth().c_str());
_ui->loopClosure_bowMinDepth->setObjectName(Parameters::kVisMinDepth().c_str()); _ui->loopClosure_bowMinDepth->setObjectName(Parameters::kVisMinDepth().c_str());
_ui->checkBox_visDepthAsMask->setObjectName(Parameters::kVisDepthAsMask().c_str());
_ui->loopClosure_roi->setObjectName(Parameters::kVisRoiRatios().c_str()); _ui->loopClosure_roi->setObjectName(Parameters::kVisRoiRatios().c_str());
_ui->subpix_winSize->setObjectName(Parameters::kVisSubPixWinSize().c_str()); _ui->subpix_winSize->setObjectName(Parameters::kVisSubPixWinSize().c_str());
_ui->subpix_iterations->setObjectName(Parameters::kVisSubPixIterations().c_str()); _ui->subpix_iterations->setObjectName(Parameters::kVisSubPixIterations().c_str());
@@ -937,6 +939,7 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
_ui->checkBox_grid_fullUpdate->setObjectName(Parameters::kGridGlobalFullUpdate().c_str()); _ui->checkBox_grid_fullUpdate->setObjectName(Parameters::kGridGlobalFullUpdate().c_str());
_ui->doubleSpinBox_grid_minMapSize->setObjectName(Parameters::kGridGlobalMinSize().c_str()); _ui->doubleSpinBox_grid_minMapSize->setObjectName(Parameters::kGridGlobalMinSize().c_str());
_ui->spinBox_grid_maxNodes->setObjectName(Parameters::kGridGlobalMaxNodes().c_str());
_ui->doubleSpinBox_grid_footprintRadius->setObjectName(Parameters::kGridGlobalFootprintRadius().c_str()); _ui->doubleSpinBox_grid_footprintRadius->setObjectName(Parameters::kGridGlobalFootprintRadius().c_str());
_ui->checkBox_grid_erode->setObjectName(Parameters::kGridGlobalEroded().c_str()); _ui->checkBox_grid_erode->setObjectName(Parameters::kGridGlobalEroded().c_str());
@@ -965,6 +968,9 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
_ui->odom_f2m_bundleStrategy->setObjectName(Parameters::kOdomF2MBundleAdjustment().c_str()); _ui->odom_f2m_bundleStrategy->setObjectName(Parameters::kOdomF2MBundleAdjustment().c_str());
_ui->odom_f2m_bundleMaxFrames->setObjectName(Parameters::kOdomF2MBundleAdjustmentMaxFrames().c_str()); _ui->odom_f2m_bundleMaxFrames->setObjectName(Parameters::kOdomF2MBundleAdjustmentMaxFrames().c_str());
//Odometry Frame To Frame
_ui->comboBox_odomf2f_corType->setObjectName(Parameters::kVisCorType().c_str());
//Odometry Mono //Odometry Mono
_ui->doubleSpinBox_minFlow->setObjectName(Parameters::kOdomMonoInitMinFlow().c_str()); _ui->doubleSpinBox_minFlow->setObjectName(Parameters::kOdomMonoInitMinFlow().c_str());
_ui->doubleSpinBox_minInitTranslation->setObjectName(Parameters::kOdomMonoInitMinTranslation().c_str()); _ui->doubleSpinBox_minInitTranslation->setObjectName(Parameters::kOdomMonoInitMinTranslation().c_str());
@@ -1041,6 +1047,7 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
_ui->doubleSpinBox_OdomORBSLAM2ThDepth->setObjectName(Parameters::kOdomORBSLAM2ThDepth().c_str()); _ui->doubleSpinBox_OdomORBSLAM2ThDepth->setObjectName(Parameters::kOdomORBSLAM2ThDepth().c_str());
_ui->doubleSpinBox_OdomORBSLAM2Fps->setObjectName(Parameters::kOdomORBSLAM2Fps().c_str()); _ui->doubleSpinBox_OdomORBSLAM2Fps->setObjectName(Parameters::kOdomORBSLAM2Fps().c_str());
_ui->spinBox_OdomORBSLAM2MaxFeatures->setObjectName(Parameters::kOdomORBSLAM2MaxFeatures().c_str()); _ui->spinBox_OdomORBSLAM2MaxFeatures->setObjectName(Parameters::kOdomORBSLAM2MaxFeatures().c_str());
_ui->spinBox_OdomORBSLAM2MapSize->setObjectName(Parameters::kOdomORBSLAM2MapSize().c_str());
//Stereo //Stereo
_ui->stereo_winWidth->setObjectName(Parameters::kStereoWinWidth().c_str()); _ui->stereo_winWidth->setObjectName(Parameters::kStereoWinWidth().c_str());
@@ -1457,7 +1464,6 @@ void PreferencesDialog::resetSettings(QGroupBox * groupBox)
_ui->groupBox_octomap->setChecked(false); _ui->groupBox_octomap->setChecked(false);
_ui->spinBox_octomap_treeDepth->setValue(16); _ui->spinBox_octomap_treeDepth->setValue(16);
_ui->checkBox_octomap_fullUpdate->setChecked(false);
_ui->checkBox_octomap_2dgrid->setChecked(true); _ui->checkBox_octomap_2dgrid->setChecked(true);
_ui->checkBox_octomap_show3dMap->setChecked(true); _ui->checkBox_octomap_show3dMap->setChecked(true);
_ui->checkBox_octomap_cubeRendering->setChecked(false); _ui->checkBox_octomap_cubeRendering->setChecked(false);
@@ -1595,6 +1601,7 @@ void PreferencesDialog::resetSettings(QGroupBox * groupBox)
_ui->doubleSpinBox_cameraImages_scanVoxelSize->setValue(0.025f); _ui->doubleSpinBox_cameraImages_scanVoxelSize->setValue(0.025f);
_ui->spinBox_cameraImages_scanNormalsK->setValue(20); _ui->spinBox_cameraImages_scanNormalsK->setValue(20);
_ui->doubleSpinBox_cameraImages_scanNormalsRadius->setValue(0.0); _ui->doubleSpinBox_cameraImages_scanNormalsRadius->setValue(0.0);
_ui->checkBox_cameraImages_scanForceGroundNormalsUp->setChecked(false);
_ui->groupBox_depthFromScan->setChecked(false); _ui->groupBox_depthFromScan->setChecked(false);
_ui->groupBox_depthFromScan_fillHoles->setChecked(true); _ui->groupBox_depthFromScan_fillHoles->setChecked(true);
@@ -1845,7 +1852,6 @@ void PreferencesDialog::readGuiSettings(const QString & filePath)
_ui->groupBox_octomap->setChecked(settings.value("octomap", _ui->groupBox_octomap->isChecked()).toBool()); _ui->groupBox_octomap->setChecked(settings.value("octomap", _ui->groupBox_octomap->isChecked()).toBool());
_ui->spinBox_octomap_treeDepth->setValue(settings.value("octomap_depth", _ui->spinBox_octomap_treeDepth->value()).toInt()); _ui->spinBox_octomap_treeDepth->setValue(settings.value("octomap_depth", _ui->spinBox_octomap_treeDepth->value()).toInt());
_ui->checkBox_octomap_fullUpdate->setChecked(settings.value("octomap_full_update", _ui->checkBox_octomap_fullUpdate->isChecked()).toBool());
_ui->checkBox_octomap_2dgrid->setChecked(settings.value("octomap_2dgrid", _ui->checkBox_octomap_2dgrid->isChecked()).toBool()); _ui->checkBox_octomap_2dgrid->setChecked(settings.value("octomap_2dgrid", _ui->checkBox_octomap_2dgrid->isChecked()).toBool());
_ui->checkBox_octomap_show3dMap->setChecked(settings.value("octomap_3dmap", _ui->checkBox_octomap_show3dMap->isChecked()).toBool()); _ui->checkBox_octomap_show3dMap->setChecked(settings.value("octomap_3dmap", _ui->checkBox_octomap_show3dMap->isChecked()).toBool());
_ui->checkBox_octomap_cubeRendering->setChecked(settings.value("octomap_cube", _ui->checkBox_octomap_cubeRendering->isChecked()).toBool()); _ui->checkBox_octomap_cubeRendering->setChecked(settings.value("octomap_cube", _ui->checkBox_octomap_cubeRendering->isChecked()).toBool());
@@ -1997,6 +2003,8 @@ void PreferencesDialog::readCameraSettings(const QString & filePath)
_ui->doubleSpinBox_cameraImages_scanVoxelSize->setValue(settings.value("voxelSize", _ui->doubleSpinBox_cameraImages_scanVoxelSize->value()).toDouble()); _ui->doubleSpinBox_cameraImages_scanVoxelSize->setValue(settings.value("voxelSize", _ui->doubleSpinBox_cameraImages_scanVoxelSize->value()).toDouble());
_ui->spinBox_cameraImages_scanNormalsK->setValue(settings.value("normalsK", _ui->spinBox_cameraImages_scanNormalsK->value()).toInt()); _ui->spinBox_cameraImages_scanNormalsK->setValue(settings.value("normalsK", _ui->spinBox_cameraImages_scanNormalsK->value()).toInt());
_ui->doubleSpinBox_cameraImages_scanNormalsRadius->setValue(settings.value("normalsRadius", _ui->doubleSpinBox_cameraImages_scanNormalsRadius->value()).toDouble()); _ui->doubleSpinBox_cameraImages_scanNormalsRadius->setValue(settings.value("normalsRadius", _ui->doubleSpinBox_cameraImages_scanNormalsRadius->value()).toDouble());
_ui->checkBox_cameraImages_scanForceGroundNormalsUp->setChecked(settings.value("normalsUp", _ui->checkBox_cameraImages_scanForceGroundNormalsUp->isChecked()).toBool());
settings.endGroup();//ScanFromDepth settings.endGroup();//ScanFromDepth
settings.beginGroup("DepthFromScan"); settings.beginGroup("DepthFromScan");
@@ -2247,7 +2255,6 @@ void PreferencesDialog::writeGuiSettings(const QString & filePath) const
settings.setValue("octomap", _ui->groupBox_octomap->isChecked()); settings.setValue("octomap", _ui->groupBox_octomap->isChecked());
settings.setValue("octomap_depth", _ui->spinBox_octomap_treeDepth->value()); settings.setValue("octomap_depth", _ui->spinBox_octomap_treeDepth->value());
settings.setValue("octomap_full_update", _ui->checkBox_octomap_fullUpdate->isChecked());
settings.setValue("octomap_2dgrid", _ui->checkBox_octomap_2dgrid->isChecked()); settings.setValue("octomap_2dgrid", _ui->checkBox_octomap_2dgrid->isChecked());
settings.setValue("octomap_3dmap", _ui->checkBox_octomap_show3dMap->isChecked()); settings.setValue("octomap_3dmap", _ui->checkBox_octomap_show3dMap->isChecked());
settings.setValue("octomap_cube", _ui->checkBox_octomap_cubeRendering->isChecked()); settings.setValue("octomap_cube", _ui->checkBox_octomap_cubeRendering->isChecked());
@@ -2401,6 +2408,7 @@ void PreferencesDialog::writeCameraSettings(const QString & filePath) const
settings.setValue("voxelSize", _ui->doubleSpinBox_cameraImages_scanVoxelSize->value()); settings.setValue("voxelSize", _ui->doubleSpinBox_cameraImages_scanVoxelSize->value());
settings.setValue("normalsK", _ui->spinBox_cameraImages_scanNormalsK->value()); settings.setValue("normalsK", _ui->spinBox_cameraImages_scanNormalsK->value());
settings.setValue("normalsRadius", _ui->doubleSpinBox_cameraImages_scanNormalsRadius->value()); settings.setValue("normalsRadius", _ui->doubleSpinBox_cameraImages_scanNormalsRadius->value());
settings.setValue("normalsUp", _ui->checkBox_cameraImages_scanForceGroundNormalsUp->isChecked());
settings.endGroup(); settings.endGroup();
settings.beginGroup("DepthFromScan"); settings.beginGroup("DepthFromScan");
@@ -2584,15 +2592,6 @@ bool PreferencesDialog::validateForm()
"with cvsba. Bundle adjustment is disabled.")); "with cvsba. Bundle adjustment is disabled."));
_ui->odom_f2m_bundleStrategy->setCurrentIndex(0); _ui->odom_f2m_bundleStrategy->setCurrentIndex(0);
} }
if(_ui->odom_strategy->currentIndex() == 0 && // F2M
_ui->odom_f2m_bundleStrategy->currentIndex() > 0 &&
_ui->loopClosure_correspondencesType->currentIndex() == 1)
{
QMessageBox::warning(this, tr("Parameter warning"),
tr("Odometry local bundle adjustment optimization cannot be used at the same time than Optical Flow correspondences "
"strategy (see Visual Registration panel). Bundle adjustment is disabled."));
_ui->odom_f2m_bundleStrategy->setCurrentIndex(0);
}
// verify that Robust and Reject threshold are not set at the same time // verify that Robust and Reject threshold are not set at the same time
if(_ui->graphOptimization_robust->isChecked() && _ui->graphOptimization_maxError->value()>0.0) if(_ui->graphOptimization_robust->isChecked() && _ui->graphOptimization_maxError->value()>0.0)
@@ -3066,6 +3065,9 @@ rtabmap::ParametersMap PreferencesDialog::getAllParameters() const
ParametersMap parameters = _parameters; ParametersMap parameters = _parameters;
uInsert(parameters, _modifiedParameters); uInsert(parameters, _modifiedParameters);
// It will be added manually for odometry
parameters.erase(Parameters::kVisCorType());
return parameters; return parameters;
} }
@@ -3328,7 +3330,7 @@ void PreferencesDialog::selectSourceImagesPathOdom()
{ {
dir = getWorkingDirectory(); dir = getWorkingDirectory();
} }
QString path = QFileDialog::getOpenFileName(this, tr("Select file"), dir, tr("Odometry (*.txt *.log *.toro *.g2o)")); QString path = QFileDialog::getOpenFileName(this, tr("Select file"), dir, tr("Odometry (*.txt *.log *.toro *.g2o *.csv)"));
if(path.size()) if(path.size())
{ {
QStringList list; QStringList list;
@@ -3352,7 +3354,7 @@ void PreferencesDialog::selectSourceImagesPathGt()
{ {
dir = getWorkingDirectory(); dir = getWorkingDirectory();
} }
QString path = QFileDialog::getOpenFileName(this, tr("Select file"), dir, tr("Ground Truth (*.txt *.log *.toro *.g2o)")); QString path = QFileDialog::getOpenFileName(this, tr("Select file"), dir, tr("Ground Truth (*.txt *.log *.toro *.g2o *.csv)"));
if(path.size()) if(path.size())
{ {
QStringList list; QStringList list;
@@ -4334,7 +4336,7 @@ int PreferencesDialog::getOctomapTreeDepth() const
} }
bool PreferencesDialog::isOctomapFullUpdate() const bool PreferencesDialog::isOctomapFullUpdate() const
{ {
return _ui->checkBox_octomap_fullUpdate->isChecked(); return uStr2Bool(this->getParameter(Parameters::kGridGlobalFullUpdate()));
} }
double PreferencesDialog::getOctomapOccupancyThr() const double PreferencesDialog::getOctomapOccupancyThr() const
{ {
@@ -4851,7 +4853,8 @@ Camera * PreferencesDialog::createCamera(bool useRawImages, bool useColor)
_ui->doubleSpinBox_cameraImages_scanVoxelSize->value(), _ui->doubleSpinBox_cameraImages_scanVoxelSize->value(),
_ui->spinBox_cameraImages_scanNormalsK->value(), _ui->spinBox_cameraImages_scanNormalsK->value(),
_ui->doubleSpinBox_cameraImages_scanNormalsRadius->value(), _ui->doubleSpinBox_cameraImages_scanNormalsRadius->value(),
this->getLaserLocalTransform()); this->getLaserLocalTransform(),
_ui->checkBox_cameraImages_scanForceGroundNormalsUp->isChecked());
((CameraRGBDImages*)camera)->setTimestamps( ((CameraRGBDImages*)camera)->setTimestamps(
_ui->checkBox_cameraImages_timestamps->isChecked(), _ui->checkBox_cameraImages_timestamps->isChecked(),
_ui->lineEdit_cameraImages_timestamps->text().toStdString(), _ui->lineEdit_cameraImages_timestamps->text().toStdString(),
@@ -4899,7 +4902,8 @@ Camera * PreferencesDialog::createCamera(bool useRawImages, bool useColor)
_ui->doubleSpinBox_cameraImages_scanVoxelSize->value(), _ui->doubleSpinBox_cameraImages_scanVoxelSize->value(),
_ui->spinBox_cameraImages_scanNormalsK->value(), _ui->spinBox_cameraImages_scanNormalsK->value(),
_ui->doubleSpinBox_cameraImages_scanNormalsRadius->value(), _ui->doubleSpinBox_cameraImages_scanNormalsRadius->value(),
this->getLaserLocalTransform()); this->getLaserLocalTransform(),
_ui->checkBox_cameraImages_scanForceGroundNormalsUp->isChecked());
((CameraStereoImages*)camera)->setTimestamps( ((CameraStereoImages*)camera)->setTimestamps(
_ui->checkBox_cameraImages_timestamps->isChecked(), _ui->checkBox_cameraImages_timestamps->isChecked(),
_ui->lineEdit_cameraImages_timestamps->text().toStdString(), _ui->lineEdit_cameraImages_timestamps->text().toStdString(),
@@ -5005,7 +5009,8 @@ Camera * PreferencesDialog::createCamera(bool useRawImages, bool useColor)
_ui->doubleSpinBox_cameraImages_scanVoxelSize->value(), _ui->doubleSpinBox_cameraImages_scanVoxelSize->value(),
_ui->spinBox_cameraImages_scanNormalsK->value(), _ui->spinBox_cameraImages_scanNormalsK->value(),
_ui->doubleSpinBox_cameraImages_scanNormalsRadius->value(), _ui->doubleSpinBox_cameraImages_scanNormalsRadius->value(),
this->getLaserLocalTransform()); this->getLaserLocalTransform(),
_ui->checkBox_cameraImages_scanForceGroundNormalsUp->isChecked());
((CameraImages*)camera)->setDepthFromScan( ((CameraImages*)camera)->setDepthFromScan(
_ui->groupBox_depthFromScan->isChecked(), _ui->groupBox_depthFromScan->isChecked(),
!_ui->groupBox_depthFromScan_fillHoles->isChecked()?0:_ui->radioButton_depthFromScan_vertical->isChecked()?1:-1, !_ui->groupBox_depthFromScan_fillHoles->isChecked()?0:_ui->radioButton_depthFromScan_vertical->isChecked()?1:-1,
@@ -5220,6 +5225,15 @@ void PreferencesDialog::testOdometry()
{ {
uInsert(parameters, ParametersPair(Parameters::kRegStrategy(), uNumber2Str(getOdomRegistrationApproach()))); uInsert(parameters, ParametersPair(Parameters::kRegStrategy(), uNumber2Str(getOdomRegistrationApproach())));
} }
int odomStrategy = Parameters::defaultOdomStrategy();
Parameters::parse(parameters, Parameters::kOdomStrategy(), odomStrategy);
if(odomStrategy == 1)
{
// Only Frame To Frame supports all VisCorType
parameters.insert(ParametersPair(Parameters::kVisCorType(), this->getParameter(Parameters::kVisCorType())));
}
Odometry * odometry = Odometry::create(parameters); Odometry * odometry = Odometry::create(parameters);
OdometryThread odomThread( OdometryThread odomThread(
+108 -65
View File
@@ -61,7 +61,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>407</width> <width>395</width>
<height>242</height> <height>242</height>
</rect> </rect>
</property> </property>
@@ -253,7 +253,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>406</width> <width>394</width>
<height>242</height> <height>242</height>
</rect> </rect>
</property> </property>
@@ -921,7 +921,7 @@
</item> </item>
<item> <item>
<layout class="QGridLayout" name="gridLayout_5" columnstretch="0,1"> <layout class="QGridLayout" name="gridLayout_5" columnstretch="0,1">
<item row="7" column="0"> <item row="8" column="0">
<widget class="QLabel" name="label_loopClosures"> <widget class="QLabel" name="label_loopClosures">
<property name="text"> <property name="text">
<string/> <string/>
@@ -954,7 +954,7 @@
<item row="0" column="0"> <item row="0" column="0">
<widget class="QSpinBox" name="spinBox_optimizationsFrom"/> <widget class="QSpinBox" name="spinBox_optimizationsFrom"/>
</item> </item>
<item row="6" column="1"> <item row="7" column="1">
<widget class="QLabel" name="label_52"> <widget class="QLabel" name="label_52">
<property name="text"> <property name="text">
<string>Poses</string> <string>Poses</string>
@@ -968,7 +968,7 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="7" column="1"> <item row="8" column="1">
<widget class="QLabel" name="label_41"> <widget class="QLabel" name="label_41">
<property name="text"> <property name="text">
<string>Links (N, NM, G, LS, LT, U, P)</string> <string>Links (N, NM, G, LS, LT, U, P)</string>
@@ -1020,7 +1020,7 @@
</item> </item>
</layout> </layout>
</item> </item>
<item row="6" column="0"> <item row="7" column="0">
<widget class="QLabel" name="label_poses"> <widget class="QLabel" name="label_poses">
<property name="text"> <property name="text">
<string/> <string/>
@@ -1050,6 +1050,16 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="0">
<widget class="QCheckBox" name="checkBox_ignoreIntermediateNodes">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="2" column="1"> <item row="2" column="1">
<widget class="QLabel" name="label_alignPosesWithGroundTruth_2"> <widget class="QLabel" name="label_alignPosesWithGroundTruth_2">
<property name="text"> <property name="text">
@@ -1060,13 +1070,20 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="0"> <item row="6" column="1">
<widget class="QCheckBox" name="checkBox_ignoreIntermediateNodes"> <widget class="QLabel" name="label_rmse_title">
<property name="text">
<string>RMSE (m)</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_rmse">
<property name="text"> <property name="text">
<string/> <string/>
</property> </property>
<property name="checked"> <property name="textInteractionFlags">
<bool>false</bool> <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property> </property>
</widget> </widget>
</item> </item>
@@ -1146,22 +1163,36 @@
<item> <item>
<widget class="QToolBox" name="toolBox"> <widget class="QToolBox" name="toolBox">
<property name="currentIndex"> <property name="currentIndex">
<number>1</number> <number>0</number>
</property> </property>
<widget class="QWidget" name="page_3"> <widget class="QWidget" name="page_3">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>340</width> <width>318</width>
<height>228</height> <height>219</height>
</rect> </rect>
</property> </property>
<attribute name="label"> <attribute name="label">
<string>Graph optimization</string> <string>Graph optimization</string>
</attribute> </attribute>
<layout class="QGridLayout" name="gridLayout_7" columnstretch="0,0,0"> <layout class="QGridLayout" name="gridLayout_7" columnstretch="0,0,1">
<item row="3" column="0"> <item row="0" column="2">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Depth (0=inf)</string>
</property>
</widget>
</item>
<item row="5" column="2">
<widget class="QLabel" name="label_49">
<property name="text">
<string>Ignore local loop closures (time)</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="checkBox_ignoreLocalLoopSpace"> <widget class="QCheckBox" name="checkBox_ignoreLocalLoopSpace">
<property name="text"> <property name="text">
<string/> <string/>
@@ -1171,37 +1202,21 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="2"> <item row="3" column="2">
<widget class="QLabel" name="label_48"> <widget class="QLabel" name="label_48">
<property name="text"> <property name="text">
<string>Ignore global loop closures</string> <string>Ignore global loop closures</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="1"> <item row="2" column="2">
<widget class="QSpinBox" name="spinBox_optimizationDepth">
<property name="suffix">
<string/>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>1000</number>
</property>
<property name="value">
<number>0</number>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLabel" name="label_35"> <widget class="QLabel" name="label_35">
<property name="text"> <property name="text">
<string>Ignore pose correction</string> <string>Ignore pose correction</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="0"> <item row="2" column="0">
<widget class="QCheckBox" name="checkBox_ignorePoseCorrection"> <widget class="QCheckBox" name="checkBox_ignorePoseCorrection">
<property name="text"> <property name="text">
<string/> <string/>
@@ -1211,7 +1226,7 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="0"> <item row="5" column="0">
<widget class="QCheckBox" name="checkBox_ignoreLocalLoopTime"> <widget class="QCheckBox" name="checkBox_ignoreLocalLoopTime">
<property name="text"> <property name="text">
<string/> <string/>
@@ -1221,7 +1236,7 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="6" column="0"> <item row="7" column="0">
<spacer name="verticalSpacer_3"> <spacer name="verticalSpacer_3">
<property name="orientation"> <property name="orientation">
<enum>Qt::Vertical</enum> <enum>Qt::Vertical</enum>
@@ -1234,28 +1249,7 @@
</property> </property>
</spacer> </spacer>
</item> </item>
<item row="0" column="2"> <item row="6" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Depth (0=inf)</string>
</property>
</widget>
</item>
<item row="5" column="2">
<widget class="QLabel" name="label_50">
<property name="text">
<string>Ignore user loop closures</string>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QLabel" name="label_47">
<property name="text">
<string>Ignore local loop closures (space)</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QCheckBox" name="checkBox_ignoreUserLoop"> <widget class="QCheckBox" name="checkBox_ignoreUserLoop">
<property name="text"> <property name="text">
<string/> <string/>
@@ -1265,7 +1259,14 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="0"> <item row="6" column="2">
<widget class="QLabel" name="label_50">
<property name="text">
<string>Ignore user loop closures</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="checkBox_ignoreGlobalLoop"> <widget class="QCheckBox" name="checkBox_ignoreGlobalLoop">
<property name="text"> <property name="text">
<string/> <string/>
@@ -1276,9 +1277,51 @@
</widget> </widget>
</item> </item>
<item row="4" column="2"> <item row="4" column="2">
<widget class="QLabel" name="label_49"> <widget class="QLabel" name="label_47">
<property name="text"> <property name="text">
<string>Ignore local loop closures (time)</string> <string>Ignore local loop closures (space)</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLabel" name="label_scale_title">
<property name="text">
<string>Scale</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_optimizationScale">
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>0.100000000000000</double>
</property>
<property name="maximum">
<double>9.900000000000000</double>
</property>
<property name="singleStep">
<double>0.001000000000000</double>
</property>
<property name="value">
<double>1.000000000000000</double>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QSpinBox" name="spinBox_optimizationDepth">
<property name="suffix">
<string/>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>1000</number>
</property>
<property name="value">
<number>0</number>
</property> </property>
</widget> </widget>
</item> </item>
@@ -1709,8 +1752,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>298</width> <width>205</width>
<height>228</height> <height>117</height>
</rect> </rect>
</property> </property>
<attribute name="label"> <attribute name="label">
@@ -1809,8 +1852,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>446</width> <width>185</width>
<height>228</height> <height>487</height>
</rect> </rect>
</property> </property>
<attribute name="label"> <attribute name="label">
File diff suppressed because it is too large Load Diff
+25 -3
View File
@@ -823,13 +823,13 @@ void UPlotCurve::draw(QPainter * painter, const QRect & limits)
} }
} }
if(limits.contains(item->pos().toPoint()) && limits.contains((item->pos() + QPointF(item->rect().width(), item->rect().height())).toPoint())) /*if(limits.contains(item->pos().toPoint()) && limits.contains((item->pos() + QPointF(item->rect().width(), item->rect().height())).toPoint()))
{ {
painter->save(); painter->save();
painter->setPen(QPen(_itemsColor)); painter->setPen(QPen(_itemsColor));
painter->drawEllipse(item->pos()+QPointF(item->rect().width()/2, item->rect().height()/2), (int)item->rect().width()/2, (int)item->rect().height()/2); painter->drawEllipse(item->pos()+QPointF(item->rect().width()/2, item->rect().height()/2), (int)item->rect().width()/2, (int)item->rect().height()/2);
painter->restore(); painter->restore();
} }*/
} }
} }
} }
@@ -1833,7 +1833,7 @@ UPlot::UPlot(QWidget *parent) :
_lowestRefreshRate = 99; _lowestRefreshRate = 99;
_refreshStartTime.start(); _refreshStartTime.start();
_penStyleCount = rand() % 10 + 1; // rand 1->10 _penStyleCount = 0;
_workingDirectory = QDir::homePath(); _workingDirectory = QDir::homePath();
} }
@@ -2081,6 +2081,28 @@ bool UPlot::contains(const QString & curveName)
QPen UPlot::getRandomPenColored() QPen UPlot::getRandomPenColored()
{ {
int penStyle = 0;
bool colorNotUsed = false;
for(int i=0; i<12; ++i)
{
QColor tmp((Qt::GlobalColor)((penStyle+i) % 12 + 7 ));
bool colorAlreadyUsed = false;
for(QList<UPlotCurve*>::const_iterator iter = _curves.constBegin(); iter!=_curves.constEnd() && !colorAlreadyUsed; ++iter)
{
colorAlreadyUsed = (*iter)->pen().color() == tmp;
}
if(!colorAlreadyUsed)
{
colorNotUsed = true;
penStyle+=i;
break;
}
}
if(colorNotUsed)
{
_penStyleCount = penStyle;
}
return QPen((Qt::GlobalColor)(_penStyleCount++ % 12 + 7 )); return QPen((Qt::GlobalColor)(_penStyleCount++ % 12 + 7 ));
} }
+1 -1
View File
@@ -1,7 +1,7 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<package> <package>
<name>rtabmap</name> <name>rtabmap</name>
<version>0.14.2</version> <version>0.15.4</version>
<description>RTAB-Map's standalone library. RTAB-Map is a RGB-D SLAM approach with real-time constraints.</description> <description>RTAB-Map's standalone library. RTAB-Map is a RGB-D SLAM approach with real-time constraints.</description>
<maintainer email="[email protected]">Mathieu Labbe</maintainer> <maintainer email="[email protected]">Mathieu Labbe</maintainer>
<author>Mathieu Labbe</author> <author>Mathieu Labbe</author>
+3 -1
View File
@@ -7,8 +7,9 @@ ADD_SUBDIRECTORY( CameraRGBD )
ADD_SUBDIRECTORY( StereoEval ) ADD_SUBDIRECTORY( StereoEval )
ADD_SUBDIRECTORY( KittiDataset ) ADD_SUBDIRECTORY( KittiDataset )
ADD_SUBDIRECTORY( RgbdDataset ) ADD_SUBDIRECTORY( RgbdDataset )
ADD_SUBDIRECTORY( EurocDataset )
ADD_SUBDIRECTORY( Recovery ) ADD_SUBDIRECTORY( Recovery )
ADD_SUBDIRECTORY( Report ) ADD_SUBDIRECTORY( Reprocess )
IF(OPENCV_NONFREE_FOUND) IF(OPENCV_NONFREE_FOUND)
ADD_SUBDIRECTORY( VocabularyComparison ) ADD_SUBDIRECTORY( VocabularyComparison )
@@ -20,6 +21,7 @@ IF(TARGET rtabmap_gui)
ADD_SUBDIRECTORY( OdometryViewer ) ADD_SUBDIRECTORY( OdometryViewer )
ADD_SUBDIRECTORY( DataRecorder ) ADD_SUBDIRECTORY( DataRecorder )
ADD_SUBDIRECTORY( Calibration ) ADD_SUBDIRECTORY( Calibration )
ADD_SUBDIRECTORY( Report )
ELSE() ELSE()
MESSAGE(STATUS "RTAB-Map GUI lib is not built, some tools won't be built...") MESSAGE(STATUS "RTAB-Map GUI lib is not built, some tools won't be built...")
ENDIF() ENDIF()
+48
View File
@@ -0,0 +1,48 @@
cmake_minimum_required(VERSION 2.8)
FIND_PACKAGE(yaml-cpp REQUIRED)
IF(yaml-cpp_FOUND)
# inside rtabmap project (see below for external build)
SET(RTABMap_INCLUDE_DIRS
${PROJECT_SOURCE_DIR}/utilite/include
${PROJECT_SOURCE_DIR}/corelib/include
)
SET(RTABMap_LIBRARIES
rtabmap_core
rtabmap_utilite
)
if(POLICY CMP0020)
cmake_policy(SET CMP0020 OLD)
endif()
SET(INCLUDE_DIRS
${RTABMap_INCLUDE_DIRS}
${OpenCV_INCLUDE_DIRS}
${PCL_INCLUDE_DIRS}
)
SET(LIBRARIES
${RTABMap_LIBRARIES}
${OpenCV_LIBRARIES}
${PCL_LIBRARIES}
${YAML_CPP_LIBRARIES}
)
INCLUDE_DIRECTORIES(${INCLUDE_DIRS})
ADD_EXECUTABLE(euroc_dataset main.cpp)
TARGET_LINK_LIBRARIES(euroc_dataset ${LIBRARIES})
SET_TARGET_PROPERTIES( euroc_dataset
PROPERTIES OUTPUT_NAME ${PROJECT_PREFIX}-euroc_dataset)
INSTALL(TARGETS euroc_dataset
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT runtime
BUNDLE DESTINATION "${CMAKE_BUNDLE_LOCATION}" COMPONENT runtime)
ELSE()
MESSAGE(STATUS "yaml-cpp not found, euroc_dataset tool won't be built...")
ENDIF()
+538
View File
@@ -0,0 +1,538 @@
/*
Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Universite de Sherbrooke nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <rtabmap/core/OdometryF2M.h>
#include "rtabmap/core/Rtabmap.h"
#include "rtabmap/core/CameraStereo.h"
#include "rtabmap/core/CameraThread.h"
#include "rtabmap/core/Graph.h"
#include "rtabmap/core/OdometryInfo.h"
#include "rtabmap/core/OdometryEvent.h"
#include "rtabmap/core/Memory.h"
#include "rtabmap/core/util3d_registration.h"
#include "rtabmap/utilite/UConversion.h"
#include "rtabmap/utilite/UDirectory.h"
#include "rtabmap/utilite/UFile.h"
#include "rtabmap/utilite/UMath.h"
#include "rtabmap/utilite/UStl.h"
#include "rtabmap/utilite/UProcessInfo.h"
#include <pcl/common/common.h>
#include <yaml-cpp/yaml.h>
#include <stdio.h>
#include <signal.h>
using namespace rtabmap;
void showUsage()
{
printf("\nUsage:\n"
"rtabmap-kitti_dataset [options] path\n"
" path Folder of the sequence (e.g., \"~/EuRoC/V1_03_difficult\")\n"
" containing least mav0/cam0/sensor.yaml, mav0/cam1/sensor.yaml, mav0/cam0/data and mav0/cam1/data folders.\n"
" Optional image_2, image_3 and velodyne folders.\n"
" --output Output directory. By default, results are saved in \"path\".\n"
" --output_name Output database name (default \"rtabmap\").\n"
" --quiet Don't show log messages and iteration updates.\n"
" --exposure_comp Do exposure compensation between left and right images.\n"
" --disp Generate full disparity.\n"
"%s\n"
"Example:\n\n"
" $ rtabmap-euroc_dataset --Rtabmap/DetectionRate 4 ~/EuRoC/V1_03_difficult\n\n", rtabmap::Parameters::showUsage());
exit(1);
}
// catch ctrl-c
bool g_forever = true;
void sighandler(int sig)
{
printf("\nSignal %d caught...\n", sig);
g_forever = false;
}
int main(int argc, char * argv[])
{
signal(SIGABRT, &sighandler);
signal(SIGTERM, &sighandler);
signal(SIGINT, &sighandler);
ULogger::setType(ULogger::kTypeConsole);
ULogger::setLevel(ULogger::kWarning);
ParametersMap parameters;
std::string path;
std::string output;
std::string outputName = "rtabmap";
std::string seq;
bool disp = false;
bool exposureCompensation = false;
bool quiet = false;
if(argc < 2)
{
showUsage();
}
else
{
for(int i=1; i<argc; ++i)
{
if(std::strcmp(argv[i], "--output") == 0)
{
output = argv[++i];
}
else if(std::strcmp(argv[i], "--output_name") == 0)
{
outputName = argv[++i];
}
else if(std::strcmp(argv[i], "--quiet") == 0)
{
quiet = true;
}
else if(std::strcmp(argv[i], "--disp") == 0)
{
disp = true;
}
else if(std::strcmp(argv[i], "--exposure_comp") == 0)
{
exposureCompensation = true;
}
}
parameters = Parameters::parseArguments(argc, argv);
path = argv[argc-1];
path = uReplaceChar(path, '~', UDirectory::homeDir());
path = uReplaceChar(path, '\\', '/');
if(output.empty())
{
output = path;
}
else
{
output = uReplaceChar(output, '~', UDirectory::homeDir());
UDirectory::makeDir(output);
}
parameters.insert(ParametersPair(Parameters::kRtabmapWorkingDirectory(), output));
parameters.insert(ParametersPair(Parameters::kRtabmapPublishRAMUsage(), "true"));
}
seq = uSplit(path, '/').back();
std::string pathLeftImages = path+"/mav0/cam0/data";
std::string pathRightImages = path+"/mav0/cam1/data";
std::string pathCalibLeft = path+"/mav0/cam0/sensor.yaml";
std::string pathCalibRight = path+"/mav0/cam1/sensor.yaml";
std::string pathGt = path+"/mav0/state_groundtruth_estimate0/data.csv";
if(!UFile::exists(pathGt))
{
UWARN("Ground truth file path doesn't exist: \"%s\", benchmark values won't be computed.", pathGt.c_str());
pathGt.clear();
}
printf("Paths:\n"
" Sequence number: %s\n"
" Sequence path: %s\n"
" Output: %s\n"
" Output name: %s\n"
" left images: %s\n"
" right images: %s\n"
" left calib: %s\n"
" right calib: %s\n",
seq.c_str(),
path.c_str(),
output.c_str(),
outputName.c_str(),
pathLeftImages.c_str(),
pathRightImages.c_str(),
pathCalibLeft.c_str(),
pathCalibRight.c_str());
if(!pathGt.empty())
{
printf(" Ground truth: %s\n", pathGt.c_str());
}
printf(" Exposure Compensation: %s\n", exposureCompensation?"true":"false");
printf(" Disparity: %s\n", disp?"true":"false");
if(!parameters.empty())
{
printf("Parameters:\n");
for(ParametersMap::iterator iter=parameters.begin(); iter!=parameters.end(); ++iter)
{
printf(" %s=%s\n", iter->first.c_str(), iter->second.c_str());
}
}
printf("RTAB-Map version: %s\n", RTABMAP_VERSION);
std::vector<CameraModel> models;
int rateHz = 20;
for(int k=0; k<2; ++k)
{
// Left calibration
std::string calibPath = k==0?pathCalibLeft:pathCalibRight;
YAML::Node config = YAML::LoadFile(calibPath);
if(config.IsNull())
{
UERROR("Cannot open calibration file \"%s\"", calibPath.c_str());
return -1;
}
YAML::Node T_BS = config["T_BS"];
YAML::Node data = T_BS["data"];
UASSERT(data.size() == 16);
rateHz = config["rate_hz"].as<int>();
YAML::Node resolution = config["resolution"];
UASSERT(resolution.size() == 2);
YAML::Node intrinsics = config["intrinsics"];
UASSERT(intrinsics.size() == 4);
YAML::Node distortion_coefficients = config["distortion_coefficients"];
UASSERT(distortion_coefficients.size() == 4 || distortion_coefficients.size() == 5 || distortion_coefficients.size() == 8);
cv::Mat K = cv::Mat::eye(3, 3, CV_64FC1);
K.at<double>(0,0) = intrinsics[0].as<double>();
K.at<double>(1,1) = intrinsics[1].as<double>();
K.at<double>(0,2) = intrinsics[2].as<double>();
K.at<double>(1,2) = intrinsics[3].as<double>();
cv::Mat R = cv::Mat::eye(3, 3, CV_64FC1);
cv::Mat P = cv::Mat::zeros(3, 4, CV_64FC1);
K.copyTo(cv::Mat(P, cv::Range(0,3), cv::Range(0,3)));
cv::Mat D = cv::Mat::zeros(1, distortion_coefficients.size(), CV_64FC1);
for(unsigned int i=0; i<distortion_coefficients.size(); ++i)
{
D.at<double>(i) = distortion_coefficients[i].as<double>();
}
Transform t(data[0].as<float>(), data[1].as<float>(), data[2].as<float>(), data[3].as<float>(),
data[4].as<float>(), data[5].as<float>(), data[6].as<float>(), data[7].as<float>(),
data[8].as<float>(), data[9].as<float>(), data[10].as<float>(), data[11].as<float>());
models.push_back(CameraModel(outputName+"_calib", cv::Size(resolution[0].as<int>(),resolution[1].as<int>()), K, D, R, P, t));
UASSERT(models.back().isValidForRectification());
}
StereoCameraModel model(outputName+"_calib", models[0], models[1], models[1].localTransform().inverse() * models[0].localTransform());
if(!model.save(output, true))
{
UERROR("Could not save calibration!");
return -1;
}
printf("Saved calibration \"%s\" to \"%s\"\n", (outputName+"_calib").c_str(), output.c_str());
if(quiet)
{
ULogger::setLevel(ULogger::kError);
}
// We use CameraThread only to use postUpdate() method
Transform opticalRotation(0,0,1,0, 0,-1,0,0, 1,0,0,0);
CameraThread cameraThread(new
CameraStereoImages(
pathLeftImages,
pathRightImages,
true,
0.0f,
opticalRotation*models[0].localTransform()), parameters);
((CameraStereoImages*)cameraThread.camera())->setTimestamps(true, "", false);
if(exposureCompensation)
{
cameraThread.setStereoExposureCompensation(true);
}
if(disp)
{
cameraThread.setStereoToDepth(true);
}
if(!pathGt.empty())
{
((CameraStereoImages*)cameraThread.camera())->setGroundTruthPath(pathGt, 9);
}
float detectionRate = Parameters::defaultRtabmapDetectionRate();
bool intermediateNodes = Parameters::defaultRtabmapCreateIntermediateNodes();
int odomStrategy = Parameters::defaultOdomStrategy();
Parameters::parse(parameters, Parameters::kOdomStrategy(), odomStrategy);
Parameters::parse(parameters, Parameters::kRtabmapDetectionRate(), detectionRate);
Parameters::parse(parameters, Parameters::kRtabmapCreateIntermediateNodes(), intermediateNodes);
int mapUpdate = rateHz / detectionRate;
if(mapUpdate < 1)
{
mapUpdate = 1;
}
std::string databasePath = output+"/"+outputName+".db";
UFile::erase(databasePath);
if(cameraThread.camera()->init(output, outputName+"_calib"))
{
int totalImages = (int)((CameraStereoImages*)cameraThread.camera())->filenames().size();
printf("Processing %d images...\n", totalImages);
ParametersMap odomParameters = parameters;
odomParameters.erase(Parameters::kRtabmapPublishRAMUsage()); // as odometry is in the same process than rtabmap, don't get RAM usage in odometry.
Odometry * odom = Odometry::create(odomParameters);
Rtabmap rtabmap;
rtabmap.init(parameters, databasePath);
UTimer totalTime;
UTimer timer;
CameraInfo cameraInfo;
SensorData data = cameraThread.camera()->takeImage(&cameraInfo);
int iteration = 0;
/////////////////////////////
// Processing dataset begin
/////////////////////////////
cv::Mat covariance;
int odomKeyFrames = 0;
while(data.isValid() && g_forever)
{
cameraThread.postUpdate(&data, &cameraInfo);
cameraInfo.timeTotal = timer.ticks();
OdometryInfo odomInfo;
Transform pose = odom->process(data, &odomInfo);
if(odomInfo.keyFrameAdded)
{
++odomKeyFrames;
}
if(odomStrategy == 2)
{
//special case for FOVIS, set covariance 1 if 9999 is detected
if(!odomInfo.reg.covariance.empty() && odomInfo.reg.covariance.at<double>(0,0) >= 9999)
{
odomInfo.reg.covariance = cv::Mat::eye(6,6,CV_64FC1);
}
}
bool processData = true;
if(iteration % mapUpdate != 0)
{
// set negative id so rtabmap will detect it as an intermediate node
data.setId(-1);
data.setFeatures(std::vector<cv::KeyPoint>(), std::vector<cv::Point3f>(), cv::Mat());// remove features
processData = intermediateNodes;
}
if(covariance.empty() || odomInfo.reg.covariance.at<double>(0,0) > covariance.at<double>(0,0))
{
covariance = odomInfo.reg.covariance;
}
timer.restart();
if(processData)
{
std::map<std::string, float> externalStats;
// save camera statistics to database
externalStats.insert(std::make_pair("Camera/BilateralFiltering/ms", cameraInfo.timeBilateralFiltering*1000.0f));
externalStats.insert(std::make_pair("Camera/Capture/ms", cameraInfo.timeCapture*1000.0f));
externalStats.insert(std::make_pair("Camera/Disparity/ms", cameraInfo.timeDisparity*1000.0f));
externalStats.insert(std::make_pair("Camera/ImageDecimation/ms", cameraInfo.timeImageDecimation*1000.0f));
externalStats.insert(std::make_pair("Camera/Mirroring/ms", cameraInfo.timeMirroring*1000.0f));
externalStats.insert(std::make_pair("Camera/ExposureCompensation/ms", cameraInfo.timeStereoExposureCompensation*1000.0f));
externalStats.insert(std::make_pair("Camera/ScanFromDepth/ms", cameraInfo.timeScanFromDepth*1000.0f));
externalStats.insert(std::make_pair("Camera/TotalTime/ms", cameraInfo.timeTotal*1000.0f));
externalStats.insert(std::make_pair("Camera/UndistortDepth/ms", cameraInfo.timeUndistortDepth*1000.0f));
// save odometry statistics to database
externalStats.insert(std::make_pair("Odometry/LocalBundle/ms", odomInfo.localBundleTime*1000.0f));
externalStats.insert(std::make_pair("Odometry/LocalBundleConstraints/", odomInfo.localBundleConstraints));
externalStats.insert(std::make_pair("Odometry/LocalBundleOutliers/", odomInfo.localBundleOutliers));
externalStats.insert(std::make_pair("Odometry/TotalTime/ms", odomInfo.timeEstimation*1000.0f));
externalStats.insert(std::make_pair("Odometry/Registration/ms", odomInfo.reg.totalTime*1000.0f));
externalStats.insert(std::make_pair("Odometry/Inliers/", odomInfo.reg.inliers));
externalStats.insert(std::make_pair("Odometry/Features/", odomInfo.features));
externalStats.insert(std::make_pair("Odometry/DistanceTravelled/m", odomInfo.distanceTravelled));
externalStats.insert(std::make_pair("Odometry/KeyFrameAdded/", odomInfo.keyFrameAdded));
externalStats.insert(std::make_pair("Odometry/LocalKeyFrames/", odomInfo.localKeyFrames));
externalStats.insert(std::make_pair("Odometry/LocalMapSize/", odomInfo.localMapSize));
externalStats.insert(std::make_pair("Odometry/LocalScanMapSize/", odomInfo.localScanMapSize));
OdometryEvent e(SensorData(), Transform(), odomInfo);
rtabmap.process(data, pose, covariance, e.velocity(), externalStats);
covariance = cv::Mat();
}
++iteration;
if(!quiet || iteration == totalImages)
{
double slamTime = timer.ticks();
float rmse = -1;
if(rtabmap.getStatistics().data().find(Statistics::kGtTranslational_rmse()) != rtabmap.getStatistics().data().end())
{
rmse = rtabmap.getStatistics().data().at(Statistics::kGtTranslational_rmse());
}
if(data.keypoints().size() == 0 && data.laserScanRaw().cols)
{
if(rmse >= 0.0f)
{
printf("Iteration %d/%d: camera=%dms, odom(quality=%f, kfs=%d)=%dms, slam=%dms, rmse=%fm",
iteration, totalImages, int(cameraInfo.timeTotal*1000.0f), odomInfo.reg.icpInliersRatio, odomKeyFrames, int(odomInfo.timeEstimation*1000.0f), int(slamTime*1000.0f), rmse);
}
else
{
printf("Iteration %d/%d: camera=%dms, odom(quality=%f, kfs=%d)=%dms, slam=%dms",
iteration, totalImages, int(cameraInfo.timeTotal*1000.0f), odomInfo.reg.icpInliersRatio, odomKeyFrames, int(odomInfo.timeEstimation*1000.0f), int(slamTime*1000.0f));
}
}
else
{
if(rmse >= 0.0f)
{
printf("Iteration %d/%d: camera=%dms, odom(quality=%d/%d, kfs=%d)=%dms, slam=%dms, rmse=%fm",
iteration, totalImages, int(cameraInfo.timeTotal*1000.0f), odomInfo.reg.inliers, odomInfo.features, odomKeyFrames, int(odomInfo.timeEstimation*1000.0f), int(slamTime*1000.0f), rmse);
}
else
{
printf("Iteration %d/%d: camera=%dms, odom(quality=%d/%d, kfs=%d)=%dms, slam=%dms",
iteration, totalImages, int(cameraInfo.timeTotal*1000.0f), odomInfo.reg.inliers, odomInfo.features, odomKeyFrames, int(odomInfo.timeEstimation*1000.0f), int(slamTime*1000.0f));
}
}
if(processData && rtabmap.getLoopClosureId()>0)
{
printf(" *");
}
printf("\n");
}
else if(iteration % (totalImages/10) == 0)
{
printf(".");
fflush(stdout);
}
cameraInfo = CameraInfo();
timer.restart();
data = cameraThread.camera()->takeImage(&cameraInfo);
}
delete odom;
printf("Total time=%fs\n", totalTime.ticks());
/////////////////////////////
// Processing dataset end
/////////////////////////////
// Save trajectory
printf("Saving trajectory ...\n");
std::map<int, Transform> poses;
std::multimap<int, Link> links;
std::map<int, Signature> signatures;
std::map<int, double> stamps;
rtabmap.getGraph(poses, links, true, true, &signatures);
for(std::map<int, Signature>::iterator iter=signatures.begin(); iter!=signatures.end(); ++iter)
{
stamps.insert(std::make_pair(iter->first, iter->second.getStamp()));
}
std::string pathTrajectory = output+"/"+outputName+"_poses.txt";
if(poses.size() && graph::exportPoses(pathTrajectory, 2, poses, links))
{
printf("Saving %s... done!\n", pathTrajectory.c_str());
}
else
{
printf("Saving %s... failed!\n", pathTrajectory.c_str());
}
if(!pathGt.empty())
{
// Log ground truth statistics
std::map<int, Transform> groundTruth;
for(std::map<int, Transform>::const_iterator iter=poses.begin(); iter!=poses.end(); ++iter)
{
Transform o, gtPose;
int m,w;
std::string l;
double s;
std::vector<float> v;
GPS gps;
rtabmap.getMemory()->getNodeInfo(iter->first, o, m, w, l, s, gtPose, v, gps, true);
if(!gtPose.isNull())
{
groundTruth.insert(std::make_pair(iter->first, gtPose));
}
}
// compute RMSE statistics
float translational_rmse = 0.0f;
float translational_mean = 0.0f;
float translational_median = 0.0f;
float translational_std = 0.0f;
float translational_min = 0.0f;
float translational_max = 0.0f;
float rotational_rmse = 0.0f;
float rotational_mean = 0.0f;
float rotational_median = 0.0f;
float rotational_std = 0.0f;
float rotational_min = 0.0f;
float rotational_max = 0.0f;
graph::calcRMSE(
groundTruth,
poses,
translational_rmse,
translational_mean,
translational_median,
translational_std,
translational_min,
translational_max,
rotational_rmse,
rotational_mean,
rotational_median,
rotational_std,
rotational_min,
rotational_max);
printf(" translational_rmse= %f m\n", translational_rmse);
printf(" rotational_rmse= %f deg\n", rotational_rmse);
FILE * pFile = 0;
std::string pathErrors = output+"/"+outputName+"_rmse.txt";
pFile = fopen(pathErrors.c_str(),"w");
if(!pFile)
{
UERROR("could not save RMSE results to \"%s\"", pathErrors.c_str());
}
fprintf(pFile, "Ground truth comparison:\n");
fprintf(pFile, " translational_rmse= %f\n", translational_rmse);
fprintf(pFile, " translational_mean= %f\n", translational_mean);
fprintf(pFile, " translational_median= %f\n", translational_median);
fprintf(pFile, " translational_std= %f\n", translational_std);
fprintf(pFile, " translational_min= %f\n", translational_min);
fprintf(pFile, " translational_max= %f\n", translational_max);
fprintf(pFile, " rotational_rmse= %f\n", rotational_rmse);
fprintf(pFile, " rotational_mean= %f\n", rotational_mean);
fprintf(pFile, " rotational_median= %f\n", rotational_median);
fprintf(pFile, " rotational_std= %f\n", rotational_std);
fprintf(pFile, " rotational_min= %f\n", rotational_min);
fprintf(pFile, " rotational_max= %f\n", rotational_max);
fclose(pFile);
}
}
else
{
UERROR("Camera init failed!");
}
printf("Saving rtabmap database (with all statistics) to \"%s\"\n", (output+"/"+outputName+".db").c_str());
printf("Do:\n"
" $ rtabmap-databaseViewer %s\n\n", (output+"/"+outputName+".db").c_str());
return 0;
}
+4
View File
@@ -34,3 +34,7 @@ TARGET_LINK_LIBRARIES(kitti_dataset ${LIBRARIES})
SET_TARGET_PROPERTIES( kitti_dataset SET_TARGET_PROPERTIES( kitti_dataset
PROPERTIES OUTPUT_NAME ${PROJECT_PREFIX}-kitti_dataset) PROPERTIES OUTPUT_NAME ${PROJECT_PREFIX}-kitti_dataset)
INSTALL(TARGETS kitti_dataset
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT runtime
BUNDLE DESTINATION "${CMAKE_BUNDLE_LOCATION}" COMPONENT runtime)
+123 -55
View File
@@ -39,6 +39,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "rtabmap/utilite/UFile.h" #include "rtabmap/utilite/UFile.h"
#include "rtabmap/utilite/UMath.h" #include "rtabmap/utilite/UMath.h"
#include "rtabmap/utilite/UStl.h" #include "rtabmap/utilite/UStl.h"
#include "rtabmap/utilite/UProcessInfo.h"
#include <pcl/common/common.h> #include <pcl/common/common.h>
#include <stdio.h> #include <stdio.h>
#include <signal.h> #include <signal.h>
@@ -53,14 +54,17 @@ void showUsage()
" containing least calib.txt, times.txt, image_0 and image_1 folders.\n" " containing least calib.txt, times.txt, image_0 and image_1 folders.\n"
" Optional image_2, image_3 and velodyne folders.\n" " Optional image_2, image_3 and velodyne folders.\n"
" --output Output directory. By default, results are saved in \"path\".\n" " --output Output directory. By default, results are saved in \"path\".\n"
" --output_name Output database name (default \"rtabmap\").\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"
" --quiet Don't show log messages and iteration updates.\n" " --quiet Don't show log messages and iteration updates.\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"
" --scaling Scale stereo baseline on some sequences (03-04-05-06).\n"
" --disp Generate full disparity.\n" " --disp Generate full disparity.\n"
" --exposure_comp Do exposure compensation between left and right images.\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=1).\n"
" --scan_voxel #.# Scan voxel size (default 0.3 m).\n" " --scan_voxel #.# Scan voxel size (default 0.5 m).\n"
" --scan_k Scan normal K (default 5).\n" " --scan_k Scan normal K (default 0).\n"
" --scan_radius Scan normal radius (default 0).\n\n" " --scan_radius Scan normal radius (default 0).\n\n"
"%s\n" "%s\n"
"Example:\n\n" "Example:\n\n"
@@ -108,13 +112,16 @@ int main(int argc, char * argv[])
ParametersMap parameters; ParametersMap parameters;
std::string path; std::string path;
std::string output; std::string output;
std::string outputName = "rtabmap";
std::string seq; std::string seq;
bool color = false; bool color = false;
bool scaling = false;
bool scan = false; bool scan = false;
bool disp = false; bool disp = false;
int scanStep = 10; bool exposureCompensation = false;
float scanVoxel = 0.3f; int scanStep = 1;
int scanNormalK = 5; float scanVoxel = 0.5f;
int scanNormalK = 0;
float scanNormalRadius = 0.0f; float scanNormalRadius = 0.0f;
std::string gtPath; std::string gtPath;
bool quiet = false; bool quiet = false;
@@ -130,6 +137,10 @@ int main(int argc, char * argv[])
{ {
output = argv[++i]; output = argv[++i];
} }
else if(std::strcmp(argv[i], "--output_name") == 0)
{
outputName = argv[++i];
}
else if(std::strcmp(argv[i], "--quiet") == 0) else if(std::strcmp(argv[i], "--quiet") == 0)
{ {
quiet = true; quiet = true;
@@ -178,6 +189,10 @@ int main(int argc, char * argv[])
{ {
color = true; color = true;
} }
else if(std::strcmp(argv[i], "--scaling") == 0)
{
scaling = true;
}
else if(std::strcmp(argv[i], "--scan") == 0) else if(std::strcmp(argv[i], "--scan") == 0)
{ {
scan = true; scan = true;
@@ -186,6 +201,10 @@ int main(int argc, char * argv[])
{ {
disp = true; disp = true;
} }
else if(std::strcmp(argv[i], "--exposure_comp") == 0)
{
exposureCompensation = true;
}
} }
parameters = Parameters::parseArguments(argc, argv); parameters = Parameters::parseArguments(argc, argv);
path = argv[argc-1]; path = argv[argc-1];
@@ -200,6 +219,8 @@ int main(int argc, char * argv[])
output = uReplaceChar(output, '~', UDirectory::homeDir()); output = uReplaceChar(output, '~', UDirectory::homeDir());
UDirectory::makeDir(output); UDirectory::makeDir(output);
} }
parameters.insert(ParametersPair(Parameters::kRtabmapWorkingDirectory(), output));
parameters.insert(ParametersPair(Parameters::kRtabmapPublishRAMUsage(), "true"));
} }
seq = uSplit(path, '/').back(); seq = uSplit(path, '/').back();
@@ -218,6 +239,7 @@ int main(int argc, char * argv[])
" Sequence number: %s\n" " Sequence number: %s\n"
" Sequence path: %s\n" " Sequence path: %s\n"
" Output: %s\n" " Output: %s\n"
" Output name: %s\n"
" left images: %s\n" " left images: %s\n"
" right images: %s\n" " right images: %s\n"
" calib.txt: %s\n" " calib.txt: %s\n"
@@ -225,6 +247,7 @@ int main(int argc, char * argv[])
seq.c_str(), seq.c_str(),
path.c_str(), path.c_str(),
output.c_str(), output.c_str(),
outputName.c_str(),
pathLeftImages.c_str(), pathLeftImages.c_str(),
pathRightImages.c_str(), pathRightImages.c_str(),
pathCalib.c_str(), pathCalib.c_str(),
@@ -243,10 +266,8 @@ int main(int argc, char * argv[])
printf(" Ground Truth: %s\n", gtPath.c_str()); printf(" Ground Truth: %s\n", gtPath.c_str());
} }
} }
if(disp) printf(" Exposure Compensation: %s\n", exposureCompensation?"true":"false");
{
printf(" Disparity: %s\n", disp?"true":"false"); printf(" Disparity: %s\n", disp?"true":"false");
}
if(scan) if(scan)
{ {
pathScan = path+"/velodyne"; pathScan = path+"/velodyne";
@@ -256,15 +277,6 @@ int main(int argc, char * argv[])
printf(" Scan normal k: %d\n", scanNormalK); printf(" Scan normal k: %d\n", scanNormalK);
printf(" Scan normal radius: %f\n", scanNormalRadius); printf(" Scan normal radius: %f\n", scanNormalRadius);
} }
if(!parameters.empty())
{
printf("Parameters:\n");
for(ParametersMap::iterator iter=parameters.begin(); iter!=parameters.end(); ++iter)
{
printf(" %s=%s\n", iter->first.c_str(), iter->second.c_str());
}
}
printf("RTAB-Map version: %s\n", RTABMAP_VERSION);
// convert calib.txt to rtabmap format (yaml) // convert calib.txt to rtabmap format (yaml)
FILE * pFile = 0; FILE * pFile = 0;
@@ -320,7 +332,28 @@ int main(int argc, char * argv[])
UERROR("Failed to read first image of \"%s\"", firstImage.c_str()); UERROR("Failed to read first image of \"%s\"", firstImage.c_str());
return -1; return -1;
} }
StereoCameraModel model("rtabmap_calib"+seq,
if(scaling)
{
// scale baseline
if(uStr2Int(seq) == 3 || uStr2Int(seq) == 5 || uStr2Int(seq) == 9)
{
P1.at<double>(0,3) *= 0.9905;
printf(" Baseline scaling factor: %f\n", 0.9905);
}
else if(uStr2Int(seq) == 4)
{
P1.at<double>(0,3) *= 0.987000;
printf(" Baseline scaling factor: %f\n", 0.987000);
}
else if(uStr2Int(seq) == 6)
{
P1.at<double>(0,3) *= 0.985000;
printf(" Baseline scaling factor: %f\n", 0.985000);
}
}
StereoCameraModel model(outputName+"_calib",
image.size(), P0.colRange(0,3), cv::Mat(), cv::Mat(), P0, image.size(), P0.colRange(0,3), cv::Mat(), cv::Mat(), P0,
image.size(), P1.colRange(0,3), cv::Mat(), cv::Mat(), P1, image.size(), P1.colRange(0,3), cv::Mat(), cv::Mat(), P1,
cv::Mat(), cv::Mat(), cv::Mat(), cv::Mat()); cv::Mat(), cv::Mat(), cv::Mat(), cv::Mat());
@@ -329,8 +362,18 @@ int main(int argc, char * argv[])
UERROR("Could not save calibration!"); UERROR("Could not save calibration!");
return -1; return -1;
} }
printf("Saved calibration \"%s\" to \"%s\"\n", ("rtabmap_calib"+seq).c_str(), output.c_str()); printf("Saved calibration \"%s\" to \"%s\"\n", (outputName+"_calib").c_str(), output.c_str());
if(!parameters.empty())
{
printf("Parameters:\n");
for(ParametersMap::iterator iter=parameters.begin(); iter!=parameters.end(); ++iter)
{
printf(" %s=%s\n", iter->first.c_str(), iter->second.c_str());
}
}
printf("RTAB-Map version: %s\n", RTABMAP_VERSION);
if(quiet) if(quiet)
{ {
@@ -347,6 +390,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(exposureCompensation)
{
cameraThread.setStereoExposureCompensation(true);
}
if(disp) if(disp)
{ {
cameraThread.setStereoToDepth(true); cameraThread.setStereoToDepth(true);
@@ -364,11 +411,14 @@ int main(int argc, char * argv[])
scanVoxel, scanVoxel,
scanNormalK, scanNormalK,
scanNormalRadius, scanNormalRadius,
Transform(-0.27f, 0.0f, 0.08, 0.0f, 0.0f, 0.0f)); Transform(-0.27f, 0.0f, 0.08, 0.0f, 0.0f, 0.0f),
true);
} }
float detectionRate = Parameters::defaultRtabmapDetectionRate(); float detectionRate = Parameters::defaultRtabmapDetectionRate();
bool intermediateNodes = Parameters::defaultRtabmapCreateIntermediateNodes(); bool intermediateNodes = Parameters::defaultRtabmapCreateIntermediateNodes();
int odomStrategy = Parameters::defaultOdomStrategy();
Parameters::parse(parameters, Parameters::kOdomStrategy(), odomStrategy);
Parameters::parse(parameters, Parameters::kRtabmapDetectionRate(), detectionRate); Parameters::parse(parameters, Parameters::kRtabmapDetectionRate(), detectionRate);
Parameters::parse(parameters, Parameters::kRtabmapCreateIntermediateNodes(), intermediateNodes); Parameters::parse(parameters, Parameters::kRtabmapCreateIntermediateNodes(), intermediateNodes);
@@ -379,15 +429,17 @@ int main(int argc, char * argv[])
mapUpdate = 1; mapUpdate = 1;
} }
std::string databasePath = output+"/rtabmap" + seq + ".db"; std::string databasePath = output+"/"+outputName+".db";
UFile::erase(databasePath); UFile::erase(databasePath);
if(cameraThread.camera()->init(output, "rtabmap_calib"+seq)) if(cameraThread.camera()->init(output, outputName+"_calib"))
{ {
int totalImages = (int)((CameraStereoImages*)cameraThread.camera())->filenames().size(); int totalImages = (int)((CameraStereoImages*)cameraThread.camera())->filenames().size();
printf("Processing %d images...\n", totalImages); printf("Processing %d images...\n", totalImages);
Odometry * odom = Odometry::create(parameters); ParametersMap odomParameters = parameters;
odomParameters.erase(Parameters::kRtabmapPublishRAMUsage()); // as odometry is in the same process than rtabmap, don't get RAM usage in odometry.
Odometry * odom = Odometry::create(odomParameters);
Rtabmap rtabmap; Rtabmap rtabmap;
rtabmap.init(parameters, databasePath); rtabmap.init(parameters, databasePath);
@@ -404,43 +456,29 @@ int main(int argc, char * argv[])
int odomKeyFrames = 0; int odomKeyFrames = 0;
while(data.isValid() && g_forever) while(data.isValid() && g_forever)
{ {
std::map<std::string, float> externalStats;
cameraThread.postUpdate(&data, &cameraInfo); cameraThread.postUpdate(&data, &cameraInfo);
cameraInfo.timeTotal = timer.ticks(); cameraInfo.timeTotal = timer.ticks();
// save camera statistics to database
externalStats.insert(std::make_pair("Camera/BilateralFiltering/ms", cameraInfo.timeBilateralFiltering*1000.0f));
externalStats.insert(std::make_pair("Camera/Capture/ms", cameraInfo.timeCapture*1000.0f));
externalStats.insert(std::make_pair("Camera/Disparity/ms", cameraInfo.timeDisparity*1000.0f));
externalStats.insert(std::make_pair("Camera/ImageDecimation/ms", cameraInfo.timeImageDecimation*1000.0f));
externalStats.insert(std::make_pair("Camera/Mirroring/ms", cameraInfo.timeMirroring*1000.0f));
externalStats.insert(std::make_pair("Camera/ScanFromDepth/ms", cameraInfo.timeScanFromDepth*1000.0f));
externalStats.insert(std::make_pair("Camera/TotalTime/ms", cameraInfo.timeTotal*1000.0f));
externalStats.insert(std::make_pair("Camera/UndistortDepth/ms", cameraInfo.timeUndistortDepth*1000.0f));
OdometryInfo odomInfo; OdometryInfo odomInfo;
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/LocalBundleConstraints/", odomInfo.localBundleConstraints));
externalStats.insert(std::make_pair("Odometry/LocalBundleOutliers/", odomInfo.localBundleOutliers));
externalStats.insert(std::make_pair("Odometry/TotalTime/ms", odomInfo.timeEstimation*1000.0f));
externalStats.insert(std::make_pair("Odometry/Registration/ms", odomInfo.reg.totalTime*1000.0f));
float speed = 0.0f; float speed = 0.0f;
if(odomInfo.interval>0.0) if(odomInfo.interval>0.0)
speed = odomInfo.transform.x()/odomInfo.interval*3.6; speed = odomInfo.transform.x()/odomInfo.interval*3.6;
externalStats.insert(std::make_pair("Odometry/Speed/kph", speed));
externalStats.insert(std::make_pair("Odometry/Inliers/", odomInfo.reg.inliers));
externalStats.insert(std::make_pair("Odometry/Features/", odomInfo.features));
externalStats.insert(std::make_pair("Odometry/DistanceTravelled/m", odomInfo.distanceTravelled));
externalStats.insert(std::make_pair("Odometry/KeyFrameAdded/", odomInfo.keyFrameAdded));
externalStats.insert(std::make_pair("Odometry/LocalKeyFrames/", odomInfo.localKeyFrames));
externalStats.insert(std::make_pair("Odometry/LocalMapSize/", odomInfo.localMapSize));
externalStats.insert(std::make_pair("Odometry/LocalScanMapSize/", odomInfo.localScanMapSize));
if(odomInfo.keyFrameAdded) if(odomInfo.keyFrameAdded)
{ {
++odomKeyFrames; ++odomKeyFrames;
} }
if(odomStrategy == 2)
{
//special case for FOVIS, set covariance 1 if 9999 is detected
if(!odomInfo.reg.covariance.empty() && odomInfo.reg.covariance.at<double>(0,0) >= 9999)
{
odomInfo.reg.covariance = cv::Mat::eye(6,6,CV_64FC1);
}
}
bool processData = true; bool processData = true;
if(iteration % mapUpdate != 0) if(iteration % mapUpdate != 0)
{ {
@@ -457,6 +495,32 @@ int main(int argc, char * argv[])
timer.restart(); timer.restart();
if(processData) if(processData)
{ {
std::map<std::string, float> externalStats;
// save camera statistics to database
externalStats.insert(std::make_pair("Camera/BilateralFiltering/ms", cameraInfo.timeBilateralFiltering*1000.0f));
externalStats.insert(std::make_pair("Camera/Capture/ms", cameraInfo.timeCapture*1000.0f));
externalStats.insert(std::make_pair("Camera/Disparity/ms", cameraInfo.timeDisparity*1000.0f));
externalStats.insert(std::make_pair("Camera/ImageDecimation/ms", cameraInfo.timeImageDecimation*1000.0f));
externalStats.insert(std::make_pair("Camera/Mirroring/ms", cameraInfo.timeMirroring*1000.0f));
externalStats.insert(std::make_pair("Camera/ExposureCompensation/ms", cameraInfo.timeStereoExposureCompensation*1000.0f));
externalStats.insert(std::make_pair("Camera/ScanFromDepth/ms", cameraInfo.timeScanFromDepth*1000.0f));
externalStats.insert(std::make_pair("Camera/TotalTime/ms", cameraInfo.timeTotal*1000.0f));
externalStats.insert(std::make_pair("Camera/UndistortDepth/ms", cameraInfo.timeUndistortDepth*1000.0f));
// save odometry statistics to database
externalStats.insert(std::make_pair("Odometry/LocalBundle/ms", odomInfo.localBundleTime*1000.0f));
externalStats.insert(std::make_pair("Odometry/LocalBundleConstraints/", odomInfo.localBundleConstraints));
externalStats.insert(std::make_pair("Odometry/LocalBundleOutliers/", odomInfo.localBundleOutliers));
externalStats.insert(std::make_pair("Odometry/TotalTime/ms", odomInfo.timeEstimation*1000.0f));
externalStats.insert(std::make_pair("Odometry/Registration/ms", odomInfo.reg.totalTime*1000.0f));
externalStats.insert(std::make_pair("Odometry/Speed/kph", speed));
externalStats.insert(std::make_pair("Odometry/Inliers/", odomInfo.reg.inliers));
externalStats.insert(std::make_pair("Odometry/Features/", odomInfo.features));
externalStats.insert(std::make_pair("Odometry/DistanceTravelled/m", odomInfo.distanceTravelled));
externalStats.insert(std::make_pair("Odometry/KeyFrameAdded/", odomInfo.keyFrameAdded));
externalStats.insert(std::make_pair("Odometry/LocalKeyFrames/", odomInfo.localKeyFrames));
externalStats.insert(std::make_pair("Odometry/LocalMapSize/", odomInfo.localMapSize));
externalStats.insert(std::make_pair("Odometry/LocalScanMapSize/", odomInfo.localScanMapSize));
OdometryEvent e(SensorData(), Transform(), odomInfo); OdometryEvent e(SensorData(), Transform(), odomInfo);
rtabmap.process(data, pose, covariance, e.velocity(), externalStats); rtabmap.process(data, pose, covariance, e.velocity(), externalStats);
covariance = cv::Mat(); covariance = cv::Mat();
@@ -477,8 +541,10 @@ int main(int argc, char * argv[])
{ {
if(rmse >= 0.0f) if(rmse >= 0.0f)
{ {
printf("Iteration %d/%d: speed=%dkm/h camera=%dms, odom(quality=%f, kfs=%d)=%dms, slam=%dms, rmse=%fm, noise stddev=%fm %frad", //printf("Iteration %d/%d: speed=%dkm/h camera=%dms, odom(quality=%f, kfs=%d)=%dms, slam=%dms, rmse=%fm, noise stddev=%fm %frad",
iteration, totalImages, int(speed), int(cameraInfo.timeTotal*1000.0f), odomInfo.reg.icpInliersRatio, odomKeyFrames, int(odomInfo.timeEstimation*1000.0f), int(slamTime*1000.0f), rmse, sqrt(odomInfo.reg.covariance.at<double>(0,0)), sqrt(odomInfo.reg.covariance.at<double>(3,3))); // iteration, totalImages, int(speed), int(cameraInfo.timeTotal*1000.0f), odomInfo.reg.icpInliersRatio, odomKeyFrames, int(odomInfo.timeEstimation*1000.0f), int(slamTime*1000.0f), rmse, sqrt(odomInfo.reg.covariance.at<double>(0,0)), sqrt(odomInfo.reg.covariance.at<double>(3,3)));
printf("Iteration %d/%d: speed=%dkm/h camera=%dms, odom(quality=%f, kfs=%d)=%dms, slam=%dms, rmse=%fm",
iteration, totalImages, int(speed), int(cameraInfo.timeTotal*1000.0f), odomInfo.reg.icpInliersRatio, odomKeyFrames, int(odomInfo.timeEstimation*1000.0f), int(slamTime*1000.0f), rmse);
} }
else else
{ {
@@ -490,8 +556,10 @@ int main(int argc, char * argv[])
{ {
if(rmse >= 0.0f) if(rmse >= 0.0f)
{ {
printf("Iteration %d/%d: speed=%dkm/h camera=%dms, odom(quality=%d/%d, kfs=%d)=%dms, slam=%dms, rmse=%fm, noise stddev=%fm %frad", //printf("Iteration %d/%d: speed=%dkm/h camera=%dms, odom(quality=%d/%d, kfs=%d)=%dms, slam=%dms, rmse=%fm, noise stddev=%fm %frad",
iteration, totalImages, int(speed), int(cameraInfo.timeTotal*1000.0f), odomInfo.reg.inliers, odomInfo.features, odomKeyFrames, int(odomInfo.timeEstimation*1000.0f), int(slamTime*1000.0f), rmse, sqrt(odomInfo.reg.covariance.at<double>(0,0)), sqrt(odomInfo.reg.covariance.at<double>(3,3))); // iteration, totalImages, int(speed), int(cameraInfo.timeTotal*1000.0f), odomInfo.reg.inliers, odomInfo.features, odomKeyFrames, int(odomInfo.timeEstimation*1000.0f), int(slamTime*1000.0f), rmse, sqrt(odomInfo.reg.covariance.at<double>(0,0)), sqrt(odomInfo.reg.covariance.at<double>(3,3)));
printf("Iteration %d/%d: speed=%dkm/h camera=%dms, odom(quality=%d/%d, kfs=%d)=%dms, slam=%dms, rmse=%fm",
iteration, totalImages, int(speed), int(cameraInfo.timeTotal*1000.0f), odomInfo.reg.inliers, odomInfo.features, odomKeyFrames, int(odomInfo.timeEstimation*1000.0f), int(slamTime*1000.0f), rmse);
} }
else else
{ {
@@ -526,7 +594,7 @@ int main(int argc, char * argv[])
std::map<int, Transform> poses; std::map<int, Transform> poses;
std::multimap<int, Link> links; std::multimap<int, Link> links;
rtabmap.getGraph(poses, links, true, true); rtabmap.getGraph(poses, links, true, true);
std::string pathTrajectory = output+"/rtabmap_poses"+seq+".txt"; std::string pathTrajectory = output+"/"+outputName+"_poses.txt";
if(poses.size() && graph::exportPoses(pathTrajectory, 2, poses, links)) if(poses.size() && graph::exportPoses(pathTrajectory, 2, poses, links))
{ {
printf("Saving %s... done!\n", pathTrajectory.c_str()); printf("Saving %s... done!\n", pathTrajectory.c_str());
@@ -597,7 +665,7 @@ int main(int argc, char * argv[])
printf(" rotational_rmse= %f deg\n", rotational_rmse); printf(" rotational_rmse= %f deg\n", rotational_rmse);
pFile = 0; pFile = 0;
std::string pathErrors = output+"/rtabmap_rmse"+seq+".txt"; std::string pathErrors = output+"/"+outputName+"_rmse.txt";
pFile = fopen(pathErrors.c_str(),"w"); pFile = fopen(pathErrors.c_str(),"w");
if(!pFile) if(!pFile)
{ {
@@ -626,9 +694,9 @@ int main(int argc, char * argv[])
UERROR("Camera init failed!"); UERROR("Camera init failed!");
} }
printf("Saving rtabmap database (with all statistics) to \"%s\"\n", (output+"/rtabmap" + seq + ".db").c_str()); printf("Saving rtabmap database (with all statistics) to \"%s\"\n", (output+"/"+outputName+".db").c_str());
printf("Do:\n" printf("Do:\n"
" $ rtabmap-databaseViewer %s\n\n", (output+"/rtabmap" + seq + ".db").c_str()); " $ rtabmap-databaseViewer %s\n\n", (output+"/"+outputName+".db").c_str());
return 0; return 0;
} }
+3
View File
@@ -33,6 +33,9 @@ TARGET_LINK_LIBRARIES(recovery ${LIBRARIES})
SET_TARGET_PROPERTIES( recovery SET_TARGET_PROPERTIES( recovery
PROPERTIES OUTPUT_NAME ${PROJECT_PREFIX}-recovery) PROPERTIES OUTPUT_NAME ${PROJECT_PREFIX}-recovery)
INSTALL(TARGETS recovery
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT runtime
BUNDLE DESTINATION "${CMAKE_BUNDLE_LOCATION}" COMPONENT runtime)
+11
View File
@@ -4,10 +4,12 @@ cmake_minimum_required(VERSION 2.8)
SET(RTABMap_INCLUDE_DIRS SET(RTABMap_INCLUDE_DIRS
${PROJECT_SOURCE_DIR}/utilite/include ${PROJECT_SOURCE_DIR}/utilite/include
${PROJECT_SOURCE_DIR}/corelib/include ${PROJECT_SOURCE_DIR}/corelib/include
${PROJECT_SOURCE_DIR}/guilib/include
) )
SET(RTABMap_LIBRARIES SET(RTABMap_LIBRARIES
rtabmap_core rtabmap_core
rtabmap_utilite rtabmap_utilite
rtabmap_gui
) )
if(POLICY CMP0020) if(POLICY CMP0020)
@@ -20,10 +22,15 @@ SET(INCLUDE_DIRS
${PCL_INCLUDE_DIRS} ${PCL_INCLUDE_DIRS}
) )
IF(QT4_FOUND)
INCLUDE(${QT_USE_FILE})
ENDIF(QT4_FOUND)
SET(LIBRARIES SET(LIBRARIES
${RTABMap_LIBRARIES} ${RTABMap_LIBRARIES}
${OpenCV_LIBRARIES} ${OpenCV_LIBRARIES}
${PCL_LIBRARIES} ${PCL_LIBRARIES}
${QT_LIBRARIES}
) )
INCLUDE_DIRECTORIES(${INCLUDE_DIRS}) INCLUDE_DIRECTORIES(${INCLUDE_DIRS})
@@ -34,3 +41,7 @@ TARGET_LINK_LIBRARIES(report ${LIBRARIES})
SET_TARGET_PROPERTIES( report SET_TARGET_PROPERTIES( report
PROPERTIES OUTPUT_NAME ${PROJECT_PREFIX}-report) PROPERTIES OUTPUT_NAME ${PROJECT_PREFIX}-report)
INSTALL(TARGETS report
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT runtime
BUNDLE DESTINATION "${CMAKE_BUNDLE_LOCATION}" COMPONENT runtime)
+398 -13
View File
@@ -26,10 +26,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <rtabmap/core/DBDriver.h> #include <rtabmap/core/DBDriver.h>
#include <rtabmap/core/Graph.h>
#include <rtabmap/core/Optimizer.h>
#include <rtabmap/utilite/UDirectory.h> #include <rtabmap/utilite/UDirectory.h>
#include <rtabmap/utilite/UFile.h> #include <rtabmap/utilite/UFile.h>
#include <rtabmap/utilite/UStl.h> #include <rtabmap/utilite/UStl.h>
#include <rtabmap/utilite/UMath.h> #include <rtabmap/utilite/UMath.h>
#include <rtabmap/utilite/UPlot.h>
#include <QApplication>
#include <stdio.h> #include <stdio.h>
using namespace rtabmap; using namespace rtabmap;
@@ -37,8 +41,8 @@ using namespace rtabmap;
void showUsage() void showUsage()
{ {
printf("\nUsage:\n" printf("\nUsage:\n"
"rtabmap-report path\n" "rtabmap-report [\"Statistic/Id\"] [--latex] [--kitti] [--scale] path\n"
" path Directory containing rtabmap databases.\n\n"); " path Directory containing rtabmap databases or path of a database.\n\n");
exit(1); exit(1);
} }
@@ -49,34 +53,113 @@ int main(int argc, char * argv[])
showUsage(); showUsage();
} }
std::string path = argv[1]; QApplication app(argc, argv);
bool outputLatex = false;
bool outputScaled = false;
bool outputKittiError = false;
std::map<std::string, UPlot*> figures;
for(int i=1; i<argc-1; ++i)
{
if(strcmp(argv[i], "--latex") == 0)
{
outputLatex = true;
}
else if(strcmp(argv[i], "--kitti") == 0)
{
outputKittiError = true;
}
else if(strcmp(argv[i], "--scale") == 0)
{
outputScaled = true;
}
else
{
std::string figureTitle = argv[i];
printf("Plot %s\n", figureTitle.c_str());
UPlot * fig = new UPlot();
fig->setTitle(figureTitle.c_str());
fig->setXLabel("Time (s)");
figures.insert(std::make_pair(figureTitle, fig));
}
}
std::string path = argv[argc-1];
path = uReplaceChar(path, '~', UDirectory::homeDir()); path = uReplaceChar(path, '~', UDirectory::homeDir());
std::string fileName; std::string fileName;
std::list<std::string> paths; std::list<std::string> paths;
paths.push_back(path); paths.push_back(path);
std::vector<std::map<std::string, std::vector<float> > > outputLatexStatistics;
std::map<std::string, std::vector<float> > outputLatexStatisticsMap;
bool odomRAMSet = false;
std::set<std::string> topDirs;
while(paths.size()) while(paths.size())
{ {
std::string currentPath = paths.front(); std::string currentPath = paths.front();
UDirectory currentDir(currentPath); UDirectory currentDir(currentPath);
paths.pop_front(); paths.pop_front();
bool currentPathIsDatabase = false;
if(!currentDir.isValid()) if(!currentDir.isValid())
{
if(UFile::getExtension(currentPath).compare("db") == 0)
{
currentPathIsDatabase=true;
printf("Database: %s\n", currentPath.c_str());
}
else
{ {
continue; continue;
} }
}
std::list<std::string> subDirs; std::list<std::string> subDirs;
if(!currentPathIsDatabase)
{
printf("Directory: %s\n", currentPath.c_str()); printf("Directory: %s\n", currentPath.c_str());
while(!(fileName = currentDir.getNextFileName()).empty()) std::list<std::string> fileNames = currentDir.getFileNames();
if(topDirs.empty())
{ {
if(UFile::getExtension(fileName).compare("db") == 0) for(std::list<std::string>::iterator iter = fileNames.begin(); iter!=fileNames.end(); ++iter)
{ {
std::string filePath = currentPath + UDirectory::separator() + fileName; topDirs.insert(currentPath+"/"+*iter);
}
}
else
{
if(topDirs.find(currentPath) != topDirs.end())
{
if(outputLatexStatisticsMap.size())
{
outputLatexStatistics.push_back(outputLatexStatisticsMap);
outputLatexStatisticsMap.clear();
}
}
}
}
while(currentPathIsDatabase || !(fileName = currentDir.getNextFileName()).empty())
{
if(currentPathIsDatabase || UFile::getExtension(fileName).compare("db") == 0)
{
std::string filePath;
if(currentPathIsDatabase)
{
filePath = currentPath;
}
else
{
filePath = currentPath + UDirectory::separator() + fileName;
}
DBDriver * driver = DBDriver::create(); DBDriver * driver = DBDriver::create();
ParametersMap params;
if(driver->openConnection(filePath)) if(driver->openConnection(filePath))
{ {
params = driver->getLastParameters();
std::set<int> ids; std::set<int> ids;
driver->getAllNodeIds(ids); driver->getAllNodeIds(ids);
std::map<int, std::pair<std::map<std::string, float>, double> > stats = driver->getAllStatistics(); std::map<int, std::pair<std::map<std::string, float>, double> > stats = driver->getAllStatistics();
std::map<int, Transform> odomPoses, gtPoses;
std::vector<float> cameraTime; std::vector<float> cameraTime;
cameraTime.reserve(ids.size()); cameraTime.reserve(ids.size());
std::vector<float> odomTime; std::vector<float> odomTime;
@@ -85,16 +168,31 @@ int main(int argc, char * argv[])
slamTime.reserve(ids.size()); slamTime.reserve(ids.size());
float rmse = -1; float rmse = -1;
float maxRMSE = -1; float maxRMSE = -1;
float rmseAng = -1;
float maxOdomRAM = -1;
float maxMapRAM = -1;
std::map<std::string, UPlotCurve*> curves;
std::map<std::string, double> firstStamps;
for(std::map<std::string, UPlot*>::iterator iter=figures.begin(); iter!=figures.end(); ++iter)
{
curves.insert(std::make_pair(iter->first, iter->second->addCurve(filePath.c_str())));
}
for(std::set<int>::iterator iter=ids.begin(); iter!=ids.end(); ++iter) for(std::set<int>::iterator iter=ids.begin(); iter!=ids.end(); ++iter)
{ {
Transform p, gt; Transform p, gt;
GPS gps; GPS gps;
int m, w; int m=-1, w=-1;
std::string l; std::string l;
double s; double s;
std::vector<float> v; std::vector<float> v;
driver->getNodeInfo(*iter, p, m, w, l, s, gt, v, gps); if(driver->getNodeInfo(*iter, p, m, w, l, s, gt, v, gps))
{
odomPoses.insert(std::make_pair(*iter, p));
if(!gt.isNull())
{
gtPoses.insert(std::make_pair(*iter, gt));
}
if(uContains(stats, *iter)) if(uContains(stats, *iter))
{ {
const std::map<std::string, float> & stat = stats.at(*iter).first; const std::map<std::string, float> & stat = stats.at(*iter).first;
@@ -106,6 +204,10 @@ int main(int argc, char * argv[])
maxRMSE = rmse; maxRMSE = rmse;
} }
} }
if(uContains(stat, Statistics::kGtRotational_rmse()))
{
rmseAng = stat.at(Statistics::kGtRotational_rmse());
}
if(uContains(stat, std::string("Camera/TotalTime/ms"))) if(uContains(stat, std::string("Camera/TotalTime/ms")))
{ {
cameraTime.push_back(stat.at(std::string("Camera/TotalTime/ms"))); cameraTime.push_back(stat.at(std::string("Camera/TotalTime/ms")));
@@ -114,20 +216,203 @@ int main(int argc, char * argv[])
{ {
odomTime.push_back(stat.at(std::string("Odometry/TotalTime/ms"))); odomTime.push_back(stat.at(std::string("Odometry/TotalTime/ms")));
} }
if(w >= 0 && uContains(stat, Statistics::kTimingTotal()))
if(uContains(stat, std::string("RtabmapROS/TotalTime/ms")))
{
if(w>=0 || stat.at("RtabmapROS/TotalTime/ms") > 10.0f)
{
slamTime.push_back(stat.at("RtabmapROS/TotalTime/ms"));
}
}
else if(uContains(stat, Statistics::kTimingTotal()))
{
if(w>=0 || stat.at(Statistics::kTimingTotal()) > 10.0f)
{ {
slamTime.push_back(stat.at(Statistics::kTimingTotal())); slamTime.push_back(stat.at(Statistics::kTimingTotal()));
} }
} }
if(uContains(stat, std::string(Statistics::kMemoryRAM_usage())))
{
float ram = stat.at(Statistics::kMemoryRAM_usage());
if(maxMapRAM==-1 || maxMapRAM < ram)
{
maxMapRAM = ram;
} }
printf(" %s (%d): %fm (max=%fm), slam: avg=%dms max=%dms, odom: avg=%dms max=%dms, camera: avg=%dms max=%dms\n", }
if(uContains(stat, std::string("Odometry/RAM_usage/MB")))
{
float ram = stat.at("Odometry/RAM_usage/MB");
if(maxOdomRAM==-1 || maxOdomRAM < ram)
{
maxOdomRAM = ram;
}
}
for(std::map<std::string, UPlotCurve*>::iterator jter=curves.begin(); jter!=curves.end(); ++jter)
{
if(uContains(stat, jter->first))
{
if(!uContains(firstStamps, jter->first))
{
firstStamps.insert(std::make_pair(jter->first, s));
}
float x = s - firstStamps.at(jter->first);
float y = stat.at(jter->first);
jter->second->addValue(x,y);
}
}
}
}
}
std::multimap<int, Link> links;
driver->getAllLinks(links, true);
std::multimap<int, Link> loopClosureLinks;
for(std::multimap<int, Link>::iterator jter=links.begin(); jter!=links.end(); ++jter)
{
if(jter->second.type() == Link::kGlobalClosure &&
graph::findLink(loopClosureLinks, jter->second.from(), jter->second.to()) == loopClosureLinks.end())
{
loopClosureLinks.insert(*jter);
}
}
UERROR("");
float bestScale = 1.0f;
float bestRMSE = rmse;
float bestRMSEAng = rmseAng;
float kitti_t_err = 0.0f;
float kitti_r_err = 0.0f;
if(ids.size())
{
std::map<int, Transform> posesOut;
std::multimap<int, Link> linksOut;
int firstId = *ids.begin();
rtabmap::Optimizer * optimizer = rtabmap::Optimizer::create(params);
optimizer->getConnectedGraph(firstId, odomPoses, graph::filterDuplicateLinks(links), posesOut, linksOut);
std::map<int, Transform> poses = optimizer->optimize(firstId, posesOut, linksOut);
std::map<int, Transform> groundTruth;
for(std::map<int, Transform>::const_iterator iter=poses.begin(); iter!=poses.end(); ++iter)
{
if(gtPoses.find(iter->first) != gtPoses.end())
{
groundTruth.insert(*gtPoses.find(iter->first));
}
}
if(outputScaled)
{
for(float scale=0.900f; scale<1.100f; scale+=0.001)
{
std::map<int, Transform> scaledPoses;
for(std::map<int, Transform>::iterator iter=poses.begin(); iter!=poses.end(); ++iter)
{
Transform t = iter->second.clone();
t.x() *= scale;
t.y() *= scale;
t.z() *= scale;
scaledPoses.insert(std::make_pair(iter->first, t));
}
// compute RMSE statistics
float translational_rmse = 0.0f;
float translational_mean = 0.0f;
float translational_median = 0.0f;
float translational_std = 0.0f;
float translational_min = 0.0f;
float translational_max = 0.0f;
float rotational_rmse = 0.0f;
float rotational_mean = 0.0f;
float rotational_median = 0.0f;
float rotational_std = 0.0f;
float rotational_min = 0.0f;
float rotational_max = 0.0f;
graph::calcRMSE(
groundTruth,
scaledPoses,
translational_rmse,
translational_mean,
translational_median,
translational_std,
translational_min,
translational_max,
rotational_rmse,
rotational_mean,
rotational_median,
rotational_std,
rotational_min,
rotational_max);
if(scale!=0.900f && translational_rmse > bestRMSE)
{
break;
}
bestRMSE = translational_rmse;
bestRMSEAng = rotational_rmse;
bestScale = scale;
}
if(bestScale!=1.0f)
{
for(std::map<int, Transform>::iterator iter=poses.begin(); iter!=poses.end(); ++iter)
{
iter->second.x()*=bestScale;
iter->second.y()*=bestScale;
iter->second.z()*=bestScale;
}
}
}
if(outputKittiError)
{
if(groundTruth.size() == poses.size())
{
// compute KITTI statistics
graph::calcKittiSequenceErrors(uValues(groundTruth), uValues(poses), kitti_t_err, kitti_r_err);
}
else
{
printf("Cannot compute KITTI statistics as optimized poses and ground truth don't have the same size (%d vs %d).\n",
(int)poses.size(), (int)groundTruth.size());
}
}
}
printf(" %s (%d, s=%.3f):\terror lin=%.3fm (max=%.3fm) ang=%.1fdeg%s, slam: avg=%dms (max=%dms) loops=%d, odom: avg=%dms (max=%dms), camera: avg=%dms, %smap=%dMB\n",
fileName.c_str(), fileName.c_str(),
(int)ids.size(), (int)ids.size(),
rmse, bestScale,
bestRMSE,
maxRMSE, maxRMSE,
bestRMSEAng,
!outputKittiError?"":uFormat(", KITTI: t_err=%.2f%% r_err=%.2f deg/100m", kitti_t_err, kitti_r_err*100).c_str(),
(int)uMean(slamTime), (int)uMax(slamTime), (int)uMean(slamTime), (int)uMax(slamTime),
(int)loopClosureLinks.size(),
(int)uMean(odomTime), (int)uMax(odomTime), (int)uMean(odomTime), (int)uMax(odomTime),
(int)uMean(cameraTime), (int)uMax(cameraTime)); (int)uMean(cameraTime),
maxOdomRAM!=-1.0f?uFormat("RAM odom=%dMB ", (int)maxOdomRAM).c_str():"",
(int)maxMapRAM);
if(outputLatex)
{
std::vector<float> stats;
stats.push_back(ids.size());
stats.push_back(bestRMSE);
stats.push_back(maxRMSE);
stats.push_back(bestRMSEAng);
stats.push_back(uMean(odomTime));
stats.push_back(uMean(slamTime));
stats.push_back(uMax(slamTime));
stats.push_back(maxOdomRAM);
stats.push_back(maxMapRAM);
outputLatexStatisticsMap.insert(std::make_pair(filePath, stats));
if(maxOdomRAM != -1.0f)
{
odomRAMSet = true;
}
}
} }
driver->closeConnection(); driver->closeConnection();
delete driver; delete driver;
@@ -137,12 +422,112 @@ int main(int argc, char * argv[])
//sub directory //sub directory
subDirs.push_front(currentPath + UDirectory::separator() + fileName); subDirs.push_front(currentPath + UDirectory::separator() + fileName);
} }
currentPathIsDatabase = false;
} }
for(std::list<std::string>::iterator iter=subDirs.begin(); iter!=subDirs.end(); ++iter) for(std::list<std::string>::iterator iter=subDirs.begin(); iter!=subDirs.end(); ++iter)
{ {
paths.push_front(*iter); paths.push_front(*iter);
} }
if(outputLatexStatisticsMap.size() && paths.empty())
{
outputLatexStatistics.push_back(outputLatexStatisticsMap);
outputLatexStatisticsMap.clear();
}
} }
if(outputLatex && outputLatexStatistics.size())
{
printf("\nLaTeX output:\n----------------\n");
printf("\\begin{table*}[!t]\n");
printf("\\caption{$t_{end}$ is the absolute translational RMSE value at the end "
"of the experiment as $ATE_{max}$ is the maximum during the experiment. "
"$r_{end}$ is rotational RMSE value at the end of the experiment. "
"$o_{avg}$ and $m_{avg}$ are the average computational time "
"for odometry (front-end) and map update (back-end). "
"$m_{avg}$ is the maximum computational time for map update. "
"$O_{end}$ and $M_{end}$ are the RAM usage at the end of the experiment "
"for odometry and map management respectively.}\n");
printf("\\label{}\n");
printf("\\centering\n");
if(odomRAMSet)
{
printf("\\begin{tabular}{l|c|c|c|c|c|c|c|c|c}\n");
printf("\\cline{2-10}\n");
printf(" & Size & $t_{end}$ & $t_{max}$ & $r_{end}$ & $o_{avg}$ & $m_{avg}$ & $m_{max}$ & $O_{end}$ & $M_{end}$ \\\\\n");
printf(" & (nodes) & (m) & (m) & (deg) & (ms) & (ms) & (ms) & (MB) & (MB) \\\\\n");
}
else
{
printf("\\begin{tabular}{l|c|c|c|c|c|c|c|c}\n");
printf("\\cline{2-9}\n");
printf(" & Size & $t_{end}$ & $t_{max}$ & $r_{end}$ & $o_{avg}$ & $m_{avg}$ & $m_{max}$ & $M_{end}$ \\\\\n");
printf(" & (nodes) & (m) & (m) & (deg) & (ms) & (ms) & (ms) & (MB) \\\\\n");
}
printf("\\hline\n");
for(unsigned int j=0; j<outputLatexStatistics.size(); ++j)
{
if(outputLatexStatistics[j].size())
{
std::vector<int> lowestIndex;
if(outputLatexStatistics[j].size() > 1)
{
std::vector<float> lowestValue(outputLatexStatistics[j].begin()->second.size(),-1);
lowestIndex = std::vector<int>(lowestValue.size(),0);
int index = 0;
for(std::map<std::string, std::vector<float> >::iterator iter=outputLatexStatistics[j].begin(); iter!=outputLatexStatistics[j].end(); ++iter)
{
UASSERT(lowestValue.size() == iter->second.size());
for(unsigned int i=0; i<iter->second.size(); ++i)
{
if(lowestValue[i] == -1 || (iter->second[i]>0.0f && lowestValue[i]>iter->second[i]))
{
lowestValue[i] = iter->second[i];
lowestIndex[i] = index;
}
}
++index;
}
}
int index = 0;
for(std::map<std::string, std::vector<float> >::iterator iter=outputLatexStatistics[j].begin(); iter!=outputLatexStatistics[j].end(); ++iter)
{
UASSERT(iter->second.size() == 9);
printf("%s & ", uReplaceChar(iter->first.c_str(), '_', '-').c_str());
printf("%d & ", (int)iter->second[0]);
printf("%s%.3f%s & ", lowestIndex.size()&&lowestIndex[1]==index?"\\textbf{":"", iter->second[1], lowestIndex.size()&&lowestIndex[1]==index?"}":"");
printf("%s%.3f%s & ", lowestIndex.size()&&lowestIndex[2]==index?"\\textbf{":"", iter->second[2], lowestIndex.size()&&lowestIndex[2]==index?"}":"");
printf("%s%.2f%s & ", lowestIndex.size()&&lowestIndex[3]==index?"\\textbf{":"", iter->second[3], lowestIndex.size()&&lowestIndex[3]==index?"}":"");
printf("%s%d%s & ", lowestIndex.size()&&lowestIndex[4]==index?"\\textbf{":"", (int)iter->second[4], lowestIndex.size()&&lowestIndex[4]==index?"}":"");
printf("%s%d%s & ", lowestIndex.size()&&lowestIndex[5]==index?"\\textbf{":"", (int)iter->second[5], lowestIndex.size()&&lowestIndex[5]==index?"}":"");
printf("%s%d%s & ", lowestIndex.size()&&lowestIndex[6]==index?"\\textbf{":"", (int)iter->second[6], lowestIndex.size()&&lowestIndex[6]==index?"}":"");
if(odomRAMSet)
{
printf("%s%d%s & ", lowestIndex.size()&&lowestIndex[7]==index?"\\textbf{":"", (int)iter->second[7], lowestIndex.size()&&lowestIndex[7]==index?"}":"");
}
printf("%s%d%s ", lowestIndex.size()&&lowestIndex[8]==index?"\\textbf{":"", (int)iter->second[8], lowestIndex.size()&&lowestIndex[8]==index?"}":"");
printf("\\\\\n");
++index;
}
printf("\\hline\n");
}
}
printf("\\end{tabular}\n");
printf("\\end{table*}\n----------------\n");
}
if(figures.size())
{
for(std::map<std::string, UPlot*>::iterator iter=figures.begin(); iter!=figures.end(); ++iter)
{
iter->second->show();
}
return app.exec();
}
return 0; return 0;
} }
+52
View File
@@ -0,0 +1,52 @@
SET(RTABMap_INCLUDE_DIRS
${PROJECT_SOURCE_DIR}/utilite/include
${PROJECT_SOURCE_DIR}/corelib/include
)
SET(RTABMap_LIBRARIES
rtabmap_core
rtabmap_utilite
)
if(POLICY CMP0020)
cmake_policy(SET CMP0020 OLD)
endif()
SET(INCLUDE_DIRS
${RTABMap_INCLUDE_DIRS}
${OpenCV_INCLUDE_DIRS}
${PCL_INCLUDE_DIRS}
)
SET(LIBRARIES
${RTABMap_LIBRARIES}
${OpenCV_LIBRARIES}
${PCL_LIBRARIES}
)
IF(OCTOMAP_FOUND)
SET(INCLUDE_DIRS
${INCLUDE_DIRS}
${OCTOMAP_INCLUDE_DIRS}
)
SET(LIBRARIES
${LIBRARIES}
${OCTOMAP_LIBRARIES}
)
ENDIF(OCTOMAP_FOUND)
INCLUDE_DIRECTORIES(${INCLUDE_DIRS})
ADD_EXECUTABLE(reprocess main.cpp)
TARGET_LINK_LIBRARIES(reprocess ${LIBRARIES})
SET_TARGET_PROPERTIES( reprocess
PROPERTIES OUTPUT_NAME ${PROJECT_PREFIX}-reprocess)
INSTALL(TARGETS reprocess
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT runtime
BUNDLE DESTINATION "${CMAKE_BUNDLE_LOCATION}" COMPONENT runtime)
+428
View File
@@ -0,0 +1,428 @@
/*
Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Universite de Sherbrooke nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <rtabmap/core/Rtabmap.h>
#include <rtabmap/core/DBDriver.h>
#include <rtabmap/core/DBReader.h>
#ifdef RTABMAP_OCTOMAP
#include <rtabmap/core/OctoMap.h>
#endif
#include <rtabmap/core/OccupancyGrid.h>
#include <rtabmap/utilite/UFile.h>
#include <rtabmap/utilite/UDirectory.h>
#include <rtabmap/utilite/UTimer.h>
#include <rtabmap/utilite/UStl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pcl/io/pcd_io.h>
using namespace rtabmap;
void showUsage()
{
printf("\nUsage:\n"
"rtabmap-reprocess [options] \"input.db\" \"output.db\"\n"
" Options:\n"
" -r Use database stamps as input rate.\n"
" -g2 Assemble 2D occupancy grid map and save it to \"[output]_map.pgm\".\n"
" -g3 Assemble 3D cloud map and save it to \"[output]_map.pcd\".\n"
" -o2 Assemble OctoMap 2D projection and save it to \"[output]_octomap.pgm\".\n"
" -o3 Assemble OctoMap 3D cloud and save it to \"[output]_octomap.pcd\".\n"
"%s\n"
"\n", Parameters::showUsage());
exit(1);
}
class RecoveryProgressState: public ProgressState
{
virtual bool callback(const std::string & msg) const
{
if(!msg.empty())
printf("%s\n", msg.c_str());
return true;
}
};
int main(int argc, char * argv[])
{
ULogger::setType(ULogger::kTypeConsole);
ULogger::setLevel(ULogger::kError);
if(argc < 3)
{
showUsage();
}
bool assemble2dMap = false;
bool assemble3dMap = false;
bool assemble2dOctoMap = false;
bool assemble3dOctoMap = false;
bool useDatabaseRate = false;
for(int i=1; i<argc-2; ++i)
{
if(strcmp(argv[i], "-r") == 0)
{
useDatabaseRate = true;
printf("Using database stamps as input rate.\n");
}
else if(strcmp(argv[i], "-g2") == 0)
{
assemble2dMap = true;
printf("2D occupancy grid will be assembled (-g2 option).\n");
}
else if(strcmp(argv[i], "-g3") == 0)
{
assemble3dMap = true;
printf("3D cloud map will be assembled (-g3 option).\n");
}
else if(strcmp(argv[i], "-o2") == 0)
{
#ifdef RTABMAP_OCTOMAP
assemble2dOctoMap = true;
printf("OctoMap will be assembled (-o2 option).\n");
#else
printf("RTAB-Map is not built with OctoMap support, cannot set -o2 option!\n");
#endif
}
else if(strcmp(argv[i], "-o3") == 0)
{
#ifdef RTABMAP_OCTOMAP
assemble3dOctoMap = true;
printf("OctoMap will be assembled (-o3 option).\n");
#else
printf("RTAB-Map is not built with OctoMap support, cannot set -o3 option!\n");
#endif
}
}
ParametersMap customParameters = Parameters::parseArguments(argc, argv);
std::string inputDatabasePath = uReplaceChar(argv[argc-2], '~', UDirectory::homeDir());
std::string outputDatabasePath = uReplaceChar(argv[argc-1], '~', UDirectory::homeDir());
if(!UFile::exists(inputDatabasePath))
{
printf("Input database \"%s\" doesn't exist!\n", inputDatabasePath.c_str());
return -1;
}
if(UFile::getExtension(inputDatabasePath).compare("db") != 0)
{
printf("File \"%s\" is not a database format (*.db)!\n", inputDatabasePath.c_str());
return -1;
}
if(UFile::getExtension(outputDatabasePath).compare("db") != 0)
{
printf("File \"%s\" is not a database format (*.db)!\n", outputDatabasePath.c_str());
return -1;
}
if(UFile::exists(outputDatabasePath))
{
UFile::erase(outputDatabasePath);
}
DBDriver * dbDriver = DBDriver::create();
if(!dbDriver->openConnection(inputDatabasePath, false))
{
printf("Failed opening input database!\n");
delete dbDriver;
return -1;
}
ParametersMap parameters = dbDriver->getLastParameters();
if(parameters.empty())
{
printf("Failed getting parameters from database, reprocessing cannot be done. Database version may be too old.\n");
dbDriver->closeConnection(false);
delete dbDriver;
return -1;
}
if(customParameters.size())
{
printf("Custom parameters:\n");
for(ParametersMap::iterator iter=customParameters.begin(); iter!=customParameters.end(); ++iter)
{
printf(" %s\t= %s\n", iter->first.c_str(), iter->second.c_str());
}
}
uInsert(parameters, customParameters);
std::set<int> ids;
dbDriver->getAllNodeIds(ids);
if(ids.empty())
{
printf("Input database doesn't have any nodes saved in it.\n");
dbDriver->closeConnection(false);
delete dbDriver;
return -1;
}
dbDriver->closeConnection(false);
delete dbDriver;
Rtabmap rtabmap;
rtabmap.init(parameters, outputDatabasePath);
bool odometryIgnored = false;
Parameters::parse(parameters, Parameters::kRGBDEnabled(), odometryIgnored);
DBReader dbReader(inputDatabasePath, useDatabaseRate?-1:0, !odometryIgnored);
dbReader.init();
OccupancyGrid grid(parameters);
grid.setCloudAssembling(assemble3dMap);
#ifdef RTABMAP_OCTOMAP
OctoMap octomap(parameters);
#endif
printf("Reprocessing data of \"%s\"...\n", inputDatabasePath.c_str());
std::map<std::string, float> globalMapStats;
int processed = 0;
CameraInfo info;
SensorData data = dbReader.takeImage(&info);
while(data.isValid())
{
UTimer iterationTime;
std::string status;
if(!odometryIgnored && info.odomPose.isNull())
{
printf("Skipping node %d as it doesn't have odometry pose set.\n", data.id());
}
else
{
if(!odometryIgnored && !info.odomCovariance.empty() && info.odomCovariance.at<double>(0,0)>=9999)
{
printf("High variance detected, triggering a new map...\n");
rtabmap.triggerNewMap();
}
if(!rtabmap.process(data, info.odomPose, info.odomCovariance, info.odomVelocity, globalMapStats))
{
printf("Failed processing node %d.\n", data.id());
globalMapStats.clear();
}
else if(assemble2dMap || assemble3dMap || assemble2dOctoMap || assemble3dOctoMap)
{
globalMapStats.clear();
double timeUpdateInit = 0.0;
double timeUpdateGrid = 0.0;
double timeUpdateOctoMap = 0.0;
const rtabmap::Statistics & stats = rtabmap.getStatistics();
UTimer t;
if(stats.poses().size() && stats.getSignatures().size())
{
int id = stats.poses().rbegin()->first;
if(stats.getSignatures().find(id)!=stats.getSignatures().end() &&
stats.getSignatures().find(id)->second.sensorData().gridCellSize() > 0.0f)
{
bool updateGridMap = false;
bool updateOctoMap = false;
if((assemble2dMap || assemble3dMap) && grid.addedNodes().find(id) == grid.addedNodes().end())
{
updateGridMap = true;
}
#ifdef RTABMAP_OCTOMAP
if((assemble2dOctoMap || assemble3dOctoMap) && octomap.addedNodes().find(id) == octomap.addedNodes().end())
{
updateOctoMap = true;
}
#endif
if(updateGridMap || updateOctoMap)
{
cv::Mat ground, obstacles;
stats.getSignatures().find(id)->second.sensorData().uncompressDataConst(0, 0, 0, 0, &ground, &obstacles);
const cv::Point3f & viewpoint = stats.getSignatures().find(id)->second.sensorData().gridViewPoint();
timeUpdateInit = t.ticks();
if(updateGridMap)
{
grid.addToCache(id, ground, obstacles);
grid.update(stats.poses());
timeUpdateGrid = t.ticks() + timeUpdateInit;
}
#ifdef RTABMAP_OCTOMAP
if(updateOctoMap)
{
octomap.addToCache(id, ground, obstacles, viewpoint);
octomap.update(stats.poses());
timeUpdateOctoMap = t.ticks() + timeUpdateInit;
}
#endif
}
}
}
//Simulate publishing
double timePub2dOctoMap = 0.0;
double timePub3dOctoMap = 0.0;
if(assemble2dOctoMap)
{
float xMin, yMin, size;
octomap.createProjectionMap(xMin, yMin, size);
timePub2dOctoMap = t.ticks();
}
if(assemble3dOctoMap)
{
octomap.createCloud();
timePub3dOctoMap = t.ticks();
}
globalMapStats.insert(std::make_pair(std::string("GlobalGrid/GridUpdate/ms"), timeUpdateGrid*1000.0f));
globalMapStats.insert(std::make_pair(std::string("GlobalGrid/OctoMapUpdate/ms"), timeUpdateOctoMap*1000.0f));
globalMapStats.insert(std::make_pair(std::string("GlobalGrid/OctoMapProjection/ms"), timePub2dOctoMap*1000.0f));
globalMapStats.insert(std::make_pair(std::string("GlobalGrid/OctomapToCloud/ms"), timePub3dOctoMap*1000.0f));
}
}
printf("Processed %d/%d nodes... %dms\n", ++processed, (int)ids.size(), int(iterationTime.ticks()*1000));
data = dbReader.takeImage(&info);
}
printf("Closing database \"%s\"...\n", outputDatabasePath.c_str());
rtabmap.close(true);
printf("Closing database \"%s\"... done!\n", outputDatabasePath.c_str());
if(assemble2dMap)
{
std::string outputPath = outputDatabasePath.substr(0, outputDatabasePath.size()-3) + "_map.pgm";
float xMin,yMin;
cv::Mat map = grid.getMap(xMin, yMin);
if(!map.empty())
{
cv::Mat map8U(map.rows, map.cols, CV_8U);
//convert to gray scaled map
for (int i = 0; i < map.rows; ++i)
{
for (int j = 0; j < map.cols; ++j)
{
char v = map.at<char>(i, j);
unsigned char gray;
if(v == 0)
{
gray = 178;
}
else if(v == 100)
{
gray = 0;
}
else // -1
{
gray = 89;
}
map8U.at<unsigned char>(i, j) = gray;
}
}
if(cv::imwrite(outputPath, map8U))
{
printf("Saving occupancy grid \"%s\"... done!\n", outputPath.c_str());
}
else
{
printf("Saving occupancy grid \"%s\"... failed!\n", outputPath.c_str());
}
}
else
{
printf("2D map is empty! Cannot save it!\n");
}
}
if(assemble3dMap)
{
std::string outputPath = outputDatabasePath.substr(0, outputDatabasePath.size()-3) + "_map.pcd";
if(pcl::io::savePCDFileBinary(outputPath, *grid.getMapObstacles()) == 0)
{
printf("Saving 3d cloud map \"%s\"... done!\n", outputPath.c_str());
}
else
{
printf("Saving 3d cloud map \"%s\"... failed!\n", outputPath.c_str());
}
}
#ifdef RTABMAP_OCTOMAP
if(assemble2dOctoMap)
{
std::string outputPath = outputDatabasePath.substr(0, outputDatabasePath.size()-3) + "_octomap.pgm";
float xMin,yMin,cellSize;
cv::Mat map = octomap.createProjectionMap(xMin, yMin, cellSize);
if(!map.empty())
{
cv::Mat map8U(map.rows, map.cols, CV_8U);
//convert to gray scaled map
for (int i = 0; i < map.rows; ++i)
{
for (int j = 0; j < map.cols; ++j)
{
char v = map.at<char>(i, j);
unsigned char gray;
if(v == 0)
{
gray = 178;
}
else if(v == 100)
{
gray = 0;
}
else // -1
{
gray = 89;
}
map8U.at<unsigned char>(i, j) = gray;
}
}
if(cv::imwrite(outputPath, map8U))
{
printf("Saving octomap 2D projection \"%s\"... done!\n", outputPath.c_str());
}
else
{
printf("Saving octomap 2D projection \"%s\"... failed!\n", outputPath.c_str());
}
}
else
{
printf("OctoMap 2D projection map is empty! Cannot save it!\n");
}
}
if(assemble3dOctoMap)
{
std::string outputPath = outputDatabasePath.substr(0, outputDatabasePath.size()-3) + "_octomap.pcd";
std::vector<int> obstacles;
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud = octomap.createCloud(0, &obstacles);
if(pcl::io::savePCDFile(outputPath, *cloud, obstacles, true) == 0)
{
printf("Saving octomap cloud \"%s\"... done!\n", outputPath.c_str());
}
else
{
printf("Saving octomap cloud \"%s\"... failed!\n", outputPath.c_str());
}
}
#endif
return 0;
}
+4
View File
@@ -35,3 +35,7 @@ TARGET_LINK_LIBRARIES(rgbd_dataset ${LIBRARIES})
SET_TARGET_PROPERTIES( rgbd_dataset SET_TARGET_PROPERTIES( rgbd_dataset
PROPERTIES OUTPUT_NAME ${PROJECT_PREFIX}-rgbd_dataset) PROPERTIES OUTPUT_NAME ${PROJECT_PREFIX}-rgbd_dataset)
INSTALL(TARGETS rgbd_dataset
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT runtime
BUNDLE DESTINATION "${CMAKE_BUNDLE_LOCATION}" COMPONENT runtime)
+67 -40
View File
@@ -39,6 +39,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "rtabmap/utilite/UFile.h" #include "rtabmap/utilite/UFile.h"
#include "rtabmap/utilite/UMath.h" #include "rtabmap/utilite/UMath.h"
#include "rtabmap/utilite/UStl.h" #include "rtabmap/utilite/UStl.h"
#include "rtabmap/utilite/UProcessInfo.h"
#include <pcl/common/common.h> #include <pcl/common/common.h>
#include <stdio.h> #include <stdio.h>
#include <signal.h> #include <signal.h>
@@ -54,7 +55,8 @@ void showUsage()
" synchronized images using associate.py tool (use tool version from\n" " synchronized images using associate.py tool (use tool version from\n"
" https://gist.github.com/matlabbe/484134a2d9da8ad425362c6669824798). If \n" " https://gist.github.com/matlabbe/484134a2d9da8ad425362c6669824798). If \n"
" \"groundtruth.txt\" is found in the sequence folder, they will be saved in the database.\n" " \"groundtruth.txt\" is found in the sequence folder, they will be saved in the database.\n"
" --output Output directory. By default, results are saved in \"path\".\n\n" " --output Output directory. By default, results are saved in \"path\".\n"
" --output_name Output database name (default \"rtabmap\").\n"
" --quiet Don't show log messages and iteration updates.\n" " --quiet Don't show log messages and iteration updates.\n"
"%s\n" "%s\n"
"Example:\n\n" "Example:\n\n"
@@ -97,6 +99,7 @@ int main(int argc, char * argv[])
ParametersMap parameters; ParametersMap parameters;
std::string path; std::string path;
std::string output; std::string output;
std::string outputName = "rtabmap";
bool quiet = false; bool quiet = false;
if(argc < 2) if(argc < 2)
{ {
@@ -110,6 +113,10 @@ int main(int argc, char * argv[])
{ {
output = argv[++i]; output = argv[++i];
} }
else if(std::strcmp(argv[i], "--output_name") == 0)
{
outputName = argv[++i];
}
else if(std::strcmp(argv[i], "--quiet") == 0) else if(std::strcmp(argv[i], "--quiet") == 0)
{ {
quiet = true; quiet = true;
@@ -128,6 +135,8 @@ int main(int argc, char * argv[])
output = uReplaceChar(output, '~', UDirectory::homeDir()); output = uReplaceChar(output, '~', UDirectory::homeDir());
UDirectory::makeDir(output); UDirectory::makeDir(output);
} }
parameters.insert(ParametersPair(Parameters::kRtabmapWorkingDirectory(), output));
parameters.insert(ParametersPair(Parameters::kRtabmapPublishRAMUsage(), "true"));
} }
std::string seq = uSplit(path, '/').back(); std::string seq = uSplit(path, '/').back();
@@ -150,12 +159,14 @@ int main(int argc, char * argv[])
" Dataset path: %s\n" " Dataset path: %s\n"
" RGB path: %s\n" " RGB path: %s\n"
" Depth path: %s\n" " Depth path: %s\n"
" Output: %s\n", " Output: %s\n"
" Output name: %s\n",
seq.c_str(), seq.c_str(),
path.c_str(), path.c_str(),
pathRgbImages.c_str(), pathRgbImages.c_str(),
pathDepthImages.c_str(), pathDepthImages.c_str(),
output.c_str()); output.c_str(),
outputName.c_str());
if(!pathGt.empty()) if(!pathGt.empty())
{ {
printf(" groundtruth.txt: %s\n", pathGt.c_str()); printf(" groundtruth.txt: %s\n", pathGt.c_str());
@@ -177,16 +188,15 @@ int main(int argc, char * argv[])
float depthFactor = 5.0f; float depthFactor = 5.0f;
if(sequenceName.find("freiburg1") != std::string::npos) if(sequenceName.find("freiburg1") != std::string::npos)
{ {
model = CameraModel("rtabmap_calib", 517.3, 516.5, 318.6, 255.3, opticalRotation, 0, cv::Size(640,480)); model = CameraModel(outputName+"_calib", 517.3, 516.5, 318.6, 255.3, opticalRotation, 0, cv::Size(640,480));
} }
else if(sequenceName.find("freiburg2") != std::string::npos) else if(sequenceName.find("freiburg2") != std::string::npos)
{ {
model = CameraModel("rtabmap_calib", 520.9, 521.0, 325.1, 249.7, opticalRotation, 0, cv::Size(640,480)); model = CameraModel(outputName+"_calib", 520.9, 521.0, 325.1, 249.7, opticalRotation, 0, cv::Size(640,480));
depthFactor = 5.208f; // based on TUM2.yaml ORB_SLAM2 file
} }
else //if(sequenceName.find("freiburg3") != std::string::npos) else //if(sequenceName.find("freiburg3") != std::string::npos)
{ {
model = CameraModel("rtabmap_calib", 535.4, 539.2, 320.1, 247.6, opticalRotation, 0, cv::Size(640,480)); model = CameraModel(outputName+"_calib", 535.4, 539.2, 320.1, 247.6, opticalRotation, 0, cv::Size(640,480));
} }
//parameters.insert(ParametersPair(Parameters::kg2oBaseline(), uNumber2Str(40.0f/model.fx()))); //parameters.insert(ParametersPair(Parameters::kg2oBaseline(), uNumber2Str(40.0f/model.fx())));
model.save(path); model.save(path);
@@ -206,17 +216,20 @@ int main(int argc, char * argv[])
bool intermediateNodes = Parameters::defaultRtabmapCreateIntermediateNodes(); bool intermediateNodes = Parameters::defaultRtabmapCreateIntermediateNodes();
float detectionRate = Parameters::defaultRtabmapDetectionRate(); float detectionRate = Parameters::defaultRtabmapDetectionRate();
Parameters::parse(parameters, Parameters::kRtabmapCreateIntermediateNodes(), intermediateNodes); int odomStrategy = Parameters::defaultOdomStrategy();
Parameters::parse(parameters, Parameters::kOdomStrategy(), odomStrategy);
Parameters::parse(parameters, Parameters::kRtabmapDetectionRate(), detectionRate); Parameters::parse(parameters, Parameters::kRtabmapDetectionRate(), detectionRate);
std::string databasePath = output+"/"+seq+".db"; std::string databasePath = output+"/"+outputName+".db";
UFile::erase(databasePath); UFile::erase(databasePath);
if(cameraThread.camera()->init(path, "rtabmap_calib")) if(cameraThread.camera()->init(path, outputName+"_calib"))
{ {
int totalImages = (int)((CameraRGBDImages*)cameraThread.camera())->filenames().size(); int totalImages = (int)((CameraRGBDImages*)cameraThread.camera())->filenames().size();
printf("Processing %d images...\n", totalImages); printf("Processing %d images...\n", totalImages);
Odometry * odom = Odometry::create(parameters); ParametersMap odomParameters = parameters;
odomParameters.erase(Parameters::kRtabmapPublishRAMUsage()); // as odometry is in the same process than rtabmap, don't get RAM usage in odometry.
Odometry * odom = Odometry::create(odomParameters);
Rtabmap rtabmap; Rtabmap rtabmap;
rtabmap.init(parameters, databasePath); rtabmap.init(parameters, databasePath);
@@ -234,34 +247,21 @@ int main(int argc, char * argv[])
double previousStamp = 0.0; double previousStamp = 0.0;
while(data.isValid() && g_forever) while(data.isValid() && g_forever)
{ {
std::map<std::string, float> externalStats;
cameraThread.postUpdate(&data, &cameraInfo); cameraThread.postUpdate(&data, &cameraInfo);
cameraInfo.timeTotal = timer.ticks(); cameraInfo.timeTotal = timer.ticks();
// save camera statistics to database
externalStats.insert(std::make_pair("Camera/BilateralFiltering/ms", cameraInfo.timeBilateralFiltering*1000.0f));
externalStats.insert(std::make_pair("Camera/Capture/ms", cameraInfo.timeCapture*1000.0f));
externalStats.insert(std::make_pair("Camera/Disparity/ms", cameraInfo.timeDisparity*1000.0f));
externalStats.insert(std::make_pair("Camera/ImageDecimation/ms", cameraInfo.timeImageDecimation*1000.0f));
externalStats.insert(std::make_pair("Camera/Mirroring/ms", cameraInfo.timeMirroring*1000.0f));
externalStats.insert(std::make_pair("Camera/ScanFromDepth/ms", cameraInfo.timeScanFromDepth*1000.0f));
externalStats.insert(std::make_pair("Camera/TotalTime/ms", cameraInfo.timeTotal*1000.0f));
externalStats.insert(std::make_pair("Camera/UndistortDepth/ms", cameraInfo.timeUndistortDepth*1000.0f));
OdometryInfo odomInfo; OdometryInfo odomInfo;
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/LocalBundleConstraints/", odomInfo.localBundleConstraints)); if(odomStrategy == 2)
externalStats.insert(std::make_pair("Odometry/LocalBundleOutliers/", odomInfo.localBundleOutliers)); {
externalStats.insert(std::make_pair("Odometry/TotalTime/ms", odomInfo.timeEstimation*1000.0f)); //special case for FOVIS, set covariance 1 if 9999 is detected
externalStats.insert(std::make_pair("Odometry/Registration/ms", odomInfo.reg.totalTime*1000.0f)); if(!odomInfo.reg.covariance.empty() && odomInfo.reg.covariance.at<double>(0,0) >= 9999)
externalStats.insert(std::make_pair("Odometry/Inliers/", odomInfo.reg.inliers)); {
externalStats.insert(std::make_pair("Odometry/Features/", odomInfo.features)); odomInfo.reg.covariance = cv::Mat::eye(6,6,CV_64FC1);
externalStats.insert(std::make_pair("Odometry/DistanceTravelled/m", odomInfo.distanceTravelled)); }
externalStats.insert(std::make_pair("Odometry/KeyFrameAdded/", odomInfo.keyFrameAdded)); }
externalStats.insert(std::make_pair("Odometry/LocalKeyFrames/", odomInfo.localKeyFrames));
externalStats.insert(std::make_pair("Odometry/LocalMapSize/", odomInfo.localMapSize));
externalStats.insert(std::make_pair("Odometry/LocalScanMapSize/", odomInfo.localScanMapSize));
if(odomInfo.keyFrameAdded) if(odomInfo.keyFrameAdded)
{ {
++odomKeyFrames; ++odomKeyFrames;
@@ -295,6 +295,31 @@ int main(int argc, char * argv[])
timer.restart(); timer.restart();
if(processData) if(processData)
{ {
std::map<std::string, float> externalStats;
// save camera statistics to database
externalStats.insert(std::make_pair("Camera/BilateralFiltering/ms", cameraInfo.timeBilateralFiltering*1000.0f));
externalStats.insert(std::make_pair("Camera/Capture/ms", cameraInfo.timeCapture*1000.0f));
externalStats.insert(std::make_pair("Camera/Disparity/ms", cameraInfo.timeDisparity*1000.0f));
externalStats.insert(std::make_pair("Camera/ImageDecimation/ms", cameraInfo.timeImageDecimation*1000.0f));
externalStats.insert(std::make_pair("Camera/Mirroring/ms", cameraInfo.timeMirroring*1000.0f));
externalStats.insert(std::make_pair("Camera/ExposureCompensation/ms", cameraInfo.timeStereoExposureCompensation*1000.0f));
externalStats.insert(std::make_pair("Camera/ScanFromDepth/ms", cameraInfo.timeScanFromDepth*1000.0f));
externalStats.insert(std::make_pair("Camera/TotalTime/ms", cameraInfo.timeTotal*1000.0f));
externalStats.insert(std::make_pair("Camera/UndistortDepth/ms", cameraInfo.timeUndistortDepth*1000.0f));
// save odometry statistics to database
externalStats.insert(std::make_pair("Odometry/LocalBundle/ms", odomInfo.localBundleTime*1000.0f));
externalStats.insert(std::make_pair("Odometry/LocalBundleConstraints/", odomInfo.localBundleConstraints));
externalStats.insert(std::make_pair("Odometry/LocalBundleOutliers/", odomInfo.localBundleOutliers));
externalStats.insert(std::make_pair("Odometry/TotalTime/ms", odomInfo.timeEstimation*1000.0f));
externalStats.insert(std::make_pair("Odometry/Registration/ms", odomInfo.reg.totalTime*1000.0f));
externalStats.insert(std::make_pair("Odometry/Inliers/", odomInfo.reg.inliers));
externalStats.insert(std::make_pair("Odometry/Features/", odomInfo.features));
externalStats.insert(std::make_pair("Odometry/DistanceTravelled/m", odomInfo.distanceTravelled));
externalStats.insert(std::make_pair("Odometry/KeyFrameAdded/", odomInfo.keyFrameAdded));
externalStats.insert(std::make_pair("Odometry/LocalKeyFrames/", odomInfo.localKeyFrames));
externalStats.insert(std::make_pair("Odometry/LocalMapSize/", odomInfo.localMapSize));
externalStats.insert(std::make_pair("Odometry/LocalScanMapSize/", odomInfo.localScanMapSize));
OdometryEvent e(SensorData(), Transform(), odomInfo); OdometryEvent e(SensorData(), Transform(), odomInfo);
rtabmap.process(data, pose, covariance, e.velocity(), externalStats); rtabmap.process(data, pose, covariance, e.velocity(), externalStats);
covariance = cv::Mat(); covariance = cv::Mat();
@@ -313,8 +338,10 @@ int main(int argc, char * argv[])
if(rmse >= 0.0f) if(rmse >= 0.0f)
{ {
printf("Iteration %d/%d: camera=%dms, odom(quality=%d/%d, kfs=%d)=%dms, slam=%dms, rmse=%fm, noise stddev=%fm %frad", //printf("Iteration %d/%d: camera=%dms, odom(quality=%d/%d, kfs=%d)=%dms, slam=%dms, rmse=%fm, noise stddev=%fm %frad",
iteration, totalImages, int(cameraInfo.timeTotal*1000.0f), odomInfo.reg.inliers, odomInfo.features, odomKeyFrames, int(odomInfo.timeEstimation*1000.0f), int(slamTime*1000.0f), rmse, sqrt(odomInfo.reg.covariance.at<double>(0,0)), sqrt(odomInfo.reg.covariance.at<double>(3,3))); // iteration, totalImages, int(cameraInfo.timeTotal*1000.0f), odomInfo.reg.inliers, odomInfo.features, odomKeyFrames, int(odomInfo.timeEstimation*1000.0f), int(slamTime*1000.0f), rmse, sqrt(odomInfo.reg.covariance.at<double>(0,0)), sqrt(odomInfo.reg.covariance.at<double>(3,3)));
printf("Iteration %d/%d: camera=%dms, odom(quality=%d/%d, kfs=%d)=%dms, slam=%dms, rmse=%fm",
iteration, totalImages, int(cameraInfo.timeTotal*1000.0f), odomInfo.reg.inliers, odomInfo.features, odomKeyFrames, int(odomInfo.timeEstimation*1000.0f), int(slamTime*1000.0f), rmse);
} }
else else
{ {
@@ -354,7 +381,7 @@ int main(int argc, char * argv[])
{ {
stamps.insert(std::make_pair(iter->first, iter->second.getStamp())); stamps.insert(std::make_pair(iter->first, iter->second.getStamp()));
} }
std::string pathTrajectory = output+"/"+seq+"_poses.txt"; std::string pathTrajectory = output+"/"+outputName+"_poses.txt";
if(poses.size() && graph::exportPoses(pathTrajectory, 1, poses, links, stamps)) if(poses.size() && graph::exportPoses(pathTrajectory, 1, poses, links, stamps))
{ {
printf("Saving %s... done!\n", pathTrajectory.c_str()); printf("Saving %s... done!\n", pathTrajectory.c_str());
@@ -418,7 +445,7 @@ int main(int argc, char * argv[])
printf(" rotational_rmse= %f deg\n", rotational_rmse); printf(" rotational_rmse= %f deg\n", rotational_rmse);
FILE * pFile = 0; FILE * pFile = 0;
std::string pathErrors = output+"/"+seq+"_rmse.txt"; std::string pathErrors = output+"/"+outputName+"_rmse.txt";
pFile = fopen(pathErrors.c_str(),"w"); pFile = fopen(pathErrors.c_str(),"w");
if(!pFile) if(!pFile)
{ {
@@ -445,9 +472,9 @@ int main(int argc, char * argv[])
UERROR("Camera init failed!"); UERROR("Camera init failed!");
} }
printf("Saving rtabmap database (with all statistics) to \"%s\"\n", (output+"/"+seq+".db").c_str()); printf("Saving rtabmap database (with all statistics) to \"%s\"\n", (output+"/"+outputName+".db").c_str());
printf("Do:\n" printf("Do:\n"
" $ rtabmap-databaseViewer %s\n\n", (output+"/"+seq+".db").c_str()); " $ rtabmap-databaseViewer %s\n\n", (output+"/"+outputName+".db").c_str());
return 0; return 0;
} }
+3 -2
View File
@@ -18,6 +18,7 @@
*/ */
#include "rtabmap/utilite/UConversion.h" #include "rtabmap/utilite/UConversion.h"
#include "rtabmap/utilite/UStl.h"
#include <sstream> #include <sstream>
#include <string.h> #include <string.h>
@@ -153,12 +154,12 @@ std::string uBool2Str(bool boolean)
bool uStr2Bool(const char * str) bool uStr2Bool(const char * str)
{ {
return !(str && (strcmp(str, "false") == 0 || strcmp(str, "FALSE") == 0 || strcmp(str, "0") == 0)); return !(str && (uStrContains(str, "false") || uStrContains(str, "FALSE") || strcmp(str, "0") == 0));
} }
bool uStr2Bool(const std::string & str) bool uStr2Bool(const std::string & str)
{ {
return !(str.compare("false") == 0 || str.compare("FALSE") == 0 || str.compare("0") == 0); return !(uStrContains(str, "false") || uStrContains(str, "FALSE") || str.compare("0") == 0);
} }
std::vector<unsigned char> uStr2Bytes(const std::string & str) std::vector<unsigned char> uStr2Bytes(const std::string & str)