mirror of
https://github.com/introlab/rtabmap.git
synced 2026-10-04 00:57:46 +08:00
Added DBDriver tests
This commit is contained in:
@@ -50,45 +50,91 @@ class Signature;
|
|||||||
class VWDictionary;
|
class VWDictionary;
|
||||||
class VisualWord;
|
class VisualWord;
|
||||||
|
|
||||||
// Todo This class needs a refactoring, the _dbSafeAccessMutex problem when the trash is emptying (transaction)
|
/**
|
||||||
// "Of course, it has always been the case and probably always will be
|
* @class DBDriver
|
||||||
//that you cannot use the same sqlite3 connection in two or more
|
* @brief Abstract database driver for RTAB-Map maps (signatures, links, words, statistics).
|
||||||
//threads at the same time. You can use different sqlite3 connections
|
*
|
||||||
//at the same time in different threads, or you can move the same
|
* DBDriver is the persistence layer used by @ref Memory, @ref DBReader and tools that
|
||||||
//sqlite3 connection across threads (subject to the constraints above)
|
* read or write \c .db files. The default implementation is @ref DBDriverSqlite3, created
|
||||||
//but never, never try to use the same connection simultaneously in
|
* by @ref create().
|
||||||
//two or more threads."
|
*
|
||||||
//
|
* The driver extends @ref UThreadNode: pending @ref Signature and @ref VisualWord objects
|
||||||
|
* are queued with @ref asyncSave() and flushed to the database by @ref emptyTrashes()
|
||||||
|
* (also called from the background thread on @ref closeConnection()).
|
||||||
|
*
|
||||||
|
* Public methods are thread-safe where noted (mutex-protected wrappers). Subclasses
|
||||||
|
* implement SQL-specific logic in protected \c *Query() virtual methods.
|
||||||
|
*
|
||||||
|
* @see DBDriverSqlite3
|
||||||
|
* @see Memory
|
||||||
|
*/
|
||||||
class RTABMAP_CORE_EXPORT DBDriver : public UThreadNode
|
class RTABMAP_CORE_EXPORT DBDriver : public UThreadNode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Factory: returns a SQLite database driver (@ref DBDriverSqlite3).
|
||||||
|
* @param parameters Optional driver parameters (e.g. @ref Parameters::kDbTargetVersion()).
|
||||||
|
* @return New driver instance; caller owns the pointer.
|
||||||
|
*/
|
||||||
static DBDriver * create(const ParametersMap & parameters = ParametersMap());
|
static DBDriver * create(const ParametersMap & parameters = ParametersMap());
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~DBDriver();
|
virtual ~DBDriver();
|
||||||
|
|
||||||
|
/** @brief Parse driver parameters from the map (e.g. target schema version). */
|
||||||
virtual void parseParameters(const ParametersMap & parameters);
|
virtual void parseParameters(const ParametersMap & parameters);
|
||||||
|
/**
|
||||||
|
* @brief True when no database file URL was set at open time.
|
||||||
|
* @note @ref DBDriverSqlite3 overrides this when @ref Parameters::kDbSqlite3InMemory() is enabled.
|
||||||
|
*/
|
||||||
virtual bool isInMemory() const {return _url.empty();}
|
virtual bool isInMemory() const {return _url.empty();}
|
||||||
|
/** @return Database file path last passed to @ref openConnection(). */
|
||||||
const std::string & getUrl() const {return _url;}
|
const std::string & getUrl() const {return _url;}
|
||||||
|
/** @return Target schema version for new databases (from parameters). */
|
||||||
const std::string & getTargetVersion() const {return _targetVersion;}
|
const std::string & getTargetVersion() const {return _targetVersion;}
|
||||||
|
|
||||||
void beginTransaction() const;
|
/** @brief Queue a signature for deferred save; ownership is transferred. */
|
||||||
void commit() const;
|
void asyncSave(Signature * s);
|
||||||
|
/** @brief Queue a visual word for deferred save; ownership is transferred. */
|
||||||
void asyncSave(Signature * s); //ownership transferred
|
void asyncSave(VisualWord * vw);
|
||||||
void asyncSave(VisualWord * vw); //ownership transferred
|
/**
|
||||||
|
* @brief Flush queued signatures and visual words to the database.
|
||||||
|
* @param async If true, signal the background thread instead of flushing synchronously.
|
||||||
|
*/
|
||||||
void emptyTrashes(bool async = false);
|
void emptyTrashes(bool async = false);
|
||||||
double getEmptyTrashesTime() const {return _emptyTrashesTime;}
|
double getEmptyTrashesTime() const {return _emptyTrashesTime;}
|
||||||
void setTimestampUpdateEnabled(bool enabled) {_timestampUpdate = enabled;} // used on Update Signature and Word queries
|
void setTimestampUpdateEnabled(bool enabled) {_timestampUpdate = enabled;} // used on Update Signature and Word queries
|
||||||
|
|
||||||
// Warning: the following functions don't look in the trash, direct database modifications
|
/**
|
||||||
|
* @brief Export the pose graph to a Graphviz DOT file for visualization.
|
||||||
|
*
|
||||||
|
* Reads nodes and links from the database (and optionally from @p otherSignatures
|
||||||
|
* not yet persisted) and writes @p fileName. Does not modify the database.
|
||||||
|
* If @p ids is empty, all node ids are included.
|
||||||
|
*/
|
||||||
void generateGraph(
|
void generateGraph(
|
||||||
const std::string & fileName,
|
const std::string & fileName,
|
||||||
const std::set<int> & ids = std::set<int>(),
|
const std::set<int> & ids = std::set<int>(),
|
||||||
const std::map<int, Signature *> & otherSignatures = std::map<int, Signature *>());
|
const std::map<int, Signature *> & otherSignatures = std::map<int, Signature *>());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Direct database updates
|
||||||
|
* @brief Write node or link data immediately (not via the async trash).
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/** @brief Insert or replace a link in the database. */
|
||||||
void addLink(const Link & link);
|
void addLink(const Link & link);
|
||||||
|
/** @brief Remove a link between two nodes. */
|
||||||
void removeLink(int from, int to);
|
void removeLink(int from, int to);
|
||||||
|
/** @brief Update an existing link in the database. */
|
||||||
void updateLink(const Link & link);
|
void updateLink(const Link & link);
|
||||||
|
/**
|
||||||
|
* @brief Update occupancy grid cells for a node.
|
||||||
|
* @param ground Ground cells (raw @c CV_32FC2/@c CV_32FC3, or compressed @c CV_8UC1 1×N).
|
||||||
|
* @param obstacles Obstacle cells (same formats as @p ground).
|
||||||
|
* @param empty Empty cells (same formats as @p ground; ignored on DB schema < 0.16.0).
|
||||||
|
* Raw mats are compressed internally via @ref SensorData::setOccupancyGrid() before writing.
|
||||||
|
*/
|
||||||
void updateOccupancyGrid(
|
void updateOccupancyGrid(
|
||||||
int nodeId,
|
int nodeId,
|
||||||
const cv::Mat & ground,
|
const cv::Mat & ground,
|
||||||
@@ -96,22 +142,61 @@ public:
|
|||||||
const cv::Mat & empty,
|
const cv::Mat & empty,
|
||||||
float cellSize,
|
float cellSize,
|
||||||
const cv::Point3f & viewpoint);
|
const cv::Point3f & viewpoint);
|
||||||
|
/** @brief Update camera calibration stored for a node. */
|
||||||
void updateCalibration(
|
void updateCalibration(
|
||||||
int nodeId,
|
int nodeId,
|
||||||
const std::vector<CameraModel> & models,
|
const std::vector<CameraModel> & models,
|
||||||
const std::vector<StereoCameraModel> & stereoModels);
|
const std::vector<StereoCameraModel> & stereoModels);
|
||||||
|
/**
|
||||||
|
* @brief Update the depth image stored for a node.
|
||||||
|
* @param image Raw depth image, or pre-compressed blob (@c CV_8UC1, single row).
|
||||||
|
* @param format Compression format when @p image is raw (e.g. @c ".png"); ignored if already compressed.
|
||||||
|
* Uncompressed images are compressed with @ref Compression::compressImage2() before writing.
|
||||||
|
*/
|
||||||
void updateDepthImage(int nodeId, const cv::Mat & image, const std::string & format);
|
void updateDepthImage(int nodeId, const cv::Mat & image, const std::string & format);
|
||||||
|
/**
|
||||||
|
* @brief Update the laser scan stored for a node.
|
||||||
|
* @param scan Uncompressed scan, or already compressed (@ref LaserScan::isCompressed()).
|
||||||
|
* Uncompressed data is compressed with @ref Compression::compressData2() before writing.
|
||||||
|
*/
|
||||||
void updateLaserScan(int nodeId, const LaserScan & scan);
|
void updateLaserScan(int nodeId, const LaserScan & scan);
|
||||||
|
/** @} */
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @name Session exports and map artifacts
|
||||||
|
* @brief Statistics, preview image, optimized poses, 2D map, mesh and FLANN index.
|
||||||
|
* @{*/
|
||||||
void addInfoAfterRun(int stMemSize, int lastSignAdded, int processMemUsed, int databaseMemUsed, int dictionarySize, const ParametersMap & parameters) const;
|
void addInfoAfterRun(int stMemSize, int lastSignAdded, int processMemUsed, int databaseMemUsed, int dictionarySize, const ParametersMap & parameters) const;
|
||||||
|
/**
|
||||||
|
* @brief Append a @ref Statistics record for a processed node.
|
||||||
|
* @param statistics Metrics for @ref Statistics::refImageId() (insert skipped if id ≤ 0 or data empty).
|
||||||
|
* @param saveWmState If true and schema ≥ 0.16.2, also store compressed working-memory state.
|
||||||
|
*/
|
||||||
void addStatistics(const Statistics & statistics, bool saveWmState) const;
|
void addStatistics(const Statistics & statistics, bool saveWmState) const;
|
||||||
|
/**
|
||||||
|
* @brief Save the map preview thumbnail in the Admin table.
|
||||||
|
* @param image Raw image or JPEG-compressed blob (@c CV_8UC1, single row); empty clears it.
|
||||||
|
* @note Requires database schema ≥ 0.12.0.
|
||||||
|
*/
|
||||||
void savePreviewImage(const cv::Mat & image) const;
|
void savePreviewImage(const cv::Mat & image) const;
|
||||||
|
/** @brief Load and uncompress the map preview thumbnail from the Admin table. */
|
||||||
cv::Mat loadPreviewImage() const;
|
cv::Mat loadPreviewImage() const;
|
||||||
|
/** @brief Persist graph-optimized poses and last localization pose. */
|
||||||
void saveOptimizedPoses(const std::map<int, Transform> & optimizedPoses, const Transform & lastlocalizationPose) const;
|
void saveOptimizedPoses(const std::map<int, Transform> & optimizedPoses, const Transform & lastlocalizationPose) const;
|
||||||
|
/** @brief Load optimized poses; optional last localization pose output. */
|
||||||
std::map<int, Transform> loadOptimizedPoses(Transform * lastlocalizationPose = 0) const;
|
std::map<int, Transform> loadOptimizedPoses(Transform * lastlocalizationPose = 0) const;
|
||||||
|
/** @brief Save the assembled 2D occupancy grid and its origin metadata. */
|
||||||
void save2DMap(const cv::Mat & map, float xMin, float yMin, float cellSize) const;
|
void save2DMap(const cv::Mat & map, float xMin, float yMin, float cellSize) const;
|
||||||
|
/** @brief Load the 2D map and fill origin/cell size outputs. */
|
||||||
cv::Mat load2DMap(float & xMin, float & yMin, float & cellSize) const;
|
cv::Mat load2DMap(float & xMin, float & yMin, float & cellSize) const;
|
||||||
|
/**
|
||||||
|
* @brief Persist the global optimized 3D mesh to the database.
|
||||||
|
* @param cloud Point cloud (@c CV_32FC1 or @c CV_32FC3).
|
||||||
|
* @param polygons Optional per-texture polygon index lists (texture → polygon → vertex indices).
|
||||||
|
* @param texCoords Optional UV coordinates per texture (one per polygon vertex).
|
||||||
|
* @param textures Optional concatenated square texture images (same size per texture).
|
||||||
|
*/
|
||||||
void saveOptimizedMesh(
|
void saveOptimizedMesh(
|
||||||
const cv::Mat & cloud,
|
const cv::Mat & cloud,
|
||||||
const std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > & polygons = std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > >(), // Textures -> polygons -> vertices
|
const std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > & polygons = std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > >(), // Textures -> polygons -> vertices
|
||||||
@@ -129,15 +214,27 @@ public:
|
|||||||
std::vector<std::vector<Eigen::Vector2f> > * texCoords = 0,
|
std::vector<std::vector<Eigen::Vector2f> > * texCoords = 0,
|
||||||
#endif
|
#endif
|
||||||
cv::Mat * textures = 0) const;
|
cv::Mat * textures = 0) const;
|
||||||
|
/**
|
||||||
|
* @brief Persist the visual word dictionary FLANN index (serialized blob).
|
||||||
|
* @param indexData Serialized index from @ref VWDictionary::serializeIndex(); pass empty to clear.
|
||||||
|
* @note Requires database schema ≥ 0.23.0. Used when @ref Parameters::kKpFlannIndexSaved() is enabled.
|
||||||
|
*/
|
||||||
void saveFlannIndex(const std::vector<unsigned char> & indexData) const;
|
void saveFlannIndex(const std::vector<unsigned char> & indexData) const;
|
||||||
|
/** @} */
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Mutex-protected methods of abstract versions below
|
/**
|
||||||
|
* @name Connection and database introspection
|
||||||
|
* @brief Mutex-protected wrappers around protected \c *Query() methods.
|
||||||
|
* @{*/
|
||||||
|
/** @brief Open or create the database at @p url (empty @p url uses an in-memory database). */
|
||||||
bool openConnection(const std::string & url, bool overwritten = false, bool readOnly = false);
|
bool openConnection(const std::string & url, bool overwritten = false, bool readOnly = false);
|
||||||
|
/** @brief Close the connection; optionally flush trashes and save in-memory DB to @p outputUrl. */
|
||||||
void closeConnection(bool save = true, const std::string & outputUrl = "");
|
void closeConnection(bool save = true, const std::string & outputUrl = "");
|
||||||
|
/** @return True if a database connection is active. */
|
||||||
bool isConnected() const;
|
bool isConnected() const;
|
||||||
unsigned long getMemoryUsed() const; // In bytes
|
unsigned long getMemoryUsed() const; // In bytes
|
||||||
|
/** @return Schema version string stored in the database (e.g. "0.21.0"). */
|
||||||
std::string getDatabaseVersion() const;
|
std::string getDatabaseVersion() const;
|
||||||
long getNodesMemoryUsed() const;
|
long getNodesMemoryUsed() const;
|
||||||
long getLinksMemoryUsed() const;
|
long getLinksMemoryUsed() const;
|
||||||
@@ -159,11 +256,33 @@ public:
|
|||||||
std::map<int, std::pair<std::map<std::string, float>, double> > getAllStatistics() const;
|
std::map<int, std::pair<std::map<std::string, float>, double> > getAllStatistics() const;
|
||||||
std::map<int, std::vector<int> > getAllStatisticsWmStates() const;
|
std::map<int, std::vector<int> > getAllStatisticsWmStates() const;
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Run a SQL statement that does not return result rows.
|
||||||
|
*
|
||||||
|
* Executes @p sql on the open database (e.g. @c INSERT, @c UPDATE, @c DELETE,
|
||||||
|
* @c CREATE, @c PRAGMA). Thread-safe wrapper around @ref executeNoResultQuery().
|
||||||
|
*
|
||||||
|
* For reads, use the dedicated @ref loadSignature(), @ref loadLinks() and related
|
||||||
|
* query methods instead of raw SQL.
|
||||||
|
*
|
||||||
|
* @param sql Complete SQL statement (SQLite syntax for @ref DBDriverSqlite3).
|
||||||
|
* @note The connection must be open (@ref isConnected()). On failure the driver
|
||||||
|
* aborts with an assertion (SQLite backend).
|
||||||
|
* @warning @p sql is passed verbatim; sanitize any user-controlled values before calling.
|
||||||
|
*/
|
||||||
void executeNoResult(const std::string & sql) const;
|
void executeNoResult(const std::string & sql) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Load and query
|
||||||
|
* @brief Load signatures, words, links and node metadata from the database.
|
||||||
|
* @{*/
|
||||||
|
|
||||||
// Load objects
|
// Load objects
|
||||||
void load(VWDictionary & dictionary, bool lastStateOnly = true) const;
|
void load(VWDictionary & dictionary, bool lastStateOnly = true) const;
|
||||||
void loadLastNodes(std::list<Signature *> & signatures, bool loadWordIdsOnly = false) const; // returned signatures must be freed after usage
|
void loadLastNodes(std::list<Signature *> & signatures, bool loadWordIdsOnly = false) const; // returned signatures must be freed after usage
|
||||||
|
/** @brief Load one signature by id; caller must delete the returned pointer. */
|
||||||
Signature * loadSignature(int id, bool * loadedFromTrash = 0); // returned signature must be freed after usage, call loadSignatures() instead if more than one signature should be loaded
|
Signature * loadSignature(int id, bool * loadedFromTrash = 0); // returned signature must be freed after usage, call loadSignatures() instead if more than one signature should be loaded
|
||||||
void loadSignatures(const std::list<int> & ids, std::list<Signature *> & signatures, std::set<int> * loadedFromTrash = 0, bool loadWordIdsOnly = false); // returned signatures must be freed after usage
|
void loadSignatures(const std::list<int> & ids, std::list<Signature *> & signatures, std::set<int> * loadedFromTrash = 0, bool loadWordIdsOnly = false); // returned signatures must be freed after usage
|
||||||
void loadWords(const std::set<int> & wordIds, std::list<VisualWord *> & vws); // returned words must be freed after usage
|
void loadWords(const std::set<int> & wordIds, std::list<VisualWord *> & vws); // returned words must be freed after usage
|
||||||
@@ -176,6 +295,7 @@ public:
|
|||||||
bool getLaserScanInfo(int signatureId, LaserScan & info) const;
|
bool getLaserScanInfo(int signatureId, LaserScan & info) const;
|
||||||
bool getNodeInfo(int signatureId, Transform & pose, int & mapId, int & weight, std::string & label, double & stamp, Transform & groundTruthPose, std::vector<float> & velocity, GPS & gps, EnvSensors & sensors) const;
|
bool getNodeInfo(int signatureId, Transform & pose, int & mapId, int & weight, std::string & label, double & stamp, Transform & groundTruthPose, std::vector<float> & velocity, GPS & gps, EnvSensors & sensors) const;
|
||||||
void getLocalFeatures(int signatureId, std::multimap<int, int> & words, std::vector<cv::KeyPoint> & keypoints, std::vector<cv::Point3f> & points, cv::Mat & descriptors) const;
|
void getLocalFeatures(int signatureId, std::multimap<int, int> & words, std::vector<cv::KeyPoint> & keypoints, std::vector<cv::Point3f> & points, cv::Mat & descriptors) const;
|
||||||
|
/** @brief Load outgoing links from @p signatureId, optionally filtered by @p type. */
|
||||||
void loadLinks(int signatureId, std::multimap<int, Link> & links, Link::Type type = Link::kUndef) const;
|
void loadLinks(int signatureId, std::multimap<int, Link> & links, Link::Type type = Link::kUndef) const;
|
||||||
void getWeight(int signatureId, int & weight) const;
|
void getWeight(int signatureId, int & weight) const;
|
||||||
void getLastNodeIds(std::set<int> & ids) const;
|
void getLastNodeIds(std::set<int> & ids) const;
|
||||||
@@ -189,10 +309,18 @@ public:
|
|||||||
void getNodesObservingLandmark(int landmarkId, std::map<int, Link> & nodes) const;
|
void getNodesObservingLandmark(int landmarkId, std::map<int, Link> & nodes) const;
|
||||||
void getNodeIdByLabel(const std::string & label, int & id) const;
|
void getNodeIdByLabel(const std::string & label, int & id) const;
|
||||||
void getAllLabels(std::map<int, std::string> & labels) const;
|
void getAllLabels(std::map<int, std::string> & labels) const;
|
||||||
|
/** @} */
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
/**
|
||||||
|
* @brief Protected constructor for subclasses.
|
||||||
|
*/
|
||||||
DBDriver(const ParametersMap & parameters = ParametersMap());
|
DBDriver(const ParametersMap & parameters = ParametersMap());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Backend implementation (subclass responsibility)
|
||||||
|
* @brief Pure virtual SQL/backend hooks invoked by public wrappers above.
|
||||||
|
* @{*/
|
||||||
virtual bool connectDatabaseQuery(const std::string & url, bool overwritten = false, bool readOnly = false) = 0;
|
virtual bool connectDatabaseQuery(const std::string & url, bool overwritten = false, bool readOnly = false) = 0;
|
||||||
virtual void disconnectDatabaseQuery(bool save = true, const std::string & outputUrl = "") = 0;
|
virtual void disconnectDatabaseQuery(bool save = true, const std::string & outputUrl = "") = 0;
|
||||||
virtual bool isConnectedQuery() const = 0;
|
virtual bool isConnectedQuery() const = 0;
|
||||||
@@ -299,8 +427,14 @@ protected:
|
|||||||
virtual void getNodesObservingLandmarkQuery(int landmarkId, std::map<int, Link> & nodes) const = 0;
|
virtual void getNodesObservingLandmarkQuery(int landmarkId, std::map<int, Link> & nodes) const = 0;
|
||||||
virtual void getNodeIdByLabelQuery(const std::string & label, int & id) const = 0;
|
virtual void getNodeIdByLabelQuery(const std::string & label, int & id) const = 0;
|
||||||
virtual void getAllLabelsQuery(std::map<int, std::string> & labels) const = 0;
|
virtual void getAllLabelsQuery(std::map<int, std::string> & labels) const = 0;
|
||||||
|
/** @} */
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/** @brief Begin a database transaction (nested calls are serialized). */
|
||||||
|
void beginTransaction() const;
|
||||||
|
/** @brief Commit the current transaction. */
|
||||||
|
void commit() const;
|
||||||
|
|
||||||
//non-abstract methods
|
//non-abstract methods
|
||||||
void saveOrUpdate(const std::vector<Signature *> & signatures);
|
void saveOrUpdate(const std::vector<Signature *> & signatures);
|
||||||
void saveOrUpdate(const std::vector<VisualWord *> & words) const;
|
void saveOrUpdate(const std::vector<VisualWord *> & words) const;
|
||||||
|
|||||||
@@ -121,6 +121,11 @@ add_executable(test_odometry test_odometry.cpp)
|
|||||||
target_link_libraries(test_odometry gtest_main rtabmap_core)
|
target_link_libraries(test_odometry gtest_main rtabmap_core)
|
||||||
gtest_discover_tests(test_odometry)
|
gtest_discover_tests(test_odometry)
|
||||||
|
|
||||||
|
#DBDriver.h
|
||||||
|
add_executable(test_dbdriver test_dbdriver.cpp)
|
||||||
|
target_link_libraries(test_dbdriver gtest_main rtabmap_core)
|
||||||
|
gtest_discover_tests(test_dbdriver)
|
||||||
|
|
||||||
#Signature.h
|
#Signature.h
|
||||||
add_executable(test_signature test_signature.cpp)
|
add_executable(test_signature test_signature.cpp)
|
||||||
target_link_libraries(test_signature gtest_main rtabmap_core)
|
target_link_libraries(test_signature gtest_main rtabmap_core)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user