0.16.3: Added OKVIS support (tested only on EuRoC dataset). Added IMU/IMUThread classes. Added OdomOKVIS/ConfigPath and Rtabmap/ImagesAlreadyRectified parameters. MainWindow, limited odom local feature map to maximum 50 meters from current pose (to avoid VTK glitching with near/far clipping plane).

This commit is contained in:
matlabbe
2018-03-07 19:43:30 -05:00
parent 2fad881202
commit 4969ece356
30 changed files with 1700 additions and 102 deletions

View File

@@ -32,6 +32,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "rtabmap/core/CameraRGB.h"
#include "rtabmap/core/CameraStereo.h"
#include "rtabmap/core/CameraThread.h"
#include "rtabmap/core/IMUThread.h"
#include "rtabmap/core/CameraEvent.h"
#include "rtabmap/core/DBReader.h"
#include "rtabmap/core/Parameters.h"
@@ -135,6 +136,7 @@ MainWindow::MainWindow(PreferencesDialog * prefDialog, QWidget * parent, bool sh
_state(kIdle),
_camera(0),
_odomThread(0),
_imuThread(0),
_preferencesDialog(0),
_aboutDialog(0),
_exportCloudsDialog(0),
@@ -759,6 +761,11 @@ void MainWindow::closeEvent(QCloseEvent* event)
UERROR("Camera must be already deleted here!");
delete _camera;
_camera = 0;
if(_imuThread)
{
delete _imuThread;
_imuThread = 0;
}
}
if(_odomThread)
{
@@ -1179,18 +1186,22 @@ void MainWindow::processOdometry(const rtabmap::OdometryEvent & odom, bool dataI
int i=0;
for(std::map<int, cv::Point3f>::const_iterator iter=odom.info().localMap.begin(); iter!=odom.info().localMap.end(); ++iter)
{
(*cloud)[i].x = iter->second.x;
(*cloud)[i].y = iter->second.y;
(*cloud)[i].z = iter->second.z;
// green = inlier, yellow = outliers
bool inlier = odom.info().words.find(iter->first) != odom.info().words.end();
(*cloud)[i].r = inlier?0:255;
(*cloud)[i].g = 255;
(*cloud)[i].b = 0;
if(!_preferencesDialog->isOdomOnlyInliersShown() || inlier)
// filter very far features from current location
if(uNormSquared(iter->second.x-odom.pose().x(), iter->second.y-odom.pose().y(), iter->second.z-odom.pose().z()) < 50*50)
{
++i;
(*cloud)[i].x = iter->second.x;
(*cloud)[i].y = iter->second.y;
(*cloud)[i].z = iter->second.z;
// green = inlier, yellow = outliers
bool inlier = odom.info().words.find(iter->first) != odom.info().words.end();
(*cloud)[i].r = inlier?0:255;
(*cloud)[i].g = 255;
(*cloud)[i].b = 0;
if(!_preferencesDialog->isOdomOnlyInliersShown() || inlier)
{
++i;
}
}
}
cloud->resize(i);
@@ -4788,6 +4799,13 @@ void MainWindow::startDetection()
_odomThread = 0;
}
if(_imuThread)
{
UERROR("ImuThread must be already deleted here?!");
delete _imuThread;
_imuThread = 0;
}
if(!camera->odomProvided() && !_preferencesDialog->isOdomDisabled())
{
ParametersMap odomParameters = parameters;
@@ -4803,12 +4821,42 @@ void MainWindow::startDetection()
// Only Frame To Frame supports all VisCorType
odomParameters.insert(ParametersPair(Parameters::kVisCorType(), _preferencesDialog->getParameter(Parameters::kVisCorType())));
}
_imuThread = 0;
if((_preferencesDialog->getSourceDriver() == PreferencesDialog::kSrcStereoImages ||
_preferencesDialog->getSourceDriver() == PreferencesDialog::kSrcRGBDImages ||
_preferencesDialog->getSourceDriver() == PreferencesDialog::kSrcImages) &&
!_preferencesDialog->getIMUPath().isEmpty())
{
if(odomStrategy != Odometry::kTypeOkvis)
{
QMessageBox::warning(this, tr("Source IMU Path"),
tr("IMU path is set but odometry chosen doesn't support IMU, ignoring IMU..."), QMessageBox::Ok);
}
else
{
_imuThread = new IMUThread(_preferencesDialog->getIMURate(), _preferencesDialog->getIMULocalTransform());
if(!_imuThread->init(_preferencesDialog->getIMUPath().toStdString()))
{
QMessageBox::warning(this, tr("Source IMU Path"),
tr("Initialization of IMU data has failed! Path=%1.").arg(_preferencesDialog->getIMUPath()), QMessageBox::Ok);
delete _camera;
_camera = 0;
delete _imuThread;
_imuThread = 0;
return;
}
}
}
Odometry * odom = Odometry::create(odomParameters);
_odomThread = new OdometryThread(odom, _preferencesDialog->getOdomBufferSize());
UEventsManager::addHandler(_odomThread);
UEventsManager::createPipe(_camera, _odomThread, "CameraEvent");
UEventsManager::createPipe(_camera, this, "CameraEvent");
if(_imuThread)
{
UEventsManager::createPipe(_imuThread, _odomThread, "IMUEvent");
}
_odomThread->start();
}
}
@@ -4910,6 +4958,11 @@ void MainWindow::stopDetection()
ULOGGER_DEBUG("");
// kill the processes
if(_imuThread)
{
_imuThread->join(true);
}
if(_camera)
{
_camera->join(true);
@@ -4922,6 +4975,11 @@ void MainWindow::stopDetection()
}
// delete the processes
if(_imuThread)
{
delete _imuThread;
_imuThread = 0;
}
if(_camera)
{
delete _camera;
@@ -7319,6 +7377,10 @@ void MainWindow::changeState(MainWindow::State newState)
if(_camera)
{
_camera->start();
if(_imuThread)
{
_imuThread->start();
}
ULogger::setTreadIdFilter(_preferencesDialog->getGeneralLoggerThreads());
}
break;
@@ -7351,6 +7413,10 @@ void MainWindow::changeState(MainWindow::State newState)
if(_camera)
{
_camera->start();
if(_imuThread)
{
_imuThread->start();
}
ULogger::setTreadIdFilter(_preferencesDialog->getGeneralLoggerThreads());
}
}
@@ -7384,6 +7450,10 @@ void MainWindow::changeState(MainWindow::State newState)
// kill sensors
if(_camera)
{
if(_imuThread)
{
_imuThread->join(true);
}
_camera->join(true);
}
}

View File

@@ -344,23 +344,28 @@ void OdometryViewer::processData(const rtabmap::OdometryEvent & odom)
// 3d features
if(featuresShown_->isChecked())
{
if(!odom.info().localMap.empty())
if(!odom.info().localMap.empty() && !odom.pose().isNull())
{
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGB>);
cloud->resize(odom.info().localMap.size());
int i=0;
for(std::map<int, cv::Point3f>::const_iterator iter=odom.info().localMap.begin(); iter!=odom.info().localMap.end(); ++iter)
{
(*cloud)[i].x = iter->second.x;
(*cloud)[i].y = iter->second.y;
(*cloud)[i].z = iter->second.z;
// filter very far features from current location
if(uNormSquared(iter->second.x-odom.pose().x(), iter->second.y-odom.pose().y(), iter->second.z-odom.pose().z()) < 50*50)
{
(*cloud)[i].x = iter->second.x;
(*cloud)[i].y = iter->second.y;
(*cloud)[i].z = iter->second.z;
// green = inlier, yellow = outliers
bool inlier = odom.info().words.find(iter->first) != odom.info().words.end();
(*cloud)[i].r = inlier?0:255;
(*cloud)[i].g = 255;
(*cloud)[i++].b = 0;
// green = inlier, yellow = outliers
bool inlier = odom.info().words.find(iter->first) != odom.info().words.end();
(*cloud)[i].r = inlier?0:255;
(*cloud)[i].g = 255;
(*cloud)[i++].b = 0;
}
}
cloud->resize(i);
if(!cloudView_->addCloud("featuresOdom", cloud))
{

View File

@@ -56,6 +56,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "rtabmap/core/CameraThread.h"
#include "rtabmap/core/CameraRGB.h"
#include "rtabmap/core/CameraStereo.h"
#include "rtabmap/core/IMUThread.h"
#include "rtabmap/core/Memory.h"
#include "rtabmap/core/VWDictionary.h"
#include "rtabmap/core/Optimizer.h"
@@ -172,6 +173,9 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
#ifndef RTABMAP_ORB_SLAM2
_ui->odom_strategy->setItemData(5, 0, Qt::UserRole - 1);
#endif
#ifndef RTABMAP_OKVIS
_ui->odom_strategy->setItemData(6, 0, Qt::UserRole - 1);
#endif
#ifndef RTABMAP_NONFREE
_ui->comboBox_detector_strategy->setItemData(0, 0, Qt::UserRole - 1);
@@ -561,6 +565,7 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
connect(_ui->toolButton_cameraRGBDImages_path_rgb, SIGNAL(clicked()), this, SLOT(selectSourceRGBDImagesPathRGB()));
connect(_ui->toolButton_cameraRGBDImages_path_depth, SIGNAL(clicked()), this, SLOT(selectSourceRGBDImagesPathDepth()));
connect(_ui->toolButton_cameraImages_path_scans, SIGNAL(clicked()), this, SLOT(selectSourceImagesPathScans()));
connect(_ui->toolButton_cameraImages_path_imu, SIGNAL(clicked()), this, SLOT(selectSourceImagesPathIMU()));
connect(_ui->toolButton_cameraImages_odom, SIGNAL(clicked()), this, SLOT(selectSourceImagesPathOdom()));
connect(_ui->toolButton_cameraImages_gt, SIGNAL(clicked()), this, SLOT(selectSourceImagesPathGt()));
connect(_ui->lineEdit_cameraRGBDImages_path_rgb, SIGNAL(textChanged(const QString &)), this, SLOT(makeObsoleteSourcePanel()));
@@ -579,6 +584,9 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
connect(_ui->lineEdit_cameraImages_gt, SIGNAL(textChanged(const QString &)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->comboBox_cameraImages_gtFormat, SIGNAL(currentIndexChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->doubleSpinBox_maxPoseTimeDiff, SIGNAL(valueChanged(double)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->lineEdit_cameraImages_path_imu, SIGNAL(textChanged(const QString &)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->lineEdit_cameraImages_imu_transform, SIGNAL(textChanged(const QString &)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->spinBox_cameraImages_max_imu_rate, SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->groupBox_depthFromScan, SIGNAL(toggled(bool)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->groupBox_depthFromScan_fillHoles, SIGNAL(toggled(bool)), this, SLOT(makeObsoleteSourcePanel()));
connect(_ui->radioButton_depthFromScan_vertical, SIGNAL(toggled(bool)), this, SLOT(makeObsoleteSourcePanel()));
@@ -674,6 +682,7 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
_ui->general_checkBox_createIntermediateNodes->setObjectName(Parameters::kRtabmapCreateIntermediateNodes().c_str());
_ui->general_spinBox_maxRetrieved->setObjectName(Parameters::kRtabmapMaxRetrieved().c_str());
_ui->general_checkBox_startNewMapOnLoopClosure->setObjectName(Parameters::kRtabmapStartNewMapOnLoopClosure().c_str());
_ui->general_checkBox_imagesAlreadyRectified->setObjectName(Parameters::kRtabmapImagesAlreadyRectified().c_str());
_ui->lineEdit_workingDirectory->setObjectName(Parameters::kRtabmapWorkingDirectory().c_str());
connect(_ui->toolButton_workingDirectory, SIGNAL(clicked()), this, SLOT(changeWorkingDirectory()));
@@ -1072,6 +1081,11 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
_ui->spinBox_OdomORBSLAM2MaxFeatures->setObjectName(Parameters::kOdomORBSLAM2MaxFeatures().c_str());
_ui->spinBox_OdomORBSLAM2MapSize->setObjectName(Parameters::kOdomORBSLAM2MapSize().c_str());
// Odometry Okvis
_ui->lineEdit_OdomOkvisPath->setObjectName(Parameters::kOdomOKVISConfigPath().c_str());
connect(_ui->toolButton_OdomOkvisPath, SIGNAL(clicked()), this, SLOT(changeOdometryOKVISConfigPath()));
//Stereo
_ui->stereo_winWidth->setObjectName(Parameters::kStereoWinWidth().c_str());
_ui->stereo_winHeight->setObjectName(Parameters::kStereoWinHeight().c_str());
@@ -1621,6 +1635,9 @@ void PreferencesDialog::resetSettings(QGroupBox * groupBox)
_ui->lineEdit_cameraImages_gt->setText("");
_ui->comboBox_cameraImages_gtFormat->setCurrentIndex(0);
_ui->doubleSpinBox_maxPoseTimeDiff->setValue(0.02);
_ui->lineEdit_cameraImages_path_imu->setText("");
_ui->lineEdit_cameraImages_imu_transform->setText("0 0 1 0 -1 0 1 0 0");
_ui->spinBox_cameraImages_max_imu_rate->setValue(0);
_ui->groupBox_scanFromDepth->setChecked(false);
_ui->spinBox_cameraScanFromDepth_decimation->setValue(8);
@@ -2021,6 +2038,10 @@ void PreferencesDialog::readCameraSettings(const QString & filePath)
_ui->lineEdit_cameraImages_gt->setText(settings.value("gt_path", _ui->lineEdit_cameraImages_gt->text()).toString());
_ui->comboBox_cameraImages_gtFormat->setCurrentIndex(settings.value("gt_format", _ui->comboBox_cameraImages_gtFormat->currentIndex()).toInt());
_ui->doubleSpinBox_maxPoseTimeDiff->setValue(settings.value("max_pose_time_diff", _ui->doubleSpinBox_maxPoseTimeDiff->value()).toDouble());
_ui->lineEdit_cameraImages_path_imu->setText(settings.value("imu_path", _ui->lineEdit_cameraImages_path_imu->text()).toString());
_ui->lineEdit_cameraImages_imu_transform->setText(settings.value("imu_local_transform", _ui->lineEdit_cameraImages_imu_transform->text()).toString());
_ui->spinBox_cameraImages_max_imu_rate->setValue(settings.value("imu_rate", _ui->spinBox_cameraImages_max_imu_rate->value()).toInt());
settings.endGroup(); // images
settings.beginGroup("Video");
@@ -2430,6 +2451,9 @@ void PreferencesDialog::writeCameraSettings(const QString & filePath) const
settings.setValue("gt_path", _ui->lineEdit_cameraImages_gt->text());
settings.setValue("gt_format", _ui->comboBox_cameraImages_gtFormat->currentIndex());
settings.setValue("max_pose_time_diff", _ui->doubleSpinBox_maxPoseTimeDiff->value());
settings.setValue("imu_path", _ui->lineEdit_cameraImages_path_imu->text());
settings.setValue("imu_local_transform", _ui->lineEdit_cameraImages_imu_transform->text());
settings.setValue("imu_rate", _ui->spinBox_cameraImages_max_imu_rate->value());
settings.endGroup(); // images
settings.beginGroup("Video");
@@ -3344,6 +3368,21 @@ void PreferencesDialog::selectSourceImagesPathScans()
}
}
void PreferencesDialog::selectSourceImagesPathIMU()
{
QString dir = _ui->lineEdit_cameraImages_path_imu->text();
if(dir.isEmpty())
{
dir = getWorkingDirectory();
}
QString path = QFileDialog::getOpenFileName(this, tr("Select file "), dir, tr("EuRoC IMU file (*.csv)"));
if(path.size())
{
_ui->lineEdit_cameraImages_path_imu->setText(path);
}
}
void PreferencesDialog::selectSourceRGBDImagesPathDepth()
{
QString dir = _ui->lineEdit_cameraRGBDImages_path_depth->text();
@@ -4161,6 +4200,23 @@ void PreferencesDialog::changeOdometryORBSLAM2Vocabulary()
}
}
void PreferencesDialog::changeOdometryOKVISConfigPath()
{
QString path;
if(_ui->lineEdit_OdomOkvisPath->text().isEmpty())
{
path = QFileDialog::getOpenFileName(this, tr("OKVIS Config"), this->getWorkingDirectory(), tr("OKVIS config (*.yaml)"));
}
else
{
path = QFileDialog::getOpenFileName(this, tr("OKVIS Config"), _ui->lineEdit_OdomOkvisPath->text(), tr("OKVIS config (*.yaml)"));
}
if(!path.isEmpty())
{
_ui->lineEdit_OdomOkvisPath->setText(path);
}
}
void PreferencesDialog::changeIcpPMConfigPath()
{
QString path;
@@ -4701,6 +4757,24 @@ Transform PreferencesDialog::getLaserLocalTransform() const
return t;
}
QString PreferencesDialog::getIMUPath() const
{
return _ui->lineEdit_cameraImages_path_imu->text();
}
Transform PreferencesDialog::getIMULocalTransform() const
{
Transform t = Transform::fromString(_ui->lineEdit_cameraImages_imu_transform->text().replace("PI_2", QString::number(3.141592/2.0)).toStdString());
if(t.isNull())
{
return Transform::getIdentity();
}
return t;
}
int PreferencesDialog::getIMURate() const
{
return _ui->spinBox_cameraImages_max_imu_rate->value();
}
bool PreferencesDialog::isSourceDatabaseStampsUsed() const
{
return _ui->source_checkBox_useDbStamps->isChecked();
@@ -4939,6 +5013,7 @@ Camera * PreferencesDialog::createCamera(bool useRawImages, bool useColor)
_ui->checkBox_cameraImages_timestamps->isChecked(),
_ui->lineEdit_cameraImages_timestamps->text().toStdString(),
_ui->checkBox_cameraImages_syncTimeStamps->isChecked());
}
else if (driver == kSrcStereoUsb)
{
@@ -5251,6 +5326,31 @@ void PreferencesDialog::testOdometry()
return;
}
IMUThread * imuThread = 0;
if((this->getSourceDriver() == kSrcStereoImages ||
this->getSourceDriver() == kSrcRGBDImages ||
this->getSourceDriver() == kSrcImages) &&
!_ui->lineEdit_cameraImages_path_imu->text().isEmpty())
{
if(this->getOdomStrategy() != Odometry::kTypeOkvis)
{
QMessageBox::warning(this, tr("Source IMU Path"),
tr("IMU path is set but odometry chosen doesn't support IMU, ignoring IMU..."), QMessageBox::Ok);
}
else
{
imuThread = new IMUThread(_ui->spinBox_cameraImages_max_imu_rate->value(), this->getIMULocalTransform());
if(!imuThread->init(_ui->lineEdit_cameraImages_path_imu->text().toStdString()))
{
QMessageBox::warning(this, tr("Source IMU Path"),
tr("Initialization of IMU data has failed! Path=%1.").arg(_ui->lineEdit_cameraImages_path_imu->text()), QMessageBox::Ok);
delete camera;
delete imuThread;
return;
}
}
}
ParametersMap parameters = this->getAllParameters();
if(getOdomRegistrationApproach() < 3)
{
@@ -5309,16 +5409,31 @@ void PreferencesDialog::testOdometry()
cameraThread.setDistortionModel(_ui->lineEdit_source_distortionModel->text().toStdString());
}
}
UEventsManager::createPipe(&cameraThread, &odomThread, "CameraEvent");
if(imuThread)
{
UEventsManager::createPipe(imuThread, &odomThread, "IMUEvent");
}
UEventsManager::createPipe(&odomThread, odomViewer, "OdometryEvent");
UEventsManager::createPipe(odomViewer, &odomThread, "OdometryResetEvent");
odomThread.start();
cameraThread.start();
if(imuThread)
{
imuThread->start();
}
odomViewer->exec();
delete odomViewer;
if(imuThread)
{
imuThread->join(true);
delete imuThread;
}
cameraThread.join(true);
odomThread.join(true);
}

View File

@@ -63,16 +63,25 @@
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>673</width>
<height>2834</height>
<y>-499</y>
<width>678</width>
<height>2811</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_16">
<property name="spacing">
<number>0</number>
</property>
<property name="margin">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
@@ -86,7 +95,7 @@
<enum>QFrame::Raised</enum>
</property>
<property name="currentIndex">
<number>7</number>
<number>18</number>
</property>
<widget class="QWidget" name="page_22">
<layout class="QVBoxLayout" name="verticalLayout_29" stretch="0,1">
@@ -2687,7 +2696,7 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
<item row="3" column="0">
<widget class="QLineEdit" name="lineEdit_sourceLocalTransform">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Format (3 values): x y z&lt;br/&gt;Format (6 values): x y z roll pitch yaw&lt;br/&gt;Format (7 values): x y z qx qy qz qw&lt;br/&gt;Format (9 values, 3x3 rotation): r11 r12 r13 r21 r22 r23 r31 r32 r33&lt;br/&gt;Format (12 values, 3x4 transform): r11 r12 r13 tx r21 r22 r23 ty r31 r32 r33 tz&lt;/p&gt;&lt;p&gt;KITTI: /base_link to /gray_camera = 0 0 1 -1 0 0 0 -1 0&lt;br/&gt;KITTI: /base_link to /color_camera = 0 0 1 0 -1 0 0 -0.06 0 -1 0 0&lt;br/&gt;KITTI: /base_footprint to /gray_camera = 0 0 1 0 -1 0 0 0 0 -1 0 1.67&lt;br/&gt;KITTI: /base_footprint to /gray_camera = 0 0 1 0 -1 0 0 -0.06 0 -1 0 1.67&lt;/p&gt;&lt;p&gt;EuRoC MAV: /base_link to /cam0 = [0 0 1 0; 0 -1 0 0; 1 0 0 0; 0 0 0 1]*T_BS&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Format (3 values): x y z&lt;br/&gt;Format (6 values): x y z roll pitch yaw&lt;br/&gt;Format (7 values): x y z qx qy qz qw&lt;br/&gt;Format (9 values, 3x3 rotation): r11 r12 r13 r21 r22 r23 r31 r32 r33&lt;br/&gt;Format (12 values, 3x4 transform): r11 r12 r13 tx r21 r22 r23 ty r31 r32 r33 tz&lt;/p&gt;&lt;p&gt;KITTI: /base_link to /gray_camera = 0 0 1 -1 0 0 0 -1 0&lt;br/&gt;KITTI: /base_link to /color_camera = 0 0 1 0 -1 0 0 -0.06 0 -1 0 0&lt;br/&gt;KITTI: /base_footprint to /gray_camera = 0 0 1 0 -1 0 0 0 0 -1 0 1.67&lt;br/&gt;KITTI: /base_footprint to /gray_camera = 0 0 1 0 -1 0 0 -0.06 0 -1 0 1.67&lt;/p&gt;&lt;p&gt;EuRoC MAV: /base_link to /cam0 = T_BS*T_SC0 = -0.0257742 0.00375623 0.999661 0.00981073 -0.999557 -0.0149672 -0.0257155 0.064677 0.0148655 -0.999881 0.00414038 -0.0216401&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>0 0 1 -1 0 0 0 -1 0</string>
@@ -4817,11 +4826,27 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
<string>Directory of images (optional settings)</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_93">
<property name="margin">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QGridLayout" name="gridLayout_68" columnstretch="0,0,1">
<item row="6" column="0">
<widget class="QToolButton" name="toolButton_cameraImages_gt">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="lineEdit_cameraImages_odom">
<property name="text">
@@ -4889,6 +4914,13 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="checkBox_cameraImages_syncTimeStamps">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="6" column="2">
<widget class="QLabel" name="label_288">
<property name="text">
@@ -4915,8 +4947,8 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="checkBox_cameraImages_syncTimeStamps">
<item row="1" column="1">
<widget class="QCheckBox" name="checkBox_cameraImages_timestamps">
<property name="text">
<string/>
</property>
@@ -4948,13 +4980,6 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="checkBox_cameraImages_timestamps">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QLineEdit" name="lineEdit_cameraImages_path_scans">
<property name="text">
@@ -4975,10 +5000,13 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QToolButton" name="toolButton_cameraImages_gt">
<property name="text">
<string>...</string>
<item row="11" column="1">
<widget class="QSpinBox" name="spinBox_cameraImages_max_scan_pts">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;KITTI: 130 000 points&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="maximum">
<number>99999999</number>
</property>
</widget>
</item>
@@ -5049,16 +5077,6 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
</property>
</widget>
</item>
<item row="11" column="1">
<widget class="QSpinBox" name="spinBox_cameraImages_max_scan_pts">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;KITTI: 130 000 points&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="maximum">
<number>99999999</number>
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="QLineEdit" name="lineEdit_cameraImages_laser_transform">
<property name="toolTip">
@@ -5239,6 +5257,79 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
</property>
</widget>
</item>
<item row="13" column="2">
<widget class="QLabel" name="label_464">
<property name="text">
<string>Local transform from /base_link to /imu_link. Mouse over the box to show formats.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="12" column="2">
<widget class="QLabel" name="label_463">
<property name="text">
<string>Path to file containing optional IMU data (*.csv [EuRoC format]).</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="12" column="0">
<widget class="QToolButton" name="toolButton_cameraImages_path_imu">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="12" column="1">
<widget class="QLineEdit" name="lineEdit_cameraImages_path_imu">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="13" column="1">
<widget class="QLineEdit" name="lineEdit_cameraImages_imu_transform">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Format (3 values): x y z&lt;br/&gt;Format (6 values): x y z roll pitch yaw&lt;br/&gt;Format (7 values): x y z qx qy qz qw&lt;br/&gt;Format (9 values, 3x3 rotation): r11 r12 r13 r21 r22 r23 r31 r32 r33&lt;br/&gt;Format (12 values, 3x4 transform): r11 r12 r13 tx r21 r22 r23 ty r31 r32 r33 tz&lt;/p&gt;&lt;p&gt;EuRoC: /base_link to /imu = 0 0 1 0 -1 0 1 0 0&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>0 0 0 0 0 0</string>
</property>
</widget>
</item>
<item row="14" column="2">
<widget class="QLabel" name="label_465">
<property name="text">
<string>IMU Rate. To synchronize capture rate with IMU timestamps, set to 0. This can be set a little over the actual IMU rate to keep up with camera capture rate if images are dropped by odometry.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="14" column="1">
<widget class="QSpinBox" name="spinBox_cameraImages_max_imu_rate">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;KITTI: 130 000 points&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="maximum">
<number>99999999</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
@@ -6015,6 +6106,16 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="general_checkBox_createIntermediateNodes">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QDoubleSpinBox" name="general_doubleSpinBox_detectionRate">
<property name="suffix">
@@ -6041,13 +6142,26 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="general_checkBox_createIntermediateNodes">
<item row="5" column="1">
<widget class="QLabel" name="label_467">
<property name="text">
<string>Images are already rectified. By default RTAB-Map assumes that received images are rectified. If they are not, they can be rectified by RTAB-Map if this parameter is false.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QCheckBox" name="general_checkBox_imagesAlreadyRectified">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>false</bool>
<bool>true</bool>
</property>
</widget>
</item>
@@ -10476,6 +10590,11 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
<string>ORB SLAM 2</string>
</property>
</item>
<item>
<property name="text">
<string>OKVIS</string>
</property>
</item>
</widget>
</item>
<item row="2" column="1">
@@ -10747,7 +10866,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
<item>
<widget class="QStackedWidget" name="stackedWidget_odometryType">
<property name="currentIndex">
<number>1</number>
<number>6</number>
</property>
<widget class="QWidget" name="page_52">
<layout class="QVBoxLayout" name="verticalLayout_77">
@@ -12746,6 +12865,75 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</item>
</layout>
</widget>
<widget class="QWidget" name="page_54">
<layout class="QVBoxLayout" name="verticalLayout_85" stretch="0,1">
<item>
<widget class="QGroupBox" name="groupBox_odomORBSLAM2_2">
<property name="title">
<string>OKVIS</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_128" stretch="0,1">
<item>
<widget class="QLabel" name="label_466">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;OKVIS: &lt;a href=&quot;https://github.com/ethz-asl/okvis&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;https://github.com/ethz-asl/okvis&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;IMU input required. Currently tested only with EuRoC data set.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_98" columnstretch="0,0,1">
<item row="0" column="1">
<widget class="QLineEdit" name="lineEdit_OdomOkvisPath"/>
</item>
<item row="0" column="2">
<widget class="QLabel" name="label_469">
<property name="text">
<string>Path to OKVIS config file (*.yaml). While OKVIS requires calibrations in the config file, they are ignored as those from received images are used instead.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QToolButton" name="toolButton_OdomOkvisPath">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_69">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="page_26">
<layout class="QVBoxLayout" name="verticalLayout_88">
<item>
@@ -13685,7 +13873,16 @@ Lower the ratio -&gt; higher the precision. 0 means disabled, matching the neare
<property name="spacing">
<number>0</number>
</property>
<property name="margin">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
@@ -13765,7 +13962,16 @@ Lower the ratio -&gt; higher the precision. 0 means disabled, matching the neare
<property name="spacing">
<number>0</number>
</property>
<property name="margin">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
@@ -13877,7 +14083,16 @@ Lower the ratio -&gt; higher the precision. 0 means disabled, matching the neare
<property name="spacing">
<number>0</number>
</property>
<property name="margin">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>