39 #include <pcl/filters/filter.h> 40 #include <pcl/io/ply_io.h> 41 #include <pcl/io/obj_io.h> 42 #include <pcl/common/common.h> 43 #include <pcl/surface/poisson.h> 51 "rtabmap-exportCloud [options] database.db\n" 53 " --mesh Create a mesh.\n" 54 " --texture Create a mesh with texture.\n" 55 " --texture_size # Texture size (default 4096).\n" 56 " --texture_count # Maximum textures generated (default 1).\n" 57 " --texture_range # Maximum camera range for texturing a polygon (default 0 meters: no limit).\n" 58 " --texture_d2c Distance to camera policy.\n" 59 " --ba Do global bundle adjustment before assembling the clouds.\n" 60 " --gain # Gain compensation value (default 1, set 0 to disable).\n" 61 " --gain_gray Do gain estimation compensation on gray channel only (default RGB channels).\n" 62 " --no_blending Disable blending when texturing.\n" 63 " --no_clean Disable cleaning colorless polygons.\n" 64 " --low_gain # Low brightness gain 0-100 (default 0).\n" 65 " --high_gain # High brightness gain 0-100 (default 10).\n" 66 " --multiband Enable multiband texturing (AliceVision dependency required).\n" 67 " --poisson_depth # Set Poisson depth for mesh reconstruction.\n" 68 " --max_polygons # Maximum polygons when creating a mesh (default 500000, set 0 for no limit).\n" 69 " --max_range # Maximum range of the created clouds (default 4 m, 0 m with --scan).\n" 70 " --decimation # Depth image decimation before creating the clouds (default 4, 1 with --scan).\n" 71 " --voxel # Voxel size of the created clouds (default 0.01 m, 0 m with --scan).\n" 72 " --color_radius # Radius used to colorize polygons (default 0.05 m, 0 m with --scan). Set 0 for nearest color.\n" 73 " --scan Use laser scan for the point cloud.\n" 74 " --save_in_db Save resulting assembled point cloud or mesh in the database.\n" 93 bool doGainCompensationRGB =
true;
95 bool doBlending =
true;
98 int maxPolygons = 500000;
100 float maxRange = -1.0f;
101 float voxelSize = -1.0f;
102 int textureSize = 4096;
103 int textureCount = 1;
104 int textureRange = 0;
105 bool distanceToCamPolicy =
false;
106 bool multiband =
false;
107 float colorRadius = -1.0f;
108 bool cloudFromScan =
false;
109 bool saveInDb =
false;
110 int lowBrightnessGain = 0;
111 int highBrightnessGain = 10;
112 for(
int i=1; i<argc; ++i)
114 if(std::strcmp(argv[i],
"--help") == 0)
118 else if(std::strcmp(argv[i],
"--mesh") == 0)
122 else if(std::strcmp(argv[i],
"--texture") == 0)
126 else if(std::strcmp(argv[i],
"--texture_size") == 0)
139 else if(std::strcmp(argv[i],
"--texture_count") == 0)
151 else if(std::strcmp(argv[i],
"--texture_range") == 0)
163 else if(std::strcmp(argv[i],
"--texture_d2c") == 0)
165 distanceToCamPolicy =
true;
167 else if(std::strcmp(argv[i],
"--ba") == 0)
171 else if(std::strcmp(argv[i],
"--gain_gray") == 0)
173 doGainCompensationRGB =
false;
175 else if(std::strcmp(argv[i],
"--gain") == 0)
188 else if(std::strcmp(argv[i],
"--no_blending") == 0)
192 else if(std::strcmp(argv[i],
"--no_clean") == 0)
196 else if(std::strcmp(argv[i],
"--multiband") == 0)
198 #ifdef RTABMAP_ALICE_VISION 201 printf(
"\"--multiband\" option cannot be used because RTAB-Map is not built with AliceVision support. Ignoring multiband...\n");
204 else if(std::strcmp(argv[i],
"--poisson_depth") == 0)
216 else if(std::strcmp(argv[i],
"--max_polygons") == 0)
228 else if(std::strcmp(argv[i],
"--max_range") == 0)
240 else if(std::strcmp(argv[i],
"--decimation") == 0)
252 else if(std::strcmp(argv[i],
"--voxel") == 0)
264 else if(std::strcmp(argv[i],
"--color_radius") == 0)
276 else if(std::strcmp(argv[i],
"--scan") == 0)
278 cloudFromScan =
true;
280 else if(std::strcmp(argv[i],
"--save_in_db") == 0)
284 else if(std::strcmp(argv[i],
"--low_gain") == 0)
289 lowBrightnessGain =
uStr2Int(argv[i]);
296 else if(std::strcmp(argv[i],
"--high_gain") == 0)
301 highBrightnessGain =
uStr2Int(argv[i]);
312 decimation = cloudFromScan?1:4;
316 maxRange = cloudFromScan?0:4;
320 voxelSize = cloudFromScan?0:0.01f;
322 if(colorRadius < 0.0
f)
324 colorRadius = cloudFromScan?0:0.05f;
331 printf(
"Option --multiband is not supported with --save_in_db option, disabling multiband...\n");
336 printf(
"Option --texture_count > 1 is not supported with --save_in_db option, setting texture_count to 1...\n");
343 std::string dbPath = argv[argc-1];
355 UERROR(
"Cannot open database %s!", dbPath.c_str());
361 for(ParametersMap::iterator iter=params.begin(); iter!=params.end(); ++iter)
363 printf(
"Added custom parameter %s=%s\n",iter->first.c_str(), iter->second.c_str());
368 printf(
"Loading database \"%s\"...\n", dbPath.c_str());
372 rtabmap.init(parameters, dbPath);
373 printf(
"Loading database \"%s\"... done (%fs).\n", dbPath.c_str(), timer.ticks());
375 std::map<int, Signature> nodes;
376 std::map<int, Transform> optimizedPoses;
377 std::multimap<int, Link> links;
378 printf(
"Optimizing the map...\n");
379 rtabmap.getGraph(optimizedPoses, links,
true,
true, &nodes,
true,
true,
true,
true);
380 printf(
"Optimizing the map... done (%fs, poses=%d).\n", timer.ticks(), (int)optimizedPoses.size());
382 if(optimizedPoses.empty())
384 printf(
"The optimized graph is empty!? Aborting...\n");
393 printf(
"Global bundle adjustment...\n");
395 std::map<int, cv::Point3f> points3DMap;
396 std::map<int, std::map<int, FeatureBA> > wordReferences;
398 std::map<int, rtabmap::CameraModel> cameraSingleModels;
399 for(std::map<int, Transform>::iterator iter=optimizedPoses.lower_bound(1); iter!=optimizedPoses.end(); ++iter)
401 Signature node = nodes.find(iter->first)->second;
405 optimizedPoses = g2o.
optimizeBA(optimizedPoses.begin()->first, optimizedPoses, links, cameraSingleModels, points3DMap, wordReferences);
406 printf(
"Global bundle adjustment... done (%fs).\n", timer.ticks());
410 printf(
"Create and assemble the clouds...\n");
411 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr mergedClouds(
new pcl::PointCloud<pcl::PointXYZRGBNormal>);
412 std::map<int, rtabmap::Transform> cameraPoses;
413 std::map<int, std::vector<rtabmap::CameraModel> > cameraModels;
414 std::map<int, cv::Mat> cameraDepths;
416 for(std::map<int, Transform>::iterator iter=optimizedPoses.lower_bound(1); iter!=optimizedPoses.end(); ++iter)
418 Signature node = nodes.find(iter->first)->second;
424 pcl::IndicesPtr indices(
new std::vector<int>);
425 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud;
431 if(decimation>1 || maxRange)
454 Eigen::Vector3f viewpoint(iter->second.x(), iter->second.y(), iter->second.z());
458 viewpoint = Eigen::Vector3f(iter->second.x(), iter->second.y(), iter->second.z());
462 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr cloudWithNormals(
new pcl::PointCloud<pcl::PointXYZRGBNormal>);
463 pcl::concatenateFields(*cloud, *normals, *cloudWithNormals);
465 if(mergedClouds->size() == 0)
467 *mergedClouds = *cloudWithNormals;
471 *mergedClouds += *cloudWithNormals;
474 cameraPoses.insert(std::make_pair(iter->first, iter->second));
477 cameraModels.insert(std::make_pair(iter->first, models));
481 cameraDepths.insert(std::make_pair(iter->first, depth));
484 printf(
"Create and assemble the clouds... done (%fs, %d points).\n", timer.ticks(), (int)mergedClouds->size());
486 if(mergedClouds->size())
499 if(!(mesh || texture))
503 printf(
"Voxel grid filtering of the assembled cloud (voxel=%f, %d points)\n", voxelSize, (
int)mergedClouds->size());
509 printf(
"Saving in db... (%d points)\n", (
int)mergedClouds->size());
511 printf(
"Saving in db... done!\n");
515 std::string outputPath=outputDirectory+
"/"+baseName+
"_cloud.ply";
516 printf(
"Saving %s... (%d points)\n", outputPath.c_str(), (int)mergedClouds->size());
517 pcl::io::savePLYFile(outputPath, *mergedClouds);
518 printf(
"Saving %s... done!\n", outputPath.c_str());
525 float mapLength =
uMax3(max[0]-min[0], max[1]-min[1], max[2]-min[2]);
526 int optimizedDepth = 12;
527 for(
int i=6; i<12; ++i)
529 if(mapLength/
float(1<<i) < 0.03
f)
537 optimizedDepth = poissonDepth;
541 printf(
"Mesh reconstruction... depth=%d\n", optimizedDepth);
542 pcl::PolygonMesh::Ptr mesh(
new pcl::PolygonMesh);
543 pcl::Poisson<pcl::PointXYZRGBNormal> poisson;
544 poisson.setDepth(optimizedDepth);
545 poisson.setInputCloud(mergedClouds);
546 poisson.reconstruct(*mesh);
547 printf(
"Mesh reconstruction... done (%fs, %d polygons).\n", timer.ticks(), (int)mesh->polygons.size());
549 if(mesh->polygons.size())
551 rtabmap::util3d::denseMeshPostProcessing<pcl::PointXYZRGBNormal>(
565 printf(
"Saving mesh in db...\n");
566 std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > polygons;
571 printf(
"Saving mesh in db... done!\n");
575 std::string outputPath=outputDirectory+
"/"+baseName+
"_mesh.ply";
576 printf(
"Saving %s...\n", outputPath.c_str());
577 pcl::io::savePLYFile(outputPath, *mesh);
578 printf(
"Saving %s... done!\n", outputPath.c_str());
583 printf(
"Texturing %d polygons... cameraPoses=%d, cameraDepths=%d\n", (
int)mesh->polygons.size(), (int)cameraPoses.size(), (int)cameraDepths.size());
584 std::vector<std::map<int, pcl::PointXY> > vertexToPixels;
594 std::vector<float>(),
597 distanceToCamPolicy);
598 printf(
"Texturing... done (%fs).\n", timer.ticks());
601 if(doClean && textureMesh->tex_coordinates.size())
603 printf(
"Cleanup mesh...\n");
605 printf(
"Cleanup mesh... done (%fs).\n", timer.ticks());
608 if(textureMesh->tex_materials.size())
612 printf(
"Merging %d texture(s) to single one (multiband enabled)...\n", (
int)textureMesh->tex_materials.size());
616 printf(
"Merging %d texture(s)... (%d max textures)\n", (
int)textureMesh->tex_materials.size(), textureCount);
618 std::map<int, std::map<int, cv::Vec4d> > gains;
619 std::map<int, std::map<int, cv::Mat> > blendingGains;
620 std::pair<float, float> contrastValues(0,0);
623 std::map<int, cv::Mat>(),
624 std::map<
int, std::vector<rtabmap::CameraModel> >(),
628 multiband?1:textureCount,
630 gainValue>0.0f, gainValue, doGainCompensationRGB,
632 lowBrightnessGain, highBrightnessGain,
639 printf(
"Merging to %d texture(s)... done (%fs).\n", (
int)textureMesh->tex_materials.size(), timer.ticks());
643 printf(
"Saving texture mesh in db...\n");
647 textureMesh->tex_coordinates,
649 printf(
"Saving texture mesh in db... done!\n");
654 bool success =
false;
656 for(
size_t i=0; i<textureMesh->tex_materials.size(); ++i)
658 textureMesh->tex_materials[i].tex_file +=
".jpg";
659 printf(
"Saving texture to %s.\n", textureMesh->tex_materials[i].tex_file.c_str());
660 UASSERT(textures.cols % textures.rows == 0);
661 success = cv::imwrite(outputDirectory+
"/"+textureMesh->tex_materials[i].tex_file, cv::Mat(textures,
cv::Range::all(), cv::Range(textures.rows*i, textures.rows*(i+1))));
664 UERROR(
"Failed saving %s!", textureMesh->tex_materials[i].tex_file.c_str());
668 printf(
"Saved %s.\n", textureMesh->tex_materials[i].tex_file.c_str());
674 std::string outputPath=outputDirectory+
"/"+baseName+
"_mesh.obj";
675 printf(
"Saving obj (%d vertices) to %s.\n", (
int)textureMesh->cloud.data.size()/textureMesh->cloud.point_step, outputPath.c_str());
676 success = pcl::io::saveOBJFile(outputPath, *textureMesh) == 0;
680 printf(
"Saved obj to %s!\n", outputPath.c_str());
684 UERROR(
"Failed saving obj to %s!", outputPath.c_str());
692 std::string outputPath=outputDirectory+
"/"+baseName+
"_mesh_multiband.obj";
693 printf(
"MultiBand texturing... \"%s\"\n", outputPath.c_str());
696 textureMesh->tex_polygons[0],
699 std::map<int, cv::Mat >(),
700 std::map<
int, std::vector<CameraModel> >(),
708 doGainCompensationRGB))
710 printf(
"MultiBand texturing...done (%fs).\n", timer.ticks());
714 printf(
"MultiBand texturing...failed! (%fs)\n", timer.ticks());
724 printf(
"Export failed! The cloud is empty.\n");
int UTILITE_EXP uStr2Int(const std::string &str)
GLM_FUNC_DECL genType min(genType const &x, genType const &y)
const cv::Mat & data() const
void saveOptimizedPoses(const std::map< int, Transform > &optimizedPoses, const Transform &lastlocalizationPose) const
pcl::PointCloud< pcl::PointXYZ >::Ptr RTABMAP_EXP transformPointCloud(const pcl::PointCloud< pcl::PointXYZ >::Ptr &cloud, const Transform &transform)
void RTABMAP_EXP getMinMax3D(const cv::Mat &laserScan, cv::Point3f &min, cv::Point3f &max)
static const char * showUsage()
void saveOptimizedMesh(const cv::Mat &cloud, const std::vector< std::vector< std::vector< RTABMAP_PCL_INDEX > > > &polygons=std::vector< std::vector< std::vector< RTABMAP_PCL_INDEX > > >(), const std::vector< std::vector< Eigen::Vector2f > > &texCoords=std::vector< std::vector< Eigen::Vector2f > >(), const cv::Mat &textures=cv::Mat()) const
static std::string getDir(const std::string &filePath)
virtual std::map< int, Transform > optimizeBA(int rootId, const std::map< int, Transform > &poses, const std::multimap< int, Link > &links, const std::map< int, CameraModel > &models, std::map< int, cv::Point3f > &points3DMap, const std::map< int, std::map< int, FeatureBA > > &wordReferences, std::set< int > *outliers=0)
bool RTABMAP_EXP multiBandTexturing(const std::string &outputOBJPath, const pcl::PCLPointCloud2 &cloud, const std::vector< pcl::Vertices > &polygons, const std::map< int, Transform > &cameraPoses, const std::vector< std::map< int, pcl::PointXY > > &vertexToPixels, const std::map< int, cv::Mat > &images, const std::map< int, std::vector< CameraModel > > &cameraModels, const Memory *memory=0, const DBDriver *dbDriver=0, int textureSize=8192, const std::string &textureFormat="jpg", const std::map< int, std::map< int, cv::Vec4d > > &gains=std::map< int, std::map< int, cv::Vec4d > >(), const std::map< int, std::map< int, cv::Mat > > &blendingGains=std::map< int, std::map< int, cv::Mat > >(), const std::pair< float, float > &contrastValues=std::pair< float, float >(0, 0), bool gainRGB=true)
static ParametersMap parseArguments(int argc, char *argv[], bool onlyParameters=false)
float UTILITE_EXP uStr2Float(const std::string &str)
GLM_FUNC_DECL bool all(vecType< bool, P > const &v)
std::map< std::string, std::string > ParametersMap
Basic mathematics functions.
const LaserScan & laserScanRaw() const
static void setLevel(ULogger::Level level)
std::list< std::string > uSplit(const std::string &str, char separator= ' ')
bool openConnection(const std::string &url, bool overwritten=false)
#define UASSERT(condition)
Wrappers of STL for convenient functions.
pcl::PointCloud< pcl::PointXYZRGB >::Ptr RTABMAP_EXP laserScanToPointCloudRGB(const LaserScan &laserScan, const Transform &transform=Transform(), unsigned char r=100, unsigned char g=100, unsigned char b=100)
int main(int argc, char *argv[])
LaserScan RTABMAP_EXP commonFiltering(const LaserScan &scan, int downsamplingStep, float rangeMin=0.0f, float rangeMax=0.0f, float voxelSize=0.0f, int normalK=0, float normalRadius=0.0f, float groundNormalsUp=0.0f)
const cv::Mat & depthOrRightCompressed() const
T uMax3(const T &a, const T &b, const T &c)
void closeConnection(bool save=true, const std::string &outputUrl="")
pcl::PointCloud< pcl::PointXYZRGB >::Ptr RTABMAP_EXP cloudRGBFromSensorData(const SensorData &sensorData, int decimation=1, float maxDepth=0.0f, float minDepth=0.0f, std::vector< int > *validIndices=0, const ParametersMap &stereoParameters=ParametersMap(), const std::vector< float > &roiRatios=std::vector< float >())
static void setType(Type type, const std::string &fileName=kDefaultLogFileName, bool append=true)
cv::Mat RTABMAP_EXP computeNormals(const cv::Mat &laserScan, int searchK, float searchRadius)
Transform localTransform() const
static DBDriver * create(const ParametersMap ¶meters=ParametersMap())
cv::Mat RTABMAP_EXP mergeTextures(pcl::TextureMesh &mesh, const std::map< int, cv::Mat > &images, const std::map< int, CameraModel > &calibrations, const Memory *memory=0, const DBDriver *dbDriver=0, int textureSize=4096, int textureCount=1, const std::vector< std::map< int, pcl::PointXY > > &vertexToPixels=std::vector< std::map< int, pcl::PointXY > >(), bool gainCompensation=true, float gainBeta=10.0f, bool gainRGB=true, bool blending=true, int blendingDecimation=0, int brightnessContrastRatioLow=0, int brightnessContrastRatioHigh=0, bool exposureFusion=false, const ProgressState *state=0, unsigned char blankValue=255, std::map< int, std::map< int, cv::Vec4d > > *gains=0, std::map< int, std::map< int, cv::Mat > > *blendingGains=0, std::pair< float, float > *contrastValues=0)
std::vector< std::vector< RTABMAP_PCL_INDEX > > RTABMAP_EXP convertPolygonsFromPCL(const std::vector< pcl::Vertices > &polygons)
pcl::TextureMesh::Ptr RTABMAP_EXP createTextureMesh(const pcl::PolygonMesh::Ptr &mesh, const std::map< int, Transform > &poses, const std::map< int, CameraModel > &cameraModels, const std::map< int, cv::Mat > &cameraDepths, float maxDistance=0.0f, float maxDepthError=0.0f, float maxAngle=0.0f, int minClusterSize=50, const std::vector< float > &roiRatios=std::vector< float >(), const ProgressState *state=0, std::vector< std::map< int, pcl::PointXY > > *vertexToPixels=0, bool distanceToCamPolicy=false)
const std::vector< CameraModel > & cameraModels() const
GLM_FUNC_DECL genType max(genType const &x, genType const &y)
SensorData & sensorData()
void RTABMAP_EXP cleanTextureMesh(pcl::TextureMesh &textureMesh, int minClusterSize)
ParametersMap getLastParameters() const
void computeBACorrespondences(const std::map< int, Transform > &poses, const std::multimap< int, Link > &links, const std::map< int, Signature > &signatures, std::map< int, cv::Point3f > &points3DMap, std::map< int, std::map< int, FeatureBA > > &wordReferences, bool rematchFeatures=false)
pcl::PointCloud< pcl::PointXYZ >::Ptr RTABMAP_EXP voxelize(const pcl::PointCloud< pcl::PointXYZ >::Ptr &cloud, const pcl::IndicesPtr &indices, float voxelSize)
void save2DMap(const cv::Mat &map, float xMin, float yMin, float cellSize) const
void uInsert(std::map< K, V > &map, const std::pair< K, V > &pair)
std::map< int, Transform > loadOptimizedPoses(Transform *lastlocalizationPose=0) const
LaserScan RTABMAP_EXP laserScanFromPointCloud(const pcl::PCLPointCloud2 &cloud, bool filterNaNs=true, bool is2D=false, const Transform &transform=Transform())