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)
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;
192 std::vector<pcl::Vertices> output(
vertices.size());
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;
230 std::vector<pcl::Vertices> output(
vertices.size());
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;
268 std::vector<pcl::Vertices> output(
vertices.size());
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)
301 for(
unsigned int j=0;
j<
vertices.vertices.size(); ++
j)
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)
327 for(
unsigned int j=0;
j<
vertices.vertices.size(); ++
j)
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)
432 if(pcl::isFinite(cloud.at(
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);
497 else if(keepLatestInRadius)
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)
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);
632 cam.focal_length_w=modelIter->second[
i].fx();
633 cam.focal_length_h=modelIter->second[
i].fy();
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)
640 cam.texture_file =
uFormat(
"%d", poseIter->first);
644 cam.texture_file =
uFormat(
"%d_%d", poseIter->first, (
int)
i);
646 if(!roiRatios.empty())
649 cam.roi[0] =
cam.width * roiRatios[0];
650 cam.roi[1] =
cam.height * roiRatios[2];
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());
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;
770 mesh_material.tex_file =
cameras[
i].texture_file;
774 mesh_material.tex_file =
"occluded";
777 textureMesh->tex_materials[
i] = mesh_material;
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;
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);
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];
1079 void concatenateTextureMaterials(pcl::TextureMesh & mesh,
const cv::Size & imageSize,
int textureSize,
int maxTextures,
float & scale, std::vector<bool> * materialsKept)
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);
1107 while((colCount*rowCount)*maxTextures < materials || (
factor == 0.1
f ||
scale > 1.0
f))
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;
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)
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;
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)
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 bool clearVertexColorUnderTexture,
1458 std::map<
int, std::map<int, cv::Vec4d> > * gains,
1459 std::map<
int, std::map<int, cv::Mat> > * blendingGains,
1460 std::pair<float, float> * contrastValues)
1462 std::map<int, std::vector<CameraModel> > calibVectors;
1463 for(std::map<int, CameraModel>::const_iterator
iter=calibrations.begin();
iter!=calibrations.end(); ++
iter)
1465 std::vector<CameraModel>
m;
1466 m.push_back(
iter->second);
1467 calibVectors.insert(std::make_pair(
iter->first,
m));
1482 brightnessContrastRatioLow,
1483 brightnessContrastRatioHigh,
1487 clearVertexColorUnderTexture,
1493 pcl::TextureMesh & mesh,
1494 const std::map<int, cv::Mat> & images,
1495 const std::map<
int, std::vector<CameraModel> > & calibrations,
1500 const std::vector<std::map<int, pcl::PointXY> > & vertexToPixels,
1501 bool gainCompensation,
1505 int blendingDecimation,
1506 int brightnessContrastRatioLow,
1507 int brightnessContrastRatioHigh,
1510 unsigned char blankValue,
1511 bool clearVertexColorUnderTexture,
1512 std::map<
int, std::map<int, cv::Vec4d> > * gainsOut,
1513 std::map<
int, std::map<int, cv::Mat> > * blendingGainsOut,
1514 std::pair<float, float> * contrastValuesOut)
1517 UASSERT(textureSize%256 == 0);
1518 UDEBUG(
"textureSize = %d", textureSize);
1519 cv::Mat globalTextures;
1520 if(!mesh.tex_materials.empty())
1522 std::vector<std::pair<int, int> > textures(mesh.tex_materials.size(), std::pair<int, int>(-1,0));
1524 const int imageType=CV_8UC3;
1527 for(
unsigned int i=0;
i<mesh.tex_materials.size(); ++
i)
1529 std::list<std::string> texFileSplit =
uSplit(mesh.tex_materials[
i].tex_file,
'_');
1530 if(!mesh.tex_materials[
i].tex_file.empty() &&
1531 mesh.tex_polygons[
i].size() &&
1534 textures[
i].first =
uStr2Int(texFileSplit.front());
1535 if(texFileSplit.size() == 2 &&
1538 textures[
i].second =
uStr2Int(texFileSplit.back());
1541 int textureId = textures[
i].first;
1542 if(imageSize.width == 0 || imageSize.height == 0)
1544 if(images.find(textureId) != images.end() &&
1545 !images.find(textureId)->second.empty() &&
1546 calibrations.find(textureId) != calibrations.end())
1548 const std::vector<CameraModel> & models = calibrations.find(textureId)->second;
1550 if( models[0].imageHeight()>0 &&
1551 models[0].imageWidth()>0)
1553 imageSize = models[0].imageSize();
1555 else if(images.find(textureId)!=images.end())
1558 cv::Mat image = images.find(textureId)->second;
1559 if(image.rows == 1 && image.type() == CV_8UC1)
1564 imageSize = image.size();
1567 imageSize.width/=models.size();
1574 const std::vector<CameraModel> & models =
data.cameraModels();
1575 const std::vector<StereoCameraModel> & stereoModels =
data.stereoCameraModels();
1576 if(models.size()>=1 &&
1577 models[0].imageHeight()>0 &&
1578 models[0].imageWidth()>0)
1580 imageSize = models[0].imageSize();
1582 else if(stereoModels.size()>=1 &&
1583 stereoModels[0].left().imageHeight() > 0 &&
1584 stereoModels[0].left().imageWidth() > 0)
1586 imageSize = stereoModels[0].left().imageSize();
1591 data.uncompressDataConst(&image, 0);
1593 imageSize = image.size();
1594 if(
data.cameraModels().size()>1)
1596 imageSize.width/=
data.cameraModels().size();
1602 std::vector<CameraModel> models;
1603 std::vector<StereoCameraModel> stereoModels;
1605 if(models.size()>=1 &&
1606 models[0].imageHeight()>0 &&
1607 models[0].imageWidth()>0)
1609 imageSize = models[0].imageSize();
1611 else if(stereoModels.size()>=1 &&
1612 stereoModels[0].left().imageHeight() > 0 &&
1613 stereoModels[0].left().imageWidth() > 0)
1615 imageSize = stereoModels[0].left().imageSize();
1622 data.uncompressDataConst(&image, 0);
1624 imageSize = image.size();
1625 if(
data.cameraModels().size()>1)
1627 imageSize.width/=
data.cameraModels().size();
1633 else if(mesh.tex_polygons[
i].size() && mesh.tex_materials[
i].tex_file.compare(
"occluded")!=0)
1635 UWARN(
"Failed parsing texture file name: %s", mesh.tex_materials[
i].tex_file.c_str());
1638 UDEBUG(
"textures=%d imageSize=%dx%d", (
int)textures.size(), imageSize.height, imageSize.width);
1639 if(textures.size() && imageSize.height>0 && imageSize.width>0)
1643 std::vector<bool> materialsKept;
1647 int materials = (
int)mesh.tex_materials.size();
1651 globalTextures = cv::Mat(textureSize, materials*textureSize, imageType,
cv::Scalar::all(blankValue));
1652 cv::Mat globalTextureMasks = cv::Mat(textureSize, materials*textureSize, CV_8UC1,
cv::Scalar::all(0));
1655 cv::Mat previousImage;
1656 int previousTextureId = 0;
1657 std::vector<CameraModel> previousCameraModels;
1663 std::vector<cv::Point2i> imageOrigin(textures.size());
1664 std::vector<int> newCamIndex(textures.size(), -1);
1665 for(
int t=0;
t<(
int)textures.size(); ++
t)
1667 if(materialsKept.at(
t))
1669 int indexMaterial = oi / (
cols*
rows);
1670 UASSERT(indexMaterial < materials);
1672 newCamIndex[
t] = oi;
1673 int u = oi%
cols * emptyImage.cols;
1674 int v = ((oi/
cols) %
rows ) * emptyImage.rows;
1675 UASSERT_MSG(u < textureSize-emptyImage.cols,
uFormat(
"u=%d textureSize=%d emptyImage.cols=%d", u, textureSize, emptyImage.cols).c_str());
1676 UASSERT_MSG(
v < textureSize-emptyImage.rows,
uFormat(
"v=%d textureSize=%d emptyImage.rows=%d",
v, textureSize, emptyImage.rows).c_str());
1677 imageOrigin[
t].x = u;
1678 imageOrigin[
t].y =
v;
1682 std::vector<CameraModel> models;
1684 if(textures[
t].
first == previousTextureId)
1686 image = previousImage;
1687 models = previousCameraModels;
1691 if(images.find(textures[
t].first) != images.end() &&
1692 !images.find(textures[
t].first)->second.empty() &&
1693 calibrations.find(textures[
t].first) != calibrations.end())
1695 image = images.find(textures[
t].
first)->second;
1696 if(image.rows == 1 && image.type() == CV_8UC1)
1700 models = calibrations.find(textures[
t].
first)->second;
1705 models =
data.cameraModels();
1706 if(models.empty() && !
data.stereoCameraModels().empty())
1708 for(
size_t i=0;
i<
data.stereoCameraModels().
size(); ++
i)
1710 models.push_back(
data.stereoCameraModels()[
i].left());
1713 data.uncompressDataConst(&image, 0);
1719 data.uncompressDataConst(&image, 0);
1720 std::vector<StereoCameraModel> stereoModels;
1722 if(models.empty() && !stereoModels.empty())
1724 for(
size_t i=0;
i<stereoModels.size(); ++
i)
1726 models.push_back(stereoModels[
i].left());
1731 previousImage = image;
1732 previousCameraModels = models;
1733 previousTextureId = textures[
t].first;
1741 int width = image.cols/models.size();
1742 image = image.colRange(width*textures[
t].
second, width*(textures[
t].
second+1));
1745 cv::Mat resizedImage;
1746 cv::resize(image, resizedImage, emptyImage.size(), 0.0f, 0.0f, cv::INTER_AREA);
1747 UASSERT(resizedImage.type() == CV_8UC1 || resizedImage.type() == CV_8UC3);
1748 if(resizedImage.type() == CV_8UC1)
1750 cv::Mat resizedImageColor;
1751 cv::cvtColor(resizedImage, resizedImageColor, CV_GRAY2BGR);
1752 resizedImage = resizedImageColor;
1754 UASSERT(resizedImage.type() == globalTextures.type());
1755 resizedImage.copyTo(globalTextures(cv::Rect(u+indexMaterial*globalTextures.rows,
v, resizedImage.cols, resizedImage.rows)));
1756 emptyImageMask.copyTo(globalTextureMasks(cv::Rect(u+indexMaterial*globalTextureMasks.rows,
v, resizedImage.cols, resizedImage.rows)));
1760 emptyImage.copyTo(globalTextures(cv::Rect(u+indexMaterial*globalTextures.rows,
v, emptyImage.cols, emptyImage.rows)));
1776 if(vertexToPixels.size())
1781 if(gainCompensation)
1787 const int num_images =
static_cast<int>(oi);
1788 cv::Mat_<int>
N(num_images, num_images);
N.setTo(0);
1789 cv::Mat_<double>
I(num_images, num_images);
I.setTo(0);
1791 cv::Mat_<double> IR(num_images, num_images); IR.setTo(0);
1792 cv::Mat_<double> IG(num_images, num_images); IG.setTo(0);
1793 cv::Mat_<double> IB(num_images, num_images); IB.setTo(0);
1796 for(
unsigned int p=0;
p<vertexToPixels.size(); ++
p)
1798 for(std::map<int, pcl::PointXY>::const_iterator
iter=vertexToPixels[
p].begin();
iter!=vertexToPixels[
p].end(); ++
iter)
1800 if(materialsKept.at(
iter->first))
1802 N(newCamIndex[
iter->first], newCamIndex[
iter->first]) +=1;
1804 std::map<int, pcl::PointXY>::const_iterator jter=
iter;
1807 for(; jter!=vertexToPixels[
p].end(); ++jter, ++k)
1809 if(materialsKept.at(jter->first))
1811 int i = newCamIndex[
iter->first];
1812 int j = newCamIndex[jter->first];
1820 int ui =
iter->second.x*emptyImage.cols + imageOrigin[
iter->first].x;
1821 int vi = (1.0-
iter->second.y)*emptyImage.rows + imageOrigin[
iter->first].y;
1822 int uj = jter->second.x*emptyImage.cols + imageOrigin[jter->first].x;
1823 int vj = (1.0-jter->second.y)*emptyImage.rows + imageOrigin[jter->first].y;
1824 cv::Vec3b * pt1 = globalTextures.
ptr<cv::Vec3b>(vi,ui+indexMaterial*globalTextures.rows);
1825 cv::Vec3b * pt2 = globalTextures.ptr<cv::Vec3b>(vj,uj+indexMaterial*globalTextures.rows);
1830 IR(
i,
j) +=
static_cast<double>(pt1->val[2]);
1831 IR(
j,
i) +=
static_cast<double>(pt2->val[2]);
1832 IG(
i,
j) +=
static_cast<double>(pt1->val[1]);
1833 IG(
j,
i) +=
static_cast<double>(pt2->val[1]);
1834 IB(
i,
j) +=
static_cast<double>(pt1->val[0]);
1835 IB(
j,
i) +=
static_cast<double>(pt2->val[0]);
1842 for(
int i=0;
i<num_images; ++
i)
1844 for(
int j=
i;
j<num_images; ++
j)
1858 IR(
i,
j) /=
N(
i,
j);
1859 IR(
j,
i) /=
N(
j,
i);
1860 IG(
i,
j) /=
N(
i,
j);
1861 IG(
j,
i) /=
N(
j,
i);
1862 IB(
i,
j) /=
N(
i,
j);
1863 IB(
j,
i) /=
N(
j,
i);
1868 cv::Mat_<double>
A(num_images, num_images);
A.setTo(0);
1869 cv::Mat_<double>
b(num_images, 1);
b.setTo(0);
1870 cv::Mat_<double> AR(num_images, num_images); AR.setTo(0);
1871 cv::Mat_<double> AG(num_images, num_images); AG.setTo(0);
1872 cv::Mat_<double> AB(num_images, num_images); AB.setTo(0);
1873 double alpha = 0.01;
1874 double beta = gainBeta;
1875 for (
int i = 0;
i < num_images; ++
i)
1877 for (
int j = 0;
j < num_images; ++
j)
1884 if (
j ==
i)
continue;
1899 cv::Mat_<double> gainsGray, gainsR, gainsG, gainsB;
1900 cv::solve(
A,
b, gainsGray);
1902 cv::solve(AR,
b, gainsR);
1903 cv::solve(AG,
b, gainsG);
1904 cv::solve(AB,
b, gainsB);
1906 cv::Mat_<double> gains(gainsGray.rows, 4);
1907 gainsGray.copyTo(gains.col(0));
1908 gainsR.copyTo(gains.col(1));
1909 gainsG.copyTo(gains.col(2));
1910 gainsB.copyTo(gains.col(3));
1912 for(
int t=0;
t<(
int)textures.size(); ++
t)
1915 if(materialsKept.at(
t))
1917 int u = imageOrigin[
t].x;
1918 int v = imageOrigin[
t].y;
1920 UDEBUG(
"Gain cam%d = %f", newCamIndex[
t], gainsGray(newCamIndex[
t], 0));
1922 int indexMaterial = newCamIndex[
t] / (
cols*
rows);
1923 cv::Mat roi = globalTextures(cv::Rect(u+indexMaterial*globalTextures.rows,
v, emptyImage.cols, emptyImage.rows));
1925 std::vector<cv::Mat> channels;
1926 cv::split(roi, channels);
1929 cv::multiply(channels[0], gains(newCamIndex[
t], gainRGB?3:0), channels[0]);
1930 cv::multiply(channels[1], gains(newCamIndex[
t], gainRGB?2:0), channels[1]);
1931 cv::multiply(channels[2], gains(newCamIndex[
t], gainRGB?1:0), channels[2]);
1933 cv::merge(channels, roi);
1938 gains(newCamIndex[
t], 0),
1939 gains(newCamIndex[
t], 1),
1940 gains(newCamIndex[
t], 2),
1941 gains(newCamIndex[
t], 3));
1942 if(gainsOut->find(textures[
t].first) == gainsOut->end())
1944 std::map<int,cv::Vec4d>
value;
1946 gainsOut->insert(std::make_pair(textures[
t].
first,
value));
1950 gainsOut->at(textures[
t].
first).insert(std::make_pair(textures[
t].
second,
g));
1964 if(blendingDecimation <= 0)
1967 std::vector<float> edgeLengths;
1968 if(mesh.tex_coordinates.size() && mesh.tex_coordinates[0].size())
1970 UASSERT(mesh.tex_polygons.size() && mesh.tex_polygons[0].size() && mesh.tex_polygons[0][0].vertices.size());
1971 int polygonSize = mesh.tex_polygons[0][0].vertices.size();
1972 UDEBUG(
"polygon size=%d", polygonSize);
1974 for(
unsigned int k=0; k<mesh.tex_coordinates.size(); ++k)
1976 for(
unsigned int i=0;
i<mesh.tex_coordinates[k].size();
i+=polygonSize)
1978 for(
int j=0;
j<polygonSize; ++
j)
1980 const Eigen::Vector2f & uc1 = mesh.tex_coordinates[k][
i +
j];
1981 const Eigen::Vector2f & uc2 = mesh.tex_coordinates[k][
i + (
j+1)%polygonSize];
1982 Eigen::Vector2f edge = (uc1-uc2)*textureSize;
1983 edgeLengths.push_back(
fabs(edge[0]));
1984 edgeLengths.push_back(
fabs(edge[1]));
1988 float edgeLength = 0.0f;
1989 if(edgeLengths.size())
1991 std::sort(edgeLengths.begin(), edgeLengths.end());
1992 float m =
uMean(edgeLengths.data(), edgeLengths.size());
1994 edgeLength =
m+stddev;
1995 decimation = 1 << 6;
1996 for(
int i=1;
i<=6; ++
i)
1998 if(
float(1 <<
i) >= edgeLength)
2000 decimation = 1 <<
i;
2006 UDEBUG(
"edge length=%f decimation=%d", edgeLength, decimation);
2011 if(blendingDecimation > 1)
2013 UASSERT(textureSize % blendingDecimation == 0);
2015 decimation = blendingDecimation;
2016 UDEBUG(
"decimation=%d", decimation);
2019 std::vector<cv::Mat> blendGains(materials);
2020 for(
int i=0;
i<materials;++
i)
2022 blendGains[
i] = cv::Mat(globalTextures.rows/decimation, globalTextures.rows/decimation, CV_32FC3,
cv::Scalar::all(1.0f));
2025 for(
unsigned int p=0;
p<vertexToPixels.size(); ++
p)
2027 if(vertexToPixels[
p].
size() > 1)
2029 std::vector<float> gainsB(vertexToPixels[
p].
size());
2030 std::vector<float> gainsG(vertexToPixels[
p].
size());
2031 std::vector<float> gainsR(vertexToPixels[
p].
size());
2032 float sumWeight = 0.0f;
2034 for(std::map<int, pcl::PointXY>::const_iterator
iter=vertexToPixels[
p].begin();
iter!=vertexToPixels[
p].end(); ++
iter)
2036 if(materialsKept.at(
iter->first))
2038 int u =
iter->second.x*emptyImage.cols + imageOrigin[
iter->first].x;
2039 int v = (1.0-
iter->second.y)*emptyImage.rows + imageOrigin[
iter->first].y;
2040 float x =
iter->second.x - 0.5f;
2041 float y =
iter->second.y - 0.5f;
2042 float weight = 0.7f -
sqrt(
x*
x+
y*
y);
2047 int indexMaterial = newCamIndex[
iter->first] / (
cols*
rows);
2048 cv::Vec3b * pt = globalTextures.ptr<cv::Vec3b>(
v,u+indexMaterial*globalTextures.rows);
2049 gainsB[k] =
static_cast<double>(pt->val[0]) * weight;
2050 gainsG[k] =
static_cast<double>(pt->val[1]) * weight;
2051 gainsR[k] =
static_cast<double>(pt->val[2]) * weight;
2052 sumWeight += weight;
2062 float targetColor[3];
2063 targetColor[0] =
uSum(gainsB.data(), gainsB.size()) / sumWeight;
2064 targetColor[1] =
uSum(gainsG.data(), gainsG.size()) / sumWeight;
2065 targetColor[2] =
uSum(gainsR.data(), gainsR.size()) / sumWeight;
2066 for(std::map<int, pcl::PointXY>::const_iterator
iter=vertexToPixels[
p].begin();
iter!=vertexToPixels[
p].end(); ++
iter)
2068 if(materialsKept.at(
iter->first))
2070 int u =
iter->second.x*emptyImage.cols + imageOrigin[
iter->first].x;
2071 int v = (1.0-
iter->second.y)*emptyImage.rows + imageOrigin[
iter->first].y;
2072 int indexMaterial = newCamIndex[
iter->first] / (
cols*
rows);
2073 cv::Vec3b * pt = globalTextures.ptr<cv::Vec3b>(
v,u+indexMaterial*globalTextures.rows);
2074 float gB = targetColor[0]/(pt->val[0]==0?1.0f:pt->val[0]);
2075 float gG = targetColor[1]/(pt->val[1]==0?1.0f:pt->val[1]);
2076 float gR = targetColor[2]/(pt->val[2]==0?1.0f:pt->val[2]);
2077 cv::Vec3f * ptr = blendGains[indexMaterial].ptr<cv::Vec3f>(
v/decimation, u/decimation);
2078 ptr->val[0] = (gB>1.3f)?1.3
f:(gB<0.7
f)?0.7f:gB;
2079 ptr->val[1] = (gG>1.3f)?1.3
f:(gG<0.7
f)?0.7f:gG;
2080 ptr->val[2] = (gR>1.3f)?1.3
f:(gR<0.7
f)?0.7f:gR;
2087 if(blendingGainsOut)
2089 for(
int t=0;
t<(
int)textures.size(); ++
t)
2092 if(materialsKept.at(
t))
2094 int u = imageOrigin[
t].
x/decimation;
2095 int v = imageOrigin[
t].y/decimation;
2097 int indexMaterial = newCamIndex[
t] / (
cols*
rows);
2098 cv::Mat roi = blendGains[indexMaterial](cv::Rect(u,
v, emptyImage.cols/decimation, emptyImage.rows/decimation));
2099 if(blendingGainsOut->find(textures[
t].first) == blendingGainsOut->end())
2101 std::map<int,cv::Mat>
value;
2102 value.insert(std::make_pair(textures[
t].
second, roi.clone()));
2103 blendingGainsOut->insert(std::make_pair(textures[
t].
first,
value));
2107 blendingGainsOut->at(textures[
t].
first).insert(std::make_pair(textures[
t].
second, roi.clone()));
2113 for(
int i=0;
i<materials; ++
i)
2125 cv::Mat globalTexturesROI = globalTextures(
cv::Range::all(), cv::Range(
i*globalTextures.rows, (
i+1)*globalTextures.rows));
2127 cv::blur(blendGains[
i],
dst, cv::Size(3,3));
2128 cv::resize(
dst, blendGains[
i], globalTexturesROI.size(), 0, 0, cv::INTER_LINEAR);
2138 cv::multiply(globalTexturesROI, blendGains[
i], globalTexturesROI, 1.0, CV_8UC3);
2148 if(brightnessContrastRatioLow > 0 || brightnessContrastRatioHigh > 0)
2152 std::vector<cv::Mat> images;
2153 images.push_back(globalTextures);
2154 if (brightnessContrastRatioLow > 0)
2159 (
float)brightnessContrastRatioLow,
2162 if (brightnessContrastRatioHigh > 0)
2168 (
float)brightnessContrastRatioHigh));
2179 (
float)brightnessContrastRatioLow,
2180 (
float)brightnessContrastRatioHigh,
2183 if(contrastValuesOut)
2185 contrastValuesOut->first =
alpha;
2186 contrastValuesOut->second =
beta;
2194 if(clearVertexColorUnderTexture)
2196 int colorOffset = 0;
2197 for(
unsigned int i=0;
i<mesh.cloud.fields.size(); ++
i)
2199 if(mesh.cloud.fields[
i].name.compare(
"rgb") == 0)
2201 colorOffset = mesh.cloud.fields[
i].offset;
2207 pcl::IndicesPtr notTexturedVertexIndices(
new std::vector<int>);
2208 UASSERT(mesh.tex_coordinates.size() == mesh.tex_polygons.size());
2209 for(
size_t t=0;
t<mesh.tex_polygons.size(); ++
t)
2212 for(
size_t p=0;
p<mesh.tex_polygons[
t].size(); ++
p)
2216 for(
size_t v=0;
v<mesh.tex_polygons[
t][
p].vertices.size() && valid; ++
v)
2218 UASSERT(pixelIndex+
v < mesh.tex_coordinates[
t].size());
2219 const Eigen::Vector2f & uv = mesh.tex_coordinates[
t][pixelIndex+
v];
2220 if(uv[0] == -1 || uv[1] == -1)
2227 for(
size_t v=0;
v<mesh.tex_polygons[
t][
p].vertices.size(); ++
v)
2229 int vertex = mesh.tex_polygons[
t][
p].vertices[
v];
2230 notTexturedVertexIndices->push_back(vertex);
2233 pixelIndex+=mesh.tex_polygons[
t][
p].vertices.size();
2237 pcl::IndicesPtr full_indices(
new std::vector<int>(mesh.cloud.width* mesh.cloud.height));
2238 for (
size_t fii = 0; fii < full_indices->size(); ++fii)
2239 full_indices->at(fii) = fii;
2242 std::sort (notTexturedVertexIndices->begin (), notTexturedVertexIndices->end ());
2245 pcl::IndicesPtr texturedVertexIndices(
new std::vector<int>());
2246 std::set_difference (full_indices->begin (), full_indices->end (), notTexturedVertexIndices->begin (), notTexturedVertexIndices->end (), std::inserter (*texturedVertexIndices, texturedVertexIndices->begin ()));
2248 for(
size_t i=0;
i<texturedVertexIndices->size(); ++
i)
2251 UASSERT(texturedVertexIndices->at(
i) * mesh.cloud.point_step + colorOffset < mesh.cloud.data.size());
2252 memcpy(&mesh.cloud.data.data()[texturedVertexIndices->at(
i) * mesh.cloud.point_step + colorOffset],
reinterpret_cast<float*
>(&white),
sizeof(
float));
2258 UDEBUG(
"globalTextures=%d", globalTextures.cols?globalTextures.cols / globalTextures.rows:0);
2259 return globalTextures;
2268 for (
unsigned int t = 0;
t < textureMesh.tex_coordinates.size(); ++
t)
2270 if(textureMesh.tex_polygons[
t].size())
2272 pcl::PointCloud<pcl::PointXYZ>::Ptr originalCloud(
new pcl::PointCloud<pcl::PointXYZ>);
2273 pcl::fromPCLPointCloud2(textureMesh.cloud, *originalCloud);
2276 unsigned int nPoints = textureMesh.tex_coordinates[
t].size();
2277 UASSERT(nPoints == textureMesh.tex_polygons[
t].size()*textureMesh.tex_polygons[
t][0].vertices.size());
2279 pcl::PointCloud<pcl::PointXYZ>::Ptr newCloud(
new pcl::PointCloud<pcl::PointXYZ>);
2280 newCloud->resize(nPoints);
2282 unsigned int oi = 0;
2283 for (
unsigned int i = 0;
i < textureMesh.tex_polygons[
t].size(); ++
i)
2285 pcl::Vertices &
vertices = textureMesh.tex_polygons[
t][
i];
2287 for(
unsigned int j=0;
j<
vertices.vertices.size(); ++
j)
2291 newCloud->at(oi) = originalCloud->at(
vertices.vertices[
j]);
2296 pcl::toPCLPointCloud2(*newCloud, textureMesh.cloud);
2302 const std::string & outputOBJPath,
2303 const pcl::PCLPointCloud2 & cloud,
2304 const std::vector<pcl::Vertices> & polygons,
2305 const std::map<int, Transform> & cameraPoses,
2306 const std::vector<std::map<int, pcl::PointXY> > & vertexToPixels,
2307 const std::map<int, cv::Mat> & images,
2308 const std::map<
int, std::vector<CameraModel> > & cameraModels,
2312 const std::string & textureFormat,
2313 const std::map<
int, std::map<int, cv::Vec4d> > & gains,
2314 const std::map<
int, std::map<int, cv::Mat> > & blendingGains,
2315 const std::pair<float, float> & contrastValues,
2339 const std::string & outputOBJPath,
2340 const pcl::PCLPointCloud2 & cloud,
2341 const std::vector<pcl::Vertices> & polygons,
2342 const std::map<int, Transform> & cameraPoses,
2343 const std::vector<std::map<int, pcl::PointXY> > & vertexToPixels,
2344 const std::map<int, cv::Mat> & images,
2345 const std::map<
int, std::vector<CameraModel> > & cameraModels,
2348 unsigned int textureSize,
2349 unsigned int textureDownScale,
2350 const std::string & nbContrib,
2351 const std::string & textureFormat,
2352 const std::map<
int, std::map<int, cv::Vec4d> > & gains,
2353 const std::map<
int, std::map<int, cv::Mat> > & blendingGains,
2354 const std::pair<float, float> & contrastValues,
2356 unsigned int unwrapMethod,
2358 unsigned int padding,
2359 double bestScoreThreshold,
2360 double angleHardThreshold,
2361 bool forceVisibleByAllVertices)
2364 #ifdef RTABMAP_ALICE_VISION
2367 system::Logger::get()->setLogLevel(system::EVerboseLevel::Trace);
2371 system::Logger::get()->setLogLevel(system::EVerboseLevel::Info);
2375 system::Logger::get()->setLogLevel(system::EVerboseLevel::Warning);
2379 system::Logger::get()->setLogLevel(system::EVerboseLevel::Error);
2382 sfmData::SfMData sfmData;
2383 pcl::PointCloud<pcl::PointXYZRGB> cloud2;
2384 pcl::fromPCLPointCloud2(cloud, cloud2);
2385 UASSERT(vertexToPixels.size() == cloud2.size());
2386 UINFO(
"Input mesh: %d points %d polygons", (
int)cloud2.size(), (
int)polygons.size());
2387 mesh::Texturing texturing;
2388 #if RTABMAP_ALICE_VISION_MAJOR > 2 || (RTABMAP_ALICE_VISION_MAJOR==2 && RTABMAP_ALICE_VISION_MINOR>=3)
2389 texturing.mesh =
new mesh::Mesh();
2390 texturing.mesh->pts.resize(cloud2.size());
2391 texturing.mesh->pointsVisibilities.resize(cloud2.size());
2393 texturing.me =
new mesh::Mesh();
2394 texturing.me->pts =
new StaticVector<Point3d>(cloud2.size());
2395 texturing.pointsVisibilities =
new mesh::PointsVisibility();
2396 texturing.pointsVisibilities->reserve(cloud2.size());
2398 texturing.texParams.textureSide = textureSize;
2399 texturing.texParams.downscale = textureDownScale;
2400 std::vector<int> multiBandNbContrib;
2401 std::list<std::string>
values =
uSplit(nbContrib,
' ');
2406 if(multiBandNbContrib.size() != 4)
2408 UERROR(
"multiband: Wrong number of nb of contribution (vaue=\"%s\", should be 4), using default values instead.", nbContrib.c_str());
2412 texturing.texParams.multiBandNbContrib = multiBandNbContrib;
2414 texturing.texParams.padding = padding;
2415 texturing.texParams.fillHoles = fillHoles;
2416 texturing.texParams.bestScoreThreshold = bestScoreThreshold;
2417 texturing.texParams.angleHardThreshold = angleHardThreshold;
2418 texturing.texParams.forceVisibleByAllVertices = forceVisibleByAllVertices;
2419 texturing.texParams.visibilityRemappingMethod = mesh::EVisibilityRemappingMethod::Pull;
2422 for(
size_t i=0;
i<cloud2.size();++
i)
2424 pcl::PointXYZRGB pt = cloud2.at(
i);
2425 #if RTABMAP_ALICE_VISION_MAJOR > 2 || (RTABMAP_ALICE_VISION_MAJOR==2 && RTABMAP_ALICE_VISION_MINOR>=3)
2426 texturing.mesh->pointsVisibilities[
i].reserve(vertexToPixels[
i].
size());
2427 for(std::map<int, pcl::PointXY>::const_iterator
iter=vertexToPixels[
i].begin();
iter!=vertexToPixels[
i].end();++
iter)
2429 texturing.mesh->pointsVisibilities[
i].push_back(
iter->first);
2431 texturing.mesh->pts[
i] = Point3d(pt.x, pt.y, pt.z);
2433 mesh::PointVisibility* pointVisibility =
new mesh::PointVisibility();
2434 pointVisibility->reserve(vertexToPixels[
i].
size());
2435 for(std::map<int, pcl::PointXY>::const_iterator
iter=vertexToPixels[
i].begin();
iter!=vertexToPixels[
i].end();++
iter)
2437 pointVisibility->push_back(
iter->first);
2439 texturing.pointsVisibilities->push_back(pointVisibility);
2440 (*texturing.me->pts)[
i] = Point3d(pt.x, pt.y, pt.z);
2444 #if RTABMAP_ALICE_VISION_MAJOR > 2 || (RTABMAP_ALICE_VISION_MAJOR==2 && RTABMAP_ALICE_VISION_MINOR>=3)
2445 texturing.mesh->tris.resize(polygons.size());
2446 texturing.mesh->trisMtlIds().resize(polygons.size());
2448 texturing.me->tris =
new StaticVector<mesh::Mesh::triangle>(polygons.size());
2450 for(
size_t i=0;
i<polygons.size();++
i)
2453 #if RTABMAP_ALICE_VISION_MAJOR > 2 || (RTABMAP_ALICE_VISION_MAJOR==2 && RTABMAP_ALICE_VISION_MINOR>=3)
2454 texturing.mesh->trisMtlIds()[
i] = -1;
2455 texturing.mesh->tris[
i] = mesh::Mesh::triangle(
2457 (*texturing.me->tris)[
i] = mesh::Mesh::triangle(
2459 polygons[
i].vertices[0],
2460 polygons[
i].vertices[1],
2461 polygons[
i].vertices[2]);
2465 std::string tmpImageDirectory = outputDirectory+
"/rtabmap_tmp_textures";
2468 UINFO(
"Temporary saving images from %ld nodes in directory \"%s\"...",
cameraPoses.size(), tmpImageDirectory.c_str());
2472 int camId =
iter->first;
2474 std::vector<CameraModel> models;
2476 if( images.find(camId) != images.end() &&
2477 !images.find(camId)->second.empty() &&
2478 cameraModels.find(camId) != cameraModels.end())
2480 image = images.find(camId)->second;
2481 models = cameraModels.find(camId)->second;
2486 models =
data.cameraModels();
2487 if(models.empty() &&
data.stereoCameraModels().size())
2489 for(
size_t i=0;
i<
data.stereoCameraModels().
size(); ++
i)
2491 models.push_back(
data.stereoCameraModels()[
i].left());
2494 if(
data.imageRaw().empty())
2496 image =
data.imageCompressed();
2500 image =
data.imageRaw();
2503 if(models.empty() || image.empty())
2511 std::vector<float> vel;
2514 memory->
getNodeInfo(camId, odomPose, mapId, weight, label, stamp, gt, vel, gps, envs,
true);
2521 std::vector<StereoCameraModel> stereoModels;
2523 if(models.empty() && stereoModels.size())
2525 for(
size_t i=0;
i<stereoModels.size(); ++
i)
2527 models.push_back(stereoModels[
i].left());
2533 if(
data.imageRaw().empty())
2535 image =
data.imageCompressed();
2539 image =
data.imageRaw();
2542 if(models.empty() || image.empty())
2552 UERROR(
"No camera models found for camera %d. Aborting multiband texturing...",
iter->first);
2557 UERROR(
"No image found for camera %d. Aborting multiband texturing...",
iter->first);
2561 if(image.rows == 1 && image.type() == CV_8UC1)
2567 image = image.clone();
2570 for(
size_t i=0;
i<models.size(); ++
i)
2573 cv::Size imageSize =
model.imageSize();
2574 if(imageSize.height == 0)
2577 imageSize.height = image.rows;
2578 imageSize.width = image.cols;
2581 UASSERT(image.cols % imageSize.width == 0);
2582 cv::Mat imageRoi = image.colRange(
i*imageSize.width, (
i+1)*imageSize.width);
2584 if(gains.find(camId) != gains.end() &&
2585 gains.at(camId).find(
i) != gains.at(camId).end())
2587 const cv::Vec4d &
g = gains.at(camId).at(
i);
2588 if(imageRoi.channels() == 1)
2590 cv::multiply(imageRoi,
g.val[0], imageRoi);
2594 std::vector<cv::Mat> channels;
2595 cv::split(imageRoi, channels);
2598 cv::multiply(channels[0],
g.val[gainRGB?3:0], channels[0]);
2599 cv::multiply(channels[1],
g.val[gainRGB?2:0], channels[1]);
2600 cv::multiply(channels[2],
g.val[gainRGB?1:0], channels[2]);
2603 cv::merge(channels, output);
2608 if(blendingGains.find(camId) != blendingGains.end() &&
2609 blendingGains.at(camId).find(
i) != blendingGains.at(camId).end())
2612 if(imageRoi.channels() == 1)
2614 cv::Mat imageRoiColor;
2615 cv::cvtColor(imageRoi, imageRoiColor, CV_GRAY2BGR);
2616 imageRoi = imageRoiColor;
2619 cv::Mat
g = blendingGains.at(camId).at(
i);
2621 cv::blur(
g,
dst, cv::Size(3,3));
2623 cv::resize(
dst, gResized, imageRoi.size(), 0, 0, cv::INTER_LINEAR);
2625 cv::multiply(imageRoi, gResized, output, 1.0, CV_8UC3);
2631 sfmData::CameraPose pose(geometry::Pose3(
m),
true);
2632 sfmData.setAbsolutePose((IndexT)viewId, pose);
2635 std::shared_ptr<camera::IntrinsicBase> camPtr = std::make_shared<camera::Pinhole>(
2636 #
if RTABMAP_ALICE_VISION_MAJOR > 2 || (RTABMAP_ALICE_VISION_MAJOR==2 && RTABMAP_ALICE_VISION_MINOR>=4)
2639 imageSize.width, imageSize.height,
model.fx(),
model.fy(),
model.cx() -
double(imageSize.width) * 0.5,
model.cy() -
double(imageSize.height) * 0.5);
2641 imageSize.width, imageSize.height,
model.fx(),
model.cx(),
model.cy());
2643 sfmData.intrinsics.insert(std::make_pair((IndexT)viewId, camPtr));
2645 std::string imagePath = tmpImageDirectory+
uFormat(
"/%d.jpg", viewId);
2646 cv::imwrite(imagePath, imageRoi);
2647 std::shared_ptr<sfmData::View> viewPtr = std::make_shared<sfmData::View>(
2654 sfmData.views.insert(std::make_pair((IndexT)viewId, viewPtr));
2657 UDEBUG(
"camId=%d", camId);
2659 UINFO(
"Temporary saving images in directory \"%s\"... done (%d images of %d nodes). %fs", tmpImageDirectory.c_str(), viewId, (
int)
cameraPoses.size(),
timer.ticks());
2661 mvsUtils::MultiViewParams mp(sfmData);
2663 UINFO(
"Unwrapping (method=%d=%s)...", unwrapMethod, mesh::EUnwrapMethod_enumToString((mesh::EUnwrapMethod)unwrapMethod).
c_str());
2664 texturing.unwrap(mp, (mesh::EUnwrapMethod)unwrapMethod);
2665 UINFO(
"Unwrapping done. %fs",
timer.ticks());
2669 #if RTABMAP_ALICE_VISION_MAJOR > 2 || (RTABMAP_ALICE_VISION_MAJOR==2 && RTABMAP_ALICE_VISION_MINOR>=4)
2670 texturing.saveAs(outputDirectory, baseName, aliceVision::mesh::EFileType::OBJ, imageIO::EImageFileType::PNG);
2672 texturing.saveAsOBJ(outputDirectory, baseName);
2674 UINFO(
"Saved %s. %fs", outputOBJPath.c_str(),
timer.ticks());
2677 UINFO(
"Generating textures...");
2678 texturing.generateTextures(mp, outputDirectory);
2679 UINFO(
"Generating textures done. %fs",
timer.ticks());
2681 UINFO(
"Cleanup temporary directory \"%s\"...", tmpImageDirectory.c_str());
2690 UINFO(
"Cleanup temporary directory \"%s\"... done.", tmpImageDirectory.c_str());
2692 UINFO(
"Rename/convert textures...");
2693 dir.
setPath(outputDirectory,
"png");
2694 std::map<std::string, std::string> texNames;
2695 std::string outputFormat = textureFormat;
2696 if(outputFormat.front() ==
'.')
2698 outputFormat = outputFormat.substr(1, std::string::npos);
2705 cv::Mat
img = cv::imread(outputDirectory+
"/"+*
iter);
2706 if(contrastValues.first != 0.0f || contrastValues.second != 0.0f)
2710 UINFO(
"Apply contrast values %f %f", contrastValues.first, contrastValues.second);
2711 img.convertTo(
img, -1, contrastValues.first, contrastValues.second);
2713 std::string newName = *
iter;
2714 boost::replace_all(newName,
"png", outputFormat);
2715 boost::replace_all(newName,
"texture", baseName);
2716 texNames.insert(std::make_pair(*
iter, newName));
2717 cv::imwrite(outputDirectory+
"/"+newName,
img);
2721 std::ifstream fi(outputDirectory+
"/"+baseName+
".mtl");
2722 std::string mtlStr((std::istreambuf_iterator<char>(fi)),
2723 std::istreambuf_iterator<char>());
2726 for(std::map<std::string, std::string>::iterator
iter=texNames.begin();
iter!=texNames.end(); ++
iter)
2728 boost::replace_all(mtlStr,
iter->first,
iter->second);
2730 std::ofstream
fo(outputDirectory+
"/"+baseName+
".mtl");
2731 fo.write(mtlStr.c_str(), mtlStr.size());
2733 UINFO(
"Rename/convert textures... done. %fs",
timer.ticks());
2735 #if RTABMAP_ALICE_VISION_MAJOR > 2 || (RTABMAP_ALICE_VISION_MAJOR==2 && RTABMAP_ALICE_VISION_MINOR>=3)
2736 UINFO(
"Cleanup sfmdata...");
2738 UINFO(
"Cleanup sfmdata... done. %fs",
timer.ticks());
2743 UERROR(
"Cannot unwrap texture mesh. RTAB-Map is not built with Alice Vision support! Returning false.");
2758 pcl::PointCloud<pcl::Normal>::Ptr normals;
2775 if(laserScan.
is2d())
2800 if(laserScan.
is2d())
2822 template<
typename Po
intT>
2824 const typename pcl::PointCloud<PointT>::Ptr & cloud,
2825 const pcl::IndicesPtr & indices,
2828 const Eigen::Vector3f & viewPoint)
2830 typename pcl::search::KdTree<PointT>::Ptr
tree (
new pcl::search::KdTree<PointT>);
2837 tree->setInputCloud (cloud);
2842 pcl::NormalEstimationOMP<PointT, pcl::Normal>
n;
2844 pcl::NormalEstimation<PointT, pcl::Normal>
n;
2846 pcl::PointCloud<pcl::Normal>::Ptr normals (
new pcl::PointCloud<pcl::Normal>);
2847 n.setInputCloud (cloud);
2853 n.setSearchMethod (
tree);
2854 n.setKSearch (searchK);
2855 n.setRadiusSearch (searchRadius);
2856 n.setViewPoint(viewPoint[0], viewPoint[1], viewPoint[2]);
2857 n.compute (*normals);
2862 const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
2865 const Eigen::Vector3f & viewPoint)
2867 pcl::IndicesPtr
indices(
new std::vector<int>);
2871 const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
2874 const Eigen::Vector3f & viewPoint)
2876 pcl::IndicesPtr
indices(
new std::vector<int>);
2880 const pcl::PointCloud<pcl::PointXYZI>::Ptr & cloud,
2883 const Eigen::Vector3f & viewPoint)
2885 pcl::IndicesPtr
indices(
new std::vector<int>);
2889 const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
2890 const pcl::IndicesPtr & indices,
2893 const Eigen::Vector3f & viewPoint)
2895 return computeNormalsImpl<pcl::PointXYZ>(cloud,
indices, searchK, searchRadius, viewPoint);
2898 const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
2899 const pcl::IndicesPtr & indices,
2902 const Eigen::Vector3f & viewPoint)
2904 return computeNormalsImpl<pcl::PointXYZRGB>(cloud,
indices, searchK, searchRadius, viewPoint);
2907 const pcl::PointCloud<pcl::PointXYZI>::Ptr & cloud,
2908 const pcl::IndicesPtr & indices,
2911 const Eigen::Vector3f & viewPoint)
2913 return computeNormalsImpl<pcl::PointXYZI>(cloud,
indices, searchK, searchRadius, viewPoint);
2916 template<
typename Po
intT>
2918 const typename pcl::PointCloud<PointT>::Ptr & cloud,
2921 const Eigen::Vector3f & viewPoint)
2923 UASSERT(searchK>0 || searchRadius>0.0
f);
2924 pcl::PointCloud<pcl::Normal>::Ptr normals (
new pcl::PointCloud<pcl::Normal>);
2926 typename pcl::search::KdTree<PointT>::Ptr
tree (
new pcl::search::KdTree<PointT>);
2927 tree->setInputCloud (cloud);
2929 normals->resize(cloud->size());
2931 float bad_point = std::numeric_limits<float>::quiet_NaN ();
2934 for(
unsigned int i=0;
i<cloud->size(); ++
i)
2936 const PointT & pt = cloud->at(
i);
2937 std::vector<Eigen::Vector3f> neighborNormals;
2938 Eigen::Vector3f direction;
2939 direction[0] = viewPoint[0] - pt.x;
2940 direction[1] = viewPoint[1] - pt.y;
2941 direction[2] = viewPoint[2] - pt.z;
2943 std::vector<int> k_indices;
2944 std::vector<float> k_sqr_distances;
2945 if(searchRadius>0.0
f)
2947 tree->radiusSearch(cloud->at(
i), searchRadius, k_indices, k_sqr_distances, searchK);
2951 tree->nearestKSearch(cloud->at(
i), searchK, k_indices, k_sqr_distances);
2954 for(
unsigned int j=0;
j<k_indices.size(); ++
j)
2956 if(k_indices.at(
j) != (
int)
i)
2958 const PointT & pt2 = cloud->at(k_indices.at(
j));
2959 Eigen::Vector3f
v(pt2.x-pt.x, pt2.y - pt.y, pt2.z - pt.z);
2960 Eigen::Vector3f up =
v.cross(direction);
2961 Eigen::Vector3f
n = up.cross(
v);
2963 neighborNormals.push_back(
n);
2967 if(neighborNormals.empty())
2969 normals->at(
i).normal_x = bad_point;
2970 normals->at(
i).normal_y = bad_point;
2971 normals->at(
i).normal_z = bad_point;
2975 Eigen::Vector3f meanNormal(0,0,0);
2976 for(
unsigned int j=0;
j<neighborNormals.size(); ++
j)
2978 meanNormal+=neighborNormals[
j];
2980 meanNormal /= (
float)neighborNormals.size();
2981 meanNormal.normalize();
2982 normals->at(
i).normal_x = meanNormal[0];
2983 normals->at(
i).normal_y = meanNormal[1];
2984 normals->at(
i).normal_z = meanNormal[2];
2991 const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
2994 const Eigen::Vector3f & viewPoint)
2996 return computeNormals2DImpl<pcl::PointXYZ>(cloud, searchK, searchRadius, viewPoint);
2999 const pcl::PointCloud<pcl::PointXYZI>::Ptr & cloud,
3002 const Eigen::Vector3f & viewPoint)
3004 return computeNormals2DImpl<pcl::PointXYZI>(cloud, searchK, searchRadius, viewPoint);
3007 template<
typename Po
intT>
3009 const typename pcl::PointCloud<PointT>::Ptr & cloud,
3012 const Eigen::Vector3f & viewPoint)
3015 pcl::PointCloud<pcl::Normal>::Ptr normals (
new pcl::PointCloud<pcl::Normal>);
3017 normals->resize(cloud->size());
3018 searchRadius *= searchRadius;
3020 float bad_point = std::numeric_limits<float>::quiet_NaN ();
3023 for(
int i=0;
i<(
int)cloud->size(); ++
i)
3031 if(hi>=(
int)cloud->size())
3033 hi=(
int)cloud->size()-1;
3037 const PointT & pt = cloud->at(
i);
3038 std::vector<Eigen::Vector3f> neighborNormals;
3039 Eigen::Vector3f direction;
3040 direction[0] = viewPoint[0] - cloud->at(
i).x;
3041 direction[1] = viewPoint[1] - cloud->at(
i).y;
3042 direction[2] = viewPoint[2] - cloud->at(
i).z;
3043 for(
int j=
i-1;
j>=li; --
j)
3045 const PointT & pt2 = cloud->at(
j);
3046 Eigen::Vector3f vd(pt2.x-pt.x, pt2.y - pt.y, pt2.z - pt.z);
3047 if(searchRadius<=0.0
f || (vd[0]*vd[0] + vd[1]*vd[1] + vd[2]*vd[2]) < searchRadius)
3049 Eigen::Vector3f
v(pt2.x-pt.x, pt2.y - pt.y, pt2.z - pt.z);
3050 Eigen::Vector3f up =
v.cross(direction);
3051 Eigen::Vector3f
n = up.cross(
v);
3053 neighborNormals.push_back(
n);
3060 for(
int j=
i+1;
j<=hi; ++
j)
3062 const PointT & pt2 = cloud->at(
j);
3063 Eigen::Vector3f vd(pt2.x-pt.x, pt2.y - pt.y, pt2.z - pt.z);
3064 if(searchRadius<=0.0
f || (vd[0]*vd[0] + vd[1]*vd[1] + vd[2]*vd[2]) < searchRadius)
3066 Eigen::Vector3f
v(pt2.x-pt.x, pt2.y - pt.y, pt2.z - pt.z);
3067 Eigen::Vector3f up =
v[2]==0.0f?Eigen::Vector3f(0,0,1):
v.cross(direction);
3068 Eigen::Vector3f
n = up.cross(
v);
3070 neighborNormals.push_back(
n);
3078 if(neighborNormals.empty())
3080 normals->at(
i).normal_x = bad_point;
3081 normals->at(
i).normal_y = bad_point;
3082 normals->at(
i).normal_z = bad_point;
3086 Eigen::Vector3f meanNormal(0,0,0);
3087 for(
unsigned int j=0;
j<neighborNormals.size(); ++
j)
3089 meanNormal+=neighborNormals[
j];
3091 meanNormal /= (
float)neighborNormals.size();
3092 meanNormal.normalize();
3093 normals->at(
i).normal_x = meanNormal[0];
3094 normals->at(
i).normal_y = meanNormal[1];
3095 normals->at(
i).normal_z = meanNormal[2];
3103 const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
3106 const Eigen::Vector3f & viewPoint)
3108 return computeFastOrganizedNormals2DImpl<pcl::PointXYZ>(cloud, searchK, searchRadius, viewPoint);
3111 const pcl::PointCloud<pcl::PointXYZI>::Ptr & cloud,
3114 const Eigen::Vector3f & viewPoint)
3116 return computeFastOrganizedNormals2DImpl<pcl::PointXYZI>(cloud, searchK, searchRadius, viewPoint);
3120 const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
3121 float maxDepthChangeFactor,
3122 float normalSmoothingSize,
3123 const Eigen::Vector3f & viewPoint)
3125 pcl::IndicesPtr
indices(
new std::vector<int>);
3129 const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
3130 const pcl::IndicesPtr & indices,
3131 float maxDepthChangeFactor,
3132 float normalSmoothingSize,
3133 const Eigen::Vector3f & viewPoint)
3135 UASSERT(cloud->isOrganized());
3137 pcl::search::KdTree<pcl::PointXYZRGB>::Ptr
tree (
new pcl::search::KdTree<pcl::PointXYZRGB>);
3144 tree->setInputCloud (cloud);
3148 pcl::PointCloud<pcl::Normal>::Ptr normals (
new pcl::PointCloud<pcl::Normal>);
3149 pcl::IntegralImageNormalEstimation<pcl::PointXYZRGB, pcl::Normal> ne;
3150 ne.setNormalEstimationMethod (ne.AVERAGE_3D_GRADIENT);
3151 ne.setMaxDepthChangeFactor(maxDepthChangeFactor);
3152 ne.setNormalSmoothingSize(normalSmoothingSize);
3153 ne.setBorderPolicy(ne.BORDER_POLICY_MIRROR);
3154 ne.setInputCloud(cloud);
3160 ne.setSearchMethod(
tree);
3161 ne.setViewPoint(viewPoint[0], viewPoint[1], viewPoint[2]);
3162 ne.compute(*normals);
3170 cv::Mat * pcaEigenVectors,
3171 cv::Mat * pcaEigenValues)
3176 int sz =
static_cast<int>(scan.
size()*2);
3177 bool is2d = scan.
is2d();
3178 cv::Mat data_normals = cv::Mat::zeros(sz, is2d?2:3, CV_32FC1);
3181 bool doTransform =
false;
3188 for (
int i = 0;
i < scan.
size(); ++
i)
3190 const float * ptrScan = scan.
data().ptr<
float>(0,
i);
3196 cv::Point3f
n(ptrScan[nOffset], ptrScan[nOffset+1], 0);
3201 float * ptr = data_normals.ptr<
float>(oi++, 0);
3210 cv::Point3f
n(ptrScan[nOffset], ptrScan[nOffset+1], ptrScan[nOffset+2]);
3215 float * ptr = data_normals.ptr<
float>(oi++, 0);
3224 cv::PCA pca_analysis(cv::Mat(data_normals, cv::Range(0, oi*2)), cv::Mat(), CV_PCA_DATA_AS_ROW);
3228 *pcaEigenVectors = pca_analysis.eigenvectors;
3232 *pcaEigenValues = pca_analysis.eigenvalues;
3234 UASSERT((is2d && pca_analysis.eigenvalues.total()>=2) || (!is2d && pca_analysis.eigenvalues.total()>=3));
3236 return pca_analysis.eigenvalues.at<
float>(0, is2d?1:2)*(is2d?2.0
f:3.0
f);
3241 UERROR(
"Scan doesn't have normals!");
3247 const pcl::PointCloud<pcl::PointNormal> & cloud,
3250 cv::Mat * pcaEigenVectors,
3251 cv::Mat * pcaEigenValues)
3254 int sz =
static_cast<int>(cloud.size()*2);
3255 cv::Mat data_normals = cv::Mat::zeros(sz, is2d?2:3, CV_32FC1);
3257 bool doTransform =
false;
3259 if(!
t.isIdentity() && !
t.isNull())
3264 for (
unsigned int i = 0;
i < cloud.size(); ++
i)
3266 const pcl::PointNormal & pt = cloud.at(
i);
3267 cv::Point3f
n(pt.normal_x, pt.normal_y, pt.normal_z);
3274 float * ptr = data_normals.ptr<
float>(oi++, 0);
3285 cv::PCA pca_analysis(cv::Mat(data_normals, cv::Range(0, oi*2)), cv::Mat(), CV_PCA_DATA_AS_ROW);
3289 *pcaEigenVectors = pca_analysis.eigenvectors;
3293 *pcaEigenValues = pca_analysis.eigenvalues;
3297 return pca_analysis.eigenvalues.at<
float>(0, is2d?1:2)*(is2d?2.0
f:3.0
f);
3303 const pcl::PointCloud<pcl::Normal> & normals,
3306 cv::Mat * pcaEigenVectors,
3307 cv::Mat * pcaEigenValues)
3310 int sz =
static_cast<int>(normals.size()*2);
3311 cv::Mat data_normals = cv::Mat::zeros(sz, is2d?2:3, CV_32FC1);
3313 bool doTransform =
false;
3320 for (
unsigned int i = 0;
i < normals.size(); ++
i)
3322 const pcl::Normal & pt = normals.at(
i);
3323 cv::Point3f
n(pt.normal_x, pt.normal_y, pt.normal_z);
3330 float * ptr = data_normals.ptr<
float>(oi++, 0);
3341 cv::PCA pca_analysis(cv::Mat(data_normals, cv::Range(0, oi*2)), cv::Mat(), CV_PCA_DATA_AS_ROW);
3345 *pcaEigenVectors = pca_analysis.eigenvectors;
3349 *pcaEigenValues = pca_analysis.eigenvalues;
3353 return pca_analysis.eigenvalues.at<
float>(0, is2d?1:2)*(is2d?2.0
f:3.0
f);
3359 const pcl::PointCloud<pcl::PointXYZINormal> & cloud,
3362 cv::Mat * pcaEigenVectors,
3363 cv::Mat * pcaEigenValues)
3366 int sz =
static_cast<int>(cloud.size()*2);
3367 cv::Mat data_normals = cv::Mat::zeros(sz, is2d?2:3, CV_32FC1);
3369 bool doTransform =
false;
3376 for (
unsigned int i = 0;
i < cloud.size(); ++
i)
3378 const pcl::PointXYZINormal & pt = cloud.at(
i);
3379 cv::Point3f
n(pt.normal_x, pt.normal_y, pt.normal_z);
3386 float * ptr = data_normals.ptr<
float>(oi++, 0);
3397 cv::PCA pca_analysis(cv::Mat(data_normals, cv::Range(0, oi*2)), cv::Mat(), CV_PCA_DATA_AS_ROW);
3401 *pcaEigenVectors = pca_analysis.eigenvectors;
3405 *pcaEigenValues = pca_analysis.eigenvalues;
3409 return pca_analysis.eigenvalues.at<
float>(0, is2d?1:2)*(is2d?2.0
f:3.0
f);
3415 const pcl::PointCloud<pcl::PointXYZRGBNormal> & cloud,
3418 cv::Mat * pcaEigenVectors,
3419 cv::Mat * pcaEigenValues)
3422 int sz =
static_cast<int>(cloud.size()*2);
3423 cv::Mat data_normals = cv::Mat::zeros(sz, is2d?2:3, CV_32FC1);
3425 bool doTransform =
false;
3432 for (
unsigned int i = 0;
i < cloud.size(); ++
i)
3434 const pcl::PointXYZRGBNormal & pt = cloud.at(
i);
3435 cv::Point3f
n(pt.normal_x, pt.normal_y, pt.normal_z);
3442 float * ptr = data_normals.ptr<
float>(oi++, 0);
3453 cv::PCA pca_analysis(cv::Mat(data_normals, cv::Range(0, oi*2)), cv::Mat(), CV_PCA_DATA_AS_ROW);
3457 *pcaEigenVectors = pca_analysis.eigenvectors;
3461 *pcaEigenValues = pca_analysis.eigenvalues;
3465 return pca_analysis.eigenvalues.at<
float>(0, is2d?1:2)*(is2d?2.0
f:3.0
f);
3470 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr
mls(
3471 const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
3473 int polygonialOrder,
3474 int upsamplingMethod,
3475 float upsamplingRadius,
3476 float upsamplingStep,
3478 float dilationVoxelSize,
3479 int dilationIterations)
3481 pcl::IndicesPtr
indices(
new std::vector<int>);
3491 dilationIterations);
3494 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr
mls(
3495 const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
3496 const pcl::IndicesPtr & indices,
3498 int polygonialOrder,
3499 int upsamplingMethod,
3500 float upsamplingRadius,
3501 float upsamplingStep,
3503 float dilationVoxelSize,
3504 int dilationIterations)
3506 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr cloud_with_normals(
new pcl::PointCloud<pcl::PointXYZRGBNormal>);
3507 pcl::search::KdTree<pcl::PointXYZRGB>::Ptr
tree (
new pcl::search::KdTree<pcl::PointXYZRGB>);
3514 tree->setInputCloud (cloud);
3518 pcl::MovingLeastSquares<pcl::PointXYZRGB, pcl::PointXYZRGBNormal>
mls;
3521 mls.setComputeNormals (
true);
3522 if(polygonialOrder > 0)
3524 #if PCL_VERSION_COMPARE(<, 1, 10, 0)
3525 mls.setPolynomialFit (
true);
3527 mls.setPolynomialOrder(polygonialOrder);
3531 #if PCL_VERSION_COMPARE(<, 1, 10, 0)
3532 mls.setPolynomialFit (
false);
3534 mls.setPolynomialOrder(1);
3538 upsamplingMethod <=
mls.VOXEL_GRID_DILATION);
3539 mls.setUpsamplingMethod((pcl::MovingLeastSquares<pcl::PointXYZRGB, pcl::PointXYZRGBNormal>::UpsamplingMethod)upsamplingMethod);
3540 mls.setSearchRadius(searchRadius);
3541 mls.setUpsamplingRadius(upsamplingRadius);
3542 mls.setUpsamplingStepSize(upsamplingStep);
3543 mls.setPointDensity(pointDensity);
3544 mls.setDilationVoxelSize(dilationVoxelSize);
3545 mls.setDilationIterations(dilationIterations);
3548 mls.setInputCloud (cloud);
3554 mls.process (*cloud_with_normals);
3557 for(
unsigned int i=0;
i<cloud_with_normals->size(); ++
i)
3559 Eigen::Vector3f
normal(cloud_with_normals->at(
i).normal_x, cloud_with_normals->at(
i).normal_y, cloud_with_normals->at(
i).normal_z);
3561 cloud_with_normals->at(
i).normal_x =
normal[0];
3562 cloud_with_normals->at(
i).normal_y =
normal[1];
3563 cloud_with_normals->at(
i).normal_z =
normal[2];
3566 return cloud_with_normals;
3571 const Eigen::Vector3f & viewpoint,
3572 bool forceGroundNormalsUp)
3578 const Eigen::Vector3f & viewpoint,
3579 float groundNormalsUp)
3586 cv::Mat output = scan.
data().clone();
3587 #pragma omp parallel for
3592 float * ptr = output.ptr<
float>(
j,
i);
3595 Eigen::Vector3f
v = viewpoint - Eigen::Vector3f(ptr[0], ptr[1], ptr[2]);
3596 Eigen::Vector3f
n(ptr[nx], ptr[ny], ptr[nz]);
3600 || (groundNormalsUp>0.0
f && ptr[nz] < -groundNormalsUp && ptr[2] < viewpoint[2]))
3622 template<
typename Po
intNormalT>
3624 typename pcl::PointCloud<PointNormalT>::Ptr & cloud,
3625 const Eigen::Vector3f & viewpoint,
3626 float groundNormalsUp)
3628 #pragma omp parallel for
3629 for(
int i=0;
i<(
int)cloud->size(); ++
i)
3631 pcl::PointXYZ
normal(cloud->points[
i].normal_x, cloud->points[
i].normal_y, cloud->points[
i].normal_z);
3632 if(pcl::isFinite(
normal))
3634 Eigen::Vector3f
v = viewpoint - cloud->points[
i].getVector3fMap();
3639 || (groundNormalsUp>0.0
f &&
normal.z < -groundNormalsUp && cloud->points[
i].z < viewpoint[2]))
3642 cloud->points[
i].normal_x *= -1.0f;
3643 cloud->points[
i].normal_y *= -1.0f;
3644 cloud->points[
i].normal_z *= -1.0f;
3651 pcl::PointCloud<pcl::PointNormal>::Ptr & cloud,
3652 const Eigen::Vector3f & viewpoint,
3653 bool forceGroundNormalsUp)
3658 pcl::PointCloud<pcl::PointNormal>::Ptr & cloud,
3659 const Eigen::Vector3f & viewpoint,
3660 float groundNormalsUp)
3662 adjustNormalsToViewPointImpl<pcl::PointNormal>(cloud, viewpoint, groundNormalsUp);
3666 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud,
3667 const Eigen::Vector3f & viewpoint,
3668 bool forceGroundNormalsUp)
3673 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud,
3674 const Eigen::Vector3f & viewpoint,
3675 float groundNormalsUp)
3677 adjustNormalsToViewPointImpl<pcl::PointXYZRGBNormal>(cloud, viewpoint, groundNormalsUp);
3681 pcl::PointCloud<pcl::PointXYZINormal>::Ptr & cloud,
3682 const Eigen::Vector3f & viewpoint,
3683 bool forceGroundNormalsUp)
3688 pcl::PointCloud<pcl::PointXYZINormal>::Ptr & cloud,
3689 const Eigen::Vector3f & viewpoint,
3690 float groundNormalsUp)
3692 adjustNormalsToViewPointImpl<pcl::PointXYZINormal>(cloud, viewpoint, groundNormalsUp);
3695 template<
typename Po
intT>
3697 const std::map<int, Transform> & poses,
3698 const std::vector<int> & cameraIndices,
3699 typename pcl::PointCloud<PointT>::Ptr & cloud,
3700 float groundNormalsUp)
3702 if(poses.size() && cloud->size() == cameraIndices.size() && cloud->size())
3704 #pragma omp parallel for
3705 for(
int i=0;
i<(
int)cloud->size(); ++
i)
3707 pcl::PointXYZ
normal(cloud->points[
i].normal_x, cloud->points[
i].normal_y, cloud->points[
i].normal_z);
3708 if(pcl::isFinite(
normal))
3711 pcl::PointXYZ viewpoint(
p.x(),
p.y(),
p.z());
3712 Eigen::Vector3f
v = viewpoint.getVector3fMap() - cloud->points[
i].getVector3fMap();
3718 (groundNormalsUp>0.0
f &&
normal.z < -groundNormalsUp && cloud->points[
i].z < viewpoint.z))
3721 cloud->points[
i].normal_x *= -1.0f;
3722 cloud->points[
i].normal_y *= -1.0f;
3723 cloud->points[
i].normal_z *= -1.0f;
3731 const std::map<int, Transform> & poses,
3732 const std::vector<int> & cameraIndices,
3733 pcl::PointCloud<pcl::PointNormal>::Ptr & cloud,
3734 float groundNormalsUp)
3736 adjustNormalsToViewPointsImpl<pcl::PointNormal>(poses, cameraIndices, cloud, groundNormalsUp);
3740 const std::map<int, Transform> & poses,
3741 const std::vector<int> & cameraIndices,
3742 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud,
3743 float groundNormalsUp)
3745 adjustNormalsToViewPointsImpl<pcl::PointXYZRGBNormal>(poses, cameraIndices, cloud, groundNormalsUp);
3749 const std::map<int, Transform> & poses,
3750 const std::vector<int> & cameraIndices,
3751 pcl::PointCloud<pcl::PointXYZINormal>::Ptr & cloud,
3752 float groundNormalsUp)
3754 adjustNormalsToViewPointsImpl<pcl::PointXYZINormal>(poses, cameraIndices, cloud, groundNormalsUp);
3757 template<
typename Po
intT>
3759 const std::map<int, Transform> & poses,
3760 const pcl::PointCloud<pcl::PointXYZ>::Ptr & rawCloud,
3761 const std::vector<int> & rawCameraIndices,
3762 typename pcl::PointCloud<PointT>::Ptr & cloud,
3763 float groundNormalsUp)
3765 if(poses.size() && rawCloud->size() && rawCloud->size() == rawCameraIndices.size() && cloud->size())
3767 pcl::search::KdTree<pcl::PointXYZ>::Ptr rawTree (
new pcl::search::KdTree<pcl::PointXYZ>);
3768 rawTree->setInputCloud (rawCloud);
3770 #pragma omp parallel for
3771 for(
int i=0;
i<(
int)cloud->size(); ++
i)
3773 pcl::PointXYZ
normal(cloud->points[
i].normal_x, cloud->points[
i].normal_y, cloud->points[
i].normal_z);
3774 if(pcl::isFinite(
normal))
3777 std::vector<float>
dist;
3778 rawTree->nearestKSearch(pcl::PointXYZ(cloud->points[
i].x, cloud->points[
i].y, cloud->points[
i].z), 1,
indices,
dist);
3783 pcl::PointXYZ viewpoint(
p.x(),
p.y(),
p.z());
3784 Eigen::Vector3f
v = viewpoint.getVector3fMap() - cloud->points[
i].getVector3fMap();
3790 (groundNormalsUp>0.0
f &&
normal.z < -groundNormalsUp && cloud->points[
i].z < viewpoint.z))
3793 cloud->points[
i].normal_x *= -1.0f;
3794 cloud->points[
i].normal_y *= -1.0f;
3795 cloud->points[
i].normal_z *= -1.0f;
3800 UWARN(
"Not found camera viewpoint for point %d",
i);
3808 const std::map<int, Transform> & poses,
3809 const pcl::PointCloud<pcl::PointXYZ>::Ptr & rawCloud,
3810 const std::vector<int> & rawCameraIndices,
3811 pcl::PointCloud<pcl::PointNormal>::Ptr & cloud,
3812 float groundNormalsUp)
3814 adjustNormalsToViewPointsImpl<pcl::PointNormal>(poses, rawCloud, rawCameraIndices, cloud, groundNormalsUp);
3818 const std::map<int, Transform> & poses,
3819 const pcl::PointCloud<pcl::PointXYZ>::Ptr & rawCloud,
3820 const std::vector<int> & rawCameraIndices,
3821 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud,
3822 float groundNormalsUp)
3824 adjustNormalsToViewPointsImpl<pcl::PointXYZRGBNormal>(poses, rawCloud, rawCameraIndices, cloud, groundNormalsUp);
3828 const std::map<int, Transform> & poses,
3829 const pcl::PointCloud<pcl::PointXYZ>::Ptr & rawCloud,
3830 const std::vector<int> & rawCameraIndices,
3831 pcl::PointCloud<pcl::PointXYZINormal>::Ptr & cloud,
3832 float groundNormalsUp)
3834 adjustNormalsToViewPointsImpl<pcl::PointXYZINormal>(poses, rawCloud, rawCameraIndices, cloud, groundNormalsUp);
3838 const std::map<int, Transform> & viewpoints,
3840 const std::vector<int> & viewpointIds,
3842 float groundNormalsUp)
3844 UDEBUG(
"poses=%d, rawCloud=%d, rawCameraIndices=%d, cloud=%d", (
int)viewpoints.size(), (
int)rawScan.
size(), (
int)viewpointIds.size(), (
int)scan.
size());
3845 if(viewpoints.size() && rawScan.
size() && rawScan.
size() == (
int)viewpointIds.size() && scan.
size() && scan.
hasNormals())
3848 pcl::search::KdTree<pcl::PointXYZ>::Ptr rawTree (
new pcl::search::KdTree<pcl::PointXYZ>);
3849 rawTree->setInputCloud (rawCloud);
3850 #pragma omp parallel for
3851 for(
int i=0;
i<scan.
size(); ++
i)
3855 if(pcl::isFinite(
normal))
3858 std::vector<float>
dist;
3865 pcl::PointXYZ viewpoint(
p.x(),
p.y(),
p.z());
3866 Eigen::Vector3f
v = viewpoint.getVector3fMap() -
point.getVector3fMap();
3872 (groundNormalsUp>0.0
f &&
normal.z < -groundNormalsUp &&
point.z < viewpoint.z))
3882 UWARN(
"Not found camera viewpoint for point %d!?",
i);
3889 pcl::PolygonMesh::Ptr
meshDecimation(
const pcl::PolygonMesh::Ptr & mesh,
float factor)
3891 pcl::PolygonMesh::Ptr output(
new pcl::PolygonMesh);
3893 pcl::MeshQuadricDecimationVTK mqd;
3894 mqd.setTargetReductionFactor(
factor);
3895 mqd.setInputMesh(mesh);
3896 mqd.process (*output);
3898 UWARN(
"RTAB-Map is not built with VTK module so mesh decimation cannot be used!");
3905 const Eigen::Vector3f & p,
3906 const Eigen::Vector3f & dir,
3907 const Eigen::Vector3f & v0,
3908 const Eigen::Vector3f & v1,
3909 const Eigen::Vector3f & v2,
3911 Eigen::Vector3f & normal)
3914 const Eigen::Vector3f u =
v1-v0;
3915 const Eigen::Vector3f
v =
v2-v0;
3917 if (
normal == Eigen::Vector3f(0,0,0))
3920 const float denomimator =
normal.dot(dir);
3921 if (
fabs(denomimator) < 10
e-9)
3930 float uu, uv, vv, wu, wv,
D;
3934 const Eigen::Vector3f
w =
p + dir *
distance - v0;
3937 D = uv * uv - uu * vv;
3941 s = (uv * wv - vv * wu) /
D;
3942 if (s < 0.0 || s > 1.0)
3944 t = (uv * wu - uu * wv) /
D;
3945 if (
t < 0.0 || (
s +
t) > 1.0)
3956 const std::string &file_name,
3957 const pcl::TextureMesh &tex_mesh,
3960 if (tex_mesh.cloud.data.empty ())
3962 UERROR (
"Input point cloud has no data!\n");
3968 fs.open (file_name.c_str ());
3971 std::string mtl_file_name = file_name.substr (0, file_name.find_last_of (
'.')) +
".mtl";
3973 std::string mtl_file_name_nopath = mtl_file_name;
3974 mtl_file_name_nopath.erase (0, mtl_file_name.find_last_of (
'/') + 1);
3978 unsigned nr_points = tex_mesh.cloud.width * tex_mesh.cloud.height;
3979 unsigned point_size =
static_cast<unsigned> (tex_mesh.cloud.data.size () / nr_points);
3982 unsigned nr_meshes =
static_cast<unsigned> (tex_mesh.tex_polygons.size ());
3984 unsigned nr_faces = 0;
3985 for (
unsigned m = 0;
m < nr_meshes; ++
m)
3986 nr_faces +=
static_cast<unsigned> (tex_mesh.tex_polygons[
m].size ());
3989 fs <<
"####" <<
'\n';
3990 fs <<
"# OBJ dataFile simple version. File name: " << file_name <<
'\n';
3991 fs <<
"# Vertices: " << nr_points <<
'\n';
3992 fs <<
"# Faces: " <<nr_faces <<
'\n';
3993 fs <<
"# Material information:" <<
'\n';
3994 fs <<
"mtllib " << mtl_file_name_nopath <<
'\n';
3995 fs <<
"####" <<
'\n';
3998 fs <<
"# Vertices" <<
'\n';
3999 for (
unsigned i = 0;
i < nr_points; ++
i)
4003 bool v_written =
false;
4004 for (std::size_t
d = 0;
d < tex_mesh.cloud.fields.size (); ++
d)
4007 if ((tex_mesh.cloud.fields[
d].datatype == pcl::PCLPointField::FLOAT32) && (
4008 tex_mesh.cloud.fields[
d].name ==
"x" ||
4009 tex_mesh.cloud.fields[
d].name ==
"y" ||
4010 tex_mesh.cloud.fields[
d].name ==
"z"))
4019 memcpy (&
value, &tex_mesh.cloud.data[
i * point_size + tex_mesh.cloud.fields[
d].offset], sizeof (
float));
4025 else if(tex_mesh.cloud.fields[
d].datatype == pcl::PCLPointField::FLOAT32 &&
4026 tex_mesh.cloud.fields[
d].name ==
"rgb")
4028 std::uint32_t rgb = *
reinterpret_cast<const int*
>(&tex_mesh.cloud.data[
i * point_size + tex_mesh.cloud.fields[
d].offset]);
4032 fs <<
" " <<
float(r)/255.0f <<
" " <<
float(
g)/255.0f <<
" " <<
float(
b)/255.0f;
4038 UERROR (
"Input point cloud has no XYZ data!\n");
4043 fs <<
"# "<< nr_points <<
" vertices" <<
'\n';
4046 for (
unsigned i = 0;
i < nr_points; ++
i)
4050 bool v_written =
false;
4051 for (std::size_t
d = 0;
d < tex_mesh.cloud.fields.size (); ++
d)
4054 if ((tex_mesh.cloud.fields[
d].datatype == pcl::PCLPointField::FLOAT32) && (
4055 tex_mesh.cloud.fields[
d].name ==
"normal_x" ||
4056 tex_mesh.cloud.fields[
d].name ==
"normal_y" ||
4057 tex_mesh.cloud.fields[
d].name ==
"normal_z"))
4066 memcpy (&
value, &tex_mesh.cloud.data[
i * point_size + tex_mesh.cloud.fields[
d].offset], sizeof (
float));
4075 UERROR (
"Input point cloud has no normals!\n");
4082 for (
unsigned m = 0;
m < nr_meshes; ++
m)
4084 fs <<
"# " << tex_mesh.tex_coordinates[
m].size() <<
" vertex textures in submesh " <<
m <<
'\n';
4085 for (
const auto &
coordinate : tex_mesh.tex_coordinates[
m])
4095 for (
unsigned m = 0;
m < nr_meshes; ++
m)
4097 if (
m > 0) f_idx +=
static_cast<unsigned> (tex_mesh.tex_polygons[
m-1].size ());
4099 fs <<
"# The material will be used for mesh " <<
m <<
'\n';
4100 fs <<
"usemtl " << tex_mesh.tex_materials[
m].tex_name <<
'\n';
4101 fs <<
"# Faces" <<
'\n';
4103 for (std::size_t
i = 0;
i < tex_mesh.tex_polygons[
m].size(); ++
i)
4109 for (std::size_t
j = 0;
j < tex_mesh.tex_polygons[
m][
i].vertices.size (); ++
j)
4113 <<
"/" << tex_mesh.tex_polygons[
m][
i].vertices.size () * (
i+f_idx) +
j+1
4118 fs <<
"# "<< tex_mesh.tex_polygons[
m].size() <<
" faces in mesh " <<
m <<
'\n';
4120 fs <<
"# End of File" << std::flush;
4130 m_fs.open (mtl_file_name.c_str ());
4133 m_fs <<
"#" <<
'\n';
4134 m_fs <<
"# Wavefront material file" <<
'\n';
4135 m_fs <<
"#" <<
'\n';
4136 for(
unsigned m = 0;
m < nr_meshes; ++
m)
4138 m_fs <<
"newmtl " << tex_mesh.tex_materials[
m].tex_name <<
'\n';
4139 m_fs <<
"Ka "<< tex_mesh.tex_materials[
m].tex_Ka.r <<
" " << tex_mesh.tex_materials[
m].tex_Ka.g <<
" " << tex_mesh.tex_materials[
m].tex_Ka.b <<
'\n';
4140 m_fs <<
"Kd "<< tex_mesh.tex_materials[
m].tex_Kd.r <<
" " << tex_mesh.tex_materials[
m].tex_Kd.g <<
" " << tex_mesh.tex_materials[
m].tex_Kd.b <<
'\n';
4141 m_fs <<
"Ks "<< tex_mesh.tex_materials[
m].tex_Ks.r <<
" " << tex_mesh.tex_materials[
m].tex_Ks.g <<
" " << tex_mesh.tex_materials[
m].tex_Ks.b <<
'\n';
4142 m_fs <<
"d " << tex_mesh.tex_materials[
m].tex_d <<
'\n';
4143 m_fs <<
"Ns "<< tex_mesh.tex_materials[
m].tex_Ns <<
'\n';
4144 m_fs <<
"illum "<< tex_mesh.tex_materials[
m].tex_illum <<
'\n';
4147 m_fs <<
"map_Kd " << tex_mesh.tex_materials[
m].tex_file <<
'\n';
4148 m_fs <<
"###" <<
'\n';
4159 const std::string &file_name,
4160 const pcl::PolygonMesh &mesh,
4163 if (mesh.cloud.data.empty ())
4165 UERROR (
"Input point cloud has no data!\n");
4171 fs.open (file_name.c_str ());
4175 int nr_points = mesh.cloud.width * mesh.cloud.height;
4177 unsigned point_size =
static_cast<unsigned> (mesh.cloud.data.size () / nr_points);
4179 unsigned nr_faces =
static_cast<unsigned> (mesh.polygons.size ());
4181 int normal_index = getFieldIndex (mesh.cloud,
"normal_x");
4184 fs <<
"####" <<
'\n';
4185 fs <<
"# OBJ dataFile simple version. File name: " << file_name <<
'\n';
4186 fs <<
"# Vertices: " << nr_points <<
'\n';
4187 if (normal_index != -1)
4188 fs <<
"# Vertices normals : " << nr_points <<
'\n';
4189 fs <<
"# Faces: " <<nr_faces <<
'\n';
4190 fs <<
"####" <<
'\n';
4193 fs <<
"# List of Vertices, with (x,y,z) coordinates, w is optional." <<
'\n';
4194 for (
int i = 0;
i < nr_points; ++
i)
4197 for (std::size_t
d = 0;
d < mesh.cloud.fields.size (); ++
d)
4200 if ((mesh.cloud.fields[
d].datatype == pcl::PCLPointField::FLOAT32) && (
4201 mesh.cloud.fields[
d].name ==
"x" ||
4202 mesh.cloud.fields[
d].name ==
"y" ||
4203 mesh.cloud.fields[
d].name ==
"z"))
4205 if (mesh.cloud.fields[
d].name ==
"x")
4210 memcpy (&
value, &mesh.cloud.data[
i * point_size + mesh.cloud.fields[
d].offset], sizeof (
float));
4216 else if(mesh.cloud.fields[
d].datatype == pcl::PCLPointField::FLOAT32 &&
4217 mesh.cloud.fields[
d].name ==
"rgb")
4219 std::uint32_t rgb = *
reinterpret_cast<const int*
>(&mesh.cloud.data[
i * point_size + mesh.cloud.fields[
d].offset]);
4223 fs <<
" " <<
float(r)/255.0f <<
" " <<
float(
g)/255.0f <<
" " <<
float(
b)/255.0f;
4229 UERROR (
"Input point cloud has no XYZ data!\n");
4235 fs <<
"# "<< nr_points <<
" vertices" <<
'\n';
4237 if(normal_index != -1)
4239 fs <<
"# Normals in (x,y,z) form; normals might not be unit." <<
'\n';
4241 for (
int i = 0;
i < nr_points; ++
i)
4244 for (std::size_t
d = 0;
d < mesh.cloud.fields.size (); ++
d)
4247 if ((mesh.cloud.fields[
d].datatype == pcl::PCLPointField::FLOAT32) && (
4248 mesh.cloud.fields[
d].name ==
"normal_x" ||
4249 mesh.cloud.fields[
d].name ==
"normal_y" ||
4250 mesh.cloud.fields[
d].name ==
"normal_z"))
4252 if (mesh.cloud.fields[
d].name ==
"normal_x")
4257 memcpy (&
value, &mesh.cloud.data[
i * point_size + mesh.cloud.fields[
d].offset], sizeof (
float));
4266 UERROR (
"Input point cloud has no normals!\n");
4272 fs <<
"# "<< nr_points <<
" vertices normals" <<
'\n';
4275 fs <<
"# Face Definitions" <<
'\n';
4277 if(normal_index == -1)
4279 for(
unsigned i = 0;
i < nr_faces;
i++)
4282 for (std::size_t
j = 0;
j < mesh.polygons[
i].vertices.size () - 1; ++
j)
4283 fs << mesh.polygons[
i].vertices[
j] + 1 <<
" ";
4284 fs << mesh.polygons[
i].vertices.back() + 1 <<
'\n';
4289 for(
unsigned i = 0;
i < nr_faces;
i++)
4292 for (std::size_t
j = 0;
j < mesh.polygons[
i].vertices.size () - 1; ++
j)
4293 fs << mesh.polygons[
i].vertices[
j] + 1 <<
"//" << mesh.polygons[
i].vertices[
j] + 1 <<
" ";
4294 fs << mesh.polygons[
i].vertices.back() + 1 <<
"//" << mesh.polygons[
i].vertices.back() + 1 <<
'\n';
4297 fs <<
"# End of File" << std::endl;