mirror of
https://github.com/introlab/rtabmap_ros.git
synced 2026-10-03 16:27:46 +08:00
Updated for issue #36: Moved "Export Poses..." to File menu, added "Export images..." action too, updated when some export actions are enabled or disabled
This commit is contained in:
@@ -231,6 +231,13 @@ private:
|
||||
float minInliers_;
|
||||
};
|
||||
|
||||
bool RTABMAP_EXP exportPoses(
|
||||
const std::string & filePath,
|
||||
int format, // 0=Raw (*.txt), 1=RGBD-SLAM (*.txt), 2=KITTI (*.txt), 3=TORO (*.graph), 4=g2o (*.g2o)
|
||||
const std::map<int, Transform> & poses,
|
||||
const std::multimap<int, Link> & constraints, // required for formats 3 and 4
|
||||
const std::map<int, double> & stamps); // required for format 1
|
||||
|
||||
////////////////////////////////////////////
|
||||
// Graph utilities
|
||||
////////////////////////////////////////////
|
||||
|
||||
@@ -112,7 +112,7 @@ public:
|
||||
const std::string & path,
|
||||
bool optimized,
|
||||
bool global,
|
||||
int type // 0=raw/KITTI format, 1=rgbd-slam format, 2=TORO
|
||||
int format // 0=raw, 1=rgbd-slam format, 2=KITTI format, 3=TORO, 4=g2o
|
||||
);
|
||||
void resetMemory();
|
||||
void dumpPrediction() const;
|
||||
|
||||
@@ -31,6 +31,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <rtabmap/utilite/UMath.h>
|
||||
#include <rtabmap/utilite/UConversion.h>
|
||||
#include <rtabmap/utilite/UTimer.h>
|
||||
#include <rtabmap/utilite/UFile.h>
|
||||
#include <rtabmap/core/Memory.h>
|
||||
#include <pcl/search/kdtree.h>
|
||||
#include <pcl/common/eigen.h>
|
||||
@@ -1573,6 +1574,109 @@ std::map<int, Transform> CVSBAOptimizer::optimizeBA(
|
||||
#endif
|
||||
}
|
||||
|
||||
bool exportPoses(
|
||||
const std::string & filePath,
|
||||
int format, // 0=Raw, 1=RGBD-SLAM, 2=KITTI, 3=TORO, 4=g2o
|
||||
const std::map<int, Transform> & poses,
|
||||
const std::multimap<int, Link> & constraints, // required for formats 3 and 4
|
||||
const std::map<int, double> & stamps) // required for format 1
|
||||
{
|
||||
std::string tmpPath = filePath;
|
||||
if(format==3) // TORO
|
||||
{
|
||||
if(UFile::getExtension(tmpPath).empty())
|
||||
{
|
||||
tmpPath+=".graph";
|
||||
}
|
||||
return graph::TOROOptimizer::saveGraph(tmpPath, poses, constraints);
|
||||
}
|
||||
else if(format == 4) // g2o
|
||||
{
|
||||
if(UFile::getExtension(tmpPath).empty())
|
||||
{
|
||||
tmpPath+=".g2o";
|
||||
}
|
||||
#ifdef WITH_G2O
|
||||
return graph::G2OOptimizer::saveGraph(tmpPath, poses, constraints);
|
||||
#else
|
||||
UERROR("Cannot export in g2o format because RTAB-Map is not built with g2o support!");
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
if(UFile::getExtension(tmpPath).empty())
|
||||
{
|
||||
tmpPath+=".txt";
|
||||
}
|
||||
|
||||
if(format == 1)
|
||||
{
|
||||
if(stamps.size() != poses.size())
|
||||
{
|
||||
UERROR("When exporting poses to format 1 (RGBD-SLAM), stamps and poses maps should have the same size!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
FILE* fout = 0;
|
||||
#ifdef _MSC_VER
|
||||
fopen_s(&fout, tmpPath.c_str(), "w");
|
||||
#else
|
||||
fout = fopen(tmpPath.c_str(), "w");
|
||||
#endif
|
||||
if(fout)
|
||||
{
|
||||
for(std::map<int, Transform>::const_iterator iter=poses.begin(); iter!=poses.end(); ++iter)
|
||||
{
|
||||
if(format == 1) // rgbd-slam format
|
||||
{
|
||||
// Format: stamp x y z qw qx qy qz
|
||||
Eigen::Quaternionf q = (*iter).second.getQuaternionf();
|
||||
|
||||
UASSERT(uContains(stamps, iter->first));
|
||||
fprintf(fout, "%f %f %f %f %f %f %f %f\n",
|
||||
stamps.at(iter->first),
|
||||
(*iter).second.x(),
|
||||
(*iter).second.y(),
|
||||
(*iter).second.z(),
|
||||
q.w(),
|
||||
q.x(),
|
||||
q.y(),
|
||||
q.z());
|
||||
}
|
||||
else // default / KITTI format
|
||||
{
|
||||
Transform pose = iter->second;
|
||||
if(format == 2)
|
||||
{
|
||||
// for KITTI, we need to remove optical rotation
|
||||
// z pointing front, x left, y down
|
||||
Transform t( 0, 0, 1, 0,
|
||||
-1, 0, 0, 0,
|
||||
0,-1, 0, 0);
|
||||
pose = t.inverse() * pose * t;
|
||||
}
|
||||
|
||||
// Format: r11 r12 r13 tx r21 r22 r23 ty r31 r32 r33 tz
|
||||
const float * p = (const float *)pose.data();
|
||||
|
||||
fprintf(fout, "%f", p[0]);
|
||||
for(int i=1; i<pose.size(); i++)
|
||||
{
|
||||
fprintf(fout, " %f", p[i]);
|
||||
}
|
||||
fprintf(fout, "\n");
|
||||
}
|
||||
}
|
||||
fclose(fout);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////
|
||||
// Graph utilities
|
||||
////////////////////////////////////////////
|
||||
|
||||
+12
-80
@@ -740,7 +740,7 @@ void Rtabmap::generateDOTGraph(const std::string & path, int id, int margin)
|
||||
}
|
||||
}
|
||||
|
||||
void Rtabmap::exportPoses(const std::string & path, bool optimized, bool global, int type)
|
||||
void Rtabmap::exportPoses(const std::string & path, bool optimized, bool global, int format)
|
||||
{
|
||||
if(_memory && _memory->getLastWorkingSignature())
|
||||
{
|
||||
@@ -757,89 +757,21 @@ void Rtabmap::exportPoses(const std::string & path, bool optimized, bool global,
|
||||
_memory->getMetricConstraints(uKeysSet(ids), poses, constraints, global);
|
||||
}
|
||||
|
||||
if(type==3) // TORO
|
||||
std::map<int, double> stamps;
|
||||
if(format == 1)
|
||||
{
|
||||
graph::TOROOptimizer::saveGraph(path, poses, constraints);
|
||||
}
|
||||
else if(type == 4) // g2o
|
||||
{
|
||||
#ifdef WITH_G2O
|
||||
graph::G2OOptimizer::saveGraph(path, poses, constraints);
|
||||
#else
|
||||
UERROR("Cannot export in g2o format because RTAB-Map is not built with g2o support!");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
//get timestamps
|
||||
std::map<int, double> stamps;
|
||||
if(type == 1)
|
||||
for(std::map<int, Transform>::iterator iter=poses.begin(); iter!=poses.end(); ++iter)
|
||||
{
|
||||
for(std::map<int, Transform>::iterator iter=poses.begin(); iter!=poses.end(); ++iter)
|
||||
{
|
||||
Transform o;
|
||||
int m, w;
|
||||
std::string l;
|
||||
double stamp = 0.0;
|
||||
_memory->getNodeInfo(iter->first, o, m, w, l, stamp, true);
|
||||
stamps.insert(std::make_pair(iter->first, stamp));
|
||||
}
|
||||
UASSERT(stamps.size()== 0 || stamps.size() == poses.size());
|
||||
}
|
||||
|
||||
FILE* fout = 0;
|
||||
#ifdef _MSC_VER
|
||||
fopen_s(&fout, path.c_str(), "w");
|
||||
#else
|
||||
fout = fopen(path.c_str(), "w");
|
||||
#endif
|
||||
if(fout)
|
||||
{
|
||||
for(std::map<int, Transform>::const_iterator iter=poses.begin(); iter!=poses.end(); ++iter)
|
||||
{
|
||||
if(type == 1) // rgbd-slam format
|
||||
{
|
||||
// Format: stamp x y z qw qx qy qz
|
||||
Eigen::Quaternionf q = (*iter).second.getQuaternionf();
|
||||
|
||||
UASSERT(uContains(stamps, iter->first));
|
||||
fprintf(fout, "%f %f %f %f %f %f %f %f\n",
|
||||
stamps.at(iter->first),
|
||||
(*iter).second.x(),
|
||||
(*iter).second.y(),
|
||||
(*iter).second.z(),
|
||||
q.w(),
|
||||
q.x(),
|
||||
q.y(),
|
||||
q.z());
|
||||
}
|
||||
else // default / KITTI format
|
||||
{
|
||||
Transform pose = iter->second;
|
||||
if(type == 2)
|
||||
{
|
||||
// for KITTI, we need to remove optical rotation
|
||||
// z pointing front, x left, y down
|
||||
Transform t( 0, 0, 1, 0,
|
||||
-1, 0, 0, 0,
|
||||
0,-1, 0, 0);
|
||||
pose = t.inverse() * pose * t;
|
||||
}
|
||||
|
||||
// Format: r11 r12 r13 tx r21 r22 r23 ty r31 r32 r33 tz
|
||||
const float * p = (const float *)pose.data();
|
||||
|
||||
fprintf(fout, "%f", p[0]);
|
||||
for(int i=1; i<pose.size(); i++)
|
||||
{
|
||||
fprintf(fout, " %f", p[i]);
|
||||
}
|
||||
fprintf(fout, "\n");
|
||||
}
|
||||
}
|
||||
fclose(fout);
|
||||
Transform o;
|
||||
int m, w;
|
||||
std::string l;
|
||||
double stamp = 0.0;
|
||||
_memory->getNodeInfo(iter->first, o, m, w, l, stamp, true);
|
||||
stamps.insert(std::make_pair(iter->first, stamp));
|
||||
}
|
||||
}
|
||||
|
||||
graph::exportPoses(path, format, poses, constraints, stamps);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -134,6 +134,7 @@ private slots:
|
||||
void exportPosesKITTI();
|
||||
void exportPosesTORO();
|
||||
void exportPosesG2O();
|
||||
void exportImages();
|
||||
void postProcessing();
|
||||
void deleteMemory();
|
||||
void openWorkingDirectory();
|
||||
|
||||
+269
-58
@@ -329,6 +329,7 @@ MainWindow::MainWindow(PreferencesDialog * prefDialog, QWidget * parent) :
|
||||
connect(_ui->actionSave_point_cloud, SIGNAL(triggered()), this, SLOT(exportClouds()));
|
||||
connect(_ui->actionExport_2D_scans_ply_pcd, SIGNAL(triggered()), this, SLOT(exportScans()));
|
||||
connect(_ui->actionExport_2D_Grid_map_bmp_png, SIGNAL(triggered()), this, SLOT(exportGridMap()));
|
||||
connect(_ui->actionExport_images_RGB_jpg_Depth_png, SIGNAL(triggered()), this , SLOT(exportImages()));
|
||||
connect(_ui->actionExport_cameras_in_Bundle_format_out, SIGNAL(triggered()), SLOT(exportBundlerFormat()));
|
||||
connect(_ui->actionView_scans, SIGNAL(triggered()), this, SLOT(viewScans()));
|
||||
connect(_ui->actionView_high_res_point_cloud, SIGNAL(triggered()), this, SLOT(viewClouds()));
|
||||
@@ -339,12 +340,6 @@ MainWindow::MainWindow(PreferencesDialog * prefDialog, QWidget * parent) :
|
||||
|
||||
_ui->actionPause->setShortcut(Qt::Key_Space);
|
||||
_ui->actionSave_GUI_config->setShortcut(QKeySequence::Save);
|
||||
_ui->actionSave_point_cloud->setEnabled(false);
|
||||
_ui->actionExport_2D_scans_ply_pcd->setEnabled(false);
|
||||
_ui->actionExport_2D_Grid_map_bmp_png->setEnabled(false);
|
||||
_ui->actionExport_cameras_in_Bundle_format_out->setEnabled(false);
|
||||
_ui->actionView_scans->setEnabled(false);
|
||||
_ui->actionView_high_res_point_cloud->setEnabled(false);
|
||||
_ui->actionReset_Odometry->setEnabled(false);
|
||||
_ui->actionPost_processing->setEnabled(false);
|
||||
|
||||
@@ -1348,6 +1343,11 @@ void MainWindow::processStats(const rtabmap::Statistics & stat)
|
||||
{
|
||||
_cachedSignatures.clear();
|
||||
}
|
||||
if(_state != kMonitoring && _state != kDetecting)
|
||||
{
|
||||
_ui->actionExport_images_RGB_jpg_Depth_png->setEnabled(!_cachedSignatures.empty() && !_currentPosesMap.empty());
|
||||
_ui->actionExport_cameras_in_Bundle_format_out->setEnabled(!_cachedSignatures.empty() && !_currentPosesMap.empty());
|
||||
}
|
||||
|
||||
_processingStatistics = false;
|
||||
}
|
||||
@@ -1371,6 +1371,7 @@ void MainWindow::updateMapCloud(
|
||||
if(_state != kMonitoring && _state != kDetecting)
|
||||
{
|
||||
_ui->actionPost_processing->setEnabled(_cachedSignatures.size() >= 2 && _currentPosesMap.size() >= 2 && _currentLinksMap.size() >= 1);
|
||||
_ui->menuExport_poses->setEnabled(!_currentPosesMap.empty());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1517,12 +1518,14 @@ void MainWindow::updateMapCloud(
|
||||
}
|
||||
|
||||
// activate actions
|
||||
_ui->actionSave_point_cloud->setEnabled(!_createdClouds.empty());
|
||||
_ui->actionView_high_res_point_cloud->setEnabled(!_createdClouds.empty());
|
||||
_ui->actionExport_2D_scans_ply_pcd->setEnabled(!_createdScans.empty());
|
||||
_ui->actionExport_2D_Grid_map_bmp_png->setEnabled(!_gridLocalMaps.empty() || !_projectionLocalMaps.empty());
|
||||
_ui->actionView_scans->setEnabled(!_createdScans.empty());
|
||||
_ui->actionExport_cameras_in_Bundle_format_out->setEnabled(!_createdClouds.empty());
|
||||
if(_state != kMonitoring && _state != kDetecting)
|
||||
{
|
||||
_ui->actionSave_point_cloud->setEnabled(!_createdClouds.empty());
|
||||
_ui->actionView_high_res_point_cloud->setEnabled(!_createdClouds.empty());
|
||||
_ui->actionExport_2D_scans_ply_pcd->setEnabled(!_createdScans.empty());
|
||||
_ui->actionExport_2D_Grid_map_bmp_png->setEnabled(!_gridLocalMaps.empty() || !_projectionLocalMaps.empty());
|
||||
_ui->actionView_scans->setEnabled(!_createdScans.empty());
|
||||
}
|
||||
|
||||
//remove not used clouds
|
||||
for(QMap<std::string, Transform>::iterator iter = viewerClouds.begin(); iter!=viewerClouds.end(); ++iter)
|
||||
@@ -2173,6 +2176,11 @@ void MainWindow::processRtabmapEvent3DMap(const rtabmap::RtabmapEvent3DMap & eve
|
||||
{
|
||||
_cachedSignatures.clear();
|
||||
}
|
||||
if(_state != kMonitoring && _state != kDetecting)
|
||||
{
|
||||
_ui->actionExport_images_RGB_jpg_Depth_png->setEnabled(!_cachedSignatures.empty() && !_currentPosesMap.empty());
|
||||
_ui->actionExport_cameras_in_Bundle_format_out->setEnabled(!_cachedSignatures.empty() && !_currentPosesMap.empty());
|
||||
}
|
||||
_processingDownloadedMap = false;
|
||||
}
|
||||
_initProgressDialog->setValue(_initProgressDialog->maximumSteps());
|
||||
@@ -3229,36 +3237,24 @@ void MainWindow::exportPosesG2O()
|
||||
|
||||
void MainWindow::exportPoses(int format)
|
||||
{
|
||||
QStringList items;
|
||||
items.append("Local map optimized");
|
||||
items.append("Local map not optimized");
|
||||
items.append("Global map optimized");
|
||||
items.append("Global map not optimized");
|
||||
bool ok;
|
||||
QString item = QInputDialog::getItem(this, tr("Parameters"), tr("Options:"), items, 2, false, &ok);
|
||||
if(ok)
|
||||
if(_currentPosesMap.size())
|
||||
{
|
||||
bool optimized=false, global=false;
|
||||
if(item.compare("Local map optimized") == 0)
|
||||
std::map<int, double> stamps;
|
||||
if(format == 1)
|
||||
{
|
||||
optimized = true;
|
||||
}
|
||||
else if(item.compare("Local map not optimized") == 0)
|
||||
{
|
||||
|
||||
}
|
||||
else if(item.compare("Global map optimized") == 0)
|
||||
{
|
||||
global=true;
|
||||
optimized=true;
|
||||
}
|
||||
else if(item.compare("Global map not optimized") == 0)
|
||||
{
|
||||
global=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
UFATAL("Item \"%s\" not found?!?", item.toStdString().c_str());
|
||||
for(std::map<int, Transform>::iterator iter=_currentPosesMap.begin(); iter!=_currentPosesMap.end(); ++iter)
|
||||
{
|
||||
if(_cachedSignatures.contains(iter->first))
|
||||
{
|
||||
stamps.insert(std::make_pair(iter->first, _cachedSignatures.value(iter->first).getStamp()));
|
||||
}
|
||||
}
|
||||
if(stamps.size()!=_currentPosesMap.size())
|
||||
{
|
||||
QMessageBox::warning(this, tr("Export poses..."), tr("RGB-D SLAM format: Poses (%1) and stamps (%2) have not the same size! Try again after updating the cache.")
|
||||
.arg(_currentPosesMap.size()).arg(stamps.size()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(_exportPosesFileName[format].isEmpty())
|
||||
@@ -3276,17 +3272,25 @@ void MainWindow::exportPoses(int format)
|
||||
{
|
||||
_exportPosesFileName[format] = path;
|
||||
|
||||
this->post(new RtabmapEventCmd(RtabmapEventCmd::kCmdExportPoses, global, optimized, path.toStdString(), format));
|
||||
bool saved = graph::exportPoses(path.toStdString(), format, _currentPosesMap, _currentLinksMap, stamps);
|
||||
|
||||
_ui->dockWidget_console->show();
|
||||
_ui->widget_console->appendMsg(
|
||||
QString("%1 saved (global=%2, optimized=%3)... %4")
|
||||
.arg(format == 3?"TORO graph":format == 4?"g2o graph":"Poses")
|
||||
.arg(global?"true":"false")
|
||||
.arg(optimized?"true":"false")
|
||||
.arg(_exportPosesFileName[format]));
|
||||
if(saved)
|
||||
{
|
||||
QMessageBox::information(this,
|
||||
tr("Export poses..."),
|
||||
tr("%1 saved to \"%2\".")
|
||||
.arg(format == 3?"TORO graph":format == 4?"g2o graph":"Poses")
|
||||
.arg(_exportPosesFileName[format]));
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::information(this,
|
||||
tr("Export poses..."),
|
||||
tr("Failed to save %1 to \"%2\"!")
|
||||
.arg(format == 3?"TORO graph":format == 4?"g2o graph":"poses")
|
||||
.arg(_exportPosesFileName[format]));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4149,6 +4153,7 @@ void MainWindow::clearTheCache()
|
||||
_ui->actionPost_processing->setEnabled(false);
|
||||
_ui->actionSave_point_cloud->setEnabled(false);
|
||||
_ui->actionExport_cameras_in_Bundle_format_out->setEnabled(false);
|
||||
_ui->actionExport_images_RGB_jpg_Depth_png->setEnabled(false);
|
||||
_ui->actionView_scans->setEnabled(false);
|
||||
_ui->actionView_high_res_point_cloud->setEnabled(false);
|
||||
_likelihoodCurve->clear();
|
||||
@@ -5040,6 +5045,163 @@ bool MainWindow::getExportedClouds(
|
||||
return false;
|
||||
}
|
||||
|
||||
void MainWindow::exportImages()
|
||||
{
|
||||
if(_cachedSignatures.empty())
|
||||
{
|
||||
QMessageBox::warning(this, tr("Export images..."), tr("Cannot export images, the cache is empty!"));
|
||||
return;
|
||||
}
|
||||
std::map<int, Transform> poses = _ui->widget_mapVisibility->getVisiblePoses();
|
||||
|
||||
if(poses.empty())
|
||||
{
|
||||
QMessageBox::warning(this, tr("Export images..."), tr("There is no map!"));
|
||||
return;
|
||||
}
|
||||
|
||||
QString path = QFileDialog::getExistingDirectory(this, tr("Select directory where to save images..."), this->getWorkingDirectory());
|
||||
if(!path.isNull())
|
||||
{
|
||||
SensorData data;
|
||||
if(_cachedSignatures.contains(poses.rbegin()->first))
|
||||
{
|
||||
data = _cachedSignatures.value(poses.rbegin()->first).sensorData();
|
||||
data.uncompressData();
|
||||
}
|
||||
if(!data.imageRaw().empty() && !data.rightRaw().empty())
|
||||
{
|
||||
QDir dir;
|
||||
dir.mkdir(QString("%1/left").arg(path));
|
||||
dir.mkdir(QString("%1/right").arg(path));
|
||||
if(data.stereoCameraModel().isValid())
|
||||
{
|
||||
std::string cameraName = "calibration";
|
||||
StereoCameraModel model(
|
||||
cameraName,
|
||||
data.imageRaw().size(),
|
||||
data.stereoCameraModel().left().K(),
|
||||
data.stereoCameraModel().left().D(),
|
||||
data.stereoCameraModel().left().R(),
|
||||
data.stereoCameraModel().left().P(),
|
||||
data.rightRaw().size(),
|
||||
data.stereoCameraModel().right().K(),
|
||||
data.stereoCameraModel().right().D(),
|
||||
data.stereoCameraModel().right().R(),
|
||||
data.stereoCameraModel().right().P(),
|
||||
data.stereoCameraModel().R(),
|
||||
data.stereoCameraModel().T(),
|
||||
data.stereoCameraModel().E(),
|
||||
data.stereoCameraModel().F(),
|
||||
data.stereoCameraModel().left().localTransform());
|
||||
if(model.save(path.toStdString()))
|
||||
{
|
||||
UINFO("Saved stereo calibration \"%s\"", (path.toStdString()+"/"+cameraName).c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
UERROR("Failed saving calibration \"%s\"", (path.toStdString()+"/"+cameraName).c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(!data.imageRaw().empty())
|
||||
{
|
||||
if(!data.depthRaw().empty())
|
||||
{
|
||||
QDir dir;
|
||||
dir.mkdir(QString("%1/rgb").arg(path));
|
||||
dir.mkdir(QString("%1/depth").arg(path));
|
||||
}
|
||||
|
||||
if(data.cameraModels().size() > 1)
|
||||
{
|
||||
UERROR("Only one camera calibration can be saved at this time (%d detected)", (int)data.cameraModels().size());
|
||||
}
|
||||
else if(data.cameraModels().size() == 1 && data.cameraModels().front().isValid())
|
||||
{
|
||||
std::string cameraName = "calibration";
|
||||
CameraModel model(cameraName,
|
||||
data.imageRaw().size(),
|
||||
data.cameraModels().front().K(),
|
||||
data.cameraModels().front().D(),
|
||||
data.cameraModels().front().R(),
|
||||
data.cameraModels().front().P(),
|
||||
data.cameraModels().front().localTransform());
|
||||
if(model.save(path.toStdString()))
|
||||
{
|
||||
UINFO("Saved calibration \"%s\"", (path.toStdString()+"/"+cameraName).c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
UERROR("Failed saving calibration \"%s\"", (path.toStdString()+"/"+cameraName).c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::warning(this,
|
||||
tr("Export images..."),
|
||||
tr("Data in the cache don't seem to have images (tested node %1). Calibration file will not be saved. Try refreshing the cache (with clouds).").arg(poses.rbegin()->first));
|
||||
}
|
||||
}
|
||||
|
||||
_initProgressDialog->resetProgress();
|
||||
_initProgressDialog->show();
|
||||
_initProgressDialog->setMaximumSteps(_cachedSignatures.size());
|
||||
|
||||
int saved = 0;
|
||||
for(std::map<int, Transform>::iterator iter=poses.begin(); iter!=poses.end(); ++iter)
|
||||
{
|
||||
int id = iter->first;
|
||||
SensorData data;
|
||||
if(_cachedSignatures.contains(iter->first))
|
||||
{
|
||||
data = _cachedSignatures.value(iter->first).sensorData();
|
||||
data.uncompressData();
|
||||
}
|
||||
QString info;
|
||||
bool warn = false;
|
||||
if(!data.imageRaw().empty() && !data.rightRaw().empty())
|
||||
{
|
||||
cv::imwrite(QString("%1/left/%2.jpg").arg(path).arg(id).toStdString(), data.imageRaw());
|
||||
cv::imwrite(QString("%1/right/%2.jpg").arg(path).arg(id).toStdString(), data.rightRaw());
|
||||
info = tr("Saved left/%1.jpg and right/%1.jpg.").arg(id);
|
||||
}
|
||||
else if(!data.imageRaw().empty() && !data.depthRaw().empty())
|
||||
{
|
||||
cv::imwrite(QString("%1/rgb/%2.jpg").arg(path).arg(id).toStdString(), data.imageRaw());
|
||||
cv::imwrite(QString("%1/depth/%2.png").arg(path).arg(id).toStdString(), data.depthRaw());
|
||||
info = tr("Saved rgb/%1.jpg and depth/%1.png.").arg(id);
|
||||
}
|
||||
else if(!data.imageRaw().empty())
|
||||
{
|
||||
cv::imwrite(QString("%1/%2.jpg").arg(path).arg(id).toStdString(), data.imageRaw());
|
||||
info = tr("Saved %1.jpg.").arg(id);
|
||||
}
|
||||
else
|
||||
{
|
||||
info = tr("No images saved for node %1!").arg(id);
|
||||
warn = true;
|
||||
}
|
||||
saved += warn?0:1;
|
||||
_initProgressDialog->appendText(info, !warn?Qt::black:Qt::darkYellow);
|
||||
_initProgressDialog->incrementStep();
|
||||
QApplication::processEvents();
|
||||
|
||||
}
|
||||
if(saved!=poses.size())
|
||||
{
|
||||
_initProgressDialog->setAutoClose(false);
|
||||
_initProgressDialog->appendText(tr("%1 images of %2 saved to \"%3\".").arg(saved).arg(poses.size()).arg(path));
|
||||
}
|
||||
else
|
||||
{
|
||||
_initProgressDialog->appendText(tr("%1 images saved to \"%2\".").arg(saved).arg(path));
|
||||
}
|
||||
|
||||
_initProgressDialog->setValue(_initProgressDialog->maximumSteps());
|
||||
}
|
||||
|
||||
void MainWindow::exportBundlerFormat()
|
||||
{
|
||||
std::map<int, Transform> posesIn = _ui->widget_mapVisibility->getVisiblePoses();
|
||||
@@ -5148,7 +5310,7 @@ void MainWindow::exportBundlerFormat()
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::warning(this, tr("Exporting cameras..."), tr("No poses exported..."));
|
||||
QMessageBox::warning(this, tr("Exporting cameras..."), tr("No poses exported because of missing images. Try refreshing the cache (with clouds)."));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5823,7 +5985,6 @@ void MainWindow::changeState(MainWindow::State newState)
|
||||
_ui->actionDump_the_prediction_matrix->setVisible(!monitoring);
|
||||
_ui->actionGenerate_map->setVisible(!monitoring);
|
||||
_ui->actionUpdate_cache_from_database->setVisible(monitoring);
|
||||
_ui->menuExport_poses->menuAction()->setVisible(!monitoring);
|
||||
_ui->actionOpen_working_directory->setVisible(!monitoring);
|
||||
_ui->actionData_recorder->setVisible(!monitoring);
|
||||
_ui->menuSelect_source->menuAction()->setVisible(!monitoring);
|
||||
@@ -5844,7 +6005,7 @@ void MainWindow::changeState(MainWindow::State newState)
|
||||
}
|
||||
}
|
||||
actions = _ui->menuFile->actions();
|
||||
if(actions.size()>=10)
|
||||
if(actions.size()==15)
|
||||
{
|
||||
if(actions.at(2)->isSeparator())
|
||||
{
|
||||
@@ -5854,9 +6015,9 @@ void MainWindow::changeState(MainWindow::State newState)
|
||||
{
|
||||
UWARN("Menu File separators have not the same order.");
|
||||
}
|
||||
if(actions.at(9)->isSeparator())
|
||||
if(actions.at(11)->isSeparator())
|
||||
{
|
||||
actions.at(9)->setVisible(!monitoring);
|
||||
actions.at(11)->setVisible(!monitoring);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -5884,7 +6045,6 @@ void MainWindow::changeState(MainWindow::State newState)
|
||||
UWARN("Menu File separators have not the same order.");
|
||||
}
|
||||
|
||||
|
||||
switch (newState)
|
||||
{
|
||||
case kIdle: // RTAB-Map is not initialized yet
|
||||
@@ -5904,8 +6064,15 @@ void MainWindow::changeState(MainWindow::State newState)
|
||||
_ui->actionDump_the_prediction_matrix->setEnabled(false);
|
||||
_ui->actionDelete_memory->setEnabled(false);
|
||||
_ui->actionPost_processing->setEnabled(_cachedSignatures.size() >= 2 && _currentPosesMap.size() >= 2 && _currentLinksMap.size() >= 1);
|
||||
_ui->actionExport_images_RGB_jpg_Depth_png->setEnabled(!_cachedSignatures.empty() && !_currentPosesMap.empty());
|
||||
_ui->actionGenerate_map->setEnabled(false);
|
||||
_ui->menuExport_poses->setEnabled(false);
|
||||
_ui->menuExport_poses->setEnabled(!_currentPosesMap.empty());
|
||||
_ui->actionSave_point_cloud->setEnabled(!_createdClouds.empty());
|
||||
_ui->actionView_high_res_point_cloud->setEnabled(!_createdClouds.empty());
|
||||
_ui->actionExport_2D_scans_ply_pcd->setEnabled(!_createdScans.empty());
|
||||
_ui->actionExport_2D_Grid_map_bmp_png->setEnabled(!_gridLocalMaps.empty() || !_projectionLocalMaps.empty());
|
||||
_ui->actionView_scans->setEnabled(!_createdScans.empty());
|
||||
_ui->actionExport_cameras_in_Bundle_format_out->setEnabled(!_cachedSignatures.empty() && !_currentPosesMap.empty());
|
||||
_ui->actionDownload_all_clouds->setEnabled(false);
|
||||
_ui->actionDownload_graph->setEnabled(false);
|
||||
_ui->menuSelect_source->setEnabled(false);
|
||||
@@ -5953,8 +6120,15 @@ void MainWindow::changeState(MainWindow::State newState)
|
||||
_ui->actionDump_the_prediction_matrix->setEnabled(true);
|
||||
_ui->actionDelete_memory->setEnabled(true);
|
||||
_ui->actionPost_processing->setEnabled(_cachedSignatures.size() >= 2 && _currentPosesMap.size() >= 2 && _currentLinksMap.size() >= 1);
|
||||
_ui->actionExport_images_RGB_jpg_Depth_png->setEnabled(!_cachedSignatures.empty() && !_currentPosesMap.empty());
|
||||
_ui->actionGenerate_map->setEnabled(true);
|
||||
_ui->menuExport_poses->setEnabled(true);
|
||||
_ui->menuExport_poses->setEnabled(!_currentPosesMap.empty());
|
||||
_ui->actionSave_point_cloud->setEnabled(!_createdClouds.empty());
|
||||
_ui->actionView_high_res_point_cloud->setEnabled(!_createdClouds.empty());
|
||||
_ui->actionExport_2D_scans_ply_pcd->setEnabled(!_createdScans.empty());
|
||||
_ui->actionExport_2D_Grid_map_bmp_png->setEnabled(!_gridLocalMaps.empty() || !_projectionLocalMaps.empty());
|
||||
_ui->actionView_scans->setEnabled(!_createdScans.empty());
|
||||
_ui->actionExport_cameras_in_Bundle_format_out->setEnabled(!_cachedSignatures.empty() && !_currentPosesMap.empty());
|
||||
_ui->actionDownload_all_clouds->setEnabled(true);
|
||||
_ui->actionDownload_graph->setEnabled(true);
|
||||
_ui->menuSelect_source->setEnabled(true);
|
||||
@@ -5991,8 +6165,15 @@ void MainWindow::changeState(MainWindow::State newState)
|
||||
_ui->actionDump_the_prediction_matrix->setEnabled(false);
|
||||
_ui->actionDelete_memory->setEnabled(false);
|
||||
_ui->actionPost_processing->setEnabled(false);
|
||||
_ui->actionExport_images_RGB_jpg_Depth_png->setEnabled(false);
|
||||
_ui->actionGenerate_map->setEnabled(false);
|
||||
_ui->menuExport_poses->setEnabled(false);
|
||||
_ui->actionSave_point_cloud->setEnabled(false);
|
||||
_ui->actionView_high_res_point_cloud->setEnabled(false);
|
||||
_ui->actionExport_2D_scans_ply_pcd->setEnabled(false);
|
||||
_ui->actionExport_2D_Grid_map_bmp_png->setEnabled(false);
|
||||
_ui->actionView_scans->setEnabled(false);
|
||||
_ui->actionExport_cameras_in_Bundle_format_out->setEnabled(false);
|
||||
_ui->actionDownload_all_clouds->setEnabled(false);
|
||||
_ui->actionDownload_graph->setEnabled(false);
|
||||
_ui->menuSelect_source->setEnabled(false);
|
||||
@@ -6031,8 +6212,15 @@ void MainWindow::changeState(MainWindow::State newState)
|
||||
_ui->actionDump_the_prediction_matrix->setEnabled(false);
|
||||
_ui->actionDelete_memory->setEnabled(false);
|
||||
_ui->actionPost_processing->setEnabled(false);
|
||||
_ui->actionExport_images_RGB_jpg_Depth_png->setEnabled(false);
|
||||
_ui->actionGenerate_map->setEnabled(false);
|
||||
_ui->menuExport_poses->setEnabled(false);
|
||||
_ui->actionSave_point_cloud->setEnabled(false);
|
||||
_ui->actionView_high_res_point_cloud->setEnabled(false);
|
||||
_ui->actionExport_2D_scans_ply_pcd->setEnabled(false);
|
||||
_ui->actionExport_2D_Grid_map_bmp_png->setEnabled(false);
|
||||
_ui->actionView_scans->setEnabled(false);
|
||||
_ui->actionExport_cameras_in_Bundle_format_out->setEnabled(false);
|
||||
_ui->actionDownload_all_clouds->setEnabled(false);
|
||||
_ui->actionDownload_graph->setEnabled(false);
|
||||
_state = kDetecting;
|
||||
@@ -6058,8 +6246,15 @@ void MainWindow::changeState(MainWindow::State newState)
|
||||
_ui->actionDump_the_prediction_matrix->setEnabled(true);
|
||||
_ui->actionDelete_memory->setEnabled(false);
|
||||
_ui->actionPost_processing->setEnabled(_cachedSignatures.size() >= 2 && _currentPosesMap.size() >= 2 && _currentLinksMap.size() >= 1);
|
||||
_ui->actionExport_images_RGB_jpg_Depth_png->setEnabled(!_cachedSignatures.empty() && !_currentPosesMap.empty());
|
||||
_ui->actionGenerate_map->setEnabled(true);
|
||||
_ui->menuExport_poses->setEnabled(true);
|
||||
_ui->menuExport_poses->setEnabled(!_currentPosesMap.empty());
|
||||
_ui->actionSave_point_cloud->setEnabled(!_createdClouds.empty());
|
||||
_ui->actionView_high_res_point_cloud->setEnabled(!_createdClouds.empty());
|
||||
_ui->actionExport_2D_scans_ply_pcd->setEnabled(!_createdScans.empty());
|
||||
_ui->actionExport_2D_Grid_map_bmp_png->setEnabled(!_gridLocalMaps.empty() || !_projectionLocalMaps.empty());
|
||||
_ui->actionView_scans->setEnabled(!_createdScans.empty());
|
||||
_ui->actionExport_cameras_in_Bundle_format_out->setEnabled(!_cachedSignatures.empty() && !_currentPosesMap.empty());
|
||||
_ui->actionDownload_all_clouds->setEnabled(true);
|
||||
_ui->actionDownload_graph->setEnabled(true);
|
||||
_state = kPaused;
|
||||
@@ -6086,6 +6281,14 @@ void MainWindow::changeState(MainWindow::State newState)
|
||||
_ui->actionPause_when_a_loop_hypothesis_is_rejected->setEnabled(true);
|
||||
_ui->actionReset_Odometry->setEnabled(true);
|
||||
_ui->actionPost_processing->setEnabled(false);
|
||||
_ui->actionExport_images_RGB_jpg_Depth_png->setEnabled(false);
|
||||
_ui->menuExport_poses->setEnabled(false);
|
||||
_ui->actionSave_point_cloud->setEnabled(false);
|
||||
_ui->actionView_high_res_point_cloud->setEnabled(false);
|
||||
_ui->actionExport_2D_scans_ply_pcd->setEnabled(false);
|
||||
_ui->actionExport_2D_Grid_map_bmp_png->setEnabled(false);
|
||||
_ui->actionView_scans->setEnabled(false);
|
||||
_ui->actionExport_cameras_in_Bundle_format_out->setEnabled(false);
|
||||
_ui->actionDelete_memory->setEnabled(true);
|
||||
_ui->actionDownload_all_clouds->setEnabled(true);
|
||||
_ui->actionDownload_graph->setEnabled(true);
|
||||
@@ -6108,6 +6311,14 @@ void MainWindow::changeState(MainWindow::State newState)
|
||||
_ui->actionPause_when_a_loop_hypothesis_is_rejected->setEnabled(true);
|
||||
_ui->actionReset_Odometry->setEnabled(true);
|
||||
_ui->actionPost_processing->setEnabled(_cachedSignatures.size() >= 2 && _currentPosesMap.size() >= 2 && _currentLinksMap.size() >= 1);
|
||||
_ui->actionExport_images_RGB_jpg_Depth_png->setEnabled(!_cachedSignatures.empty() && !_currentPosesMap.empty());
|
||||
_ui->menuExport_poses->setEnabled(!_currentPosesMap.empty());
|
||||
_ui->actionSave_point_cloud->setEnabled(!_createdClouds.empty());
|
||||
_ui->actionView_high_res_point_cloud->setEnabled(!_createdClouds.empty());
|
||||
_ui->actionExport_2D_scans_ply_pcd->setEnabled(!_createdScans.empty());
|
||||
_ui->actionExport_2D_Grid_map_bmp_png->setEnabled(!_gridLocalMaps.empty() || !_projectionLocalMaps.empty());
|
||||
_ui->actionView_scans->setEnabled(!_createdScans.empty());
|
||||
_ui->actionExport_cameras_in_Bundle_format_out->setEnabled(!_cachedSignatures.empty() && !_currentPosesMap.empty());
|
||||
_ui->actionDelete_memory->setEnabled(true);
|
||||
_ui->actionDownload_all_clouds->setEnabled(true);
|
||||
_ui->actionDownload_graph->setEnabled(true);
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>166</width>
|
||||
<width>197</width>
|
||||
<height>173</height>
|
||||
</rect>
|
||||
</property>
|
||||
@@ -236,7 +236,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>165</width>
|
||||
<width>196</width>
|
||||
<height>173</height>
|
||||
</rect>
|
||||
</property>
|
||||
@@ -429,6 +429,7 @@
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionSave_config"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionGenerate_3D_map_pcd"/>
|
||||
<addaction name="actionExport"/>
|
||||
<addaction name="actionExtract_images"/>
|
||||
<addaction name="separator"/>
|
||||
@@ -452,7 +453,6 @@
|
||||
<addaction name="actionReset_all_changes"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionView_3D_map"/>
|
||||
<addaction name="actionGenerate_3D_map_pcd"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuView">
|
||||
<property name="title">
|
||||
@@ -836,7 +836,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>338</width>
|
||||
<width>314</width>
|
||||
<height>303</height>
|
||||
</rect>
|
||||
</property>
|
||||
@@ -1375,7 +1375,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>338</width>
|
||||
<width>333</width>
|
||||
<height>333</height>
|
||||
</rect>
|
||||
</property>
|
||||
@@ -1613,8 +1613,8 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>-100</y>
|
||||
<width>338</width>
|
||||
<y>0</y>
|
||||
<width>276</width>
|
||||
<height>377</height>
|
||||
</rect>
|
||||
</property>
|
||||
@@ -1871,7 +1871,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>351</width>
|
||||
<width>289</width>
|
||||
<height>176</height>
|
||||
</rect>
|
||||
</property>
|
||||
@@ -1971,7 +1971,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>338</width>
|
||||
<width>285</width>
|
||||
<height>309</height>
|
||||
</rect>
|
||||
</property>
|
||||
@@ -2363,7 +2363,7 @@
|
||||
</action>
|
||||
<action name="actionExport">
|
||||
<property name="text">
|
||||
<string>Export...</string>
|
||||
<string>Export database...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionExtract_images">
|
||||
|
||||
+17
-11
@@ -34,6 +34,16 @@
|
||||
<property name="title">
|
||||
<string>File</string>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuExport_poses">
|
||||
<property name="title">
|
||||
<string>Export poses...</string>
|
||||
</property>
|
||||
<addaction name="actionRaw_format_txt"/>
|
||||
<addaction name="actionRGBD_SLAM_format_txt"/>
|
||||
<addaction name="actionKITTI_format_txt"/>
|
||||
<addaction name="actionTORO_graph"/>
|
||||
<addaction name="actionG2o_g2o"/>
|
||||
</widget>
|
||||
<addaction name="actionNew_database"/>
|
||||
<addaction name="actionOpen_database"/>
|
||||
<addaction name="separator"/>
|
||||
@@ -42,6 +52,8 @@
|
||||
<addaction name="actionSave_point_cloud"/>
|
||||
<addaction name="actionExport_2D_scans_ply_pcd"/>
|
||||
<addaction name="actionExport_2D_Grid_map_bmp_png"/>
|
||||
<addaction name="menuExport_poses"/>
|
||||
<addaction name="actionExport_images_RGB_jpg_Depth_png"/>
|
||||
<addaction name="actionExport_cameras_in_Bundle_format_out"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionClose_database"/>
|
||||
@@ -56,21 +68,10 @@
|
||||
<property name="title">
|
||||
<string>Advanced</string>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuExport_poses">
|
||||
<property name="title">
|
||||
<string>Export poses...</string>
|
||||
</property>
|
||||
<addaction name="actionRaw_format_txt"/>
|
||||
<addaction name="actionRGBD_SLAM_format_txt"/>
|
||||
<addaction name="actionKITTI_format_txt"/>
|
||||
<addaction name="actionTORO_graph"/>
|
||||
<addaction name="actionG2o_g2o"/>
|
||||
</widget>
|
||||
<addaction name="actionOpen_working_directory"/>
|
||||
<addaction name="actionDump_the_memory"/>
|
||||
<addaction name="actionDump_the_prediction_matrix"/>
|
||||
<addaction name="actionGenerate_map"/>
|
||||
<addaction name="menuExport_poses"/>
|
||||
<addaction name="actionPrint_loop_closure_IDs_to_console"/>
|
||||
</widget>
|
||||
<addaction name="actionDownload_all_clouds"/>
|
||||
@@ -1283,6 +1284,11 @@
|
||||
<string>Update cache from a local database copy...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionExport_images_RGB_jpg_Depth_png">
|
||||
<property name="text">
|
||||
<string>Export images (RGB=*.jpg Depth=*.png)...</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
|
||||
Reference in New Issue
Block a user