32 #include "CameraAvailability.h"
39 #include <media/NdkImage.h>
41 #ifdef RTABMAP_ARENGINE
56 #include <opencv2/opencv_modules.hpp>
69 #include <pcl/common/common.h>
70 #include <pcl/filters/extract_indices.h>
71 #include <pcl/io/ply_io.h>
72 #include <pcl/io/obj_io.h>
73 #include <pcl/surface/poisson.h>
74 #include <pcl/surface/vtk_smoothing/vtk_mesh_quadric_decimation.h>
78 #elif defined(RTABMAP_LIBLAS)
83 #define DEBUG_RENDERING_PERFORMANCE
89 static jobject RTABMapActivity = 0;
97 static void *thread_func(
void*)
101 while((rdsz = read(pfd[0], buf,
sizeof buf - 1)) > 0) {
102 if(buf[rdsz - 1] ==
'\n') --rdsz;
104 __android_log_write(ANDROID_LOG_DEBUG,
LOG_TAG, buf);
112 setvbuf(stdout, 0, _IOLBF, 0);
113 setvbuf(stderr, 0, _IONBF, 0);
121 if(pthread_create(&thr, 0, thread_func, 0) == -1)
140 parameters.insert(
rtabmap::ParametersPair(rtabmap::Parameters::kRtabmapPublishLikelihood(), std::string(
"false")));
149 parameters.insert(
rtabmap::ParametersPair(rtabmap::Parameters::kMemCompressionParallelized(), std::string(
"false")));
151 parameters.insert(
rtabmap::ParametersPair(rtabmap::Parameters::kRGBDOptimizeFromGraphEnd(), std::string(
"true")));
153 parameters.insert(
rtabmap::ParametersPair(rtabmap::Parameters::kRGBDProximityPathMaxNeighbors(), std::string(
"0")));
154 parameters.insert(
rtabmap::ParametersPair(rtabmap::Parameters::kRGBDProximityBySpace(), std::string(
"false")));
160 if(parameters.find(rtabmap::Parameters::kOptimizerStrategy()) != parameters.end())
162 if(parameters.at(rtabmap::Parameters::kOptimizerStrategy()).compare(
"2") == 0)
168 else if(parameters.at(rtabmap::Parameters::kOptimizerStrategy()).compare(
"1") == 0)
188 parameters.insert(
rtabmap::ParametersPair(rtabmap::Parameters::kIcpCorrespondenceRatio(), std::string(
"0.49")));
189 parameters.insert(
rtabmap::ParametersPair(rtabmap::Parameters::kIcpMaxCorrespondenceDistance(), std::string(
"0.05")));
220 sensorCaptureThread_(0),
224 odomCloudShown_(
true),
225 graphOptimization_(
true),
226 nodesFiltering_(
false),
227 localizationMode_(
false),
228 trajectoryMode_(
false),
229 rawScanSaved_(
false),
231 depthFromMotion_(
false),
233 fullResolution_(
false),
235 useExternalLidar_(
false),
238 cloudDensityLevel_(1),
240 meshAngleToleranceDeg_(20.0),
241 meshDecimationFactor_(0),
243 maxGainRadius_(0.02
f),
244 renderingTextureDecimation_(4),
245 backgroundColor_(0.2
f),
247 upstreamRelocalizationMaxAcc_(0.0
f),
248 exportPointCloudFormat_(
"ply"),
249 dataRecorderMode_(
false),
250 clearSceneOnNextRender_(
false),
251 openingDatabase_(
false),
253 postProcessing_(
false),
254 filterPolygonsOnNextRender_(
false),
255 gainCompensationOnNextRender_(0),
256 bilateralFilteringOnNextRender_(
false),
257 takeScreenshotOnNextRender_(
false),
258 cameraJustInitialized_(
false),
261 lastDrawnCloudsCount_(0),
262 renderingTime_(0.0
f),
263 lastPostRenderEventTime_(0.0),
264 lastPoseEventTime_(0.0),
265 visualizingMesh_(
false),
266 exportedMeshUpdated_(
false),
267 optMesh_(new
pcl::TextureMesh),
270 mapToOdom_(
rtabmap::Transform::getIdentity())
276 env->GetJavaVM(&jvm);
277 RTABMapActivity =
env->NewGlobalRef(caller_activity);
280 LOGI(
"RTABMapApp::RTABMapApp()");
281 createdMeshes_.clear();
283 clearSceneOnNextRender_ =
true;
284 openingDatabase_ =
false;
286 postProcessing_=
false;
289 lastDrawnCloudsCount_ = 0;
290 renderingTime_ = 0.0f;
291 lastPostRenderEventTime_ = 0.0;
292 lastPoseEventTime_ = 0.0;
293 bufferedStatsData_.clear();
295 progressionStatus_.setJavaObjects(jvm, RTABMapActivity);
297 main_scene_.setBackgroundColor(backgroundColor_, backgroundColor_, backgroundColor_);
301 this->registerToEventsManager();
302 LOGI(
"RTABMapApp::RTABMapApp() end");
311 #ifndef __ANDROID__ // __APPLE__
313 void(*progressCallback)(
void *,
int,
int),
314 void(*initCallback)(
void *,
int,
const char*),
315 void(*statsUpdatedCallback)(
void *,
318 int,
int,
int,
int,
int ,
int,
323 float,
float,
float,
float,
325 float,
float,
float,
float,
float,
float),
326 void(*cameraInfoEventCallback)(
void *,
int,
const char*,
const char*))
337 LOGI(
"~RTABMapApp() begin");
357 LOGI(
"~RTABMapApp() end");
375 LOGW(
"Opening database %s (inMemory=%d, optimize=%d, clearDatabase=%d)", databasePath.c_str(), databaseInMemory?1:0,
optimize?1:0, clearDatabase?1:0);
388 bool restartThread =
false;
413 optMesh_.reset(
new pcl::TextureMesh);
422 std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > polygons;
423 #if PCL_VERSION_COMPARE(>=, 1, 8, 0)
424 std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > texCoords;
426 std::vector<std::vector<Eigen::Vector2f> > texCoords;
429 if(!databasePath.empty() &&
UFile::exists(databasePath) && !clearDatabase)
436 if(!cloudMat.empty())
438 LOGI(
"Open: Found optimized mesh! Visualizing it.");
446 else if(
optMesh_->tex_polygons.size())
448 LOGI(
"Open: Polygon mesh");
451 else if(!
optMesh_->cloud.data.empty())
453 LOGI(
"Open: Point cloud");
459 LOGI(
"Open: No optimized mesh found.");
487 LOGI(
"Erasing database \"%s\"...", databasePath.c_str());
497 LOGI(
"Initializing database...");
500 if(parameters.find(rtabmap::Parameters::kRtabmapDetectionRate()) != parameters.end())
506 std::map<int, rtabmap::Signature> signatures;
507 std::map<int, rtabmap::Transform> poses;
508 std::multimap<int, rtabmap::Link> links;
509 LOGI(
"Loading full map from database...");
522 if(signatures.size() && poses.empty())
524 LOGE(
"Failed to optimize the graph!");
529 LOGI(
"Creating the meshes (%d)....", (
int)poses.size());
535 for(std::map<int, rtabmap::Transform>::iterator
iter=poses.begin();
iter!=poses.end() && status>=0; ++
iter)
539 int id =
iter->first;
540 if(!
iter->second.isNull())
546 rawPoses_.insert(std::make_pair(
id, signatures.at(
id).getPose()));
549 data.uncompressData(&tmpA, &depth);
551 if(!(!
data.imageRaw().empty() && !
data.depthRaw().empty()) && !
data.laserScanCompressed().isEmpty())
554 data.uncompressData(0, 0, &scan);
557 if((!
data.imageRaw().empty() && !
data.depthRaw().empty()) || !
data.laserScanRaw().isEmpty())
560 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud;
561 pcl::IndicesPtr
indices(
new std::vector<int>);
572 indices->resize(cloud->size());
573 for(
unsigned int i=0;
i<cloud->size(); ++
i)
579 if(cloud->size() &&
indices->size())
581 std::vector<pcl::Vertices> polygons;
582 std::vector<pcl::Vertices> polygonsLowRes;
583 #if PCL_VERSION_COMPARE(>=, 1, 8, 0)
584 std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > texCoords;
586 std::vector<Eigen::Vector2f> texCoords;
594 pcl::PolygonMesh::Ptr tmpMesh(
new pcl::PolygonMesh);
595 pcl::toPCLPointCloud2(*cloud, tmpMesh->cloud);
596 tmpMesh->polygons = polygons;
597 rtabmap::util3d::denseMeshPostProcessing<pcl::PointXYZRGB>(tmpMesh,
meshDecimationFactor_, 0, cloud, 0);
598 if(!tmpMesh->polygons.empty())
603 std::map<int, rtabmap::CameraModel> cameraModels;
605 cameraModels.insert(std::make_pair(0,
data.cameraModels()[0]));
610 std::map<int, cv::Mat>());
611 pcl::fromPCLPointCloud2(textureMesh->cloud, *cloud);
612 polygons = textureMesh->tex_polygons[0];
613 texCoords = textureMesh->tex_coordinates[0];
617 pcl::fromPCLPointCloud2(tmpMesh->cloud, *cloud);
618 polygons = tmpMesh->polygons;
621 indices->resize(cloud->size());
622 for(
unsigned int i=0;
i<cloud->size(); ++
i)
632 #ifdef DEBUG_RENDERING_PERFORMANCE
633 LOGW(
"Mesh simplication, %d polygons, %d points (%fs)", (
int)polygons.size(), (
int)cloud->size(),
timer.ticks());
645 inserted.first->second.cloud = cloud;
646 inserted.first->second.indices =
indices;
647 inserted.first->second.polygons = polygons;
648 inserted.first->second.polygonsLowRes = polygonsLowRes;
649 inserted.first->second.visible =
true;
650 inserted.first->second.cameraModel =
data.cameraModels()[0];
651 inserted.first->second.gains[0] = 1.0;
652 inserted.first->second.gains[1] = 1.0;
653 inserted.first->second.gains[2] = 1.0;
656 inserted.first->second.texCoords = texCoords;
660 cv::resize(
data.imageRaw(), inserted.first->second.texture, reducedSize, 0, 0, cv::INTER_LINEAR);
664 inserted.first->second.texture =
data.imageRaw();
667 LOGI(
"Created cloud %d (%fs, %d points)",
id,
timer.ticks(), (
int)cloud->size());
671 UWARN(
"Cloud %d is empty",
id);
674 else if(!
data.depthOrRightCompressed().empty() || !
data.laserScanCompressed().isEmpty())
676 UERROR(
"Failed to uncompress data! (rgb=%d, depth=%d, scan=%d)",
data.imageCompressed().cols,
data.depthOrRightCompressed().cols,
data.laserScanCompressed().size());
682 UWARN(
"Data for node %d not found",
id);
687 UWARN(
"Pose %d is null !?",
id);
698 UERROR(
"Exception! msg=\"%s\"",
e.what());
701 catch (
const cv::Exception &
e)
703 UERROR(
"Exception! msg=\"%s\"",
e.what());
706 catch (
const std::exception &
e)
708 UERROR(
"Exception! msg=\"%s\"",
e.what());
730 LOGI(
"Polygon filtering...");
735 if(
iter->second.polygons.size())
744 LOGI(
"Open: add rtabmap event to update the scene");
749 stats.setPoses(poses);
750 stats.setConstraints(links);
793 if(poses.empty() || status>0)
808 if((height >= 480 || width >= 480) && width % 20 == 0 && height % 20 == 0)
812 else if(width % 15 == 0 && height % 15 == 0)
816 else if(width % 10 == 0 && height % 10 == 0)
820 else if(width % 8 == 0 && height % 8 == 0)
826 UERROR(
"Could not set decimation to high (size=%dx%d)", width, height);
831 if((height >= 480 || width >= 480) && width % 10 == 0 && height % 10 == 0)
835 else if(width % 5 == 0 && height % 5 == 0)
839 else if(width % 4 == 0 && height % 4 == 0)
845 UERROR(
"Could not set decimation to medium (size=%dx%d)", width, height);
850 if((height >= 480 || width >= 480) && width % 5 == 0 && height % 5 == 0)
854 else if(width % 3 == 0 && width % 3 == 0)
858 else if(width % 2 == 0 && width % 2 == 0)
864 UERROR(
"Could not set decimation to low (size=%dx%d)", width, height);
874 if(cameraDriver == 0)
883 if(cameraDriver == 1)
885 #ifdef RTABMAP_ARCORE
892 if(cameraDriver == 2)
894 #ifdef RTABMAP_ARENGINE
915 cameraDriver_ = driver;
919 LOGW(
"startCamera() camera driver=%d", cameraDriver_);
920 boost::mutex::scoped_lock lock(cameraMutex_);
922 if(cameraDriver_ == 0)
925 camera_ =
new rtabmap::CameraTango(cameraColor_, !cameraColor_ || fullResolution_?1:2, rawScanSaved_, smoothing_);
927 if (TangoService_setBinder(
env, iBinder) != TANGO_SUCCESS) {
928 UERROR(
"TangoHandler::ConnectTango, TangoService_setBinder error");
934 UERROR(
"RTAB-Map is not built with Tango support!");
937 else if(cameraDriver_ == 1)
939 #ifdef RTABMAP_ARCORE
940 camera_ =
new rtabmap::CameraARCore(
env, context, activity, depthFromMotion_, smoothing_, upstreamRelocalizationMaxAcc_);
942 UERROR(
"RTAB-Map is not built with ARCore support!");
945 else if(cameraDriver_ == 2)
947 #ifdef RTABMAP_ARENGINE
950 UERROR(
"RTAB-Map is not built with AREngine support!");
953 else if(cameraDriver_ == 3)
960 UERROR(
"Unknown or not supported camera driver! %d", cameraDriver_);
964 if(rtabmapThread_ && dataRecorderMode_)
967 camera_->setFrameRate(rtabmapThread_->getDetectorRate());
968 rtabmapThread_->setDetectorRate(0);
973 camera_->setScreenRotationAndSize(main_scene_.getScreenRotation(), main_scene_.getViewPortWidth(), main_scene_.getViewPortHeight());
976 LOGI(
"Cloud density level %d", cloudDensityLevel_);
978 LOGI(
"Start camera thread");
979 cameraJustInitialized_ =
true;
980 if(useExternalLidar_)
984 camera_->setImageRate(0);
986 sensorCaptureThread_->setScanParameters(
false, 1, 0.0
f, 0.0
f, 0.0
f, 0, 0.0
f, 0.0
f,
true);
992 sensorCaptureThread_->start();
995 UERROR(
"Failed camera initialization!");
1001 LOGI(
"stopCamera()");
1021 const std::vector<pcl::Vertices> & polygons,
1022 int cloudSize)
const
1024 std::vector<int> vertexToCluster(cloudSize, 0);
1025 std::map<int, std::list<int> > clusters;
1026 int lastClusterID = 0;
1028 for(
unsigned int i=0;
i<polygons.size(); ++
i)
1031 for(
unsigned int j=0;
j<polygons[
i].vertices.size(); ++
j)
1033 if(vertexToCluster[polygons[
i].
vertices[
j]]>0)
1035 clusterID = vertexToCluster[polygons[
i].vertices[
j]];
1041 clusters.at(clusterID).push_back(
i);
1045 clusterID = ++lastClusterID;
1046 std::list<int> polygons;
1047 polygons.push_back(
i);
1048 clusters.insert(std::make_pair(clusterID, polygons));
1050 for(
unsigned int j=0;
j<polygons[
i].vertices.size(); ++
j)
1052 vertexToCluster[polygons[
i].vertices[
j]] = clusterID;
1056 unsigned int biggestClusterSize = 0;
1057 for(std::map<
int, std::list<int> >::
iterator iter=clusters.begin();
iter!=clusters.end(); ++
iter)
1061 if(
iter->second.size() > biggestClusterSize)
1063 biggestClusterSize =
iter->second.size();
1066 unsigned int minClusterSize = (
unsigned int)(
float(biggestClusterSize)*
clusterRatio_);
1070 std::vector<pcl::Vertices> filteredPolygons(polygons.size());
1072 for(std::map<
int, std::list<int> >::
iterator iter=clusters.begin();
iter!=clusters.end(); ++
iter)
1074 if(
iter->second.size() >= minClusterSize)
1076 for(std::list<int>::iterator jter=
iter->second.begin(); jter!=
iter->second.end(); ++jter)
1078 filteredPolygons[oi++] = polygons[*jter];
1082 filteredPolygons.resize(oi);
1083 return filteredPolygons;
1088 const std::vector<pcl::Vertices> & polygons,
1089 int cloudSize)
const
1092 std::vector<std::set<int> > neighbors;
1093 std::vector<std::set<int> > vertexToPolygons;
1101 unsigned int biggestClusterSize = 0;
1104 if(
iter->size() > biggestClusterSize)
1106 biggestClusterSize =
iter->size();
1109 unsigned int minClusterSize = (
unsigned int)(
float(biggestClusterSize)*
clusterRatio_);
1110 LOGI(
"Biggest cluster = %d -> minClusterSize(ratio=%f)=%d",
1113 std::vector<pcl::Vertices> filteredPolygons(polygons.size());
1115 for(std::list<std::list<int> >::
iterator jter=clusters.begin(); jter!=clusters.end(); ++jter)
1117 if(jter->size() >= minClusterSize)
1119 for(std::list<int>::iterator kter=jter->begin(); kter!=jter->end(); ++kter)
1121 filteredPolygons[oi++] = polygons.at(*kter);
1125 filteredPolygons.resize(oi);
1126 return filteredPolygons;
1176 cv::Mat depth = cv::Mat::zeros(mesh.
cloud->height, mesh.
cloud->width, CV_32FC1);
1178 for(
unsigned int i=0;
i<mesh.
indices->size(); ++
i)
1182 if(mesh.
cloud->at(index).x > 0)
1185 depth.at<
float>(index) = pt.z;
1190 LOGI(
"smoothMesh() Bilateral filtering of %d, time=%fs",
id,
t.ticks());
1192 if(!depth.empty() && mesh.
indices->size())
1194 pcl::IndicesPtr newIndices(
new std::vector<int>(mesh.
indices->size()));
1196 for(
unsigned int i=0;
i<mesh.
indices->size(); ++
i)
1200 pcl::PointXYZRGB & pt = mesh.
cloud->at(index);
1202 if(depth.at<
float>(index) > 0)
1204 newPt.z = depth.at<
float>(index);
1206 newIndices->at(oi++) = index;
1210 newPt.x = newPt.y = newPt.z = std::numeric_limits<float>::quiet_NaN();
1216 newIndices->resize(oi);
1220 std::vector<pcl::Vertices> polygons;
1225 LOGI(
"smoothMesh() Reconstructing the mesh of %d, time=%fs",
id,
t.ticks());
1230 UERROR(
"smoothMesh() Failed to smooth surface %d",
id);
1238 UTimer tGainCompensation;
1239 LOGI(
"Gain compensation...");
1242 std::map<int, pcl::PointCloud<pcl::PointXYZRGB>::Ptr > clouds;
1243 std::map<int, pcl::IndicesPtr>
indices;
1246 clouds.insert(std::make_pair(
iter->first,
iter->second.cloud));
1249 std::map<int, rtabmap::Transform> poses;
1250 std::multimap<int, rtabmap::Link> links;
1256 for(std::map<
int, pcl::PointCloud<pcl::PointXYZRGB>::Ptr>::const_iterator
iter=clouds.begin();
iter!=clouds.end(); ++
iter)
1258 int from =
iter->first;
1259 std::map<int, pcl::PointCloud<pcl::PointXYZRGB>::Ptr>::const_iterator jter =
iter;
1261 for(;jter!=clouds.end(); ++jter)
1263 int to = jter->first;
1271 if(clouds.size() > 1 && links.size())
1274 LOGI(
"Gain compensation... compute gain: links=%d, time=%fs", (
int)links.size(), tGainCompensation.
ticks());
1279 if(!
iter->second.cloud->empty())
1281 if(clouds.size() > 1 && links.size())
1284 LOGI(
"%d mesh has gain %f,%f,%f",
iter->first,
iter->second.gains[0],
iter->second.gains[1],
iter->second.gains[2]);
1288 LOGI(
"Gain compensation... applying gain: meshes=%d, time=%fs", (
int)
createdMeshes_.size(), tGainCompensation.
ticks());
1294 std::list<rtabmap::RtabmapEvent*> rtabmapEvents;
1303 #ifdef DEBUG_RENDERING_PERFORMANCE
1308 bool notifyDataLoaded =
false;
1309 bool notifyCameraStarted =
false;
1317 const float* uvsTransformed = 0;
1330 #ifdef DEBUG_RENDERING_PERFORMANCE
1331 LOGD(
"Camera updateOnRender %fs",
time.ticks());
1355 pcl::IndicesPtr
indices(
new std::vector<int>);
1359 occlusionMesh.
cloud.reset(
new pcl::PointCloud<pcl::PointXYZRGB>());
1360 pcl::copyPointCloud(*cloud, *occlusionMesh.
cloud);
1364 else if(!occlusionImage.empty())
1366 UERROR(
"invalid occlusionModel: %f %f %f %f %dx%d", occlusionModel.
fx(), occlusionModel.
fy(), occlusionModel.
cx(), occlusionModel.
cy(), occlusionModel.
imageWidth(), occlusionModel.
imageHeight());
1369 #ifdef DEBUG_RENDERING_PERFORMANCE
1370 LOGD(
"Update background and occlusion mesh %fs",
time.ticks());
1391 LOGI(
"Process sensor events");
1396 notifyCameraStarted =
true;
1415 notifyCameraStarted =
true;
1430 LOGI(
"Adding optimized mesh to opengl (%d points, %d polygons, %d tex_coords, materials=%d texture=%dx%d)...",
1433 optMesh_->tex_coordinates.size()!=1?0:(
int)
optMesh_->tex_coordinates[0].size(),
1434 (
int)
optMesh_->tex_materials.size(),
1440 mesh.
cloud.reset(
new pcl::PointCloud<pcl::PointXYZRGB>);
1441 mesh.
normals.reset(
new pcl::PointCloud<pcl::Normal>);
1446 if(
optMesh_->tex_coordinates.size())
1455 pcl::IndicesPtr
indices(
new std::vector<int>);
1456 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(
new pcl::PointCloud<pcl::PointXYZRGB>);
1457 pcl::fromPCLPointCloud2(
optMesh_->cloud, *cloud);
1469 if(rtabmapEvents.size())
1472 if(!
stats.mapCorrection().isNull())
1477 std::map<int, rtabmap::Transform>::const_iterator
iter =
stats.poses().find(
optRefId_);
1483 int fastMovement = (
int)
uValue(
stats.data(), rtabmap::Statistics::kMemoryFast_movement(), 0.0f);
1484 int loopClosure = (
int)
uValue(
stats.data(), rtabmap::Statistics::kLoopAccepted_hypothesis_id(), 0.0f);
1485 int proximityClosureId =
int(
uValue(
stats.data(), rtabmap::Statistics::kProximitySpace_last_detection_id(), 0.0f));
1486 int rejected = (
int)
uValue(
stats.data(), rtabmap::Statistics::kLoopRejectedHypothesis(), 0.0f);
1487 int landmark = (
int)
uValue(
stats.data(), rtabmap::Statistics::kLoopLandmark_detected(), 0.0f);
1521 for(std::map<int, rtabmap::Transform>::const_iterator
iter=
stats.poses().begin();
1525 int id =
iter->first;
1556 if(rtabmapEvents.size())
1559 if(rtabmapEvents.back()->getStats().refImageId()>0 ||
1560 !rtabmapEvents.back()->getStats().data().empty())
1563 rtabmapEvents.pop_back();
1566 for(std::list<rtabmap::RtabmapEvent*>::iterator
iter=rtabmapEvents.begin();
iter!=rtabmapEvents.end(); ++
iter)
1570 rtabmapEvents.clear();
1579 optMesh_.reset(
new pcl::TextureMesh);
1596 if(rtabmapEvents.front()->getStats().refImageId()>0 && rtabmapEvents.front()->getStats().refImageId() <
createdMeshes_.rbegin()->first)
1598 LOGI(
"Detected new database! new=%d old=%d", rtabmapEvents.front()->getStats().refImageId(),
createdMeshes_.rbegin()->first);
1603 #ifdef DEBUG_RENDERING_PERFORMANCE
1604 if(rtabmapEvents.size())
1606 LOGW(
"begin and getting rtabmap events %fs",
time.ticks());
1613 LOGI(
"Clearing all rendering data...");
1627 LOGI(
"Clearing meshes...");
1633 notifyDataLoaded =
true;
1651 if(added.size() != meshes)
1653 LOGI(
"added (%d) != meshes (%d)", (
int)added.size(), meshes);
1660 LOGI(
"Re-add mesh %d to OpenGL context",
iter->first);
1671 if(!textureRaw.empty())
1676 LOGD(
"resize image from %dx%d to %dx%d", textureRaw.cols, textureRaw.rows, reducedSize.width, reducedSize.height);
1677 cv::resize(textureRaw,
iter->second.texture, reducedSize, 0, 0, cv::INTER_LINEAR);
1681 iter->second.texture = textureRaw;
1688 iter->second.texture = cv::Mat();
1693 else if(notifyDataLoaded)
1702 if(rtabmapEvents.size())
1704 #ifdef DEBUG_RENDERING_PERFORMANCE
1705 LOGW(
"Process rtabmap events %fs",
time.ticks());
1707 LOGI(
"Process rtabmap events");
1711 std::map<int, rtabmap::SensorData> bufferedSensorData;
1714 for(std::list<rtabmap::RtabmapEvent*>::iterator
iter=rtabmapEvents.begin();
iter!=rtabmapEvents.end(); ++
iter)
1719 int smallMovement = (
int)
uValue(
stats.data(), rtabmap::Statistics::kMemorySmall_movement(), 0.0f);
1720 int fastMovement = (
int)
uValue(
stats.data(), rtabmap::Statistics::kMemoryFast_movement(), 0.0f);
1721 int rehearsalMerged = (
int)
uValue(
stats.data(), rtabmap::Statistics::kMemoryRehearsal_merged(), 0.0f);
1723 smallMovement == 0 && rehearsalMerged == 0 && fastMovement == 0)
1725 int id =
stats.getLastSignatureData().id();
1729 ((!
s.sensorData().imageRaw().empty() && !
s.sensorData().depthRaw().empty()) ||
1730 !
s.sensorData().laserScanRaw().isEmpty()))
1732 uInsert(bufferedSensorData, std::make_pair(
id,
s.sensorData()));
1738 int loopClosure = (
int)
uValue(
stats.data(), rtabmap::Statistics::kLoopAccepted_hypothesis_id(), 0.0f);
1739 int proximityClosureId =
int(
uValue(
stats.data(), rtabmap::Statistics::kProximitySpace_last_detection_id(), 0.0f));
1740 int rejected = (
int)
uValue(
stats.data(), rtabmap::Statistics::kLoopRejectedHypothesis(), 0.0f);
1741 int landmark = (
int)
uValue(
stats.data(), rtabmap::Statistics::kLoopLandmark_detected(), 0.0f);
1773 #ifdef DEBUG_RENDERING_PERFORMANCE
1774 LOGW(
"Looking for data to load (%d) %fs", (
int)bufferedSensorData.size(),
time.ticks());
1777 std::map<int, rtabmap::Transform> posesWithMarkers = rtabmapEvents.back()->getStats().poses();
1778 if(!rtabmapEvents.back()->getStats().mapCorrection().isNull())
1780 mapToOdom_ = rtabmapEvents.back()->getStats().mapCorrection();
1784 for(std::map<int, rtabmap::Transform>::iterator
iter=posesWithMarkers.begin();
iter!=posesWithMarkers.end(); ++
iter)
1788 std::map<int, rtabmap::Transform>::iterator jter =
rawPoses_.find(
iter->first);
1800 std::map<int, rtabmap::Transform> poses(posesWithMarkers.lower_bound(0), posesWithMarkers.end());
1801 const std::multimap<int, rtabmap::Link> & links = rtabmapEvents.back()->getStats().constraints();
1807 #ifdef DEBUG_RENDERING_PERFORMANCE
1808 LOGW(
"Update graph: %fs",
time.ticks());
1813 std::set<std::string> strIds;
1814 for(std::map<int, rtabmap::Transform>::iterator
iter=poses.begin();
iter!=poses.end(); ++
iter)
1816 int id =
iter->first;
1817 if(!
iter->second.isNull())
1824 std::map<int, rtabmap::Mesh>::iterator meshIter =
createdMeshes_.find(
id);
1827 meshIter->second.visible =
true;
1832 bufferedSensorData.find(
id) != bufferedSensorData.end())
1836 cv::Mat tmpA, depth;
1837 data.uncompressData(&tmpA, &depth);
1838 if(!(!
data.imageRaw().empty() && !
data.depthRaw().empty()) && !
data.laserScanCompressed().isEmpty())
1841 data.uncompressData(0, 0, &scan);
1843 #ifdef DEBUG_RENDERING_PERFORMANCE
1844 LOGW(
"Decompressing data: %fs",
time.ticks());
1847 if((!
data.imageRaw().empty() && !
data.depthRaw().empty()) || !
data.laserScanRaw().isEmpty())
1850 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud;
1851 pcl::IndicesPtr
indices(
new std::vector<int>);
1861 indices->resize(cloud->size());
1862 for(
unsigned int i=0;
i<cloud->size(); ++
i)
1867 #ifdef DEBUG_RENDERING_PERFORMANCE
1868 LOGW(
"Creating node cloud %d (depth=%dx%d rgb=%dx%d, %fs)",
id,
data.depthRaw().cols,
data.depthRaw().rows,
data.imageRaw().cols,
data.imageRaw().rows,
time.ticks());
1870 if(cloud->size() &&
indices->size())
1872 std::vector<pcl::Vertices> polygons;
1873 std::vector<pcl::Vertices> polygonsLowRes;
1874 #if PCL_VERSION_COMPARE(>=, 1, 8, 0)
1875 std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > texCoords;
1877 std::vector<Eigen::Vector2f> texCoords;
1879 pcl::PointCloud<pcl::Normal>::Ptr normals(
new pcl::PointCloud<pcl::Normal>);
1883 #ifdef DEBUG_RENDERING_PERFORMANCE
1884 LOGW(
"Creating mesh, %d polygons (%fs)", (
int)polygons.size(),
time.ticks());
1889 pcl::PolygonMesh::Ptr tmpMesh(
new pcl::PolygonMesh);
1890 pcl::toPCLPointCloud2(*cloud, tmpMesh->cloud);
1891 tmpMesh->polygons = polygons;
1892 rtabmap::util3d::denseMeshPostProcessing<pcl::PointXYZRGB>(tmpMesh,
meshDecimationFactor_, 0, cloud, 0);
1894 if(!tmpMesh->polygons.empty())
1899 std::map<int, rtabmap::CameraModel> cameraModels;
1901 cameraModels.insert(std::make_pair(0,
data.cameraModels()[0]));
1906 std::map<int, cv::Mat>());
1907 pcl::fromPCLPointCloud2(textureMesh->cloud, *cloud);
1908 polygons = textureMesh->tex_polygons[0];
1909 texCoords = textureMesh->tex_coordinates[0];
1913 pcl::fromPCLPointCloud2(tmpMesh->cloud, *cloud);
1914 polygons = tmpMesh->polygons;
1917 indices->resize(cloud->size());
1918 for(
unsigned int i=0;
i<cloud->size(); ++
i)
1927 #ifdef DEBUG_RENDERING_PERFORMANCE
1928 LOGW(
"Creating mesh, %d polygons (%fs)", (
int)polygons.size(),
time.ticks());
1931 #ifdef DEBUG_RENDERING_PERFORMANCE
1932 LOGW(
"Mesh simplication, %d polygons, %d points (%fs)", (
int)polygons.size(), (
int)cloud->size(),
time.ticks());
1939 #ifdef DEBUG_RENDERING_PERFORMANCE
1940 LOGW(
"Creating mesh, %d polygons (%fs)", (
int)polygons.size(),
time.ticks());
1947 inserted.first->second.cloud = cloud;
1948 inserted.first->second.indices =
indices;
1949 inserted.first->second.polygons = polygons;
1950 inserted.first->second.polygonsLowRes = polygonsLowRes;
1951 inserted.first->second.visible =
true;
1952 inserted.first->second.cameraModel =
data.cameraModels()[0];
1953 inserted.first->second.gains[0] = 1.0;
1954 inserted.first->second.gains[1] = 1.0;
1955 inserted.first->second.gains[2] = 1.0;
1958 inserted.first->second.texCoords = texCoords;
1962 cv::resize(
data.imageRaw(), inserted.first->second.texture, reducedSize, 0, 0, cv::INTER_LINEAR);
1963 #ifdef DEBUG_RENDERING_PERFORMANCE
1964 LOGW(
"resize image from %dx%d to %dx%d (%fs)",
data.imageRaw().cols,
data.imageRaw().rows, reducedSize.width, reducedSize.height,
time.ticks());
1969 inserted.first->second.texture =
data.imageRaw();
1982 #ifdef DEBUG_RENDERING_PERFORMANCE
1983 LOGW(
"Adding mesh to scene: %fs",
time.ticks());
1993 if(poses.size() > 2)
1997 for(std::multimap<int, rtabmap::Link>::const_iterator
iter=links.begin();
iter!=links.end(); ++
iter)
2001 int oldId =
iter->second.to()>
iter->second.from()?
iter->second.from():
iter->second.to();
2013 for(std::set<int>::const_iterator
iter=addedClouds.begin();
2014 iter!=addedClouds.end();
2017 if(*
iter > 0 && poses.find(*
iter) == poses.end())
2022 meshIter->second.visible =
false;
2029 for(std::set<int>::const_iterator
iter=addedMarkers.begin();
2030 iter!=addedMarkers.end();
2033 if(posesWithMarkers.find(*
iter) == posesWithMarkers.end())
2038 for(std::map<int, rtabmap::Transform>::const_iterator
iter=posesWithMarkers.begin();
2039 iter!=posesWithMarkers.end() &&
iter->first<0;
2042 int id =
iter->first;
2066 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud;
2067 pcl::IndicesPtr
indices(
new std::vector<int>);
2077 indices->resize(cloud->size());
2078 for(
unsigned int i=0;
i<cloud->size(); ++
i)
2084 if(cloud->size() &&
indices->size())
2086 LOGI(
"Created odom cloud (rgb=%dx%d depth=%dx%d cloud=%dx%d)",
2089 (
int)cloud->width, (
int)cloud->height);
2095 UERROR(
"Generated cloud is empty!");
2100 UWARN(
"Odom data images/scans are empty!");
2114 notifyDataLoaded =
true;
2119 LOGI(
"Bilateral filtering...");
2124 if(
iter->second.cloud->size() &&
iter->second.indices->size())
2132 notifyDataLoaded =
true;
2137 LOGI(
"Polygon filtering...");
2143 if(
iter->second.polygons.size())
2150 notifyDataLoaded =
true;
2161 if(rtabmapEvents.size())
2165 if(rtabmapEvents.back()->getStats().refImageId()>0 ||
2166 !rtabmapEvents.back()->getStats().data().empty())
2169 rtabmapEvents.pop_back();
2172 for(std::list<rtabmap::RtabmapEvent*>::iterator
iter=rtabmapEvents.begin();
iter!=rtabmapEvents.end(); ++
iter)
2176 rtabmapEvents.clear();
2182 UERROR(
"TangoPoseEventNotReceived");
2193 cv::Mat image(
h,
w, CV_8UC4);
2194 glReadPixels(0, 0,
w,
h, GL_RGBA, GL_UNSIGNED_BYTE, image.data);
2195 cv::flip(image, image, 0);
2196 cv::cvtColor(image, image, cv::COLOR_RGBA2BGRA);
2209 LOGI(
"Saving screenshot %dx%d...", roi.cols, roi.rows);
2218 double updateInterval = 1.0;
2228 if(interval >= updateInterval)
2239 return notifyDataLoaded||notifyCameraStarted?1:0;
2243 for(std::list<rtabmap::RtabmapEvent*>::iterator
iter=rtabmapEvents.begin();
iter!=rtabmapEvents.end(); ++
iter)
2247 rtabmapEvents.clear();
2248 UERROR(
"Exception! msg=\"%s\"",
e.what());
2251 catch(
const cv::Exception &
e)
2253 for(std::list<rtabmap::RtabmapEvent*>::iterator
iter=rtabmapEvents.begin();
iter!=rtabmapEvents.end(); ++
iter)
2257 rtabmapEvents.clear();
2258 UERROR(
"Exception! msg=\"%s\"",
e.what());
2261 catch(
const std::exception &
e)
2263 for(std::list<rtabmap::RtabmapEvent*>::iterator
iter=rtabmapEvents.begin();
iter!=rtabmapEvents.end(); ++
iter)
2267 rtabmapEvents.clear();
2268 UERROR(
"Exception! msg=\"%s\"",
e.what());
2280 float x0,
float y0,
float x1,
float y1) {
2374 std::map<int, rtabmap::Transform> poses;
2375 std::multimap<int, rtabmap::Link> links;
2381 stats.setPoses(poses);
2382 stats.setConstraints(links);
2384 LOGI(
"Send rtabmap event to update graph...");
2540 #if defined(RTABMAP_PDAL) || defined(RTABMAP_LIBLAS)
2547 UERROR(
"Not supported point cloud format %s",
format.c_str());
2556 std::string compatibleKey =
key;
2562 if(
iter->second.first)
2565 compatibleKey =
iter->second.second;
2566 LOGW(
"Parameter name changed: \"%s\" -> \"%s\". Please update the code accordingly. Value \"%s\" is still set to the new parameter name.",
2567 iter->first.c_str(),
iter->second.second.c_str(),
value.c_str());
2571 if(
iter->second.second.empty())
2573 UERROR(
"Parameter \"%s\" doesn't exist anymore!",
2574 iter->first.c_str());
2578 UERROR(
"Parameter \"%s\" doesn't exist anymore! You may look at this similar parameter: \"%s\"",
2579 iter->first.c_str(),
iter->second.second.c_str());
2586 LOGI(
"%s",
uFormat(
"Setting param \"%s\" to \"%s\"", compatibleKey.c_str(),
value.c_str()).c_str());
2593 UERROR(
uFormat(
"Key \"%s\" doesn't exist!", compatibleKey.c_str()).c_str());
2618 LOGI(
"Saving database to %s", databasePath.c_str());
2622 LOGI(
"Taking screenshot...");
2626 UERROR(
"Failed to take a screenshot after 2 sec!");
2648 if(appendModeBackup || dataRecorderModeBackup || localizationModeBackup)
2673 std::string errorMsg;
2676 LOGE(
"Recovery Error: %s", errorMsg.c_str());
2681 LOGI(
"Renaming %s to %s", from.c_str(), to.c_str());
2684 LOGE(
"Failed renaming %s to %s", from.c_str(), to.c_str());
2693 UWARN(
"Processing canceled!");
2698 float cloudVoxelSize,
2699 bool regenerateCloud,
2705 float optimizedVoxelSize,
2707 int optimizedMaxPolygons,
2708 float optimizedColorRadius,
2709 bool optimizedCleanWhitePolygons,
2710 int optimizedMinClusterSize,
2711 float optimizedMaxTextureDistance,
2712 int optimizedMinTextureClusterSize,
2713 bool blockRendering)
2722 std::multimap<int, rtabmap::Link> links;
2730 UERROR(
"Empty optimized poses!");
2744 bool success =
false;
2749 totalSteps+=poses.size();
2754 totalSteps += poses.size();
2760 if(optimizedMaxPolygons > 0)
2770 totalSteps+=poses.size()+1;
2775 totalSteps += poses.size()+1;
2785 pcl::PolygonMesh::Ptr polygonMesh(
new pcl::PolygonMesh);
2786 pcl::TextureMesh::Ptr textureMesh(
new pcl::TextureMesh);
2787 std::vector<std::map<int, pcl::PointXY> > vertexToPixels;
2788 cv::Mat globalTextures;
2789 int totalPolygons = 0;
2794 std::map<int, rtabmap::CameraModel> cameraModels;
2795 std::map<int, cv::Mat> cameraDepths;
2798 LOGI(
"Assemble clouds (%d)...", (
int)poses.size());
2802 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr mergedClouds(
new pcl::PointCloud<pcl::PointXYZRGBNormal>);
2803 for(std::map<int, rtabmap::Transform>::iterator
iter=poses.begin();
2808 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(
new pcl::PointCloud<pcl::PointXYZRGB>);
2809 pcl::IndicesPtr
indices(
new std::vector<int>);
2813 gains[0] = gains[1] = gains[2] = 1.0f;
2816 cloud = jter->second.cloud;
2817 indices = jter->second.indices;
2818 model = jter->second.cameraModel;
2819 gains[0] = jter->second.gains[0];
2820 gains[1] = jter->second.gains[1];
2821 gains[2] = jter->second.gains[2];
2824 data.uncompressData(0, &depth);
2829 data.uncompressData();
2830 if(!
data.imageRaw().empty() && !
data.depthRaw().empty() &&
data.cameraModels().size() == 1)
2835 depth =
data.depthRaw();
2838 if(cloud->size() &&
indices->size() &&
model.isValidForProjection())
2840 pcl::PointCloud<pcl::PointXYZRGB>::Ptr transformedCloud(
new pcl::PointCloud<pcl::PointXYZRGB>);
2841 if(optimizedVoxelSize > 0.0
f)
2850 pcl::copyPointCloud(*cloud, *
indices, *transformedCloud);
2854 Eigen::Vector3f viewpoint(
iter->second.x(),
iter->second.y(),
iter->second.z());
2857 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr cloudWithNormals(
new pcl::PointCloud<pcl::PointXYZRGBNormal>);
2858 pcl::concatenateFields(*transformedCloud, *normals, *cloudWithNormals);
2860 if(textureSize == 0 && (gains[0] != 1.0 || gains[1] != 1.0 || gains[2] != 1.0))
2862 for(
unsigned int i=0;
i<cloudWithNormals->size(); ++
i)
2864 pcl::PointXYZRGBNormal & pt = cloudWithNormals->at(
i);
2872 if(mergedClouds->size() == 0)
2874 *mergedClouds = *cloudWithNormals;
2878 *mergedClouds += *cloudWithNormals;
2882 cameraModels.insert(std::make_pair(
iter->first,
model));
2885 cameraDepths.insert(std::make_pair(
iter->first, depth));
2888 LOGI(
"Assembled %d points (%d/%d total=%d)", (
int)cloudWithNormals->size(), ++cloudCount, (
int)poses.size(), (
int)mergedClouds->size());
2892 UERROR(
"Cloud %d not found or empty",
iter->first);
2906 LOGI(
"Assembled clouds (%d)... done! %fs (total points=%d)", (
int)
cameraPoses.size(),
timer.ticks(), (
int)mergedClouds->size());
2908 if(mergedClouds->size()>=3)
2910 if(optimizedDepth == 0)
2915 optimizedDepth = 12;
2916 for(
int i=6;
i<12; ++
i)
2918 if(mapLength/
float(1<<
i) < 0.03
f)
2924 LOGI(
"optimizedDepth=%d (map length=%f)", optimizedDepth, mapLength);
2928 LOGI(
"Mesh reconstruction...");
2929 pcl::PolygonMesh::Ptr mesh(
new pcl::PolygonMesh);
2930 pcl::Poisson<pcl::PointXYZRGBNormal> poisson;
2931 poisson.setDepth(optimizedDepth);
2932 poisson.setInputCloud(mergedClouds);
2933 poisson.reconstruct(*mesh);
2934 LOGI(
"Mesh reconstruction... done! %fs (%d polygons)",
timer.ticks(), (
int)mesh->polygons.size());
2948 if(mesh->polygons.size())
2950 totalPolygons=(
int)mesh->polygons.size();
2952 if(optimizedMaxPolygons > 0 && optimizedMaxPolygons < (
int)mesh->polygons.size())
2955 unsigned int count = mesh->polygons.size();
2957 LOGI(
"Mesh decimation (max polygons %d/%d -> factor=%f)...", optimizedMaxPolygons, (
int)
count, factor);
2961 pcl::PolygonMesh::Ptr output(
new pcl::PolygonMesh);
2962 pcl::MeshQuadricDecimationVTK mqd;
2963 mqd.setTargetReductionFactor(factor);
2964 mqd.setInputMesh(mesh);
2965 mqd.process (*output);
2973 LOGI(
"Mesh decimated (factor=%f) from %d to %d polygons (%fs)", factor,
count, (
int)mesh->polygons.size(),
timer.ticks());
2974 if(count < mesh->polygons.size())
2976 UWARN(
"Decimated mesh has more polygons than before!");
2979 UWARN(
"RTAB-Map is not built with PCL-VTK module so mesh decimation cannot be used!");
2995 rtabmap::util3d::denseMeshPostProcessing<pcl::PointXYZRGBNormal>(
3000 optimizedColorRadius,
3002 optimizedCleanWhitePolygons,
3003 optimizedMinClusterSize);
3007 LOGI(
"Texturing... cameraPoses=%d, cameraDepths=%d", (
int)
cameraPoses.size(), (
int)cameraDepths.size());
3013 optimizedMaxTextureDistance,
3016 optimizedMinTextureClusterSize,
3017 std::vector<float>(),
3020 LOGI(
"Texturing... done! %fs",
timer.ticks());
3033 if(textureMesh->tex_coordinates.size() && optimizedCleanWhitePolygons)
3035 LOGI(
"Cleanup mesh...");
3037 LOGI(
"Cleanup mesh... done! %fs",
timer.ticks());
3041 for(
unsigned int t=0;
t<textureMesh->tex_polygons.size(); ++
t)
3043 totalPolygons+=textureMesh->tex_polygons[
t].size();
3048 totalPolygons = (
int)mesh->polygons.size();
3055 UERROR(
"Merged cloud too small (%d points) to create polygons!", (
int)mergedClouds->size());
3060 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr mergedClouds(
new pcl::PointCloud<pcl::PointXYZRGBNormal>);
3064 textureMesh->tex_materials.resize(poses.size());
3065 textureMesh->tex_polygons.resize(poses.size());
3066 textureMesh->tex_coordinates.resize(poses.size());
3069 int polygonsStep = 0;
3071 for(std::map<int, rtabmap::Transform>::iterator
iter=poses.begin();
3075 LOGI(
"Assembling cloud %d (total=%d)...",
iter->first, (
int)poses.size());
3078 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(
new pcl::PointCloud<pcl::PointXYZRGB>);
3079 std::vector<pcl::Vertices> polygons;
3080 float gains[3] = {1.0f};
3083 cloud = jter->second.cloud;
3084 polygons= jter->second.polygons;
3085 if(cloud->size() && polygons.size() == 0)
3089 gains[0] = jter->second.gains[0];
3090 gains[1] = jter->second.gains[1];
3091 gains[2] = jter->second.gains[2];
3096 data.uncompressData();
3097 if(!
data.imageRaw().empty() && !
data.depthRaw().empty() &&
data.cameraModels().size() == 1)
3105 if(cloud->size() && polygons.size())
3108 pcl::PointCloud<pcl::PointXYZRGB>::Ptr outputCloud(
new pcl::PointCloud<pcl::PointXYZRGB>);
3109 std::vector<pcl::Vertices> outputPolygons;
3114 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr cloudWithNormals(
new pcl::PointCloud<pcl::PointXYZRGBNormal>);
3115 pcl::concatenateFields(*outputCloud, *normals, *cloudWithNormals);
3117 UASSERT(outputPolygons.size());
3119 totalPolygons+=outputPolygons.size();
3121 if(textureSize == 0)
3126 if(gains[0] != 1.0
f || gains[1] != 1.0
f || gains[2] != 1.0
f)
3128 for(
unsigned int i=0;
i<cloudWithNormals->size(); ++
i)
3130 pcl::PointXYZRGBNormal & pt = cloudWithNormals->at(
i);
3137 if(mergedClouds->size() == 0)
3139 *mergedClouds = *cloudWithNormals;
3140 polygonMesh->polygons = outputPolygons;
3150 size_t polygonSize = outputPolygons.front().vertices.size();
3151 textureMesh->tex_polygons[oi].resize(outputPolygons.size());
3152 textureMesh->tex_coordinates[oi].resize(outputPolygons.size() * polygonSize);
3153 for(
unsigned int j=0;
j<outputPolygons.size(); ++
j)
3155 pcl::Vertices
vertices = outputPolygons[
j];
3157 for(
unsigned int k=0; k<
vertices.vertices.size(); ++k)
3161 int originalVertex = denseToOrganizedIndices[
vertices.vertices[k]];
3162 textureMesh->tex_coordinates[oi][
j*
vertices.vertices.size()+k] = Eigen::Vector2f(
3163 float(originalVertex % cloud->width) /
float(cloud->width),
3164 float(cloud->height - originalVertex / cloud->width) /
float(cloud->height));
3166 vertices.vertices[k] += polygonsStep;
3168 textureMesh->tex_polygons[oi][
j] =
vertices;
3171 polygonsStep += outputCloud->size();
3174 if(mergedClouds->size() == 0)
3176 *mergedClouds = *transformedCloud;
3180 *mergedClouds += *transformedCloud;
3183 textureMesh->tex_materials[oi].tex_illum = 1;
3184 textureMesh->tex_materials[oi].tex_name =
uFormat(
"material_%d",
iter->first);
3191 UERROR(
"Mesh not found for mesh %d",
iter->first);
3205 if(textureSize == 0)
3207 if(mergedClouds->size())
3209 pcl::toPCLPointCloud2(*mergedClouds, polygonMesh->cloud);
3213 polygonMesh->polygons.clear();
3218 textureMesh->tex_materials.resize(oi);
3219 textureMesh->tex_polygons.resize(oi);
3221 if(mergedClouds->size())
3223 pcl::toPCLPointCloud2(*mergedClouds, textureMesh->cloud);
3230 if(textureSize>0 && totalPolygons && textureMesh->tex_materials.size())
3232 LOGI(
"Merging %d textures...", (
int)textureMesh->tex_materials.size());
3235 std::map<int, cv::Mat>(),
3236 std::map<
int, std::vector<rtabmap::CameraModel> >(),
3242 true, 10.0f,
true ,
true, 0, 0, 0,
false,
3244 LOGI(
"Merging %d textures... globalTextures=%dx%d", (
int)textureMesh->tex_materials.size(),
3245 globalTextures.cols, globalTextures.rows);
3261 if(textureSize == 0)
3263 UASSERT((
int)polygonMesh->polygons.size() == totalPolygons);
3264 if(polygonMesh->polygons.size())
3267 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr cloud(
new pcl::PointCloud<pcl::PointXYZRGBNormal>);
3268 pcl::fromPCLPointCloud2(polygonMesh->cloud, *cloud);
3270 std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > polygons(1);
3271 polygons[0].resize(polygonMesh->polygons.size());
3272 for(
unsigned int p=0;
p<polygonMesh->polygons.size(); ++
p)
3274 polygons[0][
p] = polygonMesh->polygons[
p].vertices;
3282 else if(textureMesh->tex_materials.size())
3284 pcl::PointCloud<pcl::PointNormal>::Ptr cloud(
new pcl::PointCloud<pcl::PointNormal>);
3285 pcl::fromPCLPointCloud2(textureMesh->cloud, *cloud);
3289 std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > polygons(textureMesh->tex_polygons.size());
3290 for(
unsigned int t=0;
t<textureMesh->tex_polygons.size(); ++
t)
3292 polygons[
t].resize(textureMesh->tex_polygons[
t].size());
3293 for(
unsigned int p=0;
p<textureMesh->tex_polygons[
t].size(); ++
p)
3295 polygons[
t][
p] = textureMesh->tex_polygons[
t][
p].vertices;
3304 UERROR(
"Failed exporting texture mesh! There are no textures!");
3309 UERROR(
"Failed exporting mesh! There are no polygons!");
3314 pcl::PointCloud<pcl::PointXYZRGB>::Ptr mergedClouds(
new pcl::PointCloud<pcl::PointXYZRGB>);
3315 for(std::map<int, rtabmap::Transform>::iterator
iter=poses.begin();
3320 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(
new pcl::PointCloud<pcl::PointXYZRGB>);
3321 pcl::IndicesPtr
indices(
new std::vector<int>);
3323 gains[0] = gains[1] = gains[2] = 1.0f;
3328 gains[0] = jter->second.gains[0];
3329 gains[1] = jter->second.gains[1];
3330 gains[2] = jter->second.gains[2];
3333 data.uncompressData();
3334 if(!
data.imageRaw().empty() && !
data.depthRaw().empty())
3339 else if(!
data.laserScanRaw().empty())
3343 indices->resize(cloud->size());
3344 for(
unsigned int i=0;
i<cloud->size(); ++
i)
3354 cloud = jter->second.cloud;
3355 indices = jter->second.indices;
3356 gains[0] = jter->second.gains[0];
3357 gains[1] = jter->second.gains[1];
3358 gains[2] = jter->second.gains[2];
3363 data.uncompressData();
3364 if(!
data.imageRaw().empty() && !
data.depthRaw().empty())
3369 else if(!
data.laserScanRaw().empty())
3373 indices->resize(cloud->size());
3374 for(
unsigned int i=0;
i<cloud->size(); ++
i)
3381 if(cloud->size() &&
indices->size())
3384 pcl::PointCloud<pcl::PointXYZRGB>::Ptr transformedCloud(
new pcl::PointCloud<pcl::PointXYZRGB>);
3385 if(cloudVoxelSize > 0.0
f)
3394 pcl::copyPointCloud(*cloud, *
indices, *transformedCloud);
3398 if(gains[0] != 1.0
f || gains[1] != 1.0
f || gains[2] != 1.0
f)
3401 for(
unsigned int i=0;
i<transformedCloud->size(); ++
i)
3403 pcl::PointXYZRGB & pt = transformedCloud->at(
i);
3412 if(mergedClouds->size() == 0)
3414 *mergedClouds = *transformedCloud;
3418 *mergedClouds += *transformedCloud;
3434 if(mergedClouds->size())
3436 if(cloudVoxelSize > 0.0
f)
3451 UERROR(
"Merged cloud is empty!");
3462 catch (std::exception &
e)
3464 UERROR(
"Out of memory! %s",
e.what());
3481 if(success && poses.size())
3494 LOGI(
"postExportation(visualize=%d)", visualize?1:0);
3495 optMesh_.reset(
new pcl::TextureMesh);
3503 std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > polygons;
3504 #if PCL_VERSION_COMPARE(>=, 1, 8, 0)
3505 std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > texCoords;
3507 std::vector<std::vector<Eigen::Vector2f> > texCoords;
3513 if(!cloudMat.empty())
3515 LOGI(
"postExportation: Found optimized mesh! Visualizing it.");
3525 LOGI(
"postExportation: No optimized mesh found.");
3556 stats.setPoses(poses);
3557 stats.setConstraints(links);
3570 LOGI(
"writeExportedMesh: dir=%s name=%s", directory.c_str(),
name.c_str());
3573 bool success =
false;
3575 pcl::PolygonMesh::Ptr polygonMesh(
new pcl::PolygonMesh);
3576 pcl::TextureMesh::Ptr textureMesh(
new pcl::TextureMesh);
3578 std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > polygons;
3579 #if PCL_VERSION_COMPARE(>=, 1, 8, 0)
3580 std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > texCoords;
3582 std::vector<std::vector<Eigen::Vector2f> > texCoords;
3588 if(!cloudMat.empty())
3590 LOGI(
"writeExportedMesh: Found optimized mesh!");
3591 if(textures.empty())
3602 LOGI(
"writeExportedMesh: No optimized mesh found.");
3606 if(polygonMesh->cloud.data.size())
3608 #if defined(RTABMAP_PDAL) || defined(RTABMAP_LIBLAS)
3612 LOGI(
"Saving las (%d vertices) to %s.", (
int)polygonMesh->cloud.data.size()/polygonMesh->cloud.point_step, filePath.c_str());
3613 pcl::PointCloud<pcl::PointXYZRGB> output;
3614 pcl::fromPCLPointCloud2(polygonMesh->cloud, output);
3622 LOGI(
"Saved las to %s!", filePath.c_str());
3626 UERROR(
"Failed saving las to %s!", filePath.c_str());
3634 LOGI(
"Saving ply (%d vertices, %d polygons) to %s.", (
int)polygonMesh->cloud.data.size()/polygonMesh->cloud.point_step, (
int)polygonMesh->polygons.size(), filePath.c_str());
3635 success = pcl::io::savePLYFileBinary(filePath, *polygonMesh) == 0;
3638 LOGI(
"Saved ply to %s!", filePath.c_str());
3642 UERROR(
"Failed saving ply to %s!", filePath.c_str());
3646 else if(textureMesh->cloud.data.size())
3649 LOGD(
"Saving texture(s) (%d)", textures.empty()?0:textures.cols/textures.rows);
3650 UASSERT(textures.empty() || textures.cols % textures.rows == 0);
3651 UASSERT((
int)textureMesh->tex_materials.size() == textures.cols/textures.rows);
3652 for(
unsigned int i=0;
i<textureMesh->tex_materials.size(); ++
i)
3654 std::string baseNameNum =
name;
3655 if(textureMesh->tex_materials.size()>1)
3660 textureMesh->tex_materials[
i].tex_file = baseNameNum+
".jpg";
3661 LOGI(
"Saving texture to %s.", fullPath.c_str());
3662 success = cv::imwrite(fullPath, textures(
cv::Range::all(), cv::Range(
i*textures.rows, (
i+1)*textures.rows)));
3665 LOGI(
"Failed saving %s!", fullPath.c_str());
3669 LOGI(
"Saved %s.", fullPath.c_str());
3681 int totalPolygons = 0;
3682 for(
unsigned int i=0;
i<textureMesh->tex_polygons.size(); ++
i)
3684 totalPolygons += textureMesh->tex_polygons[
i].size();
3686 LOGI(
"Saving obj (%d vertices, %d polygons) to %s.", (
int)textureMesh->cloud.data.size()/textureMesh->cloud.point_step, totalPolygons, filePath.c_str());
3687 success = pcl::io::saveOBJFile(filePath, *textureMesh) == 0;
3691 LOGI(
"Saved obj to %s!", filePath.c_str());
3695 UERROR(
"Failed saving obj to %s!", filePath.c_str());
3706 LOGI(
"postProcessing begin(%d)", approach);
3707 int returnedValue = 0;
3710 std::map<int, rtabmap::Transform> poses;
3711 std::multimap<int, rtabmap::Link> links;
3714 if(approach == -1 || approach == 2)
3729 if(returnedValue >=0)
3735 std::map<int, rtabmap::Signature> signatures;
3742 poses = sba->
optimizeBA(poses.rbegin()->first, poses, links, signatures);
3747 UERROR(
"g2o not available!");
3750 else if(approach!=4 && approach!=5 && approach != 7)
3761 stats.setPoses(poses);
3762 stats.setConstraints(links);
3764 LOGI(
"PostProcessing, sending rtabmap event to update graph...");
3769 else if(approach!=4 && approach!=5 && approach != 7)
3774 if(returnedValue >=0)
3778 if(approach == -1 || approach == 4)
3784 if(approach == -1 || approach == 5 || approach == 6)
3798 LOGI(
"postProcessing end(%d) -> %d", approach, returnedValue);
3799 return returnedValue;
3804 float rgb_fx,
float rgb_fy,
float rgb_cx,
float rgb_cy,
3805 float depth_fx,
float depth_fy,
float depth_cx,
float depth_cy,
3810 const void * yPlane,
const void * uPlane,
const void * vPlane,
int yPlaneLen,
int rgbWidth,
int rgbHeight,
int rgbFormat,
3811 const void * depth,
int depthLen,
int depthWidth,
int depthHeight,
int depthFormat,
3812 const void *
conf,
int confLen,
int confWidth,
int confHeight,
int confFormat,
3813 const float * points,
int pointsLen,
int pointsChannels,
3815 float p00,
float p11,
float p02,
float p12,
float p22,
float p32,
float p23,
3816 float t0,
float t1,
float t2,
float t3,
float t4,
float t5,
float t6,
float t7)
3818 #if defined(RTABMAP_ARCORE) || defined(__APPLE__)
3828 if(rgb_fx > 0.0
f && rgb_fy > 0.0
f && rgb_cx > 0.0
f && rgb_cy > 0.0
f && stamp > 0.0
f && yPlane && vPlane && yPlaneLen == rgbWidth*rgbHeight)
3833 #if defined(RTABMAP_ARCORE)
3834 if(rgbFormat == AR_IMAGE_FORMAT_YUV_420_888 &&
3835 (depth==0 || depthFormat == AIMAGE_FORMAT_DEPTH16))
3837 if(rgbFormat == 875704422 &&
3838 (depth==0 || depthFormat == 1717855600))
3845 if((
long)vPlane-(
long)yPlane != yPlaneLen)
3848 cv::Mat yuv(rgbHeight+rgbHeight/2, rgbWidth, CV_8UC1);
3849 memcpy(yuv.data, yPlane, yPlaneLen);
3850 memcpy(yuv.data+yPlaneLen, vPlane, rgbHeight/2*rgbWidth);
3851 cv::cvtColor(yuv, outputRGB, cv::COLOR_YUV2BGR_NV21);
3856 cv::cvtColor(cv::Mat(rgbHeight+rgbHeight/2, rgbWidth, CV_8UC1, (
void*)yPlane), outputRGB, cv::COLOR_YUV2BGR_NV21);
3858 cv::cvtColor(cv::Mat(rgbHeight+rgbHeight/2, rgbWidth, CV_8UC1, (
void*)yPlane), outputRGB, cv::COLOR_YUV2RGB_NV21);
3863 cv::Mat outputDepth;
3864 if(depth && depthHeight>0 && depthWidth>0)
3869 if(depthLen == 4*depthWidth*depthHeight)
3872 outputDepth = cv::Mat(depthHeight, depthWidth, CV_32FC1, (
void*)depth).clone();
3873 if(
conf && confWidth == depthWidth && confHeight == depthHeight && confFormat == 1278226488 &&
depthConfidence_>0)
3875 const unsigned char * confPtr = (
const unsigned char *)
conf;
3876 float * depthPtr = outputDepth.ptr<
float>();
3878 for (
int y = 0;
y < outputDepth.rows; ++
y)
3880 for (
int x = 0;
x < outputDepth.cols; ++
x)
3888 depthPtr[
y*outputDepth.cols +
x] = 0.0f;
3895 else if(depthLen == 2*depthWidth*depthHeight)
3898 outputDepth = cv::Mat(depthHeight, depthWidth, CV_16UC1);
3900 for (
int y = 0;
y < outputDepth.rows; ++
y)
3902 for (
int x = 0;
x < outputDepth.cols; ++
x)
3904 uint16_t depthSample = dataShort[
y*outputDepth.cols +
x];
3905 uint16_t depthRange = (depthSample & 0x1FFF);
3912 if(!outputRGB.empty())
3921 if(!outputDepth.empty() && !depthFrame.
isNull() && depth_fx!=0 && (rgbFrame != depthFrame || depthStamp!=stamp))
3925 if(depthStamp != stamp)
3945 motion = poseRgb.
inverse()*poseDepth;
3957 float scale = (
float)outputDepth.cols/(
float)outputRGB.cols;
3958 cv::Mat colorK = (cv::Mat_<double>(3,3) <<
3962 cv::Mat depthK = (cv::Mat_<double>(3,3) <<
3963 depth_fx, 0, depth_cx,
3964 0, depth_fy, depth_cy,
3968 UDEBUG(
"Depth registration time: %fs",
time.elapsed());
3982 std::vector<cv::KeyPoint> kpts;
3983 std::vector<cv::Point3f> kpts3;
3985 if(points && pointsLen>0)
3987 cv::Mat pointsMat(1, pointsLen, CV_32FC(pointsChannels), (
void*)points);
3988 if(outputDepth.empty())
4000 if(!outputDepth.empty())
4008 data.setFeatures(kpts, kpts3, cv::Mat());
4010 projectionMatrix[0][0] = p00;
4011 projectionMatrix[1][1] = p11;
4012 projectionMatrix[2][0] = p02;
4013 projectionMatrix[2][1] = p12;
4014 projectionMatrix[2][2] =
p22;
4015 projectionMatrix[2][3] = p32;
4016 projectionMatrix[3][2] = p23;
4033 UERROR(
"Missing image information! fx=%f fy=%f cx=%f cy=%f stamp=%f yPlane=%d vPlane=%d yPlaneLen=%d rgbWidth=%d rgbHeight=%d",
4034 rgb_fx, rgb_fy, rgb_cx, rgb_cy, stamp, yPlane?1:0, vPlane?1:0, yPlaneLen, rgbWidth, rgbHeight);
4038 UERROR(
"Not built with ARCore or iOS!");
4049 LOGI(
"Received SensorEvent!");
4059 LOGI(
"Received RtabmapEvent event! status=%d",
status_.first);
4068 LOGW(
"Received RtabmapEvent event but ignoring it while we are initializing...status=%d",
status_.first);
4083 if(event->
getClassName().compare(
"CameraInfoEvent") == 0)
4088 bool success =
false;
4090 if(jvm && RTABMapActivity)
4093 jint
rs = jvm->AttachCurrentThread(&
env,
NULL);
4094 if(
rs == JNI_OK &&
env)
4096 jclass clazz =
env->GetObjectClass(RTABMapActivity);
4099 jmethodID methodID =
env->GetMethodID(clazz,
"cameraEventCallback",
"(ILjava/lang/String;Ljava/lang/String;)V" );
4102 env->CallVoidMethod(RTABMapActivity, methodID,
4104 env->NewStringUTF(tangoEvent->
key().c_str()),
4105 env->NewStringUTF(tangoEvent->
value().c_str()));
4110 jvm->DetachCurrentThread();
4115 std::function<void()> actualCallback = [&](){
4124 UERROR(
"Failed to call RTABMapActivity::tangoEventCallback");
4128 if(event->
getClassName().compare(
"RtabmapEventInit") == 0)
4132 LOGI(
"Received RtabmapEventInit! Status=%d info=%s", (
int)
status_.first,
status_.second.c_str());
4135 bool success =
false;
4137 if(jvm && RTABMapActivity)
4140 jint
rs = jvm->AttachCurrentThread(&
env,
NULL);
4141 if(
rs == JNI_OK &&
env)
4143 jclass clazz =
env->GetObjectClass(RTABMapActivity);
4146 jmethodID methodID =
env->GetMethodID(clazz,
"rtabmapInitEventCallback",
"(ILjava/lang/String;)V" );
4149 env->CallVoidMethod(RTABMapActivity, methodID,
4156 jvm->DetachCurrentThread();
4161 std::function<void()> actualCallback = [&](){
4170 UERROR(
"Failed to call RTABMapActivity::rtabmapInitEventsCallback");
4174 if(event->
getClassName().compare(
"PostRenderEvent") == 0)
4176 LOGI(
"Received PostRenderEvent!");
4178 int loopClosureId = 0;
4179 int featuresExtracted = 0;
4182 LOGI(
"Received PostRenderEvent! has getRtabmapEvent");
4185 loopClosureId =
stats.loopClosureId()>0?
stats.loopClosureId():
stats.proximityDetectionId()>0?
stats.proximityDetectionId():0;
4186 featuresExtracted =
stats.getLastSignatureData().getWords().size();
4188 uInsert(
bufferedStatsData_, std::make_pair<std::string, float>(rtabmap::Statistics::kMemoryWorking_memory_size(),
uValue(
stats.data(), rtabmap::Statistics::kMemoryWorking_memory_size(), 0.0f)));
4189 uInsert(
bufferedStatsData_, std::make_pair<std::string, float>(rtabmap::Statistics::kMemoryShort_time_memory_size(),
uValue(
stats.data(), rtabmap::Statistics::kMemoryShort_time_memory_size(), 0.0f)));
4190 uInsert(
bufferedStatsData_, std::make_pair<std::string, float>(rtabmap::Statistics::kKeypointDictionary_size(),
uValue(
stats.data(), rtabmap::Statistics::kKeypointDictionary_size(), 0.0f)));
4192 uInsert(
bufferedStatsData_, std::make_pair<std::string, float>(rtabmap::Statistics::kLoopHighest_hypothesis_id(),
uValue(
stats.data(), rtabmap::Statistics::kLoopHighest_hypothesis_id(), 0.0f)));
4193 uInsert(
bufferedStatsData_, std::make_pair<std::string, float>(rtabmap::Statistics::kMemoryDatabase_memory_used(),
uValue(
stats.data(), rtabmap::Statistics::kMemoryDatabase_memory_used(), 0.0f)));
4194 uInsert(
bufferedStatsData_, std::make_pair<std::string, float>(rtabmap::Statistics::kLoopVisual_inliers(),
uValue(
stats.data(), rtabmap::Statistics::kLoopVisual_inliers(), 0.0f)));
4195 uInsert(
bufferedStatsData_, std::make_pair<std::string, float>(rtabmap::Statistics::kLoopVisual_matches(),
uValue(
stats.data(), rtabmap::Statistics::kLoopVisual_matches(), 0.0f)));
4196 uInsert(
bufferedStatsData_, std::make_pair<std::string, float>(rtabmap::Statistics::kLoopRejectedHypothesis(),
uValue(
stats.data(), rtabmap::Statistics::kLoopRejectedHypothesis(), 0.0f)));
4197 uInsert(
bufferedStatsData_, std::make_pair<std::string, float>(rtabmap::Statistics::kLoopOptimization_max_error(),
uValue(
stats.data(), rtabmap::Statistics::kLoopOptimization_max_error(), 0.0f)));
4198 uInsert(
bufferedStatsData_, std::make_pair<std::string, float>(rtabmap::Statistics::kLoopOptimization_max_error_ratio(),
uValue(
stats.data(), rtabmap::Statistics::kLoopOptimization_max_error_ratio(), 0.0f)));
4199 uInsert(
bufferedStatsData_, std::make_pair<std::string, float>(rtabmap::Statistics::kMemoryRehearsal_sim(),
uValue(
stats.data(), rtabmap::Statistics::kMemoryRehearsal_sim(), 0.0f)));
4200 uInsert(
bufferedStatsData_, std::make_pair<std::string, float>(rtabmap::Statistics::kLoopHighest_hypothesis_value(),
uValue(
stats.data(), rtabmap::Statistics::kLoopHighest_hypothesis_value(), 0.0f)));
4201 uInsert(
bufferedStatsData_, std::make_pair<std::string, float>(rtabmap::Statistics::kMemoryDistance_travelled(),
uValue(
stats.data(), rtabmap::Statistics::kMemoryDistance_travelled(), 0.0f)));
4202 uInsert(
bufferedStatsData_, std::make_pair<std::string, float>(rtabmap::Statistics::kMemoryFast_movement(),
uValue(
stats.data(), rtabmap::Statistics::kMemoryFast_movement(), 0.0f)));
4203 uInsert(
bufferedStatsData_, std::make_pair<std::string, float>(rtabmap::Statistics::kLoopLandmark_detected(),
uValue(
stats.data(), rtabmap::Statistics::kLoopLandmark_detected(), 0.0f)));
4217 float optimizationMaxErrorRatio =
uValue(
bufferedStatsData_, rtabmap::Statistics::kLoopOptimization_max_error_ratio(), 0.0
f);
4225 if(!currentPose.
isNull())
4231 UINFO(
"Send statistics to GUI");
4232 bool success =
false;
4234 if(jvm && RTABMapActivity)
4237 jint
rs = jvm->AttachCurrentThread(&
env,
NULL);
4238 if(
rs == JNI_OK &&
env)
4240 jclass clazz =
env->GetObjectClass(RTABMapActivity);
4243 jmethodID methodID =
env->GetMethodID(clazz,
"updateStatsCallback",
"(IIIIFIIIIIIFIFIFFFFIIFFFFFF)V" );
4246 env->CallVoidMethod(RTABMapActivity, methodID,
4263 optimizationMaxError,
4264 optimizationMaxErrorRatio,
4278 jvm->DetachCurrentThread();
4283 std::function<void()> actualCallback = [&](){
4301 optimizationMaxError,
4302 optimizationMaxErrorRatio,
4319 UERROR(
"Failed to call RTABMapActivity::updateStatsCallback");