mirror of
https://github.com/introlab/rtabmap.git
synced 2026-09-01 17:10:26 +08:00
Added rtabmap::databaseRecovery() function, added rtabmap-recovery tool, added "Database recovery" menu action in DbViewer
This commit is contained in:
@@ -11,6 +11,8 @@ SET(SRC_FILES
|
||||
DBDriverSqlite3.cpp
|
||||
DBReader.cpp
|
||||
|
||||
Recovery.cpp
|
||||
|
||||
Camera.cpp
|
||||
CameraThread.cpp
|
||||
CameraRGB.cpp
|
||||
|
||||
208
corelib/src/Recovery.cpp
Normal file
208
corelib/src/Recovery.cpp
Normal file
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
Copyright (c) 2010-2017, 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/Recovery.h>
|
||||
#include <rtabmap/core/Rtabmap.h>
|
||||
#include <rtabmap/core/DBDriver.h>
|
||||
#include <rtabmap/core/DBReader.h>
|
||||
#include <rtabmap/core/Graph.h>
|
||||
#include <rtabmap/core/ProgressState.h>
|
||||
#include <rtabmap/utilite/UFile.h>
|
||||
#include <rtabmap/utilite/UStl.h>
|
||||
|
||||
namespace rtabmap {
|
||||
|
||||
bool databaseRecovery(
|
||||
const std::string & corruptedDatabase,
|
||||
bool keepCorruptedDatabase,
|
||||
std::string * errorMsg,
|
||||
ProgressState * progressState)
|
||||
{
|
||||
UDEBUG("Recovering \"%s\"", corruptedDatabase.c_str());
|
||||
|
||||
std::string databasePath = uReplaceChar(corruptedDatabase, '~', UDirectory::homeDir());
|
||||
if(!UFile::exists(databasePath))
|
||||
{
|
||||
if(errorMsg)
|
||||
*errorMsg = uFormat("File \"%s\" doesn't exist!", databasePath.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string backupPath;
|
||||
if(UFile::getExtension(databasePath).compare("db") != 0)
|
||||
{
|
||||
if(errorMsg)
|
||||
*errorMsg = uFormat("File \"%s\" is not a database (*.db)!", databasePath.c_str());
|
||||
return false;
|
||||
}
|
||||
std::list<std::string> strList = uSplit(databasePath, '.');
|
||||
strList.pop_back();
|
||||
backupPath = uJoin(strList, ".") + ".backup.db";
|
||||
if(UFile::exists(backupPath))
|
||||
{
|
||||
if(errorMsg)
|
||||
*errorMsg = uFormat("Backup file \"%s\" already exists!", backupPath.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
DBDriver * dbDriver = DBDriver::create();
|
||||
if(!dbDriver->openConnection(databasePath, false))
|
||||
{
|
||||
if(errorMsg)
|
||||
*errorMsg = uFormat("Failed opening database!");
|
||||
delete dbDriver;
|
||||
return false;
|
||||
}
|
||||
|
||||
ParametersMap parameters = dbDriver->getLastParameters();
|
||||
if(parameters.empty())
|
||||
{
|
||||
if(errorMsg)
|
||||
*errorMsg = uFormat("Failed getting parameters from database, recovery cannot be done.");
|
||||
dbDriver->closeConnection(false);
|
||||
delete dbDriver;
|
||||
return false;
|
||||
}
|
||||
std::set<int> ids;
|
||||
dbDriver->getAllNodeIds(ids);
|
||||
if(ids.empty())
|
||||
{
|
||||
if(errorMsg)
|
||||
*errorMsg = uFormat("Input database doesn't have any nodes saved in it.");
|
||||
dbDriver->closeConnection(false);
|
||||
delete dbDriver;
|
||||
return false;
|
||||
}
|
||||
if(progressState)
|
||||
progressState->callback(uFormat("Found %d nodes to recover.", (int)ids.size()));
|
||||
|
||||
//Detect if the database is corrupted
|
||||
std::multimap<int, Link> links;
|
||||
dbDriver->getAllLinks(links, true);
|
||||
bool corrupted = false;
|
||||
for(std::multimap<int, Link>::iterator iter=links.begin(); iter!=links.end(); ++iter)
|
||||
{
|
||||
if(iter->second.type() == Link::kNeighbor &&
|
||||
graph::findLink(links, iter->second.to(), iter->second.from(), false) == links.end())
|
||||
{
|
||||
corrupted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(progressState)
|
||||
{
|
||||
if(corrupted)
|
||||
progressState->callback("Database is indeed corrupted, found one or more neighbor links missing.");
|
||||
else
|
||||
progressState->callback("Database doesn't seem to be corrupted, still recovering it.");
|
||||
}
|
||||
|
||||
dbDriver->closeConnection(false);
|
||||
delete dbDriver;
|
||||
|
||||
if(progressState)
|
||||
progressState->callback(uFormat("Renaming \"%s\" to \"%s\"...", UFile::getName(databasePath).c_str(), UFile::getName(backupPath).c_str()));
|
||||
if(UFile::rename(databasePath, backupPath) != 0)
|
||||
{
|
||||
if(errorMsg)
|
||||
*errorMsg = uFormat("Failed renaming database file from \"%s\" to \"%s\". Is it opened by another app?", UFile::getName(databasePath).c_str(), UFile::getName(backupPath).c_str());
|
||||
return false;
|
||||
}
|
||||
Rtabmap rtabmap;
|
||||
rtabmap.init(parameters, databasePath);
|
||||
|
||||
bool odometryIgnored = false;
|
||||
Parameters::parse(parameters, Parameters::kRGBDEnabled(), odometryIgnored);
|
||||
DBReader dbReader(backupPath, 0, !odometryIgnored);
|
||||
dbReader.init();
|
||||
|
||||
CameraInfo info;
|
||||
SensorData data = dbReader.takeImage(&info);
|
||||
int processed = 0;
|
||||
if(progressState)
|
||||
progressState->callback(uFormat("Recovering data of \"%s\"...", backupPath.c_str()));
|
||||
while(data.isValid() && (progressState==0 || !progressState->isCanceled()))
|
||||
{
|
||||
std::string status;
|
||||
if(!odometryIgnored && info.odomPose.isNull())
|
||||
{
|
||||
status = uFormat("Skipping node %d as it doesn't have odometry pose set.", data.id());
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!rtabmap.process(data, info.odomPose, info.odomCovariance))
|
||||
{
|
||||
status = uFormat("Failed processing node %d.", data.id());
|
||||
}
|
||||
}
|
||||
if(status.empty())
|
||||
{
|
||||
if(progressState)
|
||||
progressState->callback(status);
|
||||
}
|
||||
|
||||
data = dbReader.takeImage(&info);
|
||||
|
||||
if(progressState)
|
||||
progressState->callback(uFormat("Processed %d/%d nodes...", ++processed, (int)ids.size()));
|
||||
}
|
||||
|
||||
if(progressState)
|
||||
{
|
||||
if(progressState->isCanceled())
|
||||
{
|
||||
rtabmap.close(false);
|
||||
if(errorMsg)
|
||||
*errorMsg = "Recovery canceled";
|
||||
|
||||
// put back the file as before
|
||||
UFile::erase(databasePath);
|
||||
UFile::rename(backupPath, databasePath);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(progressState)
|
||||
progressState->callback(uFormat("Closing database \"%s\"...", databasePath.c_str()));
|
||||
rtabmap.close(true);
|
||||
if(progressState)
|
||||
progressState->callback(uFormat("Closing database \"%s\"... done!", databasePath.c_str()));
|
||||
|
||||
if(!keepCorruptedDatabase)
|
||||
{
|
||||
UFile::erase(backupPath);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1053,7 +1053,7 @@ template<typename PointInT> bool
|
||||
pcl::TextureMapping<PointInT>::textureMeshwithMultipleCameras2 (
|
||||
pcl::TextureMesh &mesh,
|
||||
const pcl::texture_mapping::CameraVector &cameras,
|
||||
const ProgressState * state,
|
||||
const rtabmap::ProgressState * state,
|
||||
std::vector<std::map<int, pcl::PointXY> > * vertexToPixels)
|
||||
{
|
||||
|
||||
|
||||
@@ -365,7 +365,7 @@ namespace pcl
|
||||
bool
|
||||
textureMeshwithMultipleCameras2 (pcl::TextureMesh &mesh,
|
||||
const pcl::texture_mapping::CameraVector &cameras,
|
||||
const ProgressState * callback = 0,
|
||||
const rtabmap::ProgressState * callback = 0,
|
||||
std::vector<std::map<int, pcl::PointXY> > * vertexToPixels = 0);
|
||||
|
||||
protected:
|
||||
|
||||
Reference in New Issue
Block a user