2016-02-15 19:35:24 -05:00
/*
Copyright ( c ) 2010 - 2016 , 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 .
*/
# include <tango-gl/conversions.h>
# include "RTABMapApp.h"
# include <rtabmap/core/Rtabmap.h>
# include <rtabmap/core/util3d.h>
# include <rtabmap/core/util3d_transforms.h>
# include <rtabmap/core/util3d_filtering.h>
# include <rtabmap/core/Graph.h>
# include <rtabmap/utilite/UEventsManager.h>
# include <rtabmap/utilite/UStl.h>
2016-03-21 20:03:03 -04:00
# include <rtabmap/utilite/UDirectory.h>
# include <rtabmap/utilite/UFile.h>
2016-02-15 19:35:24 -05:00
# include <opencv2/opencv_modules.hpp>
# include <rtabmap/core/util3d_surface.h>
# include <rtabmap/utilite/UConversion.h>
# include <rtabmap/utilite/UTimer.h>
# include <rtabmap/core/ParamEvent.h>
2016-03-21 20:03:03 -04:00
# include <rtabmap/core/Compression.h>
2016-04-03 21:35:30 -04:00
# include <rtabmap/core/Optimizer.h>
2016-02-15 19:35:24 -05:00
# include <pcl/filters/extract_indices.h>
# include <pcl/io/ply_io.h>
2016-03-21 20:03:03 -04:00
# include <pcl/io/obj_io.h>
2016-02-15 19:35:24 -05:00
const int kVersionStringLength = 128 ;
static JavaVM * jvm ;
static jobject RTABMapActivity = 0 ;
rtabmap : : ParametersMap RTABMapApp : : getRtabmapParameters ( )
{
rtabmap : : ParametersMap parameters ;
2016-04-02 15:17:40 -04:00
parameters . insert ( mappingParameters_ . begin ( ) , mappingParameters_ . end ( ) ) ;
2016-02-15 19:35:24 -05:00
parameters . insert ( rtabmap : : ParametersPair ( rtabmap : : Parameters : : kKpDetectorStrategy ( ) , std : : string ( " 6 " ) ) ) ; // GFTT/BRIEF
parameters . insert ( rtabmap : : ParametersPair ( rtabmap : : Parameters : : kGFTTQualityLevel ( ) , std : : string ( " 0.0001 " ) ) ) ;
2016-04-02 15:17:40 -04:00
parameters . insert ( rtabmap : : ParametersPair ( rtabmap : : Parameters : : kGFTTMinDistance ( ) , std : : string ( fullResolution_ ? " 15 " : " 5 " ) ) ) ;
2016-02-15 19:35:24 -05:00
parameters . insert ( rtabmap : : ParametersPair ( rtabmap : : Parameters : : kFASTThreshold ( ) , std : : string ( " 1 " ) ) ) ;
parameters . insert ( rtabmap : : ParametersPair ( rtabmap : : Parameters : : kBRIEFBytes ( ) , std : : string ( " 64 " ) ) ) ;
parameters . insert ( rtabmap : : ParametersPair ( rtabmap : : Parameters : : kMemBinDataKept ( ) , uBool2Str ( ! trajectoryMode_ ) ) ) ;
parameters . insert ( rtabmap : : ParametersPair ( rtabmap : : Parameters : : kMemNotLinkedNodesKept ( ) , std : : string ( " false " ) ) ) ;
2016-04-03 21:35:30 -04:00
parameters . insert ( rtabmap : : ParametersPair ( rtabmap : : Parameters : : kOptimizerIterations ( ) , graphOptimization_ ? " 10 " : " 0 " ) ) ;
2016-02-15 19:35:24 -05:00
parameters . insert ( rtabmap : : ParametersPair ( rtabmap : : Parameters : : kMemIncrementalMemory ( ) , uBool2Str ( ! localizationMode_ ) ) ) ;
parameters . insert ( rtabmap : : ParametersPair ( rtabmap : : Parameters : : kRtabmapMaxRetrieved ( ) , uBool2Str ( ! localizationMode_ ) ) ) ;
parameters . insert ( rtabmap : : ParametersPair ( rtabmap : : Parameters : : kKpMaxDepth ( ) , std : : string ( " 10 " ) ) ) ; // to avoid extracting features in invalid depth (as we compute transformation directly from the words)
parameters . insert ( rtabmap : : ParametersPair ( rtabmap : : Parameters : : kRGBDOptimizeFromGraphEnd ( ) , std : : string ( " true " ) ) ) ;
parameters . insert ( rtabmap : : ParametersPair ( rtabmap : : Parameters : : kDbSqlite3InMemory ( ) , std : : string ( " true " ) ) ) ;
parameters . insert ( rtabmap : : ParametersPair ( rtabmap : : Parameters : : kVisMinInliers ( ) , std : : string ( " 15 " ) ) ) ;
2016-04-03 21:35:30 -04:00
parameters . insert ( rtabmap : : ParametersPair ( rtabmap : : Parameters : : kVisEstimationType ( ) , std : : string ( " 0 " ) ) ) ; // PnP
2016-02-15 19:35:24 -05:00
return parameters ;
}
RTABMapApp : : RTABMapApp ( ) :
camera_ ( 0 ) ,
rtabmapThread_ ( 0 ) ,
2016-04-03 21:35:30 -04:00
rtabmap_ ( 0 ) ,
2016-02-15 19:35:24 -05:00
logHandler_ ( 0 ) ,
odomCloudShown_ ( true ) ,
graphOptimization_ ( true ) ,
localizationMode_ ( false ) ,
trajectoryMode_ ( false ) ,
autoExposure_ ( false ) ,
2016-04-02 15:17:40 -04:00
fullResolution_ ( false ) ,
maxCloudDepth_ ( 0.0 ) ,
2016-04-04 13:03:43 -04:00
meshTrianglePix_ ( 1 ) ,
meshAngleToleranceDeg_ ( 10.0 ) ,
2016-02-15 19:35:24 -05:00
clearSceneOnNextRender_ ( false ) ,
totalPoints_ ( 0 ) ,
totalPolygons_ ( 0 ) ,
lastDrawnCloudsCount_ ( 0 )
{
2016-04-02 15:17:40 -04:00
2016-02-15 19:35:24 -05:00
}
RTABMapApp : : ~ RTABMapApp ( ) {
if ( camera_ )
{
delete camera_ ;
}
if ( rtabmapThread_ )
{
rtabmapThread_ - > close ( false ) ;
delete rtabmapThread_ ;
}
if ( logHandler_ )
{
delete logHandler_ ;
}
}
int RTABMapApp : : TangoInitialize ( JNIEnv * env , jobject caller_activity )
{
env - > GetJavaVM ( & jvm ) ;
RTABMapActivity = env - > NewGlobalRef ( caller_activity ) ;
LOGI ( " RTABMapApp::TangoInitialize() " ) ;
createdMeshes_ . clear ( ) ;
rawPoses_ . clear ( ) ;
clearSceneOnNextRender_ = true ;
totalPoints_ = 0 ;
totalPolygons_ = 0 ;
lastDrawnCloudsCount_ = 0 ;
if ( camera_ )
{
delete camera_ ;
}
if ( rtabmapThread_ )
{
rtabmapThread_ - > close ( false ) ;
delete rtabmapThread_ ;
rtabmapThread_ = 0 ;
2016-04-03 21:35:30 -04:00
rtabmap_ = 0 ;
2016-02-15 19:35:24 -05:00
}
if ( logHandler_ = = 0 )
{
logHandler_ = new LogHandler ( ) ;
}
ULogger : : setEventLevel ( ULogger : : kInfo ) ;
ULogger : : setPrintThreadId ( true ) ;
this - > registerToEventsManager ( ) ;
2016-04-02 15:17:40 -04:00
camera_ = new rtabmap : : CameraTango ( fullResolution_ ? 1 : 2 , autoExposure_ ) ;
2016-02-15 19:35:24 -05:00
// The first thing we need to do for any Tango enabled application is to
// initialize the service. We'll do that here, passing on the JNI environment
// and jobject corresponding to the Android activity that is calling us.
return TangoService_initialize ( env , caller_activity ) ;
}
void RTABMapApp : : openDatabase ( const std : : string & databasePath )
{
this - > unregisterFromEventsManager ( ) ; // to ignore published init events when closing rtabmap
status_ . first = rtabmap : : RtabmapEventInit : : kInitializing ;
rtabmapMutex_ . lock ( ) ;
if ( rtabmapThread_ )
{
rtabmapThread_ - > close ( false ) ;
delete rtabmapThread_ ;
rtabmapThread_ = 0 ;
2016-04-03 21:35:30 -04:00
rtabmap_ = 0 ;
2016-02-15 19:35:24 -05:00
}
//Rtabmap
2016-04-03 21:35:30 -04:00
rtabmap_ = new rtabmap : : Rtabmap ( ) ;
2016-02-15 19:35:24 -05:00
rtabmap : : ParametersMap parameters = getRtabmapParameters ( ) ;
2016-04-03 21:35:30 -04:00
rtabmap_ - > init ( parameters , databasePath ) ;
rtabmapThread_ = new rtabmap : : RtabmapThread ( rtabmap_ ) ;
2016-02-15 19:35:24 -05:00
// Generate all meshes
std : : map < int , rtabmap : : Signature > signatures ;
std : : map < int , rtabmap : : Transform > poses ;
std : : multimap < int , rtabmap : : Link > links ;
2016-04-03 21:35:30 -04:00
rtabmap_ - > get3DMap (
2016-02-15 19:35:24 -05:00
signatures ,
poses ,
links ,
true ,
true ) ;
clearSceneOnNextRender_ = true ;
rtabmap : : Statistics stats ;
stats . setSignatures ( signatures ) ;
stats . setPoses ( poses ) ;
stats . setConstraints ( links ) ;
rtabmapEvents_ . push_back ( stats ) ;
// Start threads
LOGI ( " Start rtabmap thread " ) ;
this - > registerToEventsManager ( ) ;
rtabmapThread_ - > registerToEventsManager ( ) ;
rtabmapThread_ - > start ( ) ;
status_ . first = rtabmap : : RtabmapEventInit : : kInitialized ;
status_ . second = " " ;
rtabmapMutex_ . unlock ( ) ;
}
int RTABMapApp : : onResume ( )
{
LOGW ( " onResume() " ) ;
if ( camera_ )
{
camera_ - > join ( true ) ;
if ( camera_ - > init ( ) )
{
LOGI ( " Start camera thread " ) ;
camera_ - > start ( ) ;
return TANGO_SUCCESS ;
}
LOGE ( " Failed camera initialization! " ) ;
}
return TANGO_ERROR ;
}
void RTABMapApp : : onPause ( )
{
LOGW ( " onPause() " ) ;
if ( camera_ )
{
camera_ - > join ( true ) ;
camera_ - > close ( ) ;
}
}
void RTABMapApp : : TangoResetMotionTracking ( ) {
TangoService_resetMotionTracking ( ) ;
}
// OpenGL thread
void RTABMapApp : : InitializeGLContent ( )
{
UINFO ( " " ) ;
main_scene_ . InitGLContent ( ) ;
}
// OpenGL thread
void RTABMapApp : : SetViewPort ( int width , int height )
{
UINFO ( " " ) ;
main_scene_ . SetupViewPort ( width , height ) ;
}
// OpenGL thread
int RTABMapApp : : Render ( )
{
// should be before clearSceneOnNextRender_ in case openDatabase is called
std : : list < rtabmap : : Statistics > rtabmapEvents ;
{
boost : : mutex : : scoped_lock lock ( rtabmapMutex_ ) ;
rtabmapEvents = rtabmapEvents_ ;
rtabmapEvents_ . clear ( ) ;
}
if ( clearSceneOnNextRender_ )
{
odomMutex_ . lock ( ) ;
odomEvents_ . clear ( ) ;
odomMutex_ . unlock ( ) ;
poseMutex_ . lock ( ) ;
poseEvents_ . clear ( ) ;
poseMutex_ . unlock ( ) ;
main_scene_ . clear ( ) ;
clearSceneOnNextRender_ = false ;
createdMeshes_ . clear ( ) ;
rawPoses_ . clear ( ) ;
totalPoints_ = 0 ;
totalPolygons_ = 0 ;
lastDrawnCloudsCount_ = 0 ;
}
// Process events
rtabmap : : Transform pose ;
{
boost : : mutex : : scoped_lock lock ( poseMutex_ ) ;
if ( poseEvents_ . size ( ) )
{
pose = poseEvents_ . back ( ) ;
poseEvents_ . clear ( ) ;
}
}
if ( ! pose . isNull ( ) )
{
// update camera pose?
main_scene_ . SetCameraPose ( pose ) ;
}
bool notifyDataLoaded = false ;
if ( rtabmapEvents . size ( ) )
{
LOGI ( " Process rtabmap events " ) ;
// update buffered signatures
std : : map < int , rtabmap : : SensorData > bufferedSensorData ;
if ( ! trajectoryMode_ )
{
for ( std : : list < rtabmap : : Statistics > : : iterator iter = rtabmapEvents . begin ( ) ; iter ! = rtabmapEvents . end ( ) ; + + iter )
{
for ( std : : map < int , rtabmap : : Signature > : : const_iterator jter = iter - > getSignatures ( ) . begin ( ) ; jter ! = iter - > getSignatures ( ) . end ( ) ; + + jter )
{
if ( ! jter - > second . sensorData ( ) . imageRaw ( ) . empty ( ) & &
! jter - > second . sensorData ( ) . depthRaw ( ) . empty ( ) )
{
uInsert ( bufferedSensorData , std : : make_pair ( jter - > first , jter - > second . sensorData ( ) ) ) ;
uInsert ( rawPoses_ , std : : make_pair ( jter - > first , jter - > second . getPose ( ) ) ) ;
}
else if ( ! jter - > second . sensorData ( ) . imageCompressed ( ) . empty ( ) & &
! jter - > second . sensorData ( ) . depthOrRightCompressed ( ) . empty ( ) )
{
// uncompress
rtabmap : : SensorData data = jter - > second . sensorData ( ) ;
cv : : Mat tmpA , tmpB ;
data . uncompressData ( & tmpA , & tmpB ) ;
uInsert ( bufferedSensorData , std : : make_pair ( jter - > first , data ) ) ;
uInsert ( rawPoses_ , std : : make_pair ( jter - > first , jter - > second . getPose ( ) ) ) ;
notifyDataLoaded = true ;
}
}
}
}
std : : map < int , rtabmap : : Transform > poses = rtabmapEvents . back ( ) . poses ( ) ;
// Transform pose in OpenGL world
for ( std : : map < int , rtabmap : : Transform > : : iterator iter = poses . begin ( ) ; iter ! = poses . end ( ) ; + + iter )
{
if ( ! graphOptimization_ )
{
std : : map < int , rtabmap : : Transform > : : iterator jter = rawPoses_ . find ( iter - > first ) ;
if ( jter ! = rawPoses_ . end ( ) )
{
iter - > second = opengl_world_T_rtabmap_world * jter - > second ;
}
}
else
{
iter - > second = opengl_world_T_rtabmap_world * iter - > second ;
}
}
if ( poses . size ( ) )
{
const std : : multimap < int , rtabmap : : Link > & links = rtabmapEvents . back ( ) . constraints ( ) ;
//update graph
main_scene_ . updateGraph ( poses , links ) ;
// update clouds
//filter poses?
// make sure the last pose is here though
//poses.insert(*rtabmapEvents.back().poses().rbegin());
std : : set < std : : string > strIds ;
for ( std : : map < int , rtabmap : : Transform > : : iterator iter = poses . begin ( ) ; iter ! = poses . end ( ) ; + + iter )
{
int id = iter - > first ;
if ( ! iter - > second . isNull ( ) )
{
if ( main_scene_ . hasCloud ( id ) )
{
//just update pose
main_scene_ . setCloudPose ( id , iter - > second ) ;
main_scene_ . setCloudVisible ( id , true ) ;
}
else if ( uContains ( bufferedSensorData , id ) )
{
rtabmap : : SensorData & data = bufferedSensorData . at ( id ) ;
if ( ! data . imageRaw ( ) . empty ( ) & & ! data . depthRaw ( ) . empty ( ) )
{
// Voxelize and filter depending on the previous cloud?
2016-04-02 15:17:40 -04:00
pcl : : PointCloud < pcl : : PointXYZRGB > : : Ptr cloud ;
2016-02-15 19:35:24 -05:00
pcl : : IndicesPtr indices ( new std : : vector < int > ) ;
LOGI ( " Creating node cloud %d (image size=%dx%d) " , id , data . imageRaw ( ) . cols , data . imageRaw ( ) . rows ) ;
2016-04-02 15:17:40 -04:00
cloud = rtabmap : : util3d : : cloudRGBFromSensorData ( data , data . imageRaw ( ) . rows / data . depthRaw ( ) . rows , maxCloudDepth_ , 0 , 0 , indices . get ( ) ) ;
2016-02-15 19:35:24 -05:00
if ( cloud - > size ( ) & & indices - > size ( ) )
{
UTimer time ;
// pcl::organizedFastMesh doesn't take indices, so set to NaN points we don't need to mesh
2016-04-02 15:17:40 -04:00
pcl : : PointCloud < pcl : : PointXYZRGB > : : Ptr output ( new pcl : : PointCloud < pcl : : PointXYZRGB > ) ;
pcl : : ExtractIndices < pcl : : PointXYZRGB > filter ;
filter . setIndices ( indices ) ;
2016-02-15 19:35:24 -05:00
filter . setKeepOrganized ( true ) ;
filter . setInputCloud ( cloud ) ;
filter . filter ( * output ) ;
2016-04-04 13:03:43 -04:00
std : : vector < pcl : : Vertices > polygons = rtabmap : : util3d : : organizedFastMesh ( output , meshAngleToleranceDeg_ * M_PI / 180.0 , false , meshTrianglePix_ ) ;
2016-04-02 15:17:40 -04:00
pcl : : PointCloud < pcl : : PointXYZRGB > : : Ptr outputCloud ( new pcl : : PointCloud < pcl : : PointXYZRGB > ) ;
2016-02-15 19:35:24 -05:00
std : : vector < pcl : : Vertices > outputPolygons ;
2016-03-21 15:45:26 -04:00
2016-04-02 15:17:40 -04:00
outputCloud = output ;
outputPolygons = polygons ;
2016-02-15 19:35:24 -05:00
LOGI ( " Creating mesh, %d polygons (%fs) " , ( int ) outputPolygons . size ( ) , time . ticks ( ) ) ;
2016-04-02 15:17:40 -04:00
if ( outputCloud - > size ( ) & & outputPolygons . size ( ) )
2016-02-15 19:35:24 -05:00
{
totalPolygons_ + = outputPolygons . size ( ) ;
2016-04-02 15:17:40 -04:00
main_scene_ . addCloud ( id , outputCloud , outputPolygons , iter - > second , data . imageRaw ( ) ) ;
2016-03-21 15:45:26 -04:00
2016-02-15 19:35:24 -05:00
// protect createdMeshes_ used also by exportMesh() method
boost : : mutex : : scoped_lock lock ( meshesMutex_ ) ;
2016-03-21 20:03:03 -04:00
std : : pair < std : : map < int , Mesh > : : iterator , bool > inserted = createdMeshes_ . insert ( std : : make_pair ( id , Mesh ( ) ) ) ;
UASSERT ( inserted . second ) ;
inserted . first - > second . cloud = outputCloud ;
inserted . first - > second . polygons = outputPolygons ;
inserted . first - > second . pose = iter - > second ;
2016-04-02 15:17:40 -04:00
inserted . first - > second . texture = data . imageCompressed ( ) ;
2016-02-15 19:35:24 -05:00
}
else
{
LOGE ( " Not mesh could be created for node %d " , id ) ;
}
}
totalPoints_ + = indices - > size ( ) ;
}
}
}
}
}
//update cloud visibility
std : : set < int > addedClouds = main_scene_ . getAddedClouds ( ) ;
for ( std : : set < int > : : const_iterator iter = addedClouds . begin ( ) ;
iter ! = addedClouds . end ( ) ;
+ + iter )
{
2016-04-04 13:03:43 -04:00
if ( * iter > 0 & & poses . find ( * iter ) = = poses . end ( ) )
2016-02-15 19:35:24 -05:00
{
main_scene_ . setCloudVisible ( * iter , false ) ;
}
}
}
else
{
rtabmap : : OdometryEvent event ;
bool set = false ;
{
boost : : mutex : : scoped_lock lock ( odomMutex_ ) ;
if ( odomEvents_ . size ( ) )
{
LOGI ( " Process odom events " ) ;
event = odomEvents_ . back ( ) ;
odomEvents_ . clear ( ) ;
set = true ;
}
}
2016-04-04 13:03:43 -04:00
main_scene_ . setCloudVisible ( - 1 , odomCloudShown_ & & ! trajectoryMode_ ) ;
2016-02-15 19:35:24 -05:00
//just process the last one
if ( set & & ! event . pose ( ) . isNull ( ) )
{
if ( odomCloudShown_ & & ! trajectoryMode_ )
{
if ( ! event . data ( ) . imageRaw ( ) . empty ( ) & & ! event . data ( ) . depthRaw ( ) . empty ( ) )
{
pcl : : PointCloud < pcl : : PointXYZRGB > : : Ptr cloud ;
2016-04-02 15:17:40 -04:00
cloud = rtabmap : : util3d : : cloudRGBFromSensorData ( event . data ( ) , event . data ( ) . imageRaw ( ) . rows / event . data ( ) . depthRaw ( ) . rows , maxCloudDepth_ ) ;
2016-02-15 19:35:24 -05:00
if ( cloud - > size ( ) )
{
2016-04-04 13:03:43 -04:00
LOGI ( " Created odom cloud (rgb=%dx%d depth=%dx%d cloud=%dx%d) " ,
event . data ( ) . imageRaw ( ) . cols , event . data ( ) . imageRaw ( ) . rows ,
event . data ( ) . depthRaw ( ) . cols , event . data ( ) . depthRaw ( ) . rows ,
( int ) cloud - > width , ( int ) cloud - > height ) ;
std : : vector < pcl : : Vertices > polygons = rtabmap : : util3d : : organizedFastMesh ( cloud , meshAngleToleranceDeg_ * M_PI / 180.0 , false , meshTrianglePix_ ) ;
2016-04-02 15:17:40 -04:00
main_scene_ . addCloud ( - 1 , cloud , polygons , opengl_world_T_rtabmap_world * event . pose ( ) , event . data ( ) . imageRaw ( ) ) ;
2016-02-15 19:35:24 -05:00
main_scene_ . setCloudVisible ( - 1 , true ) ;
}
else
{
LOGE ( " Generated cloud is empty! " ) ;
}
}
else
{
LOGE ( " Odom data images are empty! " ) ;
}
}
}
}
lastDrawnCloudsCount_ = main_scene_ . Render ( ) ;
return notifyDataLoaded ? 1 : 0 ;
}
void RTABMapApp : : SetCameraType (
tango_gl : : GestureCamera : : CameraType camera_type ) {
main_scene_ . SetCameraType ( camera_type ) ;
}
void RTABMapApp : : OnTouchEvent ( int touch_count ,
tango_gl : : GestureCamera : : TouchEvent event ,
float x0 , float y0 , float x1 , float y1 ) {
main_scene_ . OnTouchEvent ( touch_count , event , x0 , y0 , x1 , y1 ) ;
}
void RTABMapApp : : setPausedMapping ( bool paused )
{
if ( camera_ )
{
if ( paused )
{
LOGW ( " Pause! " ) ;
camera_ - > kill ( ) ;
}
else
{
LOGW ( " Resume! " ) ;
camera_ - > start ( ) ;
}
}
}
void RTABMapApp : : setMapCloudShown ( bool shown )
{
2016-04-04 13:03:43 -04:00
main_scene_ . setMapRendering ( shown ) ;
2016-02-15 19:35:24 -05:00
}
void RTABMapApp : : setOdomCloudShown ( bool shown )
{
odomCloudShown_ = shown ;
main_scene_ . setTraceVisible ( shown ) ;
}
void RTABMapApp : : setMeshRendering ( bool enabled )
{
main_scene_ . setMeshRendering ( enabled ) ;
}
void RTABMapApp : : setLocalizationMode ( bool enabled )
{
localizationMode_ = enabled ;
this - > post ( new rtabmap : : ParamEvent ( rtabmap : : Parameters : : kMemIncrementalMemory ( ) , uBool2Str ( ! localizationMode_ ) ) ) ;
}
void RTABMapApp : : setTrajectoryMode ( bool enabled )
{
if ( trajectoryMode_ ! = enabled )
{
main_scene_ . SetCameraType ( enabled ? tango_gl : : GestureCamera : : kTopDown : tango_gl : : GestureCamera : : kThirdPersonFollow ) ;
}
trajectoryMode_ = enabled ;
this - > post ( new rtabmap : : ParamEvent ( rtabmap : : Parameters : : kMemBinDataKept ( ) , uBool2Str ( ! trajectoryMode_ ) ) ) ;
}
void RTABMapApp : : setGraphOptimization ( bool enabled )
{
graphOptimization_ = enabled ;
}
void RTABMapApp : : setGraphVisible ( bool visible )
{
main_scene_ . setGraphVisible ( visible ) ;
}
void RTABMapApp : : setAutoExposure ( bool enabled )
{
if ( autoExposure_ ! = enabled )
{
autoExposure_ = enabled ;
if ( camera_ )
{
camera_ - > join ( true ) ;
camera_ - > close ( ) ;
camera_ - > setAutoExposure ( autoExposure_ ) ;
onResume ( ) ;
}
2016-04-02 15:17:40 -04:00
}
}
void RTABMapApp : : setFullResolution ( bool enabled )
{
if ( fullResolution_ ! = enabled )
{
fullResolution_ = enabled ;
if ( camera_ )
{
camera_ - > setDecimation ( fullResolution_ ? 1 : 2 ) ;
}
}
}
void RTABMapApp : : setMaxCloudDepth ( float value )
{
maxCloudDepth_ = value ;
}
2016-04-04 13:03:43 -04:00
void RTABMapApp : : setMeshAngleTolerance ( float value )
{
meshAngleToleranceDeg_ = value ;
}
void RTABMapApp : : setMeshTriangleSize ( int value )
{
meshTrianglePix_ = value ;
}
2016-04-02 15:17:40 -04:00
int RTABMapApp : : setMappingParameter ( const std : : string & key , const std : : string & value )
{
if ( rtabmap : : Parameters : : getDefaultParameters ( ) . find ( key ) ! = rtabmap : : Parameters : : getDefaultParameters ( ) . end ( ) )
{
LOGI ( uFormat ( " Setting param \" %s \" to \" \" " , key . c_str ( ) , value . c_str ( ) ) . c_str ( ) ) ;
uInsert ( mappingParameters_ , rtabmap : : ParametersPair ( key , value ) ) ;
UEventsManager : : post ( new rtabmap : : ParamEvent ( mappingParameters_ ) ) ;
return 0 ;
}
else
{
LOGE ( uFormat ( " Key \" %s \" doesn't exist! " , key . c_str ( ) ) . c_str ( ) ) ;
return - 1 ;
2016-02-15 19:35:24 -05:00
}
}
void RTABMapApp : : resetMapping ( )
{
LOGW ( " Reset! " ) ;
status_ . first = rtabmap : : RtabmapEventInit : : kInitializing ;
status_ . second = " " ;
clearSceneOnNextRender_ = true ;
UEventsManager : : post ( new rtabmap : : RtabmapEventCmd ( rtabmap : : RtabmapEventCmd : : kCmdResetMemory ) ) ;
}
void RTABMapApp : : save ( )
{
UEventsManager : : post ( new rtabmap : : RtabmapEventCmd ( rtabmap : : RtabmapEventCmd : : kCmdClose ) ) ;
}
bool RTABMapApp : : exportMesh ( const std : : string & filePath )
{
bool success = false ;
//Assemble the meshes
2016-04-02 15:17:40 -04:00
if ( UFile : : getExtension ( filePath ) . compare ( " obj " ) = = 0 )
2016-02-15 19:35:24 -05:00
{
2016-03-21 20:03:03 -04:00
pcl : : TextureMesh textureMesh ;
std : : vector < cv : : Mat > textures ;
pcl : : PointCloud < pcl : : PointXYZRGBNormal > : : Ptr mergedClouds ( new pcl : : PointCloud < pcl : : PointXYZRGBNormal > ) ;
2016-02-15 19:35:24 -05:00
{
2016-03-21 20:03:03 -04:00
boost : : mutex : : scoped_lock lock ( meshesMutex_ ) ;
textureMesh . tex_materials . resize ( createdMeshes_ . size ( ) ) ;
textureMesh . tex_polygons . resize ( createdMeshes_ . size ( ) ) ;
textureMesh . tex_coordinates . resize ( createdMeshes_ . size ( ) ) ;
textures . resize ( createdMeshes_ . size ( ) ) ;
int polygonsStep = 0 ;
int oi = 0 ;
for ( std : : map < int , Mesh > : : iterator iter = createdMeshes_ . begin ( ) ;
iter ! = createdMeshes_ . end ( ) ;
+ + iter )
2016-02-15 19:35:24 -05:00
{
2016-03-21 20:03:03 -04:00
UASSERT ( ! iter - > second . cloud - > is_dense ) ;
if ( ! iter - > second . texture . empty ( ) & &
iter - > second . cloud - > size ( ) & &
iter - > second . polygons . size ( ) )
{
2016-04-02 15:17:40 -04:00
// OBJ format requires normals
pcl : : PointCloud < pcl : : PointXYZRGBNormal > : : Ptr cloudWithNormals ;
cloudWithNormals = rtabmap : : util3d : : computeNormals ( iter - > second . cloud , 20 ) ;
2016-03-21 20:03:03 -04:00
// create dense cloud
pcl : : PointCloud < pcl : : PointXYZRGBNormal > : : Ptr denseCloud ( new pcl : : PointCloud < pcl : : PointXYZRGBNormal > ) ;
std : : vector < pcl : : Vertices > densePolygons ;
std : : map < int , int > newToOldIndices ;
newToOldIndices = rtabmap : : util3d : : filterNotUsedVerticesFromMesh (
2016-04-02 15:17:40 -04:00
* cloudWithNormals ,
2016-03-21 20:03:03 -04:00
iter - > second . polygons ,
* denseCloud ,
densePolygons ) ;
// polygons
UASSERT ( densePolygons . size ( ) ) ;
unsigned int polygonSize = densePolygons . front ( ) . vertices . size ( ) ;
textureMesh . tex_polygons [ oi ] . resize ( densePolygons . size ( ) ) ;
textureMesh . tex_coordinates [ oi ] . resize ( densePolygons . size ( ) * polygonSize ) ;
for ( unsigned int j = 0 ; j < densePolygons . size ( ) ; + + j )
{
pcl : : Vertices vertices = densePolygons [ j ] ;
UASSERT ( polygonSize = = vertices . vertices . size ( ) ) ;
for ( unsigned int k = 0 ; k < vertices . vertices . size ( ) ; + + k )
{
//uv
std : : map < int , int > : : iterator jter = newToOldIndices . find ( vertices . vertices [ k ] ) ;
textureMesh . tex_coordinates [ oi ] [ j * vertices . vertices . size ( ) + k ] = Eigen : : Vector2f (
float ( jter - > second % iter - > second . cloud - > width ) / float ( iter - > second . cloud - > width ) , // u
float ( iter - > second . cloud - > height - jter - > second / iter - > second . cloud - > width ) / float ( iter - > second . cloud - > height ) ) ; // v
vertices . vertices [ k ] + = polygonsStep ;
}
textureMesh . tex_polygons [ oi ] [ j ] = vertices ;
}
polygonsStep + = denseCloud - > size ( ) ;
pcl : : PointCloud < pcl : : PointXYZRGBNormal > : : Ptr transformedCloud = rtabmap : : util3d : : transformPointCloud ( denseCloud , iter - > second . pose ) ;
if ( mergedClouds - > size ( ) = = 0 )
{
* mergedClouds = * transformedCloud ;
}
else
{
* mergedClouds + = * transformedCloud ;
}
textures [ oi ] = iter - > second . texture ;
textureMesh . tex_materials [ oi ] . tex_illum = 1 ;
textureMesh . tex_materials [ oi ] . tex_name = uFormat ( " material_%d " , iter - > first ) ;
+ + oi ;
}
else
{
UERROR ( " Texture not set for mesh %d " , iter - > first ) ;
}
2016-02-15 19:35:24 -05:00
}
2016-03-21 20:03:03 -04:00
textureMesh . tex_materials . resize ( oi ) ;
textureMesh . tex_polygons . resize ( oi ) ;
textures . resize ( oi ) ;
if ( textures . size ( ) )
2016-02-15 19:35:24 -05:00
{
2016-03-21 20:03:03 -04:00
pcl : : toPCLPointCloud2 ( * mergedClouds , textureMesh . cloud ) ;
std : : string textureDirectory = uSplit ( filePath , ' . ' ) . front ( ) ;
UINFO ( " Saving %d textures to %s. " , textures . size ( ) , textureDirectory . c_str ( ) ) ;
UDirectory : : makeDir ( textureDirectory ) ;
for ( unsigned int i = 0 ; i < textures . size ( ) ; + + i )
{
cv : : Mat rawImage = rtabmap : : uncompressImage ( textures [ i ] ) ;
std : : string texFile = textureDirectory + " / " + textureMesh . tex_materials [ i ] . tex_name + " .png " ;
cv : : imwrite ( texFile , rawImage ) ;
UINFO ( " Saved %s (%d bytes). " , texFile . c_str ( ) , rawImage . total ( ) * rawImage . channels ( ) ) ;
// relative path
textureMesh . tex_materials [ i ] . tex_file = uSplit ( UFile : : getName ( filePath ) , ' . ' ) . front ( ) + " / " + textureMesh . tex_materials [ i ] . tex_name + " .png " ;
}
UINFO ( " Saving obj to %s. " , filePath . c_str ( ) ) ;
success = pcl : : io : : saveOBJFile ( filePath , textureMesh ) = = 0 ;
2016-04-04 13:03:43 -04:00
if ( success )
{
UINFO ( " Saved obj to %s! " , filePath . c_str ( ) ) ;
}
else
{
UERROR ( " Failed saving obj to %s! " , filePath . c_str ( ) ) ;
}
2016-02-15 19:35:24 -05:00
}
}
}
2016-03-21 20:03:03 -04:00
else
2016-02-15 19:35:24 -05:00
{
2016-04-02 15:17:40 -04:00
pcl : : PointCloud < pcl : : PointXYZRGB > : : Ptr mergedClouds ( new pcl : : PointCloud < pcl : : PointXYZRGB > ) ;
2016-03-21 20:03:03 -04:00
std : : vector < pcl : : Vertices > mergedPolygons ;
2016-02-15 19:35:24 -05:00
2016-03-21 20:03:03 -04:00
{
boost : : mutex : : scoped_lock lock ( meshesMutex_ ) ;
2016-02-15 19:35:24 -05:00
2016-03-21 20:03:03 -04:00
for ( std : : map < int , Mesh > : : iterator iter = createdMeshes_ . begin ( ) ;
iter ! = createdMeshes_ . end ( ) ;
+ + iter )
{
2016-04-02 15:17:40 -04:00
pcl : : PointCloud < pcl : : PointXYZRGB > : : Ptr denseCloud ( new pcl : : PointCloud < pcl : : PointXYZRGB > ) ;
2016-03-21 20:03:03 -04:00
std : : vector < pcl : : Vertices > densePolygons ;
2016-04-02 15:17:40 -04:00
rtabmap : : util3d : : filterNotUsedVerticesFromMesh (
* iter - > second . cloud ,
iter - > second . polygons ,
* denseCloud ,
densePolygons ) ;
pcl : : PointCloud < pcl : : PointXYZRGB > : : Ptr transformedCloud = rtabmap : : util3d : : transformPointCloud ( denseCloud , iter - > second . pose ) ;
2016-03-21 20:03:03 -04:00
if ( mergedClouds - > size ( ) = = 0 )
{
* mergedClouds = * transformedCloud ;
mergedPolygons = densePolygons ;
}
else
{
rtabmap : : util3d : : appendMesh ( * mergedClouds , mergedPolygons , * transformedCloud , densePolygons ) ;
}
}
}
if ( mergedClouds - > size ( ) & & mergedPolygons . size ( ) )
{
pcl : : PolygonMesh mesh ;
pcl : : toPCLPointCloud2 ( * mergedClouds , mesh . cloud ) ;
mesh . polygons = mergedPolygons ;
2016-04-04 13:03:43 -04:00
UINFO ( " Saving ply to %s. " , filePath . c_str ( ) ) ;
2016-03-21 20:03:03 -04:00
success = pcl : : io : : savePLYFileBinary ( filePath , mesh ) = = 0 ;
2016-04-04 13:03:43 -04:00
if ( success )
{
UINFO ( " Saved ply to %s! " , filePath . c_str ( ) ) ;
}
else
{
UERROR ( " Failed saving ply to %s! " , filePath . c_str ( ) ) ;
}
2016-03-21 20:03:03 -04:00
}
2016-02-15 19:35:24 -05:00
}
return success ;
}
2016-04-04 13:03:43 -04:00
int RTABMapApp : : postProcessing ( int approach )
2016-04-03 21:35:30 -04:00
{
2016-04-04 13:03:43 -04:00
int returnedValue = 0 ;
2016-04-03 21:35:30 -04:00
if ( rtabmap_ )
{
std : : map < int , rtabmap : : Transform > poses ;
std : : multimap < int , rtabmap : : Link > links ;
2016-04-04 13:03:43 -04:00
if ( approach = = 2 | | approach = = 0 )
2016-04-03 21:35:30 -04:00
{
2016-04-04 13:03:43 -04:00
if ( approach = = 2 )
{
// detect more loop closures
returnedValue = rtabmap_ - > detectMoreLoopClosures ( ) ;
}
if ( returnedValue > = 0 )
{
// simple graph optmimization
rtabmap_ - > getGraph ( poses , links , true , true ) ;
}
2016-04-03 21:35:30 -04:00
}
2016-04-04 13:03:43 -04:00
else if ( approach = = 1 )
2016-04-03 21:35:30 -04:00
{
if ( rtabmap : : Optimizer : : isAvailable ( rtabmap : : Optimizer : : kTypeG2O ) )
{
2016-04-04 13:03:43 -04:00
std : : map < int , rtabmap : : Signature > signatures ;
rtabmap_ - > getGraph ( poses , links , false , true , & signatures ) ;
2016-04-03 21:35:30 -04:00
rtabmap : : ParametersMap param ;
2016-04-04 13:03:43 -04:00
param . insert ( rtabmap : : ParametersPair ( rtabmap : : Parameters : : kOptimizerIterations ( ) , " 30 " ) ) ;
2016-04-03 21:35:30 -04:00
rtabmap : : Optimizer * sba = rtabmap : : Optimizer : : create ( rtabmap : : Optimizer : : kTypeG2O , param ) ;
poses = sba - > optimizeBA ( poses . rbegin ( ) - > first , poses , links , signatures ) ;
delete sba ;
}
2016-04-04 13:03:43 -04:00
else
{
LOGE ( " g2o not available! " ) ;
}
}
else
{
LOGE ( " Invalid approach %d (should be 0 (graph optimization), 1 (sba) or 2 (detect more loop closures)) " , approach ) ;
returnedValue = - 1 ;
2016-04-03 21:35:30 -04:00
}
if ( poses . size ( ) )
{
boost : : mutex : : scoped_lock lock ( rtabmapMutex_ ) ;
rtabmap : : Statistics stats ;
stats . setPoses ( poses ) ;
stats . setConstraints ( links ) ;
rtabmapEvents_ . push_back ( stats ) ;
rtabmap_ - > setOptimizedPoses ( poses ) ;
}
2016-04-04 13:03:43 -04:00
else
{
returnedValue = - 1 ;
}
2016-04-03 21:35:30 -04:00
}
2016-04-04 13:03:43 -04:00
return returnedValue ;
2016-04-03 21:35:30 -04:00
}
2016-02-15 19:35:24 -05:00
void RTABMapApp : : handleEvent ( UEvent * event )
{
if ( camera_ & & camera_ - > isRunning ( ) )
{
// called from events manager thread, so protect the data
if ( event - > getClassName ( ) . compare ( " OdometryEvent " ) = = 0 )
{
LOGI ( " GUI: Received OdometryEvent! " ) ;
if ( odomMutex_ . try_lock ( ) )
{
odomEvents_ . clear ( ) ;
if ( camera_ - > isRunning ( ) )
{
odomEvents_ . push_back ( * ( ( rtabmap : : OdometryEvent * ) ( event ) ) ) ;
}
odomMutex_ . unlock ( ) ;
}
}
if ( status_ . first = = rtabmap : : RtabmapEventInit : : kInitialized & &
event - > getClassName ( ) . compare ( " RtabmapEvent " ) = = 0 )
{
LOGI ( " GUI: Received RtabmapEvent! " ) ;
int nodes = 0 ;
int words = 0 ;
int loopClosureId = 0 ;
float updateTime = 0.0f ;
int databaseMemoryUsed = 0 ;
int inliers = 0 ;
int featuresExtracted = 0 ;
float hypothesis = 0.0f ;
{
boost : : mutex : : scoped_lock lock ( rtabmapMutex_ ) ;
if ( camera_ - > isRunning ( ) )
{
rtabmapEvents_ . push_back ( ( ( rtabmap : : RtabmapEvent * ) event ) - > getStats ( ) ) ;
nodes = ( int ) uValue ( rtabmapEvents_ . back ( ) . data ( ) , rtabmap : : Statistics : : kMemoryWorking_memory_size ( ) , 0.0f ) +
uValue ( rtabmapEvents_ . back ( ) . data ( ) , rtabmap : : Statistics : : kMemoryShort_time_memory_size ( ) , 0.0f ) ;
words = ( int ) uValue ( rtabmapEvents_ . back ( ) . data ( ) , rtabmap : : Statistics : : kKeypointDictionary_size ( ) , 0.0f ) ;
updateTime = uValue ( rtabmapEvents_ . back ( ) . data ( ) , rtabmap : : Statistics : : kTimingTotal ( ) , 0.0f ) ;
2016-03-21 15:45:26 -04:00
loopClosureId = rtabmapEvents_ . back ( ) . loopClosureId ( ) > 0 ? rtabmapEvents_ . back ( ) . loopClosureId ( ) : rtabmapEvents_ . back ( ) . proximityDetectionId ( ) > 0 ? rtabmapEvents_ . back ( ) . proximityDetectionId ( ) : 0 ;
2016-02-15 19:35:24 -05:00
databaseMemoryUsed = ( int ) uValue ( rtabmapEvents_ . back ( ) . data ( ) , rtabmap : : Statistics : : kMemoryDatabase_memory_used ( ) , 0.0f ) ;
inliers = ( int ) uValue ( rtabmapEvents_ . back ( ) . data ( ) , rtabmap : : Statistics : : kLoopVisual_inliers ( ) , 0.0f ) ;
featuresExtracted = rtabmapEvents_ . back ( ) . getSignatures ( ) . size ( ) ? rtabmapEvents_ . back ( ) . getSignatures ( ) . rbegin ( ) - > second . getWords ( ) . size ( ) : 0 ;
hypothesis = uValue ( rtabmapEvents_ . back ( ) . data ( ) , rtabmap : : Statistics : : kLoopHighest_hypothesis_value ( ) , 0.0f ) ;
}
}
// Call JAVA callback with some stats
bool success = false ;
if ( jvm & & RTABMapActivity )
{
JNIEnv * env = 0 ;
jint rs = jvm - > AttachCurrentThread ( & env , NULL ) ;
if ( rs = = JNI_OK & & env )
{
jclass clazz = env - > GetObjectClass ( RTABMapActivity ) ;
if ( clazz )
{
jmethodID methodID = env - > GetMethodID ( clazz , " updateStatsCallback " , " (IIIIFIIIIFI)V " ) ;
if ( methodID )
{
env - > CallVoidMethod ( RTABMapActivity , methodID ,
nodes ,
words ,
totalPoints_ ,
totalPolygons_ ,
updateTime ,
loopClosureId ,
databaseMemoryUsed ,
inliers ,
featuresExtracted ,
hypothesis ,
lastDrawnCloudsCount_ ) ;
success = true ;
}
}
}
jvm - > DetachCurrentThread ( ) ;
}
if ( ! success )
{
UERROR ( " Failed to call RTABMapActivity::updateStatsCallback " ) ;
}
}
}
if ( event - > getClassName ( ) . compare ( " PoseEvent " ) = = 0 )
{
if ( poseMutex_ . try_lock ( ) )
{
poseEvents_ . clear ( ) ;
poseEvents_ . push_back ( ( ( rtabmap : : PoseEvent * ) event ) - > pose ( ) ) ;
poseMutex_ . unlock ( ) ;
}
}
if ( event - > getClassName ( ) . compare ( " CameraTangoEvent " ) = = 0 )
{
rtabmap : : CameraTangoEvent * tangoEvent = ( rtabmap : : CameraTangoEvent * ) event ;
// Call JAVA callback with tango event msg
bool success = false ;
if ( jvm & & RTABMapActivity )
{
JNIEnv * env = 0 ;
jint rs = jvm - > AttachCurrentThread ( & env , NULL ) ;
if ( rs = = JNI_OK & & env )
{
jclass clazz = env - > GetObjectClass ( RTABMapActivity ) ;
if ( clazz )
{
jmethodID methodID = env - > GetMethodID ( clazz , " tangoEventCallback " , " (ILjava/lang/String;Ljava/lang/String;)V " ) ;
if ( methodID )
{
env - > CallVoidMethod ( RTABMapActivity , methodID ,
tangoEvent - > type ( ) ,
env - > NewStringUTF ( tangoEvent - > key ( ) . c_str ( ) ) ,
env - > NewStringUTF ( tangoEvent - > value ( ) . c_str ( ) ) ) ;
success = true ;
}
}
}
jvm - > DetachCurrentThread ( ) ;
}
if ( ! success )
{
UERROR ( " Failed to call RTABMapActivity::tangoEventCallback " ) ;
}
}
if ( event - > getClassName ( ) . compare ( " RtabmapEventInit " ) = = 0 )
{
LOGI ( " GUI: Received RtabmapEventInit! " ) ;
status_ . first = ( ( rtabmap : : RtabmapEventInit * ) event ) - > getStatus ( ) ;
status_ . second = ( ( rtabmap : : RtabmapEventInit * ) event ) - > getInfo ( ) ;
if ( status_ . first = = rtabmap : : RtabmapEventInit : : kClosed )
{
clearSceneOnNextRender_ = true ;
}
// Call JAVA callback with init msg
bool success = false ;
if ( jvm & & RTABMapActivity )
{
JNIEnv * env = 0 ;
jint rs = jvm - > AttachCurrentThread ( & env , NULL ) ;
if ( rs = = JNI_OK & & env )
{
jclass clazz = env - > GetObjectClass ( RTABMapActivity ) ;
if ( clazz )
{
jmethodID methodID = env - > GetMethodID ( clazz , " rtabmapInitEventCallback " , " (ILjava/lang/String;)V " ) ;
if ( methodID )
{
env - > CallVoidMethod ( RTABMapActivity , methodID ,
status_ . first ,
env - > NewStringUTF ( status_ . second . c_str ( ) ) ) ;
success = true ;
}
}
}
jvm - > DetachCurrentThread ( ) ;
}
if ( ! success )
{
UERROR ( " Failed to call RTABMapActivity::rtabmapInitEventsCallback " ) ;
}
}
}