38 #ifndef PCL_SURFACE_IMPL_TEXTURE_MAPPING_HPP_
39 #define PCL_SURFACE_IMPL_TEXTURE_MAPPING_HPP_
44 template<
typename Po
intInT> std::vector<Eigen::Vector2f>
46 const Eigen::Vector3f &p1,
47 const Eigen::Vector3f &p2,
48 const Eigen::Vector3f &p3)
50 std::vector<Eigen::Vector2f> tex_coordinates;
52 Eigen::Vector3f p1p2 (p2[0] - p1[0], p2[1] - p1[1], p2[2] - p1[2]);
53 Eigen::Vector3f p1p3 (p3[0] - p1[0], p3[1] - p1[1], p3[2] - p1[2]);
54 Eigen::Vector3f p2p3 (p3[0] - p2[0], p3[1] - p2[1], p3[2] - p2[2]);
57 p1p2 = p1p2 /
std::sqrt (p1p2.dot (p1p2));
58 p1p3 = p1p3 /
std::sqrt (p1p3.dot (p1p3));
59 p2p3 = p2p3 /
std::sqrt (p2p3.dot (p2p3));
62 Eigen::Vector3f f_normal = p1p2.cross (p1p3);
63 f_normal = f_normal /
std::sqrt (f_normal.dot (f_normal));
66 Eigen::Vector3f f_vector_field = vector_field_ - vector_field_.dot (f_normal) * f_normal;
69 f_vector_field = f_vector_field /
std::sqrt (f_vector_field.dot (f_vector_field));
72 Eigen::Vector2f tp1, tp2, tp3;
74 double alpha = std::acos (f_vector_field.dot (p1p2));
77 double e1 = (p2 - p3).norm () / f_;
78 double e2 = (p1 - p3).norm () / f_;
79 double e3 = (p1 - p2).norm () / f_;
85 tp2[0] =
static_cast<float> (e3);
89 double cos_p1 = (e2 * e2 + e3 * e3 - e1 * e1) / (2 * e2 * e3);
90 double sin_p1 =
sqrt (1 - (cos_p1 * cos_p1));
92 tp3[0] =
static_cast<float> (cos_p1 * e2);
93 tp3[1] =
static_cast<float> (sin_p1 * e2);
96 Eigen::Vector2f r_tp2, r_tp3;
97 r_tp2[0] =
static_cast<float> (tp2[0] * std::cos (alpha) - tp2[1] * std::sin (alpha));
98 r_tp2[1] =
static_cast<float> (tp2[0] * std::sin (alpha) + tp2[1] * std::cos (alpha));
100 r_tp3[0] =
static_cast<float> (tp3[0] * std::cos (alpha) - tp3[1] * std::sin (alpha));
101 r_tp3[1] =
static_cast<float> (tp3[0] * std::sin (alpha) + tp3[1] * std::cos (alpha));
111 float min_x = tp1[0];
112 float min_y = tp1[1];
124 tp1[0] = tp1[0] - min_x;
125 tp2[0] = tp2[0] - min_x;
126 tp3[0] = tp3[0] - min_x;
130 tp1[1] = tp1[1] - min_y;
131 tp2[1] = tp2[1] - min_y;
132 tp3[1] = tp3[1] - min_y;
135 tex_coordinates.push_back (tp1);
136 tex_coordinates.push_back (tp2);
137 tex_coordinates.push_back (tp3);
138 return (tex_coordinates);
142 template<
typename Po
intInT>
void
147 int point_size =
static_cast<int> (tex_mesh.
cloud.
data.size ()) / nr_points;
152 Eigen::Vector3f facet[3];
155 std::vector<std::vector<Eigen::Vector2f> > texture_map;
157 for (
size_t m = 0; m < tex_mesh.
tex_polygons.size (); ++m)
160 std::vector<Eigen::Vector2f> texture_map_tmp;
163 for (
size_t i = 0; i < tex_mesh.
tex_polygons[m].size (); ++i)
168 for (
size_t j = 0; j < tex_mesh.
tex_polygons[m][i].vertices.size (); ++j)
171 memcpy (&x, &tex_mesh.
cloud.
data[idx * point_size + tex_mesh.
cloud.
fields[0].offset],
sizeof(
float));
172 memcpy (&y, &tex_mesh.
cloud.
data[idx * point_size + tex_mesh.
cloud.
fields[1].offset],
sizeof(
float));
173 memcpy (&z, &tex_mesh.
cloud.
data[idx * point_size + tex_mesh.
cloud.
fields[2].offset],
sizeof(
float));
180 std::vector<Eigen::Vector2f> tex_coordinates = mapTexture2Face (facet[0], facet[1], facet[2]);
181 for (
size_t n = 0; n < tex_coordinates.size (); ++n)
182 texture_map_tmp.push_back (tex_coordinates[n]);
186 std::stringstream tex_name;
187 tex_name <<
"material_" << m;
188 tex_name >> tex_material_.tex_name;
189 tex_material_.tex_file = tex_files_[m];
198 template<
typename Po
intInT>
void
203 int point_size =
static_cast<int> (tex_mesh.
cloud.
data.size ()) / nr_points;
205 float x_lowest = 100000;
207 float y_lowest = 100000;
209 float z_lowest = 100000;
213 for (
int i = 0; i < nr_points; ++i)
215 memcpy (&x_, &tex_mesh.
cloud.
data[i * point_size + tex_mesh.
cloud.
fields[0].offset],
sizeof(
float));
216 memcpy (&y_, &tex_mesh.
cloud.
data[i * point_size + tex_mesh.
cloud.
fields[1].offset],
sizeof(
float));
217 memcpy (&z_, &tex_mesh.
cloud.
data[i * point_size + tex_mesh.
cloud.
fields[2].offset],
sizeof(
float));
236 float x_range = (x_lowest - x_highest) * -1;
237 float x_offset = 0 - x_lowest;
242 float z_range = (z_lowest - z_highest) * -1;
243 float z_offset = 0 - z_lowest;
246 std::vector<std::vector<Eigen::Vector2f> > texture_map;
248 for (
size_t m = 0; m < tex_mesh.
tex_polygons.size (); ++m)
251 std::vector<Eigen::Vector2f> texture_map_tmp;
254 for (
size_t i = 0; i < tex_mesh.
tex_polygons[m].size (); ++i)
257 Eigen::Vector2f tmp_VT;
258 for (
size_t j = 0; j < tex_mesh.
tex_polygons[m][i].vertices.size (); ++j)
261 memcpy (&x_, &tex_mesh.
cloud.
data[idx * point_size + tex_mesh.
cloud.
fields[0].offset],
sizeof(
float));
262 memcpy (&y_, &tex_mesh.
cloud.
data[idx * point_size + tex_mesh.
cloud.
fields[1].offset],
sizeof(
float));
263 memcpy (&z_, &tex_mesh.
cloud.
data[idx * point_size + tex_mesh.
cloud.
fields[2].offset],
sizeof(
float));
266 tmp_VT[0] = (x_ + x_offset) / x_range;
267 tmp_VT[1] = (z_ + z_offset) / z_range;
268 texture_map_tmp.push_back (tmp_VT);
273 std::stringstream tex_name;
274 tex_name <<
"material_" << m;
275 tex_name >> tex_material_.tex_name;
276 tex_material_.tex_file = tex_files_[m];
285 template<
typename Po
intInT>
void
291 PCL_ERROR (
"The mesh should be divided into nbCamera+1 sub-meshes.\n");
292 PCL_ERROR (
"You provided %d cameras and a mesh containing %d sub-meshes.\n", cams.size (), tex_mesh.
tex_polygons.size ());
296 PCL_INFO (
"You provided %d cameras and a mesh containing %d sub-meshes.\n", cams.size (), tex_mesh.
tex_polygons.size ());
305 std::vector<std::vector<Eigen::Vector2f> > texture_map;
307 for (
size_t m = 0; m < cams.size (); ++m)
310 Camera current_cam = cams[m];
313 Eigen::Affine3f cam_trans = current_cam.
pose;
319 std::vector<Eigen::Vector2f> texture_map_tmp;
324 for (
size_t i = 0; i < tex_mesh.
tex_polygons[m].size (); ++i)
326 Eigen::Vector2f tmp_VT;
328 for (
size_t j = 0; j < tex_mesh.
tex_polygons[m][i].vertices.size (); ++j)
332 pt = camera_transformed_cloud->
points[idx];
335 getPointUVCoordinates (pt, current_cam, tmp_VT);
336 texture_map_tmp.push_back (tmp_VT);
342 std::stringstream tex_name;
343 tex_name <<
"material_" << m;
344 tex_name >> tex_material_.tex_name;
353 std::vector<Eigen::Vector2f> texture_map_tmp;
354 for (
size_t i = 0; i < tex_mesh.
tex_polygons[cams.size ()].size (); ++i)
355 for (
size_t j = 0; j < tex_mesh.
tex_polygons[cams.size ()][i].vertices.size (); ++j)
357 Eigen::Vector2f tmp_VT;
360 texture_map_tmp.push_back (tmp_VT);
366 std::stringstream tex_name;
367 tex_name <<
"material_" << cams.size ();
368 tex_name >> tex_material_.tex_name;
369 tex_material_.tex_file =
"occluded.jpg";
375 template<
typename Po
intInT>
bool
378 Eigen::Vector3f direction;
379 direction (0) = pt.x;
380 direction (1) = pt.y;
381 direction (2) = pt.z;
383 std::vector<int> indices;
386 cloud = octree->getInputCloud();
388 double distance_threshold = octree->getResolution();
391 octree->getIntersectedVoxelIndices(direction, -direction, indices);
393 int nbocc =
static_cast<int> (indices.size ());
394 for (
size_t j = 0; j < indices.size (); j++)
397 if (pt.z * cloud->points[indices[j]].z < 0)
403 if (fabs (cloud->points[indices[j]].z - pt.z) <= distance_threshold)
417 template<
typename Po
intInT>
void
420 const double octree_voxel_size, std::vector<int> &visible_indices,
421 std::vector<int> &occluded_indices)
424 double maxDeltaZ = octree_voxel_size;
429 octree->setInputCloud (input_cloud);
431 octree->defineBoundingBox ();
433 octree->addPointsFromInputCloud ();
435 visible_indices.clear ();
438 Eigen::Vector3f direction;
439 std::vector<int> indices;
440 for (
size_t i = 0; i < input_cloud->points.size (); ++i)
442 direction (0) = input_cloud->points[i].x;
443 direction (1) = input_cloud->points[i].y;
444 direction (2) = input_cloud->points[i].z;
447 octree->getIntersectedVoxelIndices (direction, -direction, indices);
449 int nbocc =
static_cast<int> (indices.size ());
450 for (
size_t j = 0; j < indices.size (); j++)
453 if (input_cloud->points[i].z * input_cloud->points[indices[j]].z < 0)
459 if (fabs (input_cloud->points[indices[j]].z - input_cloud->points[i].z) <= maxDeltaZ)
469 filtered_cloud->points.push_back (input_cloud->points[i]);
470 visible_indices.push_back (static_cast<int> (i));
474 occluded_indices.push_back (static_cast<int> (i));
481 template<
typename Po
intInT>
void
485 cleaned_mesh = tex_mesh;
493 std::vector<int> visible, occluded;
494 removeOccludedPoints (cloud, filtered_cloud, octree_voxel_size, visible, occluded);
498 for (
size_t polygons = 0; polygons < cleaned_mesh.
tex_polygons.size (); ++polygons)
503 for (
size_t faces = 0; faces < tex_mesh.
tex_polygons[polygons].size (); ++faces)
506 bool faceIsVisible =
true;
507 std::vector<int>::iterator it;
510 for (
size_t points = 0; points < tex_mesh.
tex_polygons[polygons][faces].vertices.size (); ++points)
512 it = find (occluded.begin (), occluded.end (), tex_mesh.
tex_polygons[polygons][faces].vertices[points]);
514 if (it == occluded.end ())
523 faceIsVisible =
false;
537 template<
typename Po
intInT>
void
539 const double octree_voxel_size)
546 std::vector<int> visible, occluded;
547 removeOccludedPoints (cloud, filtered_cloud, octree_voxel_size, visible, occluded);
552 template<
typename Po
intInT>
int
559 PCL_ERROR (
"The mesh must contain only 1 sub-mesh!\n");
563 if (cameras.size () == 0)
565 PCL_ERROR (
"Must provide at least one camera info!\n");
570 sorted_mesh = tex_mesh;
582 for (
size_t cam = 0; cam < cameras.size (); ++cam)
585 Eigen::Affine3f cam_trans = cameras[cam].pose;
591 std::vector<int> visible, occluded;
592 removeOccludedPoints (transformed_cloud, filtered_cloud, octree_voxel_size, visible, occluded);
593 visible_pts = *filtered_cloud;
597 std::vector<pcl::Vertices> visibleFaces_currentCam;
599 for (
size_t faces = 0; faces < tex_mesh.
tex_polygons[0].size (); ++faces)
602 bool faceIsVisible =
true;
603 std::vector<int>::iterator it;
606 for (
size_t current_pt_indice = 0; faceIsVisible && current_pt_indice < tex_mesh.
tex_polygons[0][faces].vertices.size (); ++current_pt_indice)
609 it = find (occluded.begin (), occluded.end (), tex_mesh.
tex_polygons[0][faces].vertices[current_pt_indice]);
611 if (it == occluded.end ())
616 Eigen::Vector2f dummy_UV;
617 if (!getPointUVCoordinates (pt, cameras[cam], dummy_UV))
620 faceIsVisible =
false;
625 faceIsVisible =
false;
632 visibleFaces_currentCam.push_back (tex_mesh.
tex_polygons[0][faces]);
639 sorted_mesh.
tex_polygons.push_back (visibleFaces_currentCam);
649 template<
typename Po
intInT>
void
652 const double octree_voxel_size,
const bool show_nb_occlusions,
653 const int max_occlusions)
656 double maxDeltaZ = octree_voxel_size * 2.0;
669 Eigen::Vector3f direction;
671 std::vector<int> indices;
675 std::vector<double> zDist;
676 std::vector<double> ptDist;
678 for (
size_t i = 0; i < input_cloud->points.size (); ++i)
680 direction (0) = input_cloud->points[i].x;
681 pt.x = input_cloud->points[i].x;
682 direction (1) = input_cloud->points[i].y;
683 pt.y = input_cloud->points[i].y;
684 direction (2) = input_cloud->points[i].z;
685 pt.z = input_cloud->points[i].z;
691 nbocc =
static_cast<int> (indices.size ());
694 for (
size_t j = 0; j < indices.size (); j++)
697 if (pt.z * input_cloud->points[indices[j]].z < 0)
701 else if (fabs (input_cloud->points[indices[j]].z - pt.z) <= maxDeltaZ)
708 zDist.push_back (fabs (input_cloud->points[indices[j]].z - pt.z));
713 if (show_nb_occlusions)
714 (nbocc <= max_occlusions) ? (pt.
intensity = static_cast<float> (nbocc)) : (pt.
intensity = static_cast<float> (max_occlusions));
718 colored_cloud->
points.push_back (pt);
721 if (zDist.size () >= 2)
723 std::sort (zDist.begin (), zDist.end ());
724 std::sort (ptDist.begin (), ptDist.end ());
729 template<
typename Po
intInT>
void
731 double octree_voxel_size,
bool show_nb_occlusions,
int max_occlusions)
737 showOcclusions (cloud, colored_cloud, octree_voxel_size, show_nb_occlusions, max_occlusions);
741 template<
typename Po
intInT>
void
752 std::vector<pcl::Vertices> faces;
754 for (
int current_cam = 0; current_cam < static_cast<int> (cameras.size ()); ++current_cam)
756 PCL_INFO (
"Processing camera %d of %d.\n", current_cam+1, cameras.size ());
764 std::vector<pcl::Vertices>::iterator current_face;
765 std::vector<bool> visibility;
766 visibility.resize (mesh.
tex_polygons[current_cam].size ());
767 std::vector<UvIndex> indexes_uv_to_points;
772 nan_point.
x = std::numeric_limits<float>::quiet_NaN ();
773 nan_point.
y = std::numeric_limits<float>::quiet_NaN ();
779 for (
int idx_face = 0; idx_face < static_cast<int> (mesh.
tex_polygons[current_cam].size ()); ++idx_face)
786 if (isFaceProjected (cameras[current_cam],
787 camera_cloud->points[mesh.
tex_polygons[current_cam][idx_face].vertices[0]],
788 camera_cloud->points[mesh.
tex_polygons[current_cam][idx_face].vertices[1]],
789 camera_cloud->points[mesh.
tex_polygons[current_cam][idx_face].vertices[2]],
797 projections->points.push_back (uv_coord1);
798 projections->points.push_back (uv_coord2);
799 projections->points.push_back (uv_coord3);
807 indexes_uv_to_points.push_back (u1);
808 indexes_uv_to_points.push_back (u2);
809 indexes_uv_to_points.push_back (u3);
812 visibility[idx_face] =
true;
816 projections->points.push_back (nan_point);
817 projections->points.push_back (nan_point);
818 projections->points.push_back (nan_point);
819 indexes_uv_to_points.push_back (u_null);
820 indexes_uv_to_points.push_back (u_null);
821 indexes_uv_to_points.push_back (u_null);
823 visibility[idx_face] =
false;
833 if (visibility.size () - cpt_invisible !=0)
839 std::vector<int> idxNeighbors;
840 std::vector<float> neighborsSquaredDistance;
844 for (
int idx_pcam = 0 ; idx_pcam <= current_cam ; ++idx_pcam)
847 for (
int idx_face = 0; idx_face < static_cast<int> (mesh.
tex_polygons[idx_pcam].size ()); ++idx_face)
850 if (idx_pcam == current_cam && !visibility[idx_face])
863 if (isFaceProjected (cameras[current_cam],
864 camera_cloud->points[mesh.
tex_polygons[idx_pcam][idx_face].vertices[0]],
865 camera_cloud->points[mesh.
tex_polygons[idx_pcam][idx_face].vertices[1]],
866 camera_cloud->points[mesh.
tex_polygons[idx_pcam][idx_face].vertices[2]],
875 getTriangleCircumcenterAndSize (uv_coord1, uv_coord2, uv_coord3, center, radius);
878 if (kdtree.
radiusSearch (center, radius, idxNeighbors, neighborsSquaredDistance) > 0 )
881 for (
size_t i = 0; i < idxNeighbors.size (); ++i)
883 if (std::max (camera_cloud->points[mesh.
tex_polygons[idx_pcam][idx_face].vertices[0]].z,
884 std::max (camera_cloud->points[mesh.
tex_polygons[idx_pcam][idx_face].vertices[1]].z,
885 camera_cloud->points[mesh.
tex_polygons[idx_pcam][idx_face].vertices[2]].z))
886 < camera_cloud->points[indexes_uv_to_points[idxNeighbors[i]].idx_cloud].z)
889 if (checkPointInsideTriangle(uv_coord1, uv_coord2, uv_coord3, projections->points[idxNeighbors[i]]))
892 visibility[indexes_uv_to_points[idxNeighbors[i]].idx_face] =
false;
909 std::vector<Eigen::Vector2f> dummy_container;
914 std::vector<pcl::Vertices> occluded_faces;
915 occluded_faces.resize (visibility.size ());
916 std::vector<pcl::Vertices> visible_faces;
917 visible_faces.resize (visibility.size ());
919 int cpt_occluded_faces = 0;
920 int cpt_visible_faces = 0;
922 for (
size_t idx_face = 0 ; idx_face < visibility.size () ; ++idx_face)
924 if (visibility[idx_face])
927 mesh.
tex_coordinates[current_cam][cpt_visible_faces * 3](0) = projections->points[idx_face*3].x;
928 mesh.
tex_coordinates[current_cam][cpt_visible_faces * 3](1) = projections->points[idx_face*3].y;
930 mesh.
tex_coordinates[current_cam][cpt_visible_faces * 3 + 1](0) = projections->points[idx_face*3 + 1].x;
931 mesh.
tex_coordinates[current_cam][cpt_visible_faces * 3 + 1](1) = projections->points[idx_face*3 + 1].y;
933 mesh.
tex_coordinates[current_cam][cpt_visible_faces * 3 + 2](0) = projections->points[idx_face*3 + 2].x;
934 mesh.
tex_coordinates[current_cam][cpt_visible_faces * 3 + 2](1) = projections->points[idx_face*3 + 2].y;
936 visible_faces[cpt_visible_faces] = mesh.
tex_polygons[current_cam][idx_face];
943 occluded_faces[cpt_occluded_faces] = mesh.
tex_polygons[current_cam][idx_face];
944 cpt_occluded_faces++;
949 occluded_faces.resize (cpt_occluded_faces);
952 visible_faces.resize (cpt_visible_faces);
957 for (
int i = 0; i < static_cast<int> (mesh.
tex_polygons.size ()); i++)
958 nb_faces += static_cast<int> (mesh.
tex_polygons[i].size ());
967 std::vector<Eigen::Vector2f> dummy_container;
972 for(
size_t idx_face = 0 ; idx_face < mesh.
tex_polygons[cameras.size()].size() ; ++idx_face)
974 Eigen::Vector2f UV1, UV2, UV3;
975 UV1(0) = -1.0; UV1(1) = -1.0;
976 UV2(0) = -1.0; UV2(1) = -1.0;
977 UV3(0) = -1.0; UV3(1) = -1.0;
986 template<
typename Po
intInT>
inline void
991 ptB.
x = p2.
x - p1.
x; ptB.
y = p2.
y - p1.
y;
992 ptC.
x = p3.
x - p1.
x; ptC.
y = p3.
y - p1.
y;
994 double D = 2.0*(ptB.
x*ptC.
y - ptB.
y*ptC.
x);
999 circomcenter.
x = p1.
x;
1000 circomcenter.
y = p1.
y;
1005 double bx2 = ptB.
x * ptB.
x;
1006 double by2 = ptB.
y * ptB.
y;
1007 double cx2 = ptC.
x * ptC.
x;
1008 double cy2 = ptC.
y * ptC.
y;
1011 circomcenter.
x =
static_cast<float> (p1.
x + (ptC.
y*(bx2 + by2) - ptB.
y*(cx2 + cy2)) / D);
1012 circomcenter.
y =
static_cast<float> (p1.
y + (ptB.
x*(cx2 + cy2) - ptC.
x*(bx2 + by2)) / D);
1015 radius =
sqrt( (circomcenter.
x - p1.
x)*(circomcenter.
x - p1.
x) + (circomcenter.
y - p1.
y)*(circomcenter.
y - p1.
y));
1019 template<
typename Po
intInT>
inline bool
1025 double sizeX = cam.width;
1026 double sizeY = cam.height;
1027 double cx = sizeX / 2.0;
1028 double cy = sizeY / 2.0;
1031 UV_coordinates.
x =
static_cast<float> ((cam.focal_length * (pt.x / pt.z) + cx) / sizeX);
1032 UV_coordinates.
y = 1.0f -
static_cast<float> ((cam.focal_length * (pt.y / pt.z) + cy) / sizeY);
1035 if (UV_coordinates.
x >= 0.0 && UV_coordinates.
x <= 1.0 && UV_coordinates.
y >= 0.0 && UV_coordinates.
y <= 1.0)
1040 UV_coordinates.
x = -1.0f;
1041 UV_coordinates.
y = -1.0f;
1046 template<
typename Po
intInT>
inline bool
1050 Eigen::Vector2d v0, v1, v2;
1051 v0(0) = p3.
x - p1.
x; v0(1) = p3.
y - p1.
y;
1052 v1(0) = p2.
x - p1.
x; v1(1) = p2.
y - p1.
y;
1053 v2(0) = pt.
x - p1.
x; v2(1) = pt.
y - p1.
y;
1056 double dot00 = v0.dot(v0);
1057 double dot01 = v0.dot(v1);
1058 double dot02 = v0.dot(v2);
1059 double dot11 = v1.dot(v1);
1060 double dot12 = v1.dot(v2);
1063 double invDenom = 1.0 / (dot00*dot11 - dot01*dot01);
1064 double u = (dot11*dot02 - dot01*dot12) * invDenom;
1065 double v = (dot00*dot12 - dot01*dot02) * invDenom;
1068 return ((u >= 0) && (v >= 0) && (u + v < 1));
1072 template<
typename Po
intInT>
inline bool
1075 return (getPointUVCoordinates(p1, camera, proj1)
1077 getPointUVCoordinates(p2, camera, proj2)
1079 getPointUVCoordinates(p3, camera, proj3)
1083 #define PCL_INSTANTIATE_TextureMapping(T) \
1084 template class PCL_EXPORTS pcl::TextureMapping<T>;