38 #ifndef PCL_SURFACE_IMPL_TEXTURE_MAPPING_HPP_
39 #define PCL_SURFACE_IMPL_TEXTURE_MAPPING_HPP_
41 #include <pcl/common/distances.h>
43 #include <pcl/search/octree.h>
44 #include <pcl/common/common.h>
47 template<
typename Po
intInT> std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> >
49 const Eigen::Vector3f &p1,
50 const Eigen::Vector3f &p2,
51 const Eigen::Vector3f &p3)
53 std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > tex_coordinates;
55 Eigen::Vector3f p1p2 (
p2[0] -
p1[0],
p2[1] -
p1[1],
p2[2] -
p1[2]);
56 Eigen::Vector3f p1p3 (
p3[0] -
p1[0],
p3[1] -
p1[1],
p3[2] -
p1[2]);
57 Eigen::Vector3f p2p3 (
p3[0] -
p2[0],
p3[1] -
p2[1],
p3[2] -
p2[2]);
60 p1p2 = p1p2 /
std::sqrt (p1p2.dot (p1p2));
61 p1p3 = p1p3 /
std::sqrt (p1p3.dot (p1p3));
62 p2p3 = p2p3 /
std::sqrt (p2p3.dot (p2p3));
65 Eigen::Vector3f f_normal = p1p2.cross (p1p3);
66 f_normal = f_normal /
std::sqrt (f_normal.dot (f_normal));
69 Eigen::Vector3f f_vector_field = vector_field_ - vector_field_.dot (f_normal) * f_normal;
72 f_vector_field = f_vector_field /
std::sqrt (f_vector_field.dot (f_vector_field));
75 Eigen::Vector2f tp1, tp2, tp3;
80 double e1 = (
p2 -
p3).norm () / f_;
81 double e2 = (
p1 -
p3).norm () / f_;
82 double e3 = (
p1 -
p2).norm () / f_;
88 tp2[0] =
static_cast<float> (e3);
92 double cos_p1 = (e2 * e2 + e3 * e3 - e1 * e1) / (2 * e2 * e3);
93 double sin_p1 =
sqrt (1 - (cos_p1 * cos_p1));
95 tp3[0] =
static_cast<float> (cos_p1 * e2);
96 tp3[1] =
static_cast<float> (sin_p1 * e2);
99 Eigen::Vector2f r_tp2, r_tp3;
114 float min_x = tp1[0];
115 float min_y = tp1[1];
127 tp1[0] = tp1[0] - min_x;
128 tp2[0] = tp2[0] - min_x;
129 tp3[0] = tp3[0] - min_x;
133 tp1[1] = tp1[1] - min_y;
134 tp2[1] = tp2[1] - min_y;
135 tp3[1] = tp3[1] - min_y;
138 tex_coordinates.push_back (tp1);
139 tex_coordinates.push_back (tp2);
140 tex_coordinates.push_back (tp3);
141 return (tex_coordinates);
145 template<
typename Po
intInT>
void
149 int nr_points = tex_mesh.cloud.width * tex_mesh.cloud.height;
150 int point_size =
static_cast<int> (tex_mesh.cloud.data.size ()) / nr_points;
155 Eigen::Vector3f facet[3];
158 std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > >texture_map;
160 for (
size_t m = 0;
m < tex_mesh.tex_polygons.size (); ++
m)
163 #if PCL_VERSION_COMPARE(>=, 1, 8, 0)
164 std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > texture_map_tmp;
166 std::vector<Eigen::Vector2f> texture_map_tmp;
170 for (
size_t i = 0;
i < tex_mesh.tex_polygons[
m].size (); ++
i)
175 for (
size_t j = 0;
j < tex_mesh.tex_polygons[
m][
i].vertices.size (); ++
j)
177 idx = tex_mesh.tex_polygons[
m][
i].vertices[
j];
178 memcpy (&
x, &tex_mesh.cloud.data[idx * point_size + tex_mesh.cloud.fields[0].offset],
sizeof(
float));
179 memcpy (&
y, &tex_mesh.cloud.data[idx * point_size + tex_mesh.cloud.fields[1].offset],
sizeof(
float));
180 memcpy (&
z, &tex_mesh.cloud.data[idx * point_size + tex_mesh.cloud.fields[2].offset],
sizeof(
float));
187 std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > tex_coordinates = mapTexture2Face (facet[0], facet[1], facet[2]);
188 for (
size_t n = 0;
n < tex_coordinates.size (); ++
n)
189 texture_map_tmp.push_back (tex_coordinates[
n]);
193 std::stringstream tex_name;
194 tex_name <<
"material_" <<
m;
195 tex_name >> tex_material_.tex_name;
196 tex_material_.tex_file = tex_files_[
m];
197 tex_mesh.tex_materials.push_back (tex_material_);
200 tex_mesh.tex_coordinates.push_back (texture_map_tmp);
205 template<
typename Po
intInT>
void
209 int nr_points = tex_mesh.cloud.width * tex_mesh.cloud.height;
210 int point_size =
static_cast<int> (tex_mesh.cloud.data.size ()) / nr_points;
212 float x_lowest = 100000;
214 float y_lowest = 100000;
216 float z_lowest = 100000;
220 for (
int i = 0;
i < nr_points; ++
i)
222 memcpy (&x_, &tex_mesh.cloud.data[
i * point_size + tex_mesh.cloud.fields[0].offset],
sizeof(
float));
223 memcpy (&y_, &tex_mesh.cloud.data[
i * point_size + tex_mesh.cloud.fields[1].offset],
sizeof(
float));
224 memcpy (&z_, &tex_mesh.cloud.data[
i * point_size + tex_mesh.cloud.fields[2].offset],
sizeof(
float));
243 float x_range = (x_lowest - x_highest) * -1;
244 float x_offset = 0 - x_lowest;
249 float z_range = (z_lowest - z_highest) * -1;
250 float z_offset = 0 - z_lowest;
253 std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > >texture_map;
255 for (
size_t m = 0;
m < tex_mesh.tex_polygons.size (); ++
m)
258 #if PCL_VERSION_COMPARE(>=, 1, 8, 0)
259 std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > texture_map_tmp;
261 std::vector<Eigen::Vector2f> texture_map_tmp;
265 for (
size_t i = 0;
i < tex_mesh.tex_polygons[
m].size (); ++
i)
268 Eigen::Vector2f tmp_VT;
269 for (
size_t j = 0;
j < tex_mesh.tex_polygons[
m][
i].vertices.size (); ++
j)
271 idx = tex_mesh.tex_polygons[
m][
i].vertices[
j];
272 memcpy (&x_, &tex_mesh.cloud.data[idx * point_size + tex_mesh.cloud.fields[0].offset],
sizeof(
float));
273 memcpy (&y_, &tex_mesh.cloud.data[idx * point_size + tex_mesh.cloud.fields[1].offset],
sizeof(
float));
274 memcpy (&z_, &tex_mesh.cloud.data[idx * point_size + tex_mesh.cloud.fields[2].offset],
sizeof(
float));
277 tmp_VT[0] = (x_ + x_offset) / x_range;
278 tmp_VT[1] = (z_ + z_offset) / z_range;
279 texture_map_tmp.push_back (tmp_VT);
284 std::stringstream tex_name;
285 tex_name <<
"material_" <<
m;
286 tex_name >> tex_material_.tex_name;
287 tex_material_.tex_file = tex_files_[
m];
288 tex_mesh.tex_materials.push_back (tex_material_);
291 tex_mesh.tex_coordinates.push_back (texture_map_tmp);
296 template<
typename Po
intInT>
void
300 if (tex_mesh.tex_polygons.size () != cams.size () + 1)
302 PCL_ERROR (
"The mesh should be divided into nbCamera+1 sub-meshes.\n");
303 PCL_ERROR (
"You provided %d cameras and a mesh containing %d sub-meshes.\n", cams.size (), tex_mesh.tex_polygons.size ());
307 PCL_INFO (
"You provided %d cameras and a mesh containing %d sub-meshes.\n", cams.size (), tex_mesh.tex_polygons.size ());
309 typename pcl::PointCloud<PointInT>::Ptr originalCloud (
new pcl::PointCloud<PointInT>);
310 typename pcl::PointCloud<PointInT>::Ptr camera_transformed_cloud (
new pcl::PointCloud<PointInT>);
313 pcl::fromPCLPointCloud2 (tex_mesh.cloud, *originalCloud);
316 std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > texture_map;
318 for (
size_t m = 0;
m < cams.size (); ++
m)
330 #if PCL_VERSION_COMPARE(>=, 1, 8, 0)
331 std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > texture_map_tmp;
333 std::vector<Eigen::Vector2f> texture_map_tmp;
339 for (
size_t i = 0;
i < tex_mesh.tex_polygons[
m].size (); ++
i)
341 Eigen::Vector2f tmp_VT;
343 for (
size_t j = 0;
j < tex_mesh.tex_polygons[
m][
i].vertices.size (); ++
j)
346 idx = tex_mesh.tex_polygons[
m][
i].vertices[
j];
347 pt = camera_transformed_cloud->points[idx];
350 getPointUVCoordinates (pt, current_cam, tmp_VT);
351 texture_map_tmp.push_back (tmp_VT);
357 std::stringstream tex_name;
358 tex_name <<
"material_" <<
m;
359 tex_name >> tex_material_.tex_name;
361 tex_mesh.tex_materials.push_back (tex_material_);
364 tex_mesh.tex_coordinates.push_back (texture_map_tmp);
368 #if PCL_VERSION_COMPARE(>=, 1, 8, 0)
369 std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > texture_map_tmp;
371 std::vector<Eigen::Vector2f> texture_map_tmp;
373 for (
size_t i = 0;
i < tex_mesh.tex_polygons[cams.size ()].
size (); ++
i)
374 for (
size_t j = 0;
j < tex_mesh.tex_polygons[cams.size ()][
i].
vertices.size (); ++
j)
376 Eigen::Vector2f tmp_VT;
379 texture_map_tmp.push_back (tmp_VT);
382 tex_mesh.tex_coordinates.push_back (texture_map_tmp);
385 std::stringstream tex_name;
386 tex_name <<
"material_" << cams.size ();
387 tex_name >> tex_material_.tex_name;
388 tex_material_.tex_file =
"occluded.jpg";
389 tex_mesh.tex_materials.push_back (tex_material_);
394 template<
typename Po
intInT>
bool
397 Eigen::Vector3f direction;
398 direction (0) = pt.x;
399 direction (1) = pt.y;
400 direction (2) = pt.z;
405 cloud =
octree->getInputCloud();
407 double distance_threshold =
octree->getResolution();
410 octree->getIntersectedVoxelIndices(direction, -direction,
indices);
412 int nbocc =
static_cast<int> (
indices.size ());
416 if (pt.z * cloud->points[
indices[
j]].z < 0)
422 if (
fabs (cloud->points[
indices[
j]].z - pt.z) <= distance_threshold)
436 template<
typename Po
intInT>
void
439 const double octree_voxel_size, std::vector<int> &visible_indices,
440 std::vector<int> &occluded_indices)
443 double maxDeltaZ = octree_voxel_size;
448 octree->setInputCloud (input_cloud);
450 octree->defineBoundingBox ();
452 octree->addPointsFromInputCloud ();
454 visible_indices.clear ();
457 Eigen::Vector3f direction;
459 for (
size_t i = 0;
i < input_cloud->points.size (); ++
i)
461 direction (0) = input_cloud->points[
i].x;
462 direction (1) = input_cloud->points[
i].y;
463 direction (2) = input_cloud->points[
i].z;
466 octree->getIntersectedVoxelIndices (direction, -direction,
indices);
468 int nbocc =
static_cast<int> (
indices.size ());
472 if (input_cloud->points[
i].z * input_cloud->points[
indices[
j]].z < 0)
478 if (
fabs (input_cloud->points[
indices[
j]].z - input_cloud->points[
i].z) <= maxDeltaZ)
488 filtered_cloud->points.push_back (input_cloud->points[
i]);
489 visible_indices.push_back (
static_cast<int> (
i));
493 occluded_indices.push_back (
static_cast<int> (
i));
500 template<
typename Po
intInT>
void
504 cleaned_mesh = tex_mesh;
506 typename pcl::PointCloud<PointInT>::Ptr cloud (
new pcl::PointCloud<PointInT>);
507 typename pcl::PointCloud<PointInT>::Ptr filtered_cloud (
new pcl::PointCloud<PointInT>);
510 pcl::fromPCLPointCloud2 (tex_mesh.cloud, *cloud);
512 std::vector<int> visible, occluded;
513 removeOccludedPoints (cloud, filtered_cloud, octree_voxel_size, visible, occluded);
517 for (
size_t polygons = 0; polygons < cleaned_mesh.tex_polygons.size (); ++polygons)
520 cleaned_mesh.tex_polygons[polygons].clear ();
522 for (
size_t faces = 0; faces < tex_mesh.tex_polygons[polygons].size (); ++faces)
525 bool faceIsVisible =
true;
526 std::vector<int>::iterator it;
529 for (
size_t points = 0; points < tex_mesh.tex_polygons[polygons][faces].vertices.size (); ++points)
531 it = find (occluded.begin (), occluded.end (), tex_mesh.tex_polygons[polygons][faces].vertices[points]);
533 if (it == occluded.end ())
542 faceIsVisible =
false;
548 cleaned_mesh.tex_polygons[polygons].push_back (tex_mesh.tex_polygons[polygons][faces]);
556 template<
typename Po
intInT>
void
558 const double octree_voxel_size)
563 pcl::fromPCLPointCloud2 (tex_mesh.cloud, *cloud);
565 std::vector<int> visible, occluded;
566 removeOccludedPoints (cloud, filtered_cloud, octree_voxel_size, visible, occluded);
571 template<
typename Po
intInT>
int
576 if (tex_mesh.tex_polygons.size () != 1)
578 PCL_ERROR (
"The mesh must contain only 1 sub-mesh!\n");
582 if (cameras.size () == 0)
584 PCL_ERROR (
"Must provide at least one camera info!\n");
589 sorted_mesh = tex_mesh;
591 sorted_mesh.tex_polygons.clear ();
593 typename pcl::PointCloud<PointInT>::Ptr original_cloud (
new pcl::PointCloud<PointInT>);
594 typename pcl::PointCloud<PointInT>::Ptr transformed_cloud (
new pcl::PointCloud<PointInT>);
595 typename pcl::PointCloud<PointInT>::Ptr filtered_cloud (
new pcl::PointCloud<PointInT>);
598 pcl::fromPCLPointCloud2 (tex_mesh.cloud, *original_cloud);
601 for (
size_t cam = 0;
cam < cameras.size (); ++
cam)
610 std::vector<int> visible, occluded;
611 removeOccludedPoints (transformed_cloud, filtered_cloud, octree_voxel_size, visible, occluded);
612 visible_pts = *filtered_cloud;
616 std::vector<pcl::Vertices> visibleFaces_currentCam;
618 for (
size_t faces = 0; faces < tex_mesh.tex_polygons[0].size (); ++faces)
621 bool faceIsVisible =
true;
622 std::vector<int>::iterator it;
625 for (
size_t current_pt_indice = 0; faceIsVisible && current_pt_indice < tex_mesh.tex_polygons[0][faces].vertices.size (); ++current_pt_indice)
628 it = find (occluded.begin (), occluded.end (), tex_mesh.tex_polygons[0][faces].vertices[current_pt_indice]);
630 if (it == occluded.end ())
634 PointInT pt = transformed_cloud->points[tex_mesh.tex_polygons[0][faces].vertices[current_pt_indice]];
635 Eigen::Vector2f dummy_UV;
636 if (!getPointUVCoordinates (pt, cameras[
cam], dummy_UV))
639 faceIsVisible =
false;
644 faceIsVisible =
false;
651 visibleFaces_currentCam.push_back (tex_mesh.tex_polygons[0][faces]);
653 tex_mesh.tex_polygons[0].erase (tex_mesh.tex_polygons[0].begin () + faces);
658 sorted_mesh.tex_polygons.push_back (visibleFaces_currentCam);
663 sorted_mesh.tex_polygons.push_back (tex_mesh.tex_polygons[0]);
668 template<
typename Po
intInT>
void
670 pcl::PointCloud<pcl::PointXYZI>::Ptr &colored_cloud,
671 const double octree_voxel_size,
const bool show_nb_occlusions,
672 const int max_occlusions)
675 double maxDeltaZ = octree_voxel_size * 2.0;
678 pcl::octree::OctreePointCloudSearch<PointInT> *
octree;
679 octree =
new pcl::octree::OctreePointCloudSearch<PointInT> (octree_voxel_size);
681 octree->setInputCloud (input_cloud);
683 octree->defineBoundingBox ();
685 octree->addPointsFromInputCloud ();
688 Eigen::Vector3f direction;
694 std::vector<double> zDist;
695 std::vector<double> ptDist;
697 for (
size_t i = 0;
i < input_cloud->points.size (); ++
i)
699 direction (0) = input_cloud->points[
i].x;
700 pt.x = input_cloud->points[
i].x;
701 direction (1) = input_cloud->points[
i].y;
702 pt.y = input_cloud->points[
i].y;
703 direction (2) = input_cloud->points[
i].z;
704 pt.z = input_cloud->points[
i].z;
708 int nbocc =
octree->getIntersectedVoxelIndices (direction, -direction,
indices);
710 nbocc =
static_cast<int> (
indices.size ());
716 if (pt.z * input_cloud->points[
indices[
j]].z < 0)
720 else if (
fabs (input_cloud->points[
indices[
j]].z - pt.z) <= maxDeltaZ)
727 zDist.push_back (
fabs (input_cloud->points[
indices[
j]].z - pt.z));
728 ptDist.push_back (pcl::euclideanDistance (input_cloud->points[
indices[
j]], pt));
732 if (show_nb_occlusions)
733 (nbocc <= max_occlusions) ? (pt.intensity =
static_cast<float> (nbocc)) : (pt.intensity =
static_cast<float> (max_occlusions));
735 (nbocc == 0) ? (pt.intensity = 0) : (pt.intensity = 1);
737 colored_cloud->points.push_back (pt);
740 if (zDist.size () >= 2)
742 std::sort (zDist.begin (), zDist.end ());
743 std::sort (ptDist.begin (), ptDist.end ());
748 template<
typename Po
intInT>
void
750 double octree_voxel_size,
bool show_nb_occlusions,
int max_occlusions)
753 typename pcl::PointCloud<PointInT>::Ptr cloud (
new pcl::PointCloud<PointInT>);
754 pcl::fromPCLPointCloud2 (tex_mesh.cloud, *cloud);
756 showOcclusions (cloud, colored_cloud, octree_voxel_size, show_nb_occlusions, max_occlusions);
760 template<
typename Po
intInT>
void
764 if (mesh.tex_polygons.size () != 1)
767 typename pcl::PointCloud<PointInT>::Ptr mesh_cloud (
new pcl::PointCloud<PointInT>);
769 pcl::fromPCLPointCloud2 (mesh.cloud, *mesh_cloud);
771 std::vector<pcl::Vertices> faces;
773 for (
int current_cam = 0; current_cam < static_cast<int> (cameras.size ()); ++current_cam)
775 PCL_INFO (
"Processing camera %d of %d.\n", current_cam+1, cameras.size ());
778 typename pcl::PointCloud<PointInT>::Ptr camera_cloud (
new pcl::PointCloud<PointInT>);
782 pcl::PointCloud<pcl::PointXY>::Ptr projections (
new pcl::PointCloud<pcl::PointXY>);
783 std::vector<bool> visibility;
784 visibility.resize (mesh.tex_polygons[current_cam].size ());
785 std::vector<UvIndex> indexes_uv_to_points;
789 pcl::PointXY nan_point;
790 nan_point.x = std::numeric_limits<float>::quiet_NaN ();
791 nan_point.y = std::numeric_limits<float>::quiet_NaN ();
797 for (
int idx_face = 0; idx_face < static_cast<int> (mesh.tex_polygons[current_cam].size ()); ++idx_face)
800 pcl::PointXY uv_coord1;
801 pcl::PointXY uv_coord2;
802 pcl::PointXY uv_coord3;
804 if (isFaceProjected (cameras[current_cam],
805 camera_cloud->points[mesh.tex_polygons[current_cam][idx_face].vertices[0]],
806 camera_cloud->points[mesh.tex_polygons[current_cam][idx_face].vertices[1]],
807 camera_cloud->points[mesh.tex_polygons[current_cam][idx_face].vertices[2]],
815 projections->points.push_back (uv_coord1);
816 projections->points.push_back (uv_coord2);
817 projections->points.push_back (uv_coord3);
821 u1.
idx_cloud = mesh.tex_polygons[current_cam][idx_face].vertices[0];
822 u2.idx_cloud = mesh.tex_polygons[current_cam][idx_face].vertices[1];
823 u3.
idx_cloud = mesh.tex_polygons[current_cam][idx_face].vertices[2];
825 indexes_uv_to_points.push_back (u1);
826 indexes_uv_to_points.push_back (
u2);
827 indexes_uv_to_points.push_back (u3);
830 visibility[idx_face] =
true;
834 projections->points.push_back (nan_point);
835 projections->points.push_back (nan_point);
836 projections->points.push_back (nan_point);
837 indexes_uv_to_points.push_back (u_null);
838 indexes_uv_to_points.push_back (u_null);
839 indexes_uv_to_points.push_back (u_null);
841 visibility[idx_face] =
false;
851 if (visibility.size () - cpt_invisible !=0)
854 pcl::KdTreeFLANN<pcl::PointXY>
kdtree;
855 kdtree.setInputCloud (projections);
857 std::vector<int> idxNeighbors;
858 std::vector<float> neighborsSquaredDistance;
862 for (
int idx_pcam = 0 ; idx_pcam <= current_cam ; ++idx_pcam)
865 for (
int idx_face = 0; idx_face < static_cast<int> (mesh.tex_polygons[idx_pcam].size ()); ++idx_face)
868 if (idx_pcam == current_cam && !visibility[idx_face])
877 pcl::PointXY uv_coord1;
878 pcl::PointXY uv_coord2;
879 pcl::PointXY uv_coord3;
881 if (isFaceProjected (cameras[current_cam],
882 camera_cloud->points[mesh.tex_polygons[idx_pcam][idx_face].vertices[0]],
883 camera_cloud->points[mesh.tex_polygons[idx_pcam][idx_face].vertices[1]],
884 camera_cloud->points[mesh.tex_polygons[idx_pcam][idx_face].vertices[2]],
894 getTriangleCircumcscribedCircleCentroid(uv_coord1, uv_coord2, uv_coord3, center, radius);
897 if (
kdtree.radiusSearch (center, radius, idxNeighbors, neighborsSquaredDistance) > 0 )
900 for (
size_t i = 0;
i < idxNeighbors.size (); ++
i)
902 if (
std::max (camera_cloud->points[mesh.tex_polygons[idx_pcam][idx_face].vertices[0]].z,
903 std::max (camera_cloud->points[mesh.tex_polygons[idx_pcam][idx_face].vertices[1]].z,
904 camera_cloud->points[mesh.tex_polygons[idx_pcam][idx_face].vertices[2]].z))
905 < camera_cloud->points[indexes_uv_to_points[idxNeighbors[
i]].idx_cloud].z)
908 if (checkPointInsideTriangle(uv_coord1, uv_coord2, uv_coord3, projections->points[idxNeighbors[
i]]))
911 visibility[indexes_uv_to_points[idxNeighbors[
i]].idx_face] =
false;
926 if (
static_cast<int> (mesh.tex_coordinates.size ()) <= current_cam)
928 #if PCL_VERSION_COMPARE(>=, 1, 8, 0)
929 std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > dummy_container;
931 std::vector<Eigen::Vector2f> dummy_container;
933 mesh.tex_coordinates.push_back (dummy_container);
935 mesh.tex_coordinates[current_cam].resize (3 * visibility.size ());
937 std::vector<pcl::Vertices> occluded_faces;
938 occluded_faces.resize (visibility.size ());
939 std::vector<pcl::Vertices> visible_faces;
940 visible_faces.resize (visibility.size ());
942 int cpt_occluded_faces = 0;
943 int cpt_visible_faces = 0;
945 for (
size_t idx_face = 0 ; idx_face < visibility.size () ; ++idx_face)
947 if (visibility[idx_face])
950 mesh.tex_coordinates[current_cam][cpt_visible_faces * 3](0) = projections->points[idx_face*3].x;
951 mesh.tex_coordinates[current_cam][cpt_visible_faces * 3](1) = projections->points[idx_face*3].y;
953 mesh.tex_coordinates[current_cam][cpt_visible_faces * 3 + 1](0) = projections->points[idx_face*3 + 1].x;
954 mesh.tex_coordinates[current_cam][cpt_visible_faces * 3 + 1](1) = projections->points[idx_face*3 + 1].y;
956 mesh.tex_coordinates[current_cam][cpt_visible_faces * 3 + 2](0) = projections->points[idx_face*3 + 2].x;
957 mesh.tex_coordinates[current_cam][cpt_visible_faces * 3 + 2](1) = projections->points[idx_face*3 + 2].y;
959 visible_faces[cpt_visible_faces] = mesh.tex_polygons[current_cam][idx_face];
966 occluded_faces[cpt_occluded_faces] = mesh.tex_polygons[current_cam][idx_face];
967 cpt_occluded_faces++;
970 mesh.tex_coordinates[current_cam].resize (cpt_visible_faces*3);
972 occluded_faces.resize (cpt_occluded_faces);
973 mesh.tex_polygons.push_back (occluded_faces);
975 visible_faces.resize (cpt_visible_faces);
976 mesh.tex_polygons[current_cam].clear ();
977 mesh.tex_polygons[current_cam] = visible_faces;
984 if (mesh.tex_coordinates.size() <= cameras.size ())
986 #if PCL_VERSION_COMPARE(>=, 1, 8, 0)
987 std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > dummy_container;
989 std::vector<Eigen::Vector2f> dummy_container;
991 mesh.tex_coordinates.push_back(dummy_container);
995 for(
size_t idx_face = 0 ; idx_face < mesh.tex_polygons[cameras.size()].size() ; ++idx_face)
997 Eigen::Vector2f UV1, UV2, UV3;
998 UV1(0) = -1.0; UV1(1) = -1.0;
999 UV2(0) = -1.0; UV2(1) = -1.0;
1000 UV3(0) = -1.0; UV3(1) = -1.0;
1001 mesh.tex_coordinates[cameras.size()].push_back(UV1);
1002 mesh.tex_coordinates[cameras.size()].push_back(UV2);
1003 mesh.tex_coordinates[cameras.size()].push_back(UV3);
1015 const pcl::PointXY & uv1,
1016 const pcl::PointXY & uv2,
1017 const pcl::PointXY & uv3,
1018 const pcl::PointXY & center) :
1038 bool ptInTriangle(
const pcl::PointXY & p0,
const pcl::PointXY & p1,
const pcl::PointXY & p2,
const pcl::PointXY & p) {
1040 float sign =
A < 0 ? -1 : 1;
1044 return s > 0 &&
t > 0 && (
s +
t) < 2 *
A *
sign;
1048 template<
typename Po
intInT>
bool
1050 pcl::TextureMesh &mesh,
1053 std::vector<std::map<int, pcl::PointXY> > * vertexToPixels,
1054 bool distanceToCamPolicy)
1057 if (mesh.tex_polygons.size () != 1)
1060 typename pcl::PointCloud<PointInT>::Ptr mesh_cloud (
new pcl::PointCloud<PointInT>);
1062 pcl::fromPCLPointCloud2 (mesh.cloud, *mesh_cloud);
1064 std::vector<pcl::Vertices> faces;
1065 faces.swap(mesh.tex_polygons[0]);
1067 mesh.tex_polygons.clear();
1068 mesh.tex_polygons.resize(cameras.size()+1);
1069 mesh.tex_coordinates.clear();
1070 mesh.tex_coordinates.resize(cameras.size()+1);
1073 std::vector<std::map<int, FaceInfo > > visibleFaces(cameras.size());
1074 std::vector<Eigen::Affine3f> invCamTransform(cameras.size());
1075 std::vector<std::list<int> > faceCameras(faces.size());
1076 std::string
msg =
uFormat(
"Computing visible faces per cam (%d faces, %d cams)", (
int)faces.size(), (
int)cameras.size());
1081 UWARN(
"Texturing cancelled!");
1084 for (
unsigned int current_cam = 0; current_cam < cameras.size(); ++current_cam)
1086 UDEBUG(
"Texture camera %d...", current_cam);
1088 typename pcl::PointCloud<PointInT>::Ptr camera_cloud (
new pcl::PointCloud<PointInT>);
1091 std::vector<int> visibilityIndices;
1092 visibilityIndices.resize (faces.size ());
1093 pcl::PointCloud<pcl::PointXY>::Ptr projections (
new pcl::PointCloud<pcl::PointXY>);
1094 projections->resize(faces.size()*3);
1095 std::map<float, int> sortedVisibleFaces;
1097 for(
unsigned int idx_face=0; idx_face<faces.size(); ++idx_face)
1099 pcl::Vertices & face = faces[idx_face];
1102 pcl::PointXY & uv_coords1 = projections->at(
j);
1103 pcl::PointXY & uv_coords2 = projections->at(
j+1);
1104 pcl::PointXY & uv_coords3 = projections->at(
j+2);
1105 PointInT & pt0 = camera_cloud->points[face.vertices[0]];
1106 PointInT & pt1 = camera_cloud->points[face.vertices[1]];
1107 PointInT & pt2 = camera_cloud->points[face.vertices[2]];
1108 if (isFaceProjected (cameras[current_cam],
1118 uv_coords2.x - uv_coords1.x,
1119 uv_coords2.y - uv_coords1.y,
1122 uv_coords3.x - uv_coords1.x,
1123 uv_coords3.y - uv_coords1.y,
1125 Eigen::Vector3f
normal = v0.cross(
v1);
1127 bool facingTheCam =
angle>0.0f;
1129 float angleToCam = 0.0f;
1130 Eigen::Vector3f e0 = Eigen::Vector3f(
1134 Eigen::Vector3f e1 = Eigen::Vector3f(
1138 Eigen::Vector3f e2 = Eigen::Vector3f(
1142 if(facingTheCam && this->max_angle_)
1144 Eigen::Vector3f normal3D;
1145 normal3D = e0.cross(e1);
1146 angleToCam = pcl::getAngle3D(Eigen::Vector4f(normal3D[0], normal3D[1], normal3D[2], 0.0
f), Eigen::Vector4f(0.0
f,0.0
f,-1.0
f,0.0
f));
1150 float e0norm2 = e0[0]*e0[0] + e0[1]*e0[1] + e0[2]*e0[2];
1151 float e1norm2 = e1[0]*e1[0] + e1[1]*e1[1] + e1[2]*e1[2];
1152 float e2norm2 = e2[0]*e2[0] + e2[1]*e2[1] + e2[2]*e2[2];
1155 pcl::PointXY center;
1156 center.x = (uv_coords1.x+uv_coords2.x+uv_coords3.x)/3.0
f;
1157 center.
y = (uv_coords1.y+uv_coords2.y+uv_coords3.y)/3.0
f;
1158 visibleFaces[current_cam].insert(visibleFaces[current_cam].
end(), std::make_pair(idx_face,
FaceInfo(distanceToCam, angleToCam, longestEdgeSqrd, facingTheCam, uv_coords1, uv_coords2, uv_coords3, center)));
1159 sortedVisibleFaces.insert(std::make_pair(distanceToCam, idx_face));
1160 visibilityIndices[oi] = idx_face;
1164 visibilityIndices.resize(oi);
1165 projections->resize(oi*3);
1166 UASSERT(projections->size() == visibilityIndices.size()*3);
1170 pcl::KdTreeFLANN<pcl::PointXY>
kdtree;
1171 kdtree.setInputCloud (projections);
1173 std::vector<int> idxNeighbors;
1174 std::vector<float> neighborsSquaredDistance;
1178 std::set<int> occludedFaces;
1179 for (std::map<float, int>::iterator jter=sortedVisibleFaces.begin(); jter!=sortedVisibleFaces.end(); ++jter)
1182 int idx_face = jter->second;
1184 std::map<int, FaceInfo>::iterator
iter= visibleFaces[current_cam].find(idx_face);
1192 pcl::PointXY center;
1194 getTriangleCircumcscribedCircleCentroid(
info.uv_coord1,
info.uv_coord2,
info.uv_coord3, center, radius);
1197 if (
kdtree.radiusSearch (center, radius, idxNeighbors, neighborsSquaredDistance) > 0 )
1200 for (
size_t i = 0;
i < idxNeighbors.size (); ++
i)
1202 int neighborFaceIndex = idxNeighbors[
i]/3;
1206 if (
std::max(camera_cloud->points[faces[idx_face].vertices[0]].z,
1207 std::max (camera_cloud->points[faces[idx_face].vertices[1]].z,
1208 camera_cloud->points[faces[idx_face].vertices[2]].z))
1209 < camera_cloud->points[faces[visibilityIndices[neighborFaceIndex]].vertices[idxNeighbors[
i]%3]].z)
1213 if (checkPointInsideTriangle(
info.uv_coord1,
info.uv_coord2,
info.uv_coord3, projections->at(idxNeighbors[
i])))
1216 occludedFaces.insert(visibilityIndices[neighborFaceIndex]);
1226 for(std::set<int>::iterator
iter= occludedFaces.begin();
iter!=occludedFaces.end(); ++
iter)
1228 visibleFaces[current_cam].erase(*
iter);
1232 int clusterFaces = 0;
1234 std::vector<pcl::Vertices> polygons(visibleFaces[current_cam].
size());
1235 std::vector<int> polygon_to_face_index(visibleFaces[current_cam].
size());
1237 for(std::map<int, FaceInfo>::iterator
iter=visibleFaces[current_cam].begin();
iter!=visibleFaces[current_cam].end(); ++
iter)
1239 polygons[oi].vertices.resize(3);
1240 polygons[oi].vertices[0] = faces[
iter->first].vertices[0];
1241 polygons[oi].vertices[1] = faces[
iter->first].vertices[1];
1242 polygons[oi].vertices[2] = faces[
iter->first].vertices[2];
1243 polygon_to_face_index[oi] =
iter->first;
1247 std::vector<std::set<int> > neighbors;
1248 std::vector<std::set<int> > vertexToPolygons;
1250 (
int)camera_cloud->size(),
1256 std::set<int> polygonsKept;
1259 for(std::list<int>::iterator jter=
iter->begin(); jter!=
iter->end(); ++jter)
1261 polygonsKept.insert(polygon_to_face_index[*jter]);
1262 faceCameras[polygon_to_face_index[*jter]].push_back(current_cam);
1266 for(std::map<int, FaceInfo>::iterator
iter=visibleFaces[current_cam].begin();
iter!=visibleFaces[current_cam].end();)
1268 if(polygonsKept.find(
iter->first) == polygonsKept.end())
1270 visibleFaces[current_cam].erase(
iter++);
1279 msg =
uFormat(
"Processed camera %d/%d: %d occluded and %d spurious polygons out of %d", (
int)current_cam+1, (
int)cameras.size(), (
int)occludedFaces.size(), clusterFaces, (
int)visibilityIndices.size());
1284 UWARN(
"Texturing cancelled!");
1289 msg =
uFormat(
"Texturing %d polygons...", (
int)faces.size());
1294 UWARN(
"Texturing cancelled!");
1300 *vertexToPixels = std::vector<std::map<int, pcl::PointXY> >(mesh_cloud->size());
1302 for(
unsigned int idx_face=0; idx_face<faces.size(); ++idx_face)
1304 if((idx_face+1)%10000 == 0)
1306 UDEBUG(
"face %d/%d", idx_face+1, (
int)faces.size());
1310 UWARN(
"Texturing cancelled!");
1314 pcl::Vertices & face = faces[idx_face];
1316 int cameraIndex = -1;
1318 bool depthSet =
false;
1319 pcl::PointXY uv_coords[3];
1320 for (std::list<int>::iterator camIter = faceCameras[idx_face].begin(); camIter!=faceCameras[idx_face].end(); ++camIter)
1322 int current_cam = *camIter;
1323 std::map<int, FaceInfo>::iterator
iter = visibleFaces[current_cam].find(idx_face);
1325 if (
iter->second.facingTheCam && (max_angle_ <=0.0f || iter->
second.angle <= max_angle_))
1327 float distanceToCam =
iter->second.distance;
1328 float vx = (
iter->second.uv_coord1.x+
iter->second.uv_coord2.x+
iter->second.uv_coord3.x)/3.0
f-0.5
f;
1329 float vy = (
iter->second.uv_coord1.y+
iter->second.uv_coord2.y+
iter->second.uv_coord3.y)/3.0
f-0.5
f;
1330 float distanceToCenter =
vx*
vx+
vy*
vy;
1332 cv::Mat depth = cameras[current_cam].depth;
1333 bool currentDepthSet =
false;
1335 if(!cameras[current_cam].depth.empty() &&
maxDepthError > 0.0f)
1337 float d1 = depth.type() == CV_32FC1?
1338 depth.at<
float>((1.0f-
iter->second.uv_coord1.y)*depth.rows,
iter->second.uv_coord1.x*depth.cols):
1339 float(depth.at<
unsigned short>((1.0f-
iter->second.uv_coord1.y)*depth.rows,
iter->second.uv_coord1.x*depth.cols))/1000.0f;
1340 float d2 = depth.type() == CV_32FC1?
1341 depth.at<
float>((1.0f-
iter->second.uv_coord2.y)*depth.rows,
iter->second.uv_coord2.x*depth.cols):
1342 float(depth.at<
unsigned short>((1.0f-
iter->second.uv_coord2.y)*depth.rows,
iter->second.uv_coord2.x*depth.cols))/1000.0f;
1343 float d3 = depth.type() == CV_32FC1?
1344 depth.at<
float>((1.0f-
iter->second.uv_coord3.y)*depth.rows,
iter->second.uv_coord3.x*depth.cols):
1345 float(depth.at<
unsigned short>((1.0f-
iter->second.uv_coord3.y)*depth.rows,
iter->second.uv_coord3.x*depth.cols))/1000.0f;
1379 currentDepthSet =
true;
1385 vertexToPixels->at(face.vertices[0]).insert(std::make_pair(current_cam,
iter->second.uv_coord1));
1386 vertexToPixels->at(face.vertices[1]).insert(std::make_pair(current_cam,
iter->second.uv_coord2));
1387 vertexToPixels->at(face.vertices[2]).insert(std::make_pair(current_cam,
iter->second.uv_coord3));
1393 if(distanceToCamPolicy)
1397 if(
distance <= smallestWeight || (!depthSet && currentDepthSet))
1399 cameraIndex = current_cam;
1401 uv_coords[0] =
iter->second.uv_coord1;
1402 uv_coords[1] =
iter->second.uv_coord2;
1403 uv_coords[2] =
iter->second.uv_coord3;
1404 if(!depthSet && currentDepthSet)
1412 if(cameraIndex >= 0)
1415 mesh.tex_polygons[cameraIndex].push_back(face);
1416 mesh.tex_coordinates[cameraIndex].push_back(Eigen::Vector2f(uv_coords[0].
x, uv_coords[0].
y));
1417 mesh.tex_coordinates[cameraIndex].push_back(Eigen::Vector2f(uv_coords[1].
x, uv_coords[1].
y));
1418 mesh.tex_coordinates[cameraIndex].push_back(Eigen::Vector2f(uv_coords[2].
x, uv_coords[2].
y));
1422 mesh.tex_polygons[cameras.size()].push_back(face);
1423 mesh.tex_coordinates[cameras.size()].push_back(Eigen::Vector2f(-1.0,-1.0));
1424 mesh.tex_coordinates[cameras.size()].push_back(Eigen::Vector2f(-1.0,-1.0));
1425 mesh.tex_coordinates[cameras.size()].push_back(Eigen::Vector2f(-1.0,-1.0));
1428 UINFO(
"Process %d polygons...done! (%d textured)", (
int)faces.size(), textured);
1434 template<
typename Po
intInT>
inline void
1438 pcl::PointXY ptB, ptC;
1439 ptB.x =
p2.x -
p1.x; ptB.y =
p2.y -
p1.y;
1440 ptC.x =
p3.x -
p1.x; ptC.y =
p3.y -
p1.y;
1442 double D = 2.0*(ptB.x*ptC.y - ptB.y*ptC.x);
1447 circomcenter.x =
p1.x;
1448 circomcenter.y =
p1.y;
1453 double bx2 = ptB.x * ptB.x;
1454 double by2 = ptB.y * ptB.y;
1455 double cx2 = ptC.x * ptC.x;
1456 double cy2 = ptC.y * ptC.y;
1459 circomcenter.x =
static_cast<float> (
p1.x + (ptC.y*(bx2 + by2) - ptB.y*(cx2 + cy2)) /
D);
1460 circomcenter.y =
static_cast<float> (
p1.y + (ptB.x*(cx2 + cy2) - ptC.x*(bx2 + by2)) /
D);
1463 radius =
sqrt( (circomcenter.x -
p1.x)*(circomcenter.x -
p1.x) + (circomcenter.y -
p1.y)*(circomcenter.y -
p1.y));
1467 template<
typename Po
intInT>
inline void
1471 circumcenter.x =
static_cast<float> (
p1.x +
p2.x +
p3.x ) / 3;
1472 circumcenter.y =
static_cast<float> (
p1.y +
p2.y +
p3.y ) / 3;
1473 double r1 = (circumcenter.x -
p1.x) * (circumcenter.x -
p1.x) + (circumcenter.y -
p1.y) * (circumcenter.y -
p1.y) ;
1474 double r2 = (circumcenter.x -
p2.x) * (circumcenter.x -
p2.x) + (circumcenter.y -
p2.y) * (circumcenter.y -
p2.y) ;
1475 double r3 = (circumcenter.x -
p3.x) * (circumcenter.x -
p3.x) + (circumcenter.y -
p3.y) * (circumcenter.y -
p3.y) ;
1483 template<
typename Po
intInT>
inline bool
1486 if (pt.z > 0 && (max_distance_<=0.0f || pt.z<max_distance_))
1489 double sizeX =
cam.width;
1490 double sizeY =
cam.height;
1492 if (
cam.center_w > 0)
1496 if (
cam.center_h > 0)
1501 double focal_x, focal_y;
1502 if (
cam.focal_length_w > 0)
1503 focal_x =
cam.focal_length_w;
1505 focal_x =
cam.focal_length;
1506 if (
cam.focal_length_h > 0)
1507 focal_y =
cam.focal_length_h;
1509 focal_y =
cam.focal_length;
1512 UV_coordinates.x =
static_cast<float> ((focal_x * (pt.x / pt.z) +
cx) / sizeX);
1513 UV_coordinates.y =
static_cast<float> ((focal_y * (pt.y / pt.z) +
cy) / sizeY);
1515 if(
cam.roi.size() == 4)
1517 if( UV_coordinates.x <
cam.roi[0]/sizeX ||
1518 UV_coordinates.y <
cam.roi[1]/sizeY ||
1519 UV_coordinates.x > (
cam.roi[0]+
cam.roi[2])/sizeX ||
1520 UV_coordinates.y > (
cam.roi[1]+
cam.roi[3])/sizeY)
1523 UV_coordinates.x = -1.0f;
1524 UV_coordinates.y = -1.0f;
1530 if (UV_coordinates.x >= 0.0 && UV_coordinates.x <= 1.0 && UV_coordinates.y >= 0.0 && UV_coordinates.y <= 1.0)
1534 UV_coordinates.y = 1.0f - UV_coordinates.y;
1540 UV_coordinates.x = -1.0f;
1541 UV_coordinates.y = -1.0f;
1546 template<
typename Po
intInT>
inline bool
1550 Eigen::Vector2d v0,
v1,
v2;
1551 v0(0) =
p3.x -
p1.x; v0(1) =
p3.y -
p1.y;
1553 v2(0) = pt.x -
p1.x;
v2(1) = pt.y -
p1.y;
1556 double dot00 = v0.dot(v0);
1557 double dot01 = v0.dot(
v1);
1558 double dot02 = v0.dot(
v2);
1559 double dot11 =
v1.dot(
v1);
1560 double dot12 =
v1.dot(
v2);
1563 double invDenom = 1.0 / (dot00*dot11 - dot01*dot01);
1564 double u = (dot11*dot02 - dot01*dot12) * invDenom;
1565 double v = (dot00*dot12 - dot01*dot02) * invDenom;
1568 return ((u >= 0) && (
v >= 0) && (u +
v < 1));
1572 template<
typename Po
intInT>
inline bool
1575 return getPointUVCoordinates(
p1,
camera, proj1)
1577 getPointUVCoordinates(
p2,
camera, proj2)
1579 getPointUVCoordinates(
p3,
camera, proj3);
1582 #define PCL_INSTANTIATE_TextureMapping(T) \
1583 template class PCL_EXPORTS pcl::TextureMapping<T>;