mirror of
https://github.com/introlab/rtabmap.git
synced 2026-09-02 09:30:25 +08:00
Added Monocular SLAM (experimental), Odometry classes refactoring
This commit is contained in:
@@ -182,6 +182,7 @@ DatabaseViewer::DatabaseViewer(QWidget * parent) :
|
||||
connect(ui_->horizontalSlider_neighbors, SIGNAL(sliderMoved(int)), this, SLOT(sliderNeighborValueChanged(int)));
|
||||
connect(ui_->horizontalSlider_loops, SIGNAL(sliderMoved(int)), this, SLOT(sliderLoopValueChanged(int)));
|
||||
connect(ui_->checkBox_showOptimized, SIGNAL(stateChanged(int)), this, SLOT(updateConstraintView()));
|
||||
connect(ui_->checkBox_show3DWords, SIGNAL(stateChanged(int)), this, SLOT(updateConstraintView()));
|
||||
ui_->checkBox_showOptimized->setEnabled(false);
|
||||
|
||||
ui_->horizontalSlider_iterations->setTracking(false);
|
||||
@@ -1038,8 +1039,8 @@ void DatabaseViewer::view3DMap()
|
||||
cloud = rtabmap::util3d::cloudFromDisparityRGB(
|
||||
data.getImageRaw(),
|
||||
util3d::disparityFromStereoImages(leftImg, data.getDepthRaw()),
|
||||
data.getDepthCx(), data.getDepthCy(),
|
||||
data.getDepthFx(), data.getDepthFy(),
|
||||
data.getCx(), data.getCy(),
|
||||
data.getFx(), data.getFy(),
|
||||
decimation);
|
||||
}
|
||||
else
|
||||
@@ -1047,8 +1048,8 @@ void DatabaseViewer::view3DMap()
|
||||
cloud = rtabmap::util3d::cloudFromDepthRGB(
|
||||
data.getImageRaw(),
|
||||
data.getDepthRaw(),
|
||||
data.getDepthCx(), data.getDepthCy(),
|
||||
data.getDepthFx(), data.getDepthFy(),
|
||||
data.getCx(), data.getCy(),
|
||||
data.getFx(), data.getFy(),
|
||||
decimation);
|
||||
}
|
||||
|
||||
@@ -1148,8 +1149,8 @@ void DatabaseViewer::generate3DMap()
|
||||
cloud = rtabmap::util3d::cloudFromDisparityRGB(
|
||||
data.getImageRaw(),
|
||||
util3d::disparityFromStereoImages(leftImg, data.getDepthRaw()),
|
||||
data.getDepthCx(), data.getDepthCy(),
|
||||
data.getDepthFx(), data.getDepthFy(),
|
||||
data.getCx(), data.getCy(),
|
||||
data.getFx(), data.getFy(),
|
||||
decimation);
|
||||
}
|
||||
else
|
||||
@@ -1157,8 +1158,8 @@ void DatabaseViewer::generate3DMap()
|
||||
cloud = rtabmap::util3d::cloudFromDepthRGB(
|
||||
data.getImageRaw(),
|
||||
data.getDepthRaw(),
|
||||
data.getDepthCx(), data.getDepthCy(),
|
||||
data.getDepthFx(), data.getDepthFy(),
|
||||
data.getCx(), data.getCy(),
|
||||
data.getFx(), data.getFy(),
|
||||
decimation);
|
||||
}
|
||||
|
||||
@@ -1443,8 +1444,8 @@ void DatabaseViewer::update(int value,
|
||||
cloud = util3d::cloudFromStereoImages(
|
||||
data.getImageRaw(),
|
||||
data.getDepthRaw(),
|
||||
data.getDepthCx(), data.getDepthCy(),
|
||||
data.getDepthFx(), data.getDepthFy(),
|
||||
data.getCx(), data.getCy(),
|
||||
data.getFx(), data.getFy(),
|
||||
1);
|
||||
}
|
||||
else
|
||||
@@ -1452,8 +1453,8 @@ void DatabaseViewer::update(int value,
|
||||
cloud = util3d::cloudFromDepthRGB(
|
||||
data.getImageRaw(),
|
||||
data.getDepthRaw(),
|
||||
data.getDepthCx(), data.getDepthCy(),
|
||||
data.getDepthFx(), data.getDepthFy(),
|
||||
data.getCx(), data.getCy(),
|
||||
data.getFx(), data.getFy(),
|
||||
1);
|
||||
}
|
||||
view3D->addOrUpdateCloud("0", cloud, data.getLocalTransform());
|
||||
@@ -1605,11 +1606,11 @@ void DatabaseViewer::updateStereo(const Signature * data)
|
||||
std::vector<cv::KeyPoint> kpts;
|
||||
cv::Rect roi = Feature2D::computeRoi(leftMono, "0.03 0.03 0.04 0.04");
|
||||
ParametersMap parameters;
|
||||
parameters.insert(ParametersPair(Parameters::kGFTTMaxCorners(), "1000"));
|
||||
parameters.insert(ParametersPair(Parameters::kKpWordsPerImage(), "1000"));
|
||||
parameters.insert(ParametersPair(Parameters::kGFTTMinDistance(), "5"));
|
||||
Feature2D::Type type = Feature2D::kFeatureGfttBrief;
|
||||
Feature2D * kptDetector = Feature2D::create(type, parameters);
|
||||
kpts = kptDetector->generateKeypoints(leftMono, 0, roi);
|
||||
kpts = kptDetector->generateKeypoints(leftMono, roi);
|
||||
delete kptDetector;
|
||||
|
||||
float timeKpt = timer.ticks();
|
||||
@@ -1651,7 +1652,7 @@ void DatabaseViewer::updateStereo(const Signature * data)
|
||||
pcl::PointXYZ tmpPt = util3d::projectDisparityTo3D(
|
||||
leftCorners[i],
|
||||
disparity,
|
||||
data->getDepthCx(), data->getDepthCy(), data->getDepthFx(), data->getDepthFy());
|
||||
data->getCx(), data->getCy(), data->getFx(), data->getFy());
|
||||
|
||||
if(pcl::isFinite(tmpPt))
|
||||
{
|
||||
@@ -1833,7 +1834,15 @@ void DatabaseViewer::sliderLoopValueChanged(int value)
|
||||
// only called when ui_->checkBox_showOptimized state changed
|
||||
void DatabaseViewer::updateConstraintView()
|
||||
{
|
||||
this->updateConstraintView(neighborLinks_.at(ui_->horizontalSlider_neighbors->value()), false);
|
||||
Link link = this->findActiveLink(ui_->horizontalSlider_A->value(), ui_->horizontalSlider_B->value());
|
||||
if(link.type() == Link::kNeighbor)
|
||||
{
|
||||
this->updateConstraintView(neighborLinks_.at(ui_->horizontalSlider_neighbors->value()), false);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->updateConstraintView(loopLinks_.at(ui_->horizontalSlider_loops->value()), false);
|
||||
}
|
||||
}
|
||||
|
||||
void DatabaseViewer::updateConstraintView(
|
||||
@@ -1961,8 +1970,8 @@ void DatabaseViewer::updateConstraintView(
|
||||
cloudFrom = rtabmap::util3d::cloudFromStereoImages(
|
||||
dataFrom.getImageRaw(),
|
||||
dataFrom.getDepthRaw(),
|
||||
dataFrom.getDepthCx(), dataFrom.getDepthCy(),
|
||||
dataFrom.getDepthFx(), dataFrom.getDepthFy(),
|
||||
dataFrom.getCx(), dataFrom.getCy(),
|
||||
dataFrom.getFx(), dataFrom.getFy(),
|
||||
1);
|
||||
}
|
||||
else
|
||||
@@ -1970,8 +1979,8 @@ void DatabaseViewer::updateConstraintView(
|
||||
cloudFrom = rtabmap::util3d::cloudFromDepthRGB(
|
||||
dataFrom.getImageRaw(),
|
||||
dataFrom.getDepthRaw(),
|
||||
dataFrom.getDepthCx(), dataFrom.getDepthCy(),
|
||||
dataFrom.getDepthFx(), dataFrom.getDepthFy(),
|
||||
dataFrom.getCx(), dataFrom.getCy(),
|
||||
dataFrom.getFx(), dataFrom.getFy(),
|
||||
1);
|
||||
}
|
||||
|
||||
@@ -1984,8 +1993,8 @@ void DatabaseViewer::updateConstraintView(
|
||||
cloudTo = rtabmap::util3d::cloudFromStereoImages(
|
||||
dataTo.getImageRaw(),
|
||||
dataTo.getDepthRaw(),
|
||||
dataTo.getDepthCx(), dataTo.getDepthCy(),
|
||||
dataTo.getDepthFx(), dataTo.getDepthFy(),
|
||||
dataTo.getCx(), dataTo.getCy(),
|
||||
dataTo.getFx(), dataTo.getFy(),
|
||||
1);
|
||||
}
|
||||
else
|
||||
@@ -1993,8 +2002,8 @@ void DatabaseViewer::updateConstraintView(
|
||||
cloudTo = rtabmap::util3d::cloudFromDepthRGB(
|
||||
dataTo.getImageRaw(),
|
||||
dataTo.getDepthRaw(),
|
||||
dataTo.getDepthCx(), dataTo.getDepthCy(),
|
||||
dataTo.getDepthFx(), dataTo.getDepthFy(),
|
||||
dataTo.getCx(), dataTo.getCy(),
|
||||
dataTo.getFx(), dataTo.getFy(),
|
||||
1);
|
||||
}
|
||||
|
||||
@@ -2189,20 +2198,20 @@ void DatabaseViewer::sliderIterationsValueChanged(int value)
|
||||
{
|
||||
cloud = rtabmap::util3d::cloudFromDisparity(
|
||||
util3d::disparityFromStereoImages(data.getImageRaw(), data.getDepthRaw()),
|
||||
data.getDepthCx(),
|
||||
data.getDepthCy(),
|
||||
data.getDepthFx(),
|
||||
data.getDepthFy(),
|
||||
data.getCx(),
|
||||
data.getCy(),
|
||||
data.getFx(),
|
||||
data.getFy(),
|
||||
ui_->spinBox_projDecimation->value());
|
||||
}
|
||||
else
|
||||
{
|
||||
cloud = util3d::cloudFromDepth(
|
||||
data.getDepthRaw(),
|
||||
data.getDepthCx(),
|
||||
data.getDepthCy(),
|
||||
data.getDepthFx(),
|
||||
data.getDepthFy(),
|
||||
data.getCx(),
|
||||
data.getCy(),
|
||||
data.getFx(),
|
||||
data.getFy(),
|
||||
ui_->spinBox_projDecimation->value());
|
||||
}
|
||||
if(cloud->size())
|
||||
@@ -2536,7 +2545,7 @@ void DatabaseViewer::refineConstraint(int from, int to, bool updateGraph)
|
||||
{
|
||||
leftMono = left;
|
||||
}
|
||||
cloudA = util3d::cloudFromDisparity(util3d::disparityFromStereoImages(leftMono, depthA), dataFrom.getDepthCx(), dataFrom.getDepthCy(), dataFrom.getDepthFx(), dataFrom.getDepthFy(), ui_->spinBox_icp_decimation->value());
|
||||
cloudA = util3d::cloudFromDisparity(util3d::disparityFromStereoImages(leftMono, depthA), dataFrom.getCx(), dataFrom.getCy(), dataFrom.getFx(), dataFrom.getFy(), ui_->spinBox_icp_decimation->value());
|
||||
if(ui_->doubleSpinBox_icp_maxDepth->value() > 0)
|
||||
{
|
||||
cloudA = util3d::passThrough<pcl::PointXYZ>(cloudA, "z", 0, ui_->doubleSpinBox_icp_maxDepth->value());
|
||||
@@ -2550,7 +2559,7 @@ void DatabaseViewer::refineConstraint(int from, int to, bool updateGraph)
|
||||
else
|
||||
{
|
||||
cloudA = util3d::getICPReadyCloud(depthA,
|
||||
dataFrom.getDepthFx(), dataFrom.getDepthFy(), dataFrom.getDepthCx(), dataFrom.getDepthCy(),
|
||||
dataFrom.getFx(), dataFrom.getFy(), dataFrom.getCx(), dataFrom.getCy(),
|
||||
ui_->spinBox_icp_decimation->value(),
|
||||
ui_->doubleSpinBox_icp_maxDepth->value(),
|
||||
ui_->doubleSpinBox_icp_voxel->value(),
|
||||
@@ -2569,7 +2578,7 @@ void DatabaseViewer::refineConstraint(int from, int to, bool updateGraph)
|
||||
{
|
||||
leftMono = left;
|
||||
}
|
||||
cloudB = util3d::cloudFromDisparity(util3d::disparityFromStereoImages(leftMono, depthB), dataTo.getDepthCx(), dataTo.getDepthCy(), dataTo.getDepthFx(), dataTo.getDepthFy(), ui_->spinBox_icp_decimation->value());
|
||||
cloudB = util3d::cloudFromDisparity(util3d::disparityFromStereoImages(leftMono, depthB), dataTo.getCx(), dataTo.getCy(), dataTo.getFx(), dataTo.getFy(), ui_->spinBox_icp_decimation->value());
|
||||
if(ui_->doubleSpinBox_icp_maxDepth->value() > 0)
|
||||
{
|
||||
cloudB = util3d::passThrough<pcl::PointXYZ>(cloudB, "z", 0, ui_->doubleSpinBox_icp_maxDepth->value());
|
||||
@@ -2583,7 +2592,7 @@ void DatabaseViewer::refineConstraint(int from, int to, bool updateGraph)
|
||||
else
|
||||
{
|
||||
cloudB = util3d::getICPReadyCloud(depthB,
|
||||
dataTo.getDepthFx(), dataTo.getDepthFy(), dataTo.getDepthCx(), dataTo.getDepthCy(),
|
||||
dataTo.getFx(), dataTo.getFy(), dataTo.getCx(), dataTo.getCy(),
|
||||
ui_->spinBox_icp_decimation->value(),
|
||||
ui_->doubleSpinBox_icp_maxDepth->value(),
|
||||
ui_->doubleSpinBox_icp_voxel->value(),
|
||||
@@ -3075,6 +3084,11 @@ void DatabaseViewer::updateLoopClosuresSlider(int from, int to)
|
||||
|
||||
if(loopLinks_.size())
|
||||
{
|
||||
if(loopLinks_.size() == 1)
|
||||
{
|
||||
// just to be able to move the cursor of the loop slider
|
||||
loopLinks_.push_back(loopLinks_.front());
|
||||
}
|
||||
ui_->horizontalSlider_loops->setMinimum(0);
|
||||
ui_->horizontalSlider_loops->setMaximum(loopLinks_.size()-1);
|
||||
ui_->horizontalSlider_loops->setEnabled(true);
|
||||
|
||||
@@ -109,8 +109,8 @@ void LoopClosureViewer::updateView(const Transform & transform)
|
||||
{
|
||||
cloudA = util3d::cloudFromStereoImages(
|
||||
sA_.getImageRaw(),
|
||||
sA_.getDepthRaw(),
|
||||
sA_.getDepthCx(), sA_.getDepthCy(),
|
||||
sA_.getDepthRaw(),
|
||||
sA_.getCx(), sA_.getCy(),
|
||||
sA_.getFx(), sA_.getFy(),
|
||||
decimation);
|
||||
}
|
||||
@@ -118,8 +118,8 @@ void LoopClosureViewer::updateView(const Transform & transform)
|
||||
{
|
||||
cloudA = util3d::cloudFromDepthRGB(
|
||||
sA_.getImageRaw(),
|
||||
sA_.getDepthRaw(),
|
||||
sA_.getDepthCx(), sA_.getDepthCy(),
|
||||
sA_.getDepthRaw(),
|
||||
sA_.getCx(), sA_.getCy(),
|
||||
sA_.getFx(), sA_.getFy(),
|
||||
decimation);
|
||||
}
|
||||
@@ -141,8 +141,8 @@ void LoopClosureViewer::updateView(const Transform & transform)
|
||||
{
|
||||
cloudB = util3d::cloudFromStereoImages(
|
||||
sB_.getImageRaw(),
|
||||
sB_.getDepthRaw(),
|
||||
sB_.getDepthCx(), sB_.getDepthCy(),
|
||||
sB_.getDepthRaw(),
|
||||
sB_.getCx(), sB_.getCy(),
|
||||
sB_.getFx(), sB_.getFy(),
|
||||
decimation);
|
||||
}
|
||||
@@ -150,8 +150,8 @@ void LoopClosureViewer::updateView(const Transform & transform)
|
||||
{
|
||||
cloudB = util3d::cloudFromDepthRGB(
|
||||
sB_.getImageRaw(),
|
||||
sB_.getDepthRaw(),
|
||||
sB_.getDepthCx(), sB_.getDepthCy(),
|
||||
sB_.getDepthRaw(),
|
||||
sB_.getCx(), sB_.getCy(),
|
||||
sB_.getFx(), sB_.getFy(),
|
||||
decimation);
|
||||
}
|
||||
|
||||
@@ -81,6 +81,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//RGB-D stuff
|
||||
#include "rtabmap/core/CameraRGBD.h"
|
||||
#include "rtabmap/core/Odometry.h"
|
||||
#include "rtabmap/core/OdometryThread.h"
|
||||
#include "rtabmap/core/OdometryEvent.h"
|
||||
#include "rtabmap/core/util3d.h"
|
||||
#include "rtabmap/core/Graph.h"
|
||||
@@ -849,7 +850,9 @@ void MainWindow::processOdometry(const rtabmap::SensorData & data, const rtabmap
|
||||
}
|
||||
else if(info.type == 1)
|
||||
{
|
||||
_ui->imageView_odometry->setFeatures(info.refCorners, Qt::red);
|
||||
std::vector<cv::KeyPoint> kpts;
|
||||
cv::KeyPoint::convert(info.refCorners, kpts);
|
||||
_ui->imageView_odometry->setFeatures(kpts, Qt::red);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -895,37 +898,37 @@ void MainWindow::processOdometry(const rtabmap::SensorData & data, const rtabmap
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(info.type == 1)
|
||||
}
|
||||
if(info.type == 1 && info.cornerInliers.size())
|
||||
{
|
||||
if(_ui->imageView_odometry->isFeaturesShown() || _ui->imageView_odometry->isLinesShown())
|
||||
{
|
||||
if(_ui->imageView_odometry->isFeaturesShown() || _ui->imageView_odometry->isLinesShown())
|
||||
//draw lines
|
||||
UASSERT(info.refCorners.size() == info.newCorners.size());
|
||||
for(unsigned int i=0; i<info.cornerInliers.size(); ++i)
|
||||
{
|
||||
//draw lines
|
||||
UASSERT(info.refCorners.size() == info.newCorners.size());
|
||||
for(unsigned int i=0; i<info.cornerInliers.size(); ++i)
|
||||
if(_ui->imageView_odometry->isFeaturesShown())
|
||||
{
|
||||
if(_ui->imageView_odometry->isFeaturesShown())
|
||||
{
|
||||
_ui->imageView_odometry->setFeatureColor(info.cornerInliers[i], Qt::green); // inliers
|
||||
}
|
||||
if(_ui->imageView_odometry->isLinesShown())
|
||||
{
|
||||
_ui->imageView_odometry->addLine(
|
||||
info.refCorners[info.cornerInliers[i]].pt.x,
|
||||
info.refCorners[info.cornerInliers[i]].pt.y,
|
||||
info.newCorners[info.cornerInliers[i]].pt.x,
|
||||
info.newCorners[info.cornerInliers[i]].pt.y,
|
||||
Qt::blue);
|
||||
}
|
||||
_ui->imageView_odometry->setFeatureColor(info.cornerInliers[i], Qt::green); // inliers
|
||||
}
|
||||
if(_ui->imageView_odometry->isLinesShown())
|
||||
{
|
||||
_ui->imageView_odometry->addLine(
|
||||
info.refCorners[info.cornerInliers[i]].x,
|
||||
info.refCorners[info.cornerInliers[i]].y,
|
||||
info.newCorners[info.cornerInliers[i]].x,
|
||||
info.newCorners[info.cornerInliers[i]].y,
|
||||
Qt::blue);
|
||||
}
|
||||
_ui->imageView_odometry->update();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if(!data.image().empty())
|
||||
{
|
||||
_ui->imageView_odometry->setSceneRect(QRectF(0,0,(float)data.image().cols, (float)data.image().rows));
|
||||
}
|
||||
|
||||
_ui->imageView_odometry->update();
|
||||
}
|
||||
|
||||
if(_ui->actionAuto_screen_capture->isChecked() && _autoScreenCaptureOdomSync)
|
||||
@@ -1240,7 +1243,8 @@ void MainWindow::updateMapCloud(
|
||||
{
|
||||
if(!_ui->actionSave_point_cloud->isEnabled() &&
|
||||
_cachedSignatures.size() &&
|
||||
!(--_cachedSignatures.end())->getDepthCompressed().empty())
|
||||
(!(--_cachedSignatures.end())->getDepthCompressed().empty() ||
|
||||
!(--_cachedSignatures.end())->getWords3().empty()))
|
||||
{
|
||||
//enable save cloud action
|
||||
_ui->actionSave_point_cloud->setEnabled(true);
|
||||
@@ -1336,7 +1340,7 @@ void MainWindow::updateMapCloud(
|
||||
else if(_cachedSignatures.contains(iter->first))
|
||||
{
|
||||
QMap<int, Signature>::iterator jter = _cachedSignatures.find(iter->first);
|
||||
if(!jter->getImageCompressed().empty() && !jter->getDepthCompressed().empty())
|
||||
if((!jter->getImageCompressed().empty() && !jter->getDepthCompressed().empty()) || jter->getWords3().size())
|
||||
{
|
||||
this->createAndAddCloudToMap(iter->first, iter->second, uValue(mapIds, iter->first, -1));
|
||||
}
|
||||
@@ -1567,98 +1571,125 @@ void MainWindow::createAndAddCloudToMap(int nodeId, const Transform & pose, int
|
||||
return;
|
||||
}
|
||||
|
||||
if(iter->getImageCompressed().empty() || iter->getDepthCompressed().empty())
|
||||
if(!iter->getImageCompressed().empty() && !iter->getDepthCompressed().empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
cv::Mat image, depth;
|
||||
iter->uncompressData(&image, &depth, 0);
|
||||
cv::Mat image, depth;
|
||||
iter->uncompressData(&image, &depth, 0);
|
||||
|
||||
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud;
|
||||
cloud = createCloud(nodeId,
|
||||
image,
|
||||
depth,
|
||||
iter->getDepthFx(),
|
||||
iter->getDepthFy(),
|
||||
iter->getDepthCx(),
|
||||
iter->getDepthCy(),
|
||||
iter->getLocalTransform(),
|
||||
Transform::getIdentity(),
|
||||
_preferencesDialog->getCloudVoxelSize(0),
|
||||
_preferencesDialog->getCloudDecimation(0),
|
||||
_preferencesDialog->getCloudMaxDepth(0));
|
||||
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud;
|
||||
cloud = createCloud(nodeId,
|
||||
image,
|
||||
depth,
|
||||
iter->getFx(),
|
||||
iter->getFy(),
|
||||
iter->getCx(),
|
||||
iter->getCy(),
|
||||
iter->getLocalTransform(),
|
||||
Transform::getIdentity(),
|
||||
_preferencesDialog->getCloudVoxelSize(0),
|
||||
_preferencesDialog->getCloudDecimation(0),
|
||||
_preferencesDialog->getCloudMaxDepth(0));
|
||||
|
||||
if(cloud->size() && _preferencesDialog->isGridMapFrom3DCloud())
|
||||
{
|
||||
UTimer timer;
|
||||
float cellSize = _preferencesDialog->getGridMapResolution();
|
||||
float groundNormalMaxAngle = M_PI_4;
|
||||
int minClusterSize = 20;
|
||||
cv::Mat ground, obstacles;
|
||||
pcl::PointCloud<pcl::PointXYZRGB>::Ptr voxelizedCloud = cloud;
|
||||
if(voxelizedCloud->size())
|
||||
if(cloud->size() && _preferencesDialog->isGridMapFrom3DCloud())
|
||||
{
|
||||
voxelizedCloud = util3d::voxelize<pcl::PointXYZRGB>(cloud, cellSize);
|
||||
UTimer timer;
|
||||
float cellSize = _preferencesDialog->getGridMapResolution();
|
||||
float groundNormalMaxAngle = M_PI_4;
|
||||
int minClusterSize = 20;
|
||||
cv::Mat ground, obstacles;
|
||||
pcl::PointCloud<pcl::PointXYZRGB>::Ptr voxelizedCloud = cloud;
|
||||
if(voxelizedCloud->size())
|
||||
{
|
||||
voxelizedCloud = util3d::voxelize<pcl::PointXYZRGB>(cloud, cellSize);
|
||||
}
|
||||
util3d::occupancy2DFromCloud3D<pcl::PointXYZRGB>(
|
||||
voxelizedCloud,
|
||||
ground, obstacles,
|
||||
cellSize,
|
||||
groundNormalMaxAngle,
|
||||
minClusterSize);
|
||||
if(!ground.empty() || !obstacles.empty())
|
||||
{
|
||||
_projectionLocalMaps.insert(std::make_pair(nodeId, std::make_pair(ground, obstacles)));
|
||||
}
|
||||
UDEBUG("time gridMapFrom2DCloud = %f s", timer.ticks());
|
||||
}
|
||||
util3d::occupancy2DFromCloud3D<pcl::PointXYZRGB>(
|
||||
voxelizedCloud,
|
||||
ground, obstacles,
|
||||
cellSize,
|
||||
groundNormalMaxAngle,
|
||||
minClusterSize);
|
||||
if(!ground.empty() || !obstacles.empty())
|
||||
{
|
||||
_projectionLocalMaps.insert(std::make_pair(nodeId, std::make_pair(ground, obstacles)));
|
||||
}
|
||||
UDEBUG("time gridMapFrom2DCloud = %f s", timer.ticks());
|
||||
}
|
||||
|
||||
if(_preferencesDialog->isCloudMeshing())
|
||||
{
|
||||
pcl::PolygonMesh::Ptr mesh(new pcl::PolygonMesh);
|
||||
if(cloud->size())
|
||||
if(_preferencesDialog->isCloudMeshing())
|
||||
{
|
||||
pcl::PolygonMesh::Ptr mesh(new pcl::PolygonMesh);
|
||||
if(cloud->size())
|
||||
{
|
||||
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr cloudWithNormals;
|
||||
if(_preferencesDialog->getMeshSmoothing())
|
||||
{
|
||||
cloudWithNormals = util3d::computeNormalsSmoothed(cloud, (float)_preferencesDialog->getMeshSmoothingRadius());
|
||||
}
|
||||
else
|
||||
{
|
||||
cloudWithNormals = util3d::computeNormals(cloud, _preferencesDialog->getMeshNormalKSearch());
|
||||
}
|
||||
mesh = util3d::createMesh(cloudWithNormals, _preferencesDialog->getMeshGP3Radius());
|
||||
}
|
||||
|
||||
if(mesh->polygons.size())
|
||||
{
|
||||
pcl::PointCloud<pcl::PointXYZRGB>::Ptr tmp(new pcl::PointCloud<pcl::PointXYZRGB>);
|
||||
pcl::fromPCLPointCloud2(mesh->cloud, *tmp);
|
||||
if(!_ui->widget_cloudViewer->addCloudMesh(cloudName, tmp, mesh->polygons, pose))
|
||||
{
|
||||
UERROR("Adding mesh cloud %d to viewer failed!", nodeId);
|
||||
}
|
||||
else
|
||||
{
|
||||
_createdClouds.insert(std::make_pair(nodeId, tmp));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr cloudWithNormals;
|
||||
if(_preferencesDialog->getMeshSmoothing())
|
||||
{
|
||||
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr cloudWithNormals;
|
||||
cloudWithNormals = util3d::computeNormalsSmoothed(cloud, (float)_preferencesDialog->getMeshSmoothingRadius());
|
||||
cloud->clear();
|
||||
pcl::copyPointCloud(*cloudWithNormals, *cloud);
|
||||
}
|
||||
QColor color = Qt::gray;
|
||||
if(mapId >= 0)
|
||||
{
|
||||
color = (Qt::GlobalColor)(mapId % 12 + 7 );
|
||||
}
|
||||
if(!_ui->widget_cloudViewer->addOrUpdateCloud(cloudName, cloud, pose, color))
|
||||
{
|
||||
UERROR("Adding cloud %d to viewer failed!", nodeId);
|
||||
}
|
||||
else
|
||||
{
|
||||
cloudWithNormals = util3d::computeNormals(cloud, _preferencesDialog->getMeshNormalKSearch());
|
||||
}
|
||||
mesh = util3d::createMesh(cloudWithNormals, _preferencesDialog->getMeshGP3Radius());
|
||||
}
|
||||
|
||||
if(mesh->polygons.size())
|
||||
{
|
||||
pcl::PointCloud<pcl::PointXYZRGB>::Ptr tmp(new pcl::PointCloud<pcl::PointXYZRGB>);
|
||||
pcl::fromPCLPointCloud2(mesh->cloud, *tmp);
|
||||
if(!_ui->widget_cloudViewer->addCloudMesh(cloudName, tmp, mesh->polygons, pose))
|
||||
{
|
||||
UERROR("Adding mesh cloud %d to viewer failed!", nodeId);
|
||||
}
|
||||
else
|
||||
{
|
||||
_createdClouds.insert(std::make_pair(nodeId, tmp));
|
||||
_createdClouds.insert(std::make_pair(nodeId, cloud));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
else if(iter->getWords3().size())
|
||||
{
|
||||
if(_preferencesDialog->getMeshSmoothing())
|
||||
{
|
||||
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr cloudWithNormals;
|
||||
cloudWithNormals = util3d::computeNormalsSmoothed(cloud, (float)_preferencesDialog->getMeshSmoothingRadius());
|
||||
cloud->clear();
|
||||
pcl::copyPointCloud(*cloudWithNormals, *cloud);
|
||||
}
|
||||
QColor color = Qt::gray;
|
||||
if(mapId >= 0)
|
||||
{
|
||||
color = (Qt::GlobalColor)(mapId % 12 + 7 );
|
||||
}
|
||||
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGB>);
|
||||
cloud->resize(iter->getWords3().size());
|
||||
int oi=0;
|
||||
for(std::multimap<int, pcl::PointXYZ>::const_iterator jter=iter->getWords3().begin(); jter!=iter->getWords3().end(); ++jter)
|
||||
{
|
||||
(*cloud)[oi].x = jter->second.x;
|
||||
(*cloud)[oi].y = jter->second.y;
|
||||
(*cloud)[oi].z = jter->second.z;
|
||||
(*cloud)[oi].r = 255;
|
||||
(*cloud)[oi].g = 255;
|
||||
(*cloud)[oi++].b = 255;
|
||||
}
|
||||
if(!_ui->widget_cloudViewer->addOrUpdateCloud(cloudName, cloud, pose, color))
|
||||
{
|
||||
UERROR("Adding cloud %d to viewer failed!", nodeId);
|
||||
@@ -1668,6 +1699,10 @@ void MainWindow::createAndAddCloudToMap(int nodeId, const Transform & pose, int
|
||||
_createdClouds.insert(std::make_pair(nodeId, cloud));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_ui->widget_cloudViewer->setCloudOpacity(cloudName, _preferencesDialog->getCloudOpacity(0));
|
||||
_ui->widget_cloudViewer->setCloudPointSize(cloudName, _preferencesDialog->getCloudPointSize(0));
|
||||
@@ -1992,6 +2027,7 @@ void MainWindow::applyPrefSettings(PreferencesDialog::PANEL_FLAGS flags)
|
||||
if(_camera->cameraRGBD())
|
||||
{
|
||||
_camera->cameraRGBD()->setMirroringEnabled(_preferencesDialog->isSourceMirroring());
|
||||
_camera->cameraRGBD()->setColorOnly(_preferencesDialog->isSourceRGBDColorOnly());
|
||||
}
|
||||
}
|
||||
if(_dbReader)
|
||||
@@ -2637,6 +2673,7 @@ void MainWindow::startDetection()
|
||||
}
|
||||
}
|
||||
camera->setMirroringEnabled(_preferencesDialog->isSourceMirroring());
|
||||
camera->setColorOnly(_preferencesDialog->isSourceRGBDColorOnly());
|
||||
|
||||
_camera = new CameraThread(camera);
|
||||
|
||||
@@ -2673,6 +2710,10 @@ void MainWindow::startDetection()
|
||||
{
|
||||
odom = new OdometryOpticalFlow(parameters);
|
||||
}
|
||||
else if(_preferencesDialog->getOdomStrategy() == 2)
|
||||
{
|
||||
odom = new OdometryMono(parameters);
|
||||
}
|
||||
else
|
||||
{
|
||||
odom = new OdometryBOW(parameters);
|
||||
@@ -2705,6 +2746,10 @@ void MainWindow::startDetection()
|
||||
{
|
||||
odom = new OdometryOpticalFlow(parameters);
|
||||
}
|
||||
else if(_preferencesDialog->getOdomStrategy() == 2)
|
||||
{
|
||||
odom = new OdometryMono(parameters);
|
||||
}
|
||||
else
|
||||
{
|
||||
odom = new OdometryBOW(parameters);
|
||||
@@ -3104,7 +3149,7 @@ void MainWindow::postProcessing()
|
||||
if(refineNeighborLinks || refineLoopClosureLinks || reextractFeatures)
|
||||
{
|
||||
// depth data required
|
||||
if(jter->getDepthCompressed().empty() || jter->getDepthFx() <= 0.0f || jter->getDepthFy() <= 0.0f)
|
||||
if(jter->getDepthCompressed().empty() || jter->getFx() <= 0.0f || jter->getFy() <= 0.0f)
|
||||
{
|
||||
UWARN("Depth data of %d missing.", iter->first);
|
||||
allDataAvailable = false;
|
||||
@@ -3376,14 +3421,14 @@ void MainWindow::postProcessing()
|
||||
}
|
||||
|
||||
pcl::PointCloud<pcl::PointXYZ>::Ptr cloudA = util3d::getICPReadyCloud(depthA,
|
||||
signatureFrom.getDepthFx(), signatureFrom.getDepthFy(), signatureFrom.getDepthCx(), signatureFrom.getDepthCy(),
|
||||
signatureFrom.getFx(), signatureFrom.getFy(), signatureFrom.getCx(), signatureFrom.getCy(),
|
||||
decimation,
|
||||
maxDepth,
|
||||
voxelSize,
|
||||
samples,
|
||||
signatureFrom.getLocalTransform());
|
||||
pcl::PointCloud<pcl::PointXYZ>::Ptr cloudB = util3d::getICPReadyCloud(depthB,
|
||||
signatureTo.getDepthFx(), signatureTo.getDepthFy(), signatureTo.getDepthCx(), signatureTo.getDepthCy(),
|
||||
signatureTo.getFx(), signatureTo.getFy(), signatureTo.getCx(), signatureTo.getCy(),
|
||||
decimation,
|
||||
maxDepth,
|
||||
voxelSize,
|
||||
@@ -4393,7 +4438,7 @@ void MainWindow::dataRecorder()
|
||||
{
|
||||
if(_dataRecorder == 0)
|
||||
{
|
||||
QString path = QFileDialog::getSaveFileName(this, tr("Save to..."), "output.db", "RTAB-Map database (*.db)");
|
||||
QString path = QFileDialog::getSaveFileName(this, tr("Save to..."), _preferencesDialog->getWorkingDirectory()+"/output.db", "RTAB-Map database (*.db)");
|
||||
if(!path.isEmpty())
|
||||
{
|
||||
int r = QMessageBox::question(this, tr("Hard drive or RAM?"), tr("Save in RAM?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
|
||||
@@ -4867,18 +4912,35 @@ pcl::PointCloud<pcl::PointXYZRGB>::Ptr MainWindow::getAssembledCloud(
|
||||
cv::Mat image, depth;
|
||||
s.uncompressDataConst(&image, &depth, 0);
|
||||
|
||||
cloud = createCloud(iter->first,
|
||||
image,
|
||||
depth,
|
||||
s.getDepthFx(),
|
||||
s.getDepthFy(),
|
||||
s.getDepthCx(),
|
||||
s.getDepthCy(),
|
||||
s.getLocalTransform(),
|
||||
iter->second,
|
||||
regenerateVoxelSize,
|
||||
regenerateDecimation,
|
||||
regenerateMaxDepth);
|
||||
if(!image.empty() && !depth.empty())
|
||||
{
|
||||
cloud = createCloud(iter->first,
|
||||
image,
|
||||
depth,
|
||||
s.getFx(),
|
||||
s.getFy(),
|
||||
s.getCx(),
|
||||
s.getCy(),
|
||||
s.getLocalTransform(),
|
||||
iter->second,
|
||||
regenerateVoxelSize,
|
||||
regenerateDecimation,
|
||||
regenerateMaxDepth);
|
||||
}
|
||||
else if(s.getWords3().size())
|
||||
{
|
||||
cloud->resize(s.getWords3().size());
|
||||
int oi=0;
|
||||
for(std::multimap<int, pcl::PointXYZ>::const_iterator jter=s.getWords3().begin(); jter!=s.getWords3().end(); ++jter)
|
||||
{
|
||||
(*cloud)[oi].x = jter->second.x;
|
||||
(*cloud)[oi].y = jter->second.y;
|
||||
(*cloud)[oi].z = jter->second.z;
|
||||
(*cloud)[oi].r = 255;
|
||||
(*cloud)[oi].g = 255;
|
||||
(*cloud)[oi++].b = 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -4953,18 +5015,35 @@ std::map<int, pcl::PointCloud<pcl::PointXYZRGB>::Ptr > MainWindow::getClouds(
|
||||
const Signature & s = _cachedSignatures.find(iter->first).value();
|
||||
cv::Mat image, depth;
|
||||
s.uncompressDataConst(&image, &depth, 0);
|
||||
cloud = createCloud(iter->first,
|
||||
image,
|
||||
depth,
|
||||
s.getDepthFx(),
|
||||
s.getDepthFy(),
|
||||
s.getDepthCx(),
|
||||
s.getDepthCy(),
|
||||
s.getLocalTransform(),
|
||||
Transform::getIdentity(),
|
||||
regenerateVoxelSize,
|
||||
regenerateDecimation,
|
||||
regenerateMaxDepth);
|
||||
if(!image.empty() && !depth.empty())
|
||||
{
|
||||
cloud = createCloud(iter->first,
|
||||
image,
|
||||
depth,
|
||||
s.getFx(),
|
||||
s.getFy(),
|
||||
s.getCx(),
|
||||
s.getCy(),
|
||||
s.getLocalTransform(),
|
||||
Transform::getIdentity(),
|
||||
regenerateVoxelSize,
|
||||
regenerateDecimation,
|
||||
regenerateMaxDepth);
|
||||
}
|
||||
else if(s.getWords3().size())
|
||||
{
|
||||
cloud->resize(s.getWords3().size());
|
||||
int oi=0;
|
||||
for(std::multimap<int, pcl::PointXYZ>::const_iterator jter=s.getWords3().begin(); jter!=s.getWords3().end(); ++jter)
|
||||
{
|
||||
(*cloud)[oi].x = jter->second.x;
|
||||
(*cloud)[oi].y = jter->second.y;
|
||||
(*cloud)[oi].z = jter->second.z;
|
||||
(*cloud)[oi].r = 255;
|
||||
(*cloud)[oi].g = 255;
|
||||
(*cloud)[oi++].b = 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -86,6 +86,7 @@ OdometryViewer::OdometryViewer(int maxClouds, int decimation, float voxelSize, i
|
||||
decimationSpin_->setMinimum(1);
|
||||
decimationSpin_->setMaximum(16);
|
||||
decimationSpin_->setValue(decimation);
|
||||
timeLabel_ = new QLabel(this);
|
||||
QPushButton * clearButton = new QPushButton("clear", this);
|
||||
QPushButton * closeButton = new QPushButton("close", this);
|
||||
connect(clearButton, SIGNAL(clicked()), this, SLOT(clear()));
|
||||
@@ -106,6 +107,7 @@ OdometryViewer::OdometryViewer(int maxClouds, int decimation, float voxelSize, i
|
||||
hlayout2->addWidget(voxelSpin_);
|
||||
hlayout2->addWidget(decimationLabel);
|
||||
hlayout2->addWidget(decimationSpin_);
|
||||
hlayout2->addWidget(timeLabel_);
|
||||
hlayout2->addStretch(1);
|
||||
hlayout2->addWidget(clearButton);
|
||||
hlayout2->addWidget(closeButton);
|
||||
@@ -166,6 +168,7 @@ void OdometryViewer::processData(const rtabmap::SensorData & data, const rtabmap
|
||||
cloudView_->setBackgroundColor(Qt::black);
|
||||
}
|
||||
|
||||
timeLabel_->setText(QString("%1 s").arg(info.time));
|
||||
|
||||
if(!data.image().empty() && !data.depthOrRightImage().empty() && data.fx()>0.0f && data.fyOrBaseline()>0.0f)
|
||||
{
|
||||
@@ -220,7 +223,6 @@ void OdometryViewer::processData(const rtabmap::SensorData & data, const rtabmap
|
||||
|
||||
if(!data.pose().isNull())
|
||||
{
|
||||
lastOdomPose_ = data.pose();
|
||||
if(cloudView_->getAddedClouds().contains("cloudtmp"))
|
||||
{
|
||||
cloudView_->removeCloud("cloudtmp");
|
||||
@@ -236,8 +238,6 @@ void OdometryViewer::processData(const rtabmap::SensorData & data, const rtabmap
|
||||
std::string cloudName = uFormat("cloud%d", id_);
|
||||
addedClouds_.push_back(cloudName);
|
||||
UASSERT(cloudView_->addCloud(cloudName, cloud, data.pose()));
|
||||
|
||||
cloudView_->updateCameraTargetPosition(data.pose());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -246,6 +246,26 @@ void OdometryViewer::processData(const rtabmap::SensorData & data, const rtabmap
|
||||
}
|
||||
}
|
||||
|
||||
if(!data.pose().isNull())
|
||||
{
|
||||
lastOdomPose_ = data.pose();
|
||||
cloudView_->updateCameraTargetPosition(data.pose());
|
||||
}
|
||||
|
||||
if(info.localMap.size())
|
||||
{
|
||||
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
|
||||
cloud->resize(info.localMap.size());
|
||||
int i=0;
|
||||
for(std::multimap<int, cv::Point3f>::const_iterator iter=info.localMap.begin(); iter!=info.localMap.end(); ++iter)
|
||||
{
|
||||
(*cloud)[i].x = iter->second.x;
|
||||
(*cloud)[i].y = iter->second.y;
|
||||
(*cloud)[i++].z = iter->second.z;
|
||||
}
|
||||
cloudView_->addOrUpdateCloud("localmap", cloud);
|
||||
}
|
||||
|
||||
if(!data.image().empty())
|
||||
{
|
||||
if(info.type == 0)
|
||||
@@ -254,7 +274,9 @@ void OdometryViewer::processData(const rtabmap::SensorData & data, const rtabmap
|
||||
}
|
||||
else if(info.type == 1)
|
||||
{
|
||||
imageView_->setFeatures(info.refCorners, Qt::red);
|
||||
std::vector<cv::KeyPoint> kpts;
|
||||
cv::KeyPoint::convert(info.refCorners, kpts);
|
||||
imageView_->setFeatures(kpts, Qt::red);
|
||||
}
|
||||
|
||||
imageView_->clearLines();
|
||||
@@ -299,32 +321,32 @@ void OdometryViewer::processData(const rtabmap::SensorData & data, const rtabmap
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(info.type == 1)
|
||||
}
|
||||
if(info.type == 1 && info.cornerInliers.size())
|
||||
{
|
||||
if(imageView_->isFeaturesShown() || imageView_->isLinesShown())
|
||||
{
|
||||
if(imageView_->isFeaturesShown() || imageView_->isLinesShown())
|
||||
//draw lines
|
||||
UASSERT(info.refCorners.size() == info.newCorners.size());
|
||||
for(unsigned int i=0; i<info.cornerInliers.size(); ++i)
|
||||
{
|
||||
//draw lines
|
||||
UASSERT(info.refCorners.size() == info.newCorners.size());
|
||||
for(unsigned int i=0; i<info.cornerInliers.size(); ++i)
|
||||
if(imageView_->isFeaturesShown())
|
||||
{
|
||||
if(imageView_->isFeaturesShown())
|
||||
{
|
||||
imageView_->setFeatureColor(info.cornerInliers[i], Qt::green); // inliers
|
||||
}
|
||||
if(imageView_->isLinesShown())
|
||||
{
|
||||
imageView_->addLine(
|
||||
info.refCorners[info.cornerInliers[i]].pt.x,
|
||||
info.refCorners[info.cornerInliers[i]].pt.y,
|
||||
info.newCorners[info.cornerInliers[i]].pt.x,
|
||||
info.newCorners[info.cornerInliers[i]].pt.y,
|
||||
Qt::blue);
|
||||
}
|
||||
imageView_->setFeatureColor(info.cornerInliers[i], Qt::green); // inliers
|
||||
}
|
||||
if(imageView_->isLinesShown())
|
||||
{
|
||||
imageView_->addLine(
|
||||
info.refCorners[info.cornerInliers[i]].x,
|
||||
info.refCorners[info.cornerInliers[i]].y,
|
||||
info.newCorners[info.cornerInliers[i]].x,
|
||||
info.newCorners[info.cornerInliers[i]].y,
|
||||
Qt::blue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(!data.image().empty())
|
||||
{
|
||||
imageView_->setSceneRect(QRectF(0,0,(float)data.image().cols, (float)data.image().rows));
|
||||
|
||||
@@ -48,6 +48,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "rtabmap/core/Rtabmap.h"
|
||||
#include "rtabmap/core/Parameters.h"
|
||||
#include "rtabmap/core/Odometry.h"
|
||||
#include "rtabmap/core/OdometryThread.h"
|
||||
#include "rtabmap/core/CameraRGBD.h"
|
||||
#include "rtabmap/core/CameraThread.h"
|
||||
#include "rtabmap/core/Camera.h"
|
||||
@@ -302,6 +303,7 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
|
||||
connect(_ui->openni2_exposure, SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
connect(_ui->openni2_gain, SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
connect(_ui->openni2_mirroring, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
connect(_ui->checkbox_rgbd_colorOnly, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
connect(_ui->lineEdit_openniDevice, SIGNAL(textChanged(const QString &)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
connect(_ui->lineEdit_openniLocalTransform, SIGNAL(textChanged(const QString &)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
connect(_ui->pushButton_calibrate, SIGNAL(clicked()), this, SLOT(calibrate()));
|
||||
@@ -425,7 +427,6 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
|
||||
_ui->fastKeypointRatio->setObjectName(Parameters::kFASTGpuKeypointsRatio().c_str());
|
||||
|
||||
//ORB detector
|
||||
_ui->spinBox_ORBNFeatures->setObjectName(Parameters::kORBNFeatures().c_str());
|
||||
_ui->doubleSpinBox_ORBScaleFactor->setObjectName(Parameters::kORBScaleFactor().c_str());
|
||||
_ui->spinBox_ORBNLevels->setObjectName(Parameters::kORBNLevels().c_str());
|
||||
_ui->spinBox_ORBEdgeThreshold->setObjectName(Parameters::kORBEdgeThreshold().c_str());
|
||||
@@ -442,7 +443,6 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
|
||||
_ui->spinBox_FREAKNOctaves->setObjectName(Parameters::kFREAKNOctaves().c_str());
|
||||
|
||||
//GFTT detector
|
||||
_ui->spinBox_GFTT_maxCorners->setObjectName(Parameters::kGFTTMaxCorners().c_str());
|
||||
_ui->doubleSpinBox_GFTT_qualityLevel->setObjectName(Parameters::kGFTTQualityLevel().c_str());
|
||||
_ui->doubleSpinBox_GFTT_minDistance->setObjectName(Parameters::kGFTTMinDistance().c_str());
|
||||
_ui->spinBox_GFTT_blockSize->setObjectName(Parameters::kGFTTBlockSize().c_str());
|
||||
@@ -489,6 +489,8 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
|
||||
_ui->loopClosure_bowIterations->setObjectName(Parameters::kLccBowIterations().c_str());
|
||||
_ui->loopClosure_bowMaxDepth->setObjectName(Parameters::kLccBowMaxDepth().c_str());
|
||||
_ui->loopClosure_bowForce2D->setObjectName(Parameters::kLccBowForce2D().c_str());
|
||||
_ui->loopClosure_bowEpipolarGeometry->setObjectName(Parameters::kLccBowEpipolarGeometry().c_str());
|
||||
_ui->loopClosure_bowEpipolarGeometryVar->setObjectName(Parameters::kLccBowEpipolarGeometryVar().c_str());
|
||||
|
||||
_ui->groupBox_reextract->setObjectName(Parameters::kLccReextractActivated().c_str());
|
||||
_ui->reextract_nn->setObjectName(Parameters::kLccReextractNNType().c_str());
|
||||
@@ -546,6 +548,12 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
|
||||
_ui->odom_subpix_iterations->setObjectName(Parameters::kOdomSubPixIterations().c_str());
|
||||
_ui->odom_subpix_eps->setObjectName(Parameters::kOdomSubPixEps().c_str());
|
||||
|
||||
//Odometry Mono
|
||||
_ui->doubleSpinBox_minFlow->setObjectName(Parameters::kOdomMonoInitMinFlow().c_str());
|
||||
_ui->doubleSpinBox_minInitTranslation->setObjectName(Parameters::kOdomMonoInitMinTranslation().c_str());
|
||||
_ui->doubleSpinBox_minTranslation->setObjectName(Parameters::kOdomMonoMinTranslation().c_str());
|
||||
_ui->doubleSpinBox_maxVariance->setObjectName(Parameters::kOdomMonoMaxVariance().c_str());
|
||||
|
||||
//Stereo
|
||||
_ui->stereo_flow_winSize->setObjectName(Parameters::kStereoWinSize().c_str());
|
||||
_ui->stereo_flow_maxLevel->setObjectName(Parameters::kStereoMaxLevel().c_str());
|
||||
@@ -944,6 +952,7 @@ void PreferencesDialog::resetSettings(QGroupBox * groupBox)
|
||||
_ui->openni2_exposure->setValue(0);
|
||||
_ui->openni2_gain->setValue(100);
|
||||
_ui->openni2_mirroring->setChecked(false);
|
||||
_ui->checkbox_rgbd_colorOnly->setChecked(false);
|
||||
_ui->lineEdit_openniDevice->setText("");
|
||||
_ui->lineEdit_openniLocalTransform->setText("0 0 0 -PI_2 0 -PI_2");
|
||||
}
|
||||
@@ -1204,6 +1213,7 @@ void PreferencesDialog::readCameraSettings(const QString & filePath)
|
||||
_ui->openni2_exposure->setValue(settings.value("openni2Exposure", _ui->openni2_exposure->value()).toInt());
|
||||
_ui->openni2_gain->setValue(settings.value("openni2Gain", _ui->openni2_gain->value()).toInt());
|
||||
_ui->openni2_mirroring->setChecked(settings.value("openni2Mirroring", _ui->openni2_mirroring->isChecked()).toBool());
|
||||
_ui->checkbox_rgbd_colorOnly->setChecked(settings.value("rgbdColorOnly", _ui->checkbox_rgbd_colorOnly->isChecked()).toBool());
|
||||
_ui->lineEdit_openniDevice->setText(settings.value("device",_ui->lineEdit_openniDevice->text()).toString());
|
||||
_ui->lineEdit_openniLocalTransform->setText(settings.value("localTransform",_ui->lineEdit_openniLocalTransform->text()).toString());
|
||||
_calibrationDialog->loadSettings(settings, "CalibrationDialog");
|
||||
@@ -1469,6 +1479,7 @@ void PreferencesDialog::writeCameraSettings(const QString & filePath) const
|
||||
settings.setValue("openni2Exposure", _ui->openni2_exposure->value());
|
||||
settings.setValue("openni2Gain", _ui->openni2_gain->value());
|
||||
settings.setValue("openni2Mirroring", _ui->openni2_mirroring->isChecked());
|
||||
settings.setValue("rgbdColorOnly", _ui->checkbox_rgbd_colorOnly->isChecked());
|
||||
settings.setValue("device", _ui->lineEdit_openniDevice->text());
|
||||
settings.setValue("localTransform", _ui->lineEdit_openniLocalTransform->text());
|
||||
_calibrationDialog->saveSettings(settings, "CalibrationDialog");
|
||||
@@ -3054,6 +3065,10 @@ bool PreferencesDialog::getSourceOpenni2Mirroring() const
|
||||
{
|
||||
return _ui->openni2_mirroring->isChecked();
|
||||
}
|
||||
bool PreferencesDialog::isSourceRGBDColorOnly() const
|
||||
{
|
||||
return _ui->checkbox_rgbd_colorOnly->isChecked();
|
||||
}
|
||||
QString PreferencesDialog::getSourceOpenniDevice() const
|
||||
{
|
||||
return _ui->lineEdit_openniDevice->text();
|
||||
@@ -3288,6 +3303,7 @@ void PreferencesDialog::testOdometry(int type)
|
||||
}
|
||||
}
|
||||
camera->setMirroringEnabled(isSourceMirroring());
|
||||
camera->setColorOnly(isSourceRGBDColorOnly());
|
||||
|
||||
ParametersMap parameters = this->getAllParameters();
|
||||
Odometry * odometry;
|
||||
@@ -3295,6 +3311,10 @@ void PreferencesDialog::testOdometry(int type)
|
||||
{
|
||||
odometry = new OdometryOpticalFlow(parameters);
|
||||
}
|
||||
else if(this->getOdomStrategy() == 2)
|
||||
{
|
||||
odometry = new OdometryMono(parameters);
|
||||
}
|
||||
else
|
||||
{
|
||||
odometry = new OdometryBOW(parameters);
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1035</width>
|
||||
<height>702</height>
|
||||
<width>1058</width>
|
||||
<height>725</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
@@ -63,9 +63,9 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>737</width>
|
||||
<height>948</height>
|
||||
<y>-368</y>
|
||||
<width>760</width>
|
||||
<height>1009</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_16">
|
||||
@@ -86,7 +86,7 @@
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>8</number>
|
||||
<number>3</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="page_22">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_29">
|
||||
@@ -1928,6 +1928,26 @@ 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="QLabel" name="label_229">
|
||||
<property name="text">
|
||||
<string>Only RGB images are published.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="checkbox_rgbd_colorOnly">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
@@ -4171,26 +4191,6 @@ When set to false, no new words are added to dictionary, so no more updates are
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_14" columnstretch="0,1">
|
||||
<item row="0" column="0">
|
||||
<widget class="QSpinBox" name="spinBox_ORBNFeatures">
|
||||
<property name="maximum">
|
||||
<number>10000</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>500</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_24">
|
||||
<property name="text">
|
||||
<string>The maximum number of features to retain.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_ORBScaleFactor">
|
||||
<property name="decimals">
|
||||
<number>1</number>
|
||||
@@ -4200,7 +4200,7 @@ When set to false, no new words are added to dictionary, so no more updates are
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_32">
|
||||
<property name="text">
|
||||
<string>Pyramid decimation ratio, greater than 1. scaleFactor==2 means the classical pyramid, where each next level has 4x less pixels than the previous, but such a big scale factor will degrade feature matching scores dramatically. On the other hand, too close to 1 scale factor will mean that to cover certain scale range you will need more pyramid levels and so the speed will suffer.</string>
|
||||
@@ -4210,14 +4210,14 @@ When set to false, no new words are added to dictionary, so no more updates are
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<item row="1" column="0">
|
||||
<widget class="QSpinBox" name="spinBox_ORBNLevels">
|
||||
<property name="value">
|
||||
<number>8</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="label_43">
|
||||
<property name="text">
|
||||
<string>The number of pyramid levels. The smallest level will have linear size equal to input_image_linear_size/pow(scaleFactor, nlevels).</string>
|
||||
@@ -4227,14 +4227,14 @@ When set to false, no new words are added to dictionary, so no more updates are
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<item row="2" column="0">
|
||||
<widget class="QSpinBox" name="spinBox_ORBEdgeThreshold">
|
||||
<property name="value">
|
||||
<number>31</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="label_95">
|
||||
<property name="text">
|
||||
<string>This is size of the border where the features are not detected. It should roughly match the patchSize parameter.</string>
|
||||
@@ -4244,14 +4244,14 @@ When set to false, no new words are added to dictionary, so no more updates are
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<item row="3" column="0">
|
||||
<widget class="QSpinBox" name="spinBox_ORBFirstLevel">
|
||||
<property name="maximum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<item row="3" column="1">
|
||||
<widget class="QLabel" name="label_127">
|
||||
<property name="text">
|
||||
<string>It should be 0 in the current implementation.</string>
|
||||
@@ -4261,14 +4261,14 @@ When set to false, no new words are added to dictionary, so no more updates are
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<item row="4" column="0">
|
||||
<widget class="QSpinBox" name="spinBox_ORBWTA_K">
|
||||
<property name="value">
|
||||
<number>2</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<item row="4" column="1">
|
||||
<widget class="QLabel" name="label_128">
|
||||
<property name="text">
|
||||
<string>WTA_K: The number of points that produce each element of the oriented BRIEF descriptor. The default value 2 means the BRIEF where we take a random point pair and compare their brightnesses, so we get 0/1 response. Other possible values are 3 and 4. For example, 3 means that we take 3 random points (of course, those point coordinates are random, but they are generated from the pre-defined seed, so each element of BRIEF descriptor is computed deterministically from the pixel rectangle), find point of maximum brightness and output index of the winner (0, 1 or 2). Such output will occupy 2 bits, and therefore it will need a special variant of Hamming distance, denoted as NORM_HAMMING2 (2 bits per bin). When WTA_K=4, we take 4 random points to compute each bin (that will also occupy 2 bits with possible values 0, 1, 2 or 3).</string>
|
||||
@@ -4278,10 +4278,10 @@ When set to false, no new words are added to dictionary, so no more updates are
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<item row="5" column="0">
|
||||
<widget class="QSpinBox" name="spinBox_ORBScoreType"/>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<item row="5" column="1">
|
||||
<widget class="QLabel" name="label_140">
|
||||
<property name="text">
|
||||
<string>The default HARRIS_SCORE=0 means that Harris algorithm is used to rank features (the score is written to KeyPoint::score and is used to retain best nfeatures features); FAST_SCORE=1 is alternative value of the parameter that produces slightly less stable keypoints, but it is a little faster to compute.</string>
|
||||
@@ -4291,14 +4291,14 @@ When set to false, no new words are added to dictionary, so no more updates are
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<item row="6" column="0">
|
||||
<widget class="QSpinBox" name="spinBox_ORBPatchSize">
|
||||
<property name="value">
|
||||
<number>31</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<item row="6" column="1">
|
||||
<widget class="QLabel" name="label_147">
|
||||
<property name="text">
|
||||
<string>size of the patch used by the oriented BRIEF descriptor. Of course, on smaller pyramid layers the perceived image area covered by a feature will be larger.</string>
|
||||
@@ -4308,14 +4308,14 @@ When set to false, no new words are added to dictionary, so no more updates are
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<item row="7" column="0">
|
||||
<widget class="QCheckBox" name="checkBox_ORBGpu">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<item row="7" column="1">
|
||||
<widget class="QLabel" name="label_orbGpu">
|
||||
<property name="text">
|
||||
<string>GPU-ORB: Use GPU version of ORB. This option is enabled only if OpenCV is built with CUDA and GPUs are detected.</string>
|
||||
@@ -4451,7 +4451,7 @@ When set to false, no new words are added to dictionary, so no more updates are
|
||||
<string>GFTT</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_21" columnstretch="0,1">
|
||||
<item row="1" column="0">
|
||||
<item row="0" column="0">
|
||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_GFTT_qualityLevel">
|
||||
<property name="maximum">
|
||||
<double>1.000000000000000</double>
|
||||
@@ -4464,7 +4464,7 @@ When set to false, no new words are added to dictionary, so no more updates are
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<item row="1" column="0">
|
||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_GFTT_minDistance">
|
||||
<property name="decimals">
|
||||
<number>1</number>
|
||||
@@ -4474,7 +4474,7 @@ When set to false, no new words are added to dictionary, so no more updates are
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<item row="3" column="0">
|
||||
<widget class="QCheckBox" name="checkBox_GFTT_useHarrisDetector">
|
||||
<property name="text">
|
||||
<string/>
|
||||
@@ -4484,7 +4484,7 @@ When set to false, no new words are added to dictionary, so no more updates are
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<item row="3" column="1">
|
||||
<widget class="QLabel" name="label_172">
|
||||
<property name="text">
|
||||
<string>Use Harris detector.</string>
|
||||
@@ -4494,7 +4494,7 @@ When set to false, no new words are added to dictionary, so no more updates are
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<item row="4" column="0">
|
||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_GFTT_k">
|
||||
<property name="maximum">
|
||||
<double>1.000000000000000</double>
|
||||
@@ -4507,7 +4507,7 @@ When set to false, no new words are added to dictionary, so no more updates are
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<item row="4" column="1">
|
||||
<widget class="QLabel" name="label_173">
|
||||
<property name="text">
|
||||
<string>K.</string>
|
||||
@@ -4517,34 +4517,14 @@ When set to false, no new words are added to dictionary, so no more updates are
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<item row="2" column="0">
|
||||
<widget class="QSpinBox" name="spinBox_GFTT_blockSize">
|
||||
<property name="value">
|
||||
<number>3</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QSpinBox" name="spinBox_GFTT_maxCorners">
|
||||
<property name="maximum">
|
||||
<number>100000</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_174">
|
||||
<property name="text">
|
||||
<string>Maximum corners.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="label_175">
|
||||
<property name="text">
|
||||
<string>Quality level.</string>
|
||||
@@ -4554,7 +4534,7 @@ When set to false, no new words are added to dictionary, so no more updates are
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="label_176">
|
||||
<property name="text">
|
||||
<string>Mininum distance.</string>
|
||||
@@ -4564,7 +4544,7 @@ When set to false, no new words are added to dictionary, so no more updates are
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="label_177">
|
||||
<property name="text">
|
||||
<string>Block size.</string>
|
||||
@@ -5337,7 +5317,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
|
||||
<property name="title">
|
||||
<string>Loop closure constraint</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_49">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_41">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_16">
|
||||
<property name="text">
|
||||
@@ -5442,14 +5422,14 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<item row="6" column="0">
|
||||
<widget class="QCheckBox" name="loopClosure_bowForce2D">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<item row="6" column="1">
|
||||
<widget class="QLabel" name="label_184">
|
||||
<property name="text">
|
||||
<string>Force 2D transform (3DoF: x,y and yaw).</string>
|
||||
@@ -5459,7 +5439,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<item row="7" column="0">
|
||||
<widget class="QComboBox" name="globalDetection_icpType">
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QComboBox::AdjustToContents</enum>
|
||||
@@ -5481,7 +5461,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<item row="7" column="1">
|
||||
<widget class="QLabel" name="label_57">
|
||||
<property name="text">
|
||||
<string>When enabled, the visual transform is used as a guess for ICP estimation (3D or 2D). See "ICP" panel for parameters.</string>
|
||||
@@ -5491,6 +5471,52 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QLabel" name="label_658">
|
||||
<property name="text">
|
||||
<string>Use epipolar geometry to compute the loop closure transform. "Maximum distance for visual word correspondences" is not used in this mode.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QCheckBox" name="loopClosure_bowEpipolarGeometry">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QLabel" name="label_664">
|
||||
<property name="text">
|
||||
<string>Epipolar geometry maximum variance to accept the loop closure.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QDoubleSpinBox" name="loopClosure_bowEpipolarGeometryVar">
|
||||
<property name="suffix">
|
||||
<string> m</string>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.001000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.020000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
@@ -5525,6 +5551,16 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_174">
|
||||
<property name="text">
|
||||
<string>Epipolar geometry is ignored (if set above) by this option.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_25" columnstretch="0,1">
|
||||
<item row="3" column="0">
|
||||
@@ -6303,7 +6339,17 @@ Lower the ratio -> higher the precision. 0 means disabled, matching the neare
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_27" columnstretch="0,1">
|
||||
<item row="2" column="1">
|
||||
<item row="3" column="1">
|
||||
<widget class="QLabel" name="label_160">
|
||||
<property name="text">
|
||||
<string>3-Mono is for single camera motion estimation (MonoSLAM). On initialization, the camera must be translated on the side until a first transform can be computed.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QLabel" name="label_47">
|
||||
<property name="text">
|
||||
<string>Automatically reset odometry after X consecutive images on which odometry cannot be computed (value=0 disables auto-reset). When reset, the odometry starts from the last pose computed.</string>
|
||||
@@ -6328,16 +6374,28 @@ Lower the ratio -> higher the precision. 0 means disabled, matching the neare
|
||||
<string>Optical Flow</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Mono</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<item row="5" column="0">
|
||||
<widget class="QSpinBox" name="odom_countdown">
|
||||
<property name="maximum">
|
||||
<number>999999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<item row="7" column="0">
|
||||
<widget class="QCheckBox" name="odom_fillInfoData">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QComboBox" name="odom_type">
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QComboBox::AdjustToContents</enum>
|
||||
@@ -6384,10 +6442,10 @@ Lower the ratio -> higher the precision. 0 means disabled, matching the neare
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<item row="4" column="1">
|
||||
<widget class="QLabel" name="label_44">
|
||||
<property name="text">
|
||||
<string>Feature detector. In BOW mode, the related descriptor is also used. In Optical flow mode, only the keypoint detector is used.</string>
|
||||
<string>Feature detector. In BOW/Mono modes, the related descriptor is also used. In Optical flow mode, only the keypoint detector is used.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
@@ -6397,23 +6455,21 @@ Lower the ratio -> higher the precision. 0 means disabled, matching the neare
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_103">
|
||||
<property name="text">
|
||||
<string>Odometry strategy:
|
||||
1-BOW matches features extracted from both frames using nearest neighbor with descriptors, then computes RANSAC transformation estimation with corresponding 3D features.
|
||||
2-Optical flow estimate the location of 2D features from last frame to new frame, then computes RANSAC transformation with corresponding 3D features.</string>
|
||||
<string>Odometry strategy:</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<item row="6" column="0">
|
||||
<widget class="QCheckBox" name="odom_force2D">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<item row="6" column="1">
|
||||
<widget class="QLabel" name="label_196">
|
||||
<property name="text">
|
||||
<string>Force 2D transform (3DoF: x,y and yaw).</string>
|
||||
@@ -6423,7 +6479,7 @@ Lower the ratio -> higher the precision. 0 means disabled, matching the neare
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<item row="7" column="1">
|
||||
<widget class="QLabel" name="label_221">
|
||||
<property name="text">
|
||||
<string>Fill info with data (inliers/outliers features to be shown in Odometry view).</string>
|
||||
@@ -6433,20 +6489,33 @@ Lower the ratio -> higher the precision. 0 means disabled, matching the neare
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QCheckBox" name="odom_fillInfoData">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<item row="8" column="0">
|
||||
<widget class="QPushButton" name="pushButton_testOdometry">
|
||||
<property name="text">
|
||||
<string>Test selected odometry</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="label_161">
|
||||
<property name="text">
|
||||
<string>2-Optical flow estimate the location of 2D features from last frame to new frame, then computes RANSAC transformation with corresponding 3D features.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="label_162">
|
||||
<property name="text">
|
||||
<string>1-BOW matches features extracted from both frames using nearest neighbor with descriptors, then computes RANSAC transformation estimation with corresponding 3D features.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
@@ -7116,6 +7185,158 @@ Lower the ratio -> higher the precision. 0 means disabled, matching the neare
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="page_30">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_169">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_odometryMono2">
|
||||
<property name="title">
|
||||
<string>Mono</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_168">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_661">
|
||||
<property name="text">
|
||||
<string>Parameters from BOW and OpticalFlow are also used here. PnP parameters on Odometry panel are used too.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_166" columnstretch="0,1">
|
||||
<item row="0" column="0">
|
||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_minFlow">
|
||||
<property name="suffix">
|
||||
<string> pixels</string>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>1000.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>10.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>100.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_659">
|
||||
<property name="text">
|
||||
<string>Minimum optical flow required for the initialization step.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_minTranslation">
|
||||
<property name="suffix">
|
||||
<string> m</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.020000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="label_660">
|
||||
<property name="text">
|
||||
<string>Minimum translation to add new points to local map. On initialization, translation x 5 is used as the required minimum transformation.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="label_662">
|
||||
<property name="text">
|
||||
<string>Minimum translation required for the initialization step.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_minInitTranslation">
|
||||
<property name="suffix">
|
||||
<string> m</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLabel" name="label_663">
|
||||
<property name="text">
|
||||
<string>Maximum variance to add new points to local map.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_maxVariance">
|
||||
<property name="suffix">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.001000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_88">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>774</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
<zorder>groupBox_odometryMono2</zorder>
|
||||
<zorder>verticalSpacer_88</zorder>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
||||
Reference in New Issue
Block a user