Added c++ example of RTAB-Map RGB-D version

git-svn-id: http://rtabmap.googlecode.com/svn/trunk/rtabmap@1152 f169173b-cf89-36c8-b27e-44dbe73f0c83
This commit is contained in:
matlabbe
2014-02-24 21:04:02 +00:00
parent 510e9cab89
commit 30981b102e
10 changed files with 373 additions and 28 deletions

View File

@@ -21,6 +21,7 @@
#include <QtCore/QDir> #include <QtCore/QDir>
#include "rtabmap/utilite/UEventsManager.h" #include "rtabmap/utilite/UEventsManager.h"
#include "rtabmap/core/RtabmapThread.h" #include "rtabmap/core/RtabmapThread.h"
#include "rtabmap/core/Rtabmap.h"
#include "rtabmap/gui/MainWindow.h" #include "rtabmap/gui/MainWindow.h"
#include <QtGui/QMessageBox> #include <QtGui/QMessageBox>
#include "rtabmap/utilite/UObjDeletionThread.h" #include "rtabmap/utilite/UObjDeletionThread.h"
@@ -45,7 +46,7 @@ int main(int argc, char* argv[])
/* Start thread's task */ /* Start thread's task */
mainWindow->showNormal(); mainWindow->showNormal();
RtabmapThread * rtabmap = new RtabmapThread(); RtabmapThread * rtabmap = new RtabmapThread(new Rtabmap());
rtabmap->start(); // start it not initialized... will be initialized by event from the gui rtabmap->start(); // start it not initialized... will be initialized by event from the gui
UEventsManager::addHandler(rtabmap); UEventsManager::addHandler(rtabmap);

View File

@@ -66,10 +66,13 @@ public:
}; };
public: public:
RtabmapThread(); // take ownership
RtabmapThread(Rtabmap * rtabmap);
virtual ~RtabmapThread(); virtual ~RtabmapThread();
void clearBufferedData(); void clearBufferedData();
void setDetectorRate(float rate);
void setBufferSize(int bufferSize);
protected: protected:
virtual void handleEvent(UEvent * anEvent); virtual void handleEvent(UEvent * anEvent);

View File

@@ -33,14 +33,15 @@
namespace rtabmap { namespace rtabmap {
RtabmapThread::RtabmapThread() : RtabmapThread::RtabmapThread(Rtabmap * rtabmap) :
_imageBufferMaxSize(Parameters::defaultRtabmapImageBufferSize()), _imageBufferMaxSize(Parameters::defaultRtabmapImageBufferSize()),
_rate(Parameters::defaultRtabmapDetectionRate()), _rate(Parameters::defaultRtabmapDetectionRate()),
_frameRateTimer(new UTimer()), _frameRateTimer(new UTimer()),
_rtabmap(new Rtabmap()), _rtabmap(rtabmap),
_paused(false) _paused(false)
{ {
UASSERT(rtabmap != 0);
} }
RtabmapThread::~RtabmapThread() RtabmapThread::~RtabmapThread()
@@ -77,6 +78,18 @@ void RtabmapThread::clearBufferedData()
_imageMutex.unlock(); _imageMutex.unlock();
} }
void RtabmapThread::setDetectorRate(float rate)
{
UASSERT(rate >= 0.0f);
_rate = rate;
}
void RtabmapThread::setBufferSize(int bufferSize)
{
UASSERT(bufferSize >= 0);
_imageBufferMaxSize = bufferSize;
}
void RtabmapThread::publishMap(bool optimized, bool full) const void RtabmapThread::publishMap(bool optimized, bool full) const
{ {
std::map<int, std::vector<unsigned char> > images; std::map<int, std::vector<unsigned char> > images;

View File

@@ -0,0 +1,18 @@
SET(INCLUDE_DIRS
${PROJECT_SOURCE_DIR}/corelib/include
${OpenCV_INCLUDE_DIRS}
)
SET(LIBRARIES
${OpenCV_LIBRARIES}
)
add_definitions(${PCL_DEFINITIONS})
INCLUDE_DIRECTORIES(${INCLUDE_DIRS})
ADD_EXECUTABLE(bow_mapping main.cpp)
TARGET_LINK_LIBRARIES(bow_mapping rtabmap_core ${LIBRARIES})
SET_TARGET_PROPERTIES( bow_mapping
PROPERTIES OUTPUT_NAME ${PROJECT_PREFIX}-bow_mapping)

View File

@@ -25,7 +25,7 @@
void showUsage() void showUsage()
{ {
printf("\nUsage:\n" printf("\nUsage:\n"
"rtabmap-example [options] \"path\"\n" "rtabmap-bow_mapping [options] \"path\"\n"
" path Path to a directory of images\n " " path Path to a directory of images\n "
" Options:" " Options:"
" -l localization mode: use already built RTAB-Map database to localize\n "); " -l localization mode: use already built RTAB-Map database to localize\n ");

View File

@@ -1,26 +1,11 @@
SET(SRC_FILES ADD_SUBDIRECTORY( BOWMapping )
main.cpp
)
SET(INCLUDE_DIRS IF(TARGET rtabmap_gui)
${PROJECT_SOURCE_DIR}/corelib/include ADD_SUBDIRECTORY( RGBDMapping )
${OpenCV_INCLUDE_DIRS} ELSE()
${PCL_INCLUDE_DIRS} MESSAGE(STATUS "RTAB-Map GUI lib is not built, the RGBDMapping example will not be built...")
) ENDIF()
SET(LIBRARIES
${OpenCV_LIBRARIES}
${PCL_LIBRARIES}
)
add_definitions(${PCL_DEFINITIONS})
INCLUDE_DIRECTORIES(${INCLUDE_DIRS})
ADD_EXECUTABLE(example ${SRC_FILES})
TARGET_LINK_LIBRARIES(example rtabmap_core ${LIBRARIES})
SET_TARGET_PROPERTIES( example
PROPERTIES OUTPUT_NAME ${PROJECT_PREFIX}-example)

View File

@@ -0,0 +1,27 @@
SET(INCLUDE_DIRS
${PROJECT_SOURCE_DIR}/utilite/include
${PROJECT_SOURCE_DIR}/corelib/include
${PROJECT_SOURCE_DIR}/guilib/include
${OpenCV_INCLUDE_DIRS}
${PCL_INCLUDE_DIRS}
)
INCLUDE(${QT_USE_FILE})
SET(LIBRARIES
${OpenCV_LIBRARIES}
${QT_LIBRARIES}
${PCL_LIBRARIES}
)
INCLUDE_DIRECTORIES(${INCLUDE_DIRS})
QT4_WRAP_CPP(moc_srcs MapBuilder.h)
ADD_EXECUTABLE(rgbd_mapping main.cpp ${moc_srcs})
TARGET_LINK_LIBRARIES(rgbd_mapping rtabmap_core rtabmap_gui rtabmap_utilite ${LIBRARIES})
SET_TARGET_PROPERTIES( rgbd_mapping
PROPERTIES OUTPUT_NAME ${PROJECT_PREFIX}-rgbd_mapping)

View File

@@ -0,0 +1,206 @@
/*
* MapBuilder.h
*
* Created on: 2014-02-24
* Author: mathieu
*/
#ifndef MAPBUILDER_H_
#define MAPBUILDER_H_
#include <QtGui/QVBoxLayout>
#include <QtCore/QMetaType>
#include "rtabmap/gui/CloudViewer.h"
#include "rtabmap/utilite/UStl.h"
#include "rtabmap/utilite/UConversion.h"
#include "rtabmap/utilite/UEventsHandler.h"
#include "rtabmap/utilite/ULogger.h"
#include "rtabmap/core/util3d.h"
#include "rtabmap/core/RtabmapEvent.h"
#include "rtabmap/core/OdometryEvent.h"
using namespace rtabmap;
// This class receives RtabmapEvent and construct/update a 3D Map
class MapBuilder : public QWidget, public UEventsHandler
{
Q_OBJECT
public:
MapBuilder()
{
this->setWindowFlags(Qt::Dialog);
this->setWindowTitle(tr("3D Map"));
this->setMinimumWidth(800);
this->setMinimumHeight(600);
cloudViewer_ = new CloudViewer(this);
QVBoxLayout *layout = new QVBoxLayout();
layout->addWidget(cloudViewer_);
this->setLayout(layout);
qRegisterMetaType<rtabmap::Statistics>("rtabmap::Statistics");
qRegisterMetaType<rtabmap::Image>("rtabmap::Image");
}
virtual ~MapBuilder()
{
this->unregisterFromEventsManager();
}
private slots:
void processOdometry(const rtabmap::Image & data)
{
if(!this->isVisible())
{
return;
}
Transform pose = data.pose();
if(pose.isNull())
{
//Odometry lost
cloudViewer_->setBackgroundColor(Qt::darkRed);
pose = lastOdomPose_;
}
else
{
cloudViewer_->setBackgroundColor(Qt::black);
}
if(!pose.isNull())
{
lastOdomPose_ = pose;
// 3d cloud
if(data.depth().cols == data.image().cols &&
data.depth().rows == data.image().rows &&
!data.depth().empty() &&
data.depthConstant() > 0.0f)
{
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud = util3d::cloudFromDepthRGB(
data.image(),
data.depth(),
float(data.depth().cols/2),
float(data.depth().rows/2),
1.0f/data.depthConstant(),
1.0f/data.depthConstant(),
2); // decimation // high definition
if(cloud->size())
{
cloud = util3d::passThrough(cloud, "z", 0, 4.0f);
if(cloud->size())
{
cloud = util3d::transformPointCloud(cloud, data.localTransform());
}
}
if(!cloudViewer_->addOrUpdateCloud("cloudOdom", cloud, pose))
{
UERROR("Adding cloudOdom to viewer failed!");
}
}
if(!data.pose().isNull())
{
// update camera position
cloudViewer_->updateCameraPosition(data.pose());
}
}
cloudViewer_->render();
}
void processStatistics(const rtabmap::Statistics & stats)
{
if(!this->isVisible())
{
return;
}
const std::map<int, Transform> & poses = stats.poses();
QMap<std::string, Transform> clouds = cloudViewer_->getAddedClouds();
for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter)
{
if(!iter->second.isNull())
{
std::string cloudName = uFormat("cloud%d", iter->first);
// 3d point cloud
if(clouds.contains(cloudName))
{
// Update only if the pose has changed
Transform tCloud;
cloudViewer_->getPose(cloudName, tCloud);
if(tCloud.isNull() || iter->second != tCloud)
{
if(!cloudViewer_->updateCloudPose(cloudName, iter->second))
{
UERROR("Updating pose cloud %d failed!", iter->first);
}
}
cloudViewer_->setCloudVisibility(cloudName, true);
}
else if(iter->first == stats.refImageId() &&
uContains(stats.getImages(), iter->first) &&
uContains(stats.getDepths(), iter->first) &&
uContains(stats.getDepthConstants(), iter->first) &&
uContains(stats.getLocalTransforms(), iter->first))
{
// Add the new cloud
cv::Mat rgb = util3d::uncompressImage(stats.getImages().at(iter->first));
cv::Mat depth = util3d::uncompressImage(stats.getDepths().at(iter->first));
float depthConstant = stats.getDepthConstants().at(iter->first);
Transform localTransform = stats.getLocalTransforms().at(iter->first);
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud = util3d::cloudFromDepthRGB(
rgb,
depth,
float(depth.cols/2),
float(depth.rows/2),
1.0f/depthConstant,
1.0f/depthConstant,
8); // decimation
if(cloud->size())
{
cloud = util3d::passThrough(cloud, "z", 0, 4.0f);
if(cloud->size())
{
cloud = util3d::transformPointCloud(cloud, localTransform);
}
}
if(!cloudViewer_->addOrUpdateCloud(cloudName, cloud, iter->second))
{
UERROR("Adding cloud %d to viewer failed!", iter->first);
}
}
}
}
cloudViewer_->render();
}
protected:
virtual void handleEvent(UEvent * event)
{
if(event->getClassName().compare("RtabmapEvent") == 0)
{
RtabmapEvent * rtabmapEvent = (RtabmapEvent *)event;
const Statistics & stats = rtabmapEvent->getStats();
// Statistics must be processed in the Qt thread
QMetaObject::invokeMethod(this, "processStatistics", Q_ARG(rtabmap::Statistics, stats));
}
else if(event->getClassName().compare("OdometryEvent") == 0)
{
OdometryEvent * odomEvent = (OdometryEvent *)event;
// Odometry must be processed in the Qt thread
QMetaObject::invokeMethod(this, "processOdometry", Q_ARG(rtabmap::Image, odomEvent->data()));
}
}
private:
CloudViewer * cloudViewer_;
Transform lastOdomPose_;
};
#endif /* MAPBUILDER_H_ */

View File

@@ -0,0 +1,94 @@
/*
* Copyright (C) 2010-2011, Mathieu Labbe and IntRoLab - Universite de Sherbrooke
*
* This file is part of RTAB-Map.
*
* RTAB-Map is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* RTAB-Map is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with RTAB-Map. If not, see <http://www.gnu.org/licenses/>.
*/
#include "rtabmap/core/Rtabmap.h"
#include "rtabmap/core/RtabmapThread.h"
#include "rtabmap/core/CameraOpenni.h"
#include "rtabmap/core/Odometry.h"
#include "rtabmap/utilite/UEventsManager.h"
#include <QtGui/QApplication>
#include <stdio.h>
#include "MapBuilder.h"
using namespace rtabmap;
int main(int argc, char * argv[])
{
ULogger::setType(ULogger::kTypeConsole);
ULogger::setLevel(ULogger::kWarning);
// GUI stuff, there the handler will receive RtabmapEvent and construct the map
QApplication app(argc, argv);
MapBuilder mapBuilder;
// Here is the pipeline that we will use:
// CameraOpenni -> "CameraEvent" -> OdometryThread -> "OdometryEvent" -> RtabmapThread -> "RtabmapEvent"
// Create the OpenNI camera, it will send a CameraEvent at the rate specified.
// Set transform to camera so z is up, y is left and x going forward
CameraOpenni camera("", 10, rtabmap::Transform(0,0,1,0, -1,0,0,0, 0,-1,0,0));
if(!camera.init())
{
UERROR("Camera init failed!");
exit(1);
}
// Create an odometry thread to process camera events, it will send OdometryEvent.
OdometryThread odomThread(new OdometryBOW(0)); // 0=SURF 1=SIFT
// Create RTAB-Map to process OdometryEvent
Rtabmap * rtabmap = new Rtabmap();
rtabmap->init();
RtabmapThread rtabmapThread(rtabmap); // ownership is transfered
rtabmapThread.setDetectorRate(0.0f); // as fast as we can
// Setup handlers
odomThread.registerToEventsManager();
rtabmapThread.registerToEventsManager();
mapBuilder.registerToEventsManager();
// The RTAB-Map is subscribed by default to CameraEvent, but we want
// RTAB-Map to process OdometryEvent instead, ignoring the CameraEvent.
// We can do that by creating a "pipe" between the camera and odometry, then
// only the odometry will receive CameraEvent from that camera. RTAB-Map is
// also subscribed to OdometryEvent by default, so no need to create a pipe between
// odometry and RTAB-Map.
UEventsManager::createPipe(&camera, &odomThread, "CameraEvent");
// Let's start the threads
rtabmapThread.start();
odomThread.start();
camera.start();
mapBuilder.show();
app.exec(); // main loop
// remove handlers
mapBuilder.unregisterFromEventsManager();
rtabmapThread.unregisterFromEventsManager();
odomThread.unregisterFromEventsManager();
// Kill all threads
camera.kill();
odomThread.join(true);
rtabmapThread.join(true);
return 0;
}

View File

@@ -7,14 +7,12 @@ SET(INCLUDE_DIRS
${PROJECT_SOURCE_DIR}/utilite/include ${PROJECT_SOURCE_DIR}/utilite/include
${PROJECT_SOURCE_DIR}/corelib/include ${PROJECT_SOURCE_DIR}/corelib/include
${PROJECT_SOURCE_DIR}/guilib/include ${PROJECT_SOURCE_DIR}/guilib/include
${UTILITE_INCLUDE_DIRS}
${OpenCV_INCLUDE_DIRS} ${OpenCV_INCLUDE_DIRS}
) )
INCLUDE(${QT_USE_FILE}) INCLUDE(${QT_USE_FILE})
SET(LIBRARIES SET(LIBRARIES
${UTILITE_LIBRARIES}
${OpenCV_LIBRARIES} ${OpenCV_LIBRARIES}
${QT_LIBRARIES} ${QT_LIBRARIES}
) )