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(roiRatios.empty() || roiRatios.size() == 4);
607 for(std::map<int, Transform>::const_iterator poseIter=poses.begin(); poseIter!=poses.end(); ++poseIter)
609 std::map<int, std::vector<CameraModel> >::const_iterator modelIter=cameraModels.find(poseIter->first);
611 if(modelIter!=cameraModels.end())
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);
634 cam.
center_w=modelIter->second[i].cx();
635 cam.
center_h=modelIter->second[i].cy();
636 cam.
height=modelIter->second[i].imageHeight();
637 cam.
width=modelIter->second[i].imageWidth();
638 if(modelIter->second.size() == 1)
646 if(!roiRatios.empty())
649 cam.
roi[0] = cam.
width * roiRatios[0];
651 cam.
roi[2] = cam.
width * (1.0 - roiRatios[1]) - cam.
roi[0];
652 cam.
roi[3] = cam.
height * (1.0 - roiRatios[3]) - cam.
roi[1];
655 if(depthIter != cameraDepths.end() && !depthIter->second.empty())
657 UASSERT(depthIter->second.type() == CV_32FC1 || depthIter->second.type() == CV_16UC1);
658 UASSERT(depthIter->second.cols % modelIter->second.size() == 0);
659 int subWidth = depthIter->second.cols/(modelIter->second.size());
660 cam.
depth = cv::Mat(depthIter->second, cv::Range(0, depthIter->second.rows), cv::Range(subWidth*i, subWidth*(i+1)));
666 UDEBUG(
"cam.pose=%s", t.prettyPrint().c_str());
668 cameras.push_back(cam);
676 const pcl::PolygonMesh::Ptr & mesh,
677 const std::map<int, Transform> & poses,
678 const std::map<int, CameraModel> & cameraModels,
679 const std::map<int, cv::Mat> & cameraDepths,
684 const std::vector<float> & roiRatios,
686 std::vector<std::map<int, pcl::PointXY> > * vertexToPixels,
687 bool distanceToCamPolicy)
689 std::map<int, std::vector<CameraModel> > cameraSubModels;
690 for(std::map<int, CameraModel>::const_iterator iter=cameraModels.begin(); iter!=cameraModels.end(); ++iter)
692 std::vector<CameraModel> models;
693 models.push_back(iter->second);
694 cameraSubModels.insert(std::make_pair(iter->first, models));
709 distanceToCamPolicy);
713 const pcl::PolygonMesh::Ptr & mesh,
714 const std::map<int, Transform> & poses,
715 const std::map<
int, std::vector<CameraModel> > & cameraModels,
716 const std::map<int, cv::Mat> & cameraDepths,
721 const std::vector<float> & roiRatios,
723 std::vector<std::map<int, pcl::PointXY> > * vertexToPixels,
724 bool distanceToCamPolicy)
726 UASSERT(mesh->polygons.size());
727 pcl::TextureMesh::Ptr textureMesh(
new pcl::TextureMesh);
728 textureMesh->cloud = mesh->cloud;
729 textureMesh->tex_polygons.push_back(mesh->polygons);
744 textureMesh->tex_materials.resize (cameras.size () + 1);
745 for(
unsigned int i = 0 ; i <= cameras.size() ; ++i)
747 pcl::TexMaterial mesh_material;
748 mesh_material.tex_Ka.r = 0.2f;
749 mesh_material.tex_Ka.g = 0.2f;
750 mesh_material.tex_Ka.b = 0.2f;
752 mesh_material.tex_Kd.r = 0.8f;
753 mesh_material.tex_Kd.g = 0.8f;
754 mesh_material.tex_Kd.b = 0.8f;
756 mesh_material.tex_Ks.r = 1.0f;
757 mesh_material.tex_Ks.g = 1.0f;
758 mesh_material.tex_Ks.b = 1.0f;
760 mesh_material.tex_d = 1.0f;
761 mesh_material.tex_Ns = 75.0f;
762 mesh_material.tex_illum = 2;
764 std::stringstream tex_name;
765 tex_name <<
"material_" << i;
766 tex_name >> mesh_material.tex_name;
768 if(i < cameras.size ())
770 mesh_material.tex_file = cameras[i].texture_file;
774 mesh_material.tex_file =
"occluded";
777 textureMesh->tex_materials[i] = mesh_material;
784 if(maxDepthError > 0.0
f)
792 bool hasNormals =
false;
793 bool hasColors =
false;
794 for(
unsigned int i=0; i<textureMesh->cloud.fields.size(); ++i)
796 if(textureMesh->cloud.fields[i].name.compare(
"normal_x") == 0)
800 else if(textureMesh->cloud.fields[i].name.compare(
"rgb") == 0)
810 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr cloud (
new pcl::PointCloud<pcl::PointXYZRGBNormal>);
811 pcl::fromPCLPointCloud2(mesh->cloud, *cloud);
813 for(
unsigned int i=0; i<mesh->polygons.size(); ++i)
815 pcl::Vertices & v = mesh->polygons[i];
818 cloud->at(v.vertices[1]).x - cloud->at(v.vertices[0]).x,
819 cloud->at(v.vertices[1]).y - cloud->at(v.vertices[0]).y,
820 cloud->at(v.vertices[1]).z - cloud->at(v.vertices[0]).z);
821 int last = v.vertices.size()-1;
823 cloud->at(v.vertices[last]).x - cloud->at(v.vertices[0]).x,
824 cloud->at(v.vertices[last]).y - cloud->at(v.vertices[0]).y,
825 cloud->at(v.vertices[last]).z - cloud->at(v.vertices[0]).z);
826 Eigen::Vector3f normal = v0.cross(v1);
829 for(
unsigned int j=0; j<v.vertices.size(); ++j)
831 cloud->at(v.vertices[j]).normal_x = normal[0];
832 cloud->at(v.vertices[j]).normal_y = normal[1];
833 cloud->at(v.vertices[j]).normal_z = normal[2];
836 pcl::toPCLPointCloud2 (*cloud, textureMesh->cloud);
840 pcl::PointCloud<pcl::PointNormal>::Ptr cloud (
new pcl::PointCloud<pcl::PointNormal>);
841 pcl::fromPCLPointCloud2(mesh->cloud, *cloud);
843 for(
unsigned int i=0; i<mesh->polygons.size(); ++i)
845 pcl::Vertices & v = mesh->polygons[i];
848 cloud->at(v.vertices[1]).x - cloud->at(v.vertices[0]).x,
849 cloud->at(v.vertices[1]).y - cloud->at(v.vertices[0]).y,
850 cloud->at(v.vertices[1]).z - cloud->at(v.vertices[0]).z);
851 int last = v.vertices.size()-1;
853 cloud->at(v.vertices[last]).x - cloud->at(v.vertices[0]).x,
854 cloud->at(v.vertices[last]).y - cloud->at(v.vertices[0]).y,
855 cloud->at(v.vertices[last]).z - cloud->at(v.vertices[0]).z);
856 Eigen::Vector3f normal = v0.cross(v1);
859 for(
unsigned int j=0; j<v.vertices.size(); ++j)
861 cloud->at(v.vertices[j]).normal_x = normal[0];
862 cloud->at(v.vertices[j]).normal_y = normal[1];
863 cloud->at(v.vertices[j]).normal_z = normal[2];
866 pcl::toPCLPointCloud2 (*cloud, textureMesh->cloud);
874 pcl::TextureMesh & textureMesh,
877 UDEBUG(
"minClusterSize=%d", minClusterSize);
879 if(textureMesh.tex_coordinates.size())
882 textureMesh.tex_coordinates.pop_back();
883 textureMesh.tex_polygons.pop_back();
884 textureMesh.tex_materials.pop_back();
886 if(minClusterSize!=0)
889 unsigned int totalSize = 0;
890 for(
unsigned int t=0; t<textureMesh.tex_polygons.size(); ++t)
892 totalSize+=textureMesh.tex_polygons[t].size();
894 std::vector<pcl::Vertices> allPolygons(totalSize);
896 for(
unsigned int t=0; t<textureMesh.tex_polygons.size(); ++t)
898 for(
unsigned int i=0; i<textureMesh.tex_polygons[t].size(); ++i)
900 allPolygons[oi++] = textureMesh.tex_polygons[t][i];
905 std::vector<std::set<int> > neighbors;
906 std::vector<std::set<int> > vertexToPolygons;
908 (
int)textureMesh.cloud.data.size()/textureMesh.cloud.point_step,
914 minClusterSize<0?0:minClusterSize);
916 std::set<int> validPolygons;
917 if(minClusterSize < 0)
920 std::list<std::list<int> >::iterator biggestClusterIndex = clusters.end();
921 unsigned int biggestClusterSize = 0;
922 for(std::list<std::list<int> >::iterator iter=clusters.begin(); iter!=clusters.end(); ++iter)
924 if(iter->size() > biggestClusterSize)
926 biggestClusterIndex = iter;
927 biggestClusterSize = iter->size();
930 if(biggestClusterIndex != clusters.end())
932 for(std::list<int>::iterator jter=biggestClusterIndex->begin(); jter!=biggestClusterIndex->end(); ++jter)
934 validPolygons.insert(*jter);
940 for(std::list<std::list<int> >::iterator iter=clusters.begin(); iter!=clusters.end(); ++iter)
942 for(std::list<int>::iterator jter=iter->begin(); jter!=iter->end(); ++jter)
944 validPolygons.insert(*jter);
949 if(validPolygons.size() == 0)
951 UWARN(
"All %d polygons filtered after polygon cluster filtering. Cluster minimum size is %d.",totalSize, minClusterSize);
955 unsigned int allPolygonsIndex = 0;
956 for(
unsigned int t=0; t<textureMesh.tex_polygons.size(); ++t)
958 std::vector<pcl::Vertices> filteredPolygons(textureMesh.tex_polygons[t].size());
959 #if PCL_VERSION_COMPARE(>=, 1, 8, 0) 960 std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > filteredCoordinates(textureMesh.tex_coordinates[t].size());
962 std::vector<Eigen::Vector2f> filteredCoordinates(textureMesh.tex_coordinates[t].size());
965 if(textureMesh.tex_polygons[t].size())
967 UASSERT_MSG(allPolygonsIndex < allPolygons.size(),
uFormat(
"%d vs %d", (
int)allPolygonsIndex, (
int)allPolygons.size()).c_str());
970 std::vector<unsigned int> polygonToCoord(textureMesh.tex_polygons[t].size());
971 unsigned int totalCoord = 0;
972 for(
unsigned int i=0; i<textureMesh.tex_polygons[t].size(); ++i)
974 polygonToCoord[i] = totalCoord;
975 totalCoord+=textureMesh.tex_polygons[t][i].vertices.size();
977 UASSERT_MSG(totalCoord == textureMesh.tex_coordinates[t].size(),
uFormat(
"%d vs %d", totalCoord, (
int)textureMesh.tex_coordinates[t].size()).c_str());
981 for(
unsigned int i=0; i<textureMesh.tex_polygons[t].size(); ++i)
983 if(validPolygons.find(allPolygonsIndex) != validPolygons.end())
985 filteredPolygons[oi] = textureMesh.tex_polygons[t].at(i);
986 for(
unsigned int j=0; j<filteredPolygons[oi].vertices.size(); ++j)
988 UASSERT(polygonToCoord[i] < textureMesh.tex_coordinates[t].size());
989 filteredCoordinates[ci] = textureMesh.tex_coordinates[t][polygonToCoord[i]+j];
996 filteredPolygons.resize(oi);
997 filteredCoordinates.resize(ci);
998 textureMesh.tex_polygons[t] = filteredPolygons;
999 textureMesh.tex_coordinates[t] = filteredCoordinates;
1008 pcl::TextureMesh::Ptr output(
new pcl::TextureMesh);
1009 std::map<std::string, int> addedMaterials;
1010 for(std::list<pcl::TextureMesh::Ptr>::const_iterator iter = meshes.begin(); iter!=meshes.end(); ++iter)
1012 if((*iter)->cloud.point_step &&
1013 (*iter)->cloud.data.size()/(*iter)->cloud.point_step &&
1014 (*iter)->tex_polygons.size() &&
1015 (*iter)->tex_coordinates.size())
1018 int polygonStep = output->cloud.height * output->cloud.width;
1019 pcl::PCLPointCloud2 tmp;
1020 #if PCL_VERSION_COMPARE(>=, 1, 10, 0) 1023 pcl::concatenatePointCloud(output->cloud, iter->get()->cloud, tmp);
1025 output->cloud = tmp;
1027 UASSERT((*iter)->tex_polygons.size() == (*iter)->tex_coordinates.size() &&
1028 (*iter)->tex_polygons.size() == (*iter)->tex_materials.size());
1030 int materialCount = (*iter)->tex_polygons.size();
1031 for(
int i=0; i<materialCount; ++i)
1033 std::map<std::string, int>::iterator jter = addedMaterials.find((*iter)->tex_materials[i].tex_file);
1035 if(jter != addedMaterials.end())
1037 index = jter->second;
1041 addedMaterials.insert(std::make_pair((*iter)->tex_materials[i].tex_file, output->tex_materials.size()));
1042 index = output->tex_materials.size();
1043 output->tex_materials.push_back((*iter)->tex_materials[i]);
1044 output->tex_materials.back().tex_name =
uFormat(
"material_%d", index);
1045 output->tex_polygons.resize(output->tex_polygons.size() + 1);
1046 output->tex_coordinates.resize(output->tex_coordinates.size() + 1);
1050 int oi = output->tex_polygons[index].size();
1051 output->tex_polygons[index].resize(output->tex_polygons[index].size() + (*iter)->tex_polygons[i].size());
1052 for(
unsigned int j=0; j<(*iter)->tex_polygons[i].size(); ++j)
1054 pcl::Vertices polygon = (*iter)->tex_polygons[i][j];
1055 for(
unsigned int k=0; k<polygon.vertices.size(); ++k)
1057 polygon.vertices[k] += polygonStep;
1059 output->tex_polygons[index][oi+j] = polygon;
1063 oi = output->tex_coordinates[index].size();
1064 output->tex_coordinates[index].resize(output->tex_coordinates[index].size() + (*iter)->tex_coordinates[i].size());
1065 for(
unsigned int j=0; j<(*iter)->tex_coordinates[i].size(); ++j)
1067 output->tex_coordinates[index][oi+j] = (*iter)->tex_coordinates[i][j];
1076 return b == 0 ? a :
gcd(b, a % b);
1081 UASSERT(textureSize>0 && imageSize.width>0 && imageSize.height>0);
1087 for(
unsigned int i=0; i<mesh.tex_materials.size(); ++i)
1089 if(mesh.tex_polygons.size())
1096 int w = imageSize.width;
1097 int h = imageSize.height;
1101 UDEBUG(
"w=%d h=%d g=%d a=%d b=%d", w, h, g, a, b);
1104 float factor = 0.1f;
1107 while((colCount*rowCount)*maxTextures < materials || (factor == 0.1
f || scale > 1.0
f))
1112 scale = float(textureSize)/float(w*b*factor);
1114 colCount = float(textureSize)/(scale*float(w));
1115 rowCount = float(textureSize)/(scale*float(h));
1118 int outputTextures = (materials / (colCount*rowCount)) + (materials % (colCount*rowCount) > 0?1:0);
1119 UDEBUG(
"materials=%d col=%d row=%d output textures=%d factor=%f scale=%f", materials, colCount, rowCount, outputTextures, factor-epsilon, scale);
1121 UASSERT(mesh.tex_coordinates.size() == mesh.tex_materials.size() && mesh.tex_polygons.size() == mesh.tex_materials.size());
1124 std::vector<int> totalPolygons(outputTextures, 0);
1125 std::vector<int> totalCoordinates(outputTextures, 0);
1127 for(
unsigned int i=0; i<mesh.tex_materials.size(); ++i)
1129 if(mesh.tex_polygons[i].size())
1131 int indexMaterial = count / (colCount*rowCount);
1132 UASSERT(indexMaterial < outputTextures);
1134 totalPolygons[indexMaterial]+=mesh.tex_polygons[i].size();
1135 totalCoordinates[indexMaterial]+=mesh.tex_coordinates[i].size();
1141 pcl::TextureMesh outputMesh;
1146 float scaledHeight = float(
int(scale*
float(h)))/float(textureSize);
1147 float scaledWidth = float(
int(scale*
float(w)))/float(textureSize);
1148 float lowerBorderSize = 1.0f - scaledHeight*float(rowCount);
1149 UDEBUG(
"scaledWidth=%f scaledHeight=%f lowerBorderSize=%f", scaledWidth, scaledHeight, lowerBorderSize);
1152 materialsKept->resize(mesh.tex_materials.size(),
false);
1154 for(
unsigned int t=0; t<mesh.tex_materials.size(); ++t)
1156 if(mesh.tex_polygons[t].size())
1158 int indexMaterial = ti / (colCount*rowCount);
1159 UASSERT(indexMaterial < outputTextures);
1160 if((
int)outputMesh.tex_polygons.size() <= indexMaterial)
1162 std::vector<pcl::Vertices> newPolygons(totalPolygons[indexMaterial]);
1163 #if PCL_VERSION_COMPARE(>=, 1, 8, 0) 1164 std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > newCoordinates(totalCoordinates[indexMaterial]);
1166 std::vector<Eigen::Vector2f> newCoordinates(totalCoordinates[indexMaterial]);
1168 outputMesh.tex_polygons.push_back(newPolygons);
1169 outputMesh.tex_coordinates.push_back(newCoordinates);
1175 int row = (ti/colCount) % rowCount;
1176 int col = ti%colCount;
1177 float offsetU = scaledWidth * float(col);
1178 float offsetV = scaledHeight * float((rowCount - 1) - row) + lowerBorderSize;
1181 for(
unsigned int i=0; i<mesh.tex_polygons[t].size(); ++i)
1183 UASSERT(pi < (
int)outputMesh.tex_polygons[indexMaterial].size());
1184 outputMesh.tex_polygons[indexMaterial][pi++] = mesh.tex_polygons[t].at(i);
1187 for(
unsigned int i=0; i<mesh.tex_coordinates[t].size(); ++i)
1189 const Eigen::Vector2f & v = mesh.tex_coordinates[t].at(i);
1190 if(v[0] >= 0 && v[1] >=0)
1192 outputMesh.tex_coordinates[indexMaterial][ci][0] = v[0]*scaledWidth + offsetU;
1193 outputMesh.tex_coordinates[indexMaterial][ci][1] = v[1]*scaledHeight + offsetV;
1197 outputMesh.tex_coordinates[indexMaterial][ci] = v;
1204 materialsKept->at(t) =
true;
1208 pcl::TexMaterial m = mesh.tex_materials.front();
1209 mesh.tex_materials.clear();
1210 for(
int i=0; i<outputTextures; ++i)
1212 m.tex_file =
"texture";
1213 m.tex_name =
"material";
1214 if(outputTextures > 1)
1220 mesh.tex_materials.push_back(m);
1222 mesh.tex_coordinates = outputMesh.tex_coordinates;
1223 mesh.tex_polygons = outputMesh.tex_polygons;
1229 std::vector<std::vector<RTABMAP_PCL_INDEX> > polygonsOut(polygons.size());
1230 for(
unsigned int p=0; p<polygons.size(); ++p)
1232 polygonsOut[p] = polygons[p].vertices;
1236 std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > >
convertPolygonsFromPCL(
const std::vector<std::vector<pcl::Vertices> > & tex_polygons)
1238 std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > polygonsOut(tex_polygons.size());
1239 for(
unsigned int t=0; t<tex_polygons.size(); ++t)
1241 polygonsOut[t].resize(tex_polygons[t].size());
1242 for(
unsigned int p=0; p<tex_polygons[t].size(); ++p)
1244 polygonsOut[t][p] = tex_polygons[t][p].vertices;
1251 std::vector<pcl::Vertices> polygonsOut(polygons.size());
1252 for(
unsigned int p=0; p<polygons.size(); ++p)
1254 polygonsOut[p].vertices = polygons[p];
1258 std::vector<std::vector<pcl::Vertices> >
convertPolygonsToPCL(
const std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > & tex_polygons)
1260 std::vector<std::vector<pcl::Vertices> > polygonsOut(tex_polygons.size());
1261 for(
unsigned int t=0; t<tex_polygons.size(); ++t)
1263 polygonsOut[t].resize(tex_polygons[t].size());
1264 for(
unsigned int p=0; p<tex_polygons[t].size(); ++p)
1266 polygonsOut[t][p].vertices = tex_polygons[t][p];
1273 const cv::Mat & cloudMat,
1274 const std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > & polygons,
1275 #
if PCL_VERSION_COMPARE(>=, 1, 8, 0)
1276 const std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > & texCoords,
1278 const std::vector<std::vector<Eigen::Vector2f> > & texCoords,
1283 pcl::TextureMesh::Ptr textureMesh(
new pcl::TextureMesh);
1285 if(cloudMat.channels() <= 3)
1288 pcl::toPCLPointCloud2(*cloud, textureMesh->cloud);
1290 else if(cloudMat.channels() == 4)
1293 pcl::toPCLPointCloud2(*cloud, textureMesh->cloud);
1295 else if(cloudMat.channels() == 6)
1298 pcl::toPCLPointCloud2(*cloud, textureMesh->cloud);
1300 else if(cloudMat.channels() == 7)
1303 pcl::toPCLPointCloud2(*cloud, textureMesh->cloud);
1306 if(textureMesh->cloud.data.size() && polygons.size())
1308 textureMesh->tex_polygons.resize(polygons.size());
1309 for(
unsigned int t=0; t<polygons.size(); ++t)
1311 textureMesh->tex_polygons[t].resize(polygons[t].size());
1312 for(
unsigned int p=0; p<polygons[t].size(); ++p)
1314 textureMesh->tex_polygons[t][p].vertices = polygons[t][p];
1318 if(!texCoords.empty() && !textures.empty())
1320 textureMesh->tex_coordinates = texCoords;
1322 textureMesh->tex_materials.resize (textureMesh->tex_coordinates.size());
1323 for(
unsigned int i = 0 ; i < textureMesh->tex_coordinates.size() ; ++i)
1325 pcl::TexMaterial mesh_material;
1326 mesh_material.tex_Ka.r = 0.2f;
1327 mesh_material.tex_Ka.g = 0.2f;
1328 mesh_material.tex_Ka.b = 0.2f;
1330 mesh_material.tex_Kd.r = 0.8f;
1331 mesh_material.tex_Kd.g = 0.8f;
1332 mesh_material.tex_Kd.b = 0.8f;
1334 mesh_material.tex_Ks.r = 1.0f;
1335 mesh_material.tex_Ks.g = 1.0f;
1336 mesh_material.tex_Ks.b = 1.0f;
1338 mesh_material.tex_d = 1.0f;
1339 mesh_material.tex_Ns = 75.0f;
1340 mesh_material.tex_illum = 2;
1342 std::stringstream tex_name;
1343 tex_name <<
"material_" << i;
1344 tex_name >> mesh_material.tex_name;
1346 mesh_material.tex_file =
uFormat(
"%d", i);
1348 textureMesh->tex_materials[i] = mesh_material;
1351 if(mergeTextures && textures.cols/textures.rows > 1)
1353 UASSERT(textures.cols % textures.rows == 0 && textures.cols/textures.rows == (
int)textureMesh->tex_coordinates.size());
1354 std::vector<bool> materialsKept;
1356 cv::Size imageSize(textures.rows, textures.rows);
1357 int imageType = textures.type();
1359 if(scale && textureMesh->tex_materials.size() == 1)
1361 int cols = float(textures.rows)/(scale*imageSize.width);
1362 int rows = float(textures.rows)/(scale*imageSize.height);
1364 cv::Mat mergedTextures = cv::Mat(textures.rows, textures.rows, imageType,
cv::Scalar::all(255));
1367 cv::Size resizedImageSize(
int(imageSize.width*scale),
int(imageSize.height*scale));
1369 for(
int i=0; i<(int)materialsKept.size(); ++i)
1371 if(materialsKept.at(i))
1373 int u = oi%cols * resizedImageSize.width;
1374 int v = ((oi/cols) % rows ) * resizedImageSize.height;
1375 UASSERT(u < textures.rows-resizedImageSize.width);
1376 UASSERT(v < textures.rows-resizedImageSize.height);
1378 cv::Mat resizedImage;
1379 cv::resize(textures(
cv::Range::all(), cv::Range(i*textures.rows, (i+1)*textures.rows)), resizedImage, resizedImageSize, 0.0f, 0.0f, cv::INTER_AREA);
1381 UASSERT(resizedImage.type() == mergedTextures.type());
1382 resizedImage.copyTo(mergedTextures(cv::Rect(u, v, resizedImage.cols, resizedImage.rows)));
1387 textures = mergedTextures;
1396 const cv::Mat & cloudMat,
1397 const std::vector<std::vector<RTABMAP_PCL_INDEX> > & polygons)
1399 pcl::PolygonMesh::Ptr polygonMesh(
new pcl::PolygonMesh);
1401 if(cloudMat.channels() <= 3)
1404 pcl::toPCLPointCloud2(*cloud, polygonMesh->cloud);
1406 else if(cloudMat.channels() == 4)
1409 pcl::toPCLPointCloud2(*cloud, polygonMesh->cloud);
1411 else if(cloudMat.channels() == 6)
1414 pcl::toPCLPointCloud2(*cloud, polygonMesh->cloud);
1416 else if(cloudMat.channels() == 7)
1419 pcl::toPCLPointCloud2(*cloud, polygonMesh->cloud);
1422 if(polygonMesh->cloud.data.size() && polygons.size())
1424 polygonMesh->polygons.resize(polygons.size());
1425 for(
unsigned int p=0; p<polygons.size(); ++p)
1427 polygonMesh->polygons[p].vertices = polygons[p];
1435 return double(v)*double(v);
1439 pcl::TextureMesh & mesh,
1440 const std::map<int, cv::Mat> & images,
1441 const std::map<int, CameraModel> & calibrations,
1446 const std::vector<std::map<int, pcl::PointXY> > & vertexToPixels,
1447 bool gainCompensation,
1451 int blendingDecimation,
1452 int brightnessContrastRatioLow,
1453 int brightnessContrastRatioHigh,
1456 unsigned char blankValue,
1457 std::map<
int, std::map<int, cv::Vec4d> > * gains,
1458 std::map<
int, std::map<int, cv::Mat> > * blendingGains,
1459 std::pair<float, float> * contrastValues)
1461 std::map<int, std::vector<CameraModel> > calibVectors;
1462 for(std::map<int, CameraModel>::const_iterator iter=calibrations.begin(); iter!=calibrations.end(); ++iter)
1464 std::vector<CameraModel> m;
1465 m.push_back(iter->second);
1466 calibVectors.insert(std::make_pair(iter->first, m));
1481 brightnessContrastRatioLow,
1482 brightnessContrastRatioHigh,
1491 pcl::TextureMesh & mesh,
1492 const std::map<int, cv::Mat> & images,
1493 const std::map<
int, std::vector<CameraModel> > & calibrations,
1498 const std::vector<std::map<int, pcl::PointXY> > & vertexToPixels,
1499 bool gainCompensation,
1503 int blendingDecimation,
1504 int brightnessContrastRatioLow,
1505 int brightnessContrastRatioHigh,
1508 unsigned char blankValue,
1509 std::map<
int, std::map<int, cv::Vec4d> > * gainsOut,
1510 std::map<
int, std::map<int, cv::Mat> > * blendingGainsOut,
1511 std::pair<float, float> * contrastValuesOut)
1514 UASSERT(textureSize%256 == 0);
1515 UDEBUG(
"textureSize = %d", textureSize);
1516 cv::Mat globalTextures;
1517 if(!mesh.tex_materials.empty())
1519 std::vector<std::pair<int, int> > textures(mesh.tex_materials.size(), std::pair<int, int>(-1,0));
1521 const int imageType=CV_8UC3;
1524 for(
unsigned int i=0; i<mesh.tex_materials.size(); ++i)
1526 std::list<std::string> texFileSplit =
uSplit(mesh.tex_materials[i].tex_file,
'_');
1527 if(!mesh.tex_materials[i].tex_file.empty() &&
1528 mesh.tex_polygons[i].size() &&
1531 textures[i].first =
uStr2Int(texFileSplit.front());
1532 if(texFileSplit.size() == 2 &&
1535 textures[i].second =
uStr2Int(texFileSplit.back());
1538 int textureId = textures[i].first;
1539 if(imageSize.width == 0 || imageSize.height == 0)
1541 if(images.find(textureId) != images.end() &&
1542 !images.find(textureId)->second.empty() &&
1543 calibrations.find(textureId) != calibrations.end())
1545 const std::vector<CameraModel> & models = calibrations.find(textureId)->second;
1547 if( models[0].imageHeight()>0 &&
1548 models[0].imageWidth()>0)
1550 imageSize = models[0].imageSize();
1552 else if(images.find(textureId)!=images.end())
1555 cv::Mat image = images.find(textureId)->second;
1556 if(image.rows == 1 && image.type() == CV_8UC1)
1561 imageSize = image.size();
1564 imageSize.width/=models.size();
1571 const std::vector<CameraModel> & models = data.
cameraModels();
1573 if(models.size()>=1 &&
1574 models[0].imageHeight()>0 &&
1575 models[0].imageWidth()>0)
1577 imageSize = models[0].imageSize();
1579 else if(stereoModels.size()>=1 &&
1580 stereoModels[0].left().imageHeight() > 0 &&
1581 stereoModels[0].left().imageWidth() > 0)
1583 imageSize = stereoModels[0].left().imageSize();
1590 imageSize = image.size();
1599 std::vector<CameraModel> models;
1600 std::vector<StereoCameraModel> stereoModels;
1602 if(models.size()>=1 &&
1603 models[0].imageHeight()>0 &&
1604 models[0].imageWidth()>0)
1606 imageSize = models[0].imageSize();
1608 else if(stereoModels.size()>=1 &&
1609 stereoModels[0].left().imageHeight() > 0 &&
1610 stereoModels[0].left().imageWidth() > 0)
1612 imageSize = stereoModels[0].left().imageSize();
1617 dbDriver->
getNodeData(textureId, data,
true,
false,
false,
false);
1621 imageSize = image.size();
1630 else if(mesh.tex_polygons[i].size() && mesh.tex_materials[i].tex_file.compare(
"occluded")!=0)
1632 UWARN(
"Failed parsing texture file name: %s", mesh.tex_materials[i].tex_file.c_str());
1635 UDEBUG(
"textures=%d imageSize=%dx%d", (
int)textures.size(), imageSize.height, imageSize.width);
1636 if(textures.size() && imageSize.height>0 && imageSize.width>0)
1640 std::vector<bool> materialsKept;
1642 if(scale && mesh.tex_materials.size())
1644 int materials = (int)mesh.tex_materials.size();
1645 int cols = float(textureSize)/(scale*imageSize.width);
1646 int rows = float(textureSize)/(scale*imageSize.height);
1648 globalTextures = cv::Mat(textureSize, materials*textureSize, imageType,
cv::Scalar::all(blankValue));
1649 cv::Mat globalTextureMasks = cv::Mat(textureSize, materials*textureSize, CV_8UC1,
cv::Scalar::all(0));
1652 cv::Mat previousImage;
1653 int previousTextureId = 0;
1654 std::vector<CameraModel> previousCameraModels;
1657 cv::Mat emptyImage(
int(imageSize.height*scale),
int(imageSize.width*scale), imageType,
cv::Scalar::all(blankValue));
1658 cv::Mat emptyImageMask(
int(imageSize.height*scale),
int(imageSize.width*scale), CV_8UC1,
cv::Scalar::all(255));
1660 std::vector<cv::Point2i> imageOrigin(textures.size());
1661 std::vector<int> newCamIndex(textures.size(), -1);
1662 for(
int t=0; t<(int)textures.size(); ++t)
1664 if(materialsKept.at(t))
1666 int indexMaterial = oi / (cols*rows);
1667 UASSERT(indexMaterial < materials);
1669 newCamIndex[t] = oi;
1670 int u = oi%cols * emptyImage.cols;
1671 int v = ((oi/cols) % rows ) * emptyImage.rows;
1672 UASSERT_MSG(u < textureSize-emptyImage.cols,
uFormat(
"u=%d textureSize=%d emptyImage.cols=%d", u, textureSize, emptyImage.cols).c_str());
1673 UASSERT_MSG(v < textureSize-emptyImage.rows,
uFormat(
"v=%d textureSize=%d emptyImage.rows=%d", v, textureSize, emptyImage.rows).c_str());
1674 imageOrigin[t].x = u;
1675 imageOrigin[t].y = v;
1676 if(textures[t].first>=0)
1679 std::vector<CameraModel> models;
1681 if(textures[t].first == previousTextureId)
1683 image = previousImage;
1684 models = previousCameraModels;
1688 if(images.find(textures[t].first) != images.end() &&
1689 !images.find(textures[t].first)->second.empty() &&
1690 calibrations.find(textures[t].first) != calibrations.end())
1692 image = images.find(textures[t].first)->second;
1693 if(image.rows == 1 && image.type() == CV_8UC1)
1697 models = calibrations.find(textures[t].first)->second;
1715 dbDriver->
getNodeData(textures[t].first, data,
true,
false,
false,
false);
1717 std::vector<StereoCameraModel> stereoModels;
1718 dbDriver->
getCalibration(textures[t].first, models, stereoModels);
1719 if(models.empty() && !stereoModels.empty())
1721 for(
size_t i=0; i<stereoModels.size(); ++i)
1723 models.push_back(stereoModels[i].left());
1728 previousImage = image;
1729 previousCameraModels = models;
1730 previousTextureId = textures[t].first;
1735 if(textures[t].second>=0)
1737 UASSERT(textures[t].second < (
int)models.size());
1738 int width = image.cols/models.size();
1739 image = image.colRange(width*textures[t].second, width*(textures[t].second+1));
1742 cv::Mat resizedImage;
1743 cv::resize(image, resizedImage, emptyImage.size(), 0.0f, 0.0f, cv::INTER_AREA);
1744 UASSERT(resizedImage.type() == CV_8UC1 || resizedImage.type() == CV_8UC3);
1745 if(resizedImage.type() == CV_8UC1)
1747 cv::Mat resizedImageColor;
1748 cv::cvtColor(resizedImage, resizedImageColor, CV_GRAY2BGR);
1749 resizedImage = resizedImageColor;
1751 UASSERT(resizedImage.type() == globalTextures.type());
1752 resizedImage.copyTo(globalTextures(cv::Rect(u+indexMaterial*globalTextures.rows, v, resizedImage.cols, resizedImage.rows)));
1753 emptyImageMask.copyTo(globalTextureMasks(cv::Rect(u+indexMaterial*globalTextureMasks.rows, v, resizedImage.cols, resizedImage.rows)));
1757 emptyImage.copyTo(globalTextures(cv::Rect(u+indexMaterial*globalTextures.rows, v, emptyImage.cols, emptyImage.rows)));
1768 state->
callback(
uFormat(
"Assembled texture %d/%d.", t+1, (
int)textures.size()));
1773 if(vertexToPixels.size())
1778 if(gainCompensation)
1784 const int num_images =
static_cast<int>(oi);
1785 cv::Mat_<int> N(num_images, num_images); N.setTo(0);
1786 cv::Mat_<double> I(num_images, num_images); I.setTo(0);
1788 cv::Mat_<double> IR(num_images, num_images); IR.setTo(0);
1789 cv::Mat_<double> IG(num_images, num_images); IG.setTo(0);
1790 cv::Mat_<double> IB(num_images, num_images); IB.setTo(0);
1793 for(
unsigned int p=0; p<vertexToPixels.size(); ++p)
1795 for(std::map<int, pcl::PointXY>::const_iterator iter=vertexToPixels[p].begin(); iter!=vertexToPixels[p].end(); ++iter)
1797 if(materialsKept.at(iter->first))
1799 N(newCamIndex[iter->first], newCamIndex[iter->first]) +=1;
1801 std::map<int, pcl::PointXY>::const_iterator jter=iter;
1804 for(; jter!=vertexToPixels[p].end(); ++jter, ++k)
1806 if(materialsKept.at(jter->first))
1808 int i = newCamIndex[iter->first];
1809 int j = newCamIndex[jter->first];
1814 int indexMaterial = i / (cols*rows);
1817 int ui = iter->second.x*emptyImage.cols + imageOrigin[iter->first].x;
1818 int vi = (1.0-iter->second.y)*emptyImage.rows + imageOrigin[iter->first].y;
1819 int uj = jter->second.x*emptyImage.cols + imageOrigin[jter->first].x;
1820 int vj = (1.0-jter->second.y)*emptyImage.rows + imageOrigin[jter->first].y;
1821 cv::Vec3b * pt1 = globalTextures.ptr<cv::Vec3b>(vi,ui+indexMaterial*globalTextures.rows);
1822 cv::Vec3b * pt2 = globalTextures.ptr<cv::Vec3b>(vj,uj+indexMaterial*globalTextures.rows);
1824 I(i, j) +=
std::sqrt(static_cast<double>(
sqr(pt1->val[0]) +
sqr(pt1->val[1]) +
sqr(pt1->val[2])));
1825 I(j, i) +=
std::sqrt(static_cast<double>(
sqr(pt2->val[0]) +
sqr(pt2->val[1]) +
sqr(pt2->val[2])));
1827 IR(i, j) +=
static_cast<double>(pt1->val[2]);
1828 IR(j, i) +=
static_cast<double>(pt2->val[2]);
1829 IG(i, j) +=
static_cast<double>(pt1->val[1]);
1830 IG(j, i) +=
static_cast<double>(pt2->val[1]);
1831 IB(i, j) +=
static_cast<double>(pt1->val[0]);
1832 IB(j, i) +=
static_cast<double>(pt2->val[0]);
1839 for(
int i=0; i<num_images; ++i)
1841 for(
int j=i; j<num_images; ++j)
1855 IR(i, j) /= N(i, j);
1856 IR(j, i) /= N(j, i);
1857 IG(i, j) /= N(i, j);
1858 IG(j, i) /= N(j, i);
1859 IB(i, j) /= N(i, j);
1860 IB(j, i) /= N(j, i);
1865 cv::Mat_<double> A(num_images, num_images); A.setTo(0);
1866 cv::Mat_<double> b(num_images, 1); b.setTo(0);
1867 cv::Mat_<double> AR(num_images, num_images); AR.setTo(0);
1868 cv::Mat_<double> AG(num_images, num_images); AG.setTo(0);
1869 cv::Mat_<double> AB(num_images, num_images); AB.setTo(0);
1870 double alpha = 0.01;
1871 double beta = gainBeta;
1872 for (
int i = 0; i < num_images; ++i)
1874 for (
int j = 0; j < num_images; ++j)
1876 b(i, 0) += beta * N(i, j);
1877 A(i, i) += beta * N(i, j);
1878 AR(i, i) += beta * N(i, j);
1879 AG(i, i) += beta * N(i, j);
1880 AB(i, i) += beta * N(i, j);
1881 if (j == i)
continue;
1882 A(i, i) += 2 * alpha * I(i, j) * I(i, j) * N(i, j);
1883 A(i, j) -= 2 * alpha * I(i, j) * I(j, i) * N(i, j);
1885 AR(i, i) += 2 * alpha * IR(i, j) * IR(i, j) * N(i, j);
1886 AR(i, j) -= 2 * alpha * IR(i, j) * IR(j, i) * N(i, j);
1888 AG(i, i) += 2 * alpha * IG(i, j) * IG(i, j) * N(i, j);
1889 AG(i, j) -= 2 * alpha * IG(i, j) * IG(j, i) * N(i, j);
1891 AB(i, i) += 2 * alpha * IB(i, j) * IB(i, j) * N(i, j);
1892 AB(i, j) -= 2 * alpha * IB(i, j) * IB(j, i) * N(i, j);
1896 cv::Mat_<double> gainsGray, gainsR, gainsG, gainsB;
1897 cv::solve(A, b, gainsGray);
1899 cv::solve(AR, b, gainsR);
1900 cv::solve(AG, b, gainsG);
1901 cv::solve(AB, b, gainsB);
1903 cv::Mat_<double> gains(gainsGray.rows, 4);
1904 gainsGray.copyTo(gains.col(0));
1905 gainsR.copyTo(gains.col(1));
1906 gainsG.copyTo(gains.col(2));
1907 gainsB.copyTo(gains.col(3));
1909 for(
int t=0; t<(int)textures.size(); ++t)
1912 if(materialsKept.at(t))
1914 int u = imageOrigin[t].x;
1915 int v = imageOrigin[t].y;
1917 UDEBUG(
"Gain cam%d = %f", newCamIndex[t], gainsGray(newCamIndex[t], 0));
1919 int indexMaterial = newCamIndex[t] / (cols*rows);
1920 cv::Mat roi = globalTextures(cv::Rect(u+indexMaterial*globalTextures.rows, v, emptyImage.cols, emptyImage.rows));
1922 std::vector<cv::Mat> channels;
1923 cv::split(roi, channels);
1926 cv::multiply(channels[0], gains(newCamIndex[t], gainRGB?3:0), channels[0]);
1927 cv::multiply(channels[1], gains(newCamIndex[t], gainRGB?2:0), channels[1]);
1928 cv::multiply(channels[2], gains(newCamIndex[t], gainRGB?1:0), channels[2]);
1930 cv::merge(channels, roi);
1935 gains(newCamIndex[t], 0),
1936 gains(newCamIndex[t], 1),
1937 gains(newCamIndex[t], 2),
1938 gains(newCamIndex[t], 3));
1939 if(gainsOut->find(textures[t].first) == gainsOut->end())
1941 std::map<int,cv::Vec4d> value;
1942 value.insert(std::make_pair(textures[t].second, g));
1943 gainsOut->insert(std::make_pair(textures[t].first, value));
1947 gainsOut->at(textures[t].first).insert(std::make_pair(textures[t].second, g));
1961 if(blendingDecimation <= 0)
1964 std::vector<float> edgeLengths;
1965 if(mesh.tex_coordinates.size() && mesh.tex_coordinates[0].size())
1967 UASSERT(mesh.tex_polygons.size() && mesh.tex_polygons[0].size() && mesh.tex_polygons[0][0].vertices.size());
1968 int polygonSize = mesh.tex_polygons[0][0].vertices.size();
1969 UDEBUG(
"polygon size=%d", polygonSize);
1971 for(
unsigned int k=0; k<mesh.tex_coordinates.size(); ++k)
1973 for(
unsigned int i=0; i<mesh.tex_coordinates[k].size(); i+=polygonSize)
1975 for(
int j=0; j<polygonSize; ++j)
1977 const Eigen::Vector2f & uc1 = mesh.tex_coordinates[k][i + j];
1978 const Eigen::Vector2f & uc2 = mesh.tex_coordinates[k][i + (j+1)%polygonSize];
1979 Eigen::Vector2f edge = (uc1-uc2)*textureSize;
1980 edgeLengths.push_back(fabs(edge[0]));
1981 edgeLengths.push_back(fabs(edge[1]));
1985 float edgeLength = 0.0f;
1986 if(edgeLengths.size())
1988 std::sort(edgeLengths.begin(), edgeLengths.end());
1989 float m =
uMean(edgeLengths.data(), edgeLengths.size());
1991 edgeLength = m+stddev;
1992 decimation = 1 << 6;
1993 for(
int i=1; i<=6; ++i)
1995 if(
float(1 << i) >= edgeLength)
1997 decimation = 1 << i;
2003 UDEBUG(
"edge length=%f decimation=%d", edgeLength, decimation);
2008 if(blendingDecimation > 1)
2010 UASSERT(textureSize % blendingDecimation == 0);
2012 decimation = blendingDecimation;
2013 UDEBUG(
"decimation=%d", decimation);
2016 std::vector<cv::Mat> blendGains(materials);
2017 for(
int i=0; i<materials;++i)
2019 blendGains[i] = cv::Mat(globalTextures.rows/decimation, globalTextures.rows/decimation, CV_32FC3,
cv::Scalar::all(1.0f));
2022 for(
unsigned int p=0; p<vertexToPixels.size(); ++p)
2024 if(vertexToPixels[p].size() > 1)
2026 std::vector<float> gainsB(vertexToPixels[p].size());
2027 std::vector<float> gainsG(vertexToPixels[p].size());
2028 std::vector<float> gainsR(vertexToPixels[p].size());
2029 float sumWeight = 0.0f;
2031 for(std::map<int, pcl::PointXY>::const_iterator iter=vertexToPixels[p].begin(); iter!=vertexToPixels[p].end(); ++iter)
2033 if(materialsKept.at(iter->first))
2035 int u = iter->second.x*emptyImage.cols + imageOrigin[iter->first].x;
2036 int v = (1.0-iter->second.y)*emptyImage.rows + imageOrigin[iter->first].y;
2037 float x = iter->second.x - 0.5f;
2038 float y = iter->second.y - 0.5f;
2039 float weight = 0.7f -
sqrt(
x*
x+y*y);
2044 int indexMaterial = newCamIndex[iter->first] / (cols*rows);
2045 cv::Vec3b * pt = globalTextures.ptr<cv::Vec3b>(v,u+indexMaterial*globalTextures.rows);
2046 gainsB[k] =
static_cast<double>(pt->val[0]) * weight;
2047 gainsG[k] =
static_cast<double>(pt->val[1]) * weight;
2048 gainsR[k] =
static_cast<double>(pt->val[2]) * weight;
2049 sumWeight += weight;
2059 float targetColor[3];
2060 targetColor[0] =
uSum(gainsB.data(), gainsB.size()) / sumWeight;
2061 targetColor[1] =
uSum(gainsG.data(), gainsG.size()) / sumWeight;
2062 targetColor[2] =
uSum(gainsR.data(), gainsR.size()) / sumWeight;
2063 for(std::map<int, pcl::PointXY>::const_iterator iter=vertexToPixels[p].begin(); iter!=vertexToPixels[p].end(); ++iter)
2065 if(materialsKept.at(iter->first))
2067 int u = iter->second.x*emptyImage.cols + imageOrigin[iter->first].x;
2068 int v = (1.0-iter->second.y)*emptyImage.rows + imageOrigin[iter->first].y;
2069 int indexMaterial = newCamIndex[iter->first] / (cols*rows);
2070 cv::Vec3b * pt = globalTextures.ptr<cv::Vec3b>(v,u+indexMaterial*globalTextures.rows);
2071 float gB = targetColor[0]/(pt->val[0]==0?1.0f:pt->val[0]);
2072 float gG = targetColor[1]/(pt->val[1]==0?1.0f:pt->val[1]);
2073 float gR = targetColor[2]/(pt->val[2]==0?1.0f:pt->val[2]);
2074 cv::Vec3f * ptr = blendGains[indexMaterial].ptr<cv::Vec3f>(v/decimation, u/decimation);
2075 ptr->val[0] = (gB>1.3f)?1.3
f:(gB<0.7
f)?0.7f:gB;
2076 ptr->val[1] = (gG>1.3f)?1.3
f:(gG<0.7
f)?0.7f:gG;
2077 ptr->val[2] = (gR>1.3f)?1.3
f:(gR<0.7
f)?0.7f:gR;
2084 if(blendingGainsOut)
2086 for(
int t=0; t<(int)textures.size(); ++t)
2089 if(materialsKept.at(t))
2091 int u = imageOrigin[t].x/decimation;
2092 int v = imageOrigin[t].y/decimation;
2094 int indexMaterial = newCamIndex[t] / (cols*rows);
2095 cv::Mat roi = blendGains[indexMaterial](cv::Rect(u, v, emptyImage.cols/decimation, emptyImage.rows/decimation));
2096 if(blendingGainsOut->find(textures[t].first) == blendingGainsOut->end())
2098 std::map<int,cv::Mat> value;
2099 value.insert(std::make_pair(textures[t].second, roi.clone()));
2100 blendingGainsOut->insert(std::make_pair(textures[t].first, value));
2104 blendingGainsOut->at(textures[t].first).insert(std::make_pair(textures[t].second, roi.clone()));
2110 for(
int i=0; i<materials; ++i)
2122 cv::Mat globalTexturesROI = globalTextures(
cv::Range::all(), cv::Range(i*globalTextures.rows, (i+1)*globalTextures.rows));
2124 cv::blur(blendGains[i], dst, cv::Size(3,3));
2125 cv::resize(dst, blendGains[i], globalTexturesROI.size(), 0, 0, cv::INTER_LINEAR);
2135 cv::multiply(globalTexturesROI, blendGains[i], globalTexturesROI, 1.0, CV_8UC3);
2145 if(brightnessContrastRatioLow > 0 || brightnessContrastRatioHigh > 0)
2149 std::vector<cv::Mat> images;
2150 images.push_back(globalTextures);
2151 if (brightnessContrastRatioLow > 0)
2156 (
float)brightnessContrastRatioLow,
2159 if (brightnessContrastRatioHigh > 0)
2165 (
float)brightnessContrastRatioHigh));
2176 (
float)brightnessContrastRatioLow,
2177 (
float)brightnessContrastRatioHigh,
2180 if(contrastValuesOut)
2182 contrastValuesOut->first = alpha;
2183 contrastValuesOut->second = beta;
2191 UDEBUG(
"globalTextures=%d", globalTextures.cols?globalTextures.cols / globalTextures.rows:0);
2192 return globalTextures;
2201 for (
unsigned int t = 0; t < textureMesh.tex_coordinates.size(); ++t)
2203 if(textureMesh.tex_polygons[t].size())
2205 pcl::PointCloud<pcl::PointXYZ>::Ptr originalCloud(
new pcl::PointCloud<pcl::PointXYZ>);
2206 pcl::fromPCLPointCloud2(textureMesh.cloud, *originalCloud);
2209 unsigned int nPoints = textureMesh.tex_coordinates[t].size();
2210 UASSERT(nPoints == textureMesh.tex_polygons[t].size()*textureMesh.tex_polygons[t][0].vertices.size());
2212 pcl::PointCloud<pcl::PointXYZ>::Ptr newCloud(
new pcl::PointCloud<pcl::PointXYZ>);
2213 newCloud->resize(nPoints);
2215 unsigned int oi = 0;
2216 for (
unsigned int i = 0; i < textureMesh.tex_polygons[t].size(); ++i)
2218 pcl::Vertices &
vertices = textureMesh.tex_polygons[t][i];
2220 for(
unsigned int j=0; j<vertices.vertices.size(); ++j)
2222 UASSERT(oi < newCloud->size());
2223 UASSERT_MSG((
size_t)vertices.vertices[j] < originalCloud->size(),
uFormat(
"%d vs %d", vertices.vertices[j], (
int)originalCloud->size()).c_str());
2224 newCloud->at(oi) = originalCloud->at(vertices.vertices[j]);
2225 vertices.vertices[j] = oi;
2229 pcl::toPCLPointCloud2(*newCloud, textureMesh.cloud);
2235 const std::string & outputOBJPath,
2236 const pcl::PCLPointCloud2 & cloud,
2237 const std::vector<pcl::Vertices> & polygons,
2238 const std::map<int, Transform> & cameraPoses,
2239 const std::vector<std::map<int, pcl::PointXY> > & vertexToPixels,
2240 const std::map<int, cv::Mat> & images,
2241 const std::map<
int, std::vector<CameraModel> > & cameraModels,
2245 const std::string & textureFormat,
2246 const std::map<
int, std::map<int, cv::Vec4d> > & gains,
2247 const std::map<
int, std::map<int, cv::Mat> > & blendingGains,
2248 const std::pair<float, float> & contrastValues,
2272 const std::string & outputOBJPath,
2273 const pcl::PCLPointCloud2 & cloud,
2274 const std::vector<pcl::Vertices> & polygons,
2275 const std::map<int, Transform> & cameraPoses,
2276 const std::vector<std::map<int, pcl::PointXY> > & vertexToPixels,
2277 const std::map<int, cv::Mat> & images,
2278 const std::map<
int, std::vector<CameraModel> > & cameraModels,
2281 unsigned int textureSize,
2282 unsigned int textureDownScale,
2283 const std::string & nbContrib,
2284 const std::string & textureFormat,
2285 const std::map<
int, std::map<int, cv::Vec4d> > & gains,
2286 const std::map<
int, std::map<int, cv::Mat> > & blendingGains,
2287 const std::pair<float, float> & contrastValues,
2289 unsigned int unwrapMethod,
2291 unsigned int padding,
2292 double bestScoreThreshold,
2293 double angleHardThreshold,
2294 bool forceVisibleByAllVertices)
2297 #ifdef RTABMAP_ALICE_VISION 2300 system::Logger::get()->setLogLevel(system::EVerboseLevel::Trace);
2304 system::Logger::get()->setLogLevel(system::EVerboseLevel::Info);
2308 system::Logger::get()->setLogLevel(system::EVerboseLevel::Warning);
2312 system::Logger::get()->setLogLevel(system::EVerboseLevel::Error);
2315 sfmData::SfMData sfmData;
2316 pcl::PointCloud<pcl::PointXYZRGB> cloud2;
2317 pcl::fromPCLPointCloud2(cloud, cloud2);
2318 UASSERT(vertexToPixels.size() == cloud2.size());
2319 UINFO(
"Input mesh: %d points %d polygons", (
int)cloud2.size(), (int)polygons.size());
2320 mesh::Texturing texturing;
2321 #if RTABMAP_ALICE_VISION_MAJOR > 2 || (RTABMAP_ALICE_VISION_MAJOR==2 && RTABMAP_ALICE_VISION_MINOR>=3) 2322 texturing.mesh =
new mesh::Mesh();
2323 texturing.mesh->pts.resize(cloud2.size());
2324 texturing.mesh->pointsVisibilities.resize(cloud2.size());
2326 texturing.me =
new mesh::Mesh();
2327 texturing.me->pts =
new StaticVector<Point3d>(cloud2.size());
2328 texturing.pointsVisibilities =
new mesh::PointsVisibility();
2329 texturing.pointsVisibilities->reserve(cloud2.size());
2331 texturing.texParams.textureSide = textureSize;
2332 texturing.texParams.downscale = textureDownScale;
2333 std::vector<int> multiBandNbContrib;
2334 std::list<std::string> values =
uSplit(nbContrib,
' ');
2335 for(std::list<std::string>::iterator iter=values.begin(); iter!=values.end(); ++iter)
2337 multiBandNbContrib.push_back(
uStr2Int(*iter));
2339 if(multiBandNbContrib.size() != 4)
2341 UERROR(
"multiband: Wrong number of nb of contribution (vaue=\"%s\", should be 4), using default values instead.", nbContrib.c_str());
2345 texturing.texParams.multiBandNbContrib = multiBandNbContrib;
2347 texturing.texParams.padding = padding;
2348 texturing.texParams.fillHoles = fillHoles;
2349 texturing.texParams.bestScoreThreshold = bestScoreThreshold;
2350 texturing.texParams.angleHardThreshold = angleHardThreshold;
2351 texturing.texParams.forceVisibleByAllVertices = forceVisibleByAllVertices;
2352 texturing.texParams.visibilityRemappingMethod = mesh::EVisibilityRemappingMethod::Pull;
2355 for(
size_t i=0;i<cloud2.size();++i)
2357 pcl::PointXYZRGB pt = cloud2.at(i);
2358 #if RTABMAP_ALICE_VISION_MAJOR > 2 || (RTABMAP_ALICE_VISION_MAJOR==2 && RTABMAP_ALICE_VISION_MINOR>=3) 2359 texturing.mesh->pointsVisibilities[i].reserve(vertexToPixels[i].size());
2360 for(std::map<int, pcl::PointXY>::const_iterator iter=vertexToPixels[i].begin(); iter!=vertexToPixels[i].end();++iter)
2362 texturing.mesh->pointsVisibilities[i].push_back(iter->first);
2364 texturing.mesh->pts[i] = Point3d(pt.x, pt.y, pt.z);
2366 mesh::PointVisibility* pointVisibility =
new mesh::PointVisibility();
2367 pointVisibility->reserve(vertexToPixels[i].size());
2368 for(std::map<int, pcl::PointXY>::const_iterator iter=vertexToPixels[i].begin(); iter!=vertexToPixels[i].end();++iter)
2370 pointVisibility->push_back(iter->first);
2372 texturing.pointsVisibilities->push_back(pointVisibility);
2373 (*texturing.me->pts)[i] = Point3d(pt.x, pt.y, pt.z);
2377 #if RTABMAP_ALICE_VISION_MAJOR > 2 || (RTABMAP_ALICE_VISION_MAJOR==2 && RTABMAP_ALICE_VISION_MINOR>=3) 2378 texturing.mesh->tris.resize(polygons.size());
2379 texturing.mesh->trisMtlIds().resize(polygons.size());
2381 texturing.me->tris =
new StaticVector<mesh::Mesh::triangle>(polygons.size());
2383 for(
size_t i=0;i<polygons.size();++i)
2386 #if RTABMAP_ALICE_VISION_MAJOR > 2 || (RTABMAP_ALICE_VISION_MAJOR==2 && RTABMAP_ALICE_VISION_MINOR>=3) 2387 texturing.mesh->trisMtlIds()[i] = -1;
2388 texturing.mesh->tris[i] = mesh::Mesh::triangle(
2390 (*texturing.me->tris)[i] = mesh::Mesh::triangle(
2392 polygons[i].vertices[0],
2393 polygons[i].vertices[1],
2394 polygons[i].vertices[2]);
2398 std::string tmpImageDirectory = outputDirectory+
"/rtabmap_tmp_textures";
2401 UINFO(
"Temporary saving images in directory \"%s\"...", tmpImageDirectory.c_str());
2403 for(std::map<int, Transform>::const_iterator iter = cameraPoses.lower_bound(1); iter!=cameraPoses.end(); ++iter)
2405 int camId = iter->first;
2407 std::vector<CameraModel> models;
2409 if( images.find(camId) != images.end() &&
2410 !images.find(camId)->second.empty() &&
2411 cameraModels.find(camId) != cameraModels.end())
2413 image = images.find(camId)->second;
2414 models = cameraModels.find(camId)->second;
2436 if(models.empty() || image.empty())
2444 std::vector<float> vel;
2447 memory->
getNodeInfo(camId, odomPose, mapId, weight, label, stamp, gt, vel, gps, envs,
true);
2454 std::vector<StereoCameraModel> stereoModels;
2456 if(models.empty() && stereoModels.size())
2458 for(
size_t i=0; i<stereoModels.size(); ++i)
2460 models.push_back(stereoModels[i].left());
2465 dbDriver->
getNodeData(camId, data,
true,
false,
false,
false);
2475 if(models.empty() || image.empty())
2485 UERROR(
"No camera models found for camera %d. Aborting multiband texturing...", iter->first);
2490 UERROR(
"No image found for camera %d. Aborting multiband texturing...", iter->first);
2494 if(image.rows == 1 && image.type() == CV_8UC1)
2500 image = image.clone();
2503 for(
size_t i=0; i<models.size(); ++i)
2507 if(imageSize.height == 0)
2510 imageSize.height = image.rows;
2511 imageSize.width = image.cols;
2513 UASSERT(image.cols % imageSize.width == 0);
2514 cv::Mat imageRoi = image.colRange(i*imageSize.width, (i+1)*imageSize.width);
2515 if(gains.find(camId) != gains.end() &&
2516 gains.at(camId).find(i) != gains.at(camId).end())
2518 const cv::Vec4d & g = gains.at(camId).at(i);
2519 std::vector<cv::Mat> channels;
2520 cv::split(imageRoi, channels);
2523 cv::multiply(channels[0], g.val[gainRGB?3:0], channels[0]);
2524 cv::multiply(channels[1], g.val[gainRGB?2:0], channels[1]);
2525 cv::multiply(channels[2], g.val[gainRGB?1:0], channels[2]);
2528 cv::merge(channels, output);
2532 if(blendingGains.find(camId) != blendingGains.end() &&
2533 blendingGains.at(camId).find(i) != blendingGains.at(camId).end())
2535 cv::Mat g = blendingGains.at(camId).at(i);
2537 cv::blur(g, dst, cv::Size(3,3));
2539 cv::resize(dst, gResized, imageRoi.size(), 0, 0, cv::INTER_LINEAR);
2541 cv::multiply(imageRoi, gResized, output, 1.0, CV_8UC3);
2546 Eigen::Matrix<double, 3, 4> m = t.
toEigen3d().matrix().block<3,4>(0, 0);
2547 sfmData::CameraPose pose(geometry::Pose3(m),
true);
2548 sfmData.setAbsolutePose((IndexT)viewId, pose);
2550 UDEBUG(
"%d %d %f %f %f %f", imageSize.width, imageSize.height, model.
fx(), model.
fy(), model.
cx(), model.
cy());
2551 std::shared_ptr<camera::IntrinsicBase> camPtr = std::make_shared<camera::Pinhole>(
2552 #if RTABMAP_ALICE_VISION_MAJOR > 2 || (RTABMAP_ALICE_VISION_MAJOR==2 && RTABMAP_ALICE_VISION_MINOR>=4) 2555 imageSize.width, imageSize.height, model.
fx(), model.
fy(), model.
cx() - double(imageSize.width) * 0.5, model.
cy() - double(imageSize.height) * 0.5);
2557 imageSize.width, imageSize.height, model.
fx(), model.
cx(), model.
cy());
2559 sfmData.intrinsics.insert(std::make_pair((IndexT)viewId, camPtr));
2561 std::string imagePath = tmpImageDirectory+
uFormat(
"/%d.jpg", viewId);
2563 cv::imwrite(imagePath, imageRoi);
2565 std::shared_ptr<sfmData::View> viewPtr = std::make_shared<sfmData::View>(
2572 sfmData.views.insert(std::make_pair((IndexT)viewId, viewPtr));
2576 UINFO(
"Temporary saving images in directory \"%s\"... done (%d images). %fs", tmpImageDirectory.c_str(), viewId, (int)cameraPoses.size(), timer.
ticks());
2578 mvsUtils::MultiViewParams mp(sfmData);
2580 UINFO(
"Unwrapping (method=%d=%s)...", unwrapMethod, mesh::EUnwrapMethod_enumToString((mesh::EUnwrapMethod)unwrapMethod).c_str());
2581 texturing.unwrap(mp, (mesh::EUnwrapMethod)unwrapMethod);
2582 UINFO(
"Unwrapping done. %fs", timer.
ticks());
2586 #if RTABMAP_ALICE_VISION_MAJOR > 2 || (RTABMAP_ALICE_VISION_MAJOR==2 && RTABMAP_ALICE_VISION_MINOR>=4) 2587 texturing.saveAs(outputDirectory, baseName, aliceVision::mesh::EFileType::OBJ, imageIO::EImageFileType::PNG);
2589 texturing.saveAsOBJ(outputDirectory, baseName);
2591 UINFO(
"Saved %s. %fs", outputOBJPath.c_str(), timer.
ticks());
2594 UINFO(
"Generating textures...");
2595 texturing.generateTextures(mp, outputDirectory);
2596 UINFO(
"Generating textures done. %fs", timer.
ticks());
2598 UINFO(
"Cleanup temporary directory \"%s\"...", tmpImageDirectory.c_str());
2600 std::string fp = dir.getNextFilePath();
2604 fp = dir.getNextFilePath();
2607 UINFO(
"Cleanup temporary directory \"%s\"... done.", tmpImageDirectory.c_str());
2609 UINFO(
"Rename/convert textures...");
2610 dir.setPath(outputDirectory,
"png");
2611 std::map<std::string, std::string> texNames;
2612 std::string outputFormat = textureFormat;
2613 if(outputFormat.front() ==
'.')
2615 outputFormat = outputFormat.substr(1, std::string::npos);
2617 for(std::list<std::string>::const_iterator iter=dir.getFileNames().begin(); iter!=dir.getFileNames().end(); ++iter)
2622 cv::Mat img = cv::imread(outputDirectory+
"/"+*iter);
2623 if(contrastValues.first != 0.0f || contrastValues.second != 0.0f)
2627 UINFO(
"Apply contrast values %f %f", contrastValues.first, contrastValues.second);
2628 img.convertTo(img, -1, contrastValues.first, contrastValues.second);
2630 std::string newName = *iter;
2631 boost::replace_all(newName,
"png", outputFormat);
2632 boost::replace_all(newName,
"texture", baseName);
2633 texNames.insert(std::make_pair(*iter, newName));
2634 cv::imwrite(outputDirectory+
"/"+newName, img);
2638 std::ifstream fi(outputDirectory+
"/"+baseName+
".mtl");
2639 std::string mtlStr((std::istreambuf_iterator<char>(fi)),
2640 std::istreambuf_iterator<char>());
2643 for(std::map<std::string, std::string>::iterator iter=texNames.begin(); iter!=texNames.end(); ++iter)
2645 boost::replace_all(mtlStr, iter->first, iter->second);
2647 std::ofstream fo(outputDirectory+
"/"+baseName+
".mtl");
2648 fo.write(mtlStr.c_str(), mtlStr.size());
2650 UINFO(
"Rename/convert textures... done. %fs", timer.
ticks());
2652 #if RTABMAP_ALICE_VISION_MAJOR > 2 || (RTABMAP_ALICE_VISION_MAJOR==2 && RTABMAP_ALICE_VISION_MINOR>=3) 2653 UINFO(
"Cleanup sfmdata...");
2655 UINFO(
"Cleanup sfmdata... done. %fs", timer.
ticks());
2660 UERROR(
"Cannot unwrap texture mesh. RTAB-Map is not built with Alice Vision support! Returning false.");
2675 pcl::PointCloud<pcl::Normal>::Ptr normals;
2692 if(laserScan.
is2d())
2717 if(laserScan.
is2d())
2739 template<
typename Po
intT>
2741 const typename pcl::PointCloud<PointT>::Ptr & cloud,
2742 const pcl::IndicesPtr & indices,
2745 const Eigen::Vector3f & viewPoint)
2747 typename pcl::search::KdTree<PointT>::Ptr
tree (
new pcl::search::KdTree<PointT>);
2750 tree->setInputCloud(cloud, indices);
2754 tree->setInputCloud (cloud);
2759 pcl::NormalEstimationOMP<PointT, pcl::Normal> n;
2761 pcl::NormalEstimation<PointT, pcl::Normal> n;
2763 pcl::PointCloud<pcl::Normal>::Ptr normals (
new pcl::PointCloud<pcl::Normal>);
2764 n.setInputCloud (cloud);
2770 n.setSearchMethod (tree);
2771 n.setKSearch (searchK);
2772 n.setRadiusSearch (searchRadius);
2773 n.setViewPoint(viewPoint[0], viewPoint[1], viewPoint[2]);
2774 n.compute (*normals);
2779 const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
2782 const Eigen::Vector3f & viewPoint)
2784 pcl::IndicesPtr indices(
new std::vector<int>);
2785 return computeNormals(cloud, indices, searchK, searchRadius, viewPoint);
2788 const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
2791 const Eigen::Vector3f & viewPoint)
2793 pcl::IndicesPtr indices(
new std::vector<int>);
2794 return computeNormals(cloud, indices, searchK, searchRadius, viewPoint);
2797 const pcl::PointCloud<pcl::PointXYZI>::Ptr & cloud,
2800 const Eigen::Vector3f & viewPoint)
2802 pcl::IndicesPtr indices(
new std::vector<int>);
2803 return computeNormals(cloud, indices, searchK, searchRadius, viewPoint);
2806 const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
2807 const pcl::IndicesPtr & indices,
2810 const Eigen::Vector3f & viewPoint)
2812 return computeNormalsImpl<pcl::PointXYZ>(cloud, indices, searchK, searchRadius, viewPoint);
2815 const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
2816 const pcl::IndicesPtr & indices,
2819 const Eigen::Vector3f & viewPoint)
2821 return computeNormalsImpl<pcl::PointXYZRGB>(cloud, indices, searchK, searchRadius, viewPoint);
2824 const pcl::PointCloud<pcl::PointXYZI>::Ptr & cloud,
2825 const pcl::IndicesPtr & indices,
2828 const Eigen::Vector3f & viewPoint)
2830 return computeNormalsImpl<pcl::PointXYZI>(cloud, indices, searchK, searchRadius, viewPoint);
2833 template<
typename Po
intT>
2835 const typename pcl::PointCloud<PointT>::Ptr & cloud,
2838 const Eigen::Vector3f & viewPoint)
2840 UASSERT(searchK>0 || searchRadius>0.0
f);
2841 pcl::PointCloud<pcl::Normal>::Ptr normals (
new pcl::PointCloud<pcl::Normal>);
2843 typename pcl::search::KdTree<PointT>::Ptr
tree (
new pcl::search::KdTree<PointT>);
2844 tree->setInputCloud (cloud);
2846 normals->resize(cloud->size());
2848 float bad_point = std::numeric_limits<float>::quiet_NaN ();
2851 for(
unsigned int i=0; i<cloud->size(); ++i)
2853 const PointT & pt = cloud->at(i);
2854 std::vector<Eigen::Vector3f> neighborNormals;
2855 Eigen::Vector3f direction;
2856 direction[0] = viewPoint[0] - pt.x;
2857 direction[1] = viewPoint[1] - pt.y;
2858 direction[2] = viewPoint[2] - pt.z;
2860 std::vector<int> k_indices;
2861 std::vector<float> k_sqr_distances;
2862 if(searchRadius>0.0
f)
2864 tree->radiusSearch(cloud->at(i), searchRadius, k_indices, k_sqr_distances, searchK);
2868 tree->nearestKSearch(cloud->at(i), searchK, k_indices, k_sqr_distances);
2871 for(
unsigned int j=0; j<k_indices.size(); ++j)
2873 if(k_indices.at(j) != (int)i)
2875 const PointT & pt2 = cloud->at(k_indices.at(j));
2876 Eigen::Vector3f v(pt2.x-pt.x, pt2.y - pt.y, pt2.z - pt.z);
2877 Eigen::Vector3f up = v.cross(direction);
2878 Eigen::Vector3f n = up.cross(v);
2880 neighborNormals.push_back(n);
2884 if(neighborNormals.empty())
2886 normals->at(i).normal_x = bad_point;
2887 normals->at(i).normal_y = bad_point;
2888 normals->at(i).normal_z = bad_point;
2892 Eigen::Vector3f meanNormal(0,0,0);
2893 for(
unsigned int j=0; j<neighborNormals.size(); ++j)
2895 meanNormal+=neighborNormals[j];
2897 meanNormal /= (float)neighborNormals.size();
2898 meanNormal.normalize();
2899 normals->at(i).normal_x = meanNormal[0];
2900 normals->at(i).normal_y = meanNormal[1];
2901 normals->at(i).normal_z = meanNormal[2];
2908 const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
2911 const Eigen::Vector3f & viewPoint)
2913 return computeNormals2DImpl<pcl::PointXYZ>(cloud, searchK, searchRadius, viewPoint);
2916 const pcl::PointCloud<pcl::PointXYZI>::Ptr & cloud,
2919 const Eigen::Vector3f & viewPoint)
2921 return computeNormals2DImpl<pcl::PointXYZI>(cloud, searchK, searchRadius, viewPoint);
2924 template<
typename Po
intT>
2926 const typename pcl::PointCloud<PointT>::Ptr & cloud,
2929 const Eigen::Vector3f & viewPoint)
2932 pcl::PointCloud<pcl::Normal>::Ptr normals (
new pcl::PointCloud<pcl::Normal>);
2934 normals->resize(cloud->size());
2935 searchRadius *= searchRadius;
2937 float bad_point = std::numeric_limits<float>::quiet_NaN ();
2940 for(
int i=0; i<(int)cloud->size(); ++i)
2948 if(hi>=(
int)cloud->size())
2950 hi=(int)cloud->size()-1;
2954 const PointT & pt = cloud->at(i);
2955 std::vector<Eigen::Vector3f> neighborNormals;
2956 Eigen::Vector3f direction;
2957 direction[0] = viewPoint[0] - cloud->at(i).x;
2958 direction[1] = viewPoint[1] - cloud->at(i).y;
2959 direction[2] = viewPoint[2] - cloud->at(i).z;
2960 for(
int j=i-1; j>=li; --j)
2962 const PointT & pt2 = cloud->at(j);
2963 Eigen::Vector3f vd(pt2.x-pt.x, pt2.y - pt.y, pt2.z - pt.z);
2964 if(searchRadius<=0.0
f || (vd[0]*vd[0] + vd[1]*vd[1] + vd[2]*vd[2]) < searchRadius)
2966 Eigen::Vector3f v(pt2.x-pt.x, pt2.y - pt.y, pt2.z - pt.z);
2967 Eigen::Vector3f up = v.cross(direction);
2968 Eigen::Vector3f n = up.cross(v);
2970 neighborNormals.push_back(n);
2977 for(
int j=i+1; j<=hi; ++j)
2979 const PointT & pt2 = cloud->at(j);
2980 Eigen::Vector3f vd(pt2.x-pt.x, pt2.y - pt.y, pt2.z - pt.z);
2981 if(searchRadius<=0.0
f || (vd[0]*vd[0] + vd[1]*vd[1] + vd[2]*vd[2]) < searchRadius)
2983 Eigen::Vector3f v(pt2.x-pt.x, pt2.y - pt.y, pt2.z - pt.z);
2984 Eigen::Vector3f up = v[2]==0.0f?Eigen::Vector3f(0,0,1):v.cross(direction);
2985 Eigen::Vector3f n = up.cross(v);
2987 neighborNormals.push_back(n);
2995 if(neighborNormals.empty())
2997 normals->at(i).normal_x = bad_point;
2998 normals->at(i).normal_y = bad_point;
2999 normals->at(i).normal_z = bad_point;
3003 Eigen::Vector3f meanNormal(0,0,0);
3004 for(
unsigned int j=0; j<neighborNormals.size(); ++j)
3006 meanNormal+=neighborNormals[j];
3008 meanNormal /= (float)neighborNormals.size();
3009 meanNormal.normalize();
3010 normals->at(i).normal_x = meanNormal[0];
3011 normals->at(i).normal_y = meanNormal[1];
3012 normals->at(i).normal_z = meanNormal[2];
3020 const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
3023 const Eigen::Vector3f & viewPoint)
3025 return computeFastOrganizedNormals2DImpl<pcl::PointXYZ>(cloud, searchK, searchRadius, viewPoint);
3028 const pcl::PointCloud<pcl::PointXYZI>::Ptr & cloud,
3031 const Eigen::Vector3f & viewPoint)
3033 return computeFastOrganizedNormals2DImpl<pcl::PointXYZI>(cloud, searchK, searchRadius, viewPoint);
3037 const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
3038 float maxDepthChangeFactor,
3039 float normalSmoothingSize,
3040 const Eigen::Vector3f & viewPoint)
3042 pcl::IndicesPtr indices(
new std::vector<int>);
3046 const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
3047 const pcl::IndicesPtr & indices,
3048 float maxDepthChangeFactor,
3049 float normalSmoothingSize,
3050 const Eigen::Vector3f & viewPoint)
3052 UASSERT(cloud->isOrganized());
3054 pcl::search::KdTree<pcl::PointXYZRGB>::Ptr
tree (
new pcl::search::KdTree<pcl::PointXYZRGB>);
3057 tree->setInputCloud(cloud, indices);
3061 tree->setInputCloud (cloud);
3065 pcl::PointCloud<pcl::Normal>::Ptr normals (
new pcl::PointCloud<pcl::Normal>);
3066 pcl::IntegralImageNormalEstimation<pcl::PointXYZRGB, pcl::Normal> ne;
3067 ne.setNormalEstimationMethod (ne.AVERAGE_3D_GRADIENT);
3068 ne.setMaxDepthChangeFactor(maxDepthChangeFactor);
3069 ne.setNormalSmoothingSize(normalSmoothingSize);
3070 ne.setBorderPolicy(ne.BORDER_POLICY_MIRROR);
3071 ne.setInputCloud(cloud);
3077 ne.setSearchMethod(tree);
3078 ne.setViewPoint(viewPoint[0], viewPoint[1], viewPoint[2]);
3079 ne.compute(*normals);
3087 cv::Mat * pcaEigenVectors,
3088 cv::Mat * pcaEigenValues)
3093 int sz =
static_cast<int>(scan.
size()*2);
3094 bool is2d = scan.
is2d();
3095 cv::Mat data_normals = cv::Mat::zeros(sz, is2d?2:3, CV_32FC1);
3098 bool doTransform =
false;
3105 for (
int i = 0; i < scan.
size(); ++i)
3107 const float * ptrScan = scan.
data().ptr<
float>(0, i);
3113 cv::Point3f n(ptrScan[nOffset], ptrScan[nOffset+1], 0);
3118 float * ptr = data_normals.ptr<
float>(oi++, 0);
3127 cv::Point3f n(ptrScan[nOffset], ptrScan[nOffset+1], ptrScan[nOffset+2]);
3132 float * ptr = data_normals.ptr<
float>(oi++, 0);
3141 cv::PCA pca_analysis(cv::Mat(data_normals, cv::Range(0, oi*2)), cv::Mat(), CV_PCA_DATA_AS_ROW);
3145 *pcaEigenVectors = pca_analysis.eigenvectors;
3149 *pcaEigenValues = pca_analysis.eigenvalues;
3151 UASSERT((is2d && pca_analysis.eigenvalues.total()>=2) || (!is2d && pca_analysis.eigenvalues.total()>=3));
3153 return pca_analysis.eigenvalues.at<
float>(0, is2d?1:2)*(is2d?2.0
f:3.0
f);
3158 UERROR(
"Scan doesn't have normals!");
3164 const pcl::PointCloud<pcl::PointNormal> & cloud,
3167 cv::Mat * pcaEigenVectors,
3168 cv::Mat * pcaEigenValues)
3171 int sz =
static_cast<int>(cloud.size()*2);
3172 cv::Mat data_normals = cv::Mat::zeros(sz, is2d?2:3, CV_32FC1);
3174 bool doTransform =
false;
3181 for (
unsigned int i = 0; i < cloud.size(); ++i)
3183 const pcl::PointNormal & pt = cloud.at(i);
3184 cv::Point3f n(pt.normal_x, pt.normal_y, pt.normal_z);
3191 float * ptr = data_normals.ptr<
float>(oi++, 0);
3202 cv::PCA pca_analysis(cv::Mat(data_normals, cv::Range(0, oi*2)), cv::Mat(), CV_PCA_DATA_AS_ROW);
3206 *pcaEigenVectors = pca_analysis.eigenvectors;
3210 *pcaEigenValues = pca_analysis.eigenvalues;
3214 return pca_analysis.eigenvalues.at<
float>(0, is2d?1:2)*(is2d?2.0
f:3.0
f);
3220 const pcl::PointCloud<pcl::Normal> & normals,
3223 cv::Mat * pcaEigenVectors,
3224 cv::Mat * pcaEigenValues)
3227 int sz =
static_cast<int>(normals.size()*2);
3228 cv::Mat data_normals = cv::Mat::zeros(sz, is2d?2:3, CV_32FC1);
3230 bool doTransform =
false;
3237 for (
unsigned int i = 0; i < normals.size(); ++i)
3239 const pcl::Normal & pt = normals.at(i);
3240 cv::Point3f n(pt.normal_x, pt.normal_y, pt.normal_z);
3247 float * ptr = data_normals.ptr<
float>(oi++, 0);
3258 cv::PCA pca_analysis(cv::Mat(data_normals, cv::Range(0, oi*2)), cv::Mat(), CV_PCA_DATA_AS_ROW);
3262 *pcaEigenVectors = pca_analysis.eigenvectors;
3266 *pcaEigenValues = pca_analysis.eigenvalues;
3270 return pca_analysis.eigenvalues.at<
float>(0, is2d?1:2)*(is2d?2.0
f:3.0
f);
3276 const pcl::PointCloud<pcl::PointXYZINormal> & cloud,
3279 cv::Mat * pcaEigenVectors,
3280 cv::Mat * pcaEigenValues)
3283 int sz =
static_cast<int>(cloud.size()*2);
3284 cv::Mat data_normals = cv::Mat::zeros(sz, is2d?2:3, CV_32FC1);
3286 bool doTransform =
false;
3293 for (
unsigned int i = 0; i < cloud.size(); ++i)
3295 const pcl::PointXYZINormal & pt = cloud.at(i);
3296 cv::Point3f n(pt.normal_x, pt.normal_y, pt.normal_z);
3303 float * ptr = data_normals.ptr<
float>(oi++, 0);
3314 cv::PCA pca_analysis(cv::Mat(data_normals, cv::Range(0, oi*2)), cv::Mat(), CV_PCA_DATA_AS_ROW);
3318 *pcaEigenVectors = pca_analysis.eigenvectors;
3322 *pcaEigenValues = pca_analysis.eigenvalues;
3326 return pca_analysis.eigenvalues.at<
float>(0, is2d?1:2)*(is2d?2.0
f:3.0
f);
3332 const pcl::PointCloud<pcl::PointXYZRGBNormal> & cloud,
3335 cv::Mat * pcaEigenVectors,
3336 cv::Mat * pcaEigenValues)
3339 int sz =
static_cast<int>(cloud.size()*2);
3340 cv::Mat data_normals = cv::Mat::zeros(sz, is2d?2:3, CV_32FC1);
3342 bool doTransform =
false;
3349 for (
unsigned int i = 0; i < cloud.size(); ++i)
3351 const pcl::PointXYZRGBNormal & pt = cloud.at(i);
3352 cv::Point3f n(pt.normal_x, pt.normal_y, pt.normal_z);
3359 float * ptr = data_normals.ptr<
float>(oi++, 0);
3370 cv::PCA pca_analysis(cv::Mat(data_normals, cv::Range(0, oi*2)), cv::Mat(), CV_PCA_DATA_AS_ROW);
3374 *pcaEigenVectors = pca_analysis.eigenvectors;
3378 *pcaEigenValues = pca_analysis.eigenvalues;
3382 return pca_analysis.eigenvalues.at<
float>(0, is2d?1:2)*(is2d?2.0
f:3.0
f);
3387 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr
mls(
3388 const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
3390 int polygonialOrder,
3391 int upsamplingMethod,
3392 float upsamplingRadius,
3393 float upsamplingStep,
3395 float dilationVoxelSize,
3396 int dilationIterations)
3398 pcl::IndicesPtr indices(
new std::vector<int>);
3408 dilationIterations);
3411 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr
mls(
3412 const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
3413 const pcl::IndicesPtr & indices,
3415 int polygonialOrder,
3416 int upsamplingMethod,
3417 float upsamplingRadius,
3418 float upsamplingStep,
3420 float dilationVoxelSize,
3421 int dilationIterations)
3423 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr cloud_with_normals(
new pcl::PointCloud<pcl::PointXYZRGBNormal>);
3424 pcl::search::KdTree<pcl::PointXYZRGB>::Ptr
tree (
new pcl::search::KdTree<pcl::PointXYZRGB>);
3427 tree->setInputCloud (cloud, indices);
3431 tree->setInputCloud (cloud);
3435 pcl::MovingLeastSquares<pcl::PointXYZRGB, pcl::PointXYZRGBNormal>
mls;
3438 mls.setComputeNormals (
true);
3439 if(polygonialOrder > 0)
3441 #if PCL_VERSION_COMPARE(<, 1, 10, 0) 3442 mls.setPolynomialFit (
true);
3444 mls.setPolynomialOrder(polygonialOrder);
3448 #if PCL_VERSION_COMPARE(<, 1, 10, 0) 3449 mls.setPolynomialFit (
false);
3451 mls.setPolynomialOrder(1);
3454 UASSERT(upsamplingMethod >= mls.NONE &&
3455 upsamplingMethod <= mls.VOXEL_GRID_DILATION);
3456 mls.setUpsamplingMethod((pcl::MovingLeastSquares<pcl::PointXYZRGB, pcl::PointXYZRGBNormal>::UpsamplingMethod)upsamplingMethod);
3457 mls.setSearchRadius(searchRadius);
3458 mls.setUpsamplingRadius(upsamplingRadius);
3459 mls.setUpsamplingStepSize(upsamplingStep);
3460 mls.setPointDensity(pointDensity);
3461 mls.setDilationVoxelSize(dilationVoxelSize);
3462 mls.setDilationIterations(dilationIterations);
3465 mls.setInputCloud (cloud);
3468 mls.setIndices(indices);
3470 mls.setSearchMethod (tree);
3471 mls.process (*cloud_with_normals);
3474 for(
unsigned int i=0; i<cloud_with_normals->size(); ++i)
3476 Eigen::Vector3f normal(cloud_with_normals->at(i).normal_x, cloud_with_normals->at(i).normal_y, cloud_with_normals->at(i).normal_z);
3478 cloud_with_normals->at(i).normal_x = normal[0];
3479 cloud_with_normals->at(i).normal_y = normal[1];
3480 cloud_with_normals->at(i).normal_z = normal[2];
3483 return cloud_with_normals;
3488 const Eigen::Vector3f & viewpoint,
3489 bool forceGroundNormalsUp)
3495 const Eigen::Vector3f & viewpoint,
3496 float groundNormalsUp)
3503 cv::Mat output = scan.
data().clone();
3504 #pragma omp parallel for 3505 for(
int i=0; i<scan.
size(); ++i)
3507 float * ptr = output.ptr<
float>(0, i);
3510 Eigen::Vector3f v = viewpoint - Eigen::Vector3f(ptr[0], ptr[1], ptr[2]);
3511 Eigen::Vector3f n(ptr[nx], ptr[ny], ptr[nz]);
3513 float result = v.dot(n);
3515 || (groundNormalsUp>0.0
f && ptr[nz] < -groundNormalsUp && ptr[2] < viewpoint[3]))
3536 template<
typename Po
intNormalT>
3538 typename pcl::PointCloud<PointNormalT>::Ptr & cloud,
3539 const Eigen::Vector3f & viewpoint,
3540 float groundNormalsUp)
3542 #pragma omp parallel for 3543 for(
int i=0; i<(int)cloud->size(); ++i)
3545 pcl::PointXYZ normal(cloud->points[i].normal_x, cloud->points[i].normal_y, cloud->points[i].normal_z);
3548 Eigen::Vector3f v = viewpoint - cloud->points[i].getVector3fMap();
3549 Eigen::Vector3f n(normal.x, normal.y, normal.z);
3551 float result = v.dot(n);
3553 || (groundNormalsUp>0.0
f && normal.z < -groundNormalsUp && cloud->points[i].z < viewpoint[3]))
3556 cloud->points[i].normal_x *= -1.0f;
3557 cloud->points[i].normal_y *= -1.0f;
3558 cloud->points[i].normal_z *= -1.0f;
3565 pcl::PointCloud<pcl::PointNormal>::Ptr & cloud,
3566 const Eigen::Vector3f & viewpoint,
3567 bool forceGroundNormalsUp)
3572 pcl::PointCloud<pcl::PointNormal>::Ptr & cloud,
3573 const Eigen::Vector3f & viewpoint,
3574 float groundNormalsUp)
3576 adjustNormalsToViewPointImpl<pcl::PointNormal>(cloud, viewpoint, groundNormalsUp);
3580 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud,
3581 const Eigen::Vector3f & viewpoint,
3582 bool forceGroundNormalsUp)
3587 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud,
3588 const Eigen::Vector3f & viewpoint,
3589 float groundNormalsUp)
3591 adjustNormalsToViewPointImpl<pcl::PointXYZRGBNormal>(cloud, viewpoint, groundNormalsUp);
3595 pcl::PointCloud<pcl::PointXYZINormal>::Ptr & cloud,
3596 const Eigen::Vector3f & viewpoint,
3597 bool forceGroundNormalsUp)
3602 pcl::PointCloud<pcl::PointXYZINormal>::Ptr & cloud,
3603 const Eigen::Vector3f & viewpoint,
3604 float groundNormalsUp)
3606 adjustNormalsToViewPointImpl<pcl::PointXYZINormal>(cloud, viewpoint, groundNormalsUp);
3610 template<
typename Po
intT>
3612 const std::map<int, Transform> & poses,
3613 const pcl::PointCloud<pcl::PointXYZ>::Ptr & rawCloud,
3614 const std::vector<int> & rawCameraIndices,
3615 typename pcl::PointCloud<PointT>::Ptr & cloud,
3616 float groundNormalsUp)
3618 if(poses.size() && rawCloud->size() && rawCloud->size() == rawCameraIndices.size() && cloud->size())
3620 pcl::search::KdTree<pcl::PointXYZ>::Ptr rawTree (
new pcl::search::KdTree<pcl::PointXYZ>);
3621 rawTree->setInputCloud (rawCloud);
3623 #pragma omp parallel for 3624 for(
int i=0; i<(int)cloud->size(); ++i)
3626 pcl::PointXYZ normal(cloud->points[i].normal_x, cloud->points[i].normal_y, cloud->points[i].normal_z);
3629 std::vector<int> indices;
3630 std::vector<float>
dist;
3631 rawTree->nearestKSearch(pcl::PointXYZ(cloud->points[i].x, cloud->points[i].y, cloud->points[i].z), 1, indices, dist);
3633 if(indices.size() && indices[0]>=0)
3635 const Transform & p = poses.at(rawCameraIndices[indices[0]]);
3636 pcl::PointXYZ viewpoint(p.
x(), p.
y(), p.
z());
3637 Eigen::Vector3f v = viewpoint.getVector3fMap() - cloud->points[i].getVector3fMap();
3639 Eigen::Vector3f n(normal.x, normal.y, normal.z);
3641 float result = v.dot(n);
3643 (groundNormalsUp>0.0
f && normal.z < -groundNormalsUp && cloud->points[i].z < viewpoint.z))
3646 cloud->points[i].normal_x *= -1.0f;
3647 cloud->points[i].normal_y *= -1.0f;
3648 cloud->points[i].normal_z *= -1.0f;
3653 UWARN(
"Not found camera viewpoint for point %d", i);
3661 const std::map<int, Transform> & poses,
3662 const pcl::PointCloud<pcl::PointXYZ>::Ptr & rawCloud,
3663 const std::vector<int> & rawCameraIndices,
3664 pcl::PointCloud<pcl::PointNormal>::Ptr & cloud,
3665 float groundNormalsUp)
3667 adjustNormalsToViewPointsImpl<pcl::PointNormal>(poses, rawCloud, rawCameraIndices, cloud, groundNormalsUp);
3671 const std::map<int, Transform> & poses,
3672 const pcl::PointCloud<pcl::PointXYZ>::Ptr & rawCloud,
3673 const std::vector<int> & rawCameraIndices,
3674 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud,
3675 float groundNormalsUp)
3677 adjustNormalsToViewPointsImpl<pcl::PointXYZRGBNormal>(poses, rawCloud, rawCameraIndices, cloud, groundNormalsUp);
3681 const std::map<int, Transform> & poses,
3682 const pcl::PointCloud<pcl::PointXYZ>::Ptr & rawCloud,
3683 const std::vector<int> & rawCameraIndices,
3684 pcl::PointCloud<pcl::PointXYZINormal>::Ptr & cloud,
3685 float groundNormalsUp)
3687 adjustNormalsToViewPointsImpl<pcl::PointXYZINormal>(poses, rawCloud, rawCameraIndices, cloud, groundNormalsUp);
3691 const std::map<int, Transform> & viewpoints,
3693 const std::vector<int> & viewpointIds,
3695 float groundNormalsUp)
3697 UDEBUG(
"poses=%d, rawCloud=%d, rawCameraIndices=%d, cloud=%d", (
int)viewpoints.size(), (int)rawScan.
size(), (int)viewpointIds.size(), (int)scan.
size());
3698 if(viewpoints.size() && rawScan.
size() && rawScan.
size() == (int)viewpointIds.size() && scan.
size() && scan.
hasNormals())
3701 pcl::search::KdTree<pcl::PointXYZ>::Ptr rawTree (
new pcl::search::KdTree<pcl::PointXYZ>);
3702 rawTree->setInputCloud (rawCloud);
3703 #pragma omp parallel for 3704 for(
int i=0; i<scan.
size(); ++i)
3707 pcl::PointXYZ normal(point.normal_x, point.normal_y, point.normal_z);
3710 std::vector<int> indices;
3711 std::vector<float>
dist;
3712 rawTree->nearestKSearch(pcl::PointXYZ(point.x, point.y, point.z), 1, indices, dist);
3713 if(indices.size() && indices[0]>=0)
3715 UASSERT_MSG(indices[0]<(
int)viewpointIds.size(),
uFormat(
"indices[0]=%d rawCameraIndices.size()=%d", indices[0], (
int)viewpointIds.size()).c_str());
3717 Transform p = viewpoints.at(viewpointIds[indices[0]]);
3718 pcl::PointXYZ viewpoint(p.
x(), p.
y(), p.
z());
3719 Eigen::Vector3f v = viewpoint.getVector3fMap() - point.getVector3fMap();
3721 Eigen::Vector3f n(normal.x, normal.y, normal.z);
3723 float result = v.dot(n);
3725 (groundNormalsUp>0.0
f && normal.z < -groundNormalsUp && point.z < viewpoint.z))
3735 UWARN(
"Not found camera viewpoint for point %d!?", i);
3742 pcl::PolygonMesh::Ptr
meshDecimation(
const pcl::PolygonMesh::Ptr & mesh,
float factor)
3744 pcl::PolygonMesh::Ptr output(
new pcl::PolygonMesh);
3746 pcl::MeshQuadricDecimationVTK mqd;
3747 mqd.setTargetReductionFactor(factor);
3748 mqd.setInputMesh(mesh);
3749 mqd.process (*output);
3751 UWARN(
"RTAB-Map is not built with VTK module so mesh decimation cannot be used!");
3758 const Eigen::Vector3f & p,
3759 const Eigen::Vector3f & dir,
3760 const Eigen::Vector3f & v0,
3761 const Eigen::Vector3f & v1,
3762 const Eigen::Vector3f & v2,
3764 Eigen::Vector3f & normal)
3767 const Eigen::Vector3f u = v1-v0;
3768 const Eigen::Vector3f v = v2-v0;
3769 normal = u.cross(v);
3770 if (normal == Eigen::Vector3f(0,0,0))
3773 const float denomimator = normal.dot(dir);
3774 if (fabs(denomimator) < 10
e-9)
3778 distance = normal.dot(v0 - p) / denomimator;
3783 float uu, uv, vv, wu, wv, D;
3787 const Eigen::Vector3f w = p + dir * distance - v0;
3790 D = uv * uv - uu * vv;
3794 s = (uv * wv - vv * wu) / D;
3795 if (s < 0.0 || s > 1.0)
3797 t = (uv * wu - uu * wv) / D;
3798 if (t < 0.0 || (s + t) > 1.0)
bool uIsInteger(const std::string &str, bool checkForSign=true)
bool getNodeInfo(int signatureId, Transform &odomPose, int &mapId, int &weight, std::string &label, double &stamp, Transform &groundTruth, std::vector< float > &velocity, GPS &gps, EnvSensors &sensors, bool lookInDatabase=false) const
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
pcl::PointNormal RTABMAP_EXP laserScanToPointNormal(const LaserScan &laserScan, int index)
const cv::Size & imageSize() const
void getWeight(int signatureId, int &weight) 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)
cv::Point3f RTABMAP_EXP transformPoint(const cv::Point3f &pt, const Transform &transform)
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)
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)
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[]
const std::vector< StereoCameraModel > & stereoCameraModels() const
const cv::Mat & data() 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)
Basic mathematics functions.
GLM_FUNC_DECL T angle(detail::tquat< T, P > const &x)
int getNormalsOffset() const
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)
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())
float & field(unsigned int pointIndex, unsigned int channelOffset)
std::vector< double > roi
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)
std::list< std::string > uSplit(const std::string &str, char separator=' ')
Structure to store camera pose and focal length.
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)
const std::vector< CameraModel > & cameraModels() 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)
virtual bool callback(const std::string &msg) const
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)
const cv::Mat & imageRaw() const
bool getCalibration(int signatureId, std::vector< CameraModel > &models, std::vector< StereoCameraModel > &stereoModels) const
GLM_FUNC_DECL genType pi()
void adjustNormalsToViewPoint(pcl::PointCloud< pcl::PointXYZINormal >::Ptr &cloud, const Eigen::Vector3f &viewpoint, bool forceGroundNormalsUp)
void getNodeData(int signatureId, SensorData &data, bool images=true, bool scan=true, bool userData=true, bool occupancyGrid=true) const
const Transform & localTransform() const
LaserScan laserScanFromPointCloud(const PointCloud2T &cloud, bool filterNaNs, bool is2D, const Transform &transform)
void setMaxDepthError(float maxDepthError)
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)
SensorData getNodeData(int locationId, bool images, bool scan, bool userData, bool occupancyGrid) const
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)
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)
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...
bool 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, const DBDriver *dbDriver, int textureSize, const std::string &textureFormat, const std::map< int, std::map< int, cv::Vec4d > > &gains, const std::map< int, std::map< int, cv::Mat > > &blendingGains, const std::pair< float, float > &contrastValues, bool gainRGB)
static bool removeDir(const std::string &dirPath)
ULogger class and convenient macros.
void setMaxAngle(float maxAngle)
bool hasIntensity() const
pcl::PointCloud< pcl::PointNormal >::Ptr RTABMAP_EXP removeNaNNormalsFromPointCloud(const pcl::PointCloud< pcl::PointNormal >::Ptr &cloud)
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, float groundNormalsUp=0.0f)
std::map< EnvSensor::Type, EnvSensor > EnvSensors
float angleIncrement() const
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.
void adjustNormalsToViewPointsImpl(const std::map< int, Transform > &poses, const pcl::PointCloud< pcl::PointXYZ >::Ptr &rawCloud, const std::vector< int > &rawCameraIndices, typename pcl::PointCloud< PointT >::Ptr &cloud, float groundNormalsUp)
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)
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
const cv::Mat & imageCompressed() const
Transform localTransform() const
LaserScan RTABMAP_EXP laserScan2dFromPointCloud(const pcl::PointCloud< pcl::PointXYZ > &cloud, const Transform &transform=Transform(), bool filterNaNs=true)
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)
cv::Mat RTABMAP_EXP uncompressImage(const cv::Mat &bytes)
GLM_FUNC_DECL matType< T, P > inverse(matType< T, P > const &m)