42 #include <opencv2/core/core_c.h> 43 #include <opencv2/imgproc/types_c.h> 44 #include <pcl/search/kdtree.h> 45 #include <pcl/surface/gp3.h> 46 #include <pcl/features/normal_3d_omp.h> 47 #include <pcl/surface/mls.h> 49 #include <pcl/features/integral_image_normal.h> 51 #ifdef RTABMAP_ALICE_VISION 52 #include <aliceVision/sfmData/SfMData.hpp> 53 #include <aliceVision/sfmDataIO/sfmDataIO.hpp> 54 #include <aliceVision/mesh/Mesh.hpp> 55 #include <aliceVision/mesh/Texturing.hpp> 56 #include <aliceVision/camera/Pinhole.hpp> 57 #include <boost/algorithm/string.hpp> 58 using namespace aliceVision;
62 #include <pcl/surface/vtk_smoothing/vtk_mesh_quadric_decimation.h> 65 #if PCL_VERSION_COMPARE(>, 1, 11, 1) 66 #include <pcl/types.h> 68 #if PCL_VERSION_COMPARE(<, 1, 8, 0) 71 #include <pcl/surface/organized_fast_mesh.h> 72 #include <pcl/surface/impl/marching_cubes.hpp> 73 #include <pcl/surface/impl/organized_fast_mesh.hpp> 74 #include <pcl/impl/instantiate.hpp> 75 #include <pcl/point_types.h> 78 PCL_INSTANTIATE(OrganizedFastMesh, (pcl::PointXYZRGBNormal))
80 #include <pcl/features/impl/normal_3d_omp.hpp> 81 #if PCL_VERSION_COMPARE(<=, 1, 8, 0) 82 #ifdef PCL_ONLY_CORE_POINT_TYPES 83 PCL_INSTANTIATE_PRODUCT(NormalEstimationOMP, ((pcl::PointXYZRGB))((pcl::Normal)))
95 const std::vector<pcl::Vertices> & polygons,
97 std::vector<std::set<int> > & neighbors,
98 std::vector<std::set<int> > & vertexToPolygons)
100 vertexToPolygons = std::vector<std::set<int> >(cloudSize);
101 neighbors = std::vector<std::set<int> >(polygons.size());
103 for(
unsigned int i=0; i<polygons.size(); ++i)
105 std::set<int>
vertices(polygons[i].
vertices.begin(), polygons[i].vertices.end());
107 for(
unsigned int j=0; j<polygons[i].vertices.size(); ++j)
109 int v = polygons[i].vertices.at(j);
110 for(std::set<int>::iterator iter=vertexToPolygons[v].begin(); iter!=vertexToPolygons[v].end(); ++iter)
112 int numSharedVertices = 0;
113 for(
unsigned int k=0; k<polygons.at(*iter).vertices.size() && numSharedVertices<2; ++k)
120 if(numSharedVertices >= 2)
122 neighbors[*iter].insert(i);
123 neighbors[i].insert(*iter);
126 vertexToPolygons[v].insert(i);
132 const std::vector<std::set<int> > & neighborPolygons,
135 std::set<int> polygonsChecked;
137 std::list<std::list<int> > clusters;
139 for(
unsigned int i=0; i<neighborPolygons.size(); ++i)
141 if(polygonsChecked.find(i) == polygonsChecked.end())
143 std::list<int> currentCluster;
144 currentCluster.push_back(i);
145 polygonsChecked.insert(i);
147 for(std::list<int>::iterator iter=currentCluster.begin(); iter!=currentCluster.end(); ++iter)
150 std::set<int> neighbors = neighborPolygons[*iter];
151 for(std::set<int>::iterator jter=neighbors.begin(); jter!=neighbors.end(); ++jter)
153 if(polygonsChecked.insert(*jter).second)
155 currentCluster.push_back(*jter);
159 if((
int)currentCluster.size() > minClusterSize)
161 clusters.push_back(currentCluster);
169 const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
170 double angleTolerance,
172 int trianglePixelSize,
173 const Eigen::Vector3f & viewpoint)
175 UDEBUG(
"size=%d angle=%f quad=%d triangleSize=%d", (
int)cloud->size(), angleTolerance, quad?1:0, trianglePixelSize);
176 UASSERT(cloud->is_dense ==
false);
177 UASSERT(cloud->width > 1 && cloud->height > 1);
182 ofm.setInputCloud (cloud);
186 std::vector<pcl::Vertices>
vertices;
187 ofm.reconstruct (vertices);
192 std::vector<pcl::Vertices> output(vertices.size());
193 for(
unsigned int i=0; i<vertices.size(); ++i)
195 output[i].vertices.resize(4);
196 output[i].vertices[0] = vertices[i].vertices[0];
197 output[i].vertices[3] = vertices[i].vertices[1];
198 output[i].vertices[2] = vertices[i].vertices[2];
199 output[i].vertices[1] = vertices[i].vertices[3];
207 const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
208 double angleTolerance,
210 int trianglePixelSize,
211 const Eigen::Vector3f & viewpoint)
213 UDEBUG(
"size=%d angle=%f quad=%d triangleSize=%d", (
int)cloud->size(), angleTolerance, quad?1:0, trianglePixelSize);
214 UASSERT(cloud->is_dense ==
false);
215 UASSERT(cloud->width > 1 && cloud->height > 1);
220 ofm.setInputCloud (cloud);
224 std::vector<pcl::Vertices>
vertices;
225 ofm.reconstruct (vertices);
230 std::vector<pcl::Vertices> output(vertices.size());
231 for(
unsigned int i=0; i<vertices.size(); ++i)
233 output[i].vertices.resize(4);
234 output[i].vertices[0] = vertices[i].vertices[0];
235 output[i].vertices[3] = vertices[i].vertices[1];
236 output[i].vertices[2] = vertices[i].vertices[2];
237 output[i].vertices[1] = vertices[i].vertices[3];
245 const pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud,
246 double angleTolerance,
248 int trianglePixelSize,
249 const Eigen::Vector3f & viewpoint)
251 UDEBUG(
"size=%d angle=%f quad=%d triangleSize=%d", (
int)cloud->size(), angleTolerance, quad?1:0, trianglePixelSize);
252 UASSERT(cloud->is_dense ==
false);
253 UASSERT(cloud->width > 1 && cloud->height > 1);
258 ofm.setInputCloud (cloud);
262 std::vector<pcl::Vertices>
vertices;
263 ofm.reconstruct (vertices);
268 std::vector<pcl::Vertices> output(vertices.size());
269 for(
unsigned int i=0; i<vertices.size(); ++i)
271 output[i].vertices.resize(4);
272 output[i].vertices[0] = vertices[i].vertices[0];
273 output[i].vertices[3] = vertices[i].vertices[1];
274 output[i].vertices[2] = vertices[i].vertices[2];
275 output[i].vertices[1] = vertices[i].vertices[3];
284 pcl::PointCloud<pcl::PointXYZRGBNormal> & cloudA,
285 std::vector<pcl::Vertices> & polygonsA,
286 const pcl::PointCloud<pcl::PointXYZRGBNormal> & cloudB,
287 const std::vector<pcl::Vertices> & polygonsB)
289 UDEBUG(
"cloudA=%d polygonsA=%d cloudB=%d polygonsB=%d", (
int)cloudA.size(), (int)polygonsA.size(), (int)cloudB.size(), (int)polygonsB.size());
290 UASSERT(!cloudA.isOrganized() && !cloudB.isOrganized());
292 int sizeA = (int)cloudA.size();
295 int sizePolygonsA = (int)polygonsA.size();
296 polygonsA.resize(sizePolygonsA+polygonsB.size());
298 for(
unsigned int i=0; i<polygonsB.size(); ++i)
300 pcl::Vertices
vertices = polygonsB[i];
301 for(
unsigned int j=0; j<vertices.vertices.size(); ++j)
303 vertices.vertices[j] += sizeA;
305 polygonsA[i+sizePolygonsA] =
vertices;
310 pcl::PointCloud<pcl::PointXYZRGB> & cloudA,
311 std::vector<pcl::Vertices> & polygonsA,
312 const pcl::PointCloud<pcl::PointXYZRGB> & cloudB,
313 const std::vector<pcl::Vertices> & polygonsB)
315 UDEBUG(
"cloudA=%d polygonsA=%d cloudB=%d polygonsB=%d", (
int)cloudA.size(), (int)polygonsA.size(), (int)cloudB.size(), (int)polygonsB.size());
316 UASSERT(!cloudA.isOrganized() && !cloudB.isOrganized());
318 int sizeA = (int)cloudA.size();
321 int sizePolygonsA = (int)polygonsA.size();
322 polygonsA.resize(sizePolygonsA+polygonsB.size());
324 for(
unsigned int i=0; i<polygonsB.size(); ++i)
326 pcl::Vertices
vertices = polygonsB[i];
327 for(
unsigned int j=0; j<vertices.vertices.size(); ++j)
329 vertices.vertices[j] += sizeA;
331 polygonsA[i+sizePolygonsA] =
vertices;
336 const pcl::PointCloud<pcl::PointXYZRGBNormal> & cloud,
337 const std::vector<pcl::Vertices> & polygons,
338 pcl::PointCloud<pcl::PointXYZRGBNormal> & outputCloud,
339 std::vector<pcl::Vertices> & outputPolygons)
341 UDEBUG(
"size=%d polygons=%d", (
int)cloud.size(), (int)polygons.size());
342 std::map<int, int> addedVertices;
343 std::vector<int> output;
344 output.resize(cloud.size());
345 outputCloud.resize(cloud.size());
346 outputCloud.is_dense =
true;
347 outputPolygons.resize(polygons.size());
349 for(
unsigned int i=0; i<polygons.size(); ++i)
351 pcl::Vertices & v = outputPolygons[i];
352 v.vertices.resize(polygons[i].
vertices.size());
353 for(
unsigned int j=0; j<polygons[i].vertices.size(); ++j)
355 std::map<int, int>::iterator iter = addedVertices.find(polygons[i].
vertices[j]);
356 if(iter == addedVertices.end())
358 outputCloud[oi] = cloud.at(polygons[i].
vertices[j]);
359 addedVertices.insert(std::make_pair(polygons[i].
vertices[j], oi));
360 output[oi] = polygons[i].vertices[j];
361 v.vertices[j] = oi++;
365 v.vertices[j] = iter->second;
369 outputCloud.resize(oi);
376 const pcl::PointCloud<pcl::PointXYZRGB> & cloud,
377 const std::vector<pcl::Vertices> & polygons,
378 pcl::PointCloud<pcl::PointXYZRGB> & outputCloud,
379 std::vector<pcl::Vertices> & outputPolygons)
381 UDEBUG(
"size=%d polygons=%d", (
int)cloud.size(), (int)polygons.size());
382 std::map<int, int> addedVertices;
383 std::vector<int> output;
384 output.resize(cloud.size());
385 outputCloud.resize(cloud.size());
386 outputCloud.is_dense =
true;
387 outputPolygons.resize(polygons.size());
389 for(
unsigned int i=0; i<polygons.size(); ++i)
391 pcl::Vertices & v = outputPolygons[i];
392 v.vertices.resize(polygons[i].
vertices.size());
393 for(
unsigned int j=0; j<polygons[i].vertices.size(); ++j)
395 std::map<int, int>::iterator iter = addedVertices.find(polygons[i].
vertices[j]);
396 if(iter == addedVertices.end())
398 outputCloud[oi] = cloud.at(polygons[i].
vertices[j]);
399 addedVertices.insert(std::make_pair(polygons[i].
vertices[j], oi));
400 output[oi] = polygons[i].vertices[j];
401 v.vertices[j] = oi++;
405 v.vertices[j] = iter->second;
409 outputCloud.resize(oi);
416 const pcl::PointCloud<pcl::PointXYZRGB> & cloud,
417 const std::vector<pcl::Vertices> & polygons,
418 pcl::PointCloud<pcl::PointXYZRGB> & outputCloud,
419 std::vector<pcl::Vertices> & outputPolygons)
421 UDEBUG(
"size=%d polygons=%d", (
int)cloud.size(), (int)polygons.size());
422 std::map<int, int> addedVertices;
423 std::vector<int> output;
424 output.resize(cloud.size());
425 outputCloud.resize(cloud.size());
426 outputCloud.is_dense =
true;
427 std::vector<int> organizedToDense(cloud.size(), -1);
430 for(
unsigned int i=0; i<cloud.size(); ++i)
434 outputCloud.at(oi) = cloud.at(i);
436 organizedToDense[i] = oi;
440 outputCloud.resize(oi);
444 outputPolygons = polygons;
445 for(
unsigned int i=0; i<outputPolygons.size(); ++i)
447 pcl::Vertices & v = outputPolygons[i];
448 for(
unsigned int j=0; j<v.vertices.size(); ++j)
450 UASSERT(organizedToDense[v.vertices[j]] >= 0);
451 v.vertices[j] = organizedToDense[v.vertices[j]];
459 const pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr cloud,
460 const std::vector<pcl::Vertices> & polygons,
463 bool keepLatestInRadius)
465 UDEBUG(
"size=%d polygons=%d radius=%f angle=%f keepLatest=%d",
466 (
int)cloud->size(), (int)polygons.size(), radius,
angle, keepLatestInRadius?1:0);
467 std::vector<pcl::Vertices> outputPolygons;
468 pcl::KdTreeFLANN<pcl::PointXYZRGBNormal>::Ptr kdtree(
new pcl::KdTreeFLANN<pcl::PointXYZRGBNormal>);
469 kdtree->setInputCloud(cloud);
471 std::map<int, int> verticesDone;
472 outputPolygons = polygons;
473 for(
unsigned int i=0; i<outputPolygons.size(); ++i)
475 pcl::Vertices & polygon = outputPolygons[i];
476 for(
unsigned int j=0; j<polygon.vertices.size(); ++j)
478 std::map<int, int>::iterator iter = verticesDone.find(polygon.vertices[j]);
479 if(iter != verticesDone.end())
481 polygon.vertices[j] = iter->second;
486 std::vector<float> kDistances;
487 kdtree->radiusSearch(polygon.vertices[j], radius, kIndices, kDistances);
491 for(
unsigned int z=0; z<kIndices.size(); ++z)
495 reference = kIndices[z];
497 else if(keepLatestInRadius)
499 if(kIndices[z] < reference)
501 reference = kIndices[z];
506 if(kIndices[z] > reference)
508 reference = kIndices[z];
514 for(
unsigned int z=0; z<kIndices.size(); ++z)
516 verticesDone.insert(std::make_pair(kIndices[j], reference));
518 polygon.vertices[j] = reference;
523 verticesDone.insert(std::make_pair(polygon.vertices[j], polygon.vertices[j]));
528 return outputPolygons;
533 std::vector<pcl::Vertices> output(polygons.size());
535 for(
unsigned int i=0; i<polygons.size(); ++i)
538 for(
unsigned int j=0; j<polygons[i].vertices.size(); ++j)
540 if(polygons[i].
vertices[j] == polygons[i].
vertices[(j+1)%polygons[i].vertices.size()])
548 output[oi++] = polygons[i];
556 const pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloudWithNormals,
557 float gp3SearchRadius,
559 int gp3MaximumNearestNeighbors,
560 float gp3MaximumSurfaceAngle,
561 float gp3MinimumAngle,
562 float gp3MaximumAngle,
563 bool gp3NormalConsistency)
568 pcl::search::KdTree<pcl::PointXYZRGBNormal>::Ptr tree2 (
new pcl::search::KdTree<pcl::PointXYZRGBNormal>);
569 tree2->setInputCloud (cloudWithNormalsNoNaN);
572 pcl::GreedyProjectionTriangulation<pcl::PointXYZRGBNormal> gp3;
573 pcl::PolygonMesh::Ptr mesh(
new pcl::PolygonMesh);
576 gp3.setSearchRadius (gp3SearchRadius);
580 gp3.setMaximumNearestNeighbors (gp3MaximumNearestNeighbors);
581 gp3.setMaximumSurfaceAngle(gp3MaximumSurfaceAngle);
582 gp3.setMinimumAngle(gp3MinimumAngle);
583 gp3.setMaximumAngle(gp3MaximumAngle);
584 gp3.setNormalConsistency(gp3NormalConsistency);
585 gp3.setConsistentVertexOrdering(gp3NormalConsistency);
588 gp3.setInputCloud (cloudWithNormalsNoNaN);
589 gp3.setSearchMethod (tree2);
590 gp3.reconstruct (*mesh);
599 const std::map<int, Transform> & poses,
600 const std::map<
int, std::vector<CameraModel> > & cameraModels,
601 const std::map<int, cv::Mat> & cameraDepths,
602 const std::vector<float> & roiRatios)
604 UASSERT_MSG(poses.size() == cameraModels.size(),
uFormat(
"%d vs %d", (
int)poses.size(), (int)cameraModels.size()).c_str());
605 UASSERT(roiRatios.empty() || roiRatios.size() == 4);
607 std::map<int, Transform>::const_iterator poseIter=poses.begin();
608 std::map<int, std::vector<CameraModel> >::const_iterator modelIter=cameraModels.begin();
609 for(; poseIter!=poses.end(); ++poseIter, ++modelIter)
611 UASSERT(poseIter->first == modelIter->first);
613 std::map<int, cv::Mat>::const_iterator depthIter = cameraDepths.find(poseIter->first);
616 for(
unsigned int i=0; i<modelIter->second.size(); ++i)
620 UASSERT(!modelIter->second[i].localTransform().isNull() && !poseIter->second.isNull());
621 Transform t = poseIter->second*modelIter->second[i].localTransform();
623 cam.
pose = t.toEigen3f();
625 if(modelIter->second[i].imageHeight() <=0 || modelIter->second[i].imageWidth() <=0)
627 UERROR(
"Should have camera models with width/height set to create texture cameras!");
631 UASSERT(modelIter->second[i].fx()>0 && modelIter->second[i].imageHeight()>0 && modelIter->second[i].imageWidth()>0);
633 cam.
height=modelIter->second[i].imageHeight();
634 cam.
width=modelIter->second[i].imageWidth();
635 if(modelIter->second.size() == 1)
643 if(!roiRatios.empty())
646 cam.
roi[0] = cam.
width * roiRatios[0];
648 cam.
roi[2] = cam.
width * (1.0 - roiRatios[1]) - cam.
roi[0];
649 cam.
roi[3] = cam.
height * (1.0 - roiRatios[3]) - cam.
roi[1];
652 if(depthIter != cameraDepths.end() && !depthIter->second.empty())
654 UASSERT(depthIter->second.type() == CV_32FC1 || depthIter->second.type() == CV_16UC1);
655 UASSERT(depthIter->second.cols % modelIter->second.size() == 0);
656 int subWidth = depthIter->second.cols/(modelIter->second.size());
657 cam.
depth = cv::Mat(depthIter->second, cv::Range(0, depthIter->second.rows), cv::Range(subWidth*i, subWidth*(i+1)));
663 UDEBUG(
"cam.pose=%s", t.prettyPrint().c_str());
665 cameras.push_back(cam);
672 const pcl::PolygonMesh::Ptr & mesh,
673 const std::map<int, Transform> & poses,
674 const std::map<int, CameraModel> & cameraModels,
675 const std::map<int, cv::Mat> & cameraDepths,
680 const std::vector<float> & roiRatios,
682 std::vector<std::map<int, pcl::PointXY> > * vertexToPixels,
683 bool distanceToCamPolicy)
685 std::map<int, std::vector<CameraModel> > cameraSubModels;
686 for(std::map<int, CameraModel>::const_iterator iter=cameraModels.begin(); iter!=cameraModels.end(); ++iter)
688 std::vector<CameraModel> models;
689 models.push_back(iter->second);
690 cameraSubModels.insert(std::make_pair(iter->first, models));
705 distanceToCamPolicy);
709 const pcl::PolygonMesh::Ptr & mesh,
710 const std::map<int, Transform> & poses,
711 const std::map<
int, std::vector<CameraModel> > & cameraModels,
712 const std::map<int, cv::Mat> & cameraDepths,
717 const std::vector<float> & roiRatios,
719 std::vector<std::map<int, pcl::PointXY> > * vertexToPixels,
720 bool distanceToCamPolicy)
722 UASSERT(mesh->polygons.size());
723 pcl::TextureMesh::Ptr textureMesh(
new pcl::TextureMesh);
724 textureMesh->cloud = mesh->cloud;
725 textureMesh->tex_polygons.push_back(mesh->polygons);
740 textureMesh->tex_materials.resize (cameras.size () + 1);
741 for(
unsigned int i = 0 ; i <= cameras.size() ; ++i)
743 pcl::TexMaterial mesh_material;
744 mesh_material.tex_Ka.r = 0.2f;
745 mesh_material.tex_Ka.g = 0.2f;
746 mesh_material.tex_Ka.b = 0.2f;
748 mesh_material.tex_Kd.r = 0.8f;
749 mesh_material.tex_Kd.g = 0.8f;
750 mesh_material.tex_Kd.b = 0.8f;
752 mesh_material.tex_Ks.r = 1.0f;
753 mesh_material.tex_Ks.g = 1.0f;
754 mesh_material.tex_Ks.b = 1.0f;
756 mesh_material.tex_d = 1.0f;
757 mesh_material.tex_Ns = 75.0f;
758 mesh_material.tex_illum = 2;
760 std::stringstream tex_name;
761 tex_name <<
"material_" << i;
762 tex_name >> mesh_material.tex_name;
764 if(i < cameras.size ())
766 mesh_material.tex_file = cameras[i].texture_file;
770 mesh_material.tex_file =
"occluded";
773 textureMesh->tex_materials[i] = mesh_material;
780 if(maxDepthError > 0.0
f)
788 bool hasNormals =
false;
789 bool hasColors =
false;
790 for(
unsigned int i=0; i<textureMesh->cloud.fields.size(); ++i)
792 if(textureMesh->cloud.fields[i].name.compare(
"normal_x") == 0)
796 else if(textureMesh->cloud.fields[i].name.compare(
"rgb") == 0)
806 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr cloud (
new pcl::PointCloud<pcl::PointXYZRGBNormal>);
807 pcl::fromPCLPointCloud2(mesh->cloud, *cloud);
809 for(
unsigned int i=0; i<mesh->polygons.size(); ++i)
811 pcl::Vertices & v = mesh->polygons[i];
814 cloud->at(v.vertices[1]).x - cloud->at(v.vertices[0]).x,
815 cloud->at(v.vertices[1]).y - cloud->at(v.vertices[0]).y,
816 cloud->at(v.vertices[1]).z - cloud->at(v.vertices[0]).z);
817 int last = v.vertices.size()-1;
819 cloud->at(v.vertices[last]).x - cloud->at(v.vertices[0]).x,
820 cloud->at(v.vertices[last]).y - cloud->at(v.vertices[0]).y,
821 cloud->at(v.vertices[last]).z - cloud->at(v.vertices[0]).z);
822 Eigen::Vector3f normal = v0.cross(v1);
825 for(
unsigned int j=0; j<v.vertices.size(); ++j)
827 cloud->at(v.vertices[j]).normal_x = normal[0];
828 cloud->at(v.vertices[j]).normal_y = normal[1];
829 cloud->at(v.vertices[j]).normal_z = normal[2];
832 pcl::toPCLPointCloud2 (*cloud, textureMesh->cloud);
836 pcl::PointCloud<pcl::PointNormal>::Ptr cloud (
new pcl::PointCloud<pcl::PointNormal>);
837 pcl::fromPCLPointCloud2(mesh->cloud, *cloud);
839 for(
unsigned int i=0; i<mesh->polygons.size(); ++i)
841 pcl::Vertices & v = mesh->polygons[i];
844 cloud->at(v.vertices[1]).x - cloud->at(v.vertices[0]).x,
845 cloud->at(v.vertices[1]).y - cloud->at(v.vertices[0]).y,
846 cloud->at(v.vertices[1]).z - cloud->at(v.vertices[0]).z);
847 int last = v.vertices.size()-1;
849 cloud->at(v.vertices[last]).x - cloud->at(v.vertices[0]).x,
850 cloud->at(v.vertices[last]).y - cloud->at(v.vertices[0]).y,
851 cloud->at(v.vertices[last]).z - cloud->at(v.vertices[0]).z);
852 Eigen::Vector3f normal = v0.cross(v1);
855 for(
unsigned int j=0; j<v.vertices.size(); ++j)
857 cloud->at(v.vertices[j]).normal_x = normal[0];
858 cloud->at(v.vertices[j]).normal_y = normal[1];
859 cloud->at(v.vertices[j]).normal_z = normal[2];
862 pcl::toPCLPointCloud2 (*cloud, textureMesh->cloud);
870 pcl::TextureMesh & textureMesh,
873 UDEBUG(
"minClusterSize=%d", minClusterSize);
875 if(textureMesh.tex_coordinates.size())
878 textureMesh.tex_coordinates.pop_back();
879 textureMesh.tex_polygons.pop_back();
880 textureMesh.tex_materials.pop_back();
882 if(minClusterSize!=0)
885 unsigned int totalSize = 0;
886 for(
unsigned int t=0; t<textureMesh.tex_polygons.size(); ++t)
888 totalSize+=textureMesh.tex_polygons[t].size();
890 std::vector<pcl::Vertices> allPolygons(totalSize);
892 for(
unsigned int t=0; t<textureMesh.tex_polygons.size(); ++t)
894 for(
unsigned int i=0; i<textureMesh.tex_polygons[t].size(); ++i)
896 allPolygons[oi++] = textureMesh.tex_polygons[t][i];
901 std::vector<std::set<int> > neighbors;
902 std::vector<std::set<int> > vertexToPolygons;
904 (
int)textureMesh.cloud.data.size()/textureMesh.cloud.point_step,
910 minClusterSize<0?0:minClusterSize);
912 std::set<int> validPolygons;
913 if(minClusterSize < 0)
916 std::list<std::list<int> >::iterator biggestClusterIndex = clusters.end();
917 unsigned int biggestClusterSize = 0;
918 for(std::list<std::list<int> >::iterator iter=clusters.begin(); iter!=clusters.end(); ++iter)
920 if(iter->size() > biggestClusterSize)
922 biggestClusterIndex = iter;
923 biggestClusterSize = iter->size();
926 if(biggestClusterIndex != clusters.end())
928 for(std::list<int>::iterator jter=biggestClusterIndex->begin(); jter!=biggestClusterIndex->end(); ++jter)
930 validPolygons.insert(*jter);
936 for(std::list<std::list<int> >::iterator iter=clusters.begin(); iter!=clusters.end(); ++iter)
938 for(std::list<int>::iterator jter=iter->begin(); jter!=iter->end(); ++jter)
940 validPolygons.insert(*jter);
945 if(validPolygons.size() == 0)
947 UWARN(
"All %d polygons filtered after polygon cluster filtering. Cluster minimum size is %d.",totalSize, minClusterSize);
951 unsigned int allPolygonsIndex = 0;
952 for(
unsigned int t=0; t<textureMesh.tex_polygons.size(); ++t)
954 std::vector<pcl::Vertices> filteredPolygons(textureMesh.tex_polygons[t].size());
955 #if PCL_VERSION_COMPARE(>=, 1, 8, 0) 956 std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > filteredCoordinates(textureMesh.tex_coordinates[t].size());
958 std::vector<Eigen::Vector2f> filteredCoordinates(textureMesh.tex_coordinates[t].size());
961 if(textureMesh.tex_polygons[t].size())
963 UASSERT_MSG(allPolygonsIndex < allPolygons.size(),
uFormat(
"%d vs %d", (
int)allPolygonsIndex, (
int)allPolygons.size()).c_str());
966 std::vector<unsigned int> polygonToCoord(textureMesh.tex_polygons[t].size());
967 unsigned int totalCoord = 0;
968 for(
unsigned int i=0; i<textureMesh.tex_polygons[t].size(); ++i)
970 polygonToCoord[i] = totalCoord;
971 totalCoord+=textureMesh.tex_polygons[t][i].vertices.size();
973 UASSERT_MSG(totalCoord == textureMesh.tex_coordinates[t].size(),
uFormat(
"%d vs %d", totalCoord, (
int)textureMesh.tex_coordinates[t].size()).c_str());
977 for(
unsigned int i=0; i<textureMesh.tex_polygons[t].size(); ++i)
979 if(validPolygons.find(allPolygonsIndex) != validPolygons.end())
981 filteredPolygons[oi] = textureMesh.tex_polygons[t].at(i);
982 for(
unsigned int j=0; j<filteredPolygons[oi].vertices.size(); ++j)
984 UASSERT(polygonToCoord[i] < textureMesh.tex_coordinates[t].size());
985 filteredCoordinates[ci] = textureMesh.tex_coordinates[t][polygonToCoord[i]+j];
992 filteredPolygons.resize(oi);
993 filteredCoordinates.resize(ci);
994 textureMesh.tex_polygons[t] = filteredPolygons;
995 textureMesh.tex_coordinates[t] = filteredCoordinates;
1004 pcl::TextureMesh::Ptr output(
new pcl::TextureMesh);
1005 std::map<std::string, int> addedMaterials;
1006 for(std::list<pcl::TextureMesh::Ptr>::const_iterator iter = meshes.begin(); iter!=meshes.end(); ++iter)
1008 if((*iter)->cloud.point_step &&
1009 (*iter)->cloud.data.size()/(*iter)->cloud.point_step &&
1010 (*iter)->tex_polygons.size() &&
1011 (*iter)->tex_coordinates.size())
1014 int polygonStep = output->cloud.height * output->cloud.width;
1015 pcl::PCLPointCloud2 tmp;
1016 #if PCL_VERSION_COMPARE(>=, 1, 10, 0) 1019 pcl::concatenatePointCloud(output->cloud, iter->get()->cloud, tmp);
1021 output->cloud = tmp;
1023 UASSERT((*iter)->tex_polygons.size() == (*iter)->tex_coordinates.size() &&
1024 (*iter)->tex_polygons.size() == (*iter)->tex_materials.size());
1026 int materialCount = (*iter)->tex_polygons.size();
1027 for(
int i=0; i<materialCount; ++i)
1029 std::map<std::string, int>::iterator jter = addedMaterials.find((*iter)->tex_materials[i].tex_file);
1031 if(jter != addedMaterials.end())
1033 index = jter->second;
1037 addedMaterials.insert(std::make_pair((*iter)->tex_materials[i].tex_file, output->tex_materials.size()));
1038 index = output->tex_materials.size();
1039 output->tex_materials.push_back((*iter)->tex_materials[i]);
1040 output->tex_materials.back().tex_name =
uFormat(
"material_%d", index);
1041 output->tex_polygons.resize(output->tex_polygons.size() + 1);
1042 output->tex_coordinates.resize(output->tex_coordinates.size() + 1);
1046 int oi = output->tex_polygons[index].size();
1047 output->tex_polygons[index].resize(output->tex_polygons[index].size() + (*iter)->tex_polygons[i].size());
1048 for(
unsigned int j=0; j<(*iter)->tex_polygons[i].size(); ++j)
1050 pcl::Vertices polygon = (*iter)->tex_polygons[i][j];
1051 for(
unsigned int k=0; k<polygon.vertices.size(); ++k)
1053 polygon.vertices[k] += polygonStep;
1055 output->tex_polygons[index][oi+j] = polygon;
1059 oi = output->tex_coordinates[index].size();
1060 output->tex_coordinates[index].resize(output->tex_coordinates[index].size() + (*iter)->tex_coordinates[i].size());
1061 for(
unsigned int j=0; j<(*iter)->tex_coordinates[i].size(); ++j)
1063 output->tex_coordinates[index][oi+j] = (*iter)->tex_coordinates[i][j];
1072 return b == 0 ? a :
gcd(b, a % b);
1077 UASSERT(textureSize>0 && imageSize.width>0 && imageSize.height>0);
1083 for(
unsigned int i=0; i<mesh.tex_materials.size(); ++i)
1085 if(mesh.tex_polygons.size())
1092 int w = imageSize.width;
1093 int h = imageSize.height;
1097 UDEBUG(
"w=%d h=%d g=%d a=%d b=%d", w, h, g, a, b);
1100 float factor = 0.1f;
1103 while((colCount*rowCount)*maxTextures < materials || (factor == 0.1
f || scale > 1.0
f))
1108 scale = float(textureSize)/float(w*b*factor);
1110 colCount = float(textureSize)/(scale*float(w));
1111 rowCount = float(textureSize)/(scale*float(h));
1114 int outputTextures = (materials / (colCount*rowCount)) + (materials % (colCount*rowCount) > 0?1:0);
1115 UDEBUG(
"materials=%d col=%d row=%d output textures=%d factor=%f scale=%f", materials, colCount, rowCount, outputTextures, factor-epsilon, scale);
1117 UASSERT(mesh.tex_coordinates.size() == mesh.tex_materials.size() && mesh.tex_polygons.size() == mesh.tex_materials.size());
1120 std::vector<int> totalPolygons(outputTextures, 0);
1121 std::vector<int> totalCoordinates(outputTextures, 0);
1123 for(
unsigned int i=0; i<mesh.tex_materials.size(); ++i)
1125 if(mesh.tex_polygons[i].size())
1127 int indexMaterial = count / (colCount*rowCount);
1128 UASSERT(indexMaterial < outputTextures);
1130 totalPolygons[indexMaterial]+=mesh.tex_polygons[i].size();
1131 totalCoordinates[indexMaterial]+=mesh.tex_coordinates[i].size();
1137 pcl::TextureMesh outputMesh;
1142 float scaledHeight = float(
int(scale*
float(h)))/float(textureSize);
1143 float scaledWidth = float(
int(scale*
float(w)))/float(textureSize);
1144 float lowerBorderSize = 1.0f - scaledHeight*float(rowCount);
1145 UDEBUG(
"scaledWidth=%f scaledHeight=%f lowerBorderSize=%f", scaledWidth, scaledHeight, lowerBorderSize);
1148 materialsKept->resize(mesh.tex_materials.size(),
false);
1150 for(
unsigned int t=0; t<mesh.tex_materials.size(); ++t)
1152 if(mesh.tex_polygons[t].size())
1154 int indexMaterial = ti / (colCount*rowCount);
1155 UASSERT(indexMaterial < outputTextures);
1156 if((
int)outputMesh.tex_polygons.size() <= indexMaterial)
1158 std::vector<pcl::Vertices> newPolygons(totalPolygons[indexMaterial]);
1159 #if PCL_VERSION_COMPARE(>=, 1, 8, 0) 1160 std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > newCoordinates(totalCoordinates[indexMaterial]);
1162 std::vector<Eigen::Vector2f> newCoordinates(totalCoordinates[indexMaterial]);
1164 outputMesh.tex_polygons.push_back(newPolygons);
1165 outputMesh.tex_coordinates.push_back(newCoordinates);
1171 int row = (ti/colCount) % rowCount;
1172 int col = ti%colCount;
1173 float offsetU = scaledWidth * float(col);
1174 float offsetV = scaledHeight * float((rowCount - 1) - row) + lowerBorderSize;
1177 for(
unsigned int i=0; i<mesh.tex_polygons[t].size(); ++i)
1179 UASSERT(pi < (
int)outputMesh.tex_polygons[indexMaterial].size());
1180 outputMesh.tex_polygons[indexMaterial][pi++] = mesh.tex_polygons[t].at(i);
1183 for(
unsigned int i=0; i<mesh.tex_coordinates[t].size(); ++i)
1185 const Eigen::Vector2f & v = mesh.tex_coordinates[t].at(i);
1186 if(v[0] >= 0 && v[1] >=0)
1188 outputMesh.tex_coordinates[indexMaterial][ci][0] = v[0]*scaledWidth + offsetU;
1189 outputMesh.tex_coordinates[indexMaterial][ci][1] = v[1]*scaledHeight + offsetV;
1193 outputMesh.tex_coordinates[indexMaterial][ci] = v;
1200 materialsKept->at(t) =
true;
1204 pcl::TexMaterial m = mesh.tex_materials.front();
1205 mesh.tex_materials.clear();
1206 for(
int i=0; i<outputTextures; ++i)
1208 m.tex_file =
"texture";
1209 m.tex_name =
"material";
1210 if(outputTextures > 1)
1216 mesh.tex_materials.push_back(m);
1218 mesh.tex_coordinates = outputMesh.tex_coordinates;
1219 mesh.tex_polygons = outputMesh.tex_polygons;
1225 std::vector<std::vector<RTABMAP_PCL_INDEX> > polygonsOut(polygons.size());
1226 for(
unsigned int p=0; p<polygons.size(); ++p)
1228 polygonsOut[p] = polygons[p].vertices;
1232 std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > >
convertPolygonsFromPCL(
const std::vector<std::vector<pcl::Vertices> > & tex_polygons)
1234 std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > polygonsOut(tex_polygons.size());
1235 for(
unsigned int t=0; t<tex_polygons.size(); ++t)
1237 polygonsOut[t].resize(tex_polygons[t].size());
1238 for(
unsigned int p=0; p<tex_polygons[t].size(); ++p)
1240 polygonsOut[t][p] = tex_polygons[t][p].vertices;
1247 std::vector<pcl::Vertices> polygonsOut(polygons.size());
1248 for(
unsigned int p=0; p<polygons.size(); ++p)
1250 polygonsOut[p].vertices = polygons[p];
1254 std::vector<std::vector<pcl::Vertices> >
convertPolygonsToPCL(
const std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > & tex_polygons)
1256 std::vector<std::vector<pcl::Vertices> > polygonsOut(tex_polygons.size());
1257 for(
unsigned int t=0; t<tex_polygons.size(); ++t)
1259 polygonsOut[t].resize(tex_polygons[t].size());
1260 for(
unsigned int p=0; p<tex_polygons[t].size(); ++p)
1262 polygonsOut[t][p].vertices = tex_polygons[t][p];
1269 const cv::Mat & cloudMat,
1270 const std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > & polygons,
1271 #
if PCL_VERSION_COMPARE(>=, 1, 8, 0)
1272 const std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > & texCoords,
1274 const std::vector<std::vector<Eigen::Vector2f> > & texCoords,
1279 pcl::TextureMesh::Ptr textureMesh(
new pcl::TextureMesh);
1281 if(cloudMat.channels() <= 3)
1284 pcl::toPCLPointCloud2(*cloud, textureMesh->cloud);
1286 else if(cloudMat.channels() == 4)
1289 pcl::toPCLPointCloud2(*cloud, textureMesh->cloud);
1291 else if(cloudMat.channels() == 6)
1294 pcl::toPCLPointCloud2(*cloud, textureMesh->cloud);
1296 else if(cloudMat.channels() == 7)
1299 pcl::toPCLPointCloud2(*cloud, textureMesh->cloud);
1302 if(textureMesh->cloud.data.size() && polygons.size())
1304 textureMesh->tex_polygons.resize(polygons.size());
1305 for(
unsigned int t=0; t<polygons.size(); ++t)
1307 textureMesh->tex_polygons[t].resize(polygons[t].size());
1308 for(
unsigned int p=0; p<polygons[t].size(); ++p)
1310 textureMesh->tex_polygons[t][p].vertices = polygons[t][p];
1314 if(!texCoords.empty() && !textures.empty())
1316 textureMesh->tex_coordinates = texCoords;
1318 textureMesh->tex_materials.resize (textureMesh->tex_coordinates.size());
1319 for(
unsigned int i = 0 ; i < textureMesh->tex_coordinates.size() ; ++i)
1321 pcl::TexMaterial mesh_material;
1322 mesh_material.tex_Ka.r = 0.2f;
1323 mesh_material.tex_Ka.g = 0.2f;
1324 mesh_material.tex_Ka.b = 0.2f;
1326 mesh_material.tex_Kd.r = 0.8f;
1327 mesh_material.tex_Kd.g = 0.8f;
1328 mesh_material.tex_Kd.b = 0.8f;
1330 mesh_material.tex_Ks.r = 1.0f;
1331 mesh_material.tex_Ks.g = 1.0f;
1332 mesh_material.tex_Ks.b = 1.0f;
1334 mesh_material.tex_d = 1.0f;
1335 mesh_material.tex_Ns = 75.0f;
1336 mesh_material.tex_illum = 2;
1338 std::stringstream tex_name;
1339 tex_name <<
"material_" << i;
1340 tex_name >> mesh_material.tex_name;
1342 mesh_material.tex_file =
uFormat(
"%d", i);
1344 textureMesh->tex_materials[i] = mesh_material;
1347 if(mergeTextures && textures.cols/textures.rows > 1)
1349 UASSERT(textures.cols % textures.rows == 0 && textures.cols/textures.rows == (
int)textureMesh->tex_coordinates.size());
1350 std::vector<bool> materialsKept;
1352 cv::Size imageSize(textures.rows, textures.rows);
1353 int imageType = textures.type();
1355 if(scale && textureMesh->tex_materials.size() == 1)
1357 int cols = float(textures.rows)/(scale*imageSize.width);
1358 int rows = float(textures.rows)/(scale*imageSize.height);
1360 cv::Mat mergedTextures = cv::Mat(textures.rows, textures.rows, imageType,
cv::Scalar::all(255));
1363 cv::Size resizedImageSize(
int(imageSize.width*scale),
int(imageSize.height*scale));
1365 for(
int i=0; i<(int)materialsKept.size(); ++i)
1367 if(materialsKept.at(i))
1369 int u = oi%cols * resizedImageSize.width;
1370 int v = ((oi/cols) % rows ) * resizedImageSize.height;
1371 UASSERT(u < textures.rows-resizedImageSize.width);
1372 UASSERT(v < textures.rows-resizedImageSize.height);
1374 cv::Mat resizedImage;
1375 cv::resize(textures(
cv::Range::all(), cv::Range(i*textures.rows, (i+1)*textures.rows)), resizedImage, resizedImageSize, 0.0f, 0.0f, cv::INTER_AREA);
1377 UASSERT(resizedImage.type() == mergedTextures.type());
1378 resizedImage.copyTo(mergedTextures(cv::Rect(u, v, resizedImage.cols, resizedImage.rows)));
1383 textures = mergedTextures;
1392 const cv::Mat & cloudMat,
1393 const std::vector<std::vector<RTABMAP_PCL_INDEX> > & polygons)
1395 pcl::PolygonMesh::Ptr polygonMesh(
new pcl::PolygonMesh);
1397 if(cloudMat.channels() <= 3)
1400 pcl::toPCLPointCloud2(*cloud, polygonMesh->cloud);
1402 else if(cloudMat.channels() == 4)
1405 pcl::toPCLPointCloud2(*cloud, polygonMesh->cloud);
1407 else if(cloudMat.channels() == 6)
1410 pcl::toPCLPointCloud2(*cloud, polygonMesh->cloud);
1412 else if(cloudMat.channels() == 7)
1415 pcl::toPCLPointCloud2(*cloud, polygonMesh->cloud);
1418 if(polygonMesh->cloud.data.size() && polygons.size())
1420 polygonMesh->polygons.resize(polygons.size());
1421 for(
unsigned int p=0; p<polygons.size(); ++p)
1423 polygonMesh->polygons[p].vertices = polygons[p];
1431 return double(v)*double(v);
1435 pcl::TextureMesh & mesh,
1436 const std::map<int, cv::Mat> & images,
1437 const std::map<int, CameraModel> & calibrations,
1442 const std::vector<std::map<int, pcl::PointXY> > & vertexToPixels,
1443 bool gainCompensation,
1447 int blendingDecimation,
1448 int brightnessContrastRatioLow,
1449 int brightnessContrastRatioHigh,
1452 unsigned char blankValue,
1453 std::map<
int, std::map<int, cv::Vec4d> > * gains,
1454 std::map<
int, std::map<int, cv::Mat> > * blendingGains,
1455 std::pair<float, float> * contrastValues)
1457 std::map<int, std::vector<CameraModel> > calibVectors;
1458 for(std::map<int, CameraModel>::const_iterator iter=calibrations.begin(); iter!=calibrations.end(); ++iter)
1460 std::vector<CameraModel> m;
1461 m.push_back(iter->second);
1462 calibVectors.insert(std::make_pair(iter->first, m));
1477 brightnessContrastRatioLow,
1478 brightnessContrastRatioHigh,
1487 pcl::TextureMesh & mesh,
1488 const std::map<int, cv::Mat> & images,
1489 const std::map<
int, std::vector<CameraModel> > & calibrations,
1494 const std::vector<std::map<int, pcl::PointXY> > & vertexToPixels,
1495 bool gainCompensation,
1499 int blendingDecimation,
1500 int brightnessContrastRatioLow,
1501 int brightnessContrastRatioHigh,
1504 unsigned char blankValue,
1505 std::map<
int, std::map<int, cv::Vec4d> > * gainsOut,
1506 std::map<
int, std::map<int, cv::Mat> > * blendingGainsOut,
1507 std::pair<float, float> * contrastValuesOut)
1510 UASSERT(textureSize%256 == 0);
1511 UDEBUG(
"textureSize = %d", textureSize);
1512 cv::Mat globalTextures;
1513 if(mesh.tex_materials.size() > 1)
1515 std::vector<std::pair<int, int> > textures(mesh.tex_materials.size(), std::pair<int, int>(-1,0));
1517 const int imageType=CV_8UC3;
1520 for(
unsigned int i=0; i<mesh.tex_materials.size(); ++i)
1522 std::list<std::string> texFileSplit =
uSplit(mesh.tex_materials[i].tex_file,
'_');
1523 if(!mesh.tex_materials[i].tex_file.empty() &&
1524 mesh.tex_polygons[i].size() &&
1527 textures[i].first =
uStr2Int(texFileSplit.front());
1528 if(texFileSplit.size() == 2 &&
1531 textures[i].second =
uStr2Int(texFileSplit.back());
1534 int textureId = textures[i].first;
1535 if(imageSize.width == 0 || imageSize.height == 0)
1537 if(images.find(textureId) != images.end() &&
1538 !images.find(textureId)->second.empty() &&
1539 calibrations.find(textureId) != calibrations.end())
1541 const std::vector<CameraModel> & models = calibrations.find(textureId)->second;
1543 if( models[0].imageHeight()>0 &&
1544 models[0].imageWidth()>0)
1546 imageSize = models[0].imageSize();
1548 else if(images.find(textureId)!=images.end())
1551 cv::Mat image = images.find(textureId)->second;
1552 if(image.rows == 1 && image.type() == CV_8UC1)
1557 imageSize = image.size();
1560 imageSize.width/=models.size();
1569 if(models.size()>=1 &&
1570 models[0].imageHeight()>0 &&
1571 models[0].imageWidth()>0)
1573 imageSize = models[0].imageSize();
1585 imageSize = image.size();
1594 std::vector<CameraModel> models;
1597 if(models.size()>=1 &&
1598 models[0].imageHeight()>0 &&
1599 models[0].imageWidth()>0)
1601 imageSize = models[0].imageSize();
1611 dbDriver->
getNodeData(textureId, data,
true,
false,
false,
false);
1615 imageSize = image.size();
1624 else if(mesh.tex_polygons[i].size() && mesh.tex_materials[i].tex_file.compare(
"occluded")!=0)
1626 UWARN(
"Failed parsing texture file name: %s", mesh.tex_materials[i].tex_file.c_str());
1629 UDEBUG(
"textures=%d imageSize=%dx%d", (
int)textures.size(), imageSize.height, imageSize.width);
1630 if(textures.size() && imageSize.height>0 && imageSize.width>0)
1634 std::vector<bool> materialsKept;
1636 if(scale && mesh.tex_materials.size())
1638 int materials = (int)mesh.tex_materials.size();
1639 int cols = float(textureSize)/(scale*imageSize.width);
1640 int rows = float(textureSize)/(scale*imageSize.height);
1642 globalTextures = cv::Mat(textureSize, materials*textureSize, imageType,
cv::Scalar::all(blankValue));
1643 cv::Mat globalTextureMasks = cv::Mat(textureSize, materials*textureSize, CV_8UC1,
cv::Scalar::all(0));
1646 cv::Mat previousImage;
1647 int previousTextureId = 0;
1648 std::vector<CameraModel> previousCameraModels;
1651 cv::Mat emptyImage(
int(imageSize.height*scale),
int(imageSize.width*scale), imageType,
cv::Scalar::all(blankValue));
1652 cv::Mat emptyImageMask(
int(imageSize.height*scale),
int(imageSize.width*scale), CV_8UC1,
cv::Scalar::all(255));
1654 std::vector<cv::Point2i> imageOrigin(textures.size());
1655 std::vector<int> newCamIndex(textures.size(), -1);
1656 for(
int t=0; t<(int)textures.size(); ++t)
1658 if(materialsKept.at(t))
1660 int indexMaterial = oi / (cols*rows);
1661 UASSERT(indexMaterial < materials);
1663 newCamIndex[t] = oi;
1664 int u = oi%cols * emptyImage.cols;
1665 int v = ((oi/cols) % rows ) * emptyImage.rows;
1666 UASSERT_MSG(u < textureSize-emptyImage.cols,
uFormat(
"u=%d textureSize=%d emptyImage.cols=%d", u, textureSize, emptyImage.cols).c_str());
1667 UASSERT_MSG(v < textureSize-emptyImage.rows,
uFormat(
"v=%d textureSize=%d emptyImage.rows=%d", v, textureSize, emptyImage.rows).c_str());
1668 imageOrigin[t].x = u;
1669 imageOrigin[t].y = v;
1670 if(textures[t].first>=0)
1673 std::vector<CameraModel> models;
1675 if(textures[t].first == previousTextureId)
1677 image = previousImage;
1678 models = previousCameraModels;
1682 if(images.find(textures[t].first) != images.end() &&
1683 !images.find(textures[t].first)->second.empty() &&
1684 calibrations.find(textures[t].first) != calibrations.end())
1686 image = images.find(textures[t].first)->second;
1687 if(image.rows == 1 && image.type() == CV_8UC1)
1691 models = calibrations.find(textures[t].first)->second;
1702 dbDriver->
getNodeData(textures[t].first, data,
true,
false,
false,
false);
1705 dbDriver->
getCalibration(textures[t].first, models, stereoModel);
1708 previousImage = image;
1709 previousCameraModels = models;
1710 previousTextureId = textures[t].first;
1715 if(textures[t].second>=0)
1717 UASSERT(textures[t].second < (
int)models.size());
1718 int width = image.cols/models.size();
1719 image = image.colRange(width*textures[t].second, width*(textures[t].second+1));
1722 cv::Mat resizedImage;
1723 cv::resize(image, resizedImage, emptyImage.size(), 0.0f, 0.0f, cv::INTER_AREA);
1724 UASSERT(resizedImage.type() == CV_8UC1 || resizedImage.type() == CV_8UC3);
1725 if(resizedImage.type() == CV_8UC1)
1727 cv::Mat resizedImageColor;
1728 cv::cvtColor(resizedImage, resizedImageColor, CV_GRAY2BGR);
1729 resizedImage = resizedImageColor;
1731 UASSERT(resizedImage.type() == globalTextures.type());
1732 resizedImage.copyTo(globalTextures(cv::Rect(u+indexMaterial*globalTextures.rows, v, resizedImage.cols, resizedImage.rows)));
1733 emptyImageMask.copyTo(globalTextureMasks(cv::Rect(u+indexMaterial*globalTextureMasks.rows, v, resizedImage.cols, resizedImage.rows)));
1737 emptyImage.copyTo(globalTextures(cv::Rect(u+indexMaterial*globalTextures.rows, v, emptyImage.cols, emptyImage.rows)));
1748 state->
callback(
uFormat(
"Assembled texture %d/%d.", t+1, (
int)textures.size()));
1753 if(vertexToPixels.size())
1758 if(gainCompensation)
1764 const int num_images =
static_cast<int>(oi);
1765 cv::Mat_<int> N(num_images, num_images); N.setTo(0);
1766 cv::Mat_<double> I(num_images, num_images); I.setTo(0);
1768 cv::Mat_<double> IR(num_images, num_images); IR.setTo(0);
1769 cv::Mat_<double> IG(num_images, num_images); IG.setTo(0);
1770 cv::Mat_<double> IB(num_images, num_images); IB.setTo(0);
1773 for(
unsigned int p=0; p<vertexToPixels.size(); ++p)
1775 for(std::map<int, pcl::PointXY>::const_iterator iter=vertexToPixels[p].begin(); iter!=vertexToPixels[p].end(); ++iter)
1777 if(materialsKept.at(iter->first))
1779 N(newCamIndex[iter->first], newCamIndex[iter->first]) +=1;
1781 std::map<int, pcl::PointXY>::const_iterator jter=iter;
1784 for(; jter!=vertexToPixels[p].end(); ++jter, ++k)
1786 if(materialsKept.at(jter->first))
1788 int i = newCamIndex[iter->first];
1789 int j = newCamIndex[jter->first];
1794 int indexMaterial = i / (cols*rows);
1797 int ui = iter->second.x*emptyImage.cols + imageOrigin[iter->first].x;
1798 int vi = (1.0-iter->second.y)*emptyImage.rows + imageOrigin[iter->first].y;
1799 int uj = jter->second.x*emptyImage.cols + imageOrigin[jter->first].x;
1800 int vj = (1.0-jter->second.y)*emptyImage.rows + imageOrigin[jter->first].y;
1801 cv::Vec3b * pt1 = globalTextures.ptr<cv::Vec3b>(vi,ui+indexMaterial*globalTextures.rows);
1802 cv::Vec3b * pt2 = globalTextures.ptr<cv::Vec3b>(vj,uj+indexMaterial*globalTextures.rows);
1804 I(i, j) +=
std::sqrt(static_cast<double>(
sqr(pt1->val[0]) +
sqr(pt1->val[1]) +
sqr(pt1->val[2])));
1805 I(j, i) +=
std::sqrt(static_cast<double>(
sqr(pt2->val[0]) +
sqr(pt2->val[1]) +
sqr(pt2->val[2])));
1807 IR(i, j) +=
static_cast<double>(pt1->val[2]);
1808 IR(j, i) +=
static_cast<double>(pt2->val[2]);
1809 IG(i, j) +=
static_cast<double>(pt1->val[1]);
1810 IG(j, i) +=
static_cast<double>(pt2->val[1]);
1811 IB(i, j) +=
static_cast<double>(pt1->val[0]);
1812 IB(j, i) +=
static_cast<double>(pt2->val[0]);
1819 for(
int i=0; i<num_images; ++i)
1821 for(
int j=i; j<num_images; ++j)
1835 IR(i, j) /= N(i, j);
1836 IR(j, i) /= N(j, i);
1837 IG(i, j) /= N(i, j);
1838 IG(j, i) /= N(j, i);
1839 IB(i, j) /= N(i, j);
1840 IB(j, i) /= N(j, i);
1845 cv::Mat_<double> A(num_images, num_images); A.setTo(0);
1846 cv::Mat_<double> b(num_images, 1); b.setTo(0);
1847 cv::Mat_<double> AR(num_images, num_images); AR.setTo(0);
1848 cv::Mat_<double> AG(num_images, num_images); AG.setTo(0);
1849 cv::Mat_<double> AB(num_images, num_images); AB.setTo(0);
1850 double alpha = 0.01;
1851 double beta = gainBeta;
1852 for (
int i = 0; i < num_images; ++i)
1854 for (
int j = 0; j < num_images; ++j)
1856 b(i, 0) += beta * N(i, j);
1857 A(i, i) += beta * N(i, j);
1858 AR(i, i) += beta * N(i, j);
1859 AG(i, i) += beta * N(i, j);
1860 AB(i, i) += beta * N(i, j);
1861 if (j == i)
continue;
1862 A(i, i) += 2 * alpha * I(i, j) * I(i, j) * N(i, j);
1863 A(i, j) -= 2 * alpha * I(i, j) * I(j, i) * N(i, j);
1865 AR(i, i) += 2 * alpha * IR(i, j) * IR(i, j) * N(i, j);
1866 AR(i, j) -= 2 * alpha * IR(i, j) * IR(j, i) * N(i, j);
1868 AG(i, i) += 2 * alpha * IG(i, j) * IG(i, j) * N(i, j);
1869 AG(i, j) -= 2 * alpha * IG(i, j) * IG(j, i) * N(i, j);
1871 AB(i, i) += 2 * alpha * IB(i, j) * IB(i, j) * N(i, j);
1872 AB(i, j) -= 2 * alpha * IB(i, j) * IB(j, i) * N(i, j);
1876 cv::Mat_<double> gainsGray, gainsR, gainsG, gainsB;
1877 cv::solve(A, b, gainsGray);
1879 cv::solve(AR, b, gainsR);
1880 cv::solve(AG, b, gainsG);
1881 cv::solve(AB, b, gainsB);
1883 cv::Mat_<double> gains(gainsGray.rows, 4);
1884 gainsGray.copyTo(gains.col(0));
1885 gainsR.copyTo(gains.col(1));
1886 gainsG.copyTo(gains.col(2));
1887 gainsB.copyTo(gains.col(3));
1889 for(
int t=0; t<(int)textures.size(); ++t)
1892 if(materialsKept.at(t))
1894 int u = imageOrigin[t].x;
1895 int v = imageOrigin[t].y;
1897 UDEBUG(
"Gain cam%d = %f", newCamIndex[t], gainsGray(newCamIndex[t], 0));
1899 int indexMaterial = newCamIndex[t] / (cols*rows);
1900 cv::Mat roi = globalTextures(cv::Rect(u+indexMaterial*globalTextures.rows, v, emptyImage.cols, emptyImage.rows));
1902 std::vector<cv::Mat> channels;
1903 cv::split(roi, channels);
1906 cv::multiply(channels[0], gains(newCamIndex[t], gainRGB?3:0), channels[0]);
1907 cv::multiply(channels[1], gains(newCamIndex[t], gainRGB?2:0), channels[1]);
1908 cv::multiply(channels[2], gains(newCamIndex[t], gainRGB?1:0), channels[2]);
1910 cv::merge(channels, roi);
1915 gains(newCamIndex[t], 0),
1916 gains(newCamIndex[t], 1),
1917 gains(newCamIndex[t], 2),
1918 gains(newCamIndex[t], 3));
1919 if(gainsOut->find(textures[t].first) == gainsOut->end())
1921 std::map<int,cv::Vec4d> value;
1922 value.insert(std::make_pair(textures[t].second, g));
1923 gainsOut->insert(std::make_pair(textures[t].first, value));
1927 gainsOut->at(textures[t].first).insert(std::make_pair(textures[t].second, g));
1941 if(blendingDecimation <= 0)
1944 std::vector<float> edgeLengths;
1945 if(mesh.tex_coordinates.size() && mesh.tex_coordinates[0].size())
1947 UASSERT(mesh.tex_polygons.size() && mesh.tex_polygons[0].size() && mesh.tex_polygons[0][0].vertices.size());
1948 int polygonSize = mesh.tex_polygons[0][0].vertices.size();
1949 UDEBUG(
"polygon size=%d", polygonSize);
1951 for(
unsigned int k=0; k<mesh.tex_coordinates.size(); ++k)
1953 for(
unsigned int i=0; i<mesh.tex_coordinates[k].size(); i+=polygonSize)
1955 for(
int j=0; j<polygonSize; ++j)
1957 const Eigen::Vector2f & uc1 = mesh.tex_coordinates[k][i + j];
1958 const Eigen::Vector2f & uc2 = mesh.tex_coordinates[k][i + (j+1)%polygonSize];
1959 Eigen::Vector2f edge = (uc1-uc2)*textureSize;
1960 edgeLengths.push_back(fabs(edge[0]));
1961 edgeLengths.push_back(fabs(edge[1]));
1965 float edgeLength = 0.0f;
1966 if(edgeLengths.size())
1968 std::sort(edgeLengths.begin(), edgeLengths.end());
1969 float m =
uMean(edgeLengths.data(), edgeLengths.size());
1971 edgeLength = m+stddev;
1972 decimation = 1 << 6;
1973 for(
int i=1; i<=6; ++i)
1975 if(
float(1 << i) >= edgeLength)
1977 decimation = 1 << i;
1983 UDEBUG(
"edge length=%f decimation=%d", edgeLength, decimation);
1988 if(blendingDecimation > 1)
1990 UASSERT(textureSize % blendingDecimation == 0);
1992 decimation = blendingDecimation;
1993 UDEBUG(
"decimation=%d", decimation);
1996 std::vector<cv::Mat> blendGains(materials);
1997 for(
int i=0; i<materials;++i)
1999 blendGains[i] = cv::Mat(globalTextures.rows/decimation, globalTextures.rows/decimation, CV_32FC3,
cv::Scalar::all(1.0f));
2002 for(
unsigned int p=0; p<vertexToPixels.size(); ++p)
2004 if(vertexToPixels[p].size() > 1)
2006 std::vector<float> gainsB(vertexToPixels[p].size());
2007 std::vector<float> gainsG(vertexToPixels[p].size());
2008 std::vector<float> gainsR(vertexToPixels[p].size());
2009 float sumWeight = 0.0f;
2011 for(std::map<int, pcl::PointXY>::const_iterator iter=vertexToPixels[p].begin(); iter!=vertexToPixels[p].end(); ++iter)
2013 if(materialsKept.at(iter->first))
2015 int u = iter->second.x*emptyImage.cols + imageOrigin[iter->first].x;
2016 int v = (1.0-iter->second.y)*emptyImage.rows + imageOrigin[iter->first].y;
2017 float x = iter->second.x - 0.5f;
2018 float y = iter->second.y - 0.5f;
2019 float weight = 0.7f -
sqrt(x*x+y*y);
2024 int indexMaterial = newCamIndex[iter->first] / (cols*rows);
2025 cv::Vec3b * pt = globalTextures.ptr<cv::Vec3b>(v,u+indexMaterial*globalTextures.rows);
2026 gainsB[k] =
static_cast<double>(pt->val[0]) * weight;
2027 gainsG[k] =
static_cast<double>(pt->val[1]) * weight;
2028 gainsR[k] =
static_cast<double>(pt->val[2]) * weight;
2029 sumWeight += weight;
2039 float targetColor[3];
2040 targetColor[0] =
uSum(gainsB.data(), gainsB.size()) / sumWeight;
2041 targetColor[1] =
uSum(gainsG.data(), gainsG.size()) / sumWeight;
2042 targetColor[2] =
uSum(gainsR.data(), gainsR.size()) / sumWeight;
2043 for(std::map<int, pcl::PointXY>::const_iterator iter=vertexToPixels[p].begin(); iter!=vertexToPixels[p].end(); ++iter)
2045 if(materialsKept.at(iter->first))
2047 int u = iter->second.x*emptyImage.cols + imageOrigin[iter->first].x;
2048 int v = (1.0-iter->second.y)*emptyImage.rows + imageOrigin[iter->first].y;
2049 int indexMaterial = newCamIndex[iter->first] / (cols*rows);
2050 cv::Vec3b * pt = globalTextures.ptr<cv::Vec3b>(v,u+indexMaterial*globalTextures.rows);
2051 float gB = targetColor[0]/(pt->val[0]==0?1.0f:pt->val[0]);
2052 float gG = targetColor[1]/(pt->val[1]==0?1.0f:pt->val[1]);
2053 float gR = targetColor[2]/(pt->val[2]==0?1.0f:pt->val[2]);
2054 cv::Vec3f * ptr = blendGains[indexMaterial].ptr<cv::Vec3f>(v/decimation, u/decimation);
2055 ptr->val[0] = (gB>1.3f)?1.3
f:(gB<0.7
f)?0.7f:gB;
2056 ptr->val[1] = (gG>1.3f)?1.3
f:(gG<0.7
f)?0.7f:gG;
2057 ptr->val[2] = (gR>1.3f)?1.3
f:(gR<0.7
f)?0.7f:gR;
2064 if(blendingGainsOut)
2066 for(
int t=0; t<(int)textures.size(); ++t)
2069 if(materialsKept.at(t))
2071 int u = imageOrigin[t].x/decimation;
2072 int v = imageOrigin[t].y/decimation;
2074 int indexMaterial = newCamIndex[t] / (cols*rows);
2075 cv::Mat roi = blendGains[indexMaterial](cv::Rect(u, v, emptyImage.cols/decimation, emptyImage.rows/decimation));
2076 if(blendingGainsOut->find(textures[t].first) == blendingGainsOut->end())
2078 std::map<int,cv::Mat> value;
2079 value.insert(std::make_pair(textures[t].second, roi.clone()));
2080 blendingGainsOut->insert(std::make_pair(textures[t].first, value));
2084 blendingGainsOut->at(textures[t].first).insert(std::make_pair(textures[t].second, roi.clone()));
2090 for(
int i=0; i<materials; ++i)
2102 cv::Mat globalTexturesROI = globalTextures(
cv::Range::all(), cv::Range(i*globalTextures.rows, (i+1)*globalTextures.rows));
2104 cv::blur(blendGains[i], dst, cv::Size(3,3));
2105 cv::resize(dst, blendGains[i], globalTexturesROI.size(), 0, 0, cv::INTER_LINEAR);
2115 cv::multiply(globalTexturesROI, blendGains[i], globalTexturesROI, 1.0, CV_8UC3);
2125 if(brightnessContrastRatioLow > 0 || brightnessContrastRatioHigh > 0)
2129 std::vector<cv::Mat> images;
2130 images.push_back(globalTextures);
2131 if (brightnessContrastRatioLow > 0)
2136 (
float)brightnessContrastRatioLow,
2139 if (brightnessContrastRatioHigh > 0)
2145 (
float)brightnessContrastRatioHigh));
2156 (
float)brightnessContrastRatioLow,
2157 (
float)brightnessContrastRatioHigh,
2160 if(contrastValuesOut)
2162 contrastValuesOut->first = alpha;
2163 contrastValuesOut->second = beta;
2171 UDEBUG(
"globalTextures=%d", globalTextures.cols?globalTextures.cols / globalTextures.rows:0);
2172 return globalTextures;
2181 for (
unsigned int t = 0; t < textureMesh.tex_coordinates.size(); ++t)
2183 if(textureMesh.tex_polygons[t].size())
2185 pcl::PointCloud<pcl::PointXYZ>::Ptr originalCloud(
new pcl::PointCloud<pcl::PointXYZ>);
2186 pcl::fromPCLPointCloud2(textureMesh.cloud, *originalCloud);
2189 unsigned int nPoints = textureMesh.tex_coordinates[t].size();
2190 UASSERT(nPoints == textureMesh.tex_polygons[t].size()*textureMesh.tex_polygons[t][0].vertices.size());
2192 pcl::PointCloud<pcl::PointXYZ>::Ptr newCloud(
new pcl::PointCloud<pcl::PointXYZ>);
2193 newCloud->resize(nPoints);
2195 unsigned int oi = 0;
2196 for (
unsigned int i = 0; i < textureMesh.tex_polygons[t].size(); ++i)
2198 pcl::Vertices &
vertices = textureMesh.tex_polygons[t][i];
2200 for(
unsigned int j=0; j<vertices.vertices.size(); ++j)
2202 UASSERT(oi < newCloud->size());
2203 UASSERT_MSG((
size_t)vertices.vertices[j] < originalCloud->size(),
uFormat(
"%d vs %d", vertices.vertices[j], (
int)originalCloud->size()).c_str());
2204 newCloud->at(oi) = originalCloud->at(vertices.vertices[j]);
2205 vertices.vertices[j] = oi;
2209 pcl::toPCLPointCloud2(*newCloud, textureMesh.cloud);
2215 const std::string & outputOBJPath,
2216 const pcl::PCLPointCloud2 & cloud,
2217 const std::vector<pcl::Vertices> & polygons,
2218 const std::map<int, Transform> & cameraPoses,
2219 const std::vector<std::map<int, pcl::PointXY> > & vertexToPixels,
2220 const std::map<int, cv::Mat> & images,
2221 const std::map<
int, std::vector<CameraModel> > & cameraModels,
2225 const std::string & textureFormat,
2226 const std::map<
int, std::map<int, cv::Vec4d> > & gains,
2227 const std::map<
int, std::map<int, cv::Mat> > & blendingGains,
2228 const std::pair<float, float> & contrastValues,
2231 #ifdef RTABMAP_ALICE_VISION 2234 system::Logger::get()->setLogLevel(system::EVerboseLevel::Trace);
2238 system::Logger::get()->setLogLevel(system::EVerboseLevel::Info);
2242 system::Logger::get()->setLogLevel(system::EVerboseLevel::Warning);
2246 system::Logger::get()->setLogLevel(system::EVerboseLevel::Error);
2249 sfmData::SfMData sfmData;
2250 pcl::PointCloud<pcl::PointXYZRGB> cloud2;
2251 pcl::fromPCLPointCloud2(cloud, cloud2);
2252 UASSERT(vertexToPixels.size() == cloud2.size());
2253 UINFO(
"Input mesh: %d points %d polygons", (
int)cloud2.size(), (int)polygons.size());
2254 mesh::Texturing texturing;
2255 #if RTABMAP_ALICE_VISION_MAJOR > 2 || (RTABMAP_ALICE_VISION_MAJOR==2 && RTABMAP_ALICE_VISION_MINOR>=3) 2256 texturing.mesh =
new mesh::Mesh();
2257 texturing.mesh->pts.resize(cloud2.size());
2258 texturing.mesh->pointsVisibilities.resize(cloud2.size());
2260 texturing.me =
new mesh::Mesh();
2261 texturing.me->pts =
new StaticVector<Point3d>(cloud2.size());
2262 texturing.pointsVisibilities =
new mesh::PointsVisibility();
2263 texturing.pointsVisibilities->reserve(cloud2.size());
2265 texturing.texParams.textureSide = 8192;
2266 texturing.texParams.downscale = 8192/textureSize;
2268 for(
size_t i=0;i<cloud2.size();++i)
2270 pcl::PointXYZRGB pt = cloud2.at(i);
2271 #if RTABMAP_ALICE_VISION_MAJOR > 2 || (RTABMAP_ALICE_VISION_MAJOR==2 && RTABMAP_ALICE_VISION_MINOR>=3) 2272 texturing.mesh->pointsVisibilities[i].reserve(vertexToPixels[i].size());
2273 for(std::map<int, pcl::PointXY>::const_iterator iter=vertexToPixels[i].begin(); iter!=vertexToPixels[i].end();++iter)
2275 texturing.mesh->pointsVisibilities[i].push_back(iter->first);
2277 texturing.mesh->pts[i] = Point3d(pt.x, pt.y, pt.z);
2279 mesh::PointVisibility* pointVisibility =
new mesh::PointVisibility();
2280 pointVisibility->reserve(vertexToPixels[i].size());
2281 for(std::map<int, pcl::PointXY>::const_iterator iter=vertexToPixels[i].begin(); iter!=vertexToPixels[i].end();++iter)
2283 pointVisibility->push_back(iter->first);
2285 texturing.pointsVisibilities->push_back(pointVisibility);
2286 (*texturing.me->pts)[i] = Point3d(pt.x, pt.y, pt.z);
2290 #if RTABMAP_ALICE_VISION_MAJOR > 2 || (RTABMAP_ALICE_VISION_MAJOR==2 && RTABMAP_ALICE_VISION_MINOR>=3) 2291 texturing.mesh->tris.resize(polygons.size());
2292 texturing.mesh->trisMtlIds().resize(polygons.size());
2294 texturing.me->tris =
new StaticVector<mesh::Mesh::triangle>(polygons.size());
2296 for(
size_t i=0;i<polygons.size();++i)
2299 #if RTABMAP_ALICE_VISION_MAJOR > 2 || (RTABMAP_ALICE_VISION_MAJOR==2 && RTABMAP_ALICE_VISION_MINOR>=3) 2300 texturing.mesh->trisMtlIds()[i] = -1;
2301 texturing.mesh->tris[i] = mesh::Mesh::triangle(
2303 (*texturing.me->tris)[i] = mesh::Mesh::triangle(
2305 polygons[i].vertices[0],
2306 polygons[i].vertices[1],
2307 polygons[i].vertices[2]);
2311 std::string tmpImageDirectory = outputDirectory+
"/rtabmap_tmp_textures";
2314 UINFO(
"Temporary saving images in directory \"%s\"...", tmpImageDirectory.c_str());
2316 for(std::map<int, Transform>::const_iterator iter = cameraPoses.lower_bound(1); iter!=cameraPoses.end(); ++iter)
2318 int camId = iter->first;
2320 std::vector<CameraModel> models;
2322 if( images.find(camId) != images.end() &&
2323 !images.find(camId)->second.empty() &&
2324 cameraModels.find(camId) != cameraModels.end())
2326 image = images.find(camId)->second;
2327 models = cameraModels.find(camId)->second;
2352 models.push_back(stereoModel.
left());
2356 dbDriver->
getNodeData(camId, data,
true,
false,
false,
false);
2368 UERROR(
"No camera models found for camera %d. Aborting multiband texturing...", iter->first);
2373 UERROR(
"No image found for camera %d. Aborting multiband texturing...", iter->first);
2377 if(image.rows == 1 && image.type() == CV_8UC1)
2383 image = image.clone();
2386 for(
size_t i=0; i<models.size(); ++i)
2390 if(imageSize.height == 0)
2393 imageSize.height = image.rows;
2394 imageSize.width = image.cols;
2396 UASSERT(image.cols % imageSize.width == 0);
2397 cv::Mat imageRoi = image.colRange(i*imageSize.width, (i+1)*imageSize.width);
2398 if(gains.find(camId) != gains.end() &&
2399 gains.at(camId).find(i) != gains.at(camId).end())
2401 const cv::Vec4d & g = gains.at(camId).at(i);
2402 std::vector<cv::Mat> channels;
2403 cv::split(imageRoi, channels);
2406 cv::multiply(channels[0], g.val[gainRGB?3:0], channels[0]);
2407 cv::multiply(channels[1], g.val[gainRGB?2:0], channels[1]);
2408 cv::multiply(channels[2], g.val[gainRGB?1:0], channels[2]);
2411 cv::merge(channels, output);
2415 if(blendingGains.find(camId) != blendingGains.end() &&
2416 blendingGains.at(camId).find(i) != blendingGains.at(camId).end())
2418 cv::Mat g = blendingGains.at(camId).at(i);
2420 cv::blur(g, dst, cv::Size(3,3));
2422 cv::resize(dst, gResized, imageRoi.size(), 0, 0, cv::INTER_LINEAR);
2424 cv::multiply(imageRoi, gResized, output, 1.0, CV_8UC3);
2429 Eigen::Matrix<double, 3, 4> m = (t.
inverse()).toEigen3d().matrix().block<3,4>(0, 0);
2430 sfmData::CameraPose pose(geometry::Pose3(m),
true);
2431 sfmData.setAbsolutePose((IndexT)viewId, pose);
2433 std::shared_ptr<camera::IntrinsicBase> camPtr = std::make_shared<camera::Pinhole>(
2434 imageSize.width, imageSize.height, model.
fx(), model.
cx(), model.
cy());
2435 sfmData.intrinsics.insert(std::make_pair((IndexT)viewId, camPtr));
2437 std::string imagePath = tmpImageDirectory+
uFormat(
"/%d.jpg", viewId);
2439 cv::imwrite(imagePath, imageRoi);
2441 std::shared_ptr<sfmData::View> viewPtr = std::make_shared<sfmData::View>(
2448 sfmData.views.insert(std::make_pair((IndexT)viewId, viewPtr));
2452 UINFO(
"Temporary saving images in directory \"%s\"... done (%d images). %fs", tmpImageDirectory.c_str(), viewId, (int)cameraPoses.size(), timer.
ticks());
2454 mvsUtils::MultiViewParams mp(sfmData);
2456 UINFO(
"Unwrapping...");
2457 texturing.unwrap(mp, mesh::EUnwrapMethod::Basic);
2458 UINFO(
"Unwrapping done. %fs", timer.
ticks());
2462 texturing.saveAsOBJ(outputDirectory, baseName);
2463 UINFO(
"Saved %s. %fs", outputOBJPath, timer.
ticks());
2466 UINFO(
"Generating textures...");
2467 texturing.generateTextures(mp, outputDirectory);
2468 UINFO(
"Generating textures done. %fs", timer.
ticks());
2470 UINFO(
"Cleanup temporary directory \"%s\"...", tmpImageDirectory.c_str());
2472 std::string fp = dir.getNextFilePath();
2476 fp = dir.getNextFilePath();
2479 UINFO(
"Cleanup temporary directory \"%s\"... done.", tmpImageDirectory.c_str());
2481 UINFO(
"Rename/convert textures...");
2482 dir.setPath(outputDirectory,
"png");
2483 std::map<std::string, std::string> texNames;
2484 std::string outputFormat = textureFormat;
2485 if(outputFormat.front() ==
'.')
2487 outputFormat = outputFormat.substr(1, std::string::npos);
2489 for(std::list<std::string>::const_iterator iter=dir.getFileNames().begin(); iter!=dir.getFileNames().end(); ++iter)
2494 cv::Mat img = cv::imread(outputDirectory+
"/"+*iter);
2495 if(contrastValues.first != 0.0f || contrastValues.second != 0.0f)
2499 UINFO(
"Apply contrast values %f %f", contrastValues.first, contrastValues.second);
2500 img.convertTo(img, -1, contrastValues.first, contrastValues.second);
2502 std::string newName = *iter;
2503 boost::replace_all(newName,
"png", outputFormat);
2504 boost::replace_all(newName,
"texture", baseName);
2505 texNames.insert(std::make_pair(*iter, newName));
2506 cv::imwrite(outputDirectory+
"/"+newName, img);
2510 std::ifstream fi(outputDirectory+
"/"+baseName+
".mtl");
2511 std::string mtlStr((std::istreambuf_iterator<char>(fi)),
2512 std::istreambuf_iterator<char>());
2515 for(std::map<std::string, std::string>::iterator iter=texNames.begin(); iter!=texNames.end(); ++iter)
2517 boost::replace_all(mtlStr, iter->first, iter->second);
2519 std::ofstream fo(outputDirectory+
"/"+baseName+
".mtl");
2520 fo.write(mtlStr.c_str(), mtlStr.size());
2522 UINFO(
"Rename/convert textures... done. %fs", timer.
ticks());
2524 #if RTABMAP_ALICE_VISION_MAJOR > 2 || (RTABMAP_ALICE_VISION_MAJOR==2 && RTABMAP_ALICE_VISION_MINOR>=3) 2530 UERROR(
"Cannot unwrap texture mesh. RTAB-Map is not built with Alice Vision support! Returning false.");
2545 pcl::PointCloud<pcl::Normal>::Ptr normals;
2562 if(laserScan.
is2d())
2587 if(laserScan.
is2d())
2609 template<
typename Po
intT>
2611 const typename pcl::PointCloud<PointT>::Ptr & cloud,
2612 const pcl::IndicesPtr & indices,
2615 const Eigen::Vector3f & viewPoint)
2617 typename pcl::search::KdTree<PointT>::Ptr
tree (
new pcl::search::KdTree<PointT>);
2620 tree->setInputCloud(cloud, indices);
2624 tree->setInputCloud (cloud);
2629 pcl::NormalEstimationOMP<PointT, pcl::Normal> n;
2631 pcl::NormalEstimation<PointT, pcl::Normal> n;
2633 pcl::PointCloud<pcl::Normal>::Ptr normals (
new pcl::PointCloud<pcl::Normal>);
2634 n.setInputCloud (cloud);
2640 n.setSearchMethod (tree);
2641 n.setKSearch (searchK);
2642 n.setRadiusSearch (searchRadius);
2643 n.setViewPoint(viewPoint[0], viewPoint[1], viewPoint[2]);
2644 n.compute (*normals);
2649 const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
2652 const Eigen::Vector3f & viewPoint)
2654 pcl::IndicesPtr indices(
new std::vector<int>);
2655 return computeNormals(cloud, indices, searchK, searchRadius, viewPoint);
2658 const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
2661 const Eigen::Vector3f & viewPoint)
2663 pcl::IndicesPtr indices(
new std::vector<int>);
2664 return computeNormals(cloud, indices, searchK, searchRadius, viewPoint);
2667 const pcl::PointCloud<pcl::PointXYZI>::Ptr & cloud,
2670 const Eigen::Vector3f & viewPoint)
2672 pcl::IndicesPtr indices(
new std::vector<int>);
2673 return computeNormals(cloud, indices, searchK, searchRadius, viewPoint);
2676 const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
2677 const pcl::IndicesPtr & indices,
2680 const Eigen::Vector3f & viewPoint)
2682 return computeNormalsImpl<pcl::PointXYZ>(cloud, indices, searchK, searchRadius, viewPoint);
2685 const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
2686 const pcl::IndicesPtr & indices,
2689 const Eigen::Vector3f & viewPoint)
2691 return computeNormalsImpl<pcl::PointXYZRGB>(cloud, indices, searchK, searchRadius, viewPoint);
2694 const pcl::PointCloud<pcl::PointXYZI>::Ptr & cloud,
2695 const pcl::IndicesPtr & indices,
2698 const Eigen::Vector3f & viewPoint)
2700 return computeNormalsImpl<pcl::PointXYZI>(cloud, indices, searchK, searchRadius, viewPoint);
2703 template<
typename Po
intT>
2705 const typename pcl::PointCloud<PointT>::Ptr & cloud,
2708 const Eigen::Vector3f & viewPoint)
2710 UASSERT(searchK>0 || searchRadius>0.0
f);
2711 pcl::PointCloud<pcl::Normal>::Ptr normals (
new pcl::PointCloud<pcl::Normal>);
2713 typename pcl::search::KdTree<PointT>::Ptr
tree (
new pcl::search::KdTree<PointT>);
2714 tree->setInputCloud (cloud);
2716 normals->resize(cloud->size());
2718 float bad_point = std::numeric_limits<float>::quiet_NaN ();
2721 for(
unsigned int i=0; i<cloud->size(); ++i)
2723 const PointT & pt = cloud->at(i);
2724 std::vector<Eigen::Vector3f> neighborNormals;
2725 Eigen::Vector3f direction;
2726 direction[0] = viewPoint[0] - pt.x;
2727 direction[1] = viewPoint[1] - pt.y;
2728 direction[2] = viewPoint[2] - pt.z;
2730 std::vector<int> k_indices;
2731 std::vector<float> k_sqr_distances;
2732 if(searchRadius>0.0
f)
2734 tree->radiusSearch(cloud->at(i), searchRadius, k_indices, k_sqr_distances, searchK);
2738 tree->nearestKSearch(cloud->at(i), searchK, k_indices, k_sqr_distances);
2741 for(
unsigned int j=0; j<k_indices.size(); ++j)
2743 if(k_indices.at(j) != (int)i)
2745 const PointT & pt2 = cloud->at(k_indices.at(j));
2746 Eigen::Vector3f v(pt2.x-pt.x, pt2.y - pt.y, pt2.z - pt.z);
2747 Eigen::Vector3f up = v.cross(direction);
2748 Eigen::Vector3f n = up.cross(v);
2750 neighborNormals.push_back(n);
2754 if(neighborNormals.empty())
2756 normals->at(i).normal_x = bad_point;
2757 normals->at(i).normal_y = bad_point;
2758 normals->at(i).normal_z = bad_point;
2762 Eigen::Vector3f meanNormal(0,0,0);
2763 for(
unsigned int j=0; j<neighborNormals.size(); ++j)
2765 meanNormal+=neighborNormals[j];
2767 meanNormal /= (float)neighborNormals.size();
2768 meanNormal.normalize();
2769 normals->at(i).normal_x = meanNormal[0];
2770 normals->at(i).normal_y = meanNormal[1];
2771 normals->at(i).normal_z = meanNormal[2];
2778 const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
2781 const Eigen::Vector3f & viewPoint)
2783 return computeNormals2DImpl<pcl::PointXYZ>(cloud, searchK, searchRadius, viewPoint);
2786 const pcl::PointCloud<pcl::PointXYZI>::Ptr & cloud,
2789 const Eigen::Vector3f & viewPoint)
2791 return computeNormals2DImpl<pcl::PointXYZI>(cloud, searchK, searchRadius, viewPoint);
2794 template<
typename Po
intT>
2796 const typename pcl::PointCloud<PointT>::Ptr & cloud,
2799 const Eigen::Vector3f & viewPoint)
2802 pcl::PointCloud<pcl::Normal>::Ptr normals (
new pcl::PointCloud<pcl::Normal>);
2804 normals->resize(cloud->size());
2805 searchRadius *= searchRadius;
2807 float bad_point = std::numeric_limits<float>::quiet_NaN ();
2810 for(
int i=0; i<(int)cloud->size(); ++i)
2818 if(hi>=(
int)cloud->size())
2820 hi=(int)cloud->size()-1;
2824 const PointT & pt = cloud->at(i);
2825 std::vector<Eigen::Vector3f> neighborNormals;
2826 Eigen::Vector3f direction;
2827 direction[0] = viewPoint[0] - cloud->at(i).x;
2828 direction[1] = viewPoint[1] - cloud->at(i).y;
2829 direction[2] = viewPoint[2] - cloud->at(i).z;
2830 for(
int j=i-1; j>=li; --j)
2832 const PointT & pt2 = cloud->at(j);
2833 Eigen::Vector3f vd(pt2.x-pt.x, pt2.y - pt.y, pt2.z - pt.z);
2834 if(searchRadius<=0.0
f || (vd[0]*vd[0] + vd[1]*vd[1] + vd[2]*vd[2]) < searchRadius)
2836 Eigen::Vector3f v(pt2.x-pt.x, pt2.y - pt.y, pt2.z - pt.z);
2837 Eigen::Vector3f up = v.cross(direction);
2838 Eigen::Vector3f n = up.cross(v);
2840 neighborNormals.push_back(n);
2847 for(
int j=i+1; j<=hi; ++j)
2849 const PointT & pt2 = cloud->at(j);
2850 Eigen::Vector3f vd(pt2.x-pt.x, pt2.y - pt.y, pt2.z - pt.z);
2851 if(searchRadius<=0.0
f || (vd[0]*vd[0] + vd[1]*vd[1] + vd[2]*vd[2]) < searchRadius)
2853 Eigen::Vector3f v(pt2.x-pt.x, pt2.y - pt.y, pt2.z - pt.z);
2854 Eigen::Vector3f up = v[2]==0.0f?Eigen::Vector3f(0,0,1):v.cross(direction);
2855 Eigen::Vector3f n = up.cross(v);
2857 neighborNormals.push_back(n);
2865 if(neighborNormals.empty())
2867 normals->at(i).normal_x = bad_point;
2868 normals->at(i).normal_y = bad_point;
2869 normals->at(i).normal_z = bad_point;
2873 Eigen::Vector3f meanNormal(0,0,0);
2874 for(
unsigned int j=0; j<neighborNormals.size(); ++j)
2876 meanNormal+=neighborNormals[j];
2878 meanNormal /= (float)neighborNormals.size();
2879 meanNormal.normalize();
2880 normals->at(i).normal_x = meanNormal[0];
2881 normals->at(i).normal_y = meanNormal[1];
2882 normals->at(i).normal_z = meanNormal[2];
2890 const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
2893 const Eigen::Vector3f & viewPoint)
2895 return computeFastOrganizedNormals2DImpl<pcl::PointXYZ>(cloud, searchK, searchRadius, viewPoint);
2898 const pcl::PointCloud<pcl::PointXYZI>::Ptr & cloud,
2901 const Eigen::Vector3f & viewPoint)
2903 return computeFastOrganizedNormals2DImpl<pcl::PointXYZI>(cloud, searchK, searchRadius, viewPoint);
2907 const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
2908 float maxDepthChangeFactor,
2909 float normalSmoothingSize,
2910 const Eigen::Vector3f & viewPoint)
2912 pcl::IndicesPtr indices(
new std::vector<int>);
2916 const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
2917 const pcl::IndicesPtr & indices,
2918 float maxDepthChangeFactor,
2919 float normalSmoothingSize,
2920 const Eigen::Vector3f & viewPoint)
2922 UASSERT(cloud->isOrganized());
2924 pcl::search::KdTree<pcl::PointXYZRGB>::Ptr
tree (
new pcl::search::KdTree<pcl::PointXYZRGB>);
2927 tree->setInputCloud(cloud, indices);
2931 tree->setInputCloud (cloud);
2935 pcl::PointCloud<pcl::Normal>::Ptr normals (
new pcl::PointCloud<pcl::Normal>);
2936 pcl::IntegralImageNormalEstimation<pcl::PointXYZRGB, pcl::Normal> ne;
2937 ne.setNormalEstimationMethod (ne.AVERAGE_3D_GRADIENT);
2938 ne.setMaxDepthChangeFactor(maxDepthChangeFactor);
2939 ne.setNormalSmoothingSize(normalSmoothingSize);
2940 ne.setBorderPolicy(ne.BORDER_POLICY_MIRROR);
2941 ne.setInputCloud(cloud);
2947 ne.setSearchMethod(tree);
2948 ne.setViewPoint(viewPoint[0], viewPoint[1], viewPoint[2]);
2949 ne.compute(*normals);
2957 cv::Mat * pcaEigenVectors,
2958 cv::Mat * pcaEigenValues)
2963 int sz =
static_cast<int>(scan.
size()*2);
2964 bool is2d = scan.
is2d();
2965 cv::Mat data_normals = cv::Mat::zeros(sz, is2d?2:3, CV_32FC1);
2968 bool doTransform =
false;
2975 for (
int i = 0; i < scan.
size(); ++i)
2977 const float * ptrScan = scan.
data().ptr<
float>(0, i);
2983 cv::Point3f n(ptrScan[nOffset], ptrScan[nOffset+1], 0);
2988 float * ptr = data_normals.ptr<
float>(oi++, 0);
2997 cv::Point3f n(ptrScan[nOffset], ptrScan[nOffset+1], ptrScan[nOffset+2]);
3002 float * ptr = data_normals.ptr<
float>(oi++, 0);
3011 cv::PCA pca_analysis(cv::Mat(data_normals, cv::Range(0, oi*2)), cv::Mat(), CV_PCA_DATA_AS_ROW);
3015 *pcaEigenVectors = pca_analysis.eigenvectors;
3019 *pcaEigenValues = pca_analysis.eigenvalues;
3021 UASSERT((is2d && pca_analysis.eigenvalues.total()>=2) || (!is2d && pca_analysis.eigenvalues.total()>=3));
3023 return pca_analysis.eigenvalues.at<
float>(0, is2d?1:2)*(is2d?2.0
f:3.0
f);
3028 UERROR(
"Scan doesn't have normals!");
3034 const pcl::PointCloud<pcl::PointNormal> & cloud,
3037 cv::Mat * pcaEigenVectors,
3038 cv::Mat * pcaEigenValues)
3041 int sz =
static_cast<int>(cloud.size()*2);
3042 cv::Mat data_normals = cv::Mat::zeros(sz, is2d?2:3, CV_32FC1);
3044 bool doTransform =
false;
3051 for (
unsigned int i = 0; i < cloud.size(); ++i)
3053 const pcl::PointNormal & pt = cloud.at(i);
3054 cv::Point3f n(pt.normal_x, pt.normal_y, pt.normal_z);
3061 float * ptr = data_normals.ptr<
float>(oi++, 0);
3072 cv::PCA pca_analysis(cv::Mat(data_normals, cv::Range(0, oi*2)), cv::Mat(), CV_PCA_DATA_AS_ROW);
3076 *pcaEigenVectors = pca_analysis.eigenvectors;
3080 *pcaEigenValues = pca_analysis.eigenvalues;
3084 return pca_analysis.eigenvalues.at<
float>(0, is2d?1:2)*(is2d?2.0
f:3.0
f);
3090 const pcl::PointCloud<pcl::Normal> & normals,
3093 cv::Mat * pcaEigenVectors,
3094 cv::Mat * pcaEigenValues)
3097 int sz =
static_cast<int>(normals.size()*2);
3098 cv::Mat data_normals = cv::Mat::zeros(sz, is2d?2:3, CV_32FC1);
3100 bool doTransform =
false;
3107 for (
unsigned int i = 0; i < normals.size(); ++i)
3109 const pcl::Normal & pt = normals.at(i);
3110 cv::Point3f n(pt.normal_x, pt.normal_y, pt.normal_z);
3117 float * ptr = data_normals.ptr<
float>(oi++, 0);
3128 cv::PCA pca_analysis(cv::Mat(data_normals, cv::Range(0, oi*2)), cv::Mat(), CV_PCA_DATA_AS_ROW);
3132 *pcaEigenVectors = pca_analysis.eigenvectors;
3136 *pcaEigenValues = pca_analysis.eigenvalues;
3140 return pca_analysis.eigenvalues.at<
float>(0, is2d?1:2)*(is2d?2.0
f:3.0
f);
3146 const pcl::PointCloud<pcl::PointXYZINormal> & cloud,
3149 cv::Mat * pcaEigenVectors,
3150 cv::Mat * pcaEigenValues)
3153 int sz =
static_cast<int>(cloud.size()*2);
3154 cv::Mat data_normals = cv::Mat::zeros(sz, is2d?2:3, CV_32FC1);
3156 bool doTransform =
false;
3163 for (
unsigned int i = 0; i < cloud.size(); ++i)
3165 const pcl::PointXYZINormal & pt = cloud.at(i);
3166 cv::Point3f n(pt.normal_x, pt.normal_y, pt.normal_z);
3173 float * ptr = data_normals.ptr<
float>(oi++, 0);
3184 cv::PCA pca_analysis(cv::Mat(data_normals, cv::Range(0, oi*2)), cv::Mat(), CV_PCA_DATA_AS_ROW);
3188 *pcaEigenVectors = pca_analysis.eigenvectors;
3192 *pcaEigenValues = pca_analysis.eigenvalues;
3196 return pca_analysis.eigenvalues.at<
float>(0, is2d?1:2)*(is2d?2.0
f:3.0
f);
3202 const pcl::PointCloud<pcl::PointXYZRGBNormal> & cloud,
3205 cv::Mat * pcaEigenVectors,
3206 cv::Mat * pcaEigenValues)
3209 int sz =
static_cast<int>(cloud.size()*2);
3210 cv::Mat data_normals = cv::Mat::zeros(sz, is2d?2:3, CV_32FC1);
3212 bool doTransform =
false;
3219 for (
unsigned int i = 0; i < cloud.size(); ++i)
3221 const pcl::PointXYZRGBNormal & pt = cloud.at(i);
3222 cv::Point3f n(pt.normal_x, pt.normal_y, pt.normal_z);
3229 float * ptr = data_normals.ptr<
float>(oi++, 0);
3240 cv::PCA pca_analysis(cv::Mat(data_normals, cv::Range(0, oi*2)), cv::Mat(), CV_PCA_DATA_AS_ROW);
3244 *pcaEigenVectors = pca_analysis.eigenvectors;
3248 *pcaEigenValues = pca_analysis.eigenvalues;
3252 return pca_analysis.eigenvalues.at<
float>(0, is2d?1:2)*(is2d?2.0
f:3.0
f);
3257 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr
mls(
3258 const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
3260 int polygonialOrder,
3261 int upsamplingMethod,
3262 float upsamplingRadius,
3263 float upsamplingStep,
3265 float dilationVoxelSize,
3266 int dilationIterations)
3268 pcl::IndicesPtr indices(
new std::vector<int>);
3278 dilationIterations);
3281 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr
mls(
3282 const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
3283 const pcl::IndicesPtr & indices,
3285 int polygonialOrder,
3286 int upsamplingMethod,
3287 float upsamplingRadius,
3288 float upsamplingStep,
3290 float dilationVoxelSize,
3291 int dilationIterations)
3293 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr cloud_with_normals(
new pcl::PointCloud<pcl::PointXYZRGBNormal>);
3294 pcl::search::KdTree<pcl::PointXYZRGB>::Ptr
tree (
new pcl::search::KdTree<pcl::PointXYZRGB>);
3297 tree->setInputCloud (cloud, indices);
3301 tree->setInputCloud (cloud);
3305 pcl::MovingLeastSquares<pcl::PointXYZRGB, pcl::PointXYZRGBNormal>
mls;
3308 mls.setComputeNormals (
true);
3309 if(polygonialOrder > 0)
3311 #if PCL_VERSION_COMPARE(<, 1, 10, 0) 3312 mls.setPolynomialFit (
true);
3314 mls.setPolynomialOrder(polygonialOrder);
3318 #if PCL_VERSION_COMPARE(<, 1, 10, 0) 3319 mls.setPolynomialFit (
false);
3321 mls.setPolynomialOrder(1);
3324 UASSERT(upsamplingMethod >= mls.NONE &&
3325 upsamplingMethod <= mls.VOXEL_GRID_DILATION);
3326 mls.setUpsamplingMethod((pcl::MovingLeastSquares<pcl::PointXYZRGB, pcl::PointXYZRGBNormal>::UpsamplingMethod)upsamplingMethod);
3327 mls.setSearchRadius(searchRadius);
3328 mls.setUpsamplingRadius(upsamplingRadius);
3329 mls.setUpsamplingStepSize(upsamplingStep);
3330 mls.setPointDensity(pointDensity);
3331 mls.setDilationVoxelSize(dilationVoxelSize);
3332 mls.setDilationIterations(dilationIterations);
3335 mls.setInputCloud (cloud);
3338 mls.setIndices(indices);
3340 mls.setSearchMethod (tree);
3341 mls.process (*cloud_with_normals);
3344 for(
unsigned int i=0; i<cloud_with_normals->size(); ++i)
3346 Eigen::Vector3f normal(cloud_with_normals->at(i).normal_x, cloud_with_normals->at(i).normal_y, cloud_with_normals->at(i).normal_z);
3348 cloud_with_normals->at(i).normal_x = normal[0];
3349 cloud_with_normals->at(i).normal_y = normal[1];
3350 cloud_with_normals->at(i).normal_z = normal[2];
3353 return cloud_with_normals;
3358 const Eigen::Vector3f & viewpoint,
3359 bool forceGroundNormalsUp)
3365 const Eigen::Vector3f & viewpoint,
3366 float groundNormalsUp)
3373 cv::Mat output = scan.
data().clone();
3374 #pragma omp parallel for 3375 for(
int i=0; i<scan.
size(); ++i)
3377 float * ptr = output.ptr<
float>(0, i);
3380 Eigen::Vector3f v = viewpoint - Eigen::Vector3f(ptr[0], ptr[1], ptr[2]);
3381 Eigen::Vector3f n(ptr[nx], ptr[ny], ptr[nz]);
3383 float result = v.dot(n);
3385 || (groundNormalsUp>0.0
f && ptr[nz] < -groundNormalsUp && ptr[2] < viewpoint[3]))
3406 template<
typename Po
intNormalT>
3408 typename pcl::PointCloud<PointNormalT>::Ptr & cloud,
3409 const Eigen::Vector3f & viewpoint,
3410 float groundNormalsUp)
3412 for(
unsigned int i=0; i<cloud->size(); ++i)
3414 pcl::PointXYZ normal(cloud->points[i].normal_x, cloud->points[i].normal_y, cloud->points[i].normal_z);
3417 Eigen::Vector3f v = viewpoint - cloud->points[i].getVector3fMap();
3418 Eigen::Vector3f n(normal.x, normal.y, normal.z);
3420 float result = v.dot(n);
3422 || (groundNormalsUp>0.0
f && normal.z < -groundNormalsUp && cloud->points[i].z < viewpoint[3]))
3425 cloud->points[i].normal_x *= -1.0f;
3426 cloud->points[i].normal_y *= -1.0f;
3427 cloud->points[i].normal_z *= -1.0f;
3434 pcl::PointCloud<pcl::PointNormal>::Ptr & cloud,
3435 const Eigen::Vector3f & viewpoint,
3436 bool forceGroundNormalsUp)
3441 pcl::PointCloud<pcl::PointNormal>::Ptr & cloud,
3442 const Eigen::Vector3f & viewpoint,
3443 float groundNormalsUp)
3445 adjustNormalsToViewPointImpl<pcl::PointNormal>(cloud, viewpoint, groundNormalsUp);
3449 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud,
3450 const Eigen::Vector3f & viewpoint,
3451 bool forceGroundNormalsUp)
3456 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud,
3457 const Eigen::Vector3f & viewpoint,
3458 float groundNormalsUp)
3460 adjustNormalsToViewPointImpl<pcl::PointXYZRGBNormal>(cloud, viewpoint, groundNormalsUp);
3464 pcl::PointCloud<pcl::PointXYZINormal>::Ptr & cloud,
3465 const Eigen::Vector3f & viewpoint,
3466 bool forceGroundNormalsUp)
3471 pcl::PointCloud<pcl::PointXYZINormal>::Ptr & cloud,
3472 const Eigen::Vector3f & viewpoint,
3473 float groundNormalsUp)
3475 adjustNormalsToViewPointImpl<pcl::PointXYZINormal>(cloud, viewpoint, groundNormalsUp);
3479 const std::map<int, Transform> & poses,
3480 const pcl::PointCloud<pcl::PointXYZ>::Ptr & rawCloud,
3481 const std::vector<int> & rawCameraIndices,
3482 pcl::PointCloud<pcl::PointNormal>::Ptr & cloud)
3484 if(poses.size() && rawCloud->size() && rawCloud->size() == rawCameraIndices.size() && cloud->size())
3486 pcl::search::KdTree<pcl::PointXYZ>::Ptr rawTree (
new pcl::search::KdTree<pcl::PointXYZ>);
3487 rawTree->setInputCloud (rawCloud);
3489 for(
unsigned int i=0; i<cloud->size(); ++i)
3491 pcl::PointXYZ normal(cloud->points[i].normal_x, cloud->points[i].normal_y, cloud->points[i].normal_z);
3494 std::vector<int> indices;
3495 std::vector<float> dist;
3496 rawTree->nearestKSearch(pcl::PointXYZ(cloud->points[i].x, cloud->points[i].y, cloud->points[i].z), 1, indices, dist);
3498 if(indices.size() && indices[0]>=0)
3500 Transform p = poses.at(rawCameraIndices[indices[0]]);
3501 pcl::PointXYZ viewpoint(p.
x(), p.
y(), p.
z());
3502 Eigen::Vector3f v = viewpoint.getVector3fMap() - cloud->points[i].getVector3fMap();
3504 Eigen::Vector3f n(normal.x, normal.y, normal.z);
3506 float result = v.dot(n);
3510 cloud->points[i].normal_x *= -1.0f;
3511 cloud->points[i].normal_y *= -1.0f;
3512 cloud->points[i].normal_z *= -1.0f;
3517 UWARN(
"Not found camera viewpoint for point %d", i);
3525 const std::map<int, Transform> & poses,
3526 const pcl::PointCloud<pcl::PointXYZ>::Ptr & rawCloud,
3527 const std::vector<int> & rawCameraIndices,
3528 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud)
3530 UASSERT(rawCloud.get() && cloud.get());
3531 UDEBUG(
"poses=%d, rawCloud=%d, rawCameraIndices=%d, cloud=%d", (
int)poses.size(), (int)rawCloud->size(), (int)rawCameraIndices.size(), (int)cloud->size());
3532 if(poses.size() && rawCloud->size() && rawCloud->size() == rawCameraIndices.size() && cloud->size())
3534 pcl::search::KdTree<pcl::PointXYZ>::Ptr rawTree (
new pcl::search::KdTree<pcl::PointXYZ>);
3535 rawTree->setInputCloud (rawCloud);
3536 for(
unsigned int i=0; i<cloud->size(); ++i)
3538 pcl::PointXYZ normal(cloud->points[i].normal_x, cloud->points[i].normal_y, cloud->points[i].normal_z);
3541 std::vector<int> indices;
3542 std::vector<float> dist;
3543 rawTree->nearestKSearch(pcl::PointXYZ(cloud->points[i].x, cloud->points[i].y, cloud->points[i].z), 1, indices, dist);
3544 if(indices.size() && indices[0]>=0)
3546 UASSERT_MSG(indices[0]<(
int)rawCameraIndices.size(),
uFormat(
"indices[0]=%d rawCameraIndices.size()=%d", indices[0], (
int)rawCameraIndices.size()).c_str());
3548 Transform p = poses.at(rawCameraIndices[indices[0]]);
3549 pcl::PointXYZ viewpoint(p.
x(), p.
y(), p.
z());
3550 Eigen::Vector3f v = viewpoint.getVector3fMap() - cloud->points[i].getVector3fMap();
3552 Eigen::Vector3f n(normal.x, normal.y, normal.z);
3554 float result = v.dot(n);
3558 cloud->points[i].normal_x *= -1.0f;
3559 cloud->points[i].normal_y *= -1.0f;
3560 cloud->points[i].normal_z *= -1.0f;
3565 UWARN(
"Not found camera viewpoint for point %d!?", i);
3572 pcl::PolygonMesh::Ptr
meshDecimation(
const pcl::PolygonMesh::Ptr & mesh,
float factor)
3574 pcl::PolygonMesh::Ptr output(
new pcl::PolygonMesh);
3576 pcl::MeshQuadricDecimationVTK mqd;
3577 mqd.setTargetReductionFactor(factor);
3578 mqd.setInputMesh(mesh);
3579 mqd.process (*output);
3581 UWARN(
"RTAB-Map is not built with VTK module so mesh decimation cannot be used!");
3588 const Eigen::Vector3f & p,
3589 const Eigen::Vector3f & dir,
3590 const Eigen::Vector3f & v0,
3591 const Eigen::Vector3f & v1,
3592 const Eigen::Vector3f & v2,
3594 Eigen::Vector3f & normal)
3597 const Eigen::Vector3f u = v1-v0;
3598 const Eigen::Vector3f v = v2-v0;
3599 normal = u.cross(v);
3600 if (normal == Eigen::Vector3f(0,0,0))
3603 const float denomimator = normal.dot(dir);
3604 if (fabs(denomimator) < 10
e-9)
3608 distance = normal.dot(v0 - p) / denomimator;
3613 float uu, uv, vv, wu, wv, D;
3617 const Eigen::Vector3f w = p + dir * distance - v0;
3620 D = uv * uv - uu * vv;
3624 s = (uv * wv - vv * wu) / D;
3625 if (s < 0.0 || s > 1.0)
3627 t = (uv * wu - uu * wv) / D;
3628 if (t < 0.0 || (s + t) > 1.0)
bool uIsInteger(const std::string &str, bool checkForSign=true)
int UTILITE_EXP uStr2Int(const std::string &str)
std::vector< int > RTABMAP_EXP filterNaNPointsFromMesh(const pcl::PointCloud< pcl::PointXYZRGB > &cloud, const std::vector< pcl::Vertices > &polygons, pcl::PointCloud< pcl::PointXYZRGB > &outputCloud, std::vector< pcl::Vertices > &outputPolygons)
T uVariance(const T *v, unsigned int size, T meanV)
bool RTABMAP_EXP isFinite(const cv::Point3f &pt)
void setViewpoint(const Eigen::Vector3f &viewpoint)
Set the viewpoint from where the input point cloud has been acquired.
rtabmap::CameraThread * cam
void uncompressDataConst(cv::Mat *imageRaw, cv::Mat *depthOrRightRaw, LaserScan *laserScanRaw=0, cv::Mat *userDataRaw=0, cv::Mat *groundCellsRaw=0, cv::Mat *obstacleCellsRaw=0, cv::Mat *emptyCellsRaw=0) const
static bool makeDir(const std::string &dirPath)
T uMean(const T *v, unsigned int size)
pcl::TextureMesh::Ptr RTABMAP_EXP concatenateTextureMeshes(const std::list< pcl::TextureMesh::Ptr > &meshes)
pcl::PointCloud< pcl::Normal >::Ptr computeNormals2DImpl(const typename pcl::PointCloud< PointT >::Ptr &cloud, int searchK, float searchRadius, const Eigen::Vector3f &viewPoint)
const cv::Size & imageSize() const
cv::Point3f RTABMAP_EXP transformPoint(const cv::Point3f &pt, const Transform &transform)
const cv::Mat & data() const
pcl::PointCloud< pcl::Normal >::Ptr RTABMAP_EXP computeNormals2D(const pcl::PointCloud< pcl::PointXYZ >::Ptr &cloud, int searchK=5, float searchRadius=0.0f, const Eigen::Vector3f &viewPoint=Eigen::Vector3f(0, 0, 0))
bool textureMeshwithMultipleCameras2(pcl::TextureMesh &mesh, const pcl::texture_mapping::CameraVector &cameras, const rtabmap::ProgressState *callback=0, std::vector< std::map< int, pcl::PointXY > > *vertexToPixels=0, bool distanceToCamPolicy=false)
void setTriangulationType(TriangulationType type)
Set the triangulation type (see TriangulationType)
Simple triangulation/surface reconstruction for organized point clouds. Neighboring points (pixels in...
std::vector< Camera, Eigen::aligned_allocator< Camera > > CameraVector
GLM_FUNC_DECL vecType< T, P > sqrt(vecType< T, P > const &x)
SensorData getNodeData(int locationId, bool images, bool scan, bool userData, bool occupancyGrid) const
std::vector< pcl::Vertices > RTABMAP_EXP filterCloseVerticesFromMesh(const pcl::PointCloud< pcl::PointXYZRGBNormal >::Ptr cloud, const std::vector< pcl::Vertices > &polygons, float radius, float angle, bool keepLatestInRadius)
static std::string getDir(const std::string &filePath)
const float maxDepthError
pcl::PointCloud< pcl::PointXYZRGBNormal >::Ptr RTABMAP_EXP laserScanToPointCloudRGBNormal(const LaserScan &laserScan, const Transform &transform=Transform(), unsigned char r=100, unsigned char g=100, unsigned char b=100)
pcl::PointCloud< pcl::Normal >::Ptr computeNormalsImpl(const typename pcl::PointCloud< PointT >::Ptr &cloud, const pcl::IndicesPtr &indices, int searchK, float searchRadius, const Eigen::Vector3f &viewPoint)
std::vector< int > RTABMAP_EXP filterNotUsedVerticesFromMesh(const pcl::PointCloud< pcl::PointXYZRGBNormal > &cloud, const std::vector< pcl::Vertices > &polygons, pcl::PointCloud< pcl::PointXYZRGBNormal > &outputCloud, std::vector< pcl::Vertices > &outputPolygons)
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)
The texture mapping algorithm.
static int erase(const std::string &filePath)
void setAngleTolerance(float angle_tolerance)
Set the angle tolerance used for checking whether or not an edge is occluded. Standard values are 5de...
GLM_FUNC_DECL genType e()
GLM_FUNC_DECL bool all(vecType< bool, P > const &v)
static const float vertices[]
void getNodeData(int signatureId, SensorData &data, bool images=true, bool scan=true, bool userData=true, bool occupancyGrid=true) const
void setMinClusterSize(int size)
GLM_FUNC_DECL genType::value_type distance(genType const &p0, genType const &p1)
pcl::PointCloud< pcl::Normal >::Ptr RTABMAP_EXP computeFastOrganizedNormals(const pcl::PointCloud< pcl::PointXYZRGB >::Ptr &cloud, float maxDepthChangeFactor=0.02f, float normalSmoothingSize=10.0f, const Eigen::Vector3f &viewPoint=Eigen::Vector3f(0, 0, 0))
GLM_FUNC_DECL genType::row_type row(genType const &m, length_t const &index)
int getNormalsOffset() const
Basic mathematics functions.
GLM_FUNC_DECL T angle(detail::tquat< T, P > const &x)
Some conversion functions.
LaserScan computeNormals(const LaserScan &laserScan, int searchK, float searchRadius)
pcl::TextureMesh::Ptr RTABMAP_EXP assembleTextureMesh(const cv::Mat &cloudMat, const std::vector< std::vector< std::vector< RTABMAP_PCL_INDEX > > > &polygons, const std::vector< std::vector< Eigen::Vector2f > > &texCoords, cv::Mat &textures, bool mergeTextures=false)
const cv::Mat & imageRaw() const
GLM_FUNC_DECL bool intersectRayTriangle(genType const &orig, genType const &dir, genType const &vert0, genType const &vert1, genType const &vert2, genType &baryPosition)
pcl::PointCloud< pcl::Normal >::Ptr computeFastOrganizedNormals2DImpl(const typename pcl::PointCloud< PointT >::Ptr &cloud, int searchK, float searchRadius, const Eigen::Vector3f &viewPoint)
bool uStrContains(const std::string &string, const std::string &substring)
pcl::PointCloud< pcl::Normal >::Ptr RTABMAP_EXP computeFastOrganizedNormals2D(const pcl::PointCloud< pcl::PointXYZ >::Ptr &cloud, int searchK=5, float searchRadius=0.0f, const Eigen::Vector3f &viewPoint=Eigen::Vector3f(0, 0, 0))
pcl::PointCloud< pcl::PointXYZ >::Ptr RTABMAP_EXP laserScanToPointCloud(const LaserScan &laserScan, const Transform &transform=Transform())
std::list< std::string > uSplit(const std::string &str, char separator= ' ')
std::vector< double > roi
cv::Mat RTABMAP_EXP laserScan2dFromPointCloud(const pcl::PointCloud< pcl::PointXYZ > &cloud, const Transform &transform=Transform(), bool filterNaNs=true)
pcl::PointCloud< pcl::PointXYZRGBNormal >::Ptr RTABMAP_EXP mls(const pcl::PointCloud< pcl::PointXYZRGB >::Ptr &cloud, float searchRadius=0.0f, int polygonialOrder=2, int upsamplingMethod=0, float upsamplingRadius=0.0f, float upsamplingStep=0.0f, int pointDensity=0, float dilationVoxelSize=1.0f, int dilationIterations=0)
bool uIsFinite(const T &value)
pcl::texture_mapping::CameraVector createTextureCameras(const std::map< int, Transform > &poses, const std::map< int, std::vector< CameraModel > > &cameraModels, const std::map< int, cv::Mat > &cameraDepths, const std::vector< float > &roiRatios)
#define UASSERT(condition)
Structure to store camera pose and focal length.
virtual bool callback(const std::string &msg) const
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)
bool isValidForProjection() const
const CameraModel & left() const
std::list< std::list< int > > RTABMAP_EXP clusterPolygons(const std::vector< std::set< int > > &neighborPolygons, int minClusterSize=0)
void setTrianglePixelSize(int triangle_size)
Set the edge length (in pixels) used for constructing the fixed mesh.
pcl::PolygonMesh::Ptr RTABMAP_EXP meshDecimation(const pcl::PolygonMesh::Ptr &mesh, float factor)
std::vector< pcl::Vertices > RTABMAP_EXP convertPolygonsToPCL(const std::vector< std::vector< RTABMAP_PCL_INDEX > > &polygons)
void RTABMAP_EXP appendMesh(pcl::PointCloud< pcl::PointXYZRGBNormal > &cloudA, std::vector< pcl::Vertices > &polygonsA, const pcl::PointCloud< pcl::PointXYZRGBNormal > &cloudB, const std::vector< pcl::Vertices > &polygonsB)
#define UASSERT_MSG(condition, msg_str)
GLM_FUNC_DECL genType pi()
bool getCalibration(int signatureId, std::vector< CameraModel > &models, StereoCameraModel &stereoModel) const
void adjustNormalsToViewPoint(pcl::PointCloud< pcl::PointXYZINormal >::Ptr &cloud, const Eigen::Vector3f &viewpoint, bool forceGroundNormalsUp)
Transform localTransform() const
void setMaxDepthError(float maxDepthError)
float angleIncrement() const
static ULogger::Level level()
pcl::PolygonMesh::Ptr RTABMAP_EXP createMesh(const pcl::PointCloud< pcl::PointXYZRGBNormal >::Ptr &cloudWithNormals, float gp3SearchRadius=0.025, float gp3Mu=2.5, int gp3MaximumNearestNeighbors=100, float gp3MaximumSurfaceAngle=M_PI/4, float gp3MinimumAngle=M_PI/18, float gp3MaximumAngle=2 *M_PI/3, bool gp3NormalConsistency=true)
std::vector< pcl::Vertices > RTABMAP_EXP organizedFastMesh(const pcl::PointCloud< pcl::PointXYZ >::Ptr &cloud, double angleTolerance, bool quad, int trianglePixelSize, const Eigen::Vector3f &viewpoint=Eigen::Vector3f(0, 0, 0))
void RTABMAP_EXP concatenateTextureMaterials(pcl::TextureMesh &mesh, const cv::Size &imageSize, int textureSize, int maxTextures, float &scale, std::vector< bool > *materialsKept=0)
bool uContains(const std::list< V > &list, const V &value)
RecoveryProgressState state
GLM_FUNC_DECL detail::tquat< T, P > rotation(detail::tvec3< T, P > const &orig, detail::tvec3< T, P > const &dest)
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)
cv::Mat RTABMAP_EXP exposureFusion(const std::vector< cv::Mat > &images)
void adjustNormalsToViewPointImpl(typename pcl::PointCloud< PointNormalT >::Ptr &cloud, const Eigen::Vector3f &viewpoint, float groundNormalsUp)
std::vector< std::vector< RTABMAP_PCL_INDEX > > RTABMAP_EXP convertPolygonsFromPCL(const std::vector< pcl::Vertices > &polygons)
void RTABMAP_EXP adjustNormalsToViewPoints(const std::map< int, Transform > &poses, const pcl::PointCloud< pcl::PointXYZ >::Ptr &rawCloud, const std::vector< int > &rawCameraIndices, pcl::PointCloud< pcl::PointNormal >::Ptr &cloud)
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)
void RTABMAP_EXP fixTextureMeshForVisualization(pcl::TextureMesh &textureMesh)
const std::vector< CameraModel > & cameraModels() const
std::vector< pcl::Vertices > RTABMAP_EXP filterInvalidPolygons(const std::vector< pcl::Vertices > &polygons)
void RTABMAP_EXP cleanTextureMesh(pcl::TextureMesh &textureMesh, int minClusterSize)
pcl::PointCloud< pcl::PointNormal >::Ptr RTABMAP_EXP laserScanToPointCloudNormal(const LaserScan &laserScan, const Transform &transform=Transform())
void RTABMAP_EXP createPolygonIndexes(const std::vector< pcl::Vertices > &polygons, int cloudSize, std::vector< std::set< int > > &neighborPolygons, std::vector< std::set< int > > &vertexPolygons)
Given a set of polygons, create two indexes: polygons to neighbor polygons and vertices to polygons...
static bool removeDir(const std::string &dirPath)
ULogger class and convenient macros.
const StereoCameraModel & stereoCameraModel() const
void setMaxAngle(float maxAngle)
const cv::Mat & imageCompressed() const
pcl::PointCloud< pcl::PointNormal >::Ptr RTABMAP_EXP removeNaNNormalsFromPointCloud(const pcl::PointCloud< pcl::PointNormal >::Ptr &cloud)
void setMaxDistance(float maxDistance)
static const GLushort kIndices[]
pcl::PointCloud< pcl::PointXYZI >::Ptr RTABMAP_EXP laserScanToPointCloudI(const LaserScan &laserScan, const Transform &transform=Transform(), float intensity=0.0f)
T uSum(const std::list< T > &list)
cv::Mat RTABMAP_EXP brightnessAndContrastAuto(const cv::Mat &src, const cv::Mat &mask, float clipLowHistPercent=0, float clipHighHistPercent=0, float *alphaOut=0, float *betaOut=0)
Automatic brightness and contrast optimization with optional histogram clipping.
pcl::IndicesPtr RTABMAP_EXP concatenate(const std::vector< pcl::IndicesPtr > &indices)
Concatenate a vector of indices to a single vector.
std::string UTILITE_EXP uFormat(const char *fmt,...)
std::string UTILITE_EXP uNumber2Str(unsigned int number)
float RTABMAP_EXP computeNormalsComplexity(const LaserScan &scan, const Transform &t=Transform::getIdentity(), cv::Mat *pcaEigenVectors=0, cv::Mat *pcaEigenValues=0)
pcl::PolygonMesh::Ptr RTABMAP_EXP assemblePolygonMesh(const cv::Mat &cloudMat, const std::vector< std::vector< RTABMAP_PCL_INDEX > > &polygons)
bool hasIntensity() const
cv::Mat RTABMAP_EXP uncompressImage(const cv::Mat &bytes)
const Transform & localTransform() const
LaserScan RTABMAP_EXP laserScanFromPointCloud(const pcl::PCLPointCloud2 &cloud, bool filterNaNs=true, bool is2D=false, const Transform &transform=Transform())