2013-12-11 00:12:44 +00:00
|
|
|
/*
|
2014-08-11 17:00:55 +00:00
|
|
|
Copyright (c) 2010-2014, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
|
|
|
|
|
All rights reserved.
|
|
|
|
|
|
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
|
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
|
* Redistributions of source code must retain the above copyright
|
|
|
|
|
notice, this list of conditions and the following disclaimer.
|
|
|
|
|
* Redistributions in binary form must reproduce the above copyright
|
|
|
|
|
notice, this list of conditions and the following disclaimer in the
|
|
|
|
|
documentation and/or other materials provided with the distribution.
|
|
|
|
|
* Neither the name of the Universite de Sherbrooke nor the
|
|
|
|
|
names of its contributors may be used to endorse or promote products
|
|
|
|
|
derived from this software without specific prior written permission.
|
|
|
|
|
|
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
|
|
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
|
|
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
|
|
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
|
|
|
|
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
|
|
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
|
|
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
|
|
|
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
|
|
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
*/
|
2013-12-11 00:12:44 +00:00
|
|
|
|
|
|
|
|
#include "rtabmap/gui/OdometryViewer.h"
|
|
|
|
|
|
|
|
|
|
#include "rtabmap/core/util3d.h"
|
|
|
|
|
#include "rtabmap/core/OdometryEvent.h"
|
|
|
|
|
#include "rtabmap/utilite/ULogger.h"
|
|
|
|
|
#include "rtabmap/utilite/UConversion.h"
|
|
|
|
|
#include <pcl/common/transforms.h>
|
|
|
|
|
#include <pcl/io/pcd_io.h>
|
|
|
|
|
#include <QtGui/QInputDialog>
|
|
|
|
|
#include <QtGui/QAction>
|
|
|
|
|
#include <QtGui/QMenu>
|
|
|
|
|
#include <QtGui/QKeyEvent>
|
|
|
|
|
|
|
|
|
|
namespace rtabmap {
|
|
|
|
|
|
|
|
|
|
|
2014-06-06 18:06:49 +00:00
|
|
|
OdometryViewer::OdometryViewer(int maxClouds, int decimation, float voxelSize, int qualityWarningThr, QWidget * parent) :
|
2013-12-11 00:12:44 +00:00
|
|
|
CloudViewer(parent),
|
2014-07-24 17:27:43 +00:00
|
|
|
dataQuality_(-1),
|
2014-06-22 03:33:56 +00:00
|
|
|
lastOdomPose_(Transform::getIdentity()),
|
2013-12-11 00:12:44 +00:00
|
|
|
maxClouds_(maxClouds),
|
|
|
|
|
voxelSize_(voxelSize),
|
|
|
|
|
decimation_(decimation),
|
2014-06-06 18:06:49 +00:00
|
|
|
qualityWarningThr_(qualityWarningThr),
|
2013-12-11 00:12:44 +00:00
|
|
|
id_(0),
|
|
|
|
|
_aSetVoxelSize(0),
|
|
|
|
|
_aSetDecimation(0),
|
|
|
|
|
_aSetCloudHistorySize(0),
|
|
|
|
|
_aPause(0)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
//add actions to CloudViewer menu
|
|
|
|
|
_aSetVoxelSize = new QAction("Set voxel size...", this);
|
|
|
|
|
_aSetDecimation = new QAction("Set depth image decimation...", this);
|
|
|
|
|
_aSetCloudHistorySize = new QAction("Set cloud history size...", this);
|
|
|
|
|
_aPause = new QAction("Pause", this);
|
|
|
|
|
_aPause->setCheckable(true);
|
|
|
|
|
menu()->addAction(_aSetVoxelSize);
|
|
|
|
|
menu()->addAction(_aSetDecimation);
|
|
|
|
|
menu()->addAction(_aSetCloudHistorySize);
|
|
|
|
|
menu()->addAction(_aPause);
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-02 19:33:51 +00:00
|
|
|
void OdometryViewer::clear()
|
|
|
|
|
{
|
|
|
|
|
dataMutex_.lock();
|
|
|
|
|
data_.clear();
|
|
|
|
|
dataMutex_.unlock();
|
|
|
|
|
clouds_.clear();
|
|
|
|
|
CloudViewer::clear();
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-11 00:12:44 +00:00
|
|
|
void OdometryViewer::processData()
|
|
|
|
|
{
|
2014-08-18 23:14:04 +00:00
|
|
|
rtabmap::SensorData data;
|
2014-07-24 17:27:43 +00:00
|
|
|
int quality = -1;
|
2013-12-11 00:12:44 +00:00
|
|
|
dataMutex_.lock();
|
2014-06-06 18:06:49 +00:00
|
|
|
if(data_.size())
|
2013-12-11 00:12:44 +00:00
|
|
|
{
|
2014-06-06 18:06:49 +00:00
|
|
|
data = data_.back();
|
|
|
|
|
data_.clear();
|
|
|
|
|
quality = dataQuality_;
|
2014-07-24 17:27:43 +00:00
|
|
|
dataQuality_ = -1;
|
2013-12-11 00:12:44 +00:00
|
|
|
}
|
|
|
|
|
dataMutex_.unlock();
|
|
|
|
|
|
2014-10-13 19:10:22 +00:00
|
|
|
if(!data.image().empty() && !data.depth().empty() && data.fx()>0.0f && data.fy()>0.0f && this->isVisible())
|
2013-12-11 00:12:44 +00:00
|
|
|
{
|
2014-06-22 03:33:56 +00:00
|
|
|
UDEBUG("New pose = %s, quality=%d", data.pose().prettyPrint().c_str(), quality);
|
2013-12-11 00:12:44 +00:00
|
|
|
|
|
|
|
|
// visualization: buffering the clouds
|
|
|
|
|
// Create the new cloud
|
|
|
|
|
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud;
|
2014-10-16 00:14:23 +00:00
|
|
|
if(data.depth().type() == CV_8UC1)
|
|
|
|
|
{
|
|
|
|
|
cloud = util3d::cloudFromStereoImages(
|
|
|
|
|
data.image(),
|
|
|
|
|
data.depth(),
|
|
|
|
|
data.cx(), data.cy(),
|
|
|
|
|
data.fx(), data.fy(),
|
|
|
|
|
decimation_);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
cloud = util3d::cloudFromDepthRGB(
|
|
|
|
|
data.image(),
|
|
|
|
|
data.depth(),
|
|
|
|
|
data.cx(), data.cy(),
|
|
|
|
|
data.fx(), data.fy(),
|
|
|
|
|
decimation_);
|
|
|
|
|
}
|
2013-12-11 00:12:44 +00:00
|
|
|
|
|
|
|
|
if(voxelSize_ > 0.0f)
|
|
|
|
|
{
|
2014-10-24 16:58:32 +00:00
|
|
|
cloud = util3d::voxelize<pcl::PointXYZRGB>(cloud, voxelSize_);
|
2013-12-11 00:12:44 +00:00
|
|
|
}
|
|
|
|
|
|
2014-10-24 16:58:32 +00:00
|
|
|
cloud = util3d::transformPointCloud<pcl::PointXYZRGB>(cloud, data.localTransform());
|
2013-12-11 00:12:44 +00:00
|
|
|
|
2014-06-22 03:33:56 +00:00
|
|
|
if(!data.pose().isNull())
|
2013-12-11 00:12:44 +00:00
|
|
|
{
|
2014-06-22 03:33:56 +00:00
|
|
|
lastOdomPose_ = data.pose();
|
|
|
|
|
if(this->getAddedClouds().contains("cloudtmp"))
|
|
|
|
|
{
|
|
|
|
|
this->removeCloud("cloudtmp");
|
|
|
|
|
}
|
2013-12-11 00:12:44 +00:00
|
|
|
|
2014-06-22 03:33:56 +00:00
|
|
|
data.id()?id_=data.id():++id_;
|
2013-12-11 00:12:44 +00:00
|
|
|
|
2014-06-22 03:33:56 +00:00
|
|
|
clouds_.insert(std::make_pair(id_, cloud));
|
2013-12-11 00:12:44 +00:00
|
|
|
|
2014-06-22 03:33:56 +00:00
|
|
|
while(maxClouds_>0 && (int)clouds_.size() > maxClouds_)
|
|
|
|
|
{
|
|
|
|
|
this->removeCloud(uFormat("cloud%d", clouds_.begin()->first));
|
|
|
|
|
clouds_.erase(clouds_.begin());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(clouds_.size())
|
|
|
|
|
{
|
|
|
|
|
this->addCloud(uFormat("cloud%d", clouds_.rbegin()->first), clouds_.rbegin()->second, data.pose());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this->updateCameraPosition(data.pose());
|
|
|
|
|
|
2014-07-24 17:27:43 +00:00
|
|
|
if(qualityWarningThr_ && quality>=0 && quality < qualityWarningThr_)
|
2014-06-22 03:33:56 +00:00
|
|
|
{
|
|
|
|
|
this->setBackgroundColor(Qt::darkYellow);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
this->setBackgroundColor(Qt::black);
|
|
|
|
|
}
|
2014-06-06 18:06:49 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2014-06-22 03:33:56 +00:00
|
|
|
this->addOrUpdateCloud("cloudtmp", cloud, lastOdomPose_);
|
|
|
|
|
this->setBackgroundColor(Qt::darkRed);
|
2014-06-06 18:06:49 +00:00
|
|
|
}
|
2013-12-11 00:12:44 +00:00
|
|
|
|
|
|
|
|
this->render();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OdometryViewer::handleEvent(UEvent * event)
|
|
|
|
|
{
|
|
|
|
|
if(!_aPause->isChecked())
|
|
|
|
|
{
|
|
|
|
|
if(event->getClassName().compare("OdometryEvent") == 0)
|
|
|
|
|
{
|
|
|
|
|
rtabmap::OdometryEvent * odomEvent = (rtabmap::OdometryEvent*)event;
|
|
|
|
|
|
2014-06-22 03:33:56 +00:00
|
|
|
bool empty = false;
|
|
|
|
|
dataMutex_.lock();
|
|
|
|
|
if(data_.empty())
|
2013-12-11 00:12:44 +00:00
|
|
|
{
|
2014-06-22 03:33:56 +00:00
|
|
|
data_.push_back(odomEvent->data());
|
|
|
|
|
empty= true;
|
2013-12-11 00:12:44 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2014-06-22 03:33:56 +00:00
|
|
|
data_.back() = odomEvent->data();
|
|
|
|
|
}
|
2014-12-14 16:42:10 -05:00
|
|
|
dataQuality_ = odomEvent->info().inliers;
|
2014-06-22 03:33:56 +00:00
|
|
|
dataMutex_.unlock();
|
|
|
|
|
if(empty)
|
|
|
|
|
{
|
|
|
|
|
QMetaObject::invokeMethod(this, "processData");
|
2013-12-11 00:12:44 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OdometryViewer::handleAction(QAction * a)
|
|
|
|
|
{
|
|
|
|
|
CloudViewer::handleAction(a);
|
|
|
|
|
if(a == _aSetVoxelSize)
|
|
|
|
|
{
|
|
|
|
|
bool ok;
|
|
|
|
|
double value = QInputDialog::getDouble(this, tr("Set voxel size"), tr("Size (0=disabled)"), voxelSize_, 0.0, 0.1, 2, &ok);
|
|
|
|
|
if(ok)
|
|
|
|
|
{
|
|
|
|
|
voxelSize_ = value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if(a == _aSetCloudHistorySize)
|
|
|
|
|
{
|
|
|
|
|
bool ok;
|
|
|
|
|
int value = QInputDialog::getInt(this, tr("Set cloud history size"), tr("Size (0=infinite)"), maxClouds_, 0, 100, 1, &ok);
|
|
|
|
|
if(ok)
|
|
|
|
|
{
|
|
|
|
|
maxClouds_ = value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if(a == _aSetDecimation)
|
|
|
|
|
{
|
|
|
|
|
bool ok;
|
2014-02-25 21:07:32 +00:00
|
|
|
int value = QInputDialog::getInt(this, tr("Set depth image decimation"), tr("Decimation"), decimation_, 1, 8, 1, &ok);
|
2013-12-11 00:12:44 +00:00
|
|
|
if(ok)
|
|
|
|
|
{
|
|
|
|
|
decimation_ = value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} /* namespace rtabmap */
|