Added a quality odometry threshold, turning the background yellow when the mapping area has too low features

git-svn-id: http://rtabmap.googlecode.com/svn/trunk/rtabmap@1334 f169173b-cf89-36c8-b27e-44dbe73f0c83
This commit is contained in:
matlabbe
2014-06-06 18:06:49 +00:00
parent 363901cfe4
commit df0f9d60d5
12 changed files with 191 additions and 55 deletions
+10 -5
View File
@@ -34,7 +34,7 @@ class RTABMAP_EXP Odometry
{ {
public: public:
virtual ~Odometry() {} virtual ~Odometry() {}
Transform process(Image & image); Transform process(Image & image, int * quality = 0);
virtual void reset(); virtual void reset();
bool isLargeEnoughTransform(const Transform & transform); bool isLargeEnoughTransform(const Transform & transform);
@@ -44,18 +44,20 @@ public:
int getMinInliers() const {return _minInliers;} int getMinInliers() const {return _minInliers;}
float getInlierDistance() const {return _inlierDistance;} float getInlierDistance() const {return _inlierDistance;}
int getIterations() const {return _iterations;} int getIterations() const {return _iterations;}
float getWordsRatio() const {return _wordsRatio;}
float getMaxDepth() const {return _maxDepth;} float getMaxDepth() const {return _maxDepth;}
float geLinearUpdate() const {return _linearUpdate;} float geLinearUpdate() const {return _linearUpdate;}
float getAngularUpdate() const {return _angularUpdate;} float getAngularUpdate() const {return _angularUpdate;}
private: private:
virtual Transform computeTransform(Image & image) = 0; virtual Transform computeTransform(Image & image, int * quality = 0) = 0;
private: private:
int _maxFeatures; int _maxFeatures;
int _minInliers; int _minInliers;
float _inlierDistance; float _inlierDistance;
int _iterations; int _iterations;
float _wordsRatio;
float _maxDepth; float _maxDepth;
float _linearUpdate; float _linearUpdate;
float _angularUpdate; float _angularUpdate;
@@ -68,6 +70,7 @@ protected:
int maxWords = Parameters::defaultOdomMaxWords(), int maxWords = Parameters::defaultOdomMaxWords(),
int minInliers = Parameters::defaultOdomMinInliers(), int minInliers = Parameters::defaultOdomMinInliers(),
int iterations = Parameters::defaultOdomIterations(), int iterations = Parameters::defaultOdomIterations(),
float wordsRatio = Parameters::defaultOdomWordsRatio(),
float maxDepth = Parameters::defaultOdomMaxDepth(), float maxDepth = Parameters::defaultOdomMaxDepth(),
float linearUpdate = Parameters::defaultOdomLinearUpdate(), float linearUpdate = Parameters::defaultOdomLinearUpdate(),
float angularUpdate = Parameters::defaultOdomAngularUpdate(), float angularUpdate = Parameters::defaultOdomAngularUpdate(),
@@ -83,6 +86,7 @@ public:
int maxWords = Parameters::defaultOdomMaxWords(), int maxWords = Parameters::defaultOdomMaxWords(),
int minInliers = Parameters::defaultOdomMinInliers(), int minInliers = Parameters::defaultOdomMinInliers(),
int iterations = Parameters::defaultOdomIterations(), int iterations = Parameters::defaultOdomIterations(),
float wordsRatio = Parameters::defaultOdomWordsRatio(),
float maxDepth = Parameters::defaultOdomMaxDepth(), float maxDepth = Parameters::defaultOdomMaxDepth(),
float linearUpdate = Parameters::defaultOdomLinearUpdate(), float linearUpdate = Parameters::defaultOdomLinearUpdate(),
float angularUpdate = Parameters::defaultOdomAngularUpdate(), float angularUpdate = Parameters::defaultOdomAngularUpdate(),
@@ -96,7 +100,7 @@ public:
virtual void reset(); virtual void reset();
private: private:
virtual Transform computeTransform(Image & image); virtual Transform computeTransform(Image & image, int * quality = 0);
private: private:
int _briefBytes; int _briefBytes;
@@ -120,6 +124,7 @@ public:
int maxWords = Parameters::defaultOdomMaxWords(), int maxWords = Parameters::defaultOdomMaxWords(),
int minInliers = Parameters::defaultOdomMinInliers(), int minInliers = Parameters::defaultOdomMinInliers(),
int iterations = Parameters::defaultOdomIterations(), int iterations = Parameters::defaultOdomIterations(),
float wordsRatio = Parameters::defaultOdomWordsRatio(),
float maxDepth = Parameters::defaultOdomMaxDepth(), float maxDepth = Parameters::defaultOdomMaxDepth(),
float linearUpdate = Parameters::defaultOdomLinearUpdate(), float linearUpdate = Parameters::defaultOdomLinearUpdate(),
float angularUpdate = Parameters::defaultOdomAngularUpdate(), float angularUpdate = Parameters::defaultOdomAngularUpdate(),
@@ -132,7 +137,7 @@ public:
virtual void reset(); virtual void reset();
private: private:
virtual Transform computeTransform(Image & image); virtual Transform computeTransform(Image & image, int * quality = 0);
private: private:
Memory * _memory; Memory * _memory;
@@ -156,7 +161,7 @@ public:
void reset(); void reset();
private: private:
virtual Transform computeTransform(Image & image); virtual Transform computeTransform(Image & image, int * quality = 0);
private: private:
int _decimation; int _decimation;
+5 -2
View File
@@ -17,16 +17,19 @@ class OdometryEvent : public UEvent
{ {
public: public:
OdometryEvent( OdometryEvent(
const Image & data) : const Image & data, int quality = 0) :
_data(data) {} _data(data),
_quality(quality) {}
virtual ~OdometryEvent() {} virtual ~OdometryEvent() {}
virtual std::string getClassName() const {return "OdometryEvent";} virtual std::string getClassName() const {return "OdometryEvent";}
bool isValid() const {return !_data.pose().isNull();} bool isValid() const {return !_data.pose().isNull();}
const Image & data() const {return _data;} const Image & data() const {return _data;}
int quality() const {return _quality;}
private: private:
Image _data; Image _data;
int _quality;
}; };
class OdometryResetEvent : public UEvent class OdometryResetEvent : public UEvent
@@ -224,6 +224,7 @@ class RTABMAP_EXP Parameters
RTABMAP_PARAM(Odom, MinInliers, int, 10, "Minimum visual word correspondences to compute geometry transform."); RTABMAP_PARAM(Odom, MinInliers, int, 10, "Minimum visual word correspondences to compute geometry transform.");
RTABMAP_PARAM(Odom, Iterations, int, 100, "Maximum iterations to compute the transform from visual words."); RTABMAP_PARAM(Odom, Iterations, int, 100, "Maximum iterations to compute the transform from visual words.");
RTABMAP_PARAM(Odom, MaxDepth, float, 5.0, "Max depth of the words (0 means no limit)."); RTABMAP_PARAM(Odom, MaxDepth, float, 5.0, "Max depth of the words (0 means no limit).");
RTABMAP_PARAM(Odom, WordsRatio, float, 0.5, "Minmum ratio of keypoints between the current image and the last image to compute odometry.");
RTABMAP_PARAM(Odom, ResetCountdown, int, 0, "Automatically reset odometry after X consecutive images on which odometry cannot be computed (value=0 disables auto-reset).") RTABMAP_PARAM(Odom, ResetCountdown, int, 0, "Automatically reset odometry after X consecutive images on which odometry cannot be computed (value=0 disables auto-reset).")
RTABMAP_PARAM(OdomBin, BriefBytes, int, 32, ""); RTABMAP_PARAM(OdomBin, BriefBytes, int, 32, "");
+36 -19
View File
@@ -36,6 +36,7 @@ Odometry::Odometry(
int maxWords, int maxWords,
int minInliers, int minInliers,
int iterations, int iterations,
float wordsRatio,
float maxDepth, float maxDepth,
float linearUpdate, float linearUpdate,
float angularUpdate, float angularUpdate,
@@ -44,6 +45,7 @@ Odometry::Odometry(
_minInliers(minInliers), _minInliers(minInliers),
_inlierDistance(inlierDistance), _inlierDistance(inlierDistance),
_iterations(iterations), _iterations(iterations),
_wordsRatio(wordsRatio),
_maxDepth(maxDepth), _maxDepth(maxDepth),
_linearUpdate(linearUpdate), _linearUpdate(linearUpdate),
_angularUpdate(angularUpdate), _angularUpdate(angularUpdate),
@@ -59,6 +61,7 @@ Odometry::Odometry(const rtabmap::ParametersMap & parameters) :
_minInliers(Parameters::defaultOdomMinInliers()), _minInliers(Parameters::defaultOdomMinInliers()),
_inlierDistance(Parameters::defaultOdomInlierDistance()), _inlierDistance(Parameters::defaultOdomInlierDistance()),
_iterations(Parameters::defaultOdomIterations()), _iterations(Parameters::defaultOdomIterations()),
_wordsRatio(Parameters::defaultOdomWordsRatio()),
_maxDepth(Parameters::defaultOdomMaxDepth()), _maxDepth(Parameters::defaultOdomMaxDepth()),
_linearUpdate(Parameters::defaultOdomLinearUpdate()), _linearUpdate(Parameters::defaultOdomLinearUpdate()),
_angularUpdate(Parameters::defaultOdomAngularUpdate()), _angularUpdate(Parameters::defaultOdomAngularUpdate()),
@@ -72,6 +75,7 @@ Odometry::Odometry(const rtabmap::ParametersMap & parameters) :
Parameters::parse(parameters, Parameters::kOdomMinInliers(), _minInliers); Parameters::parse(parameters, Parameters::kOdomMinInliers(), _minInliers);
Parameters::parse(parameters, Parameters::kOdomInlierDistance(), _inlierDistance); Parameters::parse(parameters, Parameters::kOdomInlierDistance(), _inlierDistance);
Parameters::parse(parameters, Parameters::kOdomIterations(), _iterations); Parameters::parse(parameters, Parameters::kOdomIterations(), _iterations);
Parameters::parse(parameters, Parameters::kOdomWordsRatio(), _wordsRatio);
Parameters::parse(parameters, Parameters::kOdomMaxDepth(), _maxDepth); Parameters::parse(parameters, Parameters::kOdomMaxDepth(), _maxDepth);
Parameters::parse(parameters, Parameters::kOdomMaxWords(), _maxFeatures); Parameters::parse(parameters, Parameters::kOdomMaxWords(), _maxFeatures);
} }
@@ -89,9 +93,9 @@ bool Odometry::isLargeEnoughTransform(const Transform & transform)
fabs(transform.z()) > _linearUpdate; fabs(transform.z()) > _linearUpdate;
} }
Transform Odometry::process(Image & image) Transform Odometry::process(Image & image, int * quality)
{ {
Transform t = this->computeTransform(image); Transform t = this->computeTransform(image, quality);
if(!t.isNull()) if(!t.isNull())
{ {
_resetCurrentCount = _resetCountdown; _resetCurrentCount = _resetCountdown;
@@ -117,6 +121,7 @@ OdometryBinary::OdometryBinary(
int maxWords, int maxWords,
int minInliers, int minInliers,
int iterations, int iterations,
float wordsRatio,
float maxDepth, float maxDepth,
float linearUpdate, float linearUpdate,
float angularUpdate, float angularUpdate,
@@ -125,7 +130,7 @@ OdometryBinary::OdometryBinary(
int fastThreshold, int fastThreshold,
bool fastNonmaxSuppression, bool fastNonmaxSuppression,
bool bruteForceMatching) : bool bruteForceMatching) :
Odometry(inlierDistance, maxWords, minInliers, iterations, maxDepth, linearUpdate, angularUpdate, resetCoutdown), Odometry(inlierDistance, maxWords, minInliers, iterations, wordsRatio, maxDepth, linearUpdate, angularUpdate, resetCoutdown),
_briefBytes(briefBytes), _briefBytes(briefBytes),
_fastThreshold(fastThreshold), _fastThreshold(fastThreshold),
_fastNonmaxSuppression(fastNonmaxSuppression), _fastNonmaxSuppression(fastNonmaxSuppression),
@@ -156,8 +161,8 @@ void OdometryBinary::reset()
} }
// return true if odometry is correctly computed // return not null transform if odometry is correctly computed
Transform OdometryBinary::computeTransform(Image & image) Transform OdometryBinary::computeTransform(Image & image, int * quality)
{ {
UTimer timer; UTimer timer;
cv::Mat imageMono; cv::Mat imageMono;
@@ -187,7 +192,7 @@ Transform OdometryBinary::computeTransform(Image & image)
if(_lastKeypoints.size()) if(_lastKeypoints.size())
{ {
if(newDescriptors.rows && newDescriptors.rows > (int)_lastKeypoints.size()/2) // at least 50% keypoints if(newDescriptors.rows && newDescriptors.rows > (int)(getWordsRatio() * float(_lastKeypoints.size()))) // at least 50% keypoints
{ {
cv::Mat results; cv::Mat results;
cv::Mat dists; cv::Mat dists;
@@ -308,6 +313,11 @@ Transform OdometryBinary::computeTransform(Image & image)
float x,y,z, roll,pitch,yaw; float x,y,z, roll,pitch,yaw;
pcl::getTranslationAndEulerAngles(util3d::transformToEigen3f(t), x,y,z, roll,pitch,yaw); pcl::getTranslationAndEulerAngles(util3d::transformToEigen3f(t), x,y,z, roll,pitch,yaw);
if(quality)
{
*quality = inliers;
}
// Large transforms may be erroneous computed transforms, so keep under 1 m // Large transforms may be erroneous computed transforms, so keep under 1 m
if(inliers >= this->getMinInliers()) if(inliers >= this->getMinInliers())
{ {
@@ -335,8 +345,8 @@ Transform OdometryBinary::computeTransform(Image & image)
} }
else if(newDescriptors.rows) else if(newDescriptors.rows)
{ {
UWARN("At least 50%% keypoints of the last image required. New=%d last=%d", UWARN("At least %f%% keypoints of the last image required. New=%d last=%d",
newDescriptors.rows, _lastKeypoints.size()); getWordsRatio()*100.0f, newDescriptors.rows, _lastKeypoints.size());
} }
else else
{ {
@@ -368,13 +378,14 @@ OdometryBOW::OdometryBOW(
int maxWords, int maxWords,
int minInliers, int minInliers,
int iterations, int iterations,
float wordsRatio,
float maxDepth, float maxDepth,
float linearUpdate, float linearUpdate,
float angularUpdate, float angularUpdate,
int resetCoutdown, int resetCoutdown,
float surfHessianThreshold, float surfHessianThreshold,
float nndr) : // nearest neighbor distance ratio float nndr) : // nearest neighbor distance ratio
Odometry(inlierDistance, maxWords, minInliers, iterations, maxDepth, linearUpdate, angularUpdate, resetCoutdown), Odometry(inlierDistance, maxWords, minInliers, iterations, wordsRatio, maxDepth, linearUpdate, angularUpdate, resetCoutdown),
_memory(new Memory()) _memory(new Memory())
{ {
ParametersMap customParameters; ParametersMap customParameters;
@@ -421,8 +432,8 @@ void OdometryBOW::reset()
} }
// return true if odometry is correctly computed // return not null transform if odometry is correctly computed
Transform OdometryBOW::computeTransform(Image & image) Transform OdometryBOW::computeTransform(Image & image, int * quality)
{ {
UTimer timer; UTimer timer;
Transform output; Transform output;
@@ -444,10 +455,10 @@ Transform OdometryBOW::computeTransform(Image & image)
if(previousSignature && newSignature) if(previousSignature && newSignature)
{ {
Transform transform; Transform transform;
if(newSignature->getWords3().size() < previousSignature->getWords3().size()/2) if(newSignature->getWords3().size() < (unsigned int)(getWordsRatio() * float(previousSignature->getWords3().size())))
{ {
UWARN("At least 50%% keypoints of the last image required. New=%d last=%d", UWARN("At least %f%% keypoints of the last image required. New=%d last=%d",
newSignature->getWords3().size(), previousSignature->getWords3().size()); getWordsRatio()*100.0f, newSignature->getWords3().size(), previousSignature->getWords3().size());
} }
else if(!previousSignature->getWords3().empty() && !newSignature->getWords3().empty()) else if(!previousSignature->getWords3().empty() && !newSignature->getWords3().empty())
{ {
@@ -472,6 +483,11 @@ Transform OdometryBOW::computeTransform(Image & image)
this->getIterations(), this->getIterations(),
&inliers); &inliers);
if(quality)
{
*quality = inliers;
}
if(inliers < this->getMinInliers()) if(inliers < this->getMinInliers())
{ {
transform.setNull(); transform.setNull();
@@ -527,7 +543,7 @@ OdometryICP::OdometryICP(
float linearUpdate, float linearUpdate,
float angularUpdate, float angularUpdate,
int resetCoutdown) : int resetCoutdown) :
Odometry(0, 0, 0, 0, maxDepth, linearUpdate, angularUpdate, resetCoutdown), Odometry(0, 0, 0, 0, 0, maxDepth, linearUpdate, angularUpdate, resetCoutdown),
_decimation(decimation), _decimation(decimation),
_voxelSize(voxelSize), _voxelSize(voxelSize),
_samples(samples), _samples(samples),
@@ -563,8 +579,8 @@ void OdometryICP::reset()
_previousCloud.reset(new pcl::PointCloud<pcl::PointNormal>); _previousCloud.reset(new pcl::PointCloud<pcl::PointNormal>);
} }
// return not null if odometry is correctly computed // return not null transform if odometry is correctly computed
Transform OdometryICP::computeTransform(Image & image) Transform OdometryICP::computeTransform(Image & image, int * quality)
{ {
UTimer timer; UTimer timer;
Transform output; Transform output;
@@ -698,9 +714,10 @@ void OdometryThread::mainLoop()
getImage(image); getImage(image);
if(!image.empty()) if(!image.empty())
{ {
Transform pose = _odometry->process(image); int quality = 0;
Transform pose = _odometry->process(image, &quality);
image.setPose(pose); // a null pose notify that odometry could not be computed image.setPose(pose); // a null pose notify that odometry could not be computed
this->post(new OdometryEvent(image)); this->post(new OdometryEvent(image, quality));
} }
} }
+2 -2
View File
@@ -126,7 +126,7 @@ private slots:
void selectScreenCaptureFormat(bool checked); void selectScreenCaptureFormat(bool checked);
void takeScreenshot(); void takeScreenshot();
void updateElapsedTime(); void updateElapsedTime();
void processOdometry(const rtabmap::Image & data); void processOdometry(const rtabmap::Image & data, int quality);
void applyAllPrefSettings(); void applyAllPrefSettings();
void applyPrefSettings(PreferencesDialog::PANEL_FLAGS flags); void applyPrefSettings(PreferencesDialog::PANEL_FLAGS flags);
void applyPrefSettings(const rtabmap::ParametersMap & parameters); void applyPrefSettings(const rtabmap::ParametersMap & parameters);
@@ -156,7 +156,7 @@ private slots:
signals: signals:
void statsReceived(const rtabmap::Statistics &); void statsReceived(const rtabmap::Statistics &);
void odometryReceived(const rtabmap::Image &); void odometryReceived(const rtabmap::Image &, int);
void thresholdsChanged(int, int); void thresholdsChanged(int, int);
void stateChanged(MainWindow::State); void stateChanged(MainWindow::State);
void rtabmapEventInitReceived(int status, const QString & info); void rtabmapEventInitReceived(int status, const QString & info);
+4 -2
View File
@@ -23,7 +23,7 @@ class RTABMAPGUI_EXP OdometryViewer : public CloudViewer, public UEventsHandler
Q_OBJECT Q_OBJECT
public: public:
OdometryViewer(int maxClouds = 10, int decimation = 2, float voxelSize = 0.0f, QWidget * parent = 0); OdometryViewer(int maxClouds = 10, int decimation = 2, float voxelSize = 0.0f, int qualityWarningThr=0, QWidget * parent = 0);
virtual ~OdometryViewer() {} virtual ~OdometryViewer() {}
protected: protected:
@@ -35,11 +35,13 @@ private slots:
private: private:
UMutex dataMutex_; UMutex dataMutex_;
std::list<rtabmap::Image> buffer_; std::list<rtabmap::Image> data_;
int dataQuality_;
UTimer timer_; UTimer timer_;
int maxClouds_; int maxClouds_;
float voxelSize_; float voxelSize_;
int decimation_; int decimation_;
int qualityWarningThr_;
int id_; int id_;
std::map<int, pcl::PointCloud<pcl::PointXYZRGB>::Ptr > clouds_; std::map<int, pcl::PointCloud<pcl::PointXYZRGB>::Ptr > clouds_;
QAction * _aSetVoxelSize; QAction * _aSetVoxelSize;
@@ -113,6 +113,7 @@ public:
bool imageHighestHypShown() const; bool imageHighestHypShown() const;
bool beepOnPause() const; bool beepOnPause() const;
int getKeypointsOpacity() const; int getKeypointsOpacity() const;
int getOdomQualityWarnThr() const;
bool isCloudMeshing(int index) const; // 0=map bool isCloudMeshing(int index) const; // 0=map
bool isCloudsShown(int index) const; // 0=map, 1=odom, 2=save bool isCloudsShown(int index) const; // 0=map, 1=odom, 2=save
+11 -3
View File
@@ -328,7 +328,7 @@ MainWindow::MainWindow(PreferencesDialog * prefDialog, QWidget * parent) :
connect(this, SIGNAL(statsReceived(rtabmap::Statistics)), this, SLOT(processStats(rtabmap::Statistics))); connect(this, SIGNAL(statsReceived(rtabmap::Statistics)), this, SLOT(processStats(rtabmap::Statistics)));
qRegisterMetaType<rtabmap::Image>("rtabmap::Image"); qRegisterMetaType<rtabmap::Image>("rtabmap::Image");
connect(this, SIGNAL(odometryReceived(rtabmap::Image)), this, SLOT(processOdometry(rtabmap::Image))); connect(this, SIGNAL(odometryReceived(rtabmap::Image, int)), this, SLOT(processOdometry(rtabmap::Image, int)));
connect(this, SIGNAL(noMoreImagesReceived()), this, SLOT(stopDetection())); connect(this, SIGNAL(noMoreImagesReceived()), this, SLOT(stopDetection()));
@@ -527,7 +527,7 @@ void MainWindow::handleEvent(UEvent* anEvent)
!_processingStatistics) !_processingStatistics)
{ {
_lastOdometryProcessed = false; // if we receive too many odometry events! _lastOdometryProcessed = false; // if we receive too many odometry events!
emit odometryReceived(odomEvent->data()); emit odometryReceived(odomEvent->data(), odomEvent->quality());
} }
} }
else if(anEvent->getClassName().compare("ULogEvent") == 0) else if(anEvent->getClassName().compare("ULogEvent") == 0)
@@ -550,7 +550,7 @@ void MainWindow::handleEvent(UEvent* anEvent)
} }
} }
void MainWindow::processOdometry(const rtabmap::Image & data) void MainWindow::processOdometry(const rtabmap::Image & data, int quality)
{ {
Transform pose = data.pose(); Transform pose = data.pose();
if(pose.isNull()) if(pose.isNull())
@@ -560,11 +560,19 @@ void MainWindow::processOdometry(const rtabmap::Image & data)
pose = _lastOdomPose; pose = _lastOdomPose;
} }
else if(quality &&
_preferencesDialog->getOdomQualityWarnThr() &&
quality < _preferencesDialog->getOdomQualityWarnThr())
{
UDEBUG("odom warn, quality=%d thr=%d", quality, _preferencesDialog->getOdomQualityWarnThr());
_ui->widget_cloudViewer->setBackgroundColor(Qt::darkYellow);
}
else else
{ {
UDEBUG("odom ok"); UDEBUG("odom ok");
_ui->widget_cloudViewer->setBackgroundColor(Qt::black); _ui->widget_cloudViewer->setBackgroundColor(Qt::black);
} }
_ui->statsToolBox->updateStat("/Odom inliers/", (float)data.id(), (float)quality);
if(!pose.isNull()) if(!pose.isNull())
{ {
_lastOdomPose = pose; _lastOdomPose = pose;
+20 -8
View File
@@ -21,11 +21,12 @@
namespace rtabmap { namespace rtabmap {
OdometryViewer::OdometryViewer(int maxClouds, int decimation, float voxelSize, QWidget * parent) : OdometryViewer::OdometryViewer(int maxClouds, int decimation, float voxelSize, int qualityWarningThr, QWidget * parent) :
CloudViewer(parent), CloudViewer(parent),
maxClouds_(maxClouds), maxClouds_(maxClouds),
voxelSize_(voxelSize), voxelSize_(voxelSize),
decimation_(decimation), decimation_(decimation),
qualityWarningThr_(qualityWarningThr),
id_(0), id_(0),
_aSetVoxelSize(0), _aSetVoxelSize(0),
_aSetDecimation(0), _aSetDecimation(0),
@@ -48,11 +49,14 @@ OdometryViewer::OdometryViewer(int maxClouds, int decimation, float voxelSize, Q
void OdometryViewer::processData() void OdometryViewer::processData()
{ {
rtabmap::Image data; rtabmap::Image data;
int quality;
dataMutex_.lock(); dataMutex_.lock();
if(buffer_.size()) if(data_.size())
{ {
data = buffer_.back(); data = data_.back();
buffer_.clear(); data_.clear();
quality = dataQuality_;
dataQuality_ = 0;
} }
dataMutex_.unlock(); dataMutex_.unlock();
@@ -96,7 +100,14 @@ void OdometryViewer::processData()
this->updateCameraPosition(data.pose()); this->updateCameraPosition(data.pose());
this->setBackgroundColor(Qt::black); if(qualityWarningThr_ && quality && quality < qualityWarningThr_)
{
this->setBackgroundColor(Qt::darkYellow);
}
else
{
this->setBackgroundColor(Qt::black);
}
this->render(); this->render();
} }
@@ -114,15 +125,16 @@ void OdometryViewer::handleEvent(UEvent * event)
{ {
bool empty = false; bool empty = false;
dataMutex_.lock(); dataMutex_.lock();
if(buffer_.empty()) if(data_.empty())
{ {
buffer_.push_back(odomEvent->data()); data_.push_back(odomEvent->data());
empty= true; empty= true;
} }
else else
{ {
buffer_.back() = odomEvent->data(); data_.back() = odomEvent->data();
} }
dataQuality_ = odomEvent->quality();
dataMutex_.unlock(); dataMutex_.unlock();
if(empty) if(empty)
{ {
+8 -2
View File
@@ -394,6 +394,7 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
_ui->odom_iterations->setObjectName(Parameters::kOdomIterations().c_str()); _ui->odom_iterations->setObjectName(Parameters::kOdomIterations().c_str());
_ui->odom_maxDepth->setObjectName(Parameters::kOdomMaxDepth().c_str()); _ui->odom_maxDepth->setObjectName(Parameters::kOdomMaxDepth().c_str());
_ui->odom_minInliers->setObjectName(Parameters::kOdomMinInliers().c_str()); _ui->odom_minInliers->setObjectName(Parameters::kOdomMinInliers().c_str());
_ui->odom_ratio->setObjectName(Parameters::kOdomWordsRatio().c_str());
_ui->stackedWidget_odom->setCurrentIndex(_ui->odom_type->currentIndex()); _ui->stackedWidget_odom->setCurrentIndex(_ui->odom_type->currentIndex());
connect(_ui->odom_type, SIGNAL(currentIndexChanged(int)), _ui->stackedWidget_odom, SLOT(setCurrentIndex(int))); connect(_ui->odom_type, SIGNAL(currentIndexChanged(int)), _ui->stackedWidget_odom, SLOT(setCurrentIndex(int)));
@@ -705,6 +706,7 @@ void PreferencesDialog::resetSettings(QGroupBox * groupBox)
_ui->checkBox_imageRejectedShown->setChecked(true); _ui->checkBox_imageRejectedShown->setChecked(true);
_ui->checkBox_imageHighestHypShown->setChecked(false); _ui->checkBox_imageHighestHypShown->setChecked(false);
_ui->horizontalSlider_keypointsOpacity->setSliderPosition(20); _ui->horizontalSlider_keypointsOpacity->setSliderPosition(20);
_ui->spinBox_odomQualityWarnThr->setValue(50);
} }
else if(groupBox->objectName() == _ui->groupBox_cloudRendering1->objectName()) else if(groupBox->objectName() == _ui->groupBox_cloudRendering1->objectName())
{ {
@@ -718,7 +720,7 @@ void PreferencesDialog::resetSettings(QGroupBox * groupBox)
if(i<2) if(i<2)
{ {
_3dRenderingOpacity[i]->setValue(i==0?0.6:1.0); _3dRenderingOpacity[i]->setValue(1.0);
_3dRenderingPtSize[i]->setValue(i==0?1:2); _3dRenderingPtSize[i]->setValue(i==0?1:2);
_3dRenderingOpacityScan[i]->setValue(1.0); _3dRenderingOpacityScan[i]->setValue(1.0);
_3dRenderingPtSizeScan[i]->setValue(1); _3dRenderingPtSizeScan[i]->setValue(1);
@@ -2330,6 +2332,10 @@ int PreferencesDialog::getKeypointsOpacity() const
{ {
return _ui->horizontalSlider_keypointsOpacity->value(); return _ui->horizontalSlider_keypointsOpacity->value();
} }
int PreferencesDialog::getOdomQualityWarnThr() const
{
return _ui->spinBox_odomQualityWarnThr->value();
}
bool PreferencesDialog::isCloudsShown(int index) const bool PreferencesDialog::isCloudsShown(int index) const
{ {
@@ -2767,7 +2773,7 @@ void PreferencesDialog::testOdometry(OdomType type)
window->setMinimumHeight(600); window->setMinimumHeight(600);
connect( window, SIGNAL(destroyed(QObject*)), this, SLOT(cleanOdometryTest()) ); connect( window, SIGNAL(destroyed(QObject*)), this, SLOT(cleanOdometryTest()) );
OdometryViewer * odomViewer = new OdometryViewer(10, 2, 0.0, window); OdometryViewer * odomViewer = new OdometryViewer(10, 2, 0.0, this->getOdomQualityWarnThr(), window);
QVBoxLayout *layout = new QVBoxLayout(); QVBoxLayout *layout = new QVBoxLayout();
layout->addWidget(odomViewer); layout->addWidget(odomViewer);
+71 -12
View File
@@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>1027</width> <width>1027</width>
<height>494</height> <height>659</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">
@@ -64,8 +64,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>724</width> <width>729</width>
<height>1076</height> <height>823</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_16"> <layout class="QVBoxLayout" name="verticalLayout_16">
@@ -86,7 +86,7 @@
<enum>QFrame::Raised</enum> <enum>QFrame::Raised</enum>
</property> </property>
<property name="currentIndex"> <property name="currentIndex">
<number>0</number> <number>15</number>
</property> </property>
<widget class="QWidget" name="page_22"> <widget class="QWidget" name="page_22">
<layout class="QVBoxLayout" name="verticalLayout_29"> <layout class="QVBoxLayout" name="verticalLayout_29">
@@ -143,12 +143,9 @@
<item> <item>
<widget class="QGroupBox" name="groupBox_5"> <widget class="QGroupBox" name="groupBox_5">
<property name="title"> <property name="title">
<string>Image view</string> <string>Loop closure detection view</string>
</property> </property>
<layout class="QFormLayout" name="formLayout_12"> <layout class="QFormLayout" name="formLayout_12">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<item row="1" column="0"> <item row="1" column="0">
<widget class="QCheckBox" name="checkBox_imageFlipped"> <widget class="QCheckBox" name="checkBox_imageFlipped">
<property name="text"> <property name="text">
@@ -235,7 +232,7 @@
<item row="0" column="1"> <item row="0" column="1">
<widget class="QLabel" name="label_70"> <widget class="QLabel" name="label_70">
<property name="text"> <property name="text">
<string>Vertical layout used for the loop closure detection window.</string> <string>Vertical layout.</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>false</bool> <bool>false</bool>
@@ -255,6 +252,36 @@
</layout> </layout>
</widget> </widget>
</item> </item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>3D Map view</string>
</property>
<layout class="QFormLayout" name="formLayout_23">
<item row="0" column="0">
<widget class="QSpinBox" name="spinBox_odomQualityWarnThr">
<property name="maximum">
<number>9999</number>
</property>
<property name="value">
<number>50</number>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_86">
<property name="text">
<string>Odometry warning theshold:
Show a yellow background when the number of odometry inliers goes under this threshold. If 0, it is ignored. You can see the current odometry inliers count under Statistics view -&gt; General -&gt; Odom inliers.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item> <item>
<widget class="QGroupBox" name="groupBox_2"> <widget class="QGroupBox" name="groupBox_2">
<property name="title"> <property name="title">
@@ -598,7 +625,7 @@ High-res view</string>
<double>0.100000000000000</double> <double>0.100000000000000</double>
</property> </property>
<property name="value"> <property name="value">
<double>0.600000000000000</double> <double>1.000000000000000</double>
</property> </property>
</widget> </widget>
</item> </item>
@@ -4963,7 +4990,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property> </property>
</widget> </widget>
</item> </item>
<item row="9" column="1"> <item row="10" column="1">
<widget class="QLabel" name="label_104"> <widget class="QLabel" name="label_104">
<property name="text"> <property name="text">
<string>Max feature depth. For ICP, it is the max cloud depth.</string> <string>Max feature depth. For ICP, it is the max cloud depth.</string>
@@ -4973,7 +5000,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property> </property>
</widget> </widget>
</item> </item>
<item row="9" column="0"> <item row="10" column="0">
<widget class="QDoubleSpinBox" name="odom_maxDepth"> <widget class="QDoubleSpinBox" name="odom_maxDepth">
<property name="suffix"> <property name="suffix">
<string> m</string> <string> m</string>
@@ -5009,6 +5036,38 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property> </property>
</widget> </widget>
</item> </item>
<item row="9" column="1">
<widget class="QLabel" name="label_90">
<property name="text">
<string>Minmum ratio of keypoints between the current image and the last image to compute odometry.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QDoubleSpinBox" name="odom_ratio">
<property name="suffix">
<string/>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
<property name="value">
<double>0.500000000000000</double>
</property>
</widget>
</item>
</layout> </layout>
</item> </item>
<item> <item>
+22
View File
@@ -27,6 +27,7 @@ void showUsage()
" -min # Minimum inliers to accept the transform (default 20)\n" " -min # Minimum inliers to accept the transform (default 20)\n"
" -depth #.# Maximum features depth (default 5.0 m)\n" " -depth #.# Maximum features depth (default 5.0 m)\n"
" -i # RANSAC/ICP iterations (default 100)\n" " -i # RANSAC/ICP iterations (default 100)\n"
" -r #.# Words ratio (default 0.5)\n"
" -lu # Linear update (default 0.0 m)\n" " -lu # Linear update (default 0.0 m)\n"
" -au # Angular update (default 0.0 radian)\n" " -au # Angular update (default 0.0 radian)\n"
" -reset # Reset countdown (default 0 = disabled)\n" " -reset # Reset countdown (default 0 = disabled)\n"
@@ -63,6 +64,7 @@ int main (int argc, char * argv[])
float distance = 0.005; float distance = 0.005;
int maxWords = 0; int maxWords = 0;
int minInliers = 20; int minInliers = 20;
float wordsRatio = 0.5;
float maxDepth = 5.0f; float maxDepth = 5.0f;
int iterations = 100; int iterations = 100;
float linearUpdate = 0.0f; float linearUpdate = 0.0f;
@@ -252,6 +254,23 @@ int main (int argc, char * argv[])
} }
continue; continue;
} }
if(strcmp(argv[i], "-r") == 0)
{
++i;
if(i < argc)
{
wordsRatio = std::atof(argv[i]);
if(wordsRatio < 0.0f || wordsRatio > 1.0f)
{
showUsage();
}
}
else
{
showUsage();
}
continue;
}
if(strcmp(argv[i], "-lu") == 0) if(strcmp(argv[i], "-lu") == 0)
{ {
++i; ++i;
@@ -446,6 +465,7 @@ int main (int argc, char * argv[])
UINFO("Max features = %d", maxWords); UINFO("Max features = %d", maxWords);
UINFO("Min inliers = %d", minInliers); UINFO("Min inliers = %d", minInliers);
UINFO("RANSAC/ICP iterations = %d", iterations); UINFO("RANSAC/ICP iterations = %d", iterations);
UINFO("Words ratio = %f", wordsRatio);
UINFO("Max depth = %f", maxDepth); UINFO("Max depth = %f", maxDepth);
UINFO("Linear update = %f", linearUpdate); UINFO("Linear update = %f", linearUpdate);
UINFO("Angular update = %f", angularUpdate); UINFO("Angular update = %f", angularUpdate);
@@ -470,6 +490,7 @@ int main (int argc, char * argv[])
maxWords, maxWords,
minInliers, minInliers,
iterations, iterations,
wordsRatio,
maxDepth, maxDepth,
linearUpdate, linearUpdate,
angularUpdate, angularUpdate,
@@ -482,6 +503,7 @@ int main (int argc, char * argv[])
maxWords, maxWords,
minInliers, minInliers,
iterations, iterations,
wordsRatio,
maxDepth, maxDepth,
linearUpdate, linearUpdate,
angularUpdate, angularUpdate,