mirror of
https://github.com/introlab/rtabmap.git
synced 2026-09-02 17:40:23 +08:00
Integration of CLAMS depth calibration #114
This commit is contained in:
@@ -27,6 +27,7 @@ SET(headers_ui
|
||||
../include/${PROJECT_PREFIX}/gui/GraphViewer.h
|
||||
./CreateSimpleCalibrationDialog.h
|
||||
./ParametersToolBox.h
|
||||
./DepthCalibrationDialog.h
|
||||
)
|
||||
|
||||
SET(uis
|
||||
@@ -42,6 +43,7 @@ SET(uis
|
||||
./ui/exportScansDialog.ui
|
||||
./ui/calibrationDialog.ui
|
||||
./ui/createSimpleCalibrationDialog.ui
|
||||
./ui/depthCalibrationDialog.ui
|
||||
)
|
||||
|
||||
SET(qrc
|
||||
@@ -91,6 +93,8 @@ SET(SRC_FILES
|
||||
./GraphViewer.cpp
|
||||
./CreateSimpleCalibrationDialog.cpp
|
||||
./ParametersToolBox.cpp
|
||||
./DepthCalibrationDialog.cpp
|
||||
|
||||
${moc_srcs}
|
||||
${moc_uis}
|
||||
${srcs_qrc}
|
||||
|
||||
450
guilib/src/DepthCalibrationDialog.cpp
Normal file
450
guilib/src/DepthCalibrationDialog.cpp
Normal file
@@ -0,0 +1,450 @@
|
||||
/*
|
||||
Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Universite de Sherbrooke nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <DepthCalibrationDialog.h>
|
||||
#include "ui_depthCalibrationDialog.h"
|
||||
|
||||
#include "rtabmap/gui/ProgressDialog.h"
|
||||
#include "rtabmap/gui/CloudViewer.h"
|
||||
#include "rtabmap/gui/ImageView.h"
|
||||
#include "rtabmap/utilite/ULogger.h"
|
||||
#include "rtabmap/utilite/UThread.h"
|
||||
#include "rtabmap/utilite/UCv2Qt.h"
|
||||
#include "rtabmap/core/util3d.h"
|
||||
#include "rtabmap/core/util3d_filtering.h"
|
||||
#include "rtabmap/core/util3d_transforms.h"
|
||||
|
||||
#include "rtabmap/core/clams/slam_calibrator.h"
|
||||
#include "rtabmap/core/clams/frame_projector.h"
|
||||
|
||||
#include <QPushButton>
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QUrl>
|
||||
#include <QtGui/QDesktopServices>
|
||||
#include <QMessageBox>
|
||||
#include <QFileDialog>
|
||||
|
||||
namespace rtabmap {
|
||||
|
||||
DepthCalibrationDialog::DepthCalibrationDialog(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
_canceled(false),
|
||||
_model(0)
|
||||
{
|
||||
_ui = new Ui_DepthCalibrationDialog();
|
||||
_ui->setupUi(this);
|
||||
|
||||
connect(_ui->buttonBox->button(QDialogButtonBox::RestoreDefaults), SIGNAL(clicked()), this, SLOT(restoreDefaults()));
|
||||
connect(_ui->buttonBox->button(QDialogButtonBox::Save), SIGNAL(clicked()), this, SLOT(saveModel()));
|
||||
connect(_ui->buttonBox->button(QDialogButtonBox::Ok), SIGNAL(clicked()), this, SLOT(accept()));
|
||||
_ui->buttonBox->button(QDialogButtonBox::Ok)->setText("Calibrate");
|
||||
|
||||
restoreDefaults();
|
||||
|
||||
connect(_ui->spinBox_decimation, SIGNAL(valueChanged(int)), this, SIGNAL(configChanged()));
|
||||
connect(_ui->doubleSpinBox_maxDepth, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
|
||||
connect(_ui->doubleSpinBox_minDepth, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
|
||||
connect(_ui->doubleSpinBox_voxelSize, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
|
||||
connect(_ui->doubleSpinBox_coneRadius, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
|
||||
connect(_ui->doubleSpinBox_coneStdDevThresh, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
|
||||
connect(_ui->checkBox_laserScan, SIGNAL(stateChanged(int)), this, SIGNAL(configChanged()));
|
||||
|
||||
_ui->buttonBox->button(QDialogButtonBox::Ok)->setFocus();
|
||||
|
||||
_progressDialog = new ProgressDialog(this);
|
||||
_progressDialog->setVisible(false);
|
||||
_progressDialog->setAutoClose(true, 2);
|
||||
_progressDialog->setMinimumWidth(600);
|
||||
_progressDialog->setCancelButtonVisible(true);
|
||||
|
||||
connect(_progressDialog, SIGNAL(canceled()), this, SLOT(cancel()));
|
||||
}
|
||||
|
||||
DepthCalibrationDialog::~DepthCalibrationDialog()
|
||||
{
|
||||
delete _ui;
|
||||
if(_model)
|
||||
{
|
||||
delete _model;
|
||||
}
|
||||
}
|
||||
|
||||
void DepthCalibrationDialog::saveSettings(QSettings & settings, const QString & group) const
|
||||
{
|
||||
if(!group.isEmpty())
|
||||
{
|
||||
settings.beginGroup(group);
|
||||
}
|
||||
|
||||
settings.setValue("decimation", _ui->spinBox_decimation->value());
|
||||
settings.setValue("max_depth", _ui->doubleSpinBox_maxDepth->value());
|
||||
settings.setValue("min_depth", _ui->doubleSpinBox_minDepth->value());
|
||||
settings.setValue("voxel",_ui->doubleSpinBox_voxelSize->value());
|
||||
settings.setValue("cone_radius",_ui->doubleSpinBox_coneRadius->value());
|
||||
settings.setValue("cone_stddev_thresh",_ui->doubleSpinBox_coneStdDevThresh->value());
|
||||
settings.setValue("laser_scan",_ui->checkBox_laserScan->isChecked());
|
||||
|
||||
if(!group.isEmpty())
|
||||
{
|
||||
settings.endGroup();
|
||||
}
|
||||
}
|
||||
|
||||
void DepthCalibrationDialog::loadSettings(QSettings & settings, const QString & group)
|
||||
{
|
||||
if(!group.isEmpty())
|
||||
{
|
||||
settings.beginGroup(group);
|
||||
}
|
||||
|
||||
_ui->spinBox_decimation->setValue(settings.value("decimation", _ui->spinBox_decimation->value()).toInt());
|
||||
_ui->doubleSpinBox_maxDepth->setValue(settings.value("max_depth", _ui->doubleSpinBox_maxDepth->value()).toDouble());
|
||||
_ui->doubleSpinBox_minDepth->setValue(settings.value("min_depth", _ui->doubleSpinBox_minDepth->value()).toDouble());
|
||||
_ui->doubleSpinBox_voxelSize->setValue(settings.value("voxel", _ui->doubleSpinBox_voxelSize->value()).toDouble());
|
||||
_ui->doubleSpinBox_coneRadius->setValue(settings.value("cone_radius", _ui->doubleSpinBox_coneRadius->value()).toDouble());
|
||||
_ui->doubleSpinBox_coneStdDevThresh->setValue(settings.value("cone_stddev_thresh", _ui->doubleSpinBox_coneStdDevThresh->value()).toDouble());
|
||||
_ui->checkBox_laserScan->setChecked(settings.value("laser_scan", _ui->checkBox_laserScan->isChecked()).toBool());
|
||||
|
||||
if(!group.isEmpty())
|
||||
{
|
||||
settings.endGroup();
|
||||
}
|
||||
}
|
||||
|
||||
void DepthCalibrationDialog::restoreDefaults()
|
||||
{
|
||||
_ui->spinBox_decimation->setValue(1);
|
||||
_ui->doubleSpinBox_maxDepth->setValue(3.5);
|
||||
_ui->doubleSpinBox_minDepth->setValue(0);
|
||||
_ui->doubleSpinBox_voxelSize->setValue(0.01);
|
||||
_ui->doubleSpinBox_coneRadius->setValue(0.02);
|
||||
_ui->doubleSpinBox_coneStdDevThresh->setValue(0.1); // 0.03
|
||||
_ui->checkBox_laserScan->setChecked(false);
|
||||
_ui->checkBox_resetModel->setChecked(true);
|
||||
}
|
||||
|
||||
void DepthCalibrationDialog::saveModel()
|
||||
{
|
||||
if(_model && _model->getTrainingSamples())
|
||||
{
|
||||
QString path = QFileDialog::getSaveFileName(this, tr("Save distortion model to ..."), _workingDirectory+QDir::separator()+"distortion_model.bin", tr("Distortion model (*.bin)"));
|
||||
if(!path.isEmpty())
|
||||
{
|
||||
//
|
||||
// Save depth calibration
|
||||
//
|
||||
cv::Mat results = _model->visualize(ULogger::level() == ULogger::kDebug?_workingDirectory.toStdString():"");
|
||||
_model->save(path.toStdString());
|
||||
|
||||
if(!results.empty())
|
||||
{
|
||||
QString name = QString(path).replace(".bin", ".png", Qt::CaseInsensitive);
|
||||
cv::imwrite(name.toStdString(), results);
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(name));
|
||||
}
|
||||
|
||||
QMessageBox::information(this, tr("Depth Calibration"), tr("Distortion model saved to \"%1\"!").arg(path));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DepthCalibrationDialog::cancel()
|
||||
{
|
||||
_canceled = true;
|
||||
_progressDialog->appendText(tr("Canceled!"));
|
||||
}
|
||||
|
||||
void DepthCalibrationDialog::calibrate(
|
||||
const std::map<int, Transform> & poses,
|
||||
const QMap<int, Signature> & cachedSignatures,
|
||||
const QString & workingDirectory,
|
||||
const ParametersMap & parameters)
|
||||
{
|
||||
_canceled = false;
|
||||
_workingDirectory = workingDirectory;
|
||||
_ui->buttonBox->button(QDialogButtonBox::Save)->setEnabled(_model && _model->getTrainingSamples()>0);
|
||||
if(_model)
|
||||
{
|
||||
_ui->label_trainingSamples->setNum((int)_model->getTrainingSamples());
|
||||
}
|
||||
if(this->exec() == QDialog::Accepted)
|
||||
{
|
||||
if(_model && _ui->checkBox_resetModel->isChecked())
|
||||
{
|
||||
delete _model;
|
||||
_model = 0;
|
||||
}
|
||||
|
||||
_progressDialog->setMaximumSteps(poses.size()*2 + 3);
|
||||
if(_ui->doubleSpinBox_voxelSize->value() > 0.0)
|
||||
{
|
||||
_progressDialog->setMaximumSteps(_progressDialog->maximumSteps()+1);
|
||||
}
|
||||
_progressDialog->resetProgress();
|
||||
_progressDialog->show();
|
||||
|
||||
std::map<int, rtabmap::SensorData> sequence;
|
||||
|
||||
// Create the map
|
||||
pcl::PointCloud<pcl::PointXYZ>::Ptr map(new pcl::PointCloud<pcl::PointXYZ>);
|
||||
int index=1;
|
||||
for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end() && !_canceled; ++iter, ++index)
|
||||
{
|
||||
int points = 0;
|
||||
if(!iter->second.isNull())
|
||||
{
|
||||
pcl::IndicesPtr indices(new std::vector<int>);
|
||||
if(cachedSignatures.contains(iter->first))
|
||||
{
|
||||
const Signature & s = cachedSignatures.find(iter->first).value();
|
||||
SensorData data = s.sensorData();
|
||||
if(data.cameraModels().size() == 1 && data.cameraModels()[0].isValidForReprojection())
|
||||
{
|
||||
cv::Mat image, depth, laserScan;
|
||||
data.uncompressData(&image, &depth, _ui->checkBox_laserScan->isChecked()?&laserScan:0);
|
||||
if(!image.empty() && !depth.empty())
|
||||
{
|
||||
UASSERT(iter->first == data.id());
|
||||
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud;
|
||||
|
||||
if(_ui->checkBox_laserScan->isChecked())
|
||||
{
|
||||
cloud = util3d::laserScanToPointCloud(laserScan);
|
||||
indices->resize(cloud->size());
|
||||
for(unsigned int i=0; i<indices->size(); ++i)
|
||||
{
|
||||
indices->at(i) = i;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cloud = util3d::cloudFromSensorData(
|
||||
data,
|
||||
_ui->spinBox_decimation->value(),
|
||||
_ui->doubleSpinBox_maxDepth->value(),
|
||||
_ui->doubleSpinBox_minDepth->value(),
|
||||
indices.get(),
|
||||
parameters);
|
||||
}
|
||||
|
||||
if(indices->size())
|
||||
{
|
||||
if(_ui->doubleSpinBox_voxelSize->value() > 0.0)
|
||||
{
|
||||
cloud = util3d::voxelize(cloud, indices, _ui->doubleSpinBox_voxelSize->value());
|
||||
}
|
||||
|
||||
cloud = util3d::transformPointCloud(cloud, iter->second);
|
||||
|
||||
points+=cloud->size();
|
||||
|
||||
*map += *cloud;
|
||||
|
||||
sequence.insert(std::make_pair(iter->first, data));
|
||||
|
||||
cv::Size size = data.cameraModels()[0].imageSize();
|
||||
if(_model &&
|
||||
(_model->getWidth()!=size.width ||
|
||||
_model->getHeight()!=size.height))
|
||||
{
|
||||
QString msg = tr("Depth images (%1x%2) in the map don't have the "
|
||||
"same size then in the current model (%3x%4). You may want "
|
||||
"to check \"Reset previous model\" before trying again.")
|
||||
.arg(size.width).arg(size.height)
|
||||
.arg(_model->getWidth()).arg(_model->getHeight());
|
||||
QMessageBox::warning(this, tr("Depth Calibration"), msg);
|
||||
_progressDialog->appendText(msg, Qt::darkRed);
|
||||
_progressDialog->setAutoClose(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_progressDialog->appendText(tr("Not suitable camera model found for node %1, ignoring this node!").arg(iter->first), Qt::darkYellow);
|
||||
_progressDialog->setAutoClose(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UERROR("Cloud %d not found in cache!", iter->first);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UERROR("transform is null!?");
|
||||
}
|
||||
|
||||
if(points>0)
|
||||
{
|
||||
_progressDialog->appendText(tr("Generated cloud %1 with %2 points (%3/%4).")
|
||||
.arg(iter->first).arg(points).arg(index).arg(poses.size()));
|
||||
}
|
||||
else
|
||||
{
|
||||
_progressDialog->appendText(tr("Ignored cloud %1 (%2/%3).").arg(iter->first).arg(index).arg(poses.size()));
|
||||
}
|
||||
_progressDialog->incrementStep();
|
||||
QApplication::processEvents();
|
||||
}
|
||||
|
||||
if(!_canceled && map->size() && sequence.size())
|
||||
{
|
||||
if(_ui->doubleSpinBox_voxelSize->value() > 0.0)
|
||||
{
|
||||
_progressDialog->appendText(tr("Voxel filtering (%1 m) of the merged point cloud (%2 points)")
|
||||
.arg(_ui->doubleSpinBox_voxelSize->value())
|
||||
.arg(map->size()));
|
||||
QApplication::processEvents();
|
||||
QApplication::processEvents();
|
||||
|
||||
map = util3d::voxelize(map, _ui->doubleSpinBox_voxelSize->value());
|
||||
_progressDialog->incrementStep();
|
||||
}
|
||||
|
||||
if(ULogger::level() == ULogger::kDebug)
|
||||
{
|
||||
//
|
||||
// Show 3D map with frustums
|
||||
//
|
||||
QDialog * window = new QDialog(this->parentWidget()?this->parentWidget():this, Qt::Window);
|
||||
window->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
window->setWindowTitle(tr("Map"));
|
||||
window->setMinimumWidth(800);
|
||||
window->setMinimumHeight(600);
|
||||
|
||||
CloudViewer * viewer = new CloudViewer(window);
|
||||
viewer->setCameraLockZ(false);
|
||||
viewer->setFrustumShown(true);
|
||||
|
||||
QVBoxLayout *layout = new QVBoxLayout();
|
||||
layout->addWidget(viewer);
|
||||
window->setLayout(layout);
|
||||
connect(window, SIGNAL(finished(int)), viewer, SLOT(clear()));
|
||||
|
||||
window->show();
|
||||
|
||||
uSleep(500);
|
||||
|
||||
_progressDialog->appendText(tr("Viewing the cloud (%1 points and %2 poses)...").arg(map->size()).arg(sequence.size()));
|
||||
_progressDialog->incrementStep();
|
||||
viewer->addCloud("map", map);
|
||||
Transform opticalRot(0, 0, 1, 0, -1, 0, 0, 0, 0, -1, 0, 0);
|
||||
for(std::map<int, SensorData>::iterator iter=sequence.begin(); iter!=sequence.end(); ++iter)
|
||||
{
|
||||
Transform baseToCamera = iter->second.cameraModels()[0].localTransform()*opticalRot.inverse();
|
||||
viewer->addOrUpdateFrustum(uFormat("frustum%d",iter->first), poses.at(iter->first) * baseToCamera, 0.2);
|
||||
}
|
||||
_progressDialog->appendText(tr("Viewing the cloud (%1 points and %2 poses)... done.").arg(map->size()).arg(sequence.size()));
|
||||
|
||||
viewer->update();
|
||||
}
|
||||
|
||||
_progressDialog->appendText(tr("CLAMS depth calibration..."));
|
||||
QApplication::processEvents();
|
||||
QApplication::processEvents();
|
||||
|
||||
QDialog * dialog = new QDialog(this->parentWidget()?this->parentWidget():this, Qt::Window);
|
||||
dialog->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
dialog->setWindowTitle(tr("Original/Map"));
|
||||
dialog->setMinimumWidth(sequence.begin()->second.cameraModels()[0].imageWidth());
|
||||
ImageView * imageView1 = new ImageView(dialog);
|
||||
imageView1->setMinimumSize(320, 240);
|
||||
ImageView * imageView2 = new ImageView(dialog);
|
||||
imageView2->setMinimumSize(320, 240);
|
||||
QVBoxLayout * vlayout = new QVBoxLayout();
|
||||
vlayout->setMargin(0);
|
||||
vlayout->addWidget(imageView1, 1);
|
||||
vlayout->addWidget(imageView2, 1);
|
||||
dialog->setLayout(vlayout);
|
||||
if(ULogger::level() == ULogger::kDebug)
|
||||
{
|
||||
dialog->show();
|
||||
}
|
||||
|
||||
//clams::DiscreteDepthDistortionModel model = clams::calibrate(sequence, poses, map);
|
||||
const cv::Size & imageSize = sequence.begin()->second.cameraModels()[0].imageSize();
|
||||
if(_model == 0)
|
||||
{
|
||||
_model = new clams::DiscreteDepthDistortionModel(imageSize.width, imageSize.height);
|
||||
}
|
||||
UASSERT(_model->getWidth() == imageSize.width && _model->getHeight() == imageSize.height);
|
||||
|
||||
// -- For all selected frames, accumulate training examples
|
||||
// in the distortion model.
|
||||
size_t counts;
|
||||
index = 0;
|
||||
for(std::map<int, rtabmap::Transform>::const_iterator iter = poses.begin(); iter != poses.end() && !_canceled; ++iter)
|
||||
{
|
||||
size_t idx = iter->first;
|
||||
std::map<int, rtabmap::SensorData>::const_iterator ster = sequence.find(idx);
|
||||
if(ster!=sequence.end())
|
||||
{
|
||||
cv::Mat depthImage;
|
||||
ster->second.uncompressDataConst(0, &depthImage);
|
||||
|
||||
cv::Mat mapDepth;
|
||||
clams::FrameProjector projector(ster->second.cameraModels()[0]);
|
||||
mapDepth = projector.estimateMapDepth(
|
||||
map,
|
||||
iter->second.inverse(),
|
||||
depthImage,
|
||||
_ui->doubleSpinBox_coneRadius->value(),
|
||||
_ui->doubleSpinBox_coneStdDevThresh->value());
|
||||
|
||||
if(ULogger::level() == ULogger::kDebug)
|
||||
{
|
||||
imageView1->setImage(uCvMat2QImage(depthImage));
|
||||
imageView2->setImage(uCvMat2QImage(mapDepth));
|
||||
}
|
||||
|
||||
counts = _model->accumulate(mapDepth, depthImage);
|
||||
_progressDialog->appendText(tr("Added %1 training examples from node %2 (%3/%4).").arg(counts).arg(iter->first).arg(++index).arg(sequence.size()));
|
||||
}
|
||||
_progressDialog->incrementStep();
|
||||
QApplication::processEvents();
|
||||
}
|
||||
|
||||
_progressDialog->appendText(tr("CLAMS depth calibration... done!"));
|
||||
QApplication::processEvents();
|
||||
|
||||
if(!_canceled)
|
||||
{
|
||||
this->saveModel();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::warning(this, tr("Depth Calibration"), tr("The resulting map is empty!"));
|
||||
}
|
||||
_progressDialog->setValue(_progressDialog->maximumSteps());
|
||||
}
|
||||
}
|
||||
|
||||
} /* namespace rtabmap */
|
||||
83
guilib/src/DepthCalibrationDialog.h
Normal file
83
guilib/src/DepthCalibrationDialog.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Universite de Sherbrooke nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef GUILIB_SRC_DEPTHCALIBRATIONDIALOG_H_
|
||||
#define GUILIB_SRC_DEPTHCALIBRATIONDIALOG_H_
|
||||
|
||||
#include <QDialog>
|
||||
#include <QMap>
|
||||
#include <QtCore/QSettings>
|
||||
#include <rtabmap/core/Signature.h>
|
||||
#include <rtabmap/core/Parameters.h>
|
||||
|
||||
class Ui_DepthCalibrationDialog;
|
||||
|
||||
namespace clams {
|
||||
class DiscreteDepthDistortionModel;
|
||||
}
|
||||
|
||||
namespace rtabmap {
|
||||
|
||||
class ProgressDialog;
|
||||
|
||||
class DepthCalibrationDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DepthCalibrationDialog(QWidget * parent = 0);
|
||||
virtual ~DepthCalibrationDialog();
|
||||
|
||||
void saveSettings(QSettings & settings, const QString & group = "") const;
|
||||
void loadSettings(QSettings & settings, const QString & group = "");
|
||||
|
||||
void calibrate(const std::map<int, Transform> & poses,
|
||||
const QMap<int, Signature> & cachedSignatures,
|
||||
const QString & workingDirectory,
|
||||
const ParametersMap & parameters);
|
||||
|
||||
signals:
|
||||
void configChanged();
|
||||
|
||||
public slots:
|
||||
void restoreDefaults();
|
||||
|
||||
private slots:
|
||||
void saveModel();
|
||||
void cancel();
|
||||
|
||||
private:
|
||||
Ui_DepthCalibrationDialog * _ui;
|
||||
ProgressDialog * _progressDialog;
|
||||
bool _canceled;
|
||||
clams::DiscreteDepthDistortionModel * _model;
|
||||
QString _workingDirectory;
|
||||
};
|
||||
|
||||
} /* namespace rtabmap */
|
||||
|
||||
#endif /* GUILIB_SRC_DEPTHCALIBRATIONDIALOG_H_ */
|
||||
@@ -41,6 +41,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "rtabmap/core/util3d.h"
|
||||
#include "rtabmap/core/Graph.h"
|
||||
#include "rtabmap/core/GainCompensator.h"
|
||||
#include "rtabmap/core/clams/discrete_depth_distortion_model.h"
|
||||
|
||||
#include <pcl/conversions.h>
|
||||
#include <pcl/io/pcd_io.h>
|
||||
@@ -58,7 +59,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
namespace rtabmap {
|
||||
|
||||
ExportCloudsDialog::ExportCloudsDialog(QWidget *parent) :
|
||||
QDialog(parent)
|
||||
QDialog(parent),
|
||||
_canceled(false)
|
||||
{
|
||||
_ui = new Ui_ExportCloudsDialog();
|
||||
_ui->setupUi(this);
|
||||
@@ -77,6 +79,8 @@ ExportCloudsDialog::ExportCloudsDialog(QWidget *parent) :
|
||||
connect(_ui->spinBox_decimation, SIGNAL(valueChanged(int)), this, SIGNAL(configChanged()));
|
||||
connect(_ui->doubleSpinBox_maxDepth, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
|
||||
connect(_ui->doubleSpinBox_minDepth, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
|
||||
connect(_ui->lineEdit_distortionModel, SIGNAL(textChanged(const QString &)), this, SIGNAL(configChanged()));
|
||||
connect(_ui->toolButton_distortionModel, SIGNAL(clicked()), this, SLOT(selectDistortionModel()));
|
||||
|
||||
connect(_ui->groupBox_filtering, SIGNAL(clicked(bool)), this, SIGNAL(configChanged()));
|
||||
connect(_ui->doubleSpinBox_filteringRadius, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
|
||||
@@ -120,6 +124,8 @@ ExportCloudsDialog::ExportCloudsDialog(QWidget *parent) :
|
||||
_progressDialog->setVisible(false);
|
||||
_progressDialog->setAutoClose(true, 2);
|
||||
_progressDialog->setMinimumWidth(600);
|
||||
_progressDialog->setCancelButtonVisible(true);
|
||||
connect(_progressDialog, SIGNAL(canceled()), this, SLOT(cancel()));
|
||||
|
||||
#ifdef DISABLE_VTK
|
||||
_ui->doubleSpinBox_meshDecimationFactor->setEnabled(false);
|
||||
@@ -148,6 +154,12 @@ void ExportCloudsDialog::updateTexturingAvailability()
|
||||
_ui->label_meshDecimation->setEnabled(_ui->doubleSpinBox_meshDecimationFactor->isEnabled());
|
||||
}
|
||||
|
||||
void ExportCloudsDialog::cancel()
|
||||
{
|
||||
_canceled = true;
|
||||
_progressDialog->appendText(tr("Canceled!"));
|
||||
}
|
||||
|
||||
void ExportCloudsDialog::saveSettings(QSettings & settings, const QString & group) const
|
||||
{
|
||||
if(!group.isEmpty())
|
||||
@@ -162,6 +174,7 @@ void ExportCloudsDialog::saveSettings(QSettings & settings, const QString & grou
|
||||
settings.setValue("regenerate_decimation", _ui->spinBox_decimation->value());
|
||||
settings.setValue("regenerate_max_depth", _ui->doubleSpinBox_maxDepth->value());
|
||||
settings.setValue("regenerate_min_depth", _ui->doubleSpinBox_minDepth->value());
|
||||
settings.setValue("regenerate_distortion_model", _ui->lineEdit_distortionModel->text());
|
||||
|
||||
|
||||
settings.setValue("filtering", _ui->groupBox_filtering->isChecked());
|
||||
@@ -225,6 +238,7 @@ void ExportCloudsDialog::loadSettings(QSettings & settings, const QString & grou
|
||||
_ui->spinBox_decimation->setValue(settings.value("regenerate_decimation", _ui->spinBox_decimation->value()).toInt());
|
||||
_ui->doubleSpinBox_maxDepth->setValue(settings.value("regenerate_max_depth", _ui->doubleSpinBox_maxDepth->value()).toDouble());
|
||||
_ui->doubleSpinBox_minDepth->setValue(settings.value("regenerate_min_depth", _ui->doubleSpinBox_minDepth->value()).toDouble());
|
||||
_ui->lineEdit_distortionModel->setText(settings.value("regenerate_distortion_model", _ui->lineEdit_distortionModel->text()).toString());
|
||||
|
||||
_ui->groupBox_filtering->setChecked(settings.value("filtering", _ui->groupBox_filtering->isChecked()).toBool());
|
||||
_ui->doubleSpinBox_filteringRadius->setValue(settings.value("filtering_radius", _ui->doubleSpinBox_filteringRadius->value()).toDouble());
|
||||
@@ -285,6 +299,7 @@ void ExportCloudsDialog::restoreDefaults()
|
||||
_ui->spinBox_decimation->setValue(1);
|
||||
_ui->doubleSpinBox_maxDepth->setValue(4);
|
||||
_ui->doubleSpinBox_minDepth->setValue(0);
|
||||
_ui->lineEdit_distortionModel->setText("");
|
||||
|
||||
_ui->groupBox_filtering->setChecked(false);
|
||||
_ui->doubleSpinBox_filteringRadius->setValue(0.02);
|
||||
@@ -339,6 +354,20 @@ void ExportCloudsDialog::updateReconstructionFlavor()
|
||||
_ui->groupBox_organized->setVisible(_ui->comboBox_pipeline->currentIndex() == 0);
|
||||
}
|
||||
|
||||
void ExportCloudsDialog::selectDistortionModel()
|
||||
{
|
||||
QString dir = _ui->lineEdit_distortionModel->text();
|
||||
if(dir.isEmpty())
|
||||
{
|
||||
dir = _workingDirectory;
|
||||
}
|
||||
QString path = QFileDialog::getOpenFileName(this, tr("Select file"), dir, tr("Distortion model (*.bin)"));
|
||||
if(path.size())
|
||||
{
|
||||
_ui->lineEdit_distortionModel->setText(path);
|
||||
}
|
||||
}
|
||||
|
||||
void ExportCloudsDialog::setSaveButton()
|
||||
{
|
||||
_ui->buttonBox->button(QDialogButtonBox::Ok)->setVisible(false);
|
||||
@@ -423,7 +452,7 @@ void ExportCloudsDialog::exportClouds(
|
||||
saveClouds(workingDirectory, poses, clouds, _ui->checkBox_binary->isChecked());
|
||||
}
|
||||
}
|
||||
else
|
||||
else if(!_canceled)
|
||||
{
|
||||
_progressDialog->setAutoClose(false);
|
||||
}
|
||||
@@ -605,6 +634,8 @@ bool ExportCloudsDialog::getExportedClouds(
|
||||
std::map<int, pcl::PolygonMesh::Ptr> & meshes,
|
||||
std::map<int, pcl::TextureMesh::Ptr> & textureMeshes)
|
||||
{
|
||||
_canceled = false;
|
||||
_workingDirectory = workingDirectory;
|
||||
enableRegeneration(cachedSignatures.size());
|
||||
if(this->exec() == QDialog::Accepted)
|
||||
{
|
||||
@@ -650,6 +681,11 @@ bool ExportCloudsDialog::getExportedClouds(
|
||||
cachedClouds,
|
||||
parameters);
|
||||
|
||||
if(_canceled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(clouds.empty())
|
||||
{
|
||||
_progressDialog->setAutoClose(false);
|
||||
@@ -686,6 +722,10 @@ bool ExportCloudsDialog::getExportedClouds(
|
||||
_progressDialog->appendText(tr("Cloud %1 has gain %2").arg(jter->first).arg(gain));
|
||||
_progressDialog->incrementStep();
|
||||
QApplication::processEvents();
|
||||
if(_canceled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -721,6 +761,10 @@ bool ExportCloudsDialog::getExportedClouds(
|
||||
_progressDialog->appendText(tr("Assembled cloud %1, total=%2 (%3/%4).").arg(iter->first).arg(assembledCloud->size()).arg(++i).arg(clouds.size()));
|
||||
_progressDialog->incrementStep();
|
||||
QApplication::processEvents();
|
||||
if(_canceled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
pcl::copyPointCloud(*assembledCloud, *rawAssembledCloud);
|
||||
@@ -740,6 +784,11 @@ bool ExportCloudsDialog::getExportedClouds(
|
||||
clouds.insert(std::make_pair(0, std::make_pair(assembledCloud, pcl::IndicesPtr(new std::vector<int>))));
|
||||
}
|
||||
|
||||
if(_canceled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::map<int, Transform> viewPoints = poses;
|
||||
if(_ui->groupBox_mls->isChecked())
|
||||
{
|
||||
@@ -787,6 +836,10 @@ bool ExportCloudsDialog::getExportedClouds(
|
||||
|
||||
_progressDialog->appendText(tr("Smoothing (MLS) the cloud (%1 points)...").arg(cloudWithNormals->size()));
|
||||
QApplication::processEvents();
|
||||
if(_canceled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
cloudWithNormals = util3d::mls(
|
||||
cloudWithoutNormals,
|
||||
@@ -832,6 +885,10 @@ bool ExportCloudsDialog::getExportedClouds(
|
||||
|
||||
_progressDialog->incrementStep();
|
||||
QApplication::processEvents();
|
||||
if(_canceled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//used for organized texturing below
|
||||
@@ -968,6 +1025,10 @@ bool ExportCloudsDialog::getExportedClouds(
|
||||
|
||||
_progressDialog->incrementStep();
|
||||
QApplication::processEvents();
|
||||
if(_canceled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(_ui->checkBox_assemble->isChecked() && mergedClouds->size())
|
||||
@@ -1015,7 +1076,6 @@ bool ExportCloudsDialog::getExportedClouds(
|
||||
_progressDialog->incrementStep();
|
||||
QApplication::processEvents();
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1073,10 +1133,19 @@ bool ExportCloudsDialog::getExportedClouds(
|
||||
|
||||
_progressDialog->incrementStep();
|
||||
QApplication::processEvents();
|
||||
if(_canceled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(_canceled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// texture mesh
|
||||
UDEBUG("texture mapping=%d", _ui->checkBox_textureMapping->isChecked()?1:0);
|
||||
if(_ui->checkBox_textureMapping->isEnabled() && _ui->checkBox_textureMapping->isChecked())
|
||||
@@ -1228,6 +1297,10 @@ bool ExportCloudsDialog::getExportedClouds(
|
||||
_progressDialog->appendText(tr("TextureMesh %1 created [cameras=%2] (%3/%4).").arg(iter->first).arg(cameraPoses.size()).arg(++i).arg(meshes.size()));
|
||||
_progressDialog->incrementStep();
|
||||
QApplication::processEvents();
|
||||
if(_canceled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(textureMeshes.size() > 1 && _ui->checkBox_assemble->isChecked())
|
||||
@@ -1260,7 +1333,7 @@ std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr, pcl::Indic
|
||||
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr previousCloud;
|
||||
pcl::IndicesPtr previousIndices;
|
||||
Transform previousPose;
|
||||
for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter, ++index)
|
||||
for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end() && !_canceled; ++iter, ++index)
|
||||
{
|
||||
int points = 0;
|
||||
int totalIndices = 0;
|
||||
@@ -1278,6 +1351,16 @@ std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr, pcl::Indic
|
||||
d.uncompressData(&image, &depth, 0);
|
||||
if(!image.empty() && !depth.empty())
|
||||
{
|
||||
if(!_ui->lineEdit_distortionModel->text().isEmpty() &&
|
||||
QFileInfo(_ui->lineEdit_distortionModel->text()).exists())
|
||||
{
|
||||
clams::DiscreteDepthDistortionModel model;
|
||||
model.load(_ui->lineEdit_distortionModel->text().toStdString());
|
||||
depth = depth.clone();// make sure we are not modifying data in cached signatures.
|
||||
model.undistort(depth);
|
||||
d.setDepthOrRightRaw(depth);
|
||||
}
|
||||
|
||||
UASSERT(iter->first == d.id());
|
||||
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloudWithoutNormals;
|
||||
cloudWithoutNormals = util3d::cloudRGBFromSensorData(
|
||||
@@ -1555,6 +1638,10 @@ void ExportCloudsDialog::saveClouds(
|
||||
}
|
||||
_progressDialog->incrementStep();
|
||||
QApplication::processEvents();
|
||||
if(_canceled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1708,6 +1795,10 @@ void ExportCloudsDialog::saveMeshes(
|
||||
}
|
||||
_progressDialog->incrementStep();
|
||||
QApplication::processEvents();
|
||||
if(_canceled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1847,6 +1938,10 @@ void ExportCloudsDialog::saveTextureMeshes(
|
||||
}
|
||||
_progressDialog->incrementStep();
|
||||
QApplication::processEvents();
|
||||
if(_canceled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,8 +87,10 @@ public slots:
|
||||
|
||||
private slots:
|
||||
void updateReconstructionFlavor();
|
||||
void selectDistortionModel();
|
||||
void updateMLSGrpVisibility();
|
||||
void updateTexturingAvailability();
|
||||
void cancel();
|
||||
|
||||
private:
|
||||
std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr, pcl::IndicesPtr> > getClouds(
|
||||
@@ -118,6 +120,8 @@ private:
|
||||
private:
|
||||
Ui_ExportCloudsDialog * _ui;
|
||||
ProgressDialog * _progressDialog;
|
||||
QString _workingDirectory;
|
||||
bool _canceled;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -65,6 +65,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "ExportScansDialog.h"
|
||||
#include "AboutDialog.h"
|
||||
#include "PostProcessingDialog.h"
|
||||
#include "DepthCalibrationDialog.h"
|
||||
|
||||
#include <QtGui/QCloseEvent>
|
||||
#include <QtGui/QPixmap>
|
||||
@@ -165,7 +166,8 @@ MainWindow::MainWindow(PreferencesDialog * prefDialog, QWidget * parent) :
|
||||
_rawLikelihoodCurve(0),
|
||||
_autoScreenCaptureOdomSync(false),
|
||||
_autoScreenCaptureRAM(false),
|
||||
_firstCall(true)
|
||||
_firstCall(true),
|
||||
_progressCanceled(false)
|
||||
{
|
||||
UDEBUG("");
|
||||
|
||||
@@ -186,6 +188,8 @@ MainWindow::MainWindow(PreferencesDialog * prefDialog, QWidget * parent) :
|
||||
_exportScansDialog->setObjectName("ExportScansDialog");
|
||||
_postProcessingDialog = new PostProcessingDialog(this);
|
||||
_postProcessingDialog->setObjectName("PostProcessingDialog");
|
||||
_depthCalibrationDialog = new DepthCalibrationDialog(this);
|
||||
_depthCalibrationDialog->setObjectName("DepthCalibrationDialog");
|
||||
|
||||
_ui = new Ui_mainWindow();
|
||||
UDEBUG("Setup ui...");
|
||||
@@ -235,6 +239,7 @@ MainWindow::MainWindow(PreferencesDialog * prefDialog, QWidget * parent) :
|
||||
_preferencesDialog->loadWindowGeometry(_exportCloudsDialog);
|
||||
_preferencesDialog->loadWindowGeometry(_exportScansDialog);
|
||||
_preferencesDialog->loadWindowGeometry(_postProcessingDialog);
|
||||
_preferencesDialog->loadWindowGeometry(_depthCalibrationDialog);
|
||||
_preferencesDialog->loadWindowGeometry(_aboutDialog);
|
||||
setupMainLayout(_preferencesDialog->isVerticalLayoutUsed());
|
||||
|
||||
@@ -281,6 +286,7 @@ MainWindow::MainWindow(PreferencesDialog * prefDialog, QWidget * parent) :
|
||||
_initProgressDialog = new ProgressDialog(this);
|
||||
_initProgressDialog->setWindowTitle(tr("Progress dialog"));
|
||||
_initProgressDialog->setMinimumWidth(800);
|
||||
connect(_initProgressDialog, SIGNAL(canceled()), this, SLOT(cancelProgress()));
|
||||
|
||||
connect(_ui->widget_mapVisibility, SIGNAL(visibilityChanged(int, bool)), this, SLOT(updateNodeVisibility(int, bool)));
|
||||
|
||||
@@ -375,6 +381,7 @@ MainWindow::MainWindow(PreferencesDialog * prefDialog, QWidget * parent) :
|
||||
connect(_ui->actionTrigger_a_new_map, SIGNAL(triggered()), this, SLOT(triggerNewMap()));
|
||||
connect(_ui->actionData_recorder, SIGNAL(triggered()), this, SLOT(dataRecorder()));
|
||||
connect(_ui->actionPost_processing, SIGNAL(triggered()), this, SLOT(postProcessing()));
|
||||
connect(_ui->actionDepth_Calibration, SIGNAL(triggered()), this, SLOT(depthCalibration()));
|
||||
|
||||
_ui->actionPause->setShortcut(Qt::Key_Space);
|
||||
_ui->actionSave_GUI_config->setShortcut(QKeySequence::Save);
|
||||
@@ -458,6 +465,7 @@ MainWindow::MainWindow(PreferencesDialog * prefDialog, QWidget * parent) :
|
||||
connect(_exportCloudsDialog, SIGNAL(configChanged()), this, SLOT(configGUIModified()));
|
||||
connect(_exportScansDialog, SIGNAL(configChanged()), this, SLOT(configGUIModified()));
|
||||
connect(_postProcessingDialog, SIGNAL(configChanged()), this, SLOT(configGUIModified()));
|
||||
connect(_depthCalibrationDialog, SIGNAL(configChanged()), this, SLOT(configGUIModified()));
|
||||
connect(_ui->toolBar->toggleViewAction(), SIGNAL(toggled(bool)), this, SLOT(configGUIModified()));
|
||||
connect(_ui->toolBar, SIGNAL(orientationChanged(Qt::Orientation)), this, SLOT(configGUIModified()));
|
||||
connect(statusBarAction, SIGNAL(toggled(bool)), this, SLOT(configGUIModified()));
|
||||
@@ -518,6 +526,7 @@ MainWindow::MainWindow(PreferencesDialog * prefDialog, QWidget * parent) :
|
||||
_preferencesDialog->loadWidgetState(_exportCloudsDialog);
|
||||
_preferencesDialog->loadWidgetState(_exportScansDialog);
|
||||
_preferencesDialog->loadWidgetState(_postProcessingDialog);
|
||||
_preferencesDialog->loadWidgetState(_depthCalibrationDialog);
|
||||
|
||||
if(_ui->statsToolBox->findChildren<StatItem*>().size() == 0)
|
||||
{
|
||||
@@ -848,12 +857,13 @@ void MainWindow::processCameraInfo(const rtabmap::CameraInfo & info)
|
||||
{
|
||||
_firstStamp = info.stamp;
|
||||
}
|
||||
|
||||
_ui->statsToolBox->updateStat("Camera/Time total/ms", _preferencesDialog->isTimeUsedInFigures()?info.stamp-_firstStamp:(float)info.id, info.timeTotal*1000.0f);
|
||||
_ui->statsToolBox->updateStat("Camera/Time capturing/ms", _preferencesDialog->isTimeUsedInFigures()?info.stamp-_firstStamp:(float)info.id, info.timeCapture*1000.0f);
|
||||
_ui->statsToolBox->updateStat("Camera/Time undistort depth/ms", _preferencesDialog->isTimeUsedInFigures()?info.stamp-_firstStamp:(float)info.id, info.timeUndistortDepth*1000.0f);
|
||||
_ui->statsToolBox->updateStat("Camera/Time decimation/ms", _preferencesDialog->isTimeUsedInFigures()?info.stamp-_firstStamp:(float)info.id, info.timeImageDecimation*1000.0f);
|
||||
_ui->statsToolBox->updateStat("Camera/Time disparity/ms", _preferencesDialog->isTimeUsedInFigures()?info.stamp-_firstStamp:(float)info.id, info.timeDisparity*1000.0f);
|
||||
_ui->statsToolBox->updateStat("Camera/Time mirroring/ms", _preferencesDialog->isTimeUsedInFigures()?info.stamp-_firstStamp:(float)info.id, info.timeMirroring*1000.0f);
|
||||
_ui->statsToolBox->updateStat("Camera/Time scan_from_depth/ms", _preferencesDialog->isTimeUsedInFigures()?info.stamp-_firstStamp:(float)info.id, info.timeScanFromDepth*1000.0f);
|
||||
_ui->statsToolBox->updateStat("Camera/Time scan from depth/ms", _preferencesDialog->isTimeUsedInFigures()?info.stamp-_firstStamp:(float)info.id, info.timeScanFromDepth*1000.0f);
|
||||
}
|
||||
|
||||
void MainWindow::processOdometry(const rtabmap::OdometryEvent & odom, bool dataIgnored)
|
||||
@@ -1907,6 +1917,7 @@ void MainWindow::processStats(const rtabmap::Statistics & stat)
|
||||
{
|
||||
_ui->actionExport_images_RGB_jpg_Depth_png->setEnabled(!_cachedSignatures.empty() && !_currentPosesMap.empty());
|
||||
_ui->actionExport_cameras_in_Bundle_format_out->setEnabled(!_cachedSignatures.empty() && !_currentPosesMap.empty());
|
||||
_ui->actionDepth_Calibration->setEnabled(!_cachedSignatures.empty() && !_currentPosesMap.empty());
|
||||
}
|
||||
|
||||
_processingStatistics = false;
|
||||
@@ -2170,6 +2181,10 @@ void MainWindow::updateMapCloud(
|
||||
if(poses.size() < 200 || i % 100 == 0)
|
||||
{
|
||||
QApplication::processEvents();
|
||||
if(_progressCanceled)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3254,6 +3269,8 @@ void MainWindow::processRtabmapEvent3DMap(const rtabmap::RtabmapEvent3DMap & eve
|
||||
{
|
||||
_initProgressDialog->appendText("Updating the 3D map cloud...");
|
||||
_initProgressDialog->incrementStep();
|
||||
_initProgressDialog->setCancelButtonVisible(true);
|
||||
_progressCanceled = false;
|
||||
QApplication::processEvents();
|
||||
std::map<int, Transform> poses = event.getPoses();
|
||||
alignPosesToGroundTruth(poses, groundTruth);
|
||||
@@ -3277,10 +3294,13 @@ void MainWindow::processRtabmapEvent3DMap(const rtabmap::RtabmapEvent3DMap & eve
|
||||
{
|
||||
_ui->actionExport_images_RGB_jpg_Depth_png->setEnabled(!_cachedSignatures.empty() && !_currentPosesMap.empty());
|
||||
_ui->actionExport_cameras_in_Bundle_format_out->setEnabled(!_cachedSignatures.empty() && !_currentPosesMap.empty());
|
||||
_ui->actionDepth_Calibration->setEnabled(!_cachedSignatures.empty() && !_currentPosesMap.empty());
|
||||
}
|
||||
_processingDownloadedMap = false;
|
||||
}
|
||||
_initProgressDialog->setValue(_initProgressDialog->maximumSteps());
|
||||
_initProgressDialog->setCancelButtonVisible(false);
|
||||
_progressCanceled = false;
|
||||
}
|
||||
|
||||
void MainWindow::processRtabmapGlobalPathEvent(const rtabmap::RtabmapGlobalPathEvent & event)
|
||||
@@ -3379,7 +3399,7 @@ void MainWindow::applyPrefSettings(PreferencesDialog::PANEL_FLAGS flags)
|
||||
{
|
||||
if(dynamic_cast<DBReader*>(_camera->camera()) != 0)
|
||||
{
|
||||
_camera->setImageRate( _preferencesDialog->getSourceDatabaseStampsUsed()?-1:_preferencesDialog->getGeneralInputRate());
|
||||
_camera->setImageRate( _preferencesDialog->isSourceDatabaseStampsUsed()?-1:_preferencesDialog->getGeneralInputRate());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -3755,6 +3775,12 @@ void MainWindow::beep()
|
||||
QApplication::beep();
|
||||
}
|
||||
|
||||
void MainWindow::cancelProgress()
|
||||
{
|
||||
_progressCanceled = true;
|
||||
_initProgressDialog->appendText(tr("Canceled!"));
|
||||
}
|
||||
|
||||
void MainWindow::configGUIModified()
|
||||
{
|
||||
this->setWindowModified(true);
|
||||
@@ -3774,6 +3800,7 @@ void MainWindow::saveConfigGUI()
|
||||
_preferencesDialog->saveWidgetState(_exportCloudsDialog);
|
||||
_preferencesDialog->saveWidgetState(_exportScansDialog);
|
||||
_preferencesDialog->saveWidgetState(_postProcessingDialog);
|
||||
_preferencesDialog->saveWidgetState(_depthCalibrationDialog);
|
||||
_preferencesDialog->saveWidgetState(_ui->graphicsView_graphView);
|
||||
_preferencesDialog->saveSettings();
|
||||
this->saveFigures();
|
||||
@@ -4012,7 +4039,7 @@ void MainWindow::startDetection()
|
||||
float detectionRate = uStr2Float(parameters.at(Parameters::kRtabmapDetectionRate()));
|
||||
int bufferingSize = uStr2Float(parameters.at(Parameters::kRtabmapImageBufferSize()));
|
||||
if(((detectionRate!=0.0f && detectionRate <= inputRate) || (detectionRate > 0.0f && inputRate == 0.0f)) &&
|
||||
(_preferencesDialog->getSourceDriver() != PreferencesDialog::kSrcDatabase || !_preferencesDialog->getSourceDatabaseStampsUsed()))
|
||||
(_preferencesDialog->getSourceDriver() != PreferencesDialog::kSrcDatabase || !_preferencesDialog->isSourceDatabaseStampsUsed()))
|
||||
{
|
||||
int button = QMessageBox::question(this,
|
||||
tr("Incompatible frame rates!"),
|
||||
@@ -4028,7 +4055,7 @@ void MainWindow::startDetection()
|
||||
}
|
||||
}
|
||||
if(bufferingSize != 0 &&
|
||||
(_preferencesDialog->getSourceDriver() != PreferencesDialog::kSrcDatabase || !_preferencesDialog->getSourceDatabaseStampsUsed()))
|
||||
(_preferencesDialog->getSourceDriver() != PreferencesDialog::kSrcDatabase || !_preferencesDialog->isSourceDatabaseStampsUsed()))
|
||||
{
|
||||
int button = QMessageBox::question(this,
|
||||
tr("Some images may be skipped!"),
|
||||
@@ -4090,6 +4117,10 @@ void MainWindow::startDetection()
|
||||
_preferencesDialog->getSourceScanFromDepthMaxDepth(),
|
||||
_preferencesDialog->getSourceScanVoxelSize(),
|
||||
_preferencesDialog->getSourceScanNormalsK());
|
||||
if(_preferencesDialog->getSourceType() == PreferencesDialog::kSrcRGBD)
|
||||
{
|
||||
_camera->setDistortionModel(_preferencesDialog->getSourceDistortionModel().toStdString());
|
||||
}
|
||||
|
||||
//Create odometry thread if rgbd slam
|
||||
if(uStr2Bool(parameters.at(Parameters::kRGBDEnabled()).c_str()))
|
||||
@@ -4468,6 +4499,8 @@ void MainWindow::postProcessing()
|
||||
_initProgressDialog->clear();
|
||||
_initProgressDialog->show();
|
||||
_initProgressDialog->appendText("Post-processing beginning!");
|
||||
_initProgressDialog->setCancelButtonVisible(true);
|
||||
_progressCanceled = false;
|
||||
|
||||
int totalSteps = 0;
|
||||
if(refineNeighborLinks)
|
||||
@@ -4498,7 +4531,7 @@ void MainWindow::postProcessing()
|
||||
UDEBUG("");
|
||||
|
||||
UASSERT(detectLoopClosureIterations>0);
|
||||
for(int n=0; n<detectLoopClosureIterations; ++n)
|
||||
for(int n=0; n<detectLoopClosureIterations && !_progressCanceled; ++n)
|
||||
{
|
||||
_initProgressDialog->appendText(tr("Looking for more loop closures, clustering poses... (iteration=%1/%2, radius=%3 m angle=%4 degrees)")
|
||||
.arg(n+1).arg(detectLoopClosureIterations).arg(clusterRadius).arg(clusterAngle));
|
||||
@@ -4513,7 +4546,7 @@ void MainWindow::postProcessing()
|
||||
|
||||
int i=0;
|
||||
std::set<int> addedLinks;
|
||||
for(std::multimap<int, int>::iterator iter=clusters.begin(); iter!= clusters.end(); ++iter, ++i)
|
||||
for(std::multimap<int, int>::iterator iter=clusters.begin(); iter!= clusters.end() && !_progressCanceled; ++iter, ++i)
|
||||
{
|
||||
int from = iter->first;
|
||||
int to = iter->second;
|
||||
@@ -4552,9 +4585,6 @@ void MainWindow::postProcessing()
|
||||
}
|
||||
else
|
||||
{
|
||||
_initProgressDialog->incrementStep();
|
||||
QApplication::processEvents();
|
||||
|
||||
Signature signatureFrom = _cachedSignatures[from];
|
||||
Signature signatureTo = _cachedSignatures[to];
|
||||
|
||||
@@ -4579,6 +4609,7 @@ void MainWindow::postProcessing()
|
||||
}
|
||||
}
|
||||
}
|
||||
_initProgressDialog->incrementStep();
|
||||
}
|
||||
_initProgressDialog->appendText(tr("Iteration %1/%2: Detected %3 loop closures!")
|
||||
.arg(n+1).arg(detectLoopClosureIterations).arg(addedLinks.size()/2));
|
||||
@@ -4610,7 +4641,7 @@ void MainWindow::postProcessing()
|
||||
_initProgressDialog->appendText(tr("Total new loop closures detected=%1").arg(loopClosuresAdded));
|
||||
}
|
||||
|
||||
if(refineNeighborLinks || refineLoopClosureLinks)
|
||||
if(!_progressCanceled && (refineNeighborLinks || refineLoopClosureLinks))
|
||||
{
|
||||
UDEBUG("");
|
||||
if(refineLoopClosureLinks)
|
||||
@@ -4623,7 +4654,7 @@ void MainWindow::postProcessing()
|
||||
RegistrationIcp regIcp(parameters);
|
||||
|
||||
int i=0;
|
||||
for(std::multimap<int, Link>::iterator iter = _currentLinksMap.begin(); iter!=_currentLinksMap.end(); ++iter, ++i)
|
||||
for(std::multimap<int, Link>::iterator iter = _currentLinksMap.begin(); iter!=_currentLinksMap.end() && !_progressCanceled; ++iter, ++i)
|
||||
{
|
||||
int type = iter->second.type();
|
||||
|
||||
@@ -4712,7 +4743,7 @@ void MainWindow::postProcessing()
|
||||
_initProgressDialog->appendText(tr("Optimizing graph with updated links... done!"));
|
||||
_initProgressDialog->incrementStep();
|
||||
|
||||
if(sba)
|
||||
if(!_progressCanceled && sba)
|
||||
{
|
||||
UASSERT(Optimizer::isAvailable(sbaType));
|
||||
_initProgressDialog->appendText(tr("SBA (%1 nodes, %2 constraints, %3 iterations)...")
|
||||
@@ -4759,10 +4790,28 @@ void MainWindow::postProcessing()
|
||||
|
||||
_initProgressDialog->setValue(_initProgressDialog->maximumSteps());
|
||||
_initProgressDialog->appendText("Post-processing finished!");
|
||||
_initProgressDialog->setCancelButtonVisible(false);
|
||||
_progressCanceled = false;
|
||||
|
||||
delete optimizer;
|
||||
}
|
||||
|
||||
void MainWindow::depthCalibration()
|
||||
{
|
||||
if(_currentPosesMap.size() && _cachedSignatures.size())
|
||||
{
|
||||
_depthCalibrationDialog->calibrate(
|
||||
_currentPosesMap,
|
||||
_cachedSignatures,
|
||||
_preferencesDialog->getWorkingDirectory(),
|
||||
_preferencesDialog->getAllParameters());
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::warning(this, tr("Depth Calibration"), tr("No data in cache. Try to refresh the cache."));
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::deleteMemory()
|
||||
{
|
||||
QMessageBox::StandardButton button;
|
||||
@@ -5157,6 +5206,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->actionDepth_Calibration->setEnabled(false);
|
||||
_ui->actionExport_images_RGB_jpg_Depth_png->setEnabled(false);
|
||||
_ui->actionView_scans->setEnabled(false);
|
||||
_ui->actionExport_octomap->setEnabled(false);
|
||||
@@ -6008,7 +6058,7 @@ void MainWindow::changeState(MainWindow::State newState)
|
||||
}
|
||||
}
|
||||
actions = _ui->menuFile->actions();
|
||||
if(actions.size()==16)
|
||||
if(actions.size()==17)
|
||||
{
|
||||
if(actions.at(2)->isSeparator())
|
||||
{
|
||||
@@ -6018,9 +6068,9 @@ void MainWindow::changeState(MainWindow::State newState)
|
||||
{
|
||||
UWARN("Menu File separators have not the same order.");
|
||||
}
|
||||
if(actions.at(12)->isSeparator())
|
||||
if(actions.at(13)->isSeparator())
|
||||
{
|
||||
actions.at(12)->setVisible(!monitoring);
|
||||
actions.at(13)->setVisible(!monitoring);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -6083,6 +6133,7 @@ void MainWindow::changeState(MainWindow::State newState)
|
||||
_ui->actionExport_octomap->setEnabled(false);
|
||||
#endif
|
||||
_ui->actionExport_cameras_in_Bundle_format_out->setEnabled(!_cachedSignatures.empty() && !_currentPosesMap.empty());
|
||||
_ui->actionDepth_Calibration->setEnabled(!_cachedSignatures.empty() && !_currentPosesMap.empty());
|
||||
_ui->actionDownload_all_clouds->setEnabled(false);
|
||||
_ui->actionDownload_graph->setEnabled(false);
|
||||
_ui->menuSelect_source->setEnabled(true);
|
||||
@@ -6144,6 +6195,7 @@ void MainWindow::changeState(MainWindow::State newState)
|
||||
_ui->actionExport_octomap->setEnabled(false);
|
||||
#endif
|
||||
_ui->actionExport_cameras_in_Bundle_format_out->setEnabled(!_cachedSignatures.empty() && !_currentPosesMap.empty());
|
||||
_ui->actionDepth_Calibration->setEnabled(!_cachedSignatures.empty() && !_currentPosesMap.empty());
|
||||
_ui->actionDownload_all_clouds->setEnabled(true);
|
||||
_ui->actionDownload_graph->setEnabled(true);
|
||||
_ui->menuSelect_source->setEnabled(true);
|
||||
@@ -6190,6 +6242,7 @@ void MainWindow::changeState(MainWindow::State newState)
|
||||
_ui->actionView_scans->setEnabled(false);
|
||||
_ui->actionExport_octomap->setEnabled(false);
|
||||
_ui->actionExport_cameras_in_Bundle_format_out->setEnabled(false);
|
||||
_ui->actionDepth_Calibration->setEnabled(false);
|
||||
_ui->actionDownload_all_clouds->setEnabled(false);
|
||||
_ui->actionDownload_graph->setEnabled(false);
|
||||
_ui->menuSelect_source->setEnabled(false);
|
||||
@@ -6233,6 +6286,7 @@ void MainWindow::changeState(MainWindow::State newState)
|
||||
_ui->actionView_scans->setEnabled(false);
|
||||
_ui->actionExport_octomap->setEnabled(false);
|
||||
_ui->actionExport_cameras_in_Bundle_format_out->setEnabled(false);
|
||||
_ui->actionDepth_Calibration->setEnabled(false);
|
||||
_ui->actionDownload_all_clouds->setEnabled(false);
|
||||
_ui->actionDownload_graph->setEnabled(false);
|
||||
_state = kDetecting;
|
||||
@@ -6267,6 +6321,7 @@ void MainWindow::changeState(MainWindow::State newState)
|
||||
_ui->actionExport_octomap->setEnabled(false);
|
||||
#endif
|
||||
_ui->actionExport_cameras_in_Bundle_format_out->setEnabled(!_cachedSignatures.empty() && !_currentPosesMap.empty());
|
||||
_ui->actionDepth_Calibration->setEnabled(!_cachedSignatures.empty() && !_currentPosesMap.empty());
|
||||
_ui->actionDownload_all_clouds->setEnabled(true);
|
||||
_ui->actionDownload_graph->setEnabled(true);
|
||||
_state = kPaused;
|
||||
@@ -6297,6 +6352,7 @@ void MainWindow::changeState(MainWindow::State newState)
|
||||
_ui->actionView_scans->setEnabled(false);
|
||||
_ui->actionExport_octomap->setEnabled(false);
|
||||
_ui->actionExport_cameras_in_Bundle_format_out->setEnabled(false);
|
||||
_ui->actionDepth_Calibration->setEnabled(false);
|
||||
_ui->actionDelete_memory->setEnabled(true);
|
||||
_ui->actionDownload_all_clouds->setEnabled(true);
|
||||
_ui->actionDownload_graph->setEnabled(true);
|
||||
@@ -6332,6 +6388,7 @@ void MainWindow::changeState(MainWindow::State newState)
|
||||
_ui->actionExport_octomap->setEnabled(false);
|
||||
#endif
|
||||
_ui->actionExport_cameras_in_Bundle_format_out->setEnabled(!_cachedSignatures.empty() && !_currentPosesMap.empty());
|
||||
_ui->actionDepth_Calibration->setEnabled(!_cachedSignatures.empty() && !_currentPosesMap.empty());
|
||||
_ui->actionDelete_memory->setEnabled(true);
|
||||
_ui->actionDownload_all_clouds->setEnabled(true);
|
||||
_ui->actionDownload_graph->setEnabled(true);
|
||||
|
||||
@@ -33,6 +33,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <QtCore/QSettings>
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QUrl>
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QInputDialog>
|
||||
@@ -42,6 +43,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <QProgressDialog>
|
||||
#include <QScrollBar>
|
||||
#include <QStatusBar>
|
||||
#include <QDesktopServices>
|
||||
#include <QtGui/QCloseEvent>
|
||||
|
||||
#include "ui_preferencesDialog.h"
|
||||
@@ -60,6 +62,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "rtabmap/core/Optimizer.h"
|
||||
#include "rtabmap/core/OptimizerG2O.h"
|
||||
#include "rtabmap/core/DBReader.h"
|
||||
#include "rtabmap/core/clams/discrete_depth_distortion_model.h"
|
||||
|
||||
#include "rtabmap/gui/LoopClosureViewer.h"
|
||||
#include "rtabmap/gui/CameraViewer.h"
|
||||
@@ -70,6 +73,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "ExportScansDialog.h"
|
||||
#include "PostProcessingDialog.h"
|
||||
#include "CreateSimpleCalibrationDialog.h"
|
||||
#include "DepthCalibrationDialog.h"
|
||||
|
||||
#include <rtabmap/utilite/ULogger.h>
|
||||
#include <rtabmap/utilite/UConversion.h>
|
||||
@@ -505,8 +509,11 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
|
||||
connect(_ui->pushButton_calibrate_simple, SIGNAL(clicked()), this, SLOT(calibrateSimple()));
|
||||
connect(_ui->toolButton_openniOniPath, SIGNAL(clicked()), this, SLOT(selectSourceOniPath()));
|
||||
connect(_ui->toolButton_openni2OniPath, SIGNAL(clicked()), this, SLOT(selectSourceOni2Path()));
|
||||
connect(_ui->toolButton_source_distortionModel, SIGNAL(clicked()), this, SLOT(selectSourceDistortionModel()));
|
||||
connect(_ui->toolButton_distortionModel, SIGNAL(clicked()), this, SLOT(visualizeDistortionModel()));
|
||||
connect(_ui->lineEdit_openniOniPath, SIGNAL(textChanged(const QString &)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
connect(_ui->lineEdit_openni2OniPath, SIGNAL(textChanged(const QString &)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
connect(_ui->lineEdit_source_distortionModel, SIGNAL(textChanged(const QString &)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
|
||||
connect(_ui->groupBox_scanFromDepth, SIGNAL(toggled(bool)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
connect(_ui->spinBox_cameraScanFromDepth_decimation, SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
@@ -1336,6 +1343,7 @@ void PreferencesDialog::resetSettings(QGroupBox * groupBox)
|
||||
_ui->lineEdit_cameraRGBDImages_path_rgb->setText("");
|
||||
_ui->lineEdit_cameraRGBDImages_path_depth->setText("");
|
||||
_ui->doubleSpinBox_cameraRGBDImages_scale->setValue(1.0);
|
||||
_ui->lineEdit_source_distortionModel->setText("");
|
||||
|
||||
_ui->source_comboBox_image_type->setCurrentIndex(kSrcDC1394-kSrcDC1394);
|
||||
_ui->lineEdit_cameraStereoImages_path_left->setText("");
|
||||
@@ -1639,6 +1647,7 @@ void PreferencesDialog::readCameraSettings(const QString & filePath)
|
||||
settings.beginGroup("rgbd");
|
||||
_ui->comboBox_cameraRGBD->setCurrentIndex(settings.value("driver", _ui->comboBox_cameraRGBD->currentIndex()).toInt());
|
||||
_ui->checkbox_rgbd_colorOnly->setChecked(settings.value("rgbdColorOnly", _ui->checkbox_rgbd_colorOnly->isChecked()).toBool());
|
||||
_ui->lineEdit_source_distortionModel->setText(settings.value("distortion_model", _ui->lineEdit_source_distortionModel->text()).toString());
|
||||
settings.endGroup(); // rgbd
|
||||
|
||||
settings.beginGroup("stereo");
|
||||
@@ -2066,6 +2075,7 @@ void PreferencesDialog::writeCameraSettings(const QString & filePath) const
|
||||
settings.beginGroup("rgbd");
|
||||
settings.setValue("driver", _ui->comboBox_cameraRGBD->currentIndex());
|
||||
settings.setValue("rgbdColorOnly", _ui->checkbox_rgbd_colorOnly->isChecked());
|
||||
settings.setValue("distortion_model", _ui->lineEdit_source_distortionModel->text());
|
||||
settings.endGroup(); // rgbd
|
||||
|
||||
settings.beginGroup("stereo");
|
||||
@@ -2566,6 +2576,7 @@ void PreferencesDialog::saveWidgetState(const QWidget * widget)
|
||||
const PostProcessingDialog * postProcessingDialog = qobject_cast<const PostProcessingDialog *>(widget);
|
||||
const GraphViewer * graphViewer = qobject_cast<const GraphViewer *>(widget);
|
||||
const CalibrationDialog * calibrationDialog = qobject_cast<const CalibrationDialog *>(widget);
|
||||
const DepthCalibrationDialog * depthCalibrationDialog = qobject_cast<const DepthCalibrationDialog *>(widget);
|
||||
|
||||
if(cloudViewer)
|
||||
{
|
||||
@@ -2595,6 +2606,10 @@ void PreferencesDialog::saveWidgetState(const QWidget * widget)
|
||||
{
|
||||
calibrationDialog->saveSettings(settings);
|
||||
}
|
||||
else if(depthCalibrationDialog)
|
||||
{
|
||||
depthCalibrationDialog->saveSettings(settings);
|
||||
}
|
||||
else
|
||||
{
|
||||
UERROR("Widget \"%s\" cannot be exported in config file.", widget->objectName().toStdString().c_str());
|
||||
@@ -2621,6 +2636,7 @@ void PreferencesDialog::loadWidgetState(QWidget * widget)
|
||||
PostProcessingDialog * postProcessingDialog = qobject_cast<PostProcessingDialog *>(widget);
|
||||
GraphViewer * graphViewer = qobject_cast<GraphViewer *>(widget);
|
||||
CalibrationDialog * calibrationDialog = qobject_cast<CalibrationDialog *>(widget);
|
||||
DepthCalibrationDialog * depthCalibrationDialog = qobject_cast<DepthCalibrationDialog *>(widget);
|
||||
|
||||
if(cloudViewer)
|
||||
{
|
||||
@@ -2650,6 +2666,10 @@ void PreferencesDialog::loadWidgetState(QWidget * widget)
|
||||
{
|
||||
calibrationDialog->loadSettings(settings);
|
||||
}
|
||||
else if(depthCalibrationDialog)
|
||||
{
|
||||
depthCalibrationDialog->loadSettings(settings);
|
||||
}
|
||||
else
|
||||
{
|
||||
UERROR("Widget \"%s\" cannot be loaded from config file.", widget->objectName().toStdString().c_str());
|
||||
@@ -2788,6 +2808,31 @@ void PreferencesDialog::openDatabaseViewer()
|
||||
}
|
||||
}
|
||||
|
||||
void PreferencesDialog::visualizeDistortionModel()
|
||||
{
|
||||
if(!_ui->lineEdit_source_distortionModel->text().isEmpty() &&
|
||||
QFileInfo(_ui->lineEdit_source_distortionModel->text()).exists())
|
||||
{
|
||||
clams::DiscreteDepthDistortionModel model;
|
||||
model.load(_ui->lineEdit_source_distortionModel->text().toStdString());
|
||||
if(model.isValid())
|
||||
{
|
||||
cv::Mat img = model.visualize();
|
||||
QString name = QFileInfo(_ui->lineEdit_source_distortionModel->text()).baseName()+".png";
|
||||
cv::imwrite(name.toStdString(), img);
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(name));
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::warning(this, tr("Distortion Model"), tr("Model loaded from \"%1\" is not valid!").arg(_ui->lineEdit_source_distortionModel->text()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::warning(this, tr("Distortion Model"), tr("File \"%1\" doesn't exist!").arg(_ui->lineEdit_source_distortionModel->text()));
|
||||
}
|
||||
}
|
||||
|
||||
void PreferencesDialog::selectCalibrationPath()
|
||||
{
|
||||
QString dir = _ui->lineEdit_calibrationFile->text();
|
||||
@@ -2972,6 +3017,20 @@ void PreferencesDialog::selectSourceStereoVideoPath2()
|
||||
}
|
||||
}
|
||||
|
||||
void PreferencesDialog::selectSourceDistortionModel()
|
||||
{
|
||||
QString dir = _ui->lineEdit_source_distortionModel->text();
|
||||
if(dir.isEmpty())
|
||||
{
|
||||
dir = getWorkingDirectory();
|
||||
}
|
||||
QString path = QFileDialog::getOpenFileName(this, tr("Select file"), _ui->lineEdit_source_distortionModel->text(), tr("Distortion model (*.bin)"));
|
||||
if(!path.isEmpty())
|
||||
{
|
||||
_ui->lineEdit_source_distortionModel->setText(path);
|
||||
}
|
||||
}
|
||||
|
||||
void PreferencesDialog::selectSourceOniPath()
|
||||
{
|
||||
QString dir = _ui->lineEdit_openniOniPath->text();
|
||||
@@ -4054,7 +4113,7 @@ Transform PreferencesDialog::getLaserLocalTransform() const
|
||||
return t;
|
||||
}
|
||||
|
||||
bool PreferencesDialog::getSourceDatabaseStampsUsed() const
|
||||
bool PreferencesDialog::isSourceDatabaseStampsUsed() const
|
||||
{
|
||||
return _ui->source_checkBox_useDbStamps->isChecked();
|
||||
}
|
||||
@@ -4062,6 +4121,10 @@ bool PreferencesDialog::isSourceRGBDColorOnly() const
|
||||
{
|
||||
return _ui->checkbox_rgbd_colorOnly->isChecked();
|
||||
}
|
||||
QString PreferencesDialog::getSourceDistortionModel() const
|
||||
{
|
||||
return _ui->lineEdit_source_distortionModel->text();
|
||||
}
|
||||
int PreferencesDialog::getSourceImageDecimation() const
|
||||
{
|
||||
return _ui->spinBox_source_imageDecimation->value();
|
||||
@@ -4577,6 +4640,11 @@ void PreferencesDialog::testOdometry()
|
||||
_ui->doubleSpinBox_cameraSCanFromDepth_maxDepth->value(),
|
||||
_ui->doubleSpinBox_cameraImages_scanVoxelSize->value(),
|
||||
_ui->spinBox_cameraImages_scanNormalsK->value());
|
||||
if(this->getSourceType() == PreferencesDialog::kSrcRGBD &&
|
||||
!_ui->lineEdit_source_distortionModel->text().isEmpty())
|
||||
{
|
||||
cameraThread.setDistortionModel(_ui->lineEdit_source_distortionModel->text().toStdString());
|
||||
}
|
||||
UEventsManager::createPipe(&cameraThread, &odomThread, "CameraEvent");
|
||||
UEventsManager::createPipe(&odomThread, odomViewer, "OdometryEvent");
|
||||
UEventsManager::createPipe(odomViewer, &odomThread, "OdometryResetEvent");
|
||||
@@ -4612,6 +4680,11 @@ void PreferencesDialog::testCamera()
|
||||
_ui->doubleSpinBox_cameraSCanFromDepth_maxDepth->value(),
|
||||
_ui->doubleSpinBox_cameraImages_scanVoxelSize->value(),
|
||||
_ui->spinBox_cameraImages_scanNormalsK->value());
|
||||
if(this->getSourceType() == PreferencesDialog::kSrcRGBD &&
|
||||
!_ui->lineEdit_source_distortionModel->text().isEmpty())
|
||||
{
|
||||
cameraThread.setDistortionModel(_ui->lineEdit_source_distortionModel->text().toStdString());
|
||||
}
|
||||
UEventsManager::createPipe(&cameraThread, window, "CameraEvent");
|
||||
|
||||
cameraThread.start();
|
||||
|
||||
@@ -53,12 +53,16 @@ ProgressDialog::ProgressDialog(QWidget *parent, Qt::WindowFlags flags) :
|
||||
_detailedText->setLineWrapMode(QTextEdit::NoWrap);
|
||||
_closeButton = new QPushButton(this);
|
||||
_closeButton->setText("Close");
|
||||
_cancelButton = new QPushButton(this);
|
||||
_cancelButton->setText("Cancel");
|
||||
_cancelButton-> setVisible(false);
|
||||
_closeWhenDoneCheckBox = new QCheckBox(this);
|
||||
_closeWhenDoneCheckBox->setChecked(true);
|
||||
_closeWhenDoneCheckBox->setText("Close when done.");
|
||||
_endMessage = "Finished!";
|
||||
this->clear();
|
||||
connect(_closeButton, SIGNAL(clicked()), this, SLOT(close()));
|
||||
connect(_cancelButton, SIGNAL(clicked()), this, SIGNAL(canceled()));
|
||||
|
||||
QVBoxLayout * layout = new QVBoxLayout(this);
|
||||
layout->addWidget(_text);
|
||||
@@ -67,6 +71,8 @@ ProgressDialog::ProgressDialog(QWidget *parent, Qt::WindowFlags flags) :
|
||||
QHBoxLayout * hLayout = new QHBoxLayout();
|
||||
layout->addLayout(hLayout);
|
||||
hLayout->addWidget(_closeWhenDoneCheckBox);
|
||||
hLayout->addStretch();
|
||||
hLayout->addWidget(_cancelButton);
|
||||
hLayout->addWidget(_closeButton);
|
||||
this->setLayout(layout);
|
||||
|
||||
@@ -87,6 +93,11 @@ void ProgressDialog::setAutoClose(bool on, int delayedClosingTimeSec)
|
||||
_closeWhenDoneCheckBox->setChecked(on);
|
||||
}
|
||||
|
||||
void ProgressDialog::setCancelButtonVisible(bool visible)
|
||||
{
|
||||
_cancelButton->setVisible(visible);
|
||||
}
|
||||
|
||||
void ProgressDialog::appendText(const QString & text, const QColor & color)
|
||||
{
|
||||
_text->setText(text);
|
||||
|
||||
333
guilib/src/ui/depthCalibrationDialog.ui
Normal file
333
guilib/src/ui/depthCalibrationDialog.ui
Normal file
@@ -0,0 +1,333 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>DepthCalibrationDialog</class>
|
||||
<widget class="QDialog" name="DepthCalibrationDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>524</width>
|
||||
<height>449</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Depth Calibration</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_111">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p>CLAMS approach is used for depth calibration. Please visit <a href="http://www.alexteichman.com/octo/clams/"><span style=" text-decoration: underline; color:#0000ff;">CLAMS website</span></a> for tips about how to get a good map for depth calibration. If you want to process multiple mapping sessions, uncheck &quot;Reset previous model&quot;. If logger's level is debug, 3D map and generated depth images will be shown during the calibration.</p></body></html></string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::RichText</enum>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout" columnstretch="0,1">
|
||||
<item row="5" column="0">
|
||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_minDepth">
|
||||
<property name="suffix">
|
||||
<string> m</string>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>100.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QLabel" name="label_voxel">
|
||||
<property name="text">
|
||||
<string>Voxel size. Set 0 to disable.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_voxelSize">
|
||||
<property name="suffix">
|
||||
<string> m</string>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_coneRadius">
|
||||
<property name="suffix">
|
||||
<string> m</string>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.020000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="checkBox_laserScan">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QLabel" name="label_132">
|
||||
<property name="text">
|
||||
<string>Maximum depth (0 means no limit).</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_maxDepth">
|
||||
<property name="suffix">
|
||||
<string> m</string>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>100.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>4.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QLabel" name="label_133">
|
||||
<property name="text">
|
||||
<string>Minimum depth.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QLabel" name="label_voxel_2">
|
||||
<property name="text">
|
||||
<string>Cone radius.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<widget class="QLabel" name="label_voxel_3">
|
||||
<property name="text">
|
||||
<string>Cone std dev threshold.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_coneStdDevThresh">
|
||||
<property name="suffix">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.030000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="checkBox_resetModel">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_110">
|
||||
<property name="text">
|
||||
<string>Use 3D laser scans for 3D map.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="label_109">
|
||||
<property name="text">
|
||||
<string>Reset previous model.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLabel" name="label_108">
|
||||
<property name="text">
|
||||
<string>Decimation (1-2-4-8-...).</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QSpinBox" name="spinBox_decimation">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>32</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_112">
|
||||
<property name="text">
|
||||
<string>Current model:</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_trainingSamples">
|
||||
<property name="text">
|
||||
<string>0</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_114">
|
||||
<property name="text">
|
||||
<string>training samples</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::RestoreDefaults|QDialogButtonBox::Save</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>DepthCalibrationDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
@@ -25,7 +25,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>773</width>
|
||||
<height>1648</height>
|
||||
<height>1689</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_13">
|
||||
@@ -150,31 +150,8 @@
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_14">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout" columnstretch="0,1">
|
||||
<item row="0" column="0">
|
||||
<widget class="QSpinBox" name="spinBox_decimation">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>32</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_108">
|
||||
<property name="text">
|
||||
<string>3D cloud decimation (1-2-4-8-...).</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<layout class="QGridLayout" name="gridLayout" columnstretch="0,0,1">
|
||||
<item row="1" column="1">
|
||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_maxDepth">
|
||||
<property name="suffix">
|
||||
<string> m</string>
|
||||
@@ -193,7 +170,40 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="label_108">
|
||||
<property name="text">
|
||||
<string>3D cloud decimation (1-2-4-8-...).</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSpinBox" name="spinBox_decimation">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>32</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QLabel" name="label_134">
|
||||
<property name="text">
|
||||
<string>Path to a depth distortion model to apply (output from depth calibration).</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLabel" name="label_132">
|
||||
<property name="text">
|
||||
<string>3D cloud maximum depth (0 means no limit).</string>
|
||||
@@ -203,7 +213,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<item row="2" column="2">
|
||||
<widget class="QLabel" name="label_133">
|
||||
<property name="text">
|
||||
<string>3D cloud minimum depth.</string>
|
||||
@@ -213,7 +223,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<item row="2" column="1">
|
||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_minDepth">
|
||||
<property name="suffix">
|
||||
<string> m</string>
|
||||
@@ -232,6 +242,16 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLineEdit" name="lineEdit_distortionModel"/>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QToolButton" name="toolButton_distortionModel">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
<addaction name="menuExport_poses"/>
|
||||
<addaction name="actionExport_images_RGB_jpg_Depth_png"/>
|
||||
<addaction name="actionExport_cameras_in_Bundle_format_out"/>
|
||||
<addaction name="actionDepth_Calibration"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionClose_database"/>
|
||||
<addaction name="separator"/>
|
||||
@@ -1345,6 +1346,11 @@
|
||||
<string>RealSense</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDepth_Calibration">
|
||||
<property name="text">
|
||||
<string>Depth calibration...</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>-490</y>
|
||||
<y>-179</y>
|
||||
<width>673</width>
|
||||
<height>2496</height>
|
||||
</rect>
|
||||
@@ -2357,7 +2357,7 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
|
||||
<item>
|
||||
<widget class="QStackedWidget" name="stackedWidget_src">
|
||||
<property name="currentIndex">
|
||||
<number>1</number>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="page_41">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_64">
|
||||
@@ -2384,7 +2384,7 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_55" columnstretch="0,0,1">
|
||||
<layout class="QGridLayout" name="gridLayout_55" columnstretch="0,0,0,1,0">
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="comboBox_cameraRGBD">
|
||||
<property name="sizeAdjustPolicy">
|
||||
@@ -2432,7 +2432,7 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<item row="0" column="3">
|
||||
<widget class="QLabel" name="label_228">
|
||||
<property name="text">
|
||||
<string>Driver</string>
|
||||
@@ -2442,7 +2442,7 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<item row="1" column="3">
|
||||
<widget class="QLabel" name="label_229">
|
||||
<property name="text">
|
||||
<string>Only RGB images are published.</string>
|
||||
@@ -2452,7 +2452,7 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="checkbox_rgbd_colorOnly">
|
||||
<property name="text">
|
||||
<string/>
|
||||
@@ -2462,12 +2462,56 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QToolButton" name="toolButton_source_distortionModel">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="3">
|
||||
<widget class="QLabel" name="label_341">
|
||||
<property name="text">
|
||||
<string>Distortion model (output from depth calibration).</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="lineEdit_source_distortionModel">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QToolButton" name="toolButton_distortionModel">
|
||||
<property name="toolTip">
|
||||
<string>Open database viewer</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../GuiLib.qrc">
|
||||
<normaloff>:/images/mag_glass.png</normaloff>:/images/mag_glass.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QStackedWidget" name="stackedWidget_rgbd">
|
||||
<property name="currentIndex">
|
||||
<number>2</number>
|
||||
<number>1</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="page_32">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_63">
|
||||
|
||||
Reference in New Issue
Block a user