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>
84 static jobject RTABMapActivity = 0;
92 static void *thread_func(
void*)
96 while((rdsz = read(pfd[0], buf,
sizeof buf - 1)) > 0) {
97 if(buf[rdsz - 1] ==
'\n') --rdsz;
99 __android_log_write(ANDROID_LOG_DEBUG,
LOG_TAG, buf);
107 setvbuf(stdout, 0, _IOLBF, 0);
108 setvbuf(stderr, 0, _IONBF, 0);
116 if(pthread_create(&thr, 0, thread_func, 0) == -1)
135 parameters.insert(
rtabmap::ParametersPair(rtabmap::Parameters::kRtabmapPublishLikelihood(), std::string(
"false")));
144 parameters.insert(
rtabmap::ParametersPair(rtabmap::Parameters::kMemCompressionParallelized(), std::string(
"false")));
146 parameters.insert(
rtabmap::ParametersPair(rtabmap::Parameters::kRGBDOptimizeFromGraphEnd(), std::string(
"true")));
148 parameters.insert(
rtabmap::ParametersPair(rtabmap::Parameters::kRGBDProximityPathMaxNeighbors(), std::string(
"0")));
149 parameters.insert(
rtabmap::ParametersPair(rtabmap::Parameters::kRGBDProximityBySpace(), std::string(
"false")));
155 if(parameters.find(rtabmap::Parameters::kOptimizerStrategy()) != parameters.end())
157 if(parameters.at(rtabmap::Parameters::kOptimizerStrategy()).compare(
"2") == 0)
163 else if(parameters.at(rtabmap::Parameters::kOptimizerStrategy()).compare(
"1") == 0)
183 parameters.insert(
rtabmap::ParametersPair(rtabmap::Parameters::kIcpCorrespondenceRatio(), std::string(
"0.49")));
184 parameters.insert(
rtabmap::ParametersPair(rtabmap::Parameters::kIcpMaxCorrespondenceDistance(), std::string(
"0.05")));
207 sensorCaptureThread_(0),
211 odomCloudShown_(
true),
212 graphOptimization_(
true),
213 nodesFiltering_(
false),
214 localizationMode_(
false),
215 trajectoryMode_(
false),
216 rawScanSaved_(
false),
218 depthFromMotion_(
false),
220 fullResolution_(
false),
222 useExternalLidar_(
false),
225 cloudDensityLevel_(1),
227 meshAngleToleranceDeg_(20.0),
228 meshDecimationFactor_(0),
230 maxGainRadius_(0.02
f),
231 renderingTextureDecimation_(4),
232 backgroundColor_(0.2
f),
234 dataRecorderMode_(
false),
235 clearSceneOnNextRender_(
false),
236 openingDatabase_(
false),
238 postProcessing_(
false),
239 filterPolygonsOnNextRender_(
false),
240 gainCompensationOnNextRender_(0),
241 bilateralFilteringOnNextRender_(
false),
242 takeScreenshotOnNextRender_(
false),
243 cameraJustInitialized_(
false),
246 lastDrawnCloudsCount_(0),
247 renderingTime_(0.0
f),
248 lastPostRenderEventTime_(0.0),
249 lastPoseEventTime_(0.0),
250 visualizingMesh_(
false),
251 exportedMeshUpdated_(
false),
252 optMesh_(new
pcl::TextureMesh),
255 mapToOdom_(
rtabmap::Transform::getIdentity())
261 env->GetJavaVM(&jvm);
262 RTABMapActivity =
env->NewGlobalRef(caller_activity);
265 LOGI(
"RTABMapApp::RTABMapApp()");
266 createdMeshes_.clear();
268 clearSceneOnNextRender_ =
true;
269 openingDatabase_ =
false;
271 postProcessing_=
false;
274 lastDrawnCloudsCount_ = 0;
275 renderingTime_ = 0.0f;
276 lastPostRenderEventTime_ = 0.0;
277 lastPoseEventTime_ = 0.0;
278 bufferedStatsData_.clear();
280 progressionStatus_.setJavaObjects(jvm, RTABMapActivity);
282 main_scene_.setBackgroundColor(backgroundColor_, backgroundColor_, backgroundColor_);
286 this->registerToEventsManager();
287 LOGI(
"RTABMapApp::RTABMapApp() end");
296 #ifndef __ANDROID__ // __APPLE__
298 void(*progressCallback)(
void *,
int,
int),
299 void(*initCallback)(
void *,
int,
const char*),
300 void(*statsUpdatedCallback)(
void *,
303 int,
int,
int,
int,
int ,
int,
308 float,
float,
float,
float,
310 float,
float,
float,
float,
float,
float))
320 LOGI(
"~RTABMapApp() begin");
340 LOGI(
"~RTABMapApp() end");
358 LOGW(
"Opening database %s (inMemory=%d, optimize=%d, clearDatabase=%d)", databasePath.c_str(), databaseInMemory?1:0,
optimize?1:0, clearDatabase?1:0);
371 bool restartThread =
false;
395 optMesh_.reset(
new pcl::TextureMesh);
404 std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > polygons;
405 #if PCL_VERSION_COMPARE(>=, 1, 8, 0)
406 std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > texCoords;
408 std::vector<std::vector<Eigen::Vector2f> > texCoords;
411 if(!databasePath.empty() &&
UFile::exists(databasePath) && !clearDatabase)
418 if(!cloudMat.empty())
420 LOGI(
"Open: Found optimized mesh! Visualizing it.");
428 else if(
optMesh_->tex_polygons.size())
430 LOGI(
"Open: Polygon mesh");
433 else if(!
optMesh_->cloud.data.empty())
435 LOGI(
"Open: Point cloud");
441 LOGI(
"Open: No optimized mesh found.");
469 LOGI(
"Erasing database \"%s\"...", databasePath.c_str());
479 LOGI(
"Initializing database...");
482 if(parameters.find(rtabmap::Parameters::kRtabmapDetectionRate()) != parameters.end())
488 std::map<int, rtabmap::Signature> signatures;
489 std::map<int, rtabmap::Transform> poses;
490 std::multimap<int, rtabmap::Link> links;
491 LOGI(
"Loading full map from database...");
504 if(signatures.size() && poses.empty())
506 LOGE(
"Failed to optimize the graph!");
511 LOGI(
"Creating the meshes (%d)....", (
int)poses.size());
517 for(std::map<int, rtabmap::Transform>::iterator
iter=poses.begin();
iter!=poses.end() && status>=0; ++
iter)
521 int id =
iter->first;
522 if(!
iter->second.isNull())
528 rawPoses_.insert(std::make_pair(
id, signatures.at(
id).getPose()));
531 data.uncompressData(&tmpA, &depth);
533 if(!(!
data.imageRaw().empty() && !
data.depthRaw().empty()) && !
data.laserScanCompressed().isEmpty())
536 data.uncompressData(0, 0, &scan);
539 if((!
data.imageRaw().empty() && !
data.depthRaw().empty()) || !
data.laserScanRaw().isEmpty())
542 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud;
543 pcl::IndicesPtr
indices(
new std::vector<int>);
554 indices->resize(cloud->size());
555 for(
unsigned int i=0;
i<cloud->size(); ++
i)
561 if(cloud->size() &&
indices->size())
563 std::vector<pcl::Vertices> polygons;
564 std::vector<pcl::Vertices> polygonsLowRes;
565 #if PCL_VERSION_COMPARE(>=, 1, 8, 0)
566 std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > texCoords;
568 std::vector<Eigen::Vector2f> texCoords;
576 pcl::PolygonMesh::Ptr tmpMesh(
new pcl::PolygonMesh);
577 pcl::toPCLPointCloud2(*cloud, tmpMesh->cloud);
578 tmpMesh->polygons = polygons;
579 rtabmap::util3d::denseMeshPostProcessing<pcl::PointXYZRGB>(tmpMesh,
meshDecimationFactor_, 0, cloud, 0);
580 if(!tmpMesh->polygons.empty())
584 std::map<int, rtabmap::Transform> cameraPoses;
585 std::map<int, rtabmap::CameraModel> cameraModels;
587 cameraModels.insert(std::make_pair(0,
data.cameraModels()[0]));
592 std::map<int, cv::Mat>());
593 pcl::fromPCLPointCloud2(textureMesh->cloud, *cloud);
594 polygons = textureMesh->tex_polygons[0];
595 texCoords = textureMesh->tex_coordinates[0];
599 pcl::fromPCLPointCloud2(tmpMesh->cloud, *cloud);
600 polygons = tmpMesh->polygons;
603 indices->resize(cloud->size());
604 for(
unsigned int i=0;
i<cloud->size(); ++
i)
614 #ifdef DEBUG_RENDERING_PERFORMANCE
615 LOGW(
"Mesh simplication, %d polygons, %d points (%fs)", (
int)polygons.size(), (
int)cloud->size(),
timer.ticks());
627 inserted.first->second.cloud = cloud;
628 inserted.first->second.indices =
indices;
629 inserted.first->second.polygons = polygons;
630 inserted.first->second.polygonsLowRes = polygonsLowRes;
631 inserted.first->second.visible =
true;
632 inserted.first->second.cameraModel =
data.cameraModels()[0];
633 inserted.first->second.gains[0] = 1.0;
634 inserted.first->second.gains[1] = 1.0;
635 inserted.first->second.gains[2] = 1.0;
638 inserted.first->second.texCoords = texCoords;
642 cv::resize(
data.imageRaw(), inserted.first->second.texture, reducedSize, 0, 0, cv::INTER_LINEAR);
646 inserted.first->second.texture =
data.imageRaw();
649 LOGI(
"Created cloud %d (%fs, %d points)",
id,
timer.ticks(), (
int)cloud->size());
653 UWARN(
"Cloud %d is empty",
id);
656 else if(!
data.depthOrRightCompressed().empty() || !
data.laserScanCompressed().isEmpty())
658 UERROR(
"Failed to uncompress data! (rgb=%d, depth=%d, scan=%d)",
data.imageCompressed().cols,
data.depthOrRightCompressed().cols,
data.laserScanCompressed().size());
664 UWARN(
"Data for node %d not found",
id);
669 UWARN(
"Pose %d is null !?",
id);
680 UERROR(
"Exception! msg=\"%s\"",
e.what());
683 catch (
const cv::Exception &
e)
685 UERROR(
"Exception! msg=\"%s\"",
e.what());
688 catch (
const std::exception &
e)
690 UERROR(
"Exception! msg=\"%s\"",
e.what());
712 LOGI(
"Polygon filtering...");
717 if(
iter->second.polygons.size())
726 LOGI(
"Open: add rtabmap event to update the scene");
731 stats.setPoses(poses);
732 stats.setConstraints(links);
764 if(poses.empty() || status>0)
779 if((height >= 480 || width >= 480) && width % 20 == 0 && height % 20 == 0)
783 else if(width % 15 == 0 && height % 15 == 0)
787 else if(width % 10 == 0 && height % 10 == 0)
791 else if(width % 8 == 0 && height % 8 == 0)
797 UERROR(
"Could not set decimation to high (size=%dx%d)", width, height);
802 if((height >= 480 || width >= 480) && width % 10 == 0 && height % 10 == 0)
806 else if(width % 5 == 0 && height % 5 == 0)
810 else if(width % 4 == 0 && height % 4 == 0)
816 UERROR(
"Could not set decimation to medium (size=%dx%d)", width, height);
821 if((height >= 480 || width >= 480) && width % 5 == 0 && height % 5 == 0)
825 else if(width % 3 == 0 && width % 3 == 0)
829 else if(width % 2 == 0 && width % 2 == 0)
835 UERROR(
"Could not set decimation to low (size=%dx%d)", width, height);
845 if(cameraDriver == 0)
854 if(cameraDriver == 1)
856 #ifdef RTABMAP_ARCORE
863 if(cameraDriver == 2)
865 #ifdef RTABMAP_ARENGINE
886 cameraDriver_ = driver;
890 LOGW(
"startCamera() camera driver=%d", cameraDriver_);
891 boost::mutex::scoped_lock lock(cameraMutex_);
893 if(cameraDriver_ == 0)
896 camera_ =
new rtabmap::CameraTango(cameraColor_, !cameraColor_ || fullResolution_?1:2, rawScanSaved_, smoothing_);
898 if (TangoService_setBinder(
env, iBinder) != TANGO_SUCCESS) {
899 UERROR(
"TangoHandler::ConnectTango, TangoService_setBinder error");
905 UERROR(
"RTAB-Map is not built with Tango support!");
908 else if(cameraDriver_ == 1)
910 #ifdef RTABMAP_ARCORE
913 UERROR(
"RTAB-Map is not built with ARCore support!");
916 else if(cameraDriver_ == 2)
918 #ifdef RTABMAP_ARENGINE
921 UERROR(
"RTAB-Map is not built with AREngine support!");
924 else if(cameraDriver_ == 3)
931 UERROR(
"Unknown or not supported camera driver! %d", cameraDriver_);
937 camera_->setScreenRotationAndSize(main_scene_.getScreenRotation(), main_scene_.getViewPortWidth(), main_scene_.getViewPortHeight());
940 LOGI(
"Cloud density level %d", cloudDensityLevel_);
942 LOGI(
"Start camera thread");
943 cameraJustInitialized_ =
true;
944 if(useExternalLidar_)
948 camera_->setImageRate(0);
950 sensorCaptureThread_->setScanParameters(
false, 1, 0.0
f, 0.0
f, 0.0
f, 0, 0.0
f, 0.0
f,
true);
956 sensorCaptureThread_->start();
959 UERROR(
"Failed camera initialization!");
965 LOGI(
"stopCamera()");
984 const std::vector<pcl::Vertices> & polygons,
987 std::vector<int> vertexToCluster(cloudSize, 0);
988 std::map<int, std::list<int> > clusters;
989 int lastClusterID = 0;
991 for(
unsigned int i=0;
i<polygons.size(); ++
i)
994 for(
unsigned int j=0;
j<polygons[
i].vertices.size(); ++
j)
996 if(vertexToCluster[polygons[
i].
vertices[
j]]>0)
998 clusterID = vertexToCluster[polygons[
i].vertices[
j]];
1004 clusters.at(clusterID).push_back(
i);
1008 clusterID = ++lastClusterID;
1009 std::list<int> polygons;
1010 polygons.push_back(
i);
1011 clusters.insert(std::make_pair(clusterID, polygons));
1013 for(
unsigned int j=0;
j<polygons[
i].vertices.size(); ++
j)
1015 vertexToCluster[polygons[
i].vertices[
j]] = clusterID;
1019 unsigned int biggestClusterSize = 0;
1020 for(std::map<
int, std::list<int> >::
iterator iter=clusters.begin();
iter!=clusters.end(); ++
iter)
1024 if(
iter->second.size() > biggestClusterSize)
1026 biggestClusterSize =
iter->second.size();
1029 unsigned int minClusterSize = (
unsigned int)(
float(biggestClusterSize)*
clusterRatio_);
1033 std::vector<pcl::Vertices> filteredPolygons(polygons.size());
1035 for(std::map<
int, std::list<int> >::
iterator iter=clusters.begin();
iter!=clusters.end(); ++
iter)
1037 if(
iter->second.size() >= minClusterSize)
1039 for(std::list<int>::iterator jter=
iter->second.begin(); jter!=
iter->second.end(); ++jter)
1041 filteredPolygons[oi++] = polygons[*jter];
1045 filteredPolygons.resize(oi);
1046 return filteredPolygons;
1051 const std::vector<pcl::Vertices> & polygons,
1052 int cloudSize)
const
1055 std::vector<std::set<int> > neighbors;
1056 std::vector<std::set<int> > vertexToPolygons;
1064 unsigned int biggestClusterSize = 0;
1067 if(
iter->size() > biggestClusterSize)
1069 biggestClusterSize =
iter->size();
1072 unsigned int minClusterSize = (
unsigned int)(
float(biggestClusterSize)*
clusterRatio_);
1073 LOGI(
"Biggest cluster = %d -> minClusterSize(ratio=%f)=%d",
1076 std::vector<pcl::Vertices> filteredPolygons(polygons.size());
1078 for(std::list<std::list<int> >::
iterator jter=clusters.begin(); jter!=clusters.end(); ++jter)
1080 if(jter->size() >= minClusterSize)
1082 for(std::list<int>::iterator kter=jter->begin(); kter!=jter->end(); ++kter)
1084 filteredPolygons[oi++] = polygons.at(*kter);
1088 filteredPolygons.resize(oi);
1089 return filteredPolygons;
1139 cv::Mat depth = cv::Mat::zeros(mesh.
cloud->height, mesh.
cloud->width, CV_32FC1);
1141 for(
unsigned int i=0;
i<mesh.
indices->size(); ++
i)
1145 if(mesh.
cloud->at(index).x > 0)
1148 depth.at<
float>(index) = pt.z;
1153 LOGI(
"smoothMesh() Bilateral filtering of %d, time=%fs",
id,
t.ticks());
1155 if(!depth.empty() && mesh.
indices->size())
1157 pcl::IndicesPtr newIndices(
new std::vector<int>(mesh.
indices->size()));
1159 for(
unsigned int i=0;
i<mesh.
indices->size(); ++
i)
1163 pcl::PointXYZRGB & pt = mesh.
cloud->at(index);
1165 if(depth.at<
float>(index) > 0)
1167 newPt.z = depth.at<
float>(index);
1169 newIndices->at(oi++) = index;
1173 newPt.x = newPt.y = newPt.z = std::numeric_limits<float>::quiet_NaN();
1179 newIndices->resize(oi);
1183 std::vector<pcl::Vertices> polygons;
1188 LOGI(
"smoothMesh() Reconstructing the mesh of %d, time=%fs",
id,
t.ticks());
1193 UERROR(
"smoothMesh() Failed to smooth surface %d",
id);
1201 UTimer tGainCompensation;
1202 LOGI(
"Gain compensation...");
1205 std::map<int, pcl::PointCloud<pcl::PointXYZRGB>::Ptr > clouds;
1206 std::map<int, pcl::IndicesPtr>
indices;
1209 clouds.insert(std::make_pair(
iter->first,
iter->second.cloud));
1212 std::map<int, rtabmap::Transform> poses;
1213 std::multimap<int, rtabmap::Link> links;
1219 for(std::map<
int, pcl::PointCloud<pcl::PointXYZRGB>::Ptr>::const_iterator
iter=clouds.begin();
iter!=clouds.end(); ++
iter)
1221 int from =
iter->first;
1222 std::map<int, pcl::PointCloud<pcl::PointXYZRGB>::Ptr>::const_iterator jter =
iter;
1224 for(;jter!=clouds.end(); ++jter)
1226 int to = jter->first;
1234 if(clouds.size() > 1 && links.size())
1237 LOGI(
"Gain compensation... compute gain: links=%d, time=%fs", (
int)links.size(), tGainCompensation.
ticks());
1242 if(!
iter->second.cloud->empty())
1244 if(clouds.size() > 1 && links.size())
1247 LOGI(
"%d mesh has gain %f,%f,%f",
iter->first,
iter->second.gains[0],
iter->second.gains[1],
iter->second.gains[2]);
1251 LOGI(
"Gain compensation... applying gain: meshes=%d, time=%fs", (
int)
createdMeshes_.size(), tGainCompensation.
ticks());
1257 std::list<rtabmap::RtabmapEvent*> rtabmapEvents;
1266 #ifdef DEBUG_RENDERING_PERFORMANCE
1271 bool notifyDataLoaded =
false;
1272 bool notifyCameraStarted =
false;
1280 const float* uvsTransformed = 0;
1293 #ifdef DEBUG_RENDERING_PERFORMANCE
1294 LOGW(
"Camera updateOnRender %fs",
time.ticks());
1318 pcl::IndicesPtr
indices(
new std::vector<int>);
1322 occlusionMesh.
cloud.reset(
new pcl::PointCloud<pcl::PointXYZRGB>());
1323 pcl::copyPointCloud(*cloud, *occlusionMesh.
cloud);
1327 else if(!occlusionImage.empty())
1329 UERROR(
"invalid occlusionModel: %f %f %f %f %dx%d", occlusionModel.
fx(), occlusionModel.
fy(), occlusionModel.
cx(), occlusionModel.
cy(), occlusionModel.
imageWidth(), occlusionModel.
imageHeight());
1332 #ifdef DEBUG_RENDERING_PERFORMANCE
1333 LOGW(
"Update background and occlusion mesh %fs",
time.ticks());
1354 LOGI(
"Process sensor events");
1359 notifyCameraStarted =
true;
1378 notifyCameraStarted =
true;
1393 LOGI(
"Adding optimized mesh to opengl (%d points, %d polygons, %d tex_coords, materials=%d texture=%dx%d)...",
1396 optMesh_->tex_coordinates.size()!=1?0:(
int)
optMesh_->tex_coordinates[0].size(),
1397 (
int)
optMesh_->tex_materials.size(),
1403 mesh.
cloud.reset(
new pcl::PointCloud<pcl::PointXYZRGB>);
1404 mesh.
normals.reset(
new pcl::PointCloud<pcl::Normal>);
1409 if(
optMesh_->tex_coordinates.size())
1418 pcl::IndicesPtr
indices(
new std::vector<int>);
1419 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(
new pcl::PointCloud<pcl::PointXYZRGB>);
1420 pcl::fromPCLPointCloud2(
optMesh_->cloud, *cloud);
1432 if(rtabmapEvents.size())
1435 if(!
stats.mapCorrection().isNull())
1440 std::map<int, rtabmap::Transform>::const_iterator
iter =
stats.poses().find(
optRefId_);
1446 int fastMovement = (
int)
uValue(
stats.data(), rtabmap::Statistics::kMemoryFast_movement(), 0.0f);
1447 int loopClosure = (
int)
uValue(
stats.data(), rtabmap::Statistics::kLoopAccepted_hypothesis_id(), 0.0f);
1448 int proximityClosureId =
int(
uValue(
stats.data(), rtabmap::Statistics::kProximitySpace_last_detection_id(), 0.0f));
1449 int rejected = (
int)
uValue(
stats.data(), rtabmap::Statistics::kLoopRejectedHypothesis(), 0.0f);
1450 int landmark = (
int)
uValue(
stats.data(), rtabmap::Statistics::kLoopLandmark_detected(), 0.0f);
1484 for(std::map<int, rtabmap::Transform>::const_iterator
iter=
stats.poses().begin();
1488 int id =
iter->first;
1519 if(rtabmapEvents.size())
1522 if(rtabmapEvents.back()->getStats().refImageId()>0 ||
1523 !rtabmapEvents.back()->getStats().data().empty())
1526 rtabmapEvents.pop_back();
1529 for(std::list<rtabmap::RtabmapEvent*>::iterator
iter=rtabmapEvents.begin();
iter!=rtabmapEvents.end(); ++
iter)
1533 rtabmapEvents.clear();
1542 optMesh_.reset(
new pcl::TextureMesh);
1559 if(rtabmapEvents.front()->getStats().refImageId()>0 && rtabmapEvents.front()->getStats().refImageId() <
createdMeshes_.rbegin()->first)
1561 LOGI(
"Detected new database! new=%d old=%d", rtabmapEvents.front()->getStats().refImageId(),
createdMeshes_.rbegin()->first);
1566 #ifdef DEBUG_RENDERING_PERFORMANCE
1567 if(rtabmapEvents.size())
1569 LOGW(
"begin and getting rtabmap events %fs",
time.ticks());
1576 LOGI(
"Clearing all rendering data...");
1590 LOGI(
"Clearing meshes...");
1596 notifyDataLoaded =
true;
1614 if(added.size() != meshes)
1616 LOGI(
"added (%d) != meshes (%d)", (
int)added.size(), meshes);
1623 LOGI(
"Re-add mesh %d to OpenGL context",
iter->first);
1634 if(!textureRaw.empty())
1639 LOGD(
"resize image from %dx%d to %dx%d", textureRaw.cols, textureRaw.rows, reducedSize.width, reducedSize.height);
1640 cv::resize(textureRaw,
iter->second.texture, reducedSize, 0, 0, cv::INTER_LINEAR);
1644 iter->second.texture = textureRaw;
1651 iter->second.texture = cv::Mat();
1656 else if(notifyDataLoaded)
1665 if(rtabmapEvents.size())
1667 #ifdef DEBUG_RENDERING_PERFORMANCE
1668 LOGW(
"Process rtabmap events %fs",
time.ticks());
1670 LOGI(
"Process rtabmap events");
1674 std::map<int, rtabmap::SensorData> bufferedSensorData;
1677 for(std::list<rtabmap::RtabmapEvent*>::iterator
iter=rtabmapEvents.begin();
iter!=rtabmapEvents.end(); ++
iter)
1682 int smallMovement = (
int)
uValue(
stats.data(), rtabmap::Statistics::kMemorySmall_movement(), 0.0f);
1683 int fastMovement = (
int)
uValue(
stats.data(), rtabmap::Statistics::kMemoryFast_movement(), 0.0f);
1684 int rehearsalMerged = (
int)
uValue(
stats.data(), rtabmap::Statistics::kMemoryRehearsal_merged(), 0.0f);
1686 smallMovement == 0 && rehearsalMerged == 0 && fastMovement == 0)
1688 int id =
stats.getLastSignatureData().id();
1692 ((!
s.sensorData().imageRaw().empty() && !
s.sensorData().depthRaw().empty()) ||
1693 !
s.sensorData().laserScanRaw().isEmpty()))
1695 uInsert(bufferedSensorData, std::make_pair(
id,
s.sensorData()));
1701 int loopClosure = (
int)
uValue(
stats.data(), rtabmap::Statistics::kLoopAccepted_hypothesis_id(), 0.0f);
1702 int proximityClosureId =
int(
uValue(
stats.data(), rtabmap::Statistics::kProximitySpace_last_detection_id(), 0.0f));
1703 int rejected = (
int)
uValue(
stats.data(), rtabmap::Statistics::kLoopRejectedHypothesis(), 0.0f);
1704 int landmark = (
int)
uValue(
stats.data(), rtabmap::Statistics::kLoopLandmark_detected(), 0.0f);
1736 #ifdef DEBUG_RENDERING_PERFORMANCE
1737 LOGW(
"Looking for data to load (%d) %fs", (
int)bufferedSensorData.size(),
time.ticks());
1740 std::map<int, rtabmap::Transform> posesWithMarkers = rtabmapEvents.back()->getStats().poses();
1741 if(!rtabmapEvents.back()->getStats().mapCorrection().isNull())
1743 mapToOdom_ = rtabmapEvents.back()->getStats().mapCorrection();
1747 for(std::map<int, rtabmap::Transform>::iterator
iter=posesWithMarkers.begin();
iter!=posesWithMarkers.end(); ++
iter)
1751 std::map<int, rtabmap::Transform>::iterator jter =
rawPoses_.find(
iter->first);
1763 std::map<int, rtabmap::Transform> poses(posesWithMarkers.lower_bound(0), posesWithMarkers.end());
1764 const std::multimap<int, rtabmap::Link> & links = rtabmapEvents.back()->getStats().constraints();
1770 #ifdef DEBUG_RENDERING_PERFORMANCE
1771 LOGW(
"Update graph: %fs",
time.ticks());
1776 std::set<std::string> strIds;
1777 for(std::map<int, rtabmap::Transform>::iterator
iter=poses.begin();
iter!=poses.end(); ++
iter)
1779 int id =
iter->first;
1780 if(!
iter->second.isNull())
1787 std::map<int, rtabmap::Mesh>::iterator meshIter =
createdMeshes_.find(
id);
1790 meshIter->second.visible =
true;
1795 bufferedSensorData.find(
id) != bufferedSensorData.end())
1799 cv::Mat tmpA, depth;
1800 data.uncompressData(&tmpA, &depth);
1801 if(!(!
data.imageRaw().empty() && !
data.depthRaw().empty()) && !
data.laserScanCompressed().isEmpty())
1804 data.uncompressData(0, 0, &scan);
1806 #ifdef DEBUG_RENDERING_PERFORMANCE
1807 LOGW(
"Decompressing data: %fs",
time.ticks());
1810 if((!
data.imageRaw().empty() && !
data.depthRaw().empty()) || !
data.laserScanRaw().isEmpty())
1813 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud;
1814 pcl::IndicesPtr
indices(
new std::vector<int>);
1824 indices->resize(cloud->size());
1825 for(
unsigned int i=0;
i<cloud->size(); ++
i)
1830 #ifdef DEBUG_RENDERING_PERFORMANCE
1831 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());
1833 if(cloud->size() &&
indices->size())
1835 std::vector<pcl::Vertices> polygons;
1836 std::vector<pcl::Vertices> polygonsLowRes;
1837 #if PCL_VERSION_COMPARE(>=, 1, 8, 0)
1838 std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > texCoords;
1840 std::vector<Eigen::Vector2f> texCoords;
1842 pcl::PointCloud<pcl::Normal>::Ptr normals(
new pcl::PointCloud<pcl::Normal>);
1846 #ifdef DEBUG_RENDERING_PERFORMANCE
1847 LOGW(
"Creating mesh, %d polygons (%fs)", (
int)polygons.size(),
time.ticks());
1852 pcl::PolygonMesh::Ptr tmpMesh(
new pcl::PolygonMesh);
1853 pcl::toPCLPointCloud2(*cloud, tmpMesh->cloud);
1854 tmpMesh->polygons = polygons;
1855 rtabmap::util3d::denseMeshPostProcessing<pcl::PointXYZRGB>(tmpMesh,
meshDecimationFactor_, 0, cloud, 0);
1857 if(!tmpMesh->polygons.empty())
1861 std::map<int, rtabmap::Transform> cameraPoses;
1862 std::map<int, rtabmap::CameraModel> cameraModels;
1864 cameraModels.insert(std::make_pair(0,
data.cameraModels()[0]));
1869 std::map<int, cv::Mat>());
1870 pcl::fromPCLPointCloud2(textureMesh->cloud, *cloud);
1871 polygons = textureMesh->tex_polygons[0];
1872 texCoords = textureMesh->tex_coordinates[0];
1876 pcl::fromPCLPointCloud2(tmpMesh->cloud, *cloud);
1877 polygons = tmpMesh->polygons;
1880 indices->resize(cloud->size());
1881 for(
unsigned int i=0;
i<cloud->size(); ++
i)
1890 #ifdef DEBUG_RENDERING_PERFORMANCE
1891 LOGW(
"Creating mesh, %d polygons (%fs)", (
int)polygons.size(),
time.ticks());
1894 #ifdef DEBUG_RENDERING_PERFORMANCE
1895 LOGW(
"Mesh simplication, %d polygons, %d points (%fs)", (
int)polygons.size(), (
int)cloud->size(),
time.ticks());
1902 #ifdef DEBUG_RENDERING_PERFORMANCE
1903 LOGW(
"Creating mesh, %d polygons (%fs)", (
int)polygons.size(),
time.ticks());
1910 inserted.first->second.cloud = cloud;
1911 inserted.first->second.indices =
indices;
1912 inserted.first->second.polygons = polygons;
1913 inserted.first->second.polygonsLowRes = polygonsLowRes;
1914 inserted.first->second.visible =
true;
1915 inserted.first->second.cameraModel =
data.cameraModels()[0];
1916 inserted.first->second.gains[0] = 1.0;
1917 inserted.first->second.gains[1] = 1.0;
1918 inserted.first->second.gains[2] = 1.0;
1921 inserted.first->second.texCoords = texCoords;
1925 cv::resize(
data.imageRaw(), inserted.first->second.texture, reducedSize, 0, 0, cv::INTER_LINEAR);
1926 #ifdef DEBUG_RENDERING_PERFORMANCE
1927 LOGW(
"resize image from %dx%d to %dx%d (%fs)",
data.imageRaw().cols,
data.imageRaw().rows, reducedSize.width, reducedSize.height,
time.ticks());
1932 inserted.first->second.texture =
data.imageRaw();
1945 #ifdef DEBUG_RENDERING_PERFORMANCE
1946 LOGW(
"Adding mesh to scene: %fs",
time.ticks());
1956 if(poses.size() > 2)
1960 for(std::multimap<int, rtabmap::Link>::const_iterator
iter=links.begin();
iter!=links.end(); ++
iter)
1964 int oldId =
iter->second.to()>
iter->second.from()?
iter->second.from():
iter->second.to();
1976 for(std::set<int>::const_iterator
iter=addedClouds.begin();
1977 iter!=addedClouds.end();
1980 if(*
iter > 0 && poses.find(*
iter) == poses.end())
1985 meshIter->second.visible =
false;
1992 for(std::set<int>::const_iterator
iter=addedMarkers.begin();
1993 iter!=addedMarkers.end();
1996 if(posesWithMarkers.find(*
iter) == posesWithMarkers.end())
2001 for(std::map<int, rtabmap::Transform>::const_iterator
iter=posesWithMarkers.begin();
2002 iter!=posesWithMarkers.end() &&
iter->first<0;
2005 int id =
iter->first;
2028 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud;
2029 pcl::IndicesPtr
indices(
new std::vector<int>);
2039 indices->resize(cloud->size());
2040 for(
unsigned int i=0;
i<cloud->size(); ++
i)
2046 if(cloud->size() &&
indices->size())
2048 LOGI(
"Created odom cloud (rgb=%dx%d depth=%dx%d cloud=%dx%d)",
2051 (
int)cloud->width, (
int)cloud->height);
2057 UERROR(
"Generated cloud is empty!");
2062 UWARN(
"Odom data images/scans are empty!");
2076 notifyDataLoaded =
true;
2081 LOGI(
"Bilateral filtering...");
2086 if(
iter->second.cloud->size() &&
iter->second.indices->size())
2094 notifyDataLoaded =
true;
2099 LOGI(
"Polygon filtering...");
2105 if(
iter->second.polygons.size())
2112 notifyDataLoaded =
true;
2123 if(rtabmapEvents.size())
2127 if(rtabmapEvents.back()->getStats().refImageId()>0 ||
2128 !rtabmapEvents.back()->getStats().data().empty())
2131 rtabmapEvents.pop_back();
2134 for(std::list<rtabmap::RtabmapEvent*>::iterator
iter=rtabmapEvents.begin();
iter!=rtabmapEvents.end(); ++
iter)
2138 rtabmapEvents.clear();
2144 UERROR(
"TangoPoseEventNotReceived");
2155 cv::Mat image(
h,
w, CV_8UC4);
2156 glReadPixels(0, 0,
w,
h, GL_RGBA, GL_UNSIGNED_BYTE, image.data);
2157 cv::flip(image, image, 0);
2158 cv::cvtColor(image, image, cv::COLOR_RGBA2BGRA);
2171 LOGI(
"Saving screenshot %dx%d...", roi.cols, roi.rows);
2180 double updateInterval = 1.0;
2190 if(interval >= updateInterval)
2201 return notifyDataLoaded||notifyCameraStarted?1:0;
2205 for(std::list<rtabmap::RtabmapEvent*>::iterator
iter=rtabmapEvents.begin();
iter!=rtabmapEvents.end(); ++
iter)
2209 rtabmapEvents.clear();
2210 UERROR(
"Exception! msg=\"%s\"",
e.what());
2213 catch(
const cv::Exception &
e)
2215 for(std::list<rtabmap::RtabmapEvent*>::iterator
iter=rtabmapEvents.begin();
iter!=rtabmapEvents.end(); ++
iter)
2219 rtabmapEvents.clear();
2220 UERROR(
"Exception! msg=\"%s\"",
e.what());
2223 catch(
const std::exception &
e)
2225 for(std::list<rtabmap::RtabmapEvent*>::iterator
iter=rtabmapEvents.begin();
iter!=rtabmapEvents.end(); ++
iter)
2229 rtabmapEvents.clear();
2230 UERROR(
"Exception! msg=\"%s\"",
e.what());
2242 float x0,
float y0,
float x1,
float y1) {
2336 std::map<int, rtabmap::Transform> poses;
2337 std::multimap<int, rtabmap::Link> links;
2343 stats.setPoses(poses);
2344 stats.setConstraints(links);
2346 LOGI(
"Send rtabmap event to update graph...");
2497 std::string compatibleKey =
key;
2503 if(
iter->second.first)
2506 compatibleKey =
iter->second.second;
2507 LOGW(
"Parameter name changed: \"%s\" -> \"%s\". Please update the code accordingly. Value \"%s\" is still set to the new parameter name.",
2508 iter->first.c_str(),
iter->second.second.c_str(),
value.c_str());
2512 if(
iter->second.second.empty())
2514 UERROR(
"Parameter \"%s\" doesn't exist anymore!",
2515 iter->first.c_str());
2519 UERROR(
"Parameter \"%s\" doesn't exist anymore! You may look at this similar parameter: \"%s\"",
2520 iter->first.c_str(),
iter->second.second.c_str());
2527 LOGI(
"%s",
uFormat(
"Setting param \"%s\" to \"%s\"", compatibleKey.c_str(),
value.c_str()).c_str());
2534 UERROR(
uFormat(
"Key \"%s\" doesn't exist!", compatibleKey.c_str()).c_str());
2559 LOGI(
"Saving database to %s", databasePath.c_str());
2563 LOGI(
"Taking screenshot...");
2567 UERROR(
"Failed to take a screenshot after 2 sec!");
2589 if(appendModeBackup || dataRecorderModeBackup || localizationModeBackup)
2611 std::string errorMsg;
2614 LOGE(
"Recovery Error: %s", errorMsg.c_str());
2619 LOGI(
"Renaming %s to %s", from.c_str(), to.c_str());
2622 LOGE(
"Failed renaming %s to %s", from.c_str(), to.c_str());
2631 UWARN(
"Processing canceled!");
2636 float cloudVoxelSize,
2637 bool regenerateCloud,
2643 float optimizedVoxelSize,
2645 int optimizedMaxPolygons,
2646 float optimizedColorRadius,
2647 bool optimizedCleanWhitePolygons,
2648 int optimizedMinClusterSize,
2649 float optimizedMaxTextureDistance,
2650 int optimizedMinTextureClusterSize,
2651 bool blockRendering)
2660 std::multimap<int, rtabmap::Link> links;
2668 UERROR(
"Empty optimized poses!");
2682 bool success =
false;
2687 totalSteps+=poses.size();
2692 totalSteps += poses.size();
2698 if(optimizedMaxPolygons > 0)
2708 totalSteps+=poses.size()+1;
2713 totalSteps += poses.size()+1;
2723 pcl::PolygonMesh::Ptr polygonMesh(
new pcl::PolygonMesh);
2724 pcl::TextureMesh::Ptr textureMesh(
new pcl::TextureMesh);
2725 std::vector<std::map<int, pcl::PointXY> > vertexToPixels;
2726 cv::Mat globalTextures;
2727 int totalPolygons = 0;
2731 std::map<int, rtabmap::Transform> cameraPoses;
2732 std::map<int, rtabmap::CameraModel> cameraModels;
2733 std::map<int, cv::Mat> cameraDepths;
2736 LOGI(
"Assemble clouds (%d)...", (
int)poses.size());
2740 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr mergedClouds(
new pcl::PointCloud<pcl::PointXYZRGBNormal>);
2741 for(std::map<int, rtabmap::Transform>::iterator
iter=poses.begin();
2746 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(
new pcl::PointCloud<pcl::PointXYZRGB>);
2747 pcl::IndicesPtr
indices(
new std::vector<int>);
2751 gains[0] = gains[1] = gains[2] = 1.0f;
2754 cloud = jter->second.cloud;
2755 indices = jter->second.indices;
2756 model = jter->second.cameraModel;
2757 gains[0] = jter->second.gains[0];
2758 gains[1] = jter->second.gains[1];
2759 gains[2] = jter->second.gains[2];
2762 data.uncompressData(0, &depth);
2767 data.uncompressData();
2768 if(!
data.imageRaw().empty() && !
data.depthRaw().empty() &&
data.cameraModels().size() == 1)
2773 depth =
data.depthRaw();
2776 if(cloud->size() &&
indices->size() &&
model.isValidForProjection())
2778 pcl::PointCloud<pcl::PointXYZRGB>::Ptr transformedCloud(
new pcl::PointCloud<pcl::PointXYZRGB>);
2779 if(optimizedVoxelSize > 0.0
f)
2788 pcl::copyPointCloud(*cloud, *
indices, *transformedCloud);
2792 Eigen::Vector3f viewpoint(
iter->second.x(),
iter->second.y(),
iter->second.z());
2795 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr cloudWithNormals(
new pcl::PointCloud<pcl::PointXYZRGBNormal>);
2796 pcl::concatenateFields(*transformedCloud, *normals, *cloudWithNormals);
2798 if(textureSize == 0 && (gains[0] != 1.0 || gains[1] != 1.0 || gains[2] != 1.0))
2800 for(
unsigned int i=0;
i<cloudWithNormals->size(); ++
i)
2802 pcl::PointXYZRGBNormal & pt = cloudWithNormals->at(
i);
2810 if(mergedClouds->size() == 0)
2812 *mergedClouds = *cloudWithNormals;
2816 *mergedClouds += *cloudWithNormals;
2819 cameraPoses.insert(std::make_pair(
iter->first,
iter->second));
2820 cameraModels.insert(std::make_pair(
iter->first,
model));
2823 cameraDepths.insert(std::make_pair(
iter->first, depth));
2826 LOGI(
"Assembled %d points (%d/%d total=%d)", (
int)cloudWithNormals->size(), ++cloudCount, (
int)poses.size(), (
int)mergedClouds->size());
2830 UERROR(
"Cloud %d not found or empty",
iter->first);
2844 LOGI(
"Assembled clouds (%d)... done! %fs (total points=%d)", (
int)cameraPoses.size(),
timer.ticks(), (
int)mergedClouds->size());
2846 if(mergedClouds->size()>=3)
2848 if(optimizedDepth == 0)
2853 optimizedDepth = 12;
2854 for(
int i=6;
i<12; ++
i)
2856 if(mapLength/
float(1<<
i) < 0.03
f)
2862 LOGI(
"optimizedDepth=%d (map length=%f)", optimizedDepth, mapLength);
2866 LOGI(
"Mesh reconstruction...");
2867 pcl::PolygonMesh::Ptr mesh(
new pcl::PolygonMesh);
2868 pcl::Poisson<pcl::PointXYZRGBNormal> poisson;
2869 poisson.setDepth(optimizedDepth);
2870 poisson.setInputCloud(mergedClouds);
2871 poisson.reconstruct(*mesh);
2872 LOGI(
"Mesh reconstruction... done! %fs (%d polygons)",
timer.ticks(), (
int)mesh->polygons.size());
2886 if(mesh->polygons.size())
2888 totalPolygons=(
int)mesh->polygons.size();
2890 if(optimizedMaxPolygons > 0 && optimizedMaxPolygons < (
int)mesh->polygons.size())
2893 unsigned int count = mesh->polygons.size();
2895 LOGI(
"Mesh decimation (max polygons %d/%d -> factor=%f)...", optimizedMaxPolygons, (
int)
count, factor);
2899 pcl::PolygonMesh::Ptr output(
new pcl::PolygonMesh);
2900 pcl::MeshQuadricDecimationVTK mqd;
2901 mqd.setTargetReductionFactor(factor);
2902 mqd.setInputMesh(mesh);
2903 mqd.process (*output);
2911 LOGI(
"Mesh decimated (factor=%f) from %d to %d polygons (%fs)", factor,
count, (
int)mesh->polygons.size(),
timer.ticks());
2912 if(count < mesh->polygons.size())
2914 UWARN(
"Decimated mesh has more polygons than before!");
2917 UWARN(
"RTAB-Map is not built with PCL-VTK module so mesh decimation cannot be used!");
2933 rtabmap::util3d::denseMeshPostProcessing<pcl::PointXYZRGBNormal>(
2938 optimizedColorRadius,
2940 optimizedCleanWhitePolygons,
2941 optimizedMinClusterSize);
2945 LOGI(
"Texturing... cameraPoses=%d, cameraDepths=%d", (
int)cameraPoses.size(), (
int)cameraDepths.size());
2951 optimizedMaxTextureDistance,
2954 optimizedMinTextureClusterSize,
2955 std::vector<float>(),
2958 LOGI(
"Texturing... done! %fs",
timer.ticks());
2971 if(textureMesh->tex_coordinates.size() && optimizedCleanWhitePolygons)
2973 LOGI(
"Cleanup mesh...");
2975 LOGI(
"Cleanup mesh... done! %fs",
timer.ticks());
2979 for(
unsigned int t=0;
t<textureMesh->tex_polygons.size(); ++
t)
2981 totalPolygons+=textureMesh->tex_polygons[
t].size();
2986 totalPolygons = (
int)mesh->polygons.size();
2993 UERROR(
"Merged cloud too small (%d points) to create polygons!", (
int)mergedClouds->size());
2998 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr mergedClouds(
new pcl::PointCloud<pcl::PointXYZRGBNormal>);
3002 textureMesh->tex_materials.resize(poses.size());
3003 textureMesh->tex_polygons.resize(poses.size());
3004 textureMesh->tex_coordinates.resize(poses.size());
3007 int polygonsStep = 0;
3009 for(std::map<int, rtabmap::Transform>::iterator
iter=poses.begin();
3013 LOGI(
"Assembling cloud %d (total=%d)...",
iter->first, (
int)poses.size());
3016 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(
new pcl::PointCloud<pcl::PointXYZRGB>);
3017 std::vector<pcl::Vertices> polygons;
3018 float gains[3] = {1.0f};
3021 cloud = jter->second.cloud;
3022 polygons= jter->second.polygons;
3023 if(cloud->size() && polygons.size() == 0)
3027 gains[0] = jter->second.gains[0];
3028 gains[1] = jter->second.gains[1];
3029 gains[2] = jter->second.gains[2];
3034 data.uncompressData();
3035 if(!
data.imageRaw().empty() && !
data.depthRaw().empty() &&
data.cameraModels().size() == 1)
3043 if(cloud->size() && polygons.size())
3046 pcl::PointCloud<pcl::PointXYZRGB>::Ptr outputCloud(
new pcl::PointCloud<pcl::PointXYZRGB>);
3047 std::vector<pcl::Vertices> outputPolygons;
3052 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr cloudWithNormals(
new pcl::PointCloud<pcl::PointXYZRGBNormal>);
3053 pcl::concatenateFields(*outputCloud, *normals, *cloudWithNormals);
3055 UASSERT(outputPolygons.size());
3057 totalPolygons+=outputPolygons.size();
3059 if(textureSize == 0)
3064 if(gains[0] != 1.0
f || gains[1] != 1.0
f || gains[2] != 1.0
f)
3066 for(
unsigned int i=0;
i<cloudWithNormals->size(); ++
i)
3068 pcl::PointXYZRGBNormal & pt = cloudWithNormals->at(
i);
3075 if(mergedClouds->size() == 0)
3077 *mergedClouds = *cloudWithNormals;
3078 polygonMesh->polygons = outputPolygons;
3088 size_t polygonSize = outputPolygons.front().vertices.size();
3089 textureMesh->tex_polygons[oi].resize(outputPolygons.size());
3090 textureMesh->tex_coordinates[oi].resize(outputPolygons.size() * polygonSize);
3091 for(
unsigned int j=0;
j<outputPolygons.size(); ++
j)
3093 pcl::Vertices
vertices = outputPolygons[
j];
3095 for(
unsigned int k=0; k<
vertices.vertices.size(); ++k)
3099 int originalVertex = denseToOrganizedIndices[
vertices.vertices[k]];
3100 textureMesh->tex_coordinates[oi][
j*
vertices.vertices.size()+k] = Eigen::Vector2f(
3101 float(originalVertex % cloud->width) /
float(cloud->width),
3102 float(cloud->height - originalVertex / cloud->width) /
float(cloud->height));
3104 vertices.vertices[k] += polygonsStep;
3106 textureMesh->tex_polygons[oi][
j] =
vertices;
3109 polygonsStep += outputCloud->size();
3112 if(mergedClouds->size() == 0)
3114 *mergedClouds = *transformedCloud;
3118 *mergedClouds += *transformedCloud;
3121 textureMesh->tex_materials[oi].tex_illum = 1;
3122 textureMesh->tex_materials[oi].tex_name =
uFormat(
"material_%d",
iter->first);
3129 UERROR(
"Mesh not found for mesh %d",
iter->first);
3143 if(textureSize == 0)
3145 if(mergedClouds->size())
3147 pcl::toPCLPointCloud2(*mergedClouds, polygonMesh->cloud);
3151 polygonMesh->polygons.clear();
3156 textureMesh->tex_materials.resize(oi);
3157 textureMesh->tex_polygons.resize(oi);
3159 if(mergedClouds->size())
3161 pcl::toPCLPointCloud2(*mergedClouds, textureMesh->cloud);
3168 if(textureSize>0 && totalPolygons && textureMesh->tex_materials.size())
3170 LOGI(
"Merging %d textures...", (
int)textureMesh->tex_materials.size());
3173 std::map<int, cv::Mat>(),
3174 std::map<
int, std::vector<rtabmap::CameraModel> >(),
3180 true, 10.0f,
true ,
true, 0, 0, 0,
false,
3182 LOGI(
"Merging %d textures... globalTextures=%dx%d", (
int)textureMesh->tex_materials.size(),
3183 globalTextures.cols, globalTextures.rows);
3199 if(textureSize == 0)
3201 UASSERT((
int)polygonMesh->polygons.size() == totalPolygons);
3202 if(polygonMesh->polygons.size())
3205 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr cloud(
new pcl::PointCloud<pcl::PointXYZRGBNormal>);
3206 pcl::fromPCLPointCloud2(polygonMesh->cloud, *cloud);
3208 std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > polygons(1);
3209 polygons[0].resize(polygonMesh->polygons.size());
3210 for(
unsigned int p=0;
p<polygonMesh->polygons.size(); ++
p)
3212 polygons[0][
p] = polygonMesh->polygons[
p].vertices;
3220 else if(textureMesh->tex_materials.size())
3222 pcl::PointCloud<pcl::PointNormal>::Ptr cloud(
new pcl::PointCloud<pcl::PointNormal>);
3223 pcl::fromPCLPointCloud2(textureMesh->cloud, *cloud);
3227 std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > polygons(textureMesh->tex_polygons.size());
3228 for(
unsigned int t=0;
t<textureMesh->tex_polygons.size(); ++
t)
3230 polygons[
t].resize(textureMesh->tex_polygons[
t].size());
3231 for(
unsigned int p=0;
p<textureMesh->tex_polygons[
t].size(); ++
p)
3233 polygons[
t][
p] = textureMesh->tex_polygons[
t][
p].vertices;
3242 UERROR(
"Failed exporting texture mesh! There are no textures!");
3247 UERROR(
"Failed exporting mesh! There are no polygons!");
3252 pcl::PointCloud<pcl::PointXYZRGB>::Ptr mergedClouds(
new pcl::PointCloud<pcl::PointXYZRGB>);
3253 for(std::map<int, rtabmap::Transform>::iterator
iter=poses.begin();
3258 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(
new pcl::PointCloud<pcl::PointXYZRGB>);
3259 pcl::IndicesPtr
indices(
new std::vector<int>);
3261 gains[0] = gains[1] = gains[2] = 1.0f;
3266 gains[0] = jter->second.gains[0];
3267 gains[1] = jter->second.gains[1];
3268 gains[2] = jter->second.gains[2];
3271 data.uncompressData();
3272 if(!
data.imageRaw().empty() && !
data.depthRaw().empty())
3277 else if(!
data.laserScanRaw().empty())
3281 indices->resize(cloud->size());
3282 for(
unsigned int i=0;
i<cloud->size(); ++
i)
3292 cloud = jter->second.cloud;
3293 indices = jter->second.indices;
3294 gains[0] = jter->second.gains[0];
3295 gains[1] = jter->second.gains[1];
3296 gains[2] = jter->second.gains[2];
3301 data.uncompressData();
3302 if(!
data.imageRaw().empty() && !
data.depthRaw().empty())
3307 else if(!
data.laserScanRaw().empty())
3311 indices->resize(cloud->size());
3312 for(
unsigned int i=0;
i<cloud->size(); ++
i)
3319 if(cloud->size() &&
indices->size())
3322 pcl::PointCloud<pcl::PointXYZRGB>::Ptr transformedCloud(
new pcl::PointCloud<pcl::PointXYZRGB>);
3323 if(cloudVoxelSize > 0.0
f)
3332 pcl::copyPointCloud(*cloud, *
indices, *transformedCloud);
3336 if(gains[0] != 1.0
f || gains[1] != 1.0
f || gains[2] != 1.0
f)
3339 for(
unsigned int i=0;
i<transformedCloud->size(); ++
i)
3341 pcl::PointXYZRGB & pt = transformedCloud->at(
i);
3350 if(mergedClouds->size() == 0)
3352 *mergedClouds = *transformedCloud;
3356 *mergedClouds += *transformedCloud;
3372 if(mergedClouds->size())
3374 if(cloudVoxelSize > 0.0
f)
3389 UERROR(
"Merged cloud is empty!");
3400 catch (std::exception &
e)
3402 UERROR(
"Out of memory! %s",
e.what());
3419 if(success && poses.size())
3432 LOGI(
"postExportation(visualize=%d)", visualize?1:0);
3433 optMesh_.reset(
new pcl::TextureMesh);
3441 std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > polygons;
3442 #if PCL_VERSION_COMPARE(>=, 1, 8, 0)
3443 std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > texCoords;
3445 std::vector<std::vector<Eigen::Vector2f> > texCoords;
3451 if(!cloudMat.empty())
3453 LOGI(
"postExportation: Found optimized mesh! Visualizing it.");
3463 LOGI(
"postExportation: No optimized mesh found.");
3494 stats.setPoses(poses);
3495 stats.setConstraints(links);
3508 LOGI(
"writeExportedMesh: dir=%s name=%s", directory.c_str(),
name.c_str());
3511 bool success =
false;
3513 pcl::PolygonMesh::Ptr polygonMesh(
new pcl::PolygonMesh);
3514 pcl::TextureMesh::Ptr textureMesh(
new pcl::TextureMesh);
3516 std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > polygons;
3517 #if PCL_VERSION_COMPARE(>=, 1, 8, 0)
3518 std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > texCoords;
3520 std::vector<std::vector<Eigen::Vector2f> > texCoords;
3526 if(!cloudMat.empty())
3528 LOGI(
"writeExportedMesh: Found optimized mesh!");
3529 if(textures.empty())
3540 LOGI(
"writeExportedMesh: No optimized mesh found.");
3544 if(polygonMesh->cloud.data.size())
3548 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());
3549 success = pcl::io::savePLYFileBinary(filePath, *polygonMesh) == 0;
3552 LOGI(
"Saved ply to %s!", filePath.c_str());
3556 UERROR(
"Failed saving ply to %s!", filePath.c_str());
3559 else if(textureMesh->cloud.data.size())
3562 LOGD(
"Saving texture(s) (%d)", textures.empty()?0:textures.cols/textures.rows);
3563 UASSERT(textures.empty() || textures.cols % textures.rows == 0);
3564 UASSERT((
int)textureMesh->tex_materials.size() == textures.cols/textures.rows);
3565 for(
unsigned int i=0;
i<textureMesh->tex_materials.size(); ++
i)
3567 std::string baseNameNum =
name;
3568 if(textureMesh->tex_materials.size()>1)
3573 textureMesh->tex_materials[
i].tex_file = baseNameNum+
".jpg";
3574 LOGI(
"Saving texture to %s.", fullPath.c_str());
3575 success = cv::imwrite(fullPath, textures(
cv::Range::all(), cv::Range(
i*textures.rows, (
i+1)*textures.rows)));
3578 LOGI(
"Failed saving %s!", fullPath.c_str());
3582 LOGI(
"Saved %s.", fullPath.c_str());
3594 int totalPolygons = 0;
3595 for(
unsigned int i=0;
i<textureMesh->tex_polygons.size(); ++
i)
3597 totalPolygons += textureMesh->tex_polygons[
i].size();
3599 LOGI(
"Saving obj (%d vertices, %d polygons) to %s.", (
int)textureMesh->cloud.data.size()/textureMesh->cloud.point_step, totalPolygons, filePath.c_str());
3600 success = pcl::io::saveOBJFile(filePath, *textureMesh) == 0;
3604 LOGI(
"Saved obj to %s!", filePath.c_str());
3608 UERROR(
"Failed saving obj to %s!", filePath.c_str());
3619 LOGI(
"postProcessing begin(%d)", approach);
3620 int returnedValue = 0;
3623 std::map<int, rtabmap::Transform> poses;
3624 std::multimap<int, rtabmap::Link> links;
3627 if(approach == -1 || approach == 2)
3642 if(returnedValue >=0)
3648 std::map<int, rtabmap::Signature> signatures;
3655 poses = sba->
optimizeBA(poses.rbegin()->first, poses, links, signatures);
3660 UERROR(
"g2o not available!");
3663 else if(approach!=4 && approach!=5 && approach != 7)
3674 stats.setPoses(poses);
3675 stats.setConstraints(links);
3677 LOGI(
"PostProcessing, sending rtabmap event to update graph...");
3682 else if(approach!=4 && approach!=5 && approach != 7)
3687 if(returnedValue >=0)
3691 if(approach == -1 || approach == 4)
3697 if(approach == -1 || approach == 5 || approach == 6)
3711 LOGI(
"postProcessing end(%d) -> %d", approach, returnedValue);
3712 return returnedValue;
3716 float x,
float y,
float z,
float qx,
float qy,
float qz,
float qw,
double stamp)
3721 if(qx==0 && qy==0 &&
qz==0 && qw==0)
3735 float rgb_fx,
float rgb_fy,
float rgb_cx,
float rgb_cy,
3736 float depth_fx,
float depth_fy,
float depth_cx,
float depth_cy,
3741 const void * yPlane,
const void * uPlane,
const void * vPlane,
int yPlaneLen,
int rgbWidth,
int rgbHeight,
int rgbFormat,
3742 const void * depth,
int depthLen,
int depthWidth,
int depthHeight,
int depthFormat,
3743 const void *
conf,
int confLen,
int confWidth,
int confHeight,
int confFormat,
3744 const float * points,
int pointsLen,
int pointsChannels,
3746 float p00,
float p11,
float p02,
float p12,
float p22,
float p32,
float p23,
3747 float t0,
float t1,
float t2,
float t3,
float t4,
float t5,
float t6,
float t7)
3749 #if defined(RTABMAP_ARCORE) || defined(__APPLE__)
3753 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)
3758 #if defined(RTABMAP_ARCORE)
3759 if(rgbFormat == AR_IMAGE_FORMAT_YUV_420_888 &&
3760 (depth==0 || depthFormat == AIMAGE_FORMAT_DEPTH16))
3762 if(rgbFormat == 875704422 &&
3763 (depth==0 ||Â depthFormat == 1717855600))
3770 if((
long)vPlane-(
long)yPlane != yPlaneLen)
3773 cv::Mat yuv(rgbHeight+rgbHeight/2, rgbWidth, CV_8UC1);
3774 memcpy(yuv.data, yPlane, yPlaneLen);
3775 memcpy(yuv.data+yPlaneLen, vPlane, rgbHeight/2*rgbWidth);
3776 cv::cvtColor(yuv, outputRGB, cv::COLOR_YUV2BGR_NV21);
3781 cv::cvtColor(cv::Mat(rgbHeight+rgbHeight/2, rgbWidth, CV_8UC1, (
void*)yPlane), outputRGB, cv::COLOR_YUV2BGR_NV21);
3783 cv::cvtColor(cv::Mat(rgbHeight+rgbHeight/2, rgbWidth, CV_8UC1, (
void*)yPlane), outputRGB, cv::COLOR_YUV2RGB_NV21);
3788 cv::Mat outputDepth;
3789 if(depth && depthHeight>0 && depthWidth>0)
3794 if(depthLen == 4*depthWidth*depthHeight)
3797 outputDepth = cv::Mat(depthHeight, depthWidth, CV_32FC1, (
void*)depth).clone();
3798 if(
conf && confWidth == depthWidth && confHeight == depthHeight && confFormat == 1278226488 &&
depthConfidence_>0)
3800 const unsigned char * confPtr = (
const unsigned char *)
conf;
3801 float * depthPtr = outputDepth.ptr<
float>();
3803 for (
int y = 0;
y < outputDepth.rows; ++
y)
3805 for (
int x = 0;
x < outputDepth.cols; ++
x)
3813 depthPtr[
y*outputDepth.cols +
x] = 0.0f;
3820 else if(depthLen == 2*depthWidth*depthHeight)
3823 outputDepth = cv::Mat(depthHeight, depthWidth, CV_16UC1);
3825 for (
int y = 0;
y < outputDepth.rows; ++
y)
3827 for (
int x = 0;
x < outputDepth.cols; ++
x)
3829 uint16_t depthSample = dataShort[
y*outputDepth.cols +
x];
3830 uint16_t depthRange = (depthSample & 0x1FFF);
3837 if(!outputRGB.empty())
3848 if(!outputDepth.empty() && !depthFrame.
isNull() && depth_fx!=0 && (rgbFrame != depthFrame || depthStamp!=stamp))
3852 if(depthStamp != stamp)
3864 UDEBUG(
"poseRGB =%s (stamp=%f)", poseWithOriginOffset.
prettyPrint().c_str(), stamp);
3867 motion = poseWithOriginOffset.
inverse()*poseDepth;
3879 float scale = (
float)outputDepth.cols/(
float)outputRGB.cols;
3880 cv::Mat colorK = (cv::Mat_<double>(3,3) <<
3884 cv::Mat depthK = (cv::Mat_<double>(3,3) <<
3885 depth_fx, 0, depth_cx,
3886 0, depth_fy, depth_cy,
3890 UDEBUG(
"Depth registration time: %fs",
time.elapsed());
3904 std::vector<cv::KeyPoint> kpts;
3905 std::vector<cv::Point3f> kpts3;
3907 if(points && pointsLen>0)
3909 cv::Mat pointsMat(1, pointsLen, CV_32FC(pointsChannels), (
void*)points);
3910 if(outputDepth.empty())
3922 if(!outputDepth.empty())
3930 data.setFeatures(kpts, kpts3, cv::Mat());
3932 projectionMatrix[0][0] = p00;
3933 projectionMatrix[1][1] = p11;
3934 projectionMatrix[2][0] = p02;
3935 projectionMatrix[2][1] = p12;
3936 projectionMatrix[2][2] =
p22;
3937 projectionMatrix[2][3] = p32;
3938 projectionMatrix[3][2] = p23;
3955 UERROR(
"Missing image information! fx=%f fy=%f cx=%f cy=%f stamp=%f yPlane=%d vPlane=%d yPlaneLen=%d rgbWidth=%d rgbHeight=%d",
3956 rgb_fx, rgb_fy, rgb_cx, rgb_cy, stamp, yPlane?1:0, vPlane?1:0, yPlaneLen, rgbWidth, rgbHeight);
3960 UERROR(
"Not built with ARCore or iOS!");
3971 LOGI(
"Received SensorEvent!");
3981 LOGI(
"Received RtabmapEvent event! status=%d",
status_.first);
3990 LOGW(
"Received RtabmapEvent event but ignoring it while we are initializing...status=%d",
status_.first);
4005 if(event->
getClassName().compare(
"CameraInfoEvent") == 0)
4010 bool success =
false;
4012 if(jvm && RTABMapActivity)
4015 jint
rs = jvm->AttachCurrentThread(&
env,
NULL);
4016 if(
rs == JNI_OK &&
env)
4018 jclass clazz =
env->GetObjectClass(RTABMapActivity);
4021 jmethodID methodID =
env->GetMethodID(clazz,
"cameraEventCallback",
"(ILjava/lang/String;Ljava/lang/String;)V" );
4024 env->CallVoidMethod(RTABMapActivity, methodID,
4026 env->NewStringUTF(tangoEvent->
key().c_str()),
4027 env->NewStringUTF(tangoEvent->
value().c_str()));
4032 jvm->DetachCurrentThread();
4037 UERROR(
"Failed to call RTABMapActivity::tangoEventCallback");
4041 if(event->
getClassName().compare(
"RtabmapEventInit") == 0)
4045 LOGI(
"Received RtabmapEventInit! Status=%d info=%s", (
int)
status_.first,
status_.second.c_str());
4048 bool success =
false;
4050 if(jvm && RTABMapActivity)
4053 jint
rs = jvm->AttachCurrentThread(&
env,
NULL);
4054 if(
rs == JNI_OK &&
env)
4056 jclass clazz =
env->GetObjectClass(RTABMapActivity);
4059 jmethodID methodID =
env->GetMethodID(clazz,
"rtabmapInitEventCallback",
"(ILjava/lang/String;)V" );
4062 env->CallVoidMethod(RTABMapActivity, methodID,
4069 jvm->DetachCurrentThread();
4074 std::function<void()> actualCallback = [&](){
4083 UERROR(
"Failed to call RTABMapActivity::rtabmapInitEventsCallback");
4087 if(event->
getClassName().compare(
"PostRenderEvent") == 0)
4089 LOGI(
"Received PostRenderEvent!");
4091 int loopClosureId = 0;
4092 int featuresExtracted = 0;
4095 LOGI(
"Received PostRenderEvent! has getRtabmapEvent");
4098 loopClosureId =
stats.loopClosureId()>0?
stats.loopClosureId():
stats.proximityDetectionId()>0?
stats.proximityDetectionId():0;
4099 featuresExtracted =
stats.getLastSignatureData().getWords().size();
4101 uInsert(
bufferedStatsData_, std::make_pair<std::string, float>(rtabmap::Statistics::kMemoryWorking_memory_size(),
uValue(
stats.data(), rtabmap::Statistics::kMemoryWorking_memory_size(), 0.0f)));
4102 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)));
4103 uInsert(
bufferedStatsData_, std::make_pair<std::string, float>(rtabmap::Statistics::kKeypointDictionary_size(),
uValue(
stats.data(), rtabmap::Statistics::kKeypointDictionary_size(), 0.0f)));
4105 uInsert(
bufferedStatsData_, std::make_pair<std::string, float>(rtabmap::Statistics::kLoopHighest_hypothesis_id(),
uValue(
stats.data(), rtabmap::Statistics::kLoopHighest_hypothesis_id(), 0.0f)));
4106 uInsert(
bufferedStatsData_, std::make_pair<std::string, float>(rtabmap::Statistics::kMemoryDatabase_memory_used(),
uValue(
stats.data(), rtabmap::Statistics::kMemoryDatabase_memory_used(), 0.0f)));
4107 uInsert(
bufferedStatsData_, std::make_pair<std::string, float>(rtabmap::Statistics::kLoopVisual_inliers(),
uValue(
stats.data(), rtabmap::Statistics::kLoopVisual_inliers(), 0.0f)));
4108 uInsert(
bufferedStatsData_, std::make_pair<std::string, float>(rtabmap::Statistics::kLoopVisual_matches(),
uValue(
stats.data(), rtabmap::Statistics::kLoopVisual_matches(), 0.0f)));
4109 uInsert(
bufferedStatsData_, std::make_pair<std::string, float>(rtabmap::Statistics::kLoopRejectedHypothesis(),
uValue(
stats.data(), rtabmap::Statistics::kLoopRejectedHypothesis(), 0.0f)));
4110 uInsert(
bufferedStatsData_, std::make_pair<std::string, float>(rtabmap::Statistics::kLoopOptimization_max_error(),
uValue(
stats.data(), rtabmap::Statistics::kLoopOptimization_max_error(), 0.0f)));
4111 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)));
4112 uInsert(
bufferedStatsData_, std::make_pair<std::string, float>(rtabmap::Statistics::kMemoryRehearsal_sim(),
uValue(
stats.data(), rtabmap::Statistics::kMemoryRehearsal_sim(), 0.0f)));
4113 uInsert(
bufferedStatsData_, std::make_pair<std::string, float>(rtabmap::Statistics::kLoopHighest_hypothesis_value(),
uValue(
stats.data(), rtabmap::Statistics::kLoopHighest_hypothesis_value(), 0.0f)));
4114 uInsert(
bufferedStatsData_, std::make_pair<std::string, float>(rtabmap::Statistics::kMemoryDistance_travelled(),
uValue(
stats.data(), rtabmap::Statistics::kMemoryDistance_travelled(), 0.0f)));
4115 uInsert(
bufferedStatsData_, std::make_pair<std::string, float>(rtabmap::Statistics::kMemoryFast_movement(),
uValue(
stats.data(), rtabmap::Statistics::kMemoryFast_movement(), 0.0f)));
4116 uInsert(
bufferedStatsData_, std::make_pair<std::string, float>(rtabmap::Statistics::kLoopLandmark_detected(),
uValue(
stats.data(), rtabmap::Statistics::kLoopLandmark_detected(), 0.0f)));
4130 float optimizationMaxErrorRatio =
uValue(
bufferedStatsData_, rtabmap::Statistics::kLoopOptimization_max_error_ratio(), 0.0
f);
4138 if(!currentPose.
isNull())
4144 UINFO(
"Send statistics to GUI");
4145 bool success =
false;
4147 if(jvm && RTABMapActivity)
4150 jint
rs = jvm->AttachCurrentThread(&
env,
NULL);
4151 if(
rs == JNI_OK &&
env)
4153 jclass clazz =
env->GetObjectClass(RTABMapActivity);
4156 jmethodID methodID =
env->GetMethodID(clazz,
"updateStatsCallback",
"(IIIIFIIIIIIFIFIFFFFIIFFFFFF)V" );
4159 env->CallVoidMethod(RTABMapActivity, methodID,
4176 optimizationMaxError,
4177 optimizationMaxErrorRatio,
4191 jvm->DetachCurrentThread();
4196 std::function<void()> actualCallback = [&](){
4214 optimizationMaxError,
4215 optimizationMaxErrorRatio,
4232 UERROR(
"Failed to call RTABMapActivity::updateStatsCallback");