mirror of
https://github.com/introlab/rtabmap.git
synced 2026-09-02 01:20:25 +08:00
Odometry and stereo: added parameter OdomStereo/MaxSlope to filter bad stereo pair matches from cvOpticalFlow
git-svn-id: http://rtabmap.googlecode.com/svn/trunk/rtabmap@1967 f169173b-cf89-36c8-b27e-44dbe73f0c83
This commit is contained in:
@@ -33,6 +33,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <QtGui/QInputDialog>
|
||||
#include <QtGui/QGraphicsLineItem>
|
||||
#include <QtGui/QCloseEvent>
|
||||
#include <QtGui/QGraphicsOpacityEffect>
|
||||
#include <QtCore/QBuffer>
|
||||
#include <QtCore/QTextStream>
|
||||
#include <rtabmap/utilite/ULogger.h>
|
||||
@@ -47,6 +48,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "rtabmap/gui/UCv2Qt.h"
|
||||
#include "rtabmap/core/util3d.h"
|
||||
#include "rtabmap/core/Signature.h"
|
||||
#include "rtabmap/core/Features2d.h"
|
||||
#include "rtabmap/gui/DataRecorder.h"
|
||||
#include "rtabmap/core/SensorData.h"
|
||||
#include "ExportDialog.h"
|
||||
@@ -76,12 +78,14 @@ DatabaseViewer::DatabaseViewer(QWidget * parent) :
|
||||
ui_->dockWidget_graphView->setVisible(false);
|
||||
ui_->dockWidget_icp->setVisible(false);
|
||||
ui_->dockWidget_visual->setVisible(false);
|
||||
ui_->dockWidget_stereoView->setVisible(false);
|
||||
ui_->dockWidget_icp->setFloating(true);
|
||||
ui_->dockWidget_visual->setFloating(true);
|
||||
ui_->menuView->addAction(ui_->dockWidget_constraints->toggleViewAction());
|
||||
ui_->menuView->addAction(ui_->dockWidget_graphView->toggleViewAction());
|
||||
ui_->menuView->addAction(ui_->dockWidget_icp->toggleViewAction());
|
||||
ui_->menuView->addAction(ui_->dockWidget_visual->toggleViewAction());
|
||||
ui_->menuView->addAction(ui_->dockWidget_stereoView->toggleViewAction());
|
||||
connect(ui_->dockWidget_graphView->toggleViewAction(), SIGNAL(triggered()), this, SLOT(updateGraphView()));
|
||||
|
||||
connect(ui_->actionQuit, SIGNAL(triggered()), this, SLOT(close()));
|
||||
@@ -994,6 +998,12 @@ void DatabaseViewer::update(int value,
|
||||
}
|
||||
|
||||
mapId = memory_->getMapId(id);
|
||||
|
||||
//stereo
|
||||
if(!data.getDepthRaw().empty() && data.getDepthRaw().type() == CV_8UC1)
|
||||
{
|
||||
this->updateStereo(&data);
|
||||
}
|
||||
}
|
||||
|
||||
if(!imgDepth.isNull())
|
||||
@@ -1121,6 +1131,168 @@ void DatabaseViewer::update(int value,
|
||||
view->fitInView(view->sceneRect(), Qt::KeepAspectRatio);
|
||||
}
|
||||
|
||||
void DatabaseViewer::updateStereo(const Signature * data)
|
||||
{
|
||||
if(ui_->dockWidget_stereoView->isVisible() && !data->getImageRaw().empty() && !data->getDepthRaw().empty() && data->getDepthRaw().type() == CV_8UC1)
|
||||
{
|
||||
cv::Mat leftMono;
|
||||
if(data->getImageRaw().channels() == 3)
|
||||
{
|
||||
cv::cvtColor(data->getImageRaw(), leftMono, CV_BGR2GRAY);
|
||||
}
|
||||
else
|
||||
{
|
||||
leftMono = data->getImageRaw();
|
||||
}
|
||||
|
||||
UTimer timer;
|
||||
|
||||
// generate kpts
|
||||
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::kGFTTMinDistance(), "10"));
|
||||
Feature2D::Type type = Feature2D::kFeatureGfttBrief;
|
||||
Feature2D * kptDetector = Feature2D::create(type, parameters);
|
||||
kpts = kptDetector->generateKeypoints(leftMono, 0, roi);
|
||||
delete kptDetector;
|
||||
|
||||
float timeKpt = timer.ticks();
|
||||
|
||||
std::vector<cv::Point2f> leftCorners;
|
||||
cv::KeyPoint::convert(kpts, leftCorners);
|
||||
|
||||
// Find features in the new left image
|
||||
std::vector<unsigned char> status;
|
||||
std::vector<float> err;
|
||||
std::vector<cv::Point2f> rightCorners;
|
||||
cv::calcOpticalFlowPyrLK(
|
||||
leftMono,
|
||||
data->getDepthRaw(),
|
||||
leftCorners,
|
||||
rightCorners,
|
||||
status,
|
||||
err,
|
||||
cv::Size(21, 21), 4,
|
||||
cv::TermCriteria(cv::TermCriteria::COUNT+cv::TermCriteria::EPS, 20, 0.02));
|
||||
|
||||
float timeFlow = timer.ticks();
|
||||
|
||||
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
|
||||
cloud->resize(kpts.size());
|
||||
float bad_point = std::numeric_limits<float>::quiet_NaN ();
|
||||
UASSERT(status.size() == kpts.size());
|
||||
int oi = 0;
|
||||
for(unsigned int i=0; i<status.size(); ++i)
|
||||
{
|
||||
pcl::PointXYZ pt(bad_point, bad_point, bad_point);
|
||||
if(status[i])
|
||||
{
|
||||
float disparity = leftCorners[i].x - rightCorners[i].x;
|
||||
if(disparity > 0.0f)
|
||||
{
|
||||
if(fabs((leftCorners[i].y-rightCorners[i].y) / (leftCorners[i].x-rightCorners[i].x)) < 0.1)
|
||||
{
|
||||
pcl::PointXYZ tmpPt = util3d::projectDisparityTo3D(
|
||||
leftCorners[i],
|
||||
disparity,
|
||||
data->getDepthCx(), data->getDepthCy(), data->getDepthFx(), data->getDepthFy());
|
||||
|
||||
if(pcl::isFinite(tmpPt))
|
||||
{
|
||||
pt = pcl::transformPoint(tmpPt, util3d::transformToEigen3f(data->getLocalTransform()));
|
||||
if(fabs(pt.x) > 2 || fabs(pt.y) > 2 || fabs(pt.z) > 2)
|
||||
{
|
||||
status[i] = 100; //blue
|
||||
}
|
||||
cloud->at(oi++) = pt;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status[i] = 101; //yellow
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status[i] = 102; //magenta
|
||||
}
|
||||
}
|
||||
}
|
||||
cloud->resize(oi);
|
||||
|
||||
UINFO("correspondences = %d/%d (%f) (time kpt=%fs flow=%fs)",
|
||||
(int)cloud->size(), (int)leftCorners.size(), float(cloud->size())/float(leftCorners.size()), timeKpt, timeFlow);
|
||||
|
||||
ui_->stereoViewer->updateCameraPosition(Transform::getIdentity());
|
||||
ui_->stereoViewer->addOrUpdateCloud("stereo", cloud);
|
||||
ui_->stereoViewer->render();
|
||||
|
||||
std::vector<cv::KeyPoint> rightKpts;
|
||||
cv::KeyPoint::convert(rightCorners, rightKpts);
|
||||
std::vector<cv::DMatch> good_matches(kpts.size());
|
||||
for(unsigned int i=0; i<good_matches.size(); ++i)
|
||||
{
|
||||
good_matches[i].trainIdx = i;
|
||||
good_matches[i].queryIdx = i;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
//cv::Mat imageMatches;
|
||||
//cv::drawMatches( leftMono, kpts, data->getDepthRaw(), rightKpts,
|
||||
// good_matches, imageMatches, cv::Scalar::all(-1), cv::Scalar::all(-1),
|
||||
// std::vector<char>(), cv::DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );
|
||||
|
||||
//ui_->graphicsView_stereo->setImage(uCvMat2QImage(imageMatches));
|
||||
|
||||
ui_->graphicsView_stereo->scene()->clear();
|
||||
ui_->graphicsView_stereo->setSceneRect(0,0,(float)leftMono.cols, (float)leftMono.rows);
|
||||
ui_->graphicsView_stereo->setLinesShown(true);
|
||||
ui_->graphicsView_stereo->setFeaturesShown(false);
|
||||
|
||||
QGraphicsPixmapItem * item1 = ui_->graphicsView_stereo->scene()->addPixmap(QPixmap::fromImage(uCvMat2QImage(data->getImageRaw())));
|
||||
QGraphicsPixmapItem * item2 = ui_->graphicsView_stereo->scene()->addPixmap(QPixmap::fromImage(uCvMat2QImage(data->getDepthRaw())));
|
||||
|
||||
QGraphicsOpacityEffect * effect1 = new QGraphicsOpacityEffect();
|
||||
QGraphicsOpacityEffect * effect2 = new QGraphicsOpacityEffect();
|
||||
effect1->setOpacity(0.5);
|
||||
effect2->setOpacity(0.5);
|
||||
item1->setGraphicsEffect(effect1);
|
||||
item2->setGraphicsEffect(effect2);
|
||||
|
||||
// Draw lines between corresponding features...
|
||||
for(unsigned int i=0; i<kpts.size(); ++i)
|
||||
{
|
||||
QColor c = Qt::green;
|
||||
if(status[i] == 0)
|
||||
{
|
||||
c = Qt::red;
|
||||
}
|
||||
else if(status[i] == 100)
|
||||
{
|
||||
c = Qt::blue;
|
||||
}
|
||||
else if(status[i] == 101)
|
||||
{
|
||||
c = Qt::yellow;
|
||||
}
|
||||
else if(status[i] == 102)
|
||||
{
|
||||
c = Qt::magenta;
|
||||
}
|
||||
QGraphicsLineItem * item = ui_->graphicsView_stereo->scene()->addLine(
|
||||
kpts[i].pt.x,
|
||||
kpts[i].pt.y,
|
||||
rightKpts[i].pt.x,
|
||||
rightKpts[i].pt.y,
|
||||
QPen(c));
|
||||
item->setZValue(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DatabaseViewer::updateWordsMatching()
|
||||
{
|
||||
int from = ids_.at(ui_->horizontalSlider_A->value());
|
||||
|
||||
@@ -346,6 +346,10 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
|
||||
connect(_ui->toolButton_dictionaryPath, SIGNAL(clicked()), this, SLOT(changeDictionaryPath()));
|
||||
_ui->checkBox_kp_newWordsComparedTogether->setObjectName(Parameters::kKpNewWordsComparedTogether().c_str());
|
||||
|
||||
_ui->subpix_winSize->setObjectName(Parameters::kKpSubPixWinSize().c_str());
|
||||
_ui->subpix_iterations->setObjectName(Parameters::kKpSubPixIterations().c_str());
|
||||
_ui->subpix_eps->setObjectName(Parameters::kKpSubPixEps().c_str());
|
||||
|
||||
//SURF detector
|
||||
_ui->surf_doubleSpinBox_hessianThr->setObjectName(Parameters::kSURFHessianThreshold().c_str());
|
||||
_ui->surf_spinBox_octaves->setObjectName(Parameters::kSURFOctaves().c_str());
|
||||
@@ -478,18 +482,18 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
|
||||
_ui->odom_flow_maxLevel->setObjectName(Parameters::kOdomFlowMaxLevel().c_str());
|
||||
_ui->odom_flow_iterations->setObjectName(Parameters::kOdomFlowIterations().c_str());
|
||||
_ui->odom_flow_eps->setObjectName(Parameters::kOdomFlowEps().c_str());
|
||||
_ui->odom_flow_subpix_winSize->setObjectName(Parameters::kOdomFlowSubPixWinSize().c_str());
|
||||
_ui->odom_flow_subpix_iterations->setObjectName(Parameters::kOdomFlowSubPixIterations().c_str());
|
||||
_ui->odom_flow_subpix_eps->setObjectName(Parameters::kOdomFlowSubPixEps().c_str());
|
||||
_ui->odom_stereo_maxSlope->setObjectName(Parameters::kOdomStereoMaxSlope().c_str());
|
||||
_ui->odom_subpix_winSize->setObjectName(Parameters::kOdomSubPixWinSize().c_str());
|
||||
_ui->odom_subpix_iterations->setObjectName(Parameters::kOdomSubPixIterations().c_str());
|
||||
_ui->odom_subpix_eps->setObjectName(Parameters::kOdomSubPixEps().c_str());
|
||||
|
||||
//Stereo
|
||||
_ui->stereo_winSize->setObjectName(Parameters::kStereoWinSize().c_str());
|
||||
_ui->stereo_maxLevel->setObjectName(Parameters::kStereoMaxLevel().c_str());
|
||||
_ui->stereo_iterations->setObjectName(Parameters::kStereoIterations().c_str());
|
||||
_ui->stereo_eps->setObjectName(Parameters::kStereoEps().c_str());
|
||||
_ui->stereo_subpix_winSize->setObjectName(Parameters::kStereoSubPixWinSize().c_str());
|
||||
_ui->stereo_subpix_iterations->setObjectName(Parameters::kStereoSubPixIterations().c_str());
|
||||
_ui->stereo_subpix_eps->setObjectName(Parameters::kStereoSubPixEps().c_str());
|
||||
_ui->stereo_flow_winSize->setObjectName(Parameters::kStereoWinSize().c_str());
|
||||
_ui->stereo_flow_maxLevel->setObjectName(Parameters::kStereoMaxLevel().c_str());
|
||||
_ui->stereo_flow_iterations->setObjectName(Parameters::kStereoIterations().c_str());
|
||||
_ui->stereo_flow_eps->setObjectName(Parameters::kStereoEps().c_str());
|
||||
_ui->stereo_maxSlope->setObjectName(Parameters::kStereoMaxSlope().c_str());
|
||||
|
||||
|
||||
setupSignals();
|
||||
// custom signals
|
||||
@@ -813,8 +817,8 @@ void PreferencesDialog::resetSettings(QGroupBox * groupBox)
|
||||
_ui->checkBox_mls->setChecked(false);
|
||||
_ui->doubleSpinBox_mlsRadius->setValue(0.04);
|
||||
|
||||
_ui->groupBox_poseFiltering->setChecked(false);
|
||||
_ui->doubleSpinBox_cloudFilterRadius->setValue(0.1);
|
||||
_ui->groupBox_poseFiltering->setChecked(true);
|
||||
_ui->doubleSpinBox_cloudFilterRadius->setValue(0.3);
|
||||
_ui->doubleSpinBox_cloudFilterAngle->setValue(30);
|
||||
|
||||
_ui->checkBox_map_shown->setChecked(false);
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1187</width>
|
||||
<height>711</height>
|
||||
<height>851</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -1011,6 +1011,24 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QDockWidget" name="dockWidget_stereoView">
|
||||
<property name="windowTitle">
|
||||
<string>Stereo view</string>
|
||||
</property>
|
||||
<attribute name="dockWidgetArea">
|
||||
<number>4</number>
|
||||
</attribute>
|
||||
<widget class="QWidget" name="dockWidgetContents_5">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<item>
|
||||
<widget class="rtabmap::ImageView" name="graphicsView_stereo"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="rtabmap::CloudViewer" name="stereoViewer" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<action name="actionOpen_database">
|
||||
<property name="text">
|
||||
<string>Open database</string>
|
||||
@@ -1103,17 +1121,17 @@
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>rtabmap::ImageView</class>
|
||||
<extends>QGraphicsView</extends>
|
||||
<header>rtabmap/gui/ImageView.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>rtabmap::CloudViewer</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>rtabmap/gui/CloudViewer.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>rtabmap::ImageView</class>
|
||||
<extends>QGraphicsView</extends>
|
||||
<header>rtabmap/gui/ImageView.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>rtabmap::GraphViewer</class>
|
||||
<extends>QGraphicsView</extends>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user