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());
668 cameras.push_back(
cam);
676 const pcl::PolygonMesh::Ptr & mesh,
677 const std::map<int, Transform> & poses,
678 const std::map<int, CameraModel> & cameraModels,
679 const std::map<int, cv::Mat> & cameraDepths,
684 const std::vector<float> & roiRatios,
686 std::vector<std::map<int, pcl::PointXY> > * vertexToPixels,
687 bool distanceToCamPolicy)
689 std::map<int, std::vector<CameraModel> > cameraSubModels;
690 for(std::map<int, CameraModel>::const_iterator
iter=cameraModels.begin();
iter!=cameraModels.end(); ++
iter)
692 std::vector<CameraModel> models;
693 models.push_back(
iter->second);
694 cameraSubModels.insert(std::make_pair(
iter->first, models));
709 distanceToCamPolicy);
713 const pcl::PolygonMesh::Ptr & mesh,
714 const std::map<int, Transform> & poses,
715 const std::map<
int, std::vector<CameraModel> > & cameraModels,
716 const std::map<int, cv::Mat> & cameraDepths,
721 const std::vector<float> & roiRatios,
723 std::vector<std::map<int, pcl::PointXY> > * vertexToPixels,
724 bool distanceToCamPolicy)
726 UASSERT(mesh->polygons.size());
727 pcl::TextureMesh::Ptr textureMesh(
new pcl::TextureMesh);
728 textureMesh->cloud = mesh->cloud;
729 textureMesh->tex_polygons.push_back(mesh->polygons);
744 textureMesh->tex_materials.resize (cameras.size () + 1);
745 for(
unsigned int i = 0 ;
i <= cameras.size() ; ++
i)
747 pcl::TexMaterial mesh_material;
748 mesh_material.tex_Ka.r = 0.2f;
749 mesh_material.tex_Ka.g = 0.2f;
750 mesh_material.tex_Ka.b = 0.2f;
752 mesh_material.tex_Kd.r = 0.8f;
753 mesh_material.tex_Kd.g = 0.8f;
754 mesh_material.tex_Kd.b = 0.8f;
756 mesh_material.tex_Ks.r = 1.0f;
757 mesh_material.tex_Ks.g = 1.0f;
758 mesh_material.tex_Ks.b = 1.0f;
760 mesh_material.tex_d = 1.0f;
761 mesh_material.tex_Ns = 75.0f;
762 mesh_material.tex_illum = 2;
764 std::stringstream tex_name;
765 tex_name <<
"material_" <<
i;
766 tex_name >> mesh_material.tex_name;
768 if(
i < cameras.size ())
770 mesh_material.tex_file = cameras[
i].texture_file;
774 mesh_material.tex_file =
"occluded";
777 textureMesh->tex_materials[
i] = mesh_material;
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);
1104 float factor = 0.1f;
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 std::map<
int, std::map<int, cv::Vec4d> > * gains,
1458 std::map<
int, std::map<int, cv::Mat> > * blendingGains,
1459 std::pair<float, float> * contrastValues)
1461 std::map<int, std::vector<CameraModel> > calibVectors;
1462 for(std::map<int, CameraModel>::const_iterator
iter=calibrations.begin();
iter!=calibrations.end(); ++
iter)
1464 std::vector<CameraModel>
m;
1465 m.push_back(
iter->second);
1466 calibVectors.insert(std::make_pair(
iter->first,
m));
1481 brightnessContrastRatioLow,
1482 brightnessContrastRatioHigh,
1491 pcl::TextureMesh & mesh,
1492 const std::map<int, cv::Mat> & images,
1493 const std::map<
int, std::vector<CameraModel> > & calibrations,
1498 const std::vector<std::map<int, pcl::PointXY> > & vertexToPixels,
1499 bool gainCompensation,
1503 int blendingDecimation,
1504 int brightnessContrastRatioLow,
1505 int brightnessContrastRatioHigh,
1508 unsigned char blankValue,
1509 std::map<
int, std::map<int, cv::Vec4d> > * gainsOut,
1510 std::map<
int, std::map<int, cv::Mat> > * blendingGainsOut,
1511 std::pair<float, float> * contrastValuesOut)
1514 UASSERT(textureSize%256 == 0);
1515 UDEBUG(
"textureSize = %d", textureSize);
1516 cv::Mat globalTextures;
1517 if(!mesh.tex_materials.empty())
1519 std::vector<std::pair<int, int> > textures(mesh.tex_materials.size(), std::pair<int, int>(-1,0));
1521 const int imageType=CV_8UC3;
1524 for(
unsigned int i=0;
i<mesh.tex_materials.size(); ++
i)
1526 std::list<std::string> texFileSplit =
uSplit(mesh.tex_materials[
i].tex_file,
'_');
1527 if(!mesh.tex_materials[
i].tex_file.empty() &&
1528 mesh.tex_polygons[
i].size() &&
1531 textures[
i].first =
uStr2Int(texFileSplit.front());
1532 if(texFileSplit.size() == 2 &&
1535 textures[
i].second =
uStr2Int(texFileSplit.back());
1538 int textureId = textures[
i].first;
1539 if(imageSize.width == 0 || imageSize.height == 0)
1541 if(images.find(textureId) != images.end() &&
1542 !images.find(textureId)->second.empty() &&
1543 calibrations.find(textureId) != calibrations.end())
1545 const std::vector<CameraModel> & models = calibrations.find(textureId)->second;
1547 if( models[0].imageHeight()>0 &&
1548 models[0].imageWidth()>0)
1550 imageSize = models[0].imageSize();
1552 else if(images.find(textureId)!=images.end())
1555 cv::Mat image = images.find(textureId)->second;
1556 if(image.rows == 1 && image.type() == CV_8UC1)
1561 imageSize = image.size();
1564 imageSize.width/=models.size();
1571 const std::vector<CameraModel> & models =
data.cameraModels();
1572 const std::vector<StereoCameraModel> & stereoModels =
data.stereoCameraModels();
1573 if(models.size()>=1 &&
1574 models[0].imageHeight()>0 &&
1575 models[0].imageWidth()>0)
1577 imageSize = models[0].imageSize();
1579 else if(stereoModels.size()>=1 &&
1580 stereoModels[0].left().imageHeight() > 0 &&
1581 stereoModels[0].left().imageWidth() > 0)
1583 imageSize = stereoModels[0].left().imageSize();
1588 data.uncompressDataConst(&image, 0);
1590 imageSize = image.size();
1591 if(
data.cameraModels().size()>1)
1593 imageSize.width/=
data.cameraModels().size();
1599 std::vector<CameraModel> models;
1600 std::vector<StereoCameraModel> stereoModels;
1602 if(models.size()>=1 &&
1603 models[0].imageHeight()>0 &&
1604 models[0].imageWidth()>0)
1606 imageSize = models[0].imageSize();
1608 else if(stereoModels.size()>=1 &&
1609 stereoModels[0].left().imageHeight() > 0 &&
1610 stereoModels[0].left().imageWidth() > 0)
1612 imageSize = stereoModels[0].left().imageSize();
1619 data.uncompressDataConst(&image, 0);
1621 imageSize = image.size();
1622 if(
data.cameraModels().size()>1)
1624 imageSize.width/=
data.cameraModels().size();
1630 else if(mesh.tex_polygons[
i].size() && mesh.tex_materials[
i].tex_file.compare(
"occluded")!=0)
1632 UWARN(
"Failed parsing texture file name: %s", mesh.tex_materials[
i].tex_file.c_str());
1635 UDEBUG(
"textures=%d imageSize=%dx%d", (
int)textures.size(), imageSize.height, imageSize.width);
1636 if(textures.size() && imageSize.height>0 && imageSize.width>0)
1640 std::vector<bool> materialsKept;
1644 int materials = (
int)mesh.tex_materials.size();
1648 globalTextures = cv::Mat(textureSize, materials*textureSize, imageType,
cv::Scalar::all(blankValue));
1649 cv::Mat globalTextureMasks = cv::Mat(textureSize, materials*textureSize, CV_8UC1,
cv::Scalar::all(0));
1652 cv::Mat previousImage;
1653 int previousTextureId = 0;
1654 std::vector<CameraModel> previousCameraModels;
1660 std::vector<cv::Point2i> imageOrigin(textures.size());
1661 std::vector<int> newCamIndex(textures.size(), -1);
1662 for(
int t=0;
t<(
int)textures.size(); ++
t)
1664 if(materialsKept.at(
t))
1666 int indexMaterial = oi / (
cols*
rows);
1667 UASSERT(indexMaterial < materials);
1669 newCamIndex[
t] = oi;
1670 int u = oi%
cols * emptyImage.cols;
1671 int v = ((oi/
cols) %
rows ) * emptyImage.rows;
1672 UASSERT_MSG(u < textureSize-emptyImage.cols,
uFormat(
"u=%d textureSize=%d emptyImage.cols=%d", u, textureSize, emptyImage.cols).c_str());
1673 UASSERT_MSG(
v < textureSize-emptyImage.rows,
uFormat(
"v=%d textureSize=%d emptyImage.rows=%d",
v, textureSize, emptyImage.rows).c_str());
1674 imageOrigin[
t].x = u;
1675 imageOrigin[
t].y =
v;
1679 std::vector<CameraModel> models;
1681 if(textures[
t].
first == previousTextureId)
1683 image = previousImage;
1684 models = previousCameraModels;
1688 if(images.find(textures[
t].first) != images.end() &&
1689 !images.find(textures[
t].first)->second.empty() &&
1690 calibrations.find(textures[
t].first) != calibrations.end())
1692 image = images.find(textures[
t].
first)->second;
1693 if(image.rows == 1 && image.type() == CV_8UC1)
1697 models = calibrations.find(textures[
t].
first)->second;
1702 models =
data.cameraModels();
1703 if(models.empty() && !
data.stereoCameraModels().empty())
1705 for(
size_t i=0;
i<
data.stereoCameraModels().
size(); ++
i)
1707 models.push_back(
data.stereoCameraModels()[
i].left());
1710 data.uncompressDataConst(&image, 0);
1716 data.uncompressDataConst(&image, 0);
1717 std::vector<StereoCameraModel> stereoModels;
1719 if(models.empty() && !stereoModels.empty())
1721 for(
size_t i=0;
i<stereoModels.size(); ++
i)
1723 models.push_back(stereoModels[
i].left());
1728 previousImage = image;
1729 previousCameraModels = models;
1730 previousTextureId = textures[
t].first;
1738 int width = image.cols/models.size();
1739 image = image.colRange(width*textures[
t].
second, width*(textures[
t].
second+1));
1742 cv::Mat resizedImage;
1743 cv::resize(image, resizedImage, emptyImage.size(), 0.0f, 0.0f, cv::INTER_AREA);
1744 UASSERT(resizedImage.type() == CV_8UC1 || resizedImage.type() == CV_8UC3);
1745 if(resizedImage.type() == CV_8UC1)
1747 cv::Mat resizedImageColor;
1748 cv::cvtColor(resizedImage, resizedImageColor, CV_GRAY2BGR);
1749 resizedImage = resizedImageColor;
1751 UASSERT(resizedImage.type() == globalTextures.type());
1752 resizedImage.copyTo(globalTextures(cv::Rect(u+indexMaterial*globalTextures.rows,
v, resizedImage.cols, resizedImage.rows)));
1753 emptyImageMask.copyTo(globalTextureMasks(cv::Rect(u+indexMaterial*globalTextureMasks.rows,
v, resizedImage.cols, resizedImage.rows)));
1757 emptyImage.copyTo(globalTextures(cv::Rect(u+indexMaterial*globalTextures.rows,
v, emptyImage.cols, emptyImage.rows)));
1773 if(vertexToPixels.size())
1778 if(gainCompensation)
1784 const int num_images =
static_cast<int>(oi);
1785 cv::Mat_<int>
N(num_images, num_images);
N.setTo(0);
1786 cv::Mat_<double>
I(num_images, num_images);
I.setTo(0);
1788 cv::Mat_<double> IR(num_images, num_images); IR.setTo(0);
1789 cv::Mat_<double> IG(num_images, num_images); IG.setTo(0);
1790 cv::Mat_<double> IB(num_images, num_images); IB.setTo(0);
1793 for(
unsigned int p=0;
p<vertexToPixels.size(); ++
p)
1795 for(std::map<int, pcl::PointXY>::const_iterator
iter=vertexToPixels[
p].begin();
iter!=vertexToPixels[
p].end(); ++
iter)
1797 if(materialsKept.at(
iter->first))
1799 N(newCamIndex[
iter->first], newCamIndex[
iter->first]) +=1;
1801 std::map<int, pcl::PointXY>::const_iterator jter=
iter;
1804 for(; jter!=vertexToPixels[
p].end(); ++jter, ++k)
1806 if(materialsKept.at(jter->first))
1808 int i = newCamIndex[
iter->first];
1809 int j = newCamIndex[jter->first];
1817 int ui =
iter->second.x*emptyImage.cols + imageOrigin[
iter->first].x;
1818 int vi = (1.0-
iter->second.y)*emptyImage.rows + imageOrigin[
iter->first].y;
1819 int uj = jter->second.x*emptyImage.cols + imageOrigin[jter->first].x;
1820 int vj = (1.0-jter->second.y)*emptyImage.rows + imageOrigin[jter->first].y;
1821 cv::Vec3b * pt1 = globalTextures.
ptr<cv::Vec3b>(vi,ui+indexMaterial*globalTextures.rows);
1822 cv::Vec3b * pt2 = globalTextures.ptr<cv::Vec3b>(vj,uj+indexMaterial*globalTextures.rows);
1827 IR(
i,
j) +=
static_cast<double>(pt1->val[2]);
1828 IR(
j,
i) +=
static_cast<double>(pt2->val[2]);
1829 IG(
i,
j) +=
static_cast<double>(pt1->val[1]);
1830 IG(
j,
i) +=
static_cast<double>(pt2->val[1]);
1831 IB(
i,
j) +=
static_cast<double>(pt1->val[0]);
1832 IB(
j,
i) +=
static_cast<double>(pt2->val[0]);
1839 for(
int i=0;
i<num_images; ++
i)
1841 for(
int j=
i;
j<num_images; ++
j)
1855 IR(
i,
j) /=
N(
i,
j);
1856 IR(
j,
i) /=
N(
j,
i);
1857 IG(
i,
j) /=
N(
i,
j);
1858 IG(
j,
i) /=
N(
j,
i);
1859 IB(
i,
j) /=
N(
i,
j);
1860 IB(
j,
i) /=
N(
j,
i);
1865 cv::Mat_<double>
A(num_images, num_images);
A.setTo(0);
1866 cv::Mat_<double>
b(num_images, 1);
b.setTo(0);
1867 cv::Mat_<double> AR(num_images, num_images); AR.setTo(0);
1868 cv::Mat_<double> AG(num_images, num_images); AG.setTo(0);
1869 cv::Mat_<double> AB(num_images, num_images); AB.setTo(0);
1870 double alpha = 0.01;
1871 double beta = gainBeta;
1872 for (
int i = 0;
i < num_images; ++
i)
1874 for (
int j = 0;
j < num_images; ++
j)
1881 if (
j ==
i)
continue;
1896 cv::Mat_<double> gainsGray, gainsR, gainsG, gainsB;
1897 cv::solve(
A,
b, gainsGray);
1899 cv::solve(AR,
b, gainsR);
1900 cv::solve(AG,
b, gainsG);
1901 cv::solve(AB,
b, gainsB);
1903 cv::Mat_<double> gains(gainsGray.rows, 4);
1904 gainsGray.copyTo(gains.col(0));
1905 gainsR.copyTo(gains.col(1));
1906 gainsG.copyTo(gains.col(2));
1907 gainsB.copyTo(gains.col(3));
1909 for(
int t=0;
t<(
int)textures.size(); ++
t)
1912 if(materialsKept.at(
t))
1914 int u = imageOrigin[
t].x;
1915 int v = imageOrigin[
t].y;
1917 UDEBUG(
"Gain cam%d = %f", newCamIndex[
t], gainsGray(newCamIndex[
t], 0));
1919 int indexMaterial = newCamIndex[
t] / (
cols*
rows);
1920 cv::Mat roi = globalTextures(cv::Rect(u+indexMaterial*globalTextures.rows,
v, emptyImage.cols, emptyImage.rows));
1922 std::vector<cv::Mat> channels;
1923 cv::split(roi, channels);
1926 cv::multiply(channels[0], gains(newCamIndex[
t], gainRGB?3:0), channels[0]);
1927 cv::multiply(channels[1], gains(newCamIndex[
t], gainRGB?2:0), channels[1]);
1928 cv::multiply(channels[2], gains(newCamIndex[
t], gainRGB?1:0), channels[2]);
1930 cv::merge(channels, roi);
1935 gains(newCamIndex[
t], 0),
1936 gains(newCamIndex[
t], 1),
1937 gains(newCamIndex[
t], 2),
1938 gains(newCamIndex[
t], 3));
1939 if(gainsOut->find(textures[
t].first) == gainsOut->end())
1941 std::map<int,cv::Vec4d>
value;
1943 gainsOut->insert(std::make_pair(textures[
t].
first,
value));
1947 gainsOut->at(textures[
t].
first).insert(std::make_pair(textures[
t].
second,
g));
1961 if(blendingDecimation <= 0)
1964 std::vector<float> edgeLengths;
1965 if(mesh.tex_coordinates.size() && mesh.tex_coordinates[0].size())
1967 UASSERT(mesh.tex_polygons.size() && mesh.tex_polygons[0].size() && mesh.tex_polygons[0][0].vertices.size());
1968 int polygonSize = mesh.tex_polygons[0][0].vertices.size();
1969 UDEBUG(
"polygon size=%d", polygonSize);
1971 for(
unsigned int k=0; k<mesh.tex_coordinates.size(); ++k)
1973 for(
unsigned int i=0;
i<mesh.tex_coordinates[k].size();
i+=polygonSize)
1975 for(
int j=0;
j<polygonSize; ++
j)
1977 const Eigen::Vector2f & uc1 = mesh.tex_coordinates[k][
i +
j];
1978 const Eigen::Vector2f & uc2 = mesh.tex_coordinates[k][
i + (
j+1)%polygonSize];
1979 Eigen::Vector2f edge = (uc1-uc2)*textureSize;
1980 edgeLengths.push_back(
fabs(edge[0]));
1981 edgeLengths.push_back(
fabs(edge[1]));
1985 float edgeLength = 0.0f;
1986 if(edgeLengths.size())
1988 std::sort(edgeLengths.begin(), edgeLengths.end());
1989 float m =
uMean(edgeLengths.data(), edgeLengths.size());
1991 edgeLength =
m+stddev;
1992 decimation = 1 << 6;
1993 for(
int i=1;
i<=6; ++
i)
1995 if(
float(1 <<
i) >= edgeLength)
1997 decimation = 1 <<
i;
2003 UDEBUG(
"edge length=%f decimation=%d", edgeLength, decimation);
2008 if(blendingDecimation > 1)
2010 UASSERT(textureSize % blendingDecimation == 0);
2012 decimation = blendingDecimation;
2013 UDEBUG(
"decimation=%d", decimation);
2016 std::vector<cv::Mat> blendGains(materials);
2017 for(
int i=0;
i<materials;++
i)
2019 blendGains[
i] = cv::Mat(globalTextures.rows/decimation, globalTextures.rows/decimation, CV_32FC3,
cv::Scalar::all(1.0f));
2022 for(
unsigned int p=0;
p<vertexToPixels.size(); ++
p)
2024 if(vertexToPixels[
p].
size() > 1)
2026 std::vector<float> gainsB(vertexToPixels[
p].
size());
2027 std::vector<float> gainsG(vertexToPixels[
p].
size());
2028 std::vector<float> gainsR(vertexToPixels[
p].
size());
2029 float sumWeight = 0.0f;
2031 for(std::map<int, pcl::PointXY>::const_iterator
iter=vertexToPixels[
p].begin();
iter!=vertexToPixels[
p].end(); ++
iter)
2033 if(materialsKept.at(
iter->first))
2035 int u =
iter->second.x*emptyImage.cols + imageOrigin[
iter->first].x;
2036 int v = (1.0-
iter->second.y)*emptyImage.rows + imageOrigin[
iter->first].y;
2037 float x =
iter->second.x - 0.5f;
2038 float y =
iter->second.y - 0.5f;
2039 float weight = 0.7f -
sqrt(
x*
x+
y*
y);
2044 int indexMaterial = newCamIndex[
iter->first] / (
cols*
rows);
2045 cv::Vec3b * pt = globalTextures.ptr<cv::Vec3b>(
v,u+indexMaterial*globalTextures.rows);
2046 gainsB[k] =
static_cast<double>(pt->val[0]) * weight;
2047 gainsG[k] =
static_cast<double>(pt->val[1]) * weight;
2048 gainsR[k] =
static_cast<double>(pt->val[2]) * weight;
2049 sumWeight += weight;
2059 float targetColor[3];
2060 targetColor[0] =
uSum(gainsB.data(), gainsB.size()) / sumWeight;
2061 targetColor[1] =
uSum(gainsG.data(), gainsG.size()) / sumWeight;
2062 targetColor[2] =
uSum(gainsR.data(), gainsR.size()) / sumWeight;
2063 for(std::map<int, pcl::PointXY>::const_iterator
iter=vertexToPixels[
p].begin();
iter!=vertexToPixels[
p].end(); ++
iter)
2065 if(materialsKept.at(
iter->first))
2067 int u =
iter->second.x*emptyImage.cols + imageOrigin[
iter->first].x;
2068 int v = (1.0-
iter->second.y)*emptyImage.rows + imageOrigin[
iter->first].y;
2069 int indexMaterial = newCamIndex[
iter->first] / (
cols*
rows);
2070 cv::Vec3b * pt = globalTextures.ptr<cv::Vec3b>(
v,u+indexMaterial*globalTextures.rows);
2071 float gB = targetColor[0]/(pt->val[0]==0?1.0f:pt->val[0]);
2072 float gG = targetColor[1]/(pt->val[1]==0?1.0f:pt->val[1]);
2073 float gR = targetColor[2]/(pt->val[2]==0?1.0f:pt->val[2]);
2074 cv::Vec3f * ptr = blendGains[indexMaterial].ptr<cv::Vec3f>(
v/decimation, u/decimation);
2075 ptr->val[0] = (gB>1.3f)?1.3
f:(gB<0.7
f)?0.7f:gB;
2076 ptr->val[1] = (gG>1.3f)?1.3
f:(gG<0.7
f)?0.7f:gG;
2077 ptr->val[2] = (gR>1.3f)?1.3
f:(gR<0.7
f)?0.7f:gR;
2084 if(blendingGainsOut)
2086 for(
int t=0;
t<(
int)textures.size(); ++
t)
2089 if(materialsKept.at(
t))
2091 int u = imageOrigin[
t].
x/decimation;
2092 int v = imageOrigin[
t].y/decimation;
2094 int indexMaterial = newCamIndex[
t] / (
cols*
rows);
2095 cv::Mat roi = blendGains[indexMaterial](cv::Rect(u,
v, emptyImage.cols/decimation, emptyImage.rows/decimation));
2096 if(blendingGainsOut->find(textures[
t].first) == blendingGainsOut->end())
2098 std::map<int,cv::Mat>
value;
2099 value.insert(std::make_pair(textures[
t].
second, roi.clone()));
2100 blendingGainsOut->insert(std::make_pair(textures[
t].
first,
value));
2104 blendingGainsOut->at(textures[
t].
first).insert(std::make_pair(textures[
t].
second, roi.clone()));
2110 for(
int i=0;
i<materials; ++
i)
2122 cv::Mat globalTexturesROI = globalTextures(
cv::Range::all(), cv::Range(
i*globalTextures.rows, (
i+1)*globalTextures.rows));
2124 cv::blur(blendGains[
i],
dst, cv::Size(3,3));
2125 cv::resize(
dst, blendGains[
i], globalTexturesROI.size(), 0, 0, cv::INTER_LINEAR);
2135 cv::multiply(globalTexturesROI, blendGains[
i], globalTexturesROI, 1.0, CV_8UC3);
2145 if(brightnessContrastRatioLow > 0 || brightnessContrastRatioHigh > 0)
2149 std::vector<cv::Mat> images;
2150 images.push_back(globalTextures);
2151 if (brightnessContrastRatioLow > 0)
2156 (
float)brightnessContrastRatioLow,
2159 if (brightnessContrastRatioHigh > 0)
2165 (
float)brightnessContrastRatioHigh));
2176 (
float)brightnessContrastRatioLow,
2177 (
float)brightnessContrastRatioHigh,
2180 if(contrastValuesOut)
2182 contrastValuesOut->first =
alpha;
2183 contrastValuesOut->second =
beta;
2191 UDEBUG(
"globalTextures=%d", globalTextures.cols?globalTextures.cols / globalTextures.rows:0);
2192 return globalTextures;
2201 for (
unsigned int t = 0;
t < textureMesh.tex_coordinates.size(); ++
t)
2203 if(textureMesh.tex_polygons[
t].size())
2205 pcl::PointCloud<pcl::PointXYZ>::Ptr originalCloud(
new pcl::PointCloud<pcl::PointXYZ>);
2206 pcl::fromPCLPointCloud2(textureMesh.cloud, *originalCloud);
2209 unsigned int nPoints = textureMesh.tex_coordinates[
t].size();
2210 UASSERT(nPoints == textureMesh.tex_polygons[
t].size()*textureMesh.tex_polygons[
t][0].vertices.size());
2212 pcl::PointCloud<pcl::PointXYZ>::Ptr newCloud(
new pcl::PointCloud<pcl::PointXYZ>);
2213 newCloud->resize(nPoints);
2215 unsigned int oi = 0;
2216 for (
unsigned int i = 0;
i < textureMesh.tex_polygons[
t].size(); ++
i)
2218 pcl::Vertices &
vertices = textureMesh.tex_polygons[
t][
i];
2220 for(
unsigned int j=0;
j<
vertices.vertices.size(); ++
j)
2224 newCloud->at(oi) = originalCloud->at(
vertices.vertices[
j]);
2229 pcl::toPCLPointCloud2(*newCloud, textureMesh.cloud);
2235 const std::string & outputOBJPath,
2236 const pcl::PCLPointCloud2 & cloud,
2237 const std::vector<pcl::Vertices> & polygons,
2238 const std::map<int, Transform> & cameraPoses,
2239 const std::vector<std::map<int, pcl::PointXY> > & vertexToPixels,
2240 const std::map<int, cv::Mat> & images,
2241 const std::map<
int, std::vector<CameraModel> > & cameraModels,
2245 const std::string & textureFormat,
2246 const std::map<
int, std::map<int, cv::Vec4d> > & gains,
2247 const std::map<
int, std::map<int, cv::Mat> > & blendingGains,
2248 const std::pair<float, float> & contrastValues,
2272 const std::string & outputOBJPath,
2273 const pcl::PCLPointCloud2 & cloud,
2274 const std::vector<pcl::Vertices> & polygons,
2275 const std::map<int, Transform> & cameraPoses,
2276 const std::vector<std::map<int, pcl::PointXY> > & vertexToPixels,
2277 const std::map<int, cv::Mat> & images,
2278 const std::map<
int, std::vector<CameraModel> > & cameraModels,
2281 unsigned int textureSize,
2282 unsigned int textureDownScale,
2283 const std::string & nbContrib,
2284 const std::string & textureFormat,
2285 const std::map<
int, std::map<int, cv::Vec4d> > & gains,
2286 const std::map<
int, std::map<int, cv::Mat> > & blendingGains,
2287 const std::pair<float, float> & contrastValues,
2289 unsigned int unwrapMethod,
2291 unsigned int padding,
2292 double bestScoreThreshold,
2293 double angleHardThreshold,
2294 bool forceVisibleByAllVertices)
2297 #ifdef RTABMAP_ALICE_VISION
2300 system::Logger::get()->setLogLevel(system::EVerboseLevel::Trace);
2304 system::Logger::get()->setLogLevel(system::EVerboseLevel::Info);
2308 system::Logger::get()->setLogLevel(system::EVerboseLevel::Warning);
2312 system::Logger::get()->setLogLevel(system::EVerboseLevel::Error);
2315 sfmData::SfMData sfmData;
2316 pcl::PointCloud<pcl::PointXYZRGB> cloud2;
2317 pcl::fromPCLPointCloud2(cloud, cloud2);
2318 UASSERT(vertexToPixels.size() == cloud2.size());
2319 UINFO(
"Input mesh: %d points %d polygons", (
int)cloud2.size(), (
int)polygons.size());
2320 mesh::Texturing texturing;
2321 #if RTABMAP_ALICE_VISION_MAJOR > 2 || (RTABMAP_ALICE_VISION_MAJOR==2 && RTABMAP_ALICE_VISION_MINOR>=3)
2322 texturing.mesh =
new mesh::Mesh();
2323 texturing.mesh->pts.resize(cloud2.size());
2324 texturing.mesh->pointsVisibilities.resize(cloud2.size());
2326 texturing.me =
new mesh::Mesh();
2327 texturing.me->pts =
new StaticVector<Point3d>(cloud2.size());
2328 texturing.pointsVisibilities =
new mesh::PointsVisibility();
2329 texturing.pointsVisibilities->reserve(cloud2.size());
2331 texturing.texParams.textureSide = textureSize;
2332 texturing.texParams.downscale = textureDownScale;
2333 std::vector<int> multiBandNbContrib;
2334 std::list<std::string>
values =
uSplit(nbContrib,
' ');
2339 if(multiBandNbContrib.size() != 4)
2341 UERROR(
"multiband: Wrong number of nb of contribution (vaue=\"%s\", should be 4), using default values instead.", nbContrib.c_str());
2345 texturing.texParams.multiBandNbContrib = multiBandNbContrib;
2347 texturing.texParams.padding = padding;
2348 texturing.texParams.fillHoles = fillHoles;
2349 texturing.texParams.bestScoreThreshold = bestScoreThreshold;
2350 texturing.texParams.angleHardThreshold = angleHardThreshold;
2351 texturing.texParams.forceVisibleByAllVertices = forceVisibleByAllVertices;
2352 texturing.texParams.visibilityRemappingMethod = mesh::EVisibilityRemappingMethod::Pull;
2355 for(
size_t i=0;
i<cloud2.size();++
i)
2357 pcl::PointXYZRGB pt = cloud2.at(
i);
2358 #if RTABMAP_ALICE_VISION_MAJOR > 2 || (RTABMAP_ALICE_VISION_MAJOR==2 && RTABMAP_ALICE_VISION_MINOR>=3)
2359 texturing.mesh->pointsVisibilities[
i].reserve(vertexToPixels[
i].
size());
2360 for(std::map<int, pcl::PointXY>::const_iterator
iter=vertexToPixels[
i].begin();
iter!=vertexToPixels[
i].end();++
iter)
2362 texturing.mesh->pointsVisibilities[
i].push_back(
iter->first);
2364 texturing.mesh->pts[
i] = Point3d(pt.x, pt.y, pt.z);
2366 mesh::PointVisibility* pointVisibility =
new mesh::PointVisibility();
2367 pointVisibility->reserve(vertexToPixels[
i].
size());
2368 for(std::map<int, pcl::PointXY>::const_iterator
iter=vertexToPixels[
i].begin();
iter!=vertexToPixels[
i].end();++
iter)
2370 pointVisibility->push_back(
iter->first);
2372 texturing.pointsVisibilities->push_back(pointVisibility);
2373 (*texturing.me->pts)[
i] = Point3d(pt.x, pt.y, pt.z);
2377 #if RTABMAP_ALICE_VISION_MAJOR > 2 || (RTABMAP_ALICE_VISION_MAJOR==2 && RTABMAP_ALICE_VISION_MINOR>=3)
2378 texturing.mesh->tris.resize(polygons.size());
2379 texturing.mesh->trisMtlIds().resize(polygons.size());
2381 texturing.me->tris =
new StaticVector<mesh::Mesh::triangle>(polygons.size());
2383 for(
size_t i=0;
i<polygons.size();++
i)
2386 #if RTABMAP_ALICE_VISION_MAJOR > 2 || (RTABMAP_ALICE_VISION_MAJOR==2 && RTABMAP_ALICE_VISION_MINOR>=3)
2387 texturing.mesh->trisMtlIds()[
i] = -1;
2388 texturing.mesh->tris[
i] = mesh::Mesh::triangle(
2390 (*texturing.me->tris)[
i] = mesh::Mesh::triangle(
2392 polygons[
i].vertices[0],
2393 polygons[
i].vertices[1],
2394 polygons[
i].vertices[2]);
2398 std::string tmpImageDirectory = outputDirectory+
"/rtabmap_tmp_textures";
2401 UINFO(
"Temporary saving images from %ld nodes in directory \"%s\"...", cameraPoses.size(), tmpImageDirectory.c_str());
2403 for(std::map<int, Transform>::const_iterator
iter = cameraPoses.lower_bound(1);
iter!=cameraPoses.end(); ++
iter)
2405 int camId =
iter->first;
2407 std::vector<CameraModel> models;
2409 if( images.find(camId) != images.end() &&
2410 !images.find(camId)->second.empty() &&
2411 cameraModels.find(camId) != cameraModels.end())
2413 image = images.find(camId)->second;
2414 models = cameraModels.find(camId)->second;
2419 models =
data.cameraModels();
2420 if(models.empty() &&
data.stereoCameraModels().size())
2422 for(
size_t i=0;
i<
data.stereoCameraModels().
size(); ++
i)
2424 models.push_back(
data.stereoCameraModels()[
i].left());
2427 if(
data.imageRaw().empty())
2429 image =
data.imageCompressed();
2433 image =
data.imageRaw();
2436 if(models.empty() || image.empty())
2444 std::vector<float> vel;
2447 memory->
getNodeInfo(camId, odomPose, mapId, weight, label, stamp, gt, vel, gps, envs,
true);
2454 std::vector<StereoCameraModel> stereoModels;
2456 if(models.empty() && stereoModels.size())
2458 for(
size_t i=0;
i<stereoModels.size(); ++
i)
2460 models.push_back(stereoModels[
i].left());
2466 if(
data.imageRaw().empty())
2468 image =
data.imageCompressed();
2472 image =
data.imageRaw();
2475 if(models.empty() || image.empty())
2485 UERROR(
"No camera models found for camera %d. Aborting multiband texturing...",
iter->first);
2490 UERROR(
"No image found for camera %d. Aborting multiband texturing...",
iter->first);
2494 if(image.rows == 1 && image.type() == CV_8UC1)
2500 image = image.clone();
2503 for(
size_t i=0;
i<models.size(); ++
i)
2506 cv::Size imageSize =
model.imageSize();
2507 if(imageSize.height == 0)
2510 imageSize.height = image.rows;
2511 imageSize.width = image.cols;
2514 UASSERT(image.cols % imageSize.width == 0);
2515 cv::Mat imageRoi = image.colRange(
i*imageSize.width, (
i+1)*imageSize.width);
2517 if(gains.find(camId) != gains.end() &&
2518 gains.at(camId).find(
i) != gains.at(camId).end())
2520 const cv::Vec4d &
g = gains.at(camId).at(
i);
2521 if(imageRoi.channels() == 1)
2523 cv::multiply(imageRoi,
g.val[0], imageRoi);
2527 std::vector<cv::Mat> channels;
2528 cv::split(imageRoi, channels);
2531 cv::multiply(channels[0],
g.val[gainRGB?3:0], channels[0]);
2532 cv::multiply(channels[1],
g.val[gainRGB?2:0], channels[1]);
2533 cv::multiply(channels[2],
g.val[gainRGB?1:0], channels[2]);
2536 cv::merge(channels, output);
2541 if(blendingGains.find(camId) != blendingGains.end() &&
2542 blendingGains.at(camId).find(
i) != blendingGains.at(camId).end())
2545 if(imageRoi.channels() == 1)
2547 cv::Mat imageRoiColor;
2548 cv::cvtColor(imageRoi, imageRoiColor, CV_GRAY2BGR);
2549 imageRoi = imageRoiColor;
2552 cv::Mat
g = blendingGains.at(camId).at(
i);
2554 cv::blur(
g,
dst, cv::Size(3,3));
2556 cv::resize(
dst, gResized, imageRoi.size(), 0, 0, cv::INTER_LINEAR);
2558 cv::multiply(imageRoi, gResized, output, 1.0, CV_8UC3);
2564 sfmData::CameraPose pose(geometry::Pose3(
m),
true);
2565 sfmData.setAbsolutePose((IndexT)viewId, pose);
2568 std::shared_ptr<camera::IntrinsicBase> camPtr = std::make_shared<camera::Pinhole>(
2569 #
if RTABMAP_ALICE_VISION_MAJOR > 2 || (RTABMAP_ALICE_VISION_MAJOR==2 && RTABMAP_ALICE_VISION_MINOR>=4)
2572 imageSize.width, imageSize.height,
model.fx(),
model.fy(),
model.cx() -
double(imageSize.width) * 0.5,
model.cy() -
double(imageSize.height) * 0.5);
2574 imageSize.width, imageSize.height,
model.fx(),
model.cx(),
model.cy());
2576 sfmData.intrinsics.insert(std::make_pair((IndexT)viewId, camPtr));
2578 std::string imagePath = tmpImageDirectory+
uFormat(
"/%d.jpg", viewId);
2579 cv::imwrite(imagePath, imageRoi);
2580 std::shared_ptr<sfmData::View> viewPtr = std::make_shared<sfmData::View>(
2587 sfmData.views.insert(std::make_pair((IndexT)viewId, viewPtr));
2590 UDEBUG(
"camId=%d", camId);
2592 UINFO(
"Temporary saving images in directory \"%s\"... done (%d images of %d nodes). %fs", tmpImageDirectory.c_str(), viewId, (
int)cameraPoses.size(),
timer.ticks());
2594 mvsUtils::MultiViewParams mp(sfmData);
2596 UINFO(
"Unwrapping (method=%d=%s)...", unwrapMethod, mesh::EUnwrapMethod_enumToString((mesh::EUnwrapMethod)unwrapMethod).
c_str());
2597 texturing.unwrap(mp, (mesh::EUnwrapMethod)unwrapMethod);
2598 UINFO(
"Unwrapping done. %fs",
timer.ticks());
2602 #if RTABMAP_ALICE_VISION_MAJOR > 2 || (RTABMAP_ALICE_VISION_MAJOR==2 && RTABMAP_ALICE_VISION_MINOR>=4)
2603 texturing.saveAs(outputDirectory, baseName, aliceVision::mesh::EFileType::OBJ, imageIO::EImageFileType::PNG);
2605 texturing.saveAsOBJ(outputDirectory, baseName);
2607 UINFO(
"Saved %s. %fs", outputOBJPath.c_str(),
timer.ticks());
2610 UINFO(
"Generating textures...");
2611 texturing.generateTextures(mp, outputDirectory);
2612 UINFO(
"Generating textures done. %fs",
timer.ticks());
2614 UINFO(
"Cleanup temporary directory \"%s\"...", tmpImageDirectory.c_str());
2623 UINFO(
"Cleanup temporary directory \"%s\"... done.", tmpImageDirectory.c_str());
2625 UINFO(
"Rename/convert textures...");
2626 dir.
setPath(outputDirectory,
"png");
2627 std::map<std::string, std::string> texNames;
2628 std::string outputFormat = textureFormat;
2629 if(outputFormat.front() ==
'.')
2631 outputFormat = outputFormat.substr(1, std::string::npos);
2638 cv::Mat
img = cv::imread(outputDirectory+
"/"+*
iter);
2639 if(contrastValues.first != 0.0f || contrastValues.second != 0.0f)
2643 UINFO(
"Apply contrast values %f %f", contrastValues.first, contrastValues.second);
2644 img.convertTo(
img, -1, contrastValues.first, contrastValues.second);
2646 std::string newName = *
iter;
2647 boost::replace_all(newName,
"png", outputFormat);
2648 boost::replace_all(newName,
"texture", baseName);
2649 texNames.insert(std::make_pair(*
iter, newName));
2650 cv::imwrite(outputDirectory+
"/"+newName,
img);
2654 std::ifstream fi(outputDirectory+
"/"+baseName+
".mtl");
2655 std::string mtlStr((std::istreambuf_iterator<char>(fi)),
2656 std::istreambuf_iterator<char>());
2659 for(std::map<std::string, std::string>::iterator
iter=texNames.begin();
iter!=texNames.end(); ++
iter)
2661 boost::replace_all(mtlStr,
iter->first,
iter->second);
2663 std::ofstream
fo(outputDirectory+
"/"+baseName+
".mtl");
2664 fo.write(mtlStr.c_str(), mtlStr.size());
2666 UINFO(
"Rename/convert textures... done. %fs",
timer.ticks());
2668 #if RTABMAP_ALICE_VISION_MAJOR > 2 || (RTABMAP_ALICE_VISION_MAJOR==2 && RTABMAP_ALICE_VISION_MINOR>=3)
2669 UINFO(
"Cleanup sfmdata...");
2671 UINFO(
"Cleanup sfmdata... done. %fs",
timer.ticks());
2676 UERROR(
"Cannot unwrap texture mesh. RTAB-Map is not built with Alice Vision support! Returning false.");
2691 pcl::PointCloud<pcl::Normal>::Ptr normals;
2708 if(laserScan.
is2d())
2733 if(laserScan.
is2d())
2755 template<
typename Po
intT>
2757 const typename pcl::PointCloud<PointT>::Ptr & cloud,
2758 const pcl::IndicesPtr & indices,
2761 const Eigen::Vector3f & viewPoint)
2763 typename pcl::search::KdTree<PointT>::Ptr
tree (
new pcl::search::KdTree<PointT>);
2770 tree->setInputCloud (cloud);
2775 pcl::NormalEstimationOMP<PointT, pcl::Normal>
n;
2777 pcl::NormalEstimation<PointT, pcl::Normal>
n;
2779 pcl::PointCloud<pcl::Normal>::Ptr normals (
new pcl::PointCloud<pcl::Normal>);
2780 n.setInputCloud (cloud);
2786 n.setSearchMethod (
tree);
2787 n.setKSearch (searchK);
2788 n.setRadiusSearch (searchRadius);
2789 n.setViewPoint(viewPoint[0], viewPoint[1], viewPoint[2]);
2790 n.compute (*normals);
2795 const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
2798 const Eigen::Vector3f & viewPoint)
2800 pcl::IndicesPtr
indices(
new std::vector<int>);
2804 const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
2807 const Eigen::Vector3f & viewPoint)
2809 pcl::IndicesPtr
indices(
new std::vector<int>);
2813 const pcl::PointCloud<pcl::PointXYZI>::Ptr & cloud,
2816 const Eigen::Vector3f & viewPoint)
2818 pcl::IndicesPtr
indices(
new std::vector<int>);
2822 const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
2823 const pcl::IndicesPtr & indices,
2826 const Eigen::Vector3f & viewPoint)
2828 return computeNormalsImpl<pcl::PointXYZ>(cloud,
indices, searchK, searchRadius, viewPoint);
2831 const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
2832 const pcl::IndicesPtr & indices,
2835 const Eigen::Vector3f & viewPoint)
2837 return computeNormalsImpl<pcl::PointXYZRGB>(cloud,
indices, searchK, searchRadius, viewPoint);
2840 const pcl::PointCloud<pcl::PointXYZI>::Ptr & cloud,
2841 const pcl::IndicesPtr & indices,
2844 const Eigen::Vector3f & viewPoint)
2846 return computeNormalsImpl<pcl::PointXYZI>(cloud,
indices, searchK, searchRadius, viewPoint);
2849 template<
typename Po
intT>
2851 const typename pcl::PointCloud<PointT>::Ptr & cloud,
2854 const Eigen::Vector3f & viewPoint)
2856 UASSERT(searchK>0 || searchRadius>0.0
f);
2857 pcl::PointCloud<pcl::Normal>::Ptr normals (
new pcl::PointCloud<pcl::Normal>);
2859 typename pcl::search::KdTree<PointT>::Ptr
tree (
new pcl::search::KdTree<PointT>);
2860 tree->setInputCloud (cloud);
2862 normals->resize(cloud->size());
2864 float bad_point = std::numeric_limits<float>::quiet_NaN ();
2867 for(
unsigned int i=0;
i<cloud->size(); ++
i)
2869 const PointT & pt = cloud->at(
i);
2870 std::vector<Eigen::Vector3f> neighborNormals;
2871 Eigen::Vector3f direction;
2872 direction[0] = viewPoint[0] - pt.x;
2873 direction[1] = viewPoint[1] - pt.y;
2874 direction[2] = viewPoint[2] - pt.z;
2876 std::vector<int> k_indices;
2877 std::vector<float> k_sqr_distances;
2878 if(searchRadius>0.0
f)
2880 tree->radiusSearch(cloud->at(
i), searchRadius, k_indices, k_sqr_distances, searchK);
2884 tree->nearestKSearch(cloud->at(
i), searchK, k_indices, k_sqr_distances);
2887 for(
unsigned int j=0;
j<k_indices.size(); ++
j)
2889 if(k_indices.at(
j) != (
int)
i)
2891 const PointT & pt2 = cloud->at(k_indices.at(
j));
2892 Eigen::Vector3f
v(pt2.x-pt.x, pt2.y - pt.y, pt2.z - pt.z);
2893 Eigen::Vector3f up =
v.cross(direction);
2894 Eigen::Vector3f
n = up.cross(
v);
2896 neighborNormals.push_back(
n);
2900 if(neighborNormals.empty())
2902 normals->at(
i).normal_x = bad_point;
2903 normals->at(
i).normal_y = bad_point;
2904 normals->at(
i).normal_z = bad_point;
2908 Eigen::Vector3f meanNormal(0,0,0);
2909 for(
unsigned int j=0;
j<neighborNormals.size(); ++
j)
2911 meanNormal+=neighborNormals[
j];
2913 meanNormal /= (
float)neighborNormals.size();
2914 meanNormal.normalize();
2915 normals->at(
i).normal_x = meanNormal[0];
2916 normals->at(
i).normal_y = meanNormal[1];
2917 normals->at(
i).normal_z = meanNormal[2];
2924 const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
2927 const Eigen::Vector3f & viewPoint)
2929 return computeNormals2DImpl<pcl::PointXYZ>(cloud, searchK, searchRadius, viewPoint);
2932 const pcl::PointCloud<pcl::PointXYZI>::Ptr & cloud,
2935 const Eigen::Vector3f & viewPoint)
2937 return computeNormals2DImpl<pcl::PointXYZI>(cloud, searchK, searchRadius, viewPoint);
2940 template<
typename Po
intT>
2942 const typename pcl::PointCloud<PointT>::Ptr & cloud,
2945 const Eigen::Vector3f & viewPoint)
2948 pcl::PointCloud<pcl::Normal>::Ptr normals (
new pcl::PointCloud<pcl::Normal>);
2950 normals->resize(cloud->size());
2951 searchRadius *= searchRadius;
2953 float bad_point = std::numeric_limits<float>::quiet_NaN ();
2956 for(
int i=0;
i<(
int)cloud->size(); ++
i)
2964 if(hi>=(
int)cloud->size())
2966 hi=(
int)cloud->size()-1;
2970 const PointT & pt = cloud->at(
i);
2971 std::vector<Eigen::Vector3f> neighborNormals;
2972 Eigen::Vector3f direction;
2973 direction[0] = viewPoint[0] - cloud->at(
i).x;
2974 direction[1] = viewPoint[1] - cloud->at(
i).y;
2975 direction[2] = viewPoint[2] - cloud->at(
i).z;
2976 for(
int j=
i-1;
j>=li; --
j)
2978 const PointT & pt2 = cloud->at(
j);
2979 Eigen::Vector3f vd(pt2.x-pt.x, pt2.y - pt.y, pt2.z - pt.z);
2980 if(searchRadius<=0.0
f || (vd[0]*vd[0] + vd[1]*vd[1] + vd[2]*vd[2]) < searchRadius)
2982 Eigen::Vector3f
v(pt2.x-pt.x, pt2.y - pt.y, pt2.z - pt.z);
2983 Eigen::Vector3f up =
v.cross(direction);
2984 Eigen::Vector3f
n = up.cross(
v);
2986 neighborNormals.push_back(
n);
2993 for(
int j=
i+1;
j<=hi; ++
j)
2995 const PointT & pt2 = cloud->at(
j);
2996 Eigen::Vector3f vd(pt2.x-pt.x, pt2.y - pt.y, pt2.z - pt.z);
2997 if(searchRadius<=0.0
f || (vd[0]*vd[0] + vd[1]*vd[1] + vd[2]*vd[2]) < searchRadius)
2999 Eigen::Vector3f
v(pt2.x-pt.x, pt2.y - pt.y, pt2.z - pt.z);
3000 Eigen::Vector3f up =
v[2]==0.0f?Eigen::Vector3f(0,0,1):
v.cross(direction);
3001 Eigen::Vector3f
n = up.cross(
v);
3003 neighborNormals.push_back(
n);
3011 if(neighborNormals.empty())
3013 normals->at(
i).normal_x = bad_point;
3014 normals->at(
i).normal_y = bad_point;
3015 normals->at(
i).normal_z = bad_point;
3019 Eigen::Vector3f meanNormal(0,0,0);
3020 for(
unsigned int j=0;
j<neighborNormals.size(); ++
j)
3022 meanNormal+=neighborNormals[
j];
3024 meanNormal /= (
float)neighborNormals.size();
3025 meanNormal.normalize();
3026 normals->at(
i).normal_x = meanNormal[0];
3027 normals->at(
i).normal_y = meanNormal[1];
3028 normals->at(
i).normal_z = meanNormal[2];
3036 const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
3039 const Eigen::Vector3f & viewPoint)
3041 return computeFastOrganizedNormals2DImpl<pcl::PointXYZ>(cloud, searchK, searchRadius, viewPoint);
3044 const pcl::PointCloud<pcl::PointXYZI>::Ptr & cloud,
3047 const Eigen::Vector3f & viewPoint)
3049 return computeFastOrganizedNormals2DImpl<pcl::PointXYZI>(cloud, searchK, searchRadius, viewPoint);
3053 const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
3054 float maxDepthChangeFactor,
3055 float normalSmoothingSize,
3056 const Eigen::Vector3f & viewPoint)
3058 pcl::IndicesPtr
indices(
new std::vector<int>);
3062 const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
3063 const pcl::IndicesPtr & indices,
3064 float maxDepthChangeFactor,
3065 float normalSmoothingSize,
3066 const Eigen::Vector3f & viewPoint)
3068 UASSERT(cloud->isOrganized());
3070 pcl::search::KdTree<pcl::PointXYZRGB>::Ptr
tree (
new pcl::search::KdTree<pcl::PointXYZRGB>);
3077 tree->setInputCloud (cloud);
3081 pcl::PointCloud<pcl::Normal>::Ptr normals (
new pcl::PointCloud<pcl::Normal>);
3082 pcl::IntegralImageNormalEstimation<pcl::PointXYZRGB, pcl::Normal> ne;
3083 ne.setNormalEstimationMethod (ne.AVERAGE_3D_GRADIENT);
3084 ne.setMaxDepthChangeFactor(maxDepthChangeFactor);
3085 ne.setNormalSmoothingSize(normalSmoothingSize);
3086 ne.setBorderPolicy(ne.BORDER_POLICY_MIRROR);
3087 ne.setInputCloud(cloud);
3093 ne.setSearchMethod(
tree);
3094 ne.setViewPoint(viewPoint[0], viewPoint[1], viewPoint[2]);
3095 ne.compute(*normals);
3103 cv::Mat * pcaEigenVectors,
3104 cv::Mat * pcaEigenValues)
3109 int sz =
static_cast<int>(scan.
size()*2);
3110 bool is2d = scan.
is2d();
3111 cv::Mat data_normals = cv::Mat::zeros(sz, is2d?2:3, CV_32FC1);
3114 bool doTransform =
false;
3121 for (
int i = 0;
i < scan.
size(); ++
i)
3123 const float * ptrScan = scan.
data().ptr<
float>(0,
i);
3129 cv::Point3f
n(ptrScan[nOffset], ptrScan[nOffset+1], 0);
3134 float * ptr = data_normals.ptr<
float>(oi++, 0);
3143 cv::Point3f
n(ptrScan[nOffset], ptrScan[nOffset+1], ptrScan[nOffset+2]);
3148 float * ptr = data_normals.ptr<
float>(oi++, 0);
3157 cv::PCA pca_analysis(cv::Mat(data_normals, cv::Range(0, oi*2)), cv::Mat(), CV_PCA_DATA_AS_ROW);
3161 *pcaEigenVectors = pca_analysis.eigenvectors;
3165 *pcaEigenValues = pca_analysis.eigenvalues;
3167 UASSERT((is2d && pca_analysis.eigenvalues.total()>=2) || (!is2d && pca_analysis.eigenvalues.total()>=3));
3169 return pca_analysis.eigenvalues.at<
float>(0, is2d?1:2)*(is2d?2.0
f:3.0
f);
3174 UERROR(
"Scan doesn't have normals!");
3180 const pcl::PointCloud<pcl::PointNormal> & cloud,
3183 cv::Mat * pcaEigenVectors,
3184 cv::Mat * pcaEigenValues)
3187 int sz =
static_cast<int>(cloud.size()*2);
3188 cv::Mat data_normals = cv::Mat::zeros(sz, is2d?2:3, CV_32FC1);
3190 bool doTransform =
false;
3192 if(!
t.isIdentity() && !
t.isNull())
3197 for (
unsigned int i = 0;
i < cloud.size(); ++
i)
3199 const pcl::PointNormal & pt = cloud.at(
i);
3200 cv::Point3f
n(pt.normal_x, pt.normal_y, pt.normal_z);
3207 float * ptr = data_normals.ptr<
float>(oi++, 0);
3218 cv::PCA pca_analysis(cv::Mat(data_normals, cv::Range(0, oi*2)), cv::Mat(), CV_PCA_DATA_AS_ROW);
3222 *pcaEigenVectors = pca_analysis.eigenvectors;
3226 *pcaEigenValues = pca_analysis.eigenvalues;
3230 return pca_analysis.eigenvalues.at<
float>(0, is2d?1:2)*(is2d?2.0
f:3.0
f);
3236 const pcl::PointCloud<pcl::Normal> & normals,
3239 cv::Mat * pcaEigenVectors,
3240 cv::Mat * pcaEigenValues)
3243 int sz =
static_cast<int>(normals.size()*2);
3244 cv::Mat data_normals = cv::Mat::zeros(sz, is2d?2:3, CV_32FC1);
3246 bool doTransform =
false;
3253 for (
unsigned int i = 0;
i < normals.size(); ++
i)
3255 const pcl::Normal & pt = normals.at(
i);
3256 cv::Point3f
n(pt.normal_x, pt.normal_y, pt.normal_z);
3263 float * ptr = data_normals.ptr<
float>(oi++, 0);
3274 cv::PCA pca_analysis(cv::Mat(data_normals, cv::Range(0, oi*2)), cv::Mat(), CV_PCA_DATA_AS_ROW);
3278 *pcaEigenVectors = pca_analysis.eigenvectors;
3282 *pcaEigenValues = pca_analysis.eigenvalues;
3286 return pca_analysis.eigenvalues.at<
float>(0, is2d?1:2)*(is2d?2.0
f:3.0
f);
3292 const pcl::PointCloud<pcl::PointXYZINormal> & cloud,
3295 cv::Mat * pcaEigenVectors,
3296 cv::Mat * pcaEigenValues)
3299 int sz =
static_cast<int>(cloud.size()*2);
3300 cv::Mat data_normals = cv::Mat::zeros(sz, is2d?2:3, CV_32FC1);
3302 bool doTransform =
false;
3309 for (
unsigned int i = 0;
i < cloud.size(); ++
i)
3311 const pcl::PointXYZINormal & pt = cloud.at(
i);
3312 cv::Point3f
n(pt.normal_x, pt.normal_y, pt.normal_z);
3319 float * ptr = data_normals.ptr<
float>(oi++, 0);
3330 cv::PCA pca_analysis(cv::Mat(data_normals, cv::Range(0, oi*2)), cv::Mat(), CV_PCA_DATA_AS_ROW);
3334 *pcaEigenVectors = pca_analysis.eigenvectors;
3338 *pcaEigenValues = pca_analysis.eigenvalues;
3342 return pca_analysis.eigenvalues.at<
float>(0, is2d?1:2)*(is2d?2.0
f:3.0
f);
3348 const pcl::PointCloud<pcl::PointXYZRGBNormal> & cloud,
3351 cv::Mat * pcaEigenVectors,
3352 cv::Mat * pcaEigenValues)
3355 int sz =
static_cast<int>(cloud.size()*2);
3356 cv::Mat data_normals = cv::Mat::zeros(sz, is2d?2:3, CV_32FC1);
3358 bool doTransform =
false;
3365 for (
unsigned int i = 0;
i < cloud.size(); ++
i)
3367 const pcl::PointXYZRGBNormal & pt = cloud.at(
i);
3368 cv::Point3f
n(pt.normal_x, pt.normal_y, pt.normal_z);
3375 float * ptr = data_normals.ptr<
float>(oi++, 0);
3386 cv::PCA pca_analysis(cv::Mat(data_normals, cv::Range(0, oi*2)), cv::Mat(), CV_PCA_DATA_AS_ROW);
3390 *pcaEigenVectors = pca_analysis.eigenvectors;
3394 *pcaEigenValues = pca_analysis.eigenvalues;
3398 return pca_analysis.eigenvalues.at<
float>(0, is2d?1:2)*(is2d?2.0
f:3.0
f);
3403 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr
mls(
3404 const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
3406 int polygonialOrder,
3407 int upsamplingMethod,
3408 float upsamplingRadius,
3409 float upsamplingStep,
3411 float dilationVoxelSize,
3412 int dilationIterations)
3414 pcl::IndicesPtr
indices(
new std::vector<int>);
3424 dilationIterations);
3427 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr
mls(
3428 const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
3429 const pcl::IndicesPtr & indices,
3431 int polygonialOrder,
3432 int upsamplingMethod,
3433 float upsamplingRadius,
3434 float upsamplingStep,
3436 float dilationVoxelSize,
3437 int dilationIterations)
3439 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr cloud_with_normals(
new pcl::PointCloud<pcl::PointXYZRGBNormal>);
3440 pcl::search::KdTree<pcl::PointXYZRGB>::Ptr
tree (
new pcl::search::KdTree<pcl::PointXYZRGB>);
3447 tree->setInputCloud (cloud);
3451 pcl::MovingLeastSquares<pcl::PointXYZRGB, pcl::PointXYZRGBNormal>
mls;
3454 mls.setComputeNormals (
true);
3455 if(polygonialOrder > 0)
3457 #if PCL_VERSION_COMPARE(<, 1, 10, 0)
3458 mls.setPolynomialFit (
true);
3460 mls.setPolynomialOrder(polygonialOrder);
3464 #if PCL_VERSION_COMPARE(<, 1, 10, 0)
3465 mls.setPolynomialFit (
false);
3467 mls.setPolynomialOrder(1);
3471 upsamplingMethod <=
mls.VOXEL_GRID_DILATION);
3472 mls.setUpsamplingMethod((pcl::MovingLeastSquares<pcl::PointXYZRGB, pcl::PointXYZRGBNormal>::UpsamplingMethod)upsamplingMethod);
3473 mls.setSearchRadius(searchRadius);
3474 mls.setUpsamplingRadius(upsamplingRadius);
3475 mls.setUpsamplingStepSize(upsamplingStep);
3476 mls.setPointDensity(pointDensity);
3477 mls.setDilationVoxelSize(dilationVoxelSize);
3478 mls.setDilationIterations(dilationIterations);
3481 mls.setInputCloud (cloud);
3487 mls.process (*cloud_with_normals);
3490 for(
unsigned int i=0;
i<cloud_with_normals->size(); ++
i)
3492 Eigen::Vector3f
normal(cloud_with_normals->at(
i).normal_x, cloud_with_normals->at(
i).normal_y, cloud_with_normals->at(
i).normal_z);
3494 cloud_with_normals->at(
i).normal_x =
normal[0];
3495 cloud_with_normals->at(
i).normal_y =
normal[1];
3496 cloud_with_normals->at(
i).normal_z =
normal[2];
3499 return cloud_with_normals;
3504 const Eigen::Vector3f & viewpoint,
3505 bool forceGroundNormalsUp)
3511 const Eigen::Vector3f & viewpoint,
3512 float groundNormalsUp)
3519 cv::Mat output = scan.
data().clone();
3520 #pragma omp parallel for
3525 float * ptr = output.ptr<
float>(
j,
i);
3528 Eigen::Vector3f
v = viewpoint - Eigen::Vector3f(ptr[0], ptr[1], ptr[2]);
3529 Eigen::Vector3f
n(ptr[nx], ptr[ny], ptr[nz]);
3533 || (groundNormalsUp>0.0
f && ptr[nz] < -groundNormalsUp && ptr[2] < viewpoint[3]))
3555 template<
typename Po
intNormalT>
3557 typename pcl::PointCloud<PointNormalT>::Ptr & cloud,
3558 const Eigen::Vector3f & viewpoint,
3559 float groundNormalsUp)
3561 #pragma omp parallel for
3562 for(
int i=0;
i<(
int)cloud->size(); ++
i)
3564 pcl::PointXYZ
normal(cloud->points[
i].normal_x, cloud->points[
i].normal_y, cloud->points[
i].normal_z);
3565 if(pcl::isFinite(
normal))
3567 Eigen::Vector3f
v = viewpoint - cloud->points[
i].getVector3fMap();
3572 || (groundNormalsUp>0.0
f &&
normal.z < -groundNormalsUp && cloud->points[
i].z < viewpoint[3]))
3575 cloud->points[
i].normal_x *= -1.0f;
3576 cloud->points[
i].normal_y *= -1.0f;
3577 cloud->points[
i].normal_z *= -1.0f;
3584 pcl::PointCloud<pcl::PointNormal>::Ptr & cloud,
3585 const Eigen::Vector3f & viewpoint,
3586 bool forceGroundNormalsUp)
3591 pcl::PointCloud<pcl::PointNormal>::Ptr & cloud,
3592 const Eigen::Vector3f & viewpoint,
3593 float groundNormalsUp)
3595 adjustNormalsToViewPointImpl<pcl::PointNormal>(cloud, viewpoint, groundNormalsUp);
3599 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud,
3600 const Eigen::Vector3f & viewpoint,
3601 bool forceGroundNormalsUp)
3606 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud,
3607 const Eigen::Vector3f & viewpoint,
3608 float groundNormalsUp)
3610 adjustNormalsToViewPointImpl<pcl::PointXYZRGBNormal>(cloud, viewpoint, groundNormalsUp);
3614 pcl::PointCloud<pcl::PointXYZINormal>::Ptr & cloud,
3615 const Eigen::Vector3f & viewpoint,
3616 bool forceGroundNormalsUp)
3621 pcl::PointCloud<pcl::PointXYZINormal>::Ptr & cloud,
3622 const Eigen::Vector3f & viewpoint,
3623 float groundNormalsUp)
3625 adjustNormalsToViewPointImpl<pcl::PointXYZINormal>(cloud, viewpoint, groundNormalsUp);
3629 template<
typename Po
intT>
3631 const std::map<int, Transform> & poses,
3632 const pcl::PointCloud<pcl::PointXYZ>::Ptr & rawCloud,
3633 const std::vector<int> & rawCameraIndices,
3634 typename pcl::PointCloud<PointT>::Ptr & cloud,
3635 float groundNormalsUp)
3637 if(poses.size() && rawCloud->size() && rawCloud->size() == rawCameraIndices.size() && cloud->size())
3639 pcl::search::KdTree<pcl::PointXYZ>::Ptr rawTree (
new pcl::search::KdTree<pcl::PointXYZ>);
3640 rawTree->setInputCloud (rawCloud);
3642 #pragma omp parallel for
3643 for(
int i=0;
i<(
int)cloud->size(); ++
i)
3645 pcl::PointXYZ
normal(cloud->points[
i].normal_x, cloud->points[
i].normal_y, cloud->points[
i].normal_z);
3646 if(pcl::isFinite(
normal))
3649 std::vector<float>
dist;
3650 rawTree->nearestKSearch(pcl::PointXYZ(cloud->points[
i].x, cloud->points[
i].y, cloud->points[
i].z), 1,
indices,
dist);
3655 pcl::PointXYZ viewpoint(
p.x(),
p.y(),
p.z());
3656 Eigen::Vector3f
v = viewpoint.getVector3fMap() - cloud->points[
i].getVector3fMap();
3662 (groundNormalsUp>0.0
f &&
normal.z < -groundNormalsUp && cloud->points[
i].z < viewpoint.z))
3665 cloud->points[
i].normal_x *= -1.0f;
3666 cloud->points[
i].normal_y *= -1.0f;
3667 cloud->points[
i].normal_z *= -1.0f;
3672 UWARN(
"Not found camera viewpoint for point %d",
i);
3680 const std::map<int, Transform> & poses,
3681 const pcl::PointCloud<pcl::PointXYZ>::Ptr & rawCloud,
3682 const std::vector<int> & rawCameraIndices,
3683 pcl::PointCloud<pcl::PointNormal>::Ptr & cloud,
3684 float groundNormalsUp)
3686 adjustNormalsToViewPointsImpl<pcl::PointNormal>(poses, rawCloud, rawCameraIndices, cloud, groundNormalsUp);
3690 const std::map<int, Transform> & poses,
3691 const pcl::PointCloud<pcl::PointXYZ>::Ptr & rawCloud,
3692 const std::vector<int> & rawCameraIndices,
3693 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud,
3694 float groundNormalsUp)
3696 adjustNormalsToViewPointsImpl<pcl::PointXYZRGBNormal>(poses, rawCloud, rawCameraIndices, cloud, groundNormalsUp);
3700 const std::map<int, Transform> & poses,
3701 const pcl::PointCloud<pcl::PointXYZ>::Ptr & rawCloud,
3702 const std::vector<int> & rawCameraIndices,
3703 pcl::PointCloud<pcl::PointXYZINormal>::Ptr & cloud,
3704 float groundNormalsUp)
3706 adjustNormalsToViewPointsImpl<pcl::PointXYZINormal>(poses, rawCloud, rawCameraIndices, cloud, groundNormalsUp);
3710 const std::map<int, Transform> & viewpoints,
3712 const std::vector<int> & viewpointIds,
3714 float groundNormalsUp)
3716 UDEBUG(
"poses=%d, rawCloud=%d, rawCameraIndices=%d, cloud=%d", (
int)viewpoints.size(), (
int)rawScan.
size(), (
int)viewpointIds.size(), (
int)scan.
size());
3717 if(viewpoints.size() && rawScan.
size() && rawScan.
size() == (
int)viewpointIds.size() && scan.
size() && scan.
hasNormals())
3720 pcl::search::KdTree<pcl::PointXYZ>::Ptr rawTree (
new pcl::search::KdTree<pcl::PointXYZ>);
3721 rawTree->setInputCloud (rawCloud);
3722 #pragma omp parallel for
3723 for(
int i=0;
i<scan.
size(); ++
i)
3727 if(pcl::isFinite(
normal))
3730 std::vector<float>
dist;
3737 pcl::PointXYZ viewpoint(
p.x(),
p.y(),
p.z());
3738 Eigen::Vector3f
v = viewpoint.getVector3fMap() -
point.getVector3fMap();
3744 (groundNormalsUp>0.0
f &&
normal.z < -groundNormalsUp &&
point.z < viewpoint.z))
3754 UWARN(
"Not found camera viewpoint for point %d!?",
i);
3761 pcl::PolygonMesh::Ptr
meshDecimation(
const pcl::PolygonMesh::Ptr & mesh,
float factor)
3763 pcl::PolygonMesh::Ptr output(
new pcl::PolygonMesh);
3765 pcl::MeshQuadricDecimationVTK mqd;
3766 mqd.setTargetReductionFactor(factor);
3767 mqd.setInputMesh(mesh);
3768 mqd.process (*output);
3770 UWARN(
"RTAB-Map is not built with VTK module so mesh decimation cannot be used!");
3777 const Eigen::Vector3f & p,
3778 const Eigen::Vector3f & dir,
3779 const Eigen::Vector3f & v0,
3780 const Eigen::Vector3f & v1,
3781 const Eigen::Vector3f & v2,
3783 Eigen::Vector3f & normal)
3786 const Eigen::Vector3f u =
v1-v0;
3787 const Eigen::Vector3f
v =
v2-v0;
3789 if (
normal == Eigen::Vector3f(0,0,0))
3792 const float denomimator =
normal.dot(dir);
3793 if (
fabs(denomimator) < 10
e-9)
3802 float uu, uv, vv, wu, wv,
D;
3806 const Eigen::Vector3f
w =
p + dir *
distance - v0;
3809 D = uv * uv - uu * vv;
3813 s = (uv * wv - vv * wu) /
D;
3814 if (s < 0.0 || s > 1.0)
3816 t = (uv * wu - uu * wv) /
D;
3817 if (
t < 0.0 || (
s +
t) > 1.0)