38 #ifndef PCL_SURFACE_IMPL_TEXTURE_MAPPING_HPP_
39 #define PCL_SURFACE_IMPL_TEXTURE_MAPPING_HPP_
42 #include <pcl/surface/texture_mapping.h>
45 template<
typename Po
intInT> std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> >
47 const Eigen::Vector3f &p1,
48 const Eigen::Vector3f &p2,
49 const Eigen::Vector3f &p3)
51 std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > tex_coordinates;
53 Eigen::Vector3f p1p2 (p2[0] - p1[0], p2[1] - p1[1], p2[2] - p1[2]);
54 Eigen::Vector3f p1p3 (p3[0] - p1[0], p3[1] - p1[1], p3[2] - p1[2]);
55 Eigen::Vector3f p2p3 (p3[0] - p2[0], p3[1] - p2[1], p3[2] - p2[2]);
58 p1p2 /= std::sqrt (p1p2.dot (p1p2));
59 p1p3 /= std::sqrt (p1p3.dot (p1p3));
60 p2p3 /= std::sqrt (p2p3.dot (p2p3));
63 Eigen::Vector3f f_normal = p1p2.cross (p1p3);
64 f_normal /= std::sqrt (f_normal.dot (f_normal));
67 Eigen::Vector3f f_vector_field = vector_field_ - vector_field_.dot (f_normal) * f_normal;
70 f_vector_field /= std::sqrt (f_vector_field.dot (f_vector_field));
73 Eigen::Vector2f tp1, tp2, tp3;
75 double alpha = std::acos (f_vector_field.dot (p1p2));
78 double e1 = (p2 - p3).norm () / f_;
79 double e2 = (p1 - p3).norm () / f_;
80 double e3 = (p1 - p2).norm () / f_;
86 tp2[0] =
static_cast<float> (e3);
90 double cos_p1 = (e2 * e2 + e3 * e3 - e1 * e1) / (2 * e2 * e3);
91 double sin_p1 = sqrt (1 - (cos_p1 * cos_p1));
93 tp3[0] =
static_cast<float> (cos_p1 * e2);
94 tp3[1] =
static_cast<float> (sin_p1 * e2);
97 Eigen::Vector2f r_tp2, r_tp3;
98 r_tp2[0] =
static_cast<float> (tp2[0] * std::cos (alpha) - tp2[1] * std::sin (alpha));
99 r_tp2[1] =
static_cast<float> (tp2[0] * std::sin (alpha) + tp2[1] * std::cos (alpha));
101 r_tp3[0] =
static_cast<float> (tp3[0] * std::cos (alpha) - tp3[1] * std::sin (alpha));
102 r_tp3[1] =
static_cast<float> (tp3[0] * std::sin (alpha) + tp3[1] * std::cos (alpha));
112 float min_x = tp1[0];
113 float min_y = tp1[1];
136 tex_coordinates.push_back (tp1);
137 tex_coordinates.push_back (tp2);
138 tex_coordinates.push_back (tp3);
139 return (tex_coordinates);
143 template<
typename Po
intInT>
void
148 int point_size =
static_cast<int> (tex_mesh.
cloud.
data.size ()) / nr_points;
153 Eigen::Vector3f facet[3];
156 std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > >texture_map;
158 for (std::size_t m = 0; m < tex_mesh.
tex_polygons.size (); ++m)
161 std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > texture_map_tmp;
164 for (std::size_t i = 0; i < tex_mesh.
tex_polygons[m].size (); ++i)
169 for (std::size_t j = 0; j < tex_mesh.
tex_polygons[m][i].vertices.size (); ++j)
172 memcpy (&x, &tex_mesh.
cloud.
data[idx * point_size + tex_mesh.
cloud.
fields[0].offset],
sizeof(
float));
173 memcpy (&y, &tex_mesh.
cloud.
data[idx * point_size + tex_mesh.
cloud.
fields[1].offset],
sizeof(
float));
174 memcpy (&z, &tex_mesh.
cloud.
data[idx * point_size + tex_mesh.
cloud.
fields[2].offset],
sizeof(
float));
181 std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > tex_coordinates = mapTexture2Face (facet[0], facet[1], facet[2]);
182 for (
const auto &tex_coordinate : tex_coordinates)
183 texture_map_tmp.push_back (tex_coordinate);
187 std::stringstream tex_name;
188 tex_name <<
"material_" << m;
189 tex_name >> tex_material_.tex_name;
190 tex_material_.tex_file = tex_files_[m];
199 template<
typename Po
intInT>
void
204 int point_size =
static_cast<int> (tex_mesh.
cloud.
data.size ()) / nr_points;
206 float x_lowest = 100000;
208 float y_lowest = 100000;
210 float z_lowest = 100000;
214 for (
int i = 0; i < nr_points; ++i)
216 memcpy (&x_, &tex_mesh.
cloud.
data[i * point_size + tex_mesh.
cloud.
fields[0].offset],
sizeof(
float));
217 memcpy (&y_, &tex_mesh.
cloud.
data[i * point_size + tex_mesh.
cloud.
fields[1].offset],
sizeof(
float));
218 memcpy (&z_, &tex_mesh.
cloud.
data[i * point_size + tex_mesh.
cloud.
fields[2].offset],
sizeof(
float));
237 float x_range = (x_lowest - x_highest) * -1;
238 float x_offset = 0 - x_lowest;
243 float z_range = (z_lowest - z_highest) * -1;
244 float z_offset = 0 - z_lowest;
247 std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > >texture_map;
249 for (std::size_t m = 0; m < tex_mesh.
tex_polygons.size (); ++m)
252 std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > texture_map_tmp;
255 for (std::size_t i = 0; i < tex_mesh.
tex_polygons[m].size (); ++i)
258 Eigen::Vector2f tmp_VT;
259 for (std::size_t j = 0; j < tex_mesh.
tex_polygons[m][i].vertices.size (); ++j)
262 memcpy (&x_, &tex_mesh.
cloud.
data[idx * point_size + tex_mesh.
cloud.
fields[0].offset],
sizeof(
float));
263 memcpy (&y_, &tex_mesh.
cloud.
data[idx * point_size + tex_mesh.
cloud.
fields[1].offset],
sizeof(
float));
264 memcpy (&z_, &tex_mesh.
cloud.
data[idx * point_size + tex_mesh.
cloud.
fields[2].offset],
sizeof(
float));
267 tmp_VT[0] = (x_ + x_offset) / x_range;
268 tmp_VT[1] = (z_ + z_offset) / z_range;
269 texture_map_tmp.push_back (tmp_VT);
274 std::stringstream tex_name;
275 tex_name <<
"material_" << m;
276 tex_name >> tex_material_.tex_name;
277 tex_material_.tex_file = tex_files_[m];
286 template<
typename Po
intInT>
void
292 PCL_ERROR (
"The mesh should be divided into nbCamera+1 sub-meshes.\n");
293 PCL_ERROR (
"You provided %d cameras and a mesh containing %d sub-meshes.\n", cams.size (), tex_mesh.
tex_polygons.size ());
297 PCL_INFO (
"You provided %d cameras and a mesh containing %d sub-meshes.\n", cams.size (), tex_mesh.
tex_polygons.size ());
306 std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > texture_map;
308 for (std::size_t m = 0; m < cams.size (); ++m)
311 Camera current_cam = cams[m];
314 Eigen::Affine3f cam_trans = current_cam.
pose;
320 std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > texture_map_tmp;
323 for (
const auto &tex_polygon : tex_mesh.
tex_polygons[m])
325 Eigen::Vector2f tmp_VT;
327 for (
const unsigned int &vertex : tex_polygon.vertices)
330 PointInT pt = camera_transformed_cloud->
points[vertex];
333 getPointUVCoordinates (pt, current_cam, tmp_VT);
334 texture_map_tmp.push_back (tmp_VT);
339 std::stringstream tex_name;
340 tex_name <<
"material_" << m;
341 tex_name >> tex_material_.tex_name;
350 std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > texture_map_tmp;
351 for (
const auto &tex_polygon : tex_mesh.
tex_polygons[cams.size ()])
352 for (std::size_t j = 0; j < tex_polygon.vertices.size (); ++j)
354 Eigen::Vector2f tmp_VT;
357 texture_map_tmp.push_back (tmp_VT);
363 tex_material_.tex_name =
"material_" + std::to_string(cams.size());
364 tex_material_.tex_file =
"occluded.jpg";
369 template<
typename Po
intInT>
bool
372 Eigen::Vector3f direction;
373 direction (0) = pt.x;
374 direction (1) = pt.y;
375 direction (2) = pt.z;
377 std::vector<int> indices;
380 cloud = octree->getInputCloud();
382 double distance_threshold = octree->getResolution();
385 octree->getIntersectedVoxelIndices(direction, -direction, indices);
387 int nbocc =
static_cast<int> (indices.size ());
388 for (
const int &index : indices)
391 if (pt.z * cloud->points[index].z < 0)
397 if (std::fabs (cloud->points[index].z - pt.z) <= distance_threshold)
408 template<
typename Po
intInT>
void
411 const double octree_voxel_size, std::vector<int> &visible_indices,
412 std::vector<int> &occluded_indices)
415 double maxDeltaZ = octree_voxel_size;
418 Octree octree (octree_voxel_size);
426 visible_indices.clear ();
429 Eigen::Vector3f direction;
430 std::vector<int> indices;
431 for (std::size_t i = 0; i < input_cloud->points.size (); ++i)
433 direction (0) = input_cloud->points[i].x;
434 direction (1) = input_cloud->points[i].y;
435 direction (2) = input_cloud->points[i].z;
440 int nbocc =
static_cast<int> (indices.size ());
441 for (
const int &index : indices)
444 if (input_cloud->points[i].z * input_cloud->points[index].z < 0)
450 if (std::fabs (input_cloud->points[index].z - input_cloud->points[i].z) <= maxDeltaZ)
460 filtered_cloud->points.push_back (input_cloud->points[i]);
461 visible_indices.push_back (
static_cast<int> (i));
465 occluded_indices.push_back (
static_cast<int> (i));
472 template<
typename Po
intInT>
void
476 cleaned_mesh = tex_mesh;
484 std::vector<int> visible, occluded;
485 removeOccludedPoints (cloud, filtered_cloud, octree_voxel_size, visible, occluded);
489 for (std::size_t polygons = 0; polygons < cleaned_mesh.
tex_polygons.size (); ++polygons)
494 for (std::size_t faces = 0; faces < tex_mesh.
tex_polygons[polygons].size (); ++faces)
497 bool faceIsVisible =
true;
498 std::vector<int>::iterator it;
501 for (
const unsigned int &vertex : tex_mesh.
tex_polygons[polygons][faces].vertices)
503 it = find (occluded.begin (), occluded.end (), vertex);
505 if (it == occluded.end ())
514 faceIsVisible =
false;
528 template<
typename Po
intInT>
void
530 const double octree_voxel_size)
537 std::vector<int> visible, occluded;
538 removeOccludedPoints (cloud, filtered_cloud, octree_voxel_size, visible, occluded);
543 template<
typename Po
intInT>
int
550 PCL_ERROR (
"The mesh must contain only 1 sub-mesh!\n");
554 if (cameras.empty ())
556 PCL_ERROR (
"Must provide at least one camera info!\n");
561 sorted_mesh = tex_mesh;
573 for (
const auto &camera : cameras)
576 Eigen::Affine3f cam_trans = camera.pose;
582 std::vector<int> visible, occluded;
583 removeOccludedPoints (transformed_cloud, filtered_cloud, octree_voxel_size, visible, occluded);
584 visible_pts = *filtered_cloud;
588 std::vector<pcl::Vertices> visibleFaces_currentCam;
590 for (std::size_t faces = 0; faces < tex_mesh.
tex_polygons[0].size (); ++faces)
593 bool faceIsVisible =
true;
594 std::vector<int>::iterator it;
597 for (std::size_t current_pt_indice = 0; faceIsVisible && current_pt_indice < tex_mesh.
tex_polygons[0][faces].vertices.size (); ++current_pt_indice)
600 it = find (occluded.begin (), occluded.end (), tex_mesh.
tex_polygons[0][faces].vertices[current_pt_indice]);
602 if (it == occluded.end ())
606 PointInT pt = transformed_cloud->
points[tex_mesh.
tex_polygons[0][faces].vertices[current_pt_indice]];
607 Eigen::Vector2f dummy_UV;
608 if (!getPointUVCoordinates (pt, camera, dummy_UV))
611 faceIsVisible =
false;
616 faceIsVisible =
false;
623 visibleFaces_currentCam.push_back (tex_mesh.
tex_polygons[0][faces]);
630 sorted_mesh.
tex_polygons.push_back (visibleFaces_currentCam);
640 template<
typename Po
intInT>
void
643 const double octree_voxel_size,
const bool show_nb_occlusions,
644 const int max_occlusions)
647 double maxDeltaZ = octree_voxel_size * 2.0;
650 Octree octree (octree_voxel_size);
659 Eigen::Vector3f direction;
661 std::vector<int> indices;
665 std::vector<double> zDist;
666 std::vector<double> ptDist;
668 for (std::size_t i = 0; i < input_cloud->points.size (); ++i)
670 direction (0) = input_cloud->points[i].x;
671 pt.x = input_cloud->points[i].x;
672 direction (1) = input_cloud->points[i].y;
673 pt.y = input_cloud->points[i].y;
674 direction (2) = input_cloud->points[i].z;
675 pt.z = input_cloud->points[i].z;
681 nbocc =
static_cast<int> (indices.size ());
684 for (
const int &index : indices)
687 if (pt.z * input_cloud->points[index].z < 0)
691 else if (std::fabs (input_cloud->points[index].z - pt.z) <= maxDeltaZ)
698 zDist.push_back (std::fabs (input_cloud->points[index].z - pt.z));
703 if (show_nb_occlusions)
704 (nbocc <= max_occlusions) ? (pt.
intensity =
static_cast<float> (nbocc)) : (pt.
intensity =
static_cast<float> (max_occlusions));
708 colored_cloud->
points.push_back (pt);
711 if (zDist.size () >= 2)
713 std::sort (zDist.begin (), zDist.end ());
714 std::sort (ptDist.begin (), ptDist.end ());
719 template<
typename Po
intInT>
void
721 double octree_voxel_size,
bool show_nb_occlusions,
int max_occlusions)
727 showOcclusions (cloud, colored_cloud, octree_voxel_size, show_nb_occlusions, max_occlusions);
731 template<
typename Po
intInT>
void
742 std::vector<pcl::Vertices> faces;
744 for (
int current_cam = 0; current_cam < static_cast<int> (cameras.size ()); ++current_cam)
746 PCL_INFO (
"Processing camera %d of %d.\n", current_cam+1, cameras.size ());
754 std::vector<bool> visibility;
755 visibility.resize (mesh.
tex_polygons[current_cam].size ());
756 std::vector<UvIndex> indexes_uv_to_points;
761 nan_point.
x = std::numeric_limits<float>::quiet_NaN ();
762 nan_point.
y = std::numeric_limits<float>::quiet_NaN ();
768 for (
int idx_face = 0; idx_face < static_cast<int> (mesh.
tex_polygons[current_cam].size ()); ++idx_face)
775 if (isFaceProjected (cameras[current_cam],
786 projections->
points.push_back (uv_coord1);
787 projections->
points.push_back (uv_coord2);
788 projections->
points.push_back (uv_coord3);
796 indexes_uv_to_points.push_back (u1);
797 indexes_uv_to_points.push_back (u2);
798 indexes_uv_to_points.push_back (u3);
801 visibility[idx_face] =
true;
805 projections->
points.push_back (nan_point);
806 projections->
points.push_back (nan_point);
807 projections->
points.push_back (nan_point);
808 indexes_uv_to_points.push_back (u_null);
809 indexes_uv_to_points.push_back (u_null);
810 indexes_uv_to_points.push_back (u_null);
812 visibility[idx_face] =
false;
822 if (visibility.size () - cpt_invisible !=0)
828 std::vector<int> idxNeighbors;
829 std::vector<float> neighborsSquaredDistance;
833 for (
int idx_pcam = 0 ; idx_pcam <= current_cam ; ++idx_pcam)
836 for (
int idx_face = 0; idx_face < static_cast<int> (mesh.
tex_polygons[idx_pcam].size ()); ++idx_face)
839 if (idx_pcam == current_cam && !visibility[idx_face])
852 if (isFaceProjected (cameras[current_cam],
865 getTriangleCircumcscribedCircleCentroid(uv_coord1, uv_coord2, uv_coord3, center, radius);
868 if (kdtree.
radiusSearch (center, radius, idxNeighbors, neighborsSquaredDistance) > 0 )
871 for (
const int &idxNeighbor : idxNeighbors)
873 if (std::max (camera_cloud->
points[mesh.
tex_polygons[idx_pcam][idx_face].vertices[0]].z,
876 < camera_cloud->
points[indexes_uv_to_points[idxNeighbor].idx_cloud].z)
879 if (checkPointInsideTriangle(uv_coord1, uv_coord2, uv_coord3, projections->
points[idxNeighbor]))
882 visibility[indexes_uv_to_points[idxNeighbor].idx_face] =
false;
899 std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > dummy_container;
904 std::vector<pcl::Vertices> occluded_faces;
905 occluded_faces.resize (visibility.size ());
906 std::vector<pcl::Vertices> visible_faces;
907 visible_faces.resize (visibility.size ());
909 int cpt_occluded_faces = 0;
910 int cpt_visible_faces = 0;
912 for (std::size_t idx_face = 0 ; idx_face < visibility.size () ; ++idx_face)
914 if (visibility[idx_face])
920 mesh.
tex_coordinates[current_cam][cpt_visible_faces * 3 + 1](0) = projections->
points[idx_face*3 + 1].x;
921 mesh.
tex_coordinates[current_cam][cpt_visible_faces * 3 + 1](1) = projections->
points[idx_face*3 + 1].y;
923 mesh.
tex_coordinates[current_cam][cpt_visible_faces * 3 + 2](0) = projections->
points[idx_face*3 + 2].x;
924 mesh.
tex_coordinates[current_cam][cpt_visible_faces * 3 + 2](1) = projections->
points[idx_face*3 + 2].y;
926 visible_faces[cpt_visible_faces] = mesh.
tex_polygons[current_cam][idx_face];
933 occluded_faces[cpt_occluded_faces] = mesh.
tex_polygons[current_cam][idx_face];
934 cpt_occluded_faces++;
939 occluded_faces.resize (cpt_occluded_faces);
942 visible_faces.resize (cpt_visible_faces);
953 std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > dummy_container;
958 for(std::size_t idx_face = 0 ; idx_face < mesh.
tex_polygons[cameras.size()].size() ; ++idx_face)
960 Eigen::Vector2f UV1, UV2, UV3;
961 UV1(0) = -1.0; UV1(1) = -1.0;
962 UV2(0) = -1.0; UV2(1) = -1.0;
963 UV3(0) = -1.0; UV3(1) = -1.0;
972 template<
typename Po
intInT>
inline void
977 ptB.
x = p2.
x - p1.
x; ptB.
y = p2.
y - p1.
y;
978 ptC.
x = p3.
x - p1.
x; ptC.
y = p3.
y - p1.
y;
980 double D = 2.0*(ptB.
x*ptC.
y - ptB.
y*ptC.
x);
985 circomcenter.
x = p1.
x;
986 circomcenter.
y = p1.
y;
991 double bx2 = ptB.
x * ptB.
x;
992 double by2 = ptB.
y * ptB.
y;
993 double cx2 = ptC.
x * ptC.
x;
994 double cy2 = ptC.
y * ptC.
y;
997 circomcenter.
x =
static_cast<float> (p1.
x + (ptC.
y*(bx2 + by2) - ptB.
y*(cx2 + cy2)) / D);
998 circomcenter.
y =
static_cast<float> (p1.
y + (ptB.
x*(cx2 + cy2) - ptC.
x*(bx2 + by2)) / D);
1001 radius = std::sqrt( (circomcenter.
x - p1.
x)*(circomcenter.
x - p1.
x) + (circomcenter.
y - p1.
y)*(circomcenter.
y - p1.
y));
1005 template<
typename Po
intInT>
inline void
1009 circumcenter.
x =
static_cast<float> (p1.
x + p2.
x + p3.
x ) / 3;
1010 circumcenter.
y =
static_cast<float> (p1.
y + p2.
y + p3.
y ) / 3;
1011 double r1 = (circumcenter.
x - p1.
x) * (circumcenter.
x - p1.
x) + (circumcenter.
y - p1.
y) * (circumcenter.
y - p1.
y) ;
1012 double r2 = (circumcenter.
x - p2.
x) * (circumcenter.
x - p2.
x) + (circumcenter.
y - p2.
y) * (circumcenter.
y - p2.
y) ;
1013 double r3 = (circumcenter.
x - p3.
x) * (circumcenter.
x - p3.
x) + (circumcenter.
y - p3.
y) * (circumcenter.
y - p3.
y) ;
1016 radius = std::sqrt( std::max( r1, std::max( r2, r3) )) ;
1021 template<
typename Po
intInT>
inline bool
1027 double sizeX = cam.
width;
1028 double sizeY = cam.
height;
1039 double focal_x, focal_y;
1050 UV_coordinates.
x =
static_cast<float> ((focal_x * (pt.x / pt.z) + cx) / sizeX);
1051 UV_coordinates.
y = 1.0f -
static_cast<float> ((focal_y * (pt.y / pt.z) + cy) / sizeY);
1054 if (UV_coordinates.
x >= 0.0 && UV_coordinates.
x <= 1.0 && UV_coordinates.
y >= 0.0 && UV_coordinates.
y <= 1.0)
1059 UV_coordinates.
x = -1.0f;
1060 UV_coordinates.
y = -1.0f;
1065 template<
typename Po
intInT>
inline bool
1069 Eigen::Vector2d v0, v1, v2;
1070 v0(0) = p3.
x - p1.
x; v0(1) = p3.
y - p1.
y;
1071 v1(0) = p2.
x - p1.
x; v1(1) = p2.
y - p1.
y;
1072 v2(0) = pt.
x - p1.
x; v2(1) = pt.
y - p1.
y;
1075 double dot00 = v0.dot(v0);
1076 double dot01 = v0.dot(v1);
1077 double dot02 = v0.dot(v2);
1078 double dot11 = v1.dot(v1);
1079 double dot12 = v1.dot(v2);
1082 double invDenom = 1.0 / (dot00*dot11 - dot01*dot01);
1083 double u = (dot11*dot02 - dot01*dot12) * invDenom;
1084 double v = (dot00*dot12 - dot01*dot02) * invDenom;
1087 return ((u >= 0) && (v >= 0) && (u + v < 1));
1091 template<
typename Po
intInT>
inline bool
1094 return (getPointUVCoordinates(p1, camera, proj1)
1096 getPointUVCoordinates(p2, camera, proj2)
1098 getPointUVCoordinates(p3, camera, proj3)
1102 #define PCL_INSTANTIATE_TextureMapping(T) \
1103 template class PCL_EXPORTS pcl::TextureMapping<T>;