0.17.0: saving optimized poses and last localization pose to database (https://github.com/introlab/rtabmap_ros/issues/220). Parameters: fixed Icp default parameters when not built with libpointmatcher, added RGBD/SavedLocalizationIgnored (default false). DbViewer: added Export/Import 2D map (https://github.com/introlab/rtabmap_ros/issues/213).

This commit is contained in:
matlabbe
2018-04-04 19:14:13 -04:00
parent 34b32f53f6
commit 592b7c66c5
25 changed files with 756 additions and 183 deletions

View File

@@ -1061,9 +1061,37 @@ cv::Mat DBDriver::loadPreviewImage() const
return image;
}
void DBDriver::saveOptimizedPoses(const std::map<int, Transform> & optimizedPoses, const Transform & lastlocalizationPose) const
{
_dbSafeAccessMutex.lock();
saveOptimizedPosesQuery(optimizedPoses, lastlocalizationPose);
_dbSafeAccessMutex.unlock();
}
std::map<int, Transform> DBDriver::loadOptimizedPoses(Transform * lastlocalizationPose) const
{
_dbSafeAccessMutex.lock();
std::map<int, Transform> poses = loadOptimizedPosesQuery(lastlocalizationPose);
_dbSafeAccessMutex.unlock();
return poses;
}
void DBDriver::save2DMap(const cv::Mat & map, float xMin, float yMin, float cellSize) const
{
_dbSafeAccessMutex.lock();
save2DMapQuery(map, xMin, yMin, cellSize);
_dbSafeAccessMutex.unlock();
}
cv::Mat DBDriver::load2DMap(float & xMin, float & yMin, float & cellSize) const
{
_dbSafeAccessMutex.lock();
cv::Mat map = load2DMapQuery(xMin, yMin, cellSize);
_dbSafeAccessMutex.unlock();
return map;
}
void DBDriver::saveOptimizedMesh(
const cv::Mat & cloud,
const std::map<int, Transform> & poses,
const std::vector<std::vector<std::vector<unsigned int> > > & polygons,
#if PCL_VERSION_COMPARE(>=, 1, 8, 0)
const std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > & texCoords,
@@ -1073,12 +1101,11 @@ void DBDriver::saveOptimizedMesh(
const cv::Mat & textures) const
{
_dbSafeAccessMutex.lock();
saveOptimizedMeshQuery(cloud, poses, polygons, texCoords, textures);
saveOptimizedMeshQuery(cloud, polygons, texCoords, textures);
_dbSafeAccessMutex.unlock();
}
cv::Mat DBDriver::loadOptimizedMesh(
std::map<int, Transform> * poses,
std::vector<std::vector<std::vector<unsigned int> > > * polygons,
#if PCL_VERSION_COMPARE(>=, 1, 8, 0)
std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > * texCoords,
@@ -1088,7 +1115,7 @@ cv::Mat DBDriver::loadOptimizedMesh(
cv::Mat * textures) const
{
_dbSafeAccessMutex.lock();
cv::Mat cloud = loadOptimizedMeshQuery(poses, polygons, texCoords, textures);
cv::Mat cloud = loadOptimizedMeshQuery(polygons, texCoords, textures);
_dbSafeAccessMutex.unlock();
return cloud;
}

View File

@@ -4277,9 +4277,274 @@ cv::Mat DBDriverSqlite3::loadPreviewImageQuery() const
return image;
}
void DBDriverSqlite3::saveOptimizedPosesQuery(const std::map<int, Transform> & poses, const Transform & lastlocalizationPose) const
{
UDEBUG("");
if(_ppDb && uStrNumCmp(_version, "0.17.0") >= 0)
{
UTimer timer;
timer.start();
int rc = SQLITE_OK;
sqlite3_stmt * ppStmt = 0;
std::string query;
// Update table Admin
query = uFormat("UPDATE Admin SET opt_ids=?, opt_poses=?, opt_last_localization=?, time_enter = DATETIME('NOW') WHERE version='%s';", _version.c_str());
rc = sqlite3_prepare_v2(_ppDb, query.c_str(), -1, &ppStmt, 0);
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
int index = 1;
// opt ids and poses
cv::Mat compressedIds;
cv::Mat compressedPoses;
if(poses.empty())
{
rc = sqlite3_bind_null(ppStmt, index++);
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
rc = sqlite3_bind_null(ppStmt, index++);
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
}
else
{
std::vector<int> serializedIds(poses.size());
std::vector<float> serializedPoses(poses.size()*12);
int i=0;
for(std::map<int, Transform>::const_iterator iter=poses.begin(); iter!=poses.end(); ++iter)
{
serializedIds[i] = iter->first;
memcpy(serializedPoses.data()+(12*i), iter->second.data(), 12*sizeof(float));
++i;
}
compressedIds = compressData2(cv::Mat(1,serializedIds.size(), CV_32SC1, serializedIds.data()));
compressedPoses = compressData2(cv::Mat(1,serializedPoses.size(), CV_32FC1, serializedPoses.data()));
rc = sqlite3_bind_blob(ppStmt, index++, compressedIds.data, compressedIds.cols, SQLITE_STATIC);
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
rc = sqlite3_bind_blob(ppStmt, index++, compressedPoses.data, compressedPoses.cols, SQLITE_STATIC);
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
}
if(lastlocalizationPose.isNull())
{
rc = sqlite3_bind_null(ppStmt, index++);
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
}
else
{
UDEBUG("lastlocalizationPose=%s", lastlocalizationPose.prettyPrint().c_str());
rc = sqlite3_bind_blob(ppStmt, index++, lastlocalizationPose.data(), lastlocalizationPose.size()*sizeof(float), SQLITE_STATIC);
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
}
//execute query
rc=sqlite3_step(ppStmt);
UASSERT_MSG(rc == SQLITE_DONE, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
// Finalize (delete) the statement
rc = sqlite3_finalize(ppStmt);
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
UDEBUG("Time=%fs", timer.ticks());
}
}
std::map<int, Transform> DBDriverSqlite3::loadOptimizedPosesQuery(Transform * lastlocalizationPose) const
{
UDEBUG("");
std::map<int, Transform> poses;
if(_ppDb && uStrNumCmp(_version, "0.17.0") >= 0)
{
UTimer timer;
timer.start();
int rc = SQLITE_OK;
sqlite3_stmt * ppStmt = 0;
std::stringstream query;
query << "SELECT opt_ids, opt_poses, opt_last_localization "
<< "FROM Admin "
<< "WHERE version='" << _version.c_str()
<<"';";
rc = sqlite3_prepare_v2(_ppDb, query.str().c_str(), -1, &ppStmt, 0);
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
// Process the result if one
rc = sqlite3_step(ppStmt);
UASSERT_MSG(rc == SQLITE_ROW, uFormat("DB error (%s): Not found first Admin row: query=\"%s\"", _version.c_str(), query.str().c_str()).c_str());
if(rc == SQLITE_ROW)
{
const void * data = 0;
int dataSize = 0;
int index = 0;
//opt_poses
cv::Mat serializedIds;
data = sqlite3_column_blob(ppStmt, index);
dataSize = sqlite3_column_bytes(ppStmt, index++);
if(dataSize>0 && data)
{
serializedIds = uncompressData(cv::Mat(1, dataSize, CV_8UC1, (void *)data));
UDEBUG("serializedIds=%d", serializedIds.cols);
}
data = sqlite3_column_blob(ppStmt, index);
dataSize = sqlite3_column_bytes(ppStmt, index++);
if(dataSize>0 && data)
{
cv::Mat serializedPoses = uncompressData(cv::Mat(1, dataSize, CV_8UC1, (void *)data));
UDEBUG("serializedPoses=%d", serializedPoses.cols);
UASSERT(serializedIds.cols == serializedPoses.cols/12);
UASSERT(serializedPoses.type() == CV_32FC1);
UASSERT(serializedIds.type() == CV_32SC1);
for(int i=0; i<serializedIds.cols; ++i)
{
Transform t(serializedPoses.at<float>(i*12), serializedPoses.at<float>(i*12+1), serializedPoses.at<float>(i*12+2), serializedPoses.at<float>(i*12+3),
serializedPoses.at<float>(i*12+4), serializedPoses.at<float>(i*12+5), serializedPoses.at<float>(i*12+6), serializedPoses.at<float>(i*12+7),
serializedPoses.at<float>(i*12+8), serializedPoses.at<float>(i*12+9), serializedPoses.at<float>(i*12+10), serializedPoses.at<float>(i*12+11));
poses.insert(std::make_pair(serializedIds.at<int>(i), t));
UDEBUG("Optimized pose %d: %s", serializedIds.at<int>(i), t.prettyPrint().c_str());
}
}
data = sqlite3_column_blob(ppStmt, index); // ground_truth_pose
dataSize = sqlite3_column_bytes(ppStmt, index++);
if(lastlocalizationPose)
{
if((unsigned int)dataSize == lastlocalizationPose->size()*sizeof(float) && data)
{
memcpy(lastlocalizationPose->data(), data, dataSize);
}
UDEBUG("lastlocalizationPose=%s", lastlocalizationPose->prettyPrint().c_str());
}
rc = sqlite3_step(ppStmt); // next result...
}
UASSERT_MSG(rc == SQLITE_DONE, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
// Finalize (delete) the statement
rc = sqlite3_finalize(ppStmt);
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
ULOGGER_DEBUG("Time=%fs", timer.ticks());
}
return poses;
}
void DBDriverSqlite3::save2DMapQuery(const cv::Mat & map, float xMin, float yMin, float cellSize) const
{
UDEBUG("");
if(_ppDb && uStrNumCmp(_version, "0.17.0") >= 0)
{
UTimer timer;
timer.start();
int rc = SQLITE_OK;
sqlite3_stmt * ppStmt = 0;
std::string query;
// Update table Admin
query = uFormat("UPDATE Admin SET opt_map=?, opt_map_x_min=?, opt_map_y_min=?, opt_map_resolution=?, time_enter = DATETIME('NOW') WHERE version='%s';", _version.c_str());
rc = sqlite3_prepare_v2(_ppDb, query.c_str(), -1, &ppStmt, 0);
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
int index = 1;
// opt ids and poses
cv::Mat compressedMap;
if(map.empty())
{
rc = sqlite3_bind_null(ppStmt, index++);
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
}
else
{
compressedMap = compressData2(map);
rc = sqlite3_bind_blob(ppStmt, index++, compressedMap.data, compressedMap.cols, SQLITE_STATIC);
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
}
rc = sqlite3_bind_double(ppStmt, index++, xMin);
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
rc = sqlite3_bind_double(ppStmt, index++, yMin);
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
rc = sqlite3_bind_double(ppStmt, index++, cellSize);
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
//execute query
rc=sqlite3_step(ppStmt);
UASSERT_MSG(rc == SQLITE_DONE, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
// Finalize (delete) the statement
rc = sqlite3_finalize(ppStmt);
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
UDEBUG("Time=%fs", timer.ticks());
}
}
cv::Mat DBDriverSqlite3::load2DMapQuery(float & xMin, float & yMin, float & cellSize) const
{
UDEBUG("");
cv::Mat map;
if(_ppDb && uStrNumCmp(_version, "0.17.0") >= 0)
{
UTimer timer;
timer.start();
int rc = SQLITE_OK;
sqlite3_stmt * ppStmt = 0;
std::stringstream query;
query << "SELECT opt_map, opt_map_x_min, opt_map_y_min, opt_map_resolution "
<< "FROM Admin "
<< "WHERE version='" << _version.c_str()
<<"';";
rc = sqlite3_prepare_v2(_ppDb, query.str().c_str(), -1, &ppStmt, 0);
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
// Process the result if one
rc = sqlite3_step(ppStmt);
UASSERT_MSG(rc == SQLITE_ROW, uFormat("DB error (%s): Not found first Admin row: query=\"%s\"", _version.c_str(), query.str().c_str()).c_str());
if(rc == SQLITE_ROW)
{
const void * data = 0;
int dataSize = 0;
int index = 0;
//opt_map
data = sqlite3_column_blob(ppStmt, index);
dataSize = sqlite3_column_bytes(ppStmt, index++);
if(dataSize>0 && data)
{
map = uncompressData(cv::Mat(1, dataSize, CV_8UC1, (void *)data));
UDEBUG("map=%d/%d", map.cols, map.rows);
}
xMin = sqlite3_column_double(ppStmt, index++);
UDEBUG("xMin=%f", xMin);
yMin = sqlite3_column_double(ppStmt, index++);
UDEBUG("yMin=%f", yMin);
cellSize = sqlite3_column_double(ppStmt, index++);
UDEBUG("cellSize=%f", cellSize);
rc = sqlite3_step(ppStmt); // next result...
}
UASSERT_MSG(rc == SQLITE_DONE, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
// Finalize (delete) the statement
rc = sqlite3_finalize(ppStmt);
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
ULOGGER_DEBUG("Time=%fs", timer.ticks());
}
return map;
}
void DBDriverSqlite3::saveOptimizedMeshQuery(
const cv::Mat & cloud,
const std::map<int, Transform> & poses,
const std::vector<std::vector<std::vector<unsigned int> > > & polygons,
#if PCL_VERSION_COMPARE(>=, 1, 8, 0)
const std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > & texCoords,
@@ -4298,7 +4563,7 @@ void DBDriverSqlite3::saveOptimizedMeshQuery(
std::string query;
// Update table Admin
query = uFormat("UPDATE Admin SET opt_cloud=?, opt_ids=?, opt_poses=?, opt_polygons_size=?, opt_polygons=?, opt_tex_coords=?, opt_tex_materials=?, time_enter = DATETIME('NOW') WHERE version='%s';", _version.c_str());
query = uFormat("UPDATE Admin SET opt_cloud=?, opt_polygons_size=?, opt_polygons=?, opt_tex_coords=?, opt_tex_materials=?, time_enter = DATETIME('NOW') WHERE version='%s';", _version.c_str());
rc = sqlite3_prepare_v2(_ppDb, query.c_str(), -1, &ppStmt, 0);
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
@@ -4336,39 +4601,9 @@ void DBDriverSqlite3::saveOptimizedMeshQuery(
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
// opt ids and poses
cv::Mat compressedIds;
cv::Mat compressedPoses;
cv::Mat compressedPolygons;
cv::Mat compressedTexCoords;
cv::Mat compressedTextures;
if(poses.empty())
{
rc = sqlite3_bind_null(ppStmt, index++);
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
rc = sqlite3_bind_null(ppStmt, index++);
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
}
else
{
std::vector<int> serializedIds(poses.size());
std::vector<float> serializedPoses(poses.size()*12);
int i=0;
for(std::map<int, Transform>::const_iterator iter=poses.begin(); iter!=poses.end(); ++iter)
{
serializedIds[i] = iter->first;
memcpy(serializedPoses.data()+(12*i), iter->second.data(), 12*sizeof(float));
++i;
}
compressedIds = compressData2(cv::Mat(1,serializedIds.size(), CV_32SC1, serializedIds.data()));
compressedPoses = compressData2(cv::Mat(1,serializedPoses.size(), CV_32FC1, serializedPoses.data()));
rc = sqlite3_bind_blob(ppStmt, index++, compressedIds.data, compressedIds.cols, SQLITE_STATIC);
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
rc = sqlite3_bind_blob(ppStmt, index++, compressedPoses.data, compressedPoses.cols, SQLITE_STATIC);
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
}
// polygons
if(polygons.empty())
{
@@ -4505,7 +4740,6 @@ void DBDriverSqlite3::saveOptimizedMeshQuery(
}
cv::Mat DBDriverSqlite3::loadOptimizedMeshQuery(
std::map<int, Transform> * poses,
std::vector<std::vector<std::vector<unsigned int> > > * polygons,
#if PCL_VERSION_COMPARE(>=, 1, 8, 0)
std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > * texCoords,
@@ -4524,7 +4758,7 @@ cv::Mat DBDriverSqlite3::loadOptimizedMeshQuery(
sqlite3_stmt * ppStmt = 0;
std::stringstream query;
query << "SELECT opt_cloud, opt_ids, opt_poses, opt_polygons_size, opt_polygons, opt_tex_coords, opt_tex_materials "
query << "SELECT opt_cloud, opt_polygons_size, opt_polygons, opt_tex_coords, opt_tex_materials "
<< "FROM Admin "
<< "WHERE version='" << _version.c_str()
<<"';";
@@ -4560,29 +4794,6 @@ cv::Mat DBDriverSqlite3::loadOptimizedMeshQuery(
UDEBUG("serializedIds=%d", serializedIds.cols);
}
data = sqlite3_column_blob(ppStmt, index);
dataSize = sqlite3_column_bytes(ppStmt, index++);
if(dataSize>0 && data)
{
cv::Mat serializedPoses = uncompressData(cv::Mat(1, dataSize, CV_8UC1, (void *)data));
UDEBUG("serializedPoses=%d", serializedPoses.cols);
if(poses)
{
UASSERT(serializedIds.cols == serializedPoses.cols/12);
UASSERT(serializedPoses.type() == CV_32FC1);
UASSERT(serializedIds.type() == CV_32SC1);
for(int i=0; i<serializedIds.cols; ++i)
{
Transform t(serializedPoses.at<float>(i*12), serializedPoses.at<float>(i*12+1), serializedPoses.at<float>(i*12+2), serializedPoses.at<float>(i*12+3),
serializedPoses.at<float>(i*12+4), serializedPoses.at<float>(i*12+5), serializedPoses.at<float>(i*12+6), serializedPoses.at<float>(i*12+7),
serializedPoses.at<float>(i*12+8), serializedPoses.at<float>(i*12+9), serializedPoses.at<float>(i*12+10), serializedPoses.at<float>(i*12+11));
poses->insert(std::make_pair(serializedIds.at<int>(i), t));
UDEBUG("Optimized pose %d: %s", serializedIds.at<int>(i), t.prettyPrint().c_str());
}
}
}
//opt_polygons_size
int polygonSize = sqlite3_column_int(ppStmt, index++);
UDEBUG("polygonSize=%d", polygonSize);

View File

@@ -101,9 +101,12 @@ private:
virtual void addStatisticsQuery(const Statistics & statistics) const;
virtual void savePreviewImageQuery(const cv::Mat & image) const;
virtual cv::Mat loadPreviewImageQuery() const;
virtual void saveOptimizedPosesQuery(const std::map<int, Transform> & optimizedPoses, const Transform & lastlocalizationPose) const;
virtual std::map<int, Transform> loadOptimizedPosesQuery(Transform * lastlocalizationPose) const;
virtual void save2DMapQuery(const cv::Mat & map, float xMin, float yMin, float cellSize) const;
virtual cv::Mat load2DMapQuery(float & xMin, float & yMin, float & cellSize) const;
virtual void saveOptimizedMeshQuery(
const cv::Mat & cloud,
const std::map<int, Transform> & poses,
const std::vector<std::vector<std::vector<unsigned int> > > & polygons,
#if PCL_VERSION_COMPARE(>=, 1, 8, 0)
const std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > & texCoords,
@@ -112,7 +115,6 @@ private:
#endif
const cv::Mat & textures) const;
virtual cv::Mat loadOptimizedMeshQuery(
std::map<int, Transform> * poses,
std::vector<std::vector<std::vector<unsigned int> > > * polygons,
#if PCL_VERSION_COMPARE(>=, 1, 8, 0)
std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > * texCoords,

View File

@@ -361,7 +361,7 @@ void Memory::close(bool databaseSaved, bool postInitClosingEvents, const std::st
if(postInitClosingEvents) UEventsManager::post(new RtabmapEventInit(RtabmapEventInit::kClosing));
bool databaseNameChanged = false;
if(databaseSaved)
if(databaseSaved && _dbDriver)
{
databaseNameChanged = ouputDatabasePath.size() && _dbDriver->getUrl().size() && _dbDriver->getUrl().compare(ouputDatabasePath) != 0?true:false;
}
@@ -1756,9 +1756,42 @@ cv::Mat Memory::loadPreviewImage() const
return cv::Mat();
}
void Memory::saveOptimizedPoses(const std::map<int, Transform> & optimizedPoses, const Transform & lastlocalizationPose) const
{
if(_dbDriver)
{
_dbDriver->saveOptimizedPoses(optimizedPoses, lastlocalizationPose);
}
}
std::map<int, Transform> Memory::loadOptimizedPoses(Transform * lastlocalizationPose) const
{
if(_dbDriver)
{
return _dbDriver->loadOptimizedPoses(lastlocalizationPose);
}
return std::map<int, Transform>();
}
void Memory::save2DMap(const cv::Mat & map, float xMin, float yMin, float cellSize) const
{
if(_dbDriver)
{
_dbDriver->save2DMap(map, xMin, yMin, cellSize);
}
}
cv::Mat Memory::load2DMap(float & xMin, float & yMin, float & cellSize) const
{
if(_dbDriver)
{
return _dbDriver->load2DMap(xMin, yMin, cellSize);
}
return cv::Mat();
}
void Memory::saveOptimizedMesh(
const cv::Mat & cloud,
const std::map<int, Transform> & poses,
const std::vector<std::vector<std::vector<unsigned int> > > & polygons,
#if PCL_VERSION_COMPARE(>=, 1, 8, 0)
const std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > & texCoords,
@@ -1769,12 +1802,11 @@ void Memory::saveOptimizedMesh(
{
if(_dbDriver)
{
_dbDriver->saveOptimizedMesh(cloud, poses, polygons, texCoords, textures);
_dbDriver->saveOptimizedMesh(cloud, polygons, texCoords, textures);
}
}
cv::Mat Memory::loadOptimizedMesh(
std::map<int, Transform> * poses,
std::vector<std::vector<std::vector<unsigned int> > > * polygons,
#if PCL_VERSION_COMPARE(>=, 1, 8, 0)
std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > * texCoords,
@@ -1785,7 +1817,7 @@ cv::Mat Memory::loadOptimizedMesh(
{
if(_dbDriver)
{
return _dbDriver->loadOptimizedMesh(poses, polygons, texCoords, textures);
return _dbDriver->loadOptimizedMesh(polygons, texCoords, textures);
}
return cv::Mat();
}

View File

@@ -197,6 +197,24 @@ void OccupancyGrid::parseParameters(const ParametersMap & parameters)
}
}
void OccupancyGrid::setMap(const cv::Mat & map, float xMin, float yMin, float cellSize, const std::map<int, Transform> & poses)
{
UDEBUG("map=%d/%d xMin=%f yMin=%f cellSize=%f poses=%d",
map.cols, map.rows, xMin, yMin, cellSize, (int)poses.size());
this->clear();
if(!poses.empty() && !map.empty())
{
UASSERT(cellSize > 0.0f);
UASSERT(map.type() == CV_8SC1);
map_ = map.clone();
mapInfo_ = cv::Mat::zeros(map.size(), CV_32FC3);
xMin_ = xMin;
yMin_ = yMin;
cellSize_ = cellSize;
addedNodes_ = poses;
}
}
void OccupancyGrid::setCellSize(float cellSize)
{
UASSERT_MSG(cellSize > 0.0f, uFormat("Param name is \"%s\"", Parameters::kGridCellSize().c_str()).c_str());

View File

@@ -423,7 +423,7 @@ void RegistrationIcp::parseParameters(const ParametersMap & parameters)
#ifndef RTABMAP_POINTMATCHER
if(_libpointmatcher)
{
UWARN("Parameter %s is set to true but RTAB-MAp has not been built with libpointmatcher support. Setting to false.", Parameters::kIcpPM().c_str());
UWARN("Parameter %s is set to true but RTAB-Map has not been built with libpointmatcher support. Setting to false.", Parameters::kIcpPM().c_str());
_libpointmatcher = false;
}
#else

View File

@@ -121,6 +121,7 @@ Rtabmap::Rtabmap() :
_pathStuckIterations(Parameters::defaultRGBDPlanStuckIterations()),
_pathLinearVelocity(Parameters::defaultRGBDPlanLinearVelocity()),
_pathAngularVelocity(Parameters::defaultRGBDPlanAngularVelocity()),
_savedLocalizationIgnored(Parameters::defaultRGBDSavedLocalizationIgnored()),
_loopClosureHypothesis(0,0.0f),
_highestHypothesis(0,0.0f),
_lastProcessTime(0.0),
@@ -309,6 +310,19 @@ void Rtabmap::init(const ParametersMap & parameters, const std::string & databas
// Parse all parameters
this->parseParameters(parameters);
Transform lastPose;
_optimizedPoses = _memory->loadOptimizedPoses(&lastPose);
if(_optimizedPoses.size())
{
if(!_savedLocalizationIgnored)
{
_lastLocalizationPose = lastPose;
}
std::map<int, Transform> tmp;
// Get just the links
_memory->getMetricConstraints(uKeysSet(_optimizedPoses), tmp, _constraints, false);
}
if(_databasePath.empty())
{
_statisticLogged = false;
@@ -337,11 +351,10 @@ void Rtabmap::close(bool databaseSaved, const std::string & ouputDatabasePath)
_loopClosureHypothesis = std::make_pair(0,0.0f);
_lastProcessTime = 0.0;
_someNodesHaveBeenTransferred = false;
_optimizedPoses.clear();
_constraints.clear();
_mapCorrection.setIdentity();
_mapCorrectionBackup.setNull();
_lastLocalizationPose.setNull();
_lastLocalizationNodeId = 0;
_distanceTravelled = 0.0f;
this->clearPath(0);
@@ -365,10 +378,14 @@ void Rtabmap::close(bool databaseSaved, const std::string & ouputDatabasePath)
}
if(_memory)
{
_memory->saveOptimizedPoses(_optimizedPoses, _lastLocalizationPose);
_memory->close(databaseSaved, true, ouputDatabasePath);
delete _memory;
_memory = 0;
}
_optimizedPoses.clear();
_lastLocalizationPose.setNull();
if(_bayesFilter)
{
delete _bayesFilter;
@@ -444,6 +461,7 @@ void Rtabmap::parseParameters(const ParametersMap & parameters)
Parameters::parse(parameters, Parameters::kRGBDPlanStuckIterations(), _pathStuckIterations);
Parameters::parse(parameters, Parameters::kRGBDPlanLinearVelocity(), _pathLinearVelocity);
Parameters::parse(parameters, Parameters::kRGBDPlanAngularVelocity(), _pathAngularVelocity);
Parameters::parse(parameters, Parameters::kRGBDSavedLocalizationIgnored(), _savedLocalizationIgnored);
UASSERT(_rgbdLinearUpdate >= 0.0f);
UASSERT(_rgbdAngularUpdate >= 0.0f);
@@ -937,10 +955,24 @@ bool Rtabmap::process(
bool fakeOdom = false;
if(_rgbdSlamMode)
{
if(!_memory->isIncremental() && !odomPose.isNull() && !_mapCorrectionBackup.isNull())
if(!_memory->isIncremental() && !odomPose.isNull())
{
_mapCorrection = _mapCorrectionBackup;
_mapCorrectionBackup.setNull();
if(!_mapCorrectionBackup.isNull())
{
_mapCorrection = _mapCorrectionBackup;
_mapCorrectionBackup.setNull();
}
else if(_optimizedPoses.size() && _mapCorrection.isIdentity() && !_lastLocalizationPose.isNull() && _lastLocalizationNodeId == 0)
{
// Localization mode, set map->odom so that odom is moved back to last saved localization
_mapCorrection = _lastLocalizationPose * odomPose.inverse();
_lastLocalizationNodeId = graph::findNearestNode(_optimizedPoses, _lastLocalizationPose);
UWARN("Update map correction based on last localization saved in database! correction = %s, nearest id = %d of last pose = %s, odom = %s",
_mapCorrection.prettyPrint().c_str(),
_lastLocalizationNodeId,
_lastLocalizationPose.prettyPrint().c_str(),
odomPose.prettyPrint().c_str());
}
}
if(odomPose.isNull())

View File

@@ -112,6 +112,7 @@ CREATE TABLE Admin (
opt_cloud BLOB, -- compressed data
opt_ids BLOB, -- Node ids used to generate the optimized cloud/mesh
opt_poses BLOB, -- compressed N*3x4 float
opt_last_localization BLOB, -- 3x4 float
opt_polygons_size INTEGER, -- e.g., 3
opt_polygons BLOB, -- compressed data [length_v0, i0,i1,i3, length_v1, i0,i1,i3]
opt_tex_coords BLOB, -- compressed data [length_v0, u0,v0,u1,v1,u2,v2, length_v1, u0,v0,u1,v1,u2,v2]
@@ -119,6 +120,7 @@ CREATE TABLE Admin (
opt_map BLOB, -- compressed CV_8SC1 occupancy grid
opt_map_x_min FLOAT,
opt_map_y_min FLOAT,
opt_map_resolution FLOAT,
time_enter DATE
);

View File

@@ -849,7 +849,7 @@ void rayTrace(const cv::Point2i & start, const cv::Point2i & end, cv::Mat & grid
}
//convert to gray scaled map
cv::Mat convertMap2Image8U(const cv::Mat & map8S)
cv::Mat convertMap2Image8U(const cv::Mat & map8S, bool pgmFormat)
{
UASSERT(map8S.channels() == 1 && map8S.type() == CV_8S);
cv::Mat map8U = cv::Mat(map8S.rows, map8S.cols, CV_8U);
@@ -857,11 +857,11 @@ cv::Mat convertMap2Image8U(const cv::Mat & map8S)
{
for (int j = 0; j < map8S.cols; ++j)
{
char v = map8S.at<char>(i, j);
char v = pgmFormat?map8S.at<char>((map8S.rows-1)-i, j):map8S.at<char>(i, j);
unsigned char gray;
if(v == 0)
{
gray = 178;
gray = pgmFormat?254:178;
}
else if(v == 100)
{
@@ -869,11 +869,11 @@ cv::Mat convertMap2Image8U(const cv::Mat & map8S)
}
else if(v == -2)
{
gray = 200;
gray = pgmFormat?254:200;
}
else // -1
{
gray = 89;
gray = pgmFormat?205:89;
}
map8U.at<unsigned char>(i, j) = gray;
}
@@ -881,6 +881,58 @@ cv::Mat convertMap2Image8U(const cv::Mat & map8S)
return map8U;
}
//convert gray scaled image to map
cv::Mat convertImage8U2Map(const cv::Mat & map8U, bool pgmFormat)
{
UASSERT_MSG(map8U.channels() == 1 && map8U.type() == CV_8U, uFormat("map8U.channels()=%d map8U.type()=%d", map8U.channels(), map8U.type()).c_str());
cv::Mat map8S = cv::Mat(map8U.rows, map8U.cols, CV_8S);
for (int i = 0; i < map8U.rows; ++i)
{
for (int j = 0; j < map8U.cols; ++j)
{
unsigned char v = pgmFormat?map8U.at<char>((map8U.rows-1)-i, j):map8U.at<char>(i, j);
char occupancy;
if(pgmFormat)
{
if(v >= 254)
{
occupancy = 0;
}
else if(v == 0)
{
occupancy = 100;
}
else // 205
{
occupancy = -1;
}
}
else
{
if(v == 178)
{
occupancy = 0;
}
else if(v == 0)
{
occupancy = 100;
}
else if(v == 200)
{
occupancy = -2;
}
else // 89
{
occupancy = -1;
}
}
map8S.at<char>(i, j) = occupancy;
}
}
return map8S;
}
cv::Mat erodeMap(const cv::Mat & map)
{
UASSERT(map.type() == CV_8SC1);