Point Cloud Library (PCL)  1.11.1-dev
texture_mapping.hpp
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2010, Willow Garage, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of Willow Garage, Inc. nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * $Id$
35  *
36  */
37 
38 #ifndef PCL_SURFACE_IMPL_TEXTURE_MAPPING_HPP_
39 #define PCL_SURFACE_IMPL_TEXTURE_MAPPING_HPP_
40 
41 #include <pcl/common/distances.h>
42 #include <pcl/surface/texture_mapping.h>
43 #include <unordered_set>
44 
45 ///////////////////////////////////////////////////////////////////////////////////////////////
46 template<typename PointInT> std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> >
48  const Eigen::Vector3f &p1,
49  const Eigen::Vector3f &p2,
50  const Eigen::Vector3f &p3)
51 {
52  std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > tex_coordinates;
53  // process for each face
54  Eigen::Vector3f p1p2 (p2[0] - p1[0], p2[1] - p1[1], p2[2] - p1[2]);
55  Eigen::Vector3f p1p3 (p3[0] - p1[0], p3[1] - p1[1], p3[2] - p1[2]);
56  Eigen::Vector3f p2p3 (p3[0] - p2[0], p3[1] - p2[1], p3[2] - p2[2]);
57 
58  // Normalize
59  p1p2 /= std::sqrt (p1p2.dot (p1p2));
60  p1p3 /= std::sqrt (p1p3.dot (p1p3));
61  p2p3 /= std::sqrt (p2p3.dot (p2p3));
62 
63  // compute vector normal of a face
64  Eigen::Vector3f f_normal = p1p2.cross (p1p3);
65  f_normal /= std::sqrt (f_normal.dot (f_normal));
66 
67  // project vector field onto the face: vector v1_projected = v1 - Dot(v1, n) * n;
68  Eigen::Vector3f f_vector_field = vector_field_ - vector_field_.dot (f_normal) * f_normal;
69 
70  // Normalize
71  f_vector_field /= std::sqrt (f_vector_field.dot (f_vector_field));
72 
73  // texture coordinates
74  Eigen::Vector2f tp1, tp2, tp3;
75 
76  double alpha = std::acos (f_vector_field.dot (p1p2));
77 
78  // distance between 3 vertices of triangles
79  double e1 = (p2 - p3).norm () / f_;
80  double e2 = (p1 - p3).norm () / f_;
81  double e3 = (p1 - p2).norm () / f_;
82 
83  // initialize
84  tp1[0] = 0.0;
85  tp1[1] = 0.0;
86 
87  tp2[0] = static_cast<float> (e3);
88  tp2[1] = 0.0;
89 
90  // determine texture coordinate tp3;
91  double cos_p1 = (e2 * e2 + e3 * e3 - e1 * e1) / (2 * e2 * e3);
92  double sin_p1 = sqrt (1 - (cos_p1 * cos_p1));
93 
94  tp3[0] = static_cast<float> (cos_p1 * e2);
95  tp3[1] = static_cast<float> (sin_p1 * e2);
96 
97  // rotating by alpha (angle between V and pp1 & pp2)
98  Eigen::Vector2f r_tp2, r_tp3;
99  r_tp2[0] = static_cast<float> (tp2[0] * std::cos (alpha) - tp2[1] * std::sin (alpha));
100  r_tp2[1] = static_cast<float> (tp2[0] * std::sin (alpha) + tp2[1] * std::cos (alpha));
101 
102  r_tp3[0] = static_cast<float> (tp3[0] * std::cos (alpha) - tp3[1] * std::sin (alpha));
103  r_tp3[1] = static_cast<float> (tp3[0] * std::sin (alpha) + tp3[1] * std::cos (alpha));
104 
105  // shifting
106  tp1[0] = tp1[0];
107  tp2[0] = r_tp2[0];
108  tp3[0] = r_tp3[0];
109  tp1[1] = tp1[1];
110  tp2[1] = r_tp2[1];
111  tp3[1] = r_tp3[1];
112 
113  float min_x = tp1[0];
114  float min_y = tp1[1];
115  if (min_x > tp2[0])
116  min_x = tp2[0];
117  if (min_x > tp3[0])
118  min_x = tp3[0];
119  if (min_y > tp2[1])
120  min_y = tp2[1];
121  if (min_y > tp3[1])
122  min_y = tp3[1];
123 
124  if (min_x < 0)
125  {
126  tp1[0] -= min_x;
127  tp2[0] -= min_x;
128  tp3[0] -= min_x;
129  }
130  if (min_y < 0)
131  {
132  tp1[1] -= min_y;
133  tp2[1] -= min_y;
134  tp3[1] -= min_y;
135  }
136 
137  tex_coordinates.push_back (tp1);
138  tex_coordinates.push_back (tp2);
139  tex_coordinates.push_back (tp3);
140  return (tex_coordinates);
141 }
142 
143 ///////////////////////////////////////////////////////////////////////////////////////////////
144 template<typename PointInT> void
146 {
147  // mesh information
148  int nr_points = tex_mesh.cloud.width * tex_mesh.cloud.height;
149  int point_size = static_cast<int> (tex_mesh.cloud.data.size ()) / nr_points;
150 
151  // temporary PointXYZ
152  float x, y, z;
153  // temporary face
154  Eigen::Vector3f facet[3];
155 
156  // texture coordinates for each mesh
157  std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > >texture_map;
158 
159  for (std::size_t m = 0; m < tex_mesh.tex_polygons.size (); ++m)
160  {
161  // texture coordinates for each mesh
162  std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > texture_map_tmp;
163 
164  // processing for each face
165  for (std::size_t i = 0; i < tex_mesh.tex_polygons[m].size (); ++i)
166  {
167  std::size_t idx;
168 
169  // get facet information
170  for (std::size_t j = 0; j < tex_mesh.tex_polygons[m][i].vertices.size (); ++j)
171  {
172  idx = tex_mesh.tex_polygons[m][i].vertices[j];
173  memcpy (&x, &tex_mesh.cloud.data[idx * point_size + tex_mesh.cloud.fields[0].offset], sizeof(float));
174  memcpy (&y, &tex_mesh.cloud.data[idx * point_size + tex_mesh.cloud.fields[1].offset], sizeof(float));
175  memcpy (&z, &tex_mesh.cloud.data[idx * point_size + tex_mesh.cloud.fields[2].offset], sizeof(float));
176  facet[j][0] = x;
177  facet[j][1] = y;
178  facet[j][2] = z;
179  }
180 
181  // get texture coordinates of each face
182  std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > tex_coordinates = mapTexture2Face (facet[0], facet[1], facet[2]);
183  for (const auto &tex_coordinate : tex_coordinates)
184  texture_map_tmp.push_back (tex_coordinate);
185  }// end faces
186 
187  // texture materials
188  std::stringstream tex_name;
189  tex_name << "material_" << m;
190  tex_name >> tex_material_.tex_name;
191  tex_material_.tex_file = tex_files_[m];
192  tex_mesh.tex_materials.push_back (tex_material_);
193 
194  // texture coordinates
195  tex_mesh.tex_coordinates.push_back (texture_map_tmp);
196  }// end meshes
197 }
198 
199 ///////////////////////////////////////////////////////////////////////////////////////////////
200 template<typename PointInT> void
202 {
203  // mesh information
204  int nr_points = tex_mesh.cloud.width * tex_mesh.cloud.height;
205  int point_size = static_cast<int> (tex_mesh.cloud.data.size ()) / nr_points;
206 
207  float x_lowest = 100000;
208  float x_highest = 0;
209  float y_lowest = 100000;
210  //float y_highest = 0 ;
211  float z_lowest = 100000;
212  float z_highest = 0;
213  float x_, y_, z_;
214 
215  for (int i = 0; i < nr_points; ++i)
216  {
217  memcpy (&x_, &tex_mesh.cloud.data[i * point_size + tex_mesh.cloud.fields[0].offset], sizeof(float));
218  memcpy (&y_, &tex_mesh.cloud.data[i * point_size + tex_mesh.cloud.fields[1].offset], sizeof(float));
219  memcpy (&z_, &tex_mesh.cloud.data[i * point_size + tex_mesh.cloud.fields[2].offset], sizeof(float));
220  // x
221  if (x_ <= x_lowest)
222  x_lowest = x_;
223  if (x_ > x_lowest)
224  x_highest = x_;
225 
226  // y
227  if (y_ <= y_lowest)
228  y_lowest = y_;
229  //if (y_ > y_lowest) y_highest = y_;
230 
231  // z
232  if (z_ <= z_lowest)
233  z_lowest = z_;
234  if (z_ > z_lowest)
235  z_highest = z_;
236  }
237  // x
238  float x_range = (x_lowest - x_highest) * -1;
239  float x_offset = 0 - x_lowest;
240  // x
241  // float y_range = (y_lowest - y_highest)*-1;
242  // float y_offset = 0 - y_lowest;
243  // z
244  float z_range = (z_lowest - z_highest) * -1;
245  float z_offset = 0 - z_lowest;
246 
247  // texture coordinates for each mesh
248  std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > >texture_map;
249 
250  for (std::size_t m = 0; m < tex_mesh.tex_polygons.size (); ++m)
251  {
252  // texture coordinates for each mesh
253  std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > texture_map_tmp;
254 
255  // processing for each face
256  for (std::size_t i = 0; i < tex_mesh.tex_polygons[m].size (); ++i)
257  {
258  Eigen::Vector2f tmp_VT;
259  for (std::size_t j = 0; j < tex_mesh.tex_polygons[m][i].vertices.size (); ++j)
260  {
261  std::size_t idx = tex_mesh.tex_polygons[m][i].vertices[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));
265 
266  // calculate uv coordinates
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);
270  }
271  }// end faces
272 
273  // texture materials
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];
278  tex_mesh.tex_materials.push_back (tex_material_);
279 
280  // texture coordinates
281  tex_mesh.tex_coordinates.push_back (texture_map_tmp);
282  }// end meshes
283 }
284 
285 ///////////////////////////////////////////////////////////////////////////////////////////////
286 template<typename PointInT> void
288 {
289 
290  if (tex_mesh.tex_polygons.size () != cams.size () + 1)
291  {
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 ());
294  return;
295  }
296 
297  PCL_INFO ("You provided %d cameras and a mesh containing %d sub-meshes.\n", cams.size (), tex_mesh.tex_polygons.size ());
298 
299  typename pcl::PointCloud<PointInT>::Ptr originalCloud (new pcl::PointCloud<PointInT>);
300  typename pcl::PointCloud<PointInT>::Ptr camera_transformed_cloud (new pcl::PointCloud<PointInT>);
301 
302  // convert mesh's cloud to pcl format for ease
303  pcl::fromPCLPointCloud2 (tex_mesh.cloud, *originalCloud);
304 
305  for (std::size_t m = 0; m < cams.size (); ++m)
306  {
307  // get current camera parameters
308  Camera current_cam = cams[m];
309 
310  // get camera transform
311  Eigen::Affine3f cam_trans = current_cam.pose;
312 
313  // transform cloud into current camera frame
314  pcl::transformPointCloud (*originalCloud, *camera_transformed_cloud, cam_trans.inverse ());
315 
316  // vector of texture coordinates for each face
317  std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > texture_map_tmp;
318 
319  // processing each face visible by this camera
320  for (const auto &tex_polygon : tex_mesh.tex_polygons[m])
321  {
322  Eigen::Vector2f tmp_VT;
323  // for each point of this face
324  for (const auto &vertex : tex_polygon.vertices)
325  {
326  // get point
327  PointInT pt = (*camera_transformed_cloud)[vertex];
328 
329  // compute UV coordinates for this point
330  getPointUVCoordinates (pt, current_cam, tmp_VT);
331  texture_map_tmp.push_back (tmp_VT);
332  }// end points
333  }// end faces
334 
335  // texture materials
336  std::stringstream tex_name;
337  tex_name << "material_" << m;
338  tex_name >> tex_material_.tex_name;
339  tex_material_.tex_file = current_cam.texture_file;
340  tex_mesh.tex_materials.push_back (tex_material_);
341 
342  // texture coordinates
343  tex_mesh.tex_coordinates.push_back (texture_map_tmp);
344  }// end cameras
345 
346  // push on extra empty UV map (for unseen faces) so that obj writer does not crash!
347  std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > texture_map_tmp;
348  for (const auto &tex_polygon : tex_mesh.tex_polygons[cams.size ()])
349  for (std::size_t j = 0; j < tex_polygon.vertices.size (); ++j)
350  {
351  Eigen::Vector2f tmp_VT;
352  tmp_VT[0] = -1;
353  tmp_VT[1] = -1;
354  texture_map_tmp.push_back (tmp_VT);
355  }
356 
357  tex_mesh.tex_coordinates.push_back (texture_map_tmp);
358 
359  // push on an extra dummy material for the same reason
360  tex_material_.tex_name = "material_" + std::to_string(cams.size());
361  tex_material_.tex_file = "occluded.jpg";
362  tex_mesh.tex_materials.push_back (tex_material_);
363 }
364 
365 ///////////////////////////////////////////////////////////////////////////////////////////////
366 template<typename PointInT> bool
368 {
369  Eigen::Vector3f direction;
370  direction (0) = pt.x;
371  direction (1) = pt.y;
372  direction (2) = pt.z;
373 
374  pcl::Indices indices;
375 
376  PointCloudConstPtr cloud (new PointCloud());
377  cloud = octree->getInputCloud();
378 
379  double distance_threshold = octree->getResolution();
380 
381  // raytrace
382  octree->getIntersectedVoxelIndices(direction, -direction, indices);
383 
384  int nbocc = static_cast<int> (indices.size ());
385  for (const auto &index : indices)
386  {
387  // if intersected point is on the over side of the camera
388  if (pt.z * (*cloud)[index].z < 0)
389  {
390  nbocc--;
391  continue;
392  }
393 
394  if (std::fabs ((*cloud)[index].z - pt.z) <= distance_threshold)
395  {
396  // points are very close to each-other, we do not consider the occlusion
397  nbocc--;
398  }
399  }
400 
401  return (nbocc != 0);
402 }
403 
404 ///////////////////////////////////////////////////////////////////////////////////////////////
405 template<typename PointInT> void
407  PointCloudPtr &filtered_cloud,
408  const double octree_voxel_size, pcl::Indices &visible_indices,
409  pcl::Indices &occluded_indices)
410 {
411  // variable used to filter occluded points by depth
412  double maxDeltaZ = octree_voxel_size;
413 
414  // create an octree to perform rayTracing
415  Octree octree (octree_voxel_size);
416  // create octree structure
417  octree.setInputCloud (input_cloud);
418  // update bounding box automatically
419  octree.defineBoundingBox ();
420  // add points in the tree
421  octree.addPointsFromInputCloud ();
422 
423  visible_indices.clear ();
424 
425  // for each point of the cloud, raycast toward camera and check intersected voxels.
426  Eigen::Vector3f direction;
427  pcl::Indices indices;
428  for (std::size_t i = 0; i < input_cloud->size (); ++i)
429  {
430  direction (0) = (*input_cloud)[i].x;
431  direction (1) = (*input_cloud)[i].y;
432  direction (2) = (*input_cloud)[i].z;
433 
434  // if point is not occluded
435  octree.getIntersectedVoxelIndices (direction, -direction, indices);
436 
437  int nbocc = static_cast<int> (indices.size ());
438  for (const auto &index : indices)
439  {
440  // if intersected point is on the over side of the camera
441  if ((*input_cloud)[i].z * (*input_cloud)[index].z < 0)
442  {
443  nbocc--;
444  continue;
445  }
446 
447  if (std::fabs ((*input_cloud)[index].z - (*input_cloud)[i].z) <= maxDeltaZ)
448  {
449  // points are very close to each-other, we do not consider the occlusion
450  nbocc--;
451  }
452  }
453 
454  if (nbocc == 0)
455  {
456  // point is added in the filtered mesh
457  filtered_cloud->points.push_back ((*input_cloud)[i]);
458  visible_indices.push_back (static_cast<pcl::index_t> (i));
459  }
460  else
461  {
462  occluded_indices.push_back (static_cast<pcl::index_t> (i));
463  }
464  }
465 
466 }
467 
468 ///////////////////////////////////////////////////////////////////////////////////////////////
469 template<typename PointInT> void
470 pcl::TextureMapping<PointInT>::removeOccludedPoints (const pcl::TextureMesh &tex_mesh, pcl::TextureMesh &cleaned_mesh, const double octree_voxel_size)
471 {
472  // copy mesh
473  cleaned_mesh = tex_mesh;
474 
476  typename pcl::PointCloud<PointInT>::Ptr filtered_cloud (new pcl::PointCloud<PointInT>);
477 
478  // load points into a PCL format
479  pcl::fromPCLPointCloud2 (tex_mesh.cloud, *cloud);
480 
481  pcl::Indices visible, occluded;
482  removeOccludedPoints (cloud, filtered_cloud, octree_voxel_size, visible, occluded);
483 
484  // Now that we know which points are visible, let's iterate over each face.
485  // if the face has one invisible point => out!
486  for (std::size_t polygons = 0; polygons < cleaned_mesh.tex_polygons.size (); ++polygons)
487  {
488  // remove all faces from cleaned mesh
489  cleaned_mesh.tex_polygons[polygons].clear ();
490  // iterate over faces
491  for (std::size_t faces = 0; faces < tex_mesh.tex_polygons[polygons].size (); ++faces)
492  {
493  // check if all the face's points are visible
494  bool faceIsVisible = true;
495 
496  // iterate over face's vertex
497  for (const auto &vertex : tex_mesh.tex_polygons[polygons][faces].vertices)
498  {
499  if (find (occluded.begin (), occluded.end (), vertex) == occluded.end ())
500  {
501  // point is not in the occluded vector
502  // PCL_INFO (" VISIBLE!\n");
503  }
504  else
505  {
506  // point was occluded
507  // PCL_INFO(" OCCLUDED!\n");
508  faceIsVisible = false;
509  }
510  }
511 
512  if (faceIsVisible)
513  {
514  cleaned_mesh.tex_polygons[polygons].push_back (tex_mesh.tex_polygons[polygons][faces]);
515  }
516 
517  }
518  }
519 }
520 
521 ///////////////////////////////////////////////////////////////////////////////////////////////
522 template<typename PointInT> void
524  const double octree_voxel_size)
525 {
526  PointCloudPtr cloud (new PointCloud);
527 
528  // load points into a PCL format
529  pcl::fromPCLPointCloud2 (tex_mesh.cloud, *cloud);
530 
531  pcl::Indices visible, occluded;
532  removeOccludedPoints (cloud, filtered_cloud, octree_voxel_size, visible, occluded);
533 
534 }
535 
536 ///////////////////////////////////////////////////////////////////////////////////////////////
537 template<typename PointInT> int
539  const pcl::texture_mapping::CameraVector &cameras, const double octree_voxel_size,
540  PointCloud &visible_pts)
541 {
542  if (tex_mesh.tex_polygons.size () != 1)
543  {
544  PCL_ERROR ("The mesh must contain only 1 sub-mesh!\n");
545  return (-1);
546  }
547 
548  if (cameras.empty ())
549  {
550  PCL_ERROR ("Must provide at least one camera info!\n");
551  return (-1);
552  }
553 
554  // copy mesh
555  sorted_mesh = tex_mesh;
556  // clear polygons from cleaned_mesh
557  sorted_mesh.tex_polygons.clear ();
558 
559  typename pcl::PointCloud<PointInT>::Ptr original_cloud (new pcl::PointCloud<PointInT>);
560  typename pcl::PointCloud<PointInT>::Ptr transformed_cloud (new pcl::PointCloud<PointInT>);
561  typename pcl::PointCloud<PointInT>::Ptr filtered_cloud (new pcl::PointCloud<PointInT>);
562 
563  // load points into a PCL format
564  pcl::fromPCLPointCloud2 (tex_mesh.cloud, *original_cloud);
565 
566  // for each camera
567  for (const auto &camera : cameras)
568  {
569  // get camera pose as transform
570  Eigen::Affine3f cam_trans = camera.pose;
571 
572  // transform original cloud in camera coordinates
573  pcl::transformPointCloud (*original_cloud, *transformed_cloud, cam_trans.inverse ());
574 
575  // find occlusions on transformed cloud
576  pcl::Indices visible, occluded;
577  removeOccludedPoints (transformed_cloud, filtered_cloud, octree_voxel_size, visible, occluded);
578  visible_pts = *filtered_cloud;
579 
580  // pushing occluded idxs into a set for faster lookup
581  std::unordered_set<index_t> occluded_set(occluded.cbegin(), occluded.cend());
582 
583  // find visible faces => add them to polygon N for camera N
584  // add polygon group for current camera in clean
585  std::vector<pcl::Vertices> visibleFaces_currentCam;
586  // iterate over the faces of the current mesh
587  for (std::size_t faces = 0; faces < tex_mesh.tex_polygons[0].size (); ++faces)
588  {
589  // check if all the face's points are visible
590  // iterate over face's vertex
591  const auto faceIsVisible = std::all_of(tex_mesh.tex_polygons[0][faces].vertices.cbegin(),
592  tex_mesh.tex_polygons[0][faces].vertices.cend(),
593  [&](const auto& vertex)
594  {
595  if (occluded_set.find(vertex) != occluded_set.cend()) {
596  return false; // point is occluded
597  }
598  // is the point visible to the camera?
599  Eigen::Vector2f dummy_UV;
600  return this->getPointUVCoordinates ((*transformed_cloud)[vertex], camera, dummy_UV);
601  });
602 
603  if (faceIsVisible)
604  {
605  // push current visible face into the sorted mesh
606  visibleFaces_currentCam.push_back (tex_mesh.tex_polygons[0][faces]);
607  // remove it from the unsorted mesh
608  tex_mesh.tex_polygons[0].erase (tex_mesh.tex_polygons[0].begin () + faces);
609  faces--;
610  }
611 
612  }
613  sorted_mesh.tex_polygons.push_back (visibleFaces_currentCam);
614  }
615 
616  // we should only have occluded and non-visible faces left in tex_mesh.tex_polygons[0]
617  // we need to add them as an extra polygon in the sorted mesh
618  sorted_mesh.tex_polygons.push_back (tex_mesh.tex_polygons[0]);
619  return (0);
620 }
621 
622 ///////////////////////////////////////////////////////////////////////////////////////////////
623 template<typename PointInT> void
626  const double octree_voxel_size, const bool show_nb_occlusions,
627  const int max_occlusions)
628  {
629  // variable used to filter occluded points by depth
630  double maxDeltaZ = octree_voxel_size * 2.0;
631 
632  // create an octree to perform rayTracing
633  Octree octree (octree_voxel_size);
634  // create octree structure
635  octree.setInputCloud (input_cloud);
636  // update bounding box automatically
637  octree.defineBoundingBox ();
638  // add points in the tree
639  octree.addPointsFromInputCloud ();
640 
641  // ray direction
642  Eigen::Vector3f direction;
643 
644  pcl::Indices indices;
645  // point from where we ray-trace
646  pcl::PointXYZI pt;
647 
648  std::vector<double> zDist;
649  std::vector<double> ptDist;
650  // for each point of the cloud, ray-trace toward the camera and check intersected voxels.
651  for (const auto& point: *input_cloud)
652  {
653  direction = pt.getVector3fMap() = point.getVector3fMap();
654 
655  // get number of occlusions for that point
656  indices.clear ();
657  int nbocc = octree.getIntersectedVoxelIndices (direction, -direction, indices);
658 
659  nbocc = static_cast<int> (indices.size ());
660 
661  // TODO need to clean this up and find tricks to get remove aliasaing effect on planes
662  for (const auto &index : indices)
663  {
664  // if intersected point is on the over side of the camera
665  if (pt.z * (*input_cloud)[index].z < 0)
666  {
667  nbocc--;
668  }
669  else if (std::fabs ((*input_cloud)[index].z - pt.z) <= maxDeltaZ)
670  {
671  // points are very close to each-other, we do not consider the occlusion
672  nbocc--;
673  }
674  else
675  {
676  zDist.push_back (std::fabs ((*input_cloud)[index].z - pt.z));
677  ptDist.push_back (pcl::euclideanDistance ((*input_cloud)[index], pt));
678  }
679  }
680 
681  if (show_nb_occlusions)
682  (nbocc <= max_occlusions) ? (pt.intensity = static_cast<float> (nbocc)) : (pt.intensity = static_cast<float> (max_occlusions));
683  else
684  (nbocc == 0) ? (pt.intensity = 0) : (pt.intensity = 1);
685 
686  colored_cloud->points.push_back (pt);
687  }
688 
689  if (zDist.size () >= 2)
690  {
691  std::sort (zDist.begin (), zDist.end ());
692  std::sort (ptDist.begin (), ptDist.end ());
693  }
694 }
695 
696 ///////////////////////////////////////////////////////////////////////////////////////////////
697 template<typename PointInT> void
699  double octree_voxel_size, bool show_nb_occlusions, int max_occlusions)
700 {
701  // load points into a PCL format
703  pcl::fromPCLPointCloud2 (tex_mesh.cloud, *cloud);
704 
705  showOcclusions (cloud, colored_cloud, octree_voxel_size, show_nb_occlusions, max_occlusions);
706 }
707 
708 ///////////////////////////////////////////////////////////////////////////////////////////////
709 template<typename PointInT> void
711 {
712 
713  if (mesh.tex_polygons.size () != 1)
714  return;
715 
717 
718  pcl::fromPCLPointCloud2 (mesh.cloud, *mesh_cloud);
719 
720  std::vector<pcl::Vertices> faces;
721 
722  for (int current_cam = 0; current_cam < static_cast<int> (cameras.size ()); ++current_cam)
723  {
724  PCL_INFO ("Processing camera %d of %d.\n", current_cam+1, cameras.size ());
725 
726  // transform mesh into camera's frame
727  typename pcl::PointCloud<PointInT>::Ptr camera_cloud (new pcl::PointCloud<PointInT>);
728  pcl::transformPointCloud (*mesh_cloud, *camera_cloud, cameras[current_cam].pose.inverse ());
729 
730  // CREATE UV MAP FOR CURRENT FACES
732  std::vector<bool> visibility;
733  visibility.resize (mesh.tex_polygons[current_cam].size ());
734  std::vector<UvIndex> indexes_uv_to_points;
735  // for each current face
736 
737  //TODO change this
738  pcl::PointXY nan_point;
739  nan_point.x = std::numeric_limits<float>::quiet_NaN ();
740  nan_point.y = std::numeric_limits<float>::quiet_NaN ();
741  UvIndex u_null;
742  u_null.idx_cloud = -1;
743  u_null.idx_face = -1;
744 
745  int cpt_invisible=0;
746  for (int idx_face = 0; idx_face < static_cast<int> (mesh.tex_polygons[current_cam].size ()); ++idx_face)
747  {
748  //project each vertice, if one is out of view, stop
749  pcl::PointXY uv_coord1;
750  pcl::PointXY uv_coord2;
751  pcl::PointXY uv_coord3;
752 
753  if (isFaceProjected (cameras[current_cam],
754  (*camera_cloud)[mesh.tex_polygons[current_cam][idx_face].vertices[0]],
755  (*camera_cloud)[mesh.tex_polygons[current_cam][idx_face].vertices[1]],
756  (*camera_cloud)[mesh.tex_polygons[current_cam][idx_face].vertices[2]],
757  uv_coord1,
758  uv_coord2,
759  uv_coord3))
760  {
761  // face is in the camera's FOV
762 
763  // add UV coordinates
764  projections->points.push_back (uv_coord1);
765  projections->points.push_back (uv_coord2);
766  projections->points.push_back (uv_coord3);
767 
768  // remember corresponding face
769  UvIndex u1, u2, u3;
770  u1.idx_cloud = mesh.tex_polygons[current_cam][idx_face].vertices[0];
771  u2.idx_cloud = mesh.tex_polygons[current_cam][idx_face].vertices[1];
772  u3.idx_cloud = mesh.tex_polygons[current_cam][idx_face].vertices[2];
773  u1.idx_face = idx_face; u2.idx_face = idx_face; u3.idx_face = idx_face;
774  indexes_uv_to_points.push_back (u1);
775  indexes_uv_to_points.push_back (u2);
776  indexes_uv_to_points.push_back (u3);
777 
778  //keep track of visibility
779  visibility[idx_face] = true;
780  }
781  else
782  {
783  projections->points.push_back (nan_point);
784  projections->points.push_back (nan_point);
785  projections->points.push_back (nan_point);
786  indexes_uv_to_points.push_back (u_null);
787  indexes_uv_to_points.push_back (u_null);
788  indexes_uv_to_points.push_back (u_null);
789  //keep track of visibility
790  visibility[idx_face] = false;
791  cpt_invisible++;
792  }
793  }
794 
795  // projections contains all UV points of the current faces
796  // indexes_uv_to_points links a uv point to its point in the camera cloud
797  // visibility contains tells if a face was in the camera FOV (false = skip)
798 
799  // TODO handle case were no face could be projected
800  if (visibility.size () - cpt_invisible !=0)
801  {
802  //create kdtree
804  kdtree.setInputCloud (projections);
805 
806  pcl::Indices idxNeighbors;
807  std::vector<float> neighborsSquaredDistance;
808  // af first (idx_pcan < current_cam), check if some of the faces attached to previous cameras occlude the current faces
809  // then (idx_pcam == current_cam), check for self occlusions. At this stage, we skip faces that were already marked as occluded
810  cpt_invisible = 0;
811  for (int idx_pcam = 0 ; idx_pcam <= current_cam ; ++idx_pcam)
812  {
813  // project all faces
814  for (int idx_face = 0; idx_face < static_cast<int> (mesh.tex_polygons[idx_pcam].size ()); ++idx_face)
815  {
816 
817  if (idx_pcam == current_cam && !visibility[idx_face])
818  {
819  // we are now checking for self occlusions within the current faces
820  // the current face was already declared as occluded.
821  // therefore, it cannot occlude another face anymore => we skip it
822  continue;
823  }
824 
825  // project each vertice, if one is out of view, stop
826  pcl::PointXY uv_coord1;
827  pcl::PointXY uv_coord2;
828  pcl::PointXY uv_coord3;
829 
830  if (isFaceProjected (cameras[current_cam],
831  (*camera_cloud)[mesh.tex_polygons[idx_pcam][idx_face].vertices[0]],
832  (*camera_cloud)[mesh.tex_polygons[idx_pcam][idx_face].vertices[1]],
833  (*camera_cloud)[mesh.tex_polygons[idx_pcam][idx_face].vertices[2]],
834  uv_coord1,
835  uv_coord2,
836  uv_coord3))
837  {
838  // face is in the camera's FOV
839  //get its circumsribed circle
840  double radius;
841  pcl::PointXY center;
842  // getTriangleCircumcenterAndSize (uv_coord1, uv_coord2, uv_coord3, center, radius);
843  getTriangleCircumcscribedCircleCentroid(uv_coord1, uv_coord2, uv_coord3, center, radius); // this function yields faster results than getTriangleCircumcenterAndSize
844 
845  // get points inside circ.circle
846  if (kdtree.radiusSearch (center, radius, idxNeighbors, neighborsSquaredDistance) > 0 )
847  {
848  // for each neighbor
849  for (const auto &idxNeighbor : idxNeighbors)
850  {
851  if (std::max ((*camera_cloud)[mesh.tex_polygons[idx_pcam][idx_face].vertices[0]].z,
852  std::max ((*camera_cloud)[mesh.tex_polygons[idx_pcam][idx_face].vertices[1]].z,
853  (*camera_cloud)[mesh.tex_polygons[idx_pcam][idx_face].vertices[2]].z))
854  < (*camera_cloud)[indexes_uv_to_points[idxNeighbor].idx_cloud].z)
855  {
856  // neighbor is farther than all the face's points. Check if it falls into the triangle
857  if (checkPointInsideTriangle(uv_coord1, uv_coord2, uv_coord3, (*projections)[idxNeighbor]))
858  {
859  // current neighbor is inside triangle and is closer => the corresponding face
860  visibility[indexes_uv_to_points[idxNeighbor].idx_face] = false;
861  cpt_invisible++;
862  //TODO we could remove the projections of this face from the kd-tree cloud, but I fond it slower, and I need the point to keep ordered to querry UV coordinates later
863  }
864  }
865  }
866  }
867  }
868  }
869  }
870  }
871 
872  // now, visibility is true for each face that belongs to the current camera
873  // if a face is not visible, we push it into the next one.
874 
875  if (static_cast<int> (mesh.tex_coordinates.size ()) <= current_cam)
876  {
877  std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > dummy_container;
878  mesh.tex_coordinates.push_back (dummy_container);
879  }
880  mesh.tex_coordinates[current_cam].resize (3 * visibility.size ());
881 
882  std::vector<pcl::Vertices> occluded_faces;
883  occluded_faces.resize (visibility.size ());
884  std::vector<pcl::Vertices> visible_faces;
885  visible_faces.resize (visibility.size ());
886 
887  int cpt_occluded_faces = 0;
888  int cpt_visible_faces = 0;
889 
890  for (std::size_t idx_face = 0 ; idx_face < visibility.size () ; ++idx_face)
891  {
892  if (visibility[idx_face])
893  {
894  // face is visible by the current camera copy UV coordinates
895  mesh.tex_coordinates[current_cam][cpt_visible_faces * 3](0) = (*projections)[idx_face*3].x;
896  mesh.tex_coordinates[current_cam][cpt_visible_faces * 3](1) = (*projections)[idx_face*3].y;
897 
898  mesh.tex_coordinates[current_cam][cpt_visible_faces * 3 + 1](0) = (*projections)[idx_face*3 + 1].x;
899  mesh.tex_coordinates[current_cam][cpt_visible_faces * 3 + 1](1) = (*projections)[idx_face*3 + 1].y;
900 
901  mesh.tex_coordinates[current_cam][cpt_visible_faces * 3 + 2](0) = (*projections)[idx_face*3 + 2].x;
902  mesh.tex_coordinates[current_cam][cpt_visible_faces * 3 + 2](1) = (*projections)[idx_face*3 + 2].y;
903 
904  visible_faces[cpt_visible_faces] = mesh.tex_polygons[current_cam][idx_face];
905 
906  cpt_visible_faces++;
907  }
908  else
909  {
910  // face is occluded copy face into temp vector
911  occluded_faces[cpt_occluded_faces] = mesh.tex_polygons[current_cam][idx_face];
912  cpt_occluded_faces++;
913  }
914  }
915  mesh.tex_coordinates[current_cam].resize (cpt_visible_faces*3);
916 
917  occluded_faces.resize (cpt_occluded_faces);
918  mesh.tex_polygons.push_back (occluded_faces);
919 
920  visible_faces.resize (cpt_visible_faces);
921  mesh.tex_polygons[current_cam].clear ();
922  mesh.tex_polygons[current_cam] = visible_faces;
923  }
924 
925  // we have been through all the cameras.
926  // if any faces are left, they were not visible by any camera
927  // we still need to produce uv coordinates for them
928 
929  if (mesh.tex_coordinates.size() <= cameras.size ())
930  {
931  std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > dummy_container;
932  mesh.tex_coordinates.push_back(dummy_container);
933  }
934 
935 
936  for(std::size_t idx_face = 0 ; idx_face < mesh.tex_polygons[cameras.size()].size() ; ++idx_face)
937  {
938  Eigen::Vector2f UV1, UV2, UV3;
939  UV1(0) = -1.0; UV1(1) = -1.0;
940  UV2(0) = -1.0; UV2(1) = -1.0;
941  UV3(0) = -1.0; UV3(1) = -1.0;
942  mesh.tex_coordinates[cameras.size()].push_back(UV1);
943  mesh.tex_coordinates[cameras.size()].push_back(UV2);
944  mesh.tex_coordinates[cameras.size()].push_back(UV3);
945  }
946 
947 }
948 
949 ///////////////////////////////////////////////////////////////////////////////////////////////
950 template<typename PointInT> inline void
952 {
953  // we simplify the problem by translating the triangle's origin to its first point
954  pcl::PointXY ptB, ptC;
955  ptB.x = p2.x - p1.x; ptB.y = p2.y - p1.y; // B'=B-A
956  ptC.x = p3.x - p1.x; ptC.y = p3.y - p1.y; // C'=C-A
957 
958  double D = 2.0*(ptB.x*ptC.y - ptB.y*ptC.x); // D'=2(B'x*C'y - B'y*C'x)
959 
960  // Safety check to avoid division by zero
961  if(D == 0)
962  {
963  circomcenter.x = p1.x;
964  circomcenter.y = p1.y;
965  }
966  else
967  {
968  // compute squares once
969  double bx2 = ptB.x * ptB.x; // B'x^2
970  double by2 = ptB.y * ptB.y; // B'y^2
971  double cx2 = ptC.x * ptC.x; // C'x^2
972  double cy2 = ptC.y * ptC.y; // C'y^2
973 
974  // compute circomcenter's coordinates (translate back to original coordinates)
975  circomcenter.x = static_cast<float> (p1.x + (ptC.y*(bx2 + by2) - ptB.y*(cx2 + cy2)) / D);
976  circomcenter.y = static_cast<float> (p1.y + (ptB.x*(cx2 + cy2) - ptC.x*(bx2 + by2)) / D);
977  }
978 
979  radius = std::sqrt( (circomcenter.x - p1.x)*(circomcenter.x - p1.x) + (circomcenter.y - p1.y)*(circomcenter.y - p1.y));//2.0* (p1.x*(p2.y - p3.y) + p2.x*(p3.y - p1.y) + p3.x*(p1.y - p2.y));
980 }
981 
982 ///////////////////////////////////////////////////////////////////////////////////////////////
983 template<typename PointInT> inline void
985 {
986  // compute centroid's coordinates (translate back to original coordinates)
987  circumcenter.x = static_cast<float> (p1.x + p2.x + p3.x ) / 3;
988  circumcenter.y = static_cast<float> (p1.y + p2.y + p3.y ) / 3;
989  double r1 = (circumcenter.x - p1.x) * (circumcenter.x - p1.x) + (circumcenter.y - p1.y) * (circumcenter.y - p1.y) ;
990  double r2 = (circumcenter.x - p2.x) * (circumcenter.x - p2.x) + (circumcenter.y - p2.y) * (circumcenter.y - p2.y) ;
991  double r3 = (circumcenter.x - p3.x) * (circumcenter.x - p3.x) + (circumcenter.y - p3.y) * (circumcenter.y - p3.y) ;
992 
993  // radius
994  radius = std::sqrt( std::max( r1, std::max( r2, r3) )) ;
995 }
996 
997 
998 ///////////////////////////////////////////////////////////////////////////////////////////////
999 template<typename PointInT> inline bool
1000 pcl::TextureMapping<PointInT>::getPointUVCoordinates(const PointInT &pt, const Camera &cam, pcl::PointXY &UV_coordinates)
1001 {
1002  if (pt.z > 0)
1003  {
1004  // compute image center and dimension
1005  double sizeX = cam.width;
1006  double sizeY = cam.height;
1007  double cx, cy;
1008  if (cam.center_w > 0)
1009  cx = cam.center_w;
1010  else
1011  cx = sizeX / 2.0;
1012  if (cam.center_h > 0)
1013  cy = cam.center_h;
1014  else
1015  cy = sizeY / 2.0;
1016 
1017  double focal_x, focal_y;
1018  if (cam.focal_length_w > 0)
1019  focal_x = cam.focal_length_w;
1020  else
1021  focal_x = cam.focal_length;
1022  if (cam.focal_length_h > 0)
1023  focal_y = cam.focal_length_h;
1024  else
1025  focal_y = cam.focal_length;
1026 
1027  // project point on camera's image plane
1028  UV_coordinates.x = static_cast<float> ((focal_x * (pt.x / pt.z) + cx) / sizeX); //horizontal
1029  UV_coordinates.y = 1.0f - static_cast<float> ((focal_y * (pt.y / pt.z) + cy) / sizeY); //vertical
1030 
1031  // point is visible!
1032  if (UV_coordinates.x >= 0.0 && UV_coordinates.x <= 1.0 && UV_coordinates.y >= 0.0 && UV_coordinates.y <= 1.0)
1033  return (true); // point was visible by the camera
1034  }
1035 
1036  // point is NOT visible by the camera
1037  UV_coordinates.x = -1.0f;
1038  UV_coordinates.y = -1.0f;
1039  return (false); // point was not visible by the camera
1040 }
1041 
1042 ///////////////////////////////////////////////////////////////////////////////////////////////
1043 template<typename PointInT> inline bool
1045 {
1046  // Compute vectors
1047  Eigen::Vector2d v0, v1, v2;
1048  v0(0) = p3.x - p1.x; v0(1) = p3.y - p1.y; // v0= C - A
1049  v1(0) = p2.x - p1.x; v1(1) = p2.y - p1.y; // v1= B - A
1050  v2(0) = pt.x - p1.x; v2(1) = pt.y - p1.y; // v2= P - A
1051 
1052  // Compute dot products
1053  double dot00 = v0.dot(v0); // dot00 = dot(v0, v0)
1054  double dot01 = v0.dot(v1); // dot01 = dot(v0, v1)
1055  double dot02 = v0.dot(v2); // dot02 = dot(v0, v2)
1056  double dot11 = v1.dot(v1); // dot11 = dot(v1, v1)
1057  double dot12 = v1.dot(v2); // dot12 = dot(v1, v2)
1058 
1059  // Compute barycentric coordinates
1060  double invDenom = 1.0 / (dot00*dot11 - dot01*dot01);
1061  double u = (dot11*dot02 - dot01*dot12) * invDenom;
1062  double v = (dot00*dot12 - dot01*dot02) * invDenom;
1063 
1064  // Check if point is in triangle
1065  return ((u >= 0) && (v >= 0) && (u + v < 1));
1066 }
1067 
1068 ///////////////////////////////////////////////////////////////////////////////////////////////
1069 template<typename PointInT> inline bool
1070 pcl::TextureMapping<PointInT>::isFaceProjected (const Camera &camera, const PointInT &p1, const PointInT &p2, const PointInT &p3, pcl::PointXY &proj1, pcl::PointXY &proj2, pcl::PointXY &proj3)
1071 {
1072  return (getPointUVCoordinates(p1, camera, proj1)
1073  &&
1074  getPointUVCoordinates(p2, camera, proj2)
1075  &&
1076  getPointUVCoordinates(p3, camera, proj3)
1077  );
1078 }
1079 
1080 #define PCL_INSTANTIATE_TextureMapping(T) \
1081  template class PCL_EXPORTS pcl::TextureMapping<T>;
1082 
1083 #endif /* TEXTURE_MAPPING_HPP_ */
pcl::TextureMapping::checkPointInsideTriangle
bool checkPointInsideTriangle(const pcl::PointXY &p1, const pcl::PointXY &p2, const pcl::PointXY &p3, const pcl::PointXY &pt)
Returns True if a point lays within a triangle.
Definition: texture_mapping.hpp:1044
pcl::TextureMesh::tex_polygons
std::vector< std::vector< pcl::Vertices > > tex_polygons
Definition: TextureMesh.h:94
pcl::texture_mapping::Camera::width
double width
Definition: texture_mapping.h:76
pcl::texture_mapping::Camera::focal_length_w
double focal_length_w
Definition: texture_mapping.h:71
pcl::texture_mapping::Camera::pose
Eigen::Affine3f pose
Definition: texture_mapping.h:69
pcl::TextureMesh::tex_coordinates
std::vector< std::vector< Eigen::Vector2f, Eigen::aligned_allocator< Eigen::Vector2f > > > tex_coordinates
Definition: TextureMesh.h:95
pcl::octree::OctreePointCloudSearch::getIntersectedVoxelIndices
int getIntersectedVoxelIndices(Eigen::Vector3f origin, Eigen::Vector3f direction, std::vector< int > &k_indices, int max_voxel_count=0) const
Get indices of all voxels that are intersected by a ray (origin, direction).
Definition: octree_search.hpp:631
pcl::PointCloud::points
std::vector< PointT, Eigen::aligned_allocator< PointT > > points
The point data.
Definition: point_cloud.h:388
pcl::TextureMapping::getTriangleCircumcscribedCircleCentroid
void getTriangleCircumcscribedCircleCentroid(const pcl::PointXY &p1, const pcl::PointXY &p2, const pcl::PointXY &p3, pcl::PointXY &circumcenter, double &radius)
Returns the centroid of a triangle and the corresponding circumscribed circle's radius.
Definition: texture_mapping.hpp:984
pcl::texture_mapping::UvIndex
Structure that links a uv coordinate to its 3D point and face.
Definition: texture_mapping.h:84
pcl::TextureMapping::mapTexture2MeshUV
void mapTexture2MeshUV(pcl::TextureMesh &tex_mesh)
Map texture to a mesh UV mapping.
Definition: texture_mapping.hpp:201
pcl::TextureMapping::textureMeshwithMultipleCameras
void textureMeshwithMultipleCameras(pcl::TextureMesh &mesh, const pcl::texture_mapping::CameraVector &cameras)
Segment and texture faces by camera visibility.
Definition: texture_mapping.hpp:710
pcl::PCLPointCloud2::height
index_t height
Definition: PCLPointCloud2.h:20
pcl::texture_mapping::Camera::focal_length_h
double focal_length_h
Definition: texture_mapping.h:72
pcl::octree::OctreePointCloud::addPointsFromInputCloud
void addPointsFromInputCloud()
Add points from input point cloud to octree.
Definition: octree_pointcloud.hpp:78
pcl::euclideanDistance
float euclideanDistance(const PointType1 &p1, const PointType2 &p2)
Calculate the euclidean distance between the two given points.
Definition: distances.h:204
pcl::PointXYZI
Definition: point_types.hpp:464
pcl::TextureMesh::cloud
pcl::PCLPointCloud2 cloud
Definition: TextureMesh.h:90
pcl::PointCloud< PointInT >
pcl::texture_mapping::UvIndex::idx_face
int idx_face
Definition: texture_mapping.h:88
pcl::index_t
detail::int_type_t< detail::index_type_size, detail::index_type_signed > index_t
Type used for an index in PCL.
Definition: types.h:110
pcl::TextureMesh::tex_materials
std::vector< pcl::TexMaterial > tex_materials
Definition: TextureMesh.h:96
pcl::TextureMapping::isFaceProjected
bool isFaceProjected(const Camera &camera, const PointInT &p1, const PointInT &p2, const PointInT &p3, pcl::PointXY &proj1, pcl::PointXY &proj2, pcl::PointXY &proj3)
Returns true if all the vertices of one face are projected on the camera's image plane.
Definition: texture_mapping.hpp:1070
pcl::octree::OctreePointCloud::defineBoundingBox
void defineBoundingBox()
Investigate dimensions of pointcloud data set and define corresponding bounding box for octree.
Definition: octree_pointcloud.hpp:332
pcl::transformPointCloud
void transformPointCloud(const pcl::PointCloud< PointT > &cloud_in, pcl::PointCloud< PointT > &cloud_out, const Eigen::Matrix< Scalar, 4, 4 > &transform, bool copy_all_fields)
Apply a rigid transform defined by a 4x4 matrix.
Definition: transforms.hpp:221
pcl::_PointXYZI::intensity
float intensity
Definition: point_types.hpp:456
pcl::PointXY::x
float x
Definition: point_types.hpp:746
pcl::octree::OctreePointCloud::setInputCloud
void setInputCloud(const PointCloudConstPtr &cloud_arg, const IndicesConstPtr &indices_arg=IndicesConstPtr())
Provide a pointer to the input data set.
Definition: octree_pointcloud.h:117
pcl::texture_mapping::Camera::height
double height
Definition: texture_mapping.h:75
pcl::PCLPointCloud2::width
index_t width
Definition: PCLPointCloud2.h:21
pcl::TextureMapping::isPointOccluded
bool isPointOccluded(const PointInT &pt, const OctreePtr octree)
Check if a point is occluded using raycasting on octree.
Definition: texture_mapping.hpp:367
pcl::texture_mapping::Camera::focal_length
double focal_length
Definition: texture_mapping.h:70
pcl::PCLPointCloud2::fields
std::vector<::pcl::PCLPointField > fields
Definition: PCLPointCloud2.h:23
pcl::texture_mapping::Camera
Structure to store camera pose and focal length.
Definition: texture_mapping.h:65
pcl::PointXY::y
float y
Definition: point_types.hpp:747
pcl::TextureMapping::OctreePtr
typename Octree::Ptr OctreePtr
Definition: texture_mapping.h:112
pcl::TextureMapping::getPointUVCoordinates
bool getPointUVCoordinates(const PointInT &pt, const Camera &cam, Eigen::Vector2f &UV_coordinates)
computes UV coordinates of point, observed by one particular camera
Definition: texture_mapping.h:198
pcl::KdTreeFLANN
KdTreeFLANN is a generic type of 3D spatial locator using kD-tree structures.
Definition: kdtree_flann.h:64
pcl::texture_mapping::Camera::texture_file
std::string texture_file
Definition: texture_mapping.h:77
pcl::texture_mapping::Camera::center_w
double center_w
Definition: texture_mapping.h:73
pcl::texture_mapping::CameraVector
std::vector< Camera, Eigen::aligned_allocator< Camera > > CameraVector
Definition: texture_mapping.h:91
pcl::TextureMapping::mapTexture2Mesh
void mapTexture2Mesh(pcl::TextureMesh &tex_mesh)
Map texture to a mesh synthesis algorithm.
Definition: texture_mapping.hpp:145
pcl::KdTreeFLANN::radiusSearch
int radiusSearch(const PointT &point, double radius, std::vector< int > &k_indices, std::vector< float > &k_sqr_distances, unsigned int max_nn=0) const override
Search for all the nearest neighbors of the query point in a given radius.
Definition: kdtree_flann.hpp:172
pcl::PointXY
A 2D point structure representing Euclidean xy coordinates.
Definition: point_types.hpp:744
pcl::Indices
IndicesAllocator<> Indices
Type used for indices in PCL.
Definition: types.h:131
pcl::PCLPointCloud2::data
std::vector< std::uint8_t > data
Definition: PCLPointCloud2.h:30
pcl::TextureMapping::mapTexture2Face
std::vector< Eigen::Vector2f, Eigen::aligned_allocator< Eigen::Vector2f > > mapTexture2Face(const Eigen::Vector3f &p1, const Eigen::Vector3f &p2, const Eigen::Vector3f &p3)
Map texture to a face.
Definition: texture_mapping.hpp:47
pcl::PointCloud::Ptr
shared_ptr< PointCloud< PointT > > Ptr
Definition: point_cloud.h:406
pcl::TextureMapping::PointCloudConstPtr
typename PointCloud::ConstPtr PointCloudConstPtr
Definition: texture_mapping.h:109
pcl::TextureMapping::showOcclusions
void showOcclusions(const PointCloudPtr &input_cloud, pcl::PointCloud< pcl::PointXYZI >::Ptr &colored_cloud, const double octree_voxel_size, const bool show_nb_occlusions=true, const int max_occlusions=4)
Colors a point cloud, depending on its occlusions.
Definition: texture_mapping.hpp:624
pcl::TextureMapping::removeOccludedPoints
void removeOccludedPoints(const PointCloudPtr &input_cloud, PointCloudPtr &filtered_cloud, const double octree_voxel_size, pcl::Indices &visible_indices, pcl::Indices &occluded_indices)
Remove occluded points from a point cloud.
Definition: texture_mapping.hpp:406
pcl::TextureMesh
Definition: TextureMesh.h:88
pcl::texture_mapping::Camera::center_h
double center_h
Definition: texture_mapping.h:74
distances.h
pcl::TextureMapping::mapMultipleTexturesToMeshUV
void mapMultipleTexturesToMeshUV(pcl::TextureMesh &tex_mesh, pcl::texture_mapping::CameraVector &cams)
Map textures acquired from a set of cameras onto a mesh.
Definition: texture_mapping.hpp:287
pcl::TextureMapping::getTriangleCircumcenterAndSize
void getTriangleCircumcenterAndSize(const pcl::PointXY &p1, const pcl::PointXY &p2, const pcl::PointXY &p3, pcl::PointXY &circumcenter, double &radius)
Returns the circumcenter of a triangle and the circle's radius.
Definition: texture_mapping.hpp:951
pcl::TextureMapping::PointCloudPtr
typename PointCloud::Ptr PointCloudPtr
Definition: texture_mapping.h:108
pcl::octree::OctreePointCloudSearch
Octree pointcloud search class
Definition: octree_search.h:57
pcl::KdTreeFLANN::setInputCloud
void setInputCloud(const PointCloudConstPtr &cloud, const IndicesConstPtr &indices=IndicesConstPtr()) override
Provide a pointer to the input dataset.
Definition: kdtree_flann.hpp:92
pcl::fromPCLPointCloud2
void fromPCLPointCloud2(const pcl::PCLPointCloud2 &msg, pcl::PointCloud< PointT > &cloud, const MsgFieldMap &field_map)
Convert a PCLPointCloud2 binary data blob into a pcl::PointCloud<T> object using a field_map.
Definition: conversions.h:167
pcl::TextureMapping::sortFacesByCamera
int sortFacesByCamera(pcl::TextureMesh &tex_mesh, pcl::TextureMesh &sorted_mesh, const pcl::texture_mapping::CameraVector &cameras, const double octree_voxel_size, PointCloud &visible_pts)
Segment faces by camera visibility.
Definition: texture_mapping.hpp:538
pcl::texture_mapping::UvIndex::idx_cloud
int idx_cloud
Definition: texture_mapping.h:87