texture_mapping.hpp
Go to the documentation of this file.
00001 /*
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Copyright (c) 2010, Willow Garage, Inc.
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions
00009  *  are met:
00010  *
00011  *   * Redistributions of source code must retain the above copyright
00012  *     notice, this list of conditions and the following disclaimer.
00013  *   * Redistributions in binary form must reproduce the above
00014  *     copyright notice, this list of conditions and the following
00015  *     disclaimer in the documentation and/or other materials provided
00016  *     with the distribution.
00017  *   * Neither the name of Willow Garage, Inc. nor the names of its
00018  *     contributors may be used to endorse or promote products derived
00019  *     from this software without specific prior written permission.
00020  *
00021  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032  *  POSSIBILITY OF SUCH DAMAGE.
00033  *
00034  * $Id$
00035  *
00036  */
00037 
00038 #ifndef PCL_SURFACE_IMPL_TEXTURE_MAPPING_HPP_
00039 #define PCL_SURFACE_IMPL_TEXTURE_MAPPING_HPP_
00040 
00041 #include <pcl/common/distances.h>
00042 #include <pcl18/surface/texture_mapping.h>
00043 #include <pcl/search/octree.h>
00044 
00046 template<typename PointInT> std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> >
00047 pcl::TextureMapping<PointInT>::mapTexture2Face (
00048     const Eigen::Vector3f &p1, 
00049     const Eigen::Vector3f &p2, 
00050     const Eigen::Vector3f &p3)
00051 {
00052   std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > tex_coordinates;
00053   // process for each face
00054   Eigen::Vector3f p1p2 (p2[0] - p1[0], p2[1] - p1[1], p2[2] - p1[2]);
00055   Eigen::Vector3f p1p3 (p3[0] - p1[0], p3[1] - p1[1], p3[2] - p1[2]);
00056   Eigen::Vector3f p2p3 (p3[0] - p2[0], p3[1] - p2[1], p3[2] - p2[2]);
00057 
00058   // Normalize
00059   p1p2 = p1p2 / std::sqrt (p1p2.dot (p1p2));
00060   p1p3 = p1p3 / std::sqrt (p1p3.dot (p1p3));
00061   p2p3 = p2p3 / std::sqrt (p2p3.dot (p2p3));
00062 
00063   // compute vector normal of a face
00064   Eigen::Vector3f f_normal = p1p2.cross (p1p3);
00065   f_normal = f_normal / std::sqrt (f_normal.dot (f_normal));
00066 
00067   // project vector field onto the face: vector v1_projected = v1 - Dot(v1, n) * n;
00068   Eigen::Vector3f f_vector_field = vector_field_ - vector_field_.dot (f_normal) * f_normal;
00069 
00070   // Normalize
00071   f_vector_field = f_vector_field / std::sqrt (f_vector_field.dot (f_vector_field));
00072 
00073   // texture coordinates
00074   Eigen::Vector2f tp1, tp2, tp3;
00075 
00076   double alpha = std::acos (f_vector_field.dot (p1p2));
00077 
00078   // distance between 3 vertices of triangles
00079   double e1 = (p2 - p3).norm () / f_;
00080   double e2 = (p1 - p3).norm () / f_;
00081   double e3 = (p1 - p2).norm () / f_;
00082 
00083   // initialize
00084   tp1[0] = 0.0;
00085   tp1[1] = 0.0;
00086 
00087   tp2[0] = static_cast<float> (e3);
00088   tp2[1] = 0.0;
00089 
00090   // determine texture coordinate tp3;
00091   double cos_p1 = (e2 * e2 + e3 * e3 - e1 * e1) / (2 * e2 * e3);
00092   double sin_p1 = sqrt (1 - (cos_p1 * cos_p1));
00093 
00094   tp3[0] = static_cast<float> (cos_p1 * e2);
00095   tp3[1] = static_cast<float> (sin_p1 * e2);
00096 
00097   // rotating by alpha (angle between V and pp1 & pp2)
00098   Eigen::Vector2f r_tp2, r_tp3;
00099   r_tp2[0] = static_cast<float> (tp2[0] * std::cos (alpha) - tp2[1] * std::sin (alpha));
00100   r_tp2[1] = static_cast<float> (tp2[0] * std::sin (alpha) + tp2[1] * std::cos (alpha));
00101 
00102   r_tp3[0] = static_cast<float> (tp3[0] * std::cos (alpha) - tp3[1] * std::sin (alpha));
00103   r_tp3[1] = static_cast<float> (tp3[0] * std::sin (alpha) + tp3[1] * std::cos (alpha));
00104 
00105   // shifting
00106   tp1[0] = tp1[0];
00107   tp2[0] = r_tp2[0];
00108   tp3[0] = r_tp3[0];
00109   tp1[1] = tp1[1];
00110   tp2[1] = r_tp2[1];
00111   tp3[1] = r_tp3[1];
00112 
00113   float min_x = tp1[0];
00114   float min_y = tp1[1];
00115   if (min_x > tp2[0])
00116     min_x = tp2[0];
00117   if (min_x > tp3[0])
00118     min_x = tp3[0];
00119   if (min_y > tp2[1])
00120     min_y = tp2[1];
00121   if (min_y > tp3[1])
00122     min_y = tp3[1];
00123 
00124   if (min_x < 0)
00125   {
00126     tp1[0] = tp1[0] - min_x;
00127     tp2[0] = tp2[0] - min_x;
00128     tp3[0] = tp3[0] - min_x;
00129   }
00130   if (min_y < 0)
00131   {
00132     tp1[1] = tp1[1] - min_y;
00133     tp2[1] = tp2[1] - min_y;
00134     tp3[1] = tp3[1] - min_y;
00135   }
00136 
00137   tex_coordinates.push_back (tp1);
00138   tex_coordinates.push_back (tp2);
00139   tex_coordinates.push_back (tp3);
00140   return (tex_coordinates);
00141 }
00142 
00144 template<typename PointInT> void
00145 pcl::TextureMapping<PointInT>::mapTexture2Mesh (pcl::TextureMesh &tex_mesh)
00146 {
00147   // mesh information
00148   int nr_points = tex_mesh.cloud.width * tex_mesh.cloud.height;
00149   int point_size = static_cast<int> (tex_mesh.cloud.data.size ()) / nr_points;
00150 
00151   // temporary PointXYZ
00152   float x, y, z;
00153   // temporary face
00154   Eigen::Vector3f facet[3];
00155 
00156   // texture coordinates for each mesh
00157   std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > >texture_map;
00158 
00159   for (size_t m = 0; m < tex_mesh.tex_polygons.size (); ++m)
00160   {
00161     // texture coordinates for each mesh
00162 #if PCL_VERSION_COMPARE(>=, 1, 8, 0)
00163         std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > texture_map_tmp;
00164 #else
00165         std::vector<Eigen::Vector2f> texture_map_tmp;
00166 #endif
00167 
00168     // processing for each face
00169     for (size_t i = 0; i < tex_mesh.tex_polygons[m].size (); ++i)
00170     {
00171       size_t idx;
00172 
00173       // get facet information
00174       for (size_t j = 0; j < tex_mesh.tex_polygons[m][i].vertices.size (); ++j)
00175       {
00176         idx = tex_mesh.tex_polygons[m][i].vertices[j];
00177         memcpy (&x, &tex_mesh.cloud.data[idx * point_size + tex_mesh.cloud.fields[0].offset], sizeof(float));
00178         memcpy (&y, &tex_mesh.cloud.data[idx * point_size + tex_mesh.cloud.fields[1].offset], sizeof(float));
00179         memcpy (&z, &tex_mesh.cloud.data[idx * point_size + tex_mesh.cloud.fields[2].offset], sizeof(float));
00180         facet[j][0] = x;
00181         facet[j][1] = y;
00182         facet[j][2] = z;
00183       }
00184 
00185       // get texture coordinates of each face
00186       std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > tex_coordinates = mapTexture2Face (facet[0], facet[1], facet[2]);
00187       for (size_t n = 0; n < tex_coordinates.size (); ++n)
00188         texture_map_tmp.push_back (tex_coordinates[n]);
00189     }// end faces
00190 
00191     // texture materials
00192     std::stringstream tex_name;
00193     tex_name << "material_" << m;
00194     tex_name >> tex_material_.tex_name;
00195     tex_material_.tex_file = tex_files_[m];
00196     tex_mesh.tex_materials.push_back (tex_material_);
00197 
00198     // texture coordinates
00199     tex_mesh.tex_coordinates.push_back (texture_map_tmp);
00200   }// end meshes
00201 }
00202 
00204 template<typename PointInT> void
00205 pcl::TextureMapping<PointInT>::mapTexture2MeshUV (pcl::TextureMesh &tex_mesh)
00206 {
00207   // mesh information
00208   int nr_points = tex_mesh.cloud.width * tex_mesh.cloud.height;
00209   int point_size = static_cast<int> (tex_mesh.cloud.data.size ()) / nr_points;
00210 
00211   float x_lowest = 100000;
00212   float x_highest = 0;
00213   float y_lowest = 100000;
00214   //float y_highest = 0 ;
00215   float z_lowest = 100000;
00216   float z_highest = 0;
00217   float x_, y_, z_;
00218 
00219   for (int i = 0; i < nr_points; ++i)
00220   {
00221     memcpy (&x_, &tex_mesh.cloud.data[i * point_size + tex_mesh.cloud.fields[0].offset], sizeof(float));
00222     memcpy (&y_, &tex_mesh.cloud.data[i * point_size + tex_mesh.cloud.fields[1].offset], sizeof(float));
00223     memcpy (&z_, &tex_mesh.cloud.data[i * point_size + tex_mesh.cloud.fields[2].offset], sizeof(float));
00224     // x
00225     if (x_ <= x_lowest)
00226       x_lowest = x_;
00227     if (x_ > x_lowest)
00228       x_highest = x_;
00229 
00230     // y
00231     if (y_ <= y_lowest)
00232       y_lowest = y_;
00233     //if (y_ > y_lowest) y_highest = y_;
00234 
00235     // z
00236     if (z_ <= z_lowest)
00237       z_lowest = z_;
00238     if (z_ > z_lowest)
00239       z_highest = z_;
00240   }
00241   // x
00242   float x_range = (x_lowest - x_highest) * -1;
00243   float x_offset = 0 - x_lowest;
00244   // x
00245   // float y_range = (y_lowest - y_highest)*-1;
00246   // float y_offset = 0 - y_lowest;
00247   // z
00248   float z_range = (z_lowest - z_highest) * -1;
00249   float z_offset = 0 - z_lowest;
00250 
00251   // texture coordinates for each mesh
00252   std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > >texture_map;
00253 
00254   for (size_t m = 0; m < tex_mesh.tex_polygons.size (); ++m)
00255   {
00256     // texture coordinates for each mesh
00257 #if PCL_VERSION_COMPARE(>=, 1, 8, 0)
00258         std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > texture_map_tmp;
00259 #else
00260         std::vector<Eigen::Vector2f> texture_map_tmp;
00261 #endif
00262 
00263     // processing for each face
00264     for (size_t i = 0; i < tex_mesh.tex_polygons[m].size (); ++i)
00265     {
00266       size_t idx;
00267       Eigen::Vector2f tmp_VT;
00268       for (size_t j = 0; j < tex_mesh.tex_polygons[m][i].vertices.size (); ++j)
00269       {
00270         idx = tex_mesh.tex_polygons[m][i].vertices[j];
00271         memcpy (&x_, &tex_mesh.cloud.data[idx * point_size + tex_mesh.cloud.fields[0].offset], sizeof(float));
00272         memcpy (&y_, &tex_mesh.cloud.data[idx * point_size + tex_mesh.cloud.fields[1].offset], sizeof(float));
00273         memcpy (&z_, &tex_mesh.cloud.data[idx * point_size + tex_mesh.cloud.fields[2].offset], sizeof(float));
00274 
00275         // calculate uv coordinates
00276         tmp_VT[0] = (x_ + x_offset) / x_range;
00277         tmp_VT[1] = (z_ + z_offset) / z_range;
00278         texture_map_tmp.push_back (tmp_VT);
00279       }
00280     }// end faces
00281 
00282     // texture materials
00283     std::stringstream tex_name;
00284     tex_name << "material_" << m;
00285     tex_name >> tex_material_.tex_name;
00286     tex_material_.tex_file = tex_files_[m];
00287     tex_mesh.tex_materials.push_back (tex_material_);
00288 
00289     // texture coordinates
00290     tex_mesh.tex_coordinates.push_back (texture_map_tmp);
00291   }// end meshes
00292 }
00293 
00295 template<typename PointInT> void
00296 pcl::TextureMapping<PointInT>::mapMultipleTexturesToMeshUV (pcl::TextureMesh &tex_mesh, pcl::texture_mapping::CameraVector &cams)
00297 {
00298 
00299   if (tex_mesh.tex_polygons.size () != cams.size () + 1)
00300   {
00301     PCL_ERROR ("The mesh should be divided into nbCamera+1 sub-meshes.\n");
00302     PCL_ERROR ("You provided %d cameras and a mesh containing %d sub-meshes.\n", cams.size (), tex_mesh.tex_polygons.size ());
00303     return;
00304   }
00305 
00306   PCL_INFO ("You provided %d  cameras and a mesh containing %d sub-meshes.\n", cams.size (), tex_mesh.tex_polygons.size ());
00307 
00308   typename pcl::PointCloud<PointInT>::Ptr originalCloud (new pcl::PointCloud<PointInT>);
00309   typename pcl::PointCloud<PointInT>::Ptr camera_transformed_cloud (new pcl::PointCloud<PointInT>);
00310 
00311   // convert mesh's cloud to pcl format for ease
00312   pcl::fromPCLPointCloud2 (tex_mesh.cloud, *originalCloud);
00313 
00314   // texture coordinates for each mesh
00315   std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > texture_map;
00316 
00317   for (size_t m = 0; m < cams.size (); ++m)
00318   {
00319     // get current camera parameters
00320     Camera current_cam = cams[m];
00321 
00322     // get camera transform
00323     Eigen::Affine3f cam_trans = current_cam.pose;
00324 
00325     // transform cloud into current camera frame
00326     pcl::transformPointCloud (*originalCloud, *camera_transformed_cloud, cam_trans.inverse ());
00327 
00328     // vector of texture coordinates for each face
00329 #if PCL_VERSION_COMPARE(>=, 1, 8, 0)
00330         std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > texture_map_tmp;
00331 #else
00332         std::vector<Eigen::Vector2f> texture_map_tmp;
00333 #endif
00334 
00335     // processing each face visible by this camera
00336     PointInT pt;
00337     size_t idx;
00338     for (size_t i = 0; i < tex_mesh.tex_polygons[m].size (); ++i)
00339     {
00340       Eigen::Vector2f tmp_VT;
00341       // for each point of this face
00342       for (size_t j = 0; j < tex_mesh.tex_polygons[m][i].vertices.size (); ++j)
00343       {
00344         // get point
00345         idx = tex_mesh.tex_polygons[m][i].vertices[j];
00346         pt = camera_transformed_cloud->points[idx];
00347 
00348         // compute UV coordinates for this point
00349         getPointUVCoordinates (pt, current_cam, tmp_VT);
00350         texture_map_tmp.push_back (tmp_VT);
00351 
00352       }// end points
00353     }// end faces
00354 
00355     // texture materials
00356     std::stringstream tex_name;
00357     tex_name << "material_" << m;
00358     tex_name >> tex_material_.tex_name;
00359     tex_material_.tex_file = current_cam.texture_file;
00360     tex_mesh.tex_materials.push_back (tex_material_);
00361 
00362     // texture coordinates
00363     tex_mesh.tex_coordinates.push_back (texture_map_tmp);
00364   }// end cameras
00365 
00366   // push on extra empty UV map (for unseen faces) so that obj writer does not crash!
00367 #if PCL_VERSION_COMPARE(>=, 1, 8, 0)
00368         std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > texture_map_tmp;
00369 #else
00370         std::vector<Eigen::Vector2f> texture_map_tmp;
00371 #endif
00372   for (size_t i = 0; i < tex_mesh.tex_polygons[cams.size ()].size (); ++i)
00373     for (size_t j = 0; j < tex_mesh.tex_polygons[cams.size ()][i].vertices.size (); ++j)
00374     {
00375       Eigen::Vector2f tmp_VT;
00376       tmp_VT[0] = -1;
00377       tmp_VT[1] = -1;
00378       texture_map_tmp.push_back (tmp_VT);
00379     }
00380 
00381   tex_mesh.tex_coordinates.push_back (texture_map_tmp);
00382 
00383   // push on an extra dummy material for the same reason
00384   std::stringstream tex_name;
00385   tex_name << "material_" << cams.size ();
00386   tex_name >> tex_material_.tex_name;
00387   tex_material_.tex_file = "occluded.jpg";
00388   tex_mesh.tex_materials.push_back (tex_material_);
00389 
00390 }
00391 
00393 template<typename PointInT> bool
00394 pcl::TextureMapping<PointInT>::isPointOccluded (const PointInT &pt, OctreePtr octree)
00395 {
00396   Eigen::Vector3f direction;
00397   direction (0) = pt.x;
00398   direction (1) = pt.y;
00399   direction (2) = pt.z;
00400 
00401   std::vector<int> indices;
00402 
00403   PointCloudConstPtr cloud (new PointCloud());
00404   cloud = octree->getInputCloud();
00405 
00406   double distance_threshold = octree->getResolution();
00407 
00408   // raytrace
00409   octree->getIntersectedVoxelIndices(direction, -direction, indices);
00410 
00411   int nbocc = static_cast<int> (indices.size ());
00412   for (size_t j = 0; j < indices.size (); j++)
00413   {
00414    // if intersected point is on the over side of the camera
00415    if (pt.z * cloud->points[indices[j]].z < 0)
00416    {
00417      nbocc--;
00418      continue;
00419    }
00420 
00421    if (fabs (cloud->points[indices[j]].z - pt.z) <= distance_threshold)
00422    {
00423      // points are very close to each-other, we do not consider the occlusion
00424      nbocc--;
00425    }
00426   }
00427 
00428   if (nbocc == 0)
00429    return (false);
00430   else
00431    return (true);
00432 }
00433 
00435 template<typename PointInT> void
00436 pcl::TextureMapping<PointInT>::removeOccludedPoints (const PointCloudPtr &input_cloud,
00437                                                      PointCloudPtr &filtered_cloud,
00438                                                      const double octree_voxel_size, std::vector<int> &visible_indices,
00439                                                      std::vector<int> &occluded_indices)
00440 {
00441   // variable used to filter occluded points by depth
00442   double maxDeltaZ = octree_voxel_size;
00443 
00444   // create an octree to perform rayTracing
00445   OctreePtr octree (new Octree (octree_voxel_size));
00446   // create octree structure
00447   octree->setInputCloud (input_cloud);
00448   // update bounding box automatically
00449   octree->defineBoundingBox ();
00450   // add points in the tree
00451   octree->addPointsFromInputCloud ();
00452 
00453   visible_indices.clear ();
00454 
00455   // for each point of the cloud, raycast toward camera and check intersected voxels.
00456   Eigen::Vector3f direction;
00457   std::vector<int> indices;
00458   for (size_t i = 0; i < input_cloud->points.size (); ++i)
00459   {
00460     direction (0) = input_cloud->points[i].x;
00461     direction (1) = input_cloud->points[i].y;
00462     direction (2) = input_cloud->points[i].z;
00463 
00464     // if point is not occluded
00465     octree->getIntersectedVoxelIndices (direction, -direction, indices);
00466 
00467     int nbocc = static_cast<int> (indices.size ());
00468     for (size_t j = 0; j < indices.size (); j++)
00469     {
00470       // if intersected point is on the over side of the camera
00471       if (input_cloud->points[i].z * input_cloud->points[indices[j]].z < 0)
00472       {
00473         nbocc--;
00474         continue;
00475       }
00476 
00477       if (fabs (input_cloud->points[indices[j]].z - input_cloud->points[i].z) <= maxDeltaZ)
00478       {
00479         // points are very close to each-other, we do not consider the occlusion
00480         nbocc--;
00481       }
00482     }
00483 
00484     if (nbocc == 0)
00485     {
00486       // point is added in the filtered mesh
00487       filtered_cloud->points.push_back (input_cloud->points[i]);
00488       visible_indices.push_back (static_cast<int> (i));
00489     }
00490     else
00491     {
00492       occluded_indices.push_back (static_cast<int> (i));
00493     }
00494   }
00495 
00496 }
00497 
00499 template<typename PointInT> void
00500 pcl::TextureMapping<PointInT>::removeOccludedPoints (const pcl::TextureMesh &tex_mesh, pcl::TextureMesh &cleaned_mesh, const double octree_voxel_size)
00501 {
00502   // copy mesh
00503   cleaned_mesh = tex_mesh;
00504 
00505   typename pcl::PointCloud<PointInT>::Ptr cloud (new pcl::PointCloud<PointInT>);
00506   typename pcl::PointCloud<PointInT>::Ptr filtered_cloud (new pcl::PointCloud<PointInT>);
00507 
00508   // load points into a PCL format
00509   pcl::fromPCLPointCloud2 (tex_mesh.cloud, *cloud);
00510 
00511   std::vector<int> visible, occluded;
00512   removeOccludedPoints (cloud, filtered_cloud, octree_voxel_size, visible, occluded);
00513 
00514   // Now that we know which points are visible, let's iterate over each face.
00515   // if the face has one invisible point => out!
00516   for (size_t polygons = 0; polygons < cleaned_mesh.tex_polygons.size (); ++polygons)
00517   {
00518     // remove all faces from cleaned mesh
00519     cleaned_mesh.tex_polygons[polygons].clear ();
00520     // iterate over faces
00521     for (size_t faces = 0; faces < tex_mesh.tex_polygons[polygons].size (); ++faces)
00522     {
00523       // check if all the face's points are visible
00524       bool faceIsVisible = true;
00525       std::vector<int>::iterator it;
00526 
00527       // iterate over face's vertex
00528       for (size_t points = 0; points < tex_mesh.tex_polygons[polygons][faces].vertices.size (); ++points)
00529       {
00530         it = find (occluded.begin (), occluded.end (), tex_mesh.tex_polygons[polygons][faces].vertices[points]);
00531 
00532         if (it == occluded.end ())
00533         {
00534           // point is not in the occluded vector
00535           // PCL_INFO ("  VISIBLE!\n");
00536         }
00537         else
00538         {
00539           // point was occluded
00540           // PCL_INFO("  OCCLUDED!\n");
00541           faceIsVisible = false;
00542         }
00543       }
00544 
00545       if (faceIsVisible)
00546       {
00547         cleaned_mesh.tex_polygons[polygons].push_back (tex_mesh.tex_polygons[polygons][faces]);
00548       }
00549 
00550     }
00551   }
00552 }
00553 
00555 template<typename PointInT> void
00556 pcl::TextureMapping<PointInT>::removeOccludedPoints (const pcl::TextureMesh &tex_mesh, PointCloudPtr &filtered_cloud,
00557                       const double octree_voxel_size)
00558 {
00559   PointCloudPtr cloud (new PointCloud);
00560 
00561   // load points into a PCL format
00562   pcl::fromPCLPointCloud2 (tex_mesh.cloud, *cloud);
00563 
00564   std::vector<int> visible, occluded;
00565   removeOccludedPoints (cloud, filtered_cloud, octree_voxel_size, visible, occluded);
00566 
00567 }
00568 
00570 template<typename PointInT> int
00571 pcl::TextureMapping<PointInT>::sortFacesByCamera (pcl::TextureMesh &tex_mesh, pcl::TextureMesh &sorted_mesh,
00572                                                   const pcl::texture_mapping::CameraVector &cameras, const double octree_voxel_size,
00573                                                   PointCloud &visible_pts)
00574 {
00575   if (tex_mesh.tex_polygons.size () != 1)
00576   {
00577     PCL_ERROR ("The mesh must contain only 1 sub-mesh!\n");
00578     return (-1);
00579   }
00580 
00581   if (cameras.size () == 0)
00582   {
00583     PCL_ERROR ("Must provide at least one camera info!\n");
00584     return (-1);
00585   }
00586 
00587   // copy mesh
00588   sorted_mesh = tex_mesh;
00589   // clear polygons from cleaned_mesh
00590   sorted_mesh.tex_polygons.clear ();
00591 
00592   typename pcl::PointCloud<PointInT>::Ptr original_cloud (new pcl::PointCloud<PointInT>);
00593   typename pcl::PointCloud<PointInT>::Ptr transformed_cloud (new pcl::PointCloud<PointInT>);
00594   typename pcl::PointCloud<PointInT>::Ptr filtered_cloud (new pcl::PointCloud<PointInT>);
00595 
00596   // load points into a PCL format
00597   pcl::fromPCLPointCloud2 (tex_mesh.cloud, *original_cloud);
00598 
00599   // for each camera
00600   for (size_t cam = 0; cam < cameras.size (); ++cam)
00601   {
00602     // get camera pose as transform
00603     Eigen::Affine3f cam_trans = cameras[cam].pose;
00604 
00605     // transform original cloud in camera coordinates
00606     pcl::transformPointCloud (*original_cloud, *transformed_cloud, cam_trans.inverse ());
00607 
00608     // find occlusions on transformed cloud
00609     std::vector<int> visible, occluded;
00610     removeOccludedPoints (transformed_cloud, filtered_cloud, octree_voxel_size, visible, occluded);
00611     visible_pts = *filtered_cloud;
00612 
00613     // find visible faces => add them to polygon N for camera N
00614     // add polygon group for current camera in clean
00615     std::vector<pcl::Vertices> visibleFaces_currentCam;
00616     // iterate over the faces of the current mesh
00617     for (size_t faces = 0; faces < tex_mesh.tex_polygons[0].size (); ++faces)
00618     {
00619       // check if all the face's points are visible
00620       bool faceIsVisible = true;
00621       std::vector<int>::iterator it;
00622 
00623       // iterate over face's vertex
00624       for (size_t current_pt_indice = 0; faceIsVisible && current_pt_indice < tex_mesh.tex_polygons[0][faces].vertices.size (); ++current_pt_indice)
00625       {
00626         // TODO this is far too long! Better create an helper function that raycasts here.
00627         it = find (occluded.begin (), occluded.end (), tex_mesh.tex_polygons[0][faces].vertices[current_pt_indice]);
00628 
00629         if (it == occluded.end ())
00630         {
00631           // point is not occluded
00632           // does it land on the camera's image plane?
00633           PointInT pt = transformed_cloud->points[tex_mesh.tex_polygons[0][faces].vertices[current_pt_indice]];
00634           Eigen::Vector2f dummy_UV;
00635           if (!getPointUVCoordinates (pt, cameras[cam], dummy_UV))
00636           {
00637             // point is not visible by the camera
00638             faceIsVisible = false;
00639           }
00640         }
00641         else
00642         {
00643           faceIsVisible = false;
00644         }
00645       }
00646 
00647       if (faceIsVisible)
00648       {
00649         // push current visible face into the sorted mesh
00650         visibleFaces_currentCam.push_back (tex_mesh.tex_polygons[0][faces]);
00651         // remove it from the unsorted mesh
00652         tex_mesh.tex_polygons[0].erase (tex_mesh.tex_polygons[0].begin () + faces);
00653         faces--;
00654       }
00655 
00656     }
00657     sorted_mesh.tex_polygons.push_back (visibleFaces_currentCam);
00658   }
00659 
00660   // we should only have occluded and non-visible faces left in tex_mesh.tex_polygons[0]
00661   // we need to add them as an extra polygon in the sorted mesh
00662   sorted_mesh.tex_polygons.push_back (tex_mesh.tex_polygons[0]);
00663   return (0);
00664 }
00665 
00667 template<typename PointInT> void
00668 pcl::TextureMapping<PointInT>::showOcclusions (const PointCloudPtr &input_cloud,
00669                                                pcl::PointCloud<pcl::PointXYZI>::Ptr &colored_cloud,
00670                                                const double octree_voxel_size, const bool show_nb_occlusions,
00671                                                const int max_occlusions)
00672                                                {
00673   // variable used to filter occluded points by depth
00674   double maxDeltaZ = octree_voxel_size * 2.0;
00675 
00676   // create an octree to perform rayTracing
00677   pcl::octree::OctreePointCloudSearch<PointInT> *octree;
00678   octree = new pcl::octree::OctreePointCloudSearch<PointInT> (octree_voxel_size);
00679   // create octree structure
00680   octree->setInputCloud (input_cloud);
00681   // update bounding box automatically
00682   octree->defineBoundingBox ();
00683   // add points in the tree
00684   octree->addPointsFromInputCloud ();
00685 
00686   // ray direction
00687   Eigen::Vector3f direction;
00688 
00689   std::vector<int> indices;
00690   // point from where we ray-trace
00691   pcl::PointXYZI pt;
00692 
00693   std::vector<double> zDist;
00694   std::vector<double> ptDist;
00695   // for each point of the cloud, ray-trace toward the camera and check intersected voxels.
00696   for (size_t i = 0; i < input_cloud->points.size (); ++i)
00697   {
00698     direction (0) = input_cloud->points[i].x;
00699     pt.x = input_cloud->points[i].x;
00700     direction (1) = input_cloud->points[i].y;
00701     pt.y = input_cloud->points[i].y;
00702     direction (2) = input_cloud->points[i].z;
00703     pt.z = input_cloud->points[i].z;
00704 
00705     // get number of occlusions for that point
00706     indices.clear ();
00707     int nbocc = octree->getIntersectedVoxelIndices (direction, -direction, indices);
00708 
00709     nbocc = static_cast<int> (indices.size ());
00710 
00711     // TODO need to clean this up and find tricks to get remove aliasaing effect on planes
00712     for (size_t j = 0; j < indices.size (); j++)
00713     {
00714       // if intersected point is on the over side of the camera
00715       if (pt.z * input_cloud->points[indices[j]].z < 0)
00716       {
00717         nbocc--;
00718       }
00719       else if (fabs (input_cloud->points[indices[j]].z - pt.z) <= maxDeltaZ)
00720       {
00721         // points are very close to each-other, we do not consider the occlusion
00722         nbocc--;
00723       }
00724       else
00725       {
00726         zDist.push_back (fabs (input_cloud->points[indices[j]].z - pt.z));
00727         ptDist.push_back (pcl::euclideanDistance (input_cloud->points[indices[j]], pt));
00728       }
00729     }
00730 
00731     if (show_nb_occlusions)
00732       (nbocc <= max_occlusions) ? (pt.intensity = static_cast<float> (nbocc)) : (pt.intensity = static_cast<float> (max_occlusions));
00733     else
00734       (nbocc == 0) ? (pt.intensity = 0) : (pt.intensity = 1);
00735 
00736     colored_cloud->points.push_back (pt);
00737   }
00738 
00739   if (zDist.size () >= 2)
00740   {
00741     std::sort (zDist.begin (), zDist.end ());
00742     std::sort (ptDist.begin (), ptDist.end ());
00743   }
00744 }
00745 
00747 template<typename PointInT> void
00748 pcl::TextureMapping<PointInT>::showOcclusions (pcl::TextureMesh &tex_mesh, pcl::PointCloud<pcl::PointXYZI>::Ptr &colored_cloud,
00749                   double octree_voxel_size, bool show_nb_occlusions, int max_occlusions)
00750 {
00751   // load points into a PCL format
00752   typename pcl::PointCloud<PointInT>::Ptr cloud (new pcl::PointCloud<PointInT>);
00753   pcl::fromPCLPointCloud2 (tex_mesh.cloud, *cloud);
00754 
00755   showOcclusions (cloud, colored_cloud, octree_voxel_size, show_nb_occlusions, max_occlusions);
00756 }
00757 
00759 template<typename PointInT> void
00760 pcl::TextureMapping<PointInT>::textureMeshwithMultipleCameras (pcl::TextureMesh &mesh, const pcl::texture_mapping::CameraVector &cameras)
00761 {
00762 
00763   if (mesh.tex_polygons.size () != 1)
00764     return;
00765 
00766   typename pcl::PointCloud<PointInT>::Ptr mesh_cloud (new pcl::PointCloud<PointInT>);
00767 
00768   pcl::fromPCLPointCloud2 (mesh.cloud, *mesh_cloud);
00769 
00770   std::vector<pcl::Vertices> faces;
00771 
00772   for (int current_cam = 0; current_cam < static_cast<int> (cameras.size ()); ++current_cam)
00773   {
00774     PCL_INFO ("Processing camera %d of %d.\n", current_cam+1, cameras.size ());
00775     
00776     // transform mesh into camera's frame
00777     typename pcl::PointCloud<PointInT>::Ptr camera_cloud (new pcl::PointCloud<PointInT>);
00778     pcl::transformPointCloud (*mesh_cloud, *camera_cloud, cameras[current_cam].pose.inverse ());
00779 
00780     // CREATE UV MAP FOR CURRENT FACES
00781     pcl::PointCloud<pcl::PointXY>::Ptr projections (new pcl::PointCloud<pcl::PointXY>);
00782     std::vector<pcl::Vertices>::iterator current_face;
00783     std::vector<bool> visibility;
00784     visibility.resize (mesh.tex_polygons[current_cam].size ());
00785     std::vector<UvIndex> indexes_uv_to_points;
00786     // for each current face
00787 
00788     //TODO change this
00789     pcl::PointXY nan_point;
00790     nan_point.x = std::numeric_limits<float>::quiet_NaN ();
00791     nan_point.y = std::numeric_limits<float>::quiet_NaN ();
00792     UvIndex u_null;
00793     u_null.idx_cloud = -1;
00794     u_null.idx_face = -1;
00795 
00796     int cpt_invisible=0;
00797     for (int idx_face = 0; idx_face <  static_cast<int> (mesh.tex_polygons[current_cam].size ()); ++idx_face)
00798     {
00799       //project each vertice, if one is out of view, stop
00800       pcl::PointXY uv_coord1;
00801       pcl::PointXY uv_coord2;
00802       pcl::PointXY uv_coord3;
00803 
00804       if (isFaceProjected (cameras[current_cam],
00805                            camera_cloud->points[mesh.tex_polygons[current_cam][idx_face].vertices[0]],
00806                            camera_cloud->points[mesh.tex_polygons[current_cam][idx_face].vertices[1]],
00807                            camera_cloud->points[mesh.tex_polygons[current_cam][idx_face].vertices[2]],
00808                            uv_coord1,
00809                            uv_coord2,
00810                            uv_coord3))
00811        {
00812         // face is in the camera's FOV
00813 
00814         // add UV coordinates
00815         projections->points.push_back (uv_coord1);
00816         projections->points.push_back (uv_coord2);
00817         projections->points.push_back (uv_coord3);
00818 
00819         // remember corresponding face
00820         UvIndex u1, u2, u3;
00821         u1.idx_cloud = mesh.tex_polygons[current_cam][idx_face].vertices[0];
00822         u2.idx_cloud = mesh.tex_polygons[current_cam][idx_face].vertices[1];
00823         u3.idx_cloud = mesh.tex_polygons[current_cam][idx_face].vertices[2];
00824         u1.idx_face = idx_face; u2.idx_face = idx_face; u3.idx_face = idx_face;
00825         indexes_uv_to_points.push_back (u1);
00826         indexes_uv_to_points.push_back (u2);
00827         indexes_uv_to_points.push_back (u3);
00828 
00829         //keep track of visibility
00830         visibility[idx_face] = true;
00831       }
00832       else
00833       {
00834         projections->points.push_back (nan_point);
00835         projections->points.push_back (nan_point);
00836         projections->points.push_back (nan_point);
00837         indexes_uv_to_points.push_back (u_null);
00838         indexes_uv_to_points.push_back (u_null);
00839         indexes_uv_to_points.push_back (u_null);
00840         //keep track of visibility
00841         visibility[idx_face] = false;
00842         cpt_invisible++;
00843       }
00844     }
00845 
00846     // projections contains all UV points of the current faces
00847     // indexes_uv_to_points links a uv point to its point in the camera cloud
00848     // visibility contains tells if a face was in the camera FOV (false = skip)
00849 
00850     // TODO handle case were no face could be projected
00851     if (visibility.size () - cpt_invisible !=0)
00852     {
00853         //create kdtree
00854         pcl::KdTreeFLANN<pcl::PointXY> kdtree;
00855         kdtree.setInputCloud (projections);
00856 
00857         std::vector<int> idxNeighbors;
00858         std::vector<float> neighborsSquaredDistance;
00859         // af first (idx_pcan < current_cam), check if some of the faces attached to previous cameras occlude the current faces
00860         // then (idx_pcam == current_cam), check for self occlusions. At this stage, we skip faces that were already marked as occluded
00861         cpt_invisible = 0;
00862         for (int idx_pcam = 0 ; idx_pcam <= current_cam ; ++idx_pcam)
00863         {
00864           // project all faces
00865           for (int idx_face = 0; idx_face <  static_cast<int> (mesh.tex_polygons[idx_pcam].size ()); ++idx_face)
00866           {
00867 
00868             if (idx_pcam == current_cam && !visibility[idx_face])
00869             {
00870               // we are now checking for self occlusions within the current faces
00871               // the current face was already declared as occluded.
00872               // therefore, it cannot occlude another face anymore => we skip it
00873               continue;
00874             }
00875 
00876             // project each vertice, if one is out of view, stop
00877             pcl::PointXY uv_coord1;
00878             pcl::PointXY uv_coord2;
00879             pcl::PointXY uv_coord3;
00880 
00881             if (isFaceProjected (cameras[current_cam],
00882                                  camera_cloud->points[mesh.tex_polygons[idx_pcam][idx_face].vertices[0]],
00883                                  camera_cloud->points[mesh.tex_polygons[idx_pcam][idx_face].vertices[1]],
00884                                  camera_cloud->points[mesh.tex_polygons[idx_pcam][idx_face].vertices[2]],
00885                                  uv_coord1,
00886                                  uv_coord2,
00887                                  uv_coord3))
00888              {
00889               // face is in the camera's FOV
00890               //get its circumsribed circle
00891               double radius;
00892               pcl::PointXY center;
00893               // getTriangleCircumcenterAndSize (uv_coord1, uv_coord2, uv_coord3, center, radius);
00894               getTriangleCircumcscribedCircleCentroid(uv_coord1, uv_coord2, uv_coord3, center, radius); // this function yields faster results than getTriangleCircumcenterAndSize
00895 
00896               // get points inside circ.circle
00897               if (kdtree.radiusSearch (center, radius, idxNeighbors, neighborsSquaredDistance) > 0 )
00898               {
00899                 // for each neighbor
00900                 for (size_t i = 0; i < idxNeighbors.size (); ++i)
00901                 {
00902                   if (std::max (camera_cloud->points[mesh.tex_polygons[idx_pcam][idx_face].vertices[0]].z,
00903                                 std::max (camera_cloud->points[mesh.tex_polygons[idx_pcam][idx_face].vertices[1]].z, 
00904                                           camera_cloud->points[mesh.tex_polygons[idx_pcam][idx_face].vertices[2]].z))
00905                      < camera_cloud->points[indexes_uv_to_points[idxNeighbors[i]].idx_cloud].z)
00906                   {
00907                     // neighbor is farther than all the face's points. Check if it falls into the triangle
00908                     if (checkPointInsideTriangle(uv_coord1, uv_coord2, uv_coord3, projections->points[idxNeighbors[i]]))
00909                     {
00910                       // current neighbor is inside triangle and is closer => the corresponding face
00911                       visibility[indexes_uv_to_points[idxNeighbors[i]].idx_face] = false;
00912                       cpt_invisible++;
00913                       //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
00914                     }
00915                   }
00916                 }
00917               }
00918              }
00919           }
00920         }
00921     }
00922 
00923     // now, visibility is true for each face that belongs to the current camera
00924     // if a face is not visible, we push it into the next one.
00925 
00926     if (static_cast<int> (mesh.tex_coordinates.size ()) <= current_cam)
00927     {
00928 #if PCL_VERSION_COMPARE(>=, 1, 8, 0)
00929         std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > dummy_container;
00930 #else
00931         std::vector<Eigen::Vector2f> dummy_container;
00932 #endif
00933       mesh.tex_coordinates.push_back (dummy_container);
00934     }
00935     mesh.tex_coordinates[current_cam].resize (3 * visibility.size ());
00936 
00937     std::vector<pcl::Vertices> occluded_faces;
00938     occluded_faces.resize (visibility.size ());
00939     std::vector<pcl::Vertices> visible_faces;
00940     visible_faces.resize (visibility.size ());
00941 
00942     int cpt_occluded_faces = 0;
00943     int cpt_visible_faces = 0;
00944 
00945     for (size_t idx_face = 0 ; idx_face < visibility.size () ; ++idx_face)
00946     {
00947       if (visibility[idx_face])
00948       {
00949         // face is visible by the current camera copy UV coordinates
00950         mesh.tex_coordinates[current_cam][cpt_visible_faces * 3](0) = projections->points[idx_face*3].x;
00951         mesh.tex_coordinates[current_cam][cpt_visible_faces * 3](1) = projections->points[idx_face*3].y;
00952 
00953         mesh.tex_coordinates[current_cam][cpt_visible_faces * 3 + 1](0) = projections->points[idx_face*3 + 1].x;
00954         mesh.tex_coordinates[current_cam][cpt_visible_faces * 3 + 1](1) = projections->points[idx_face*3 + 1].y;
00955 
00956         mesh.tex_coordinates[current_cam][cpt_visible_faces * 3 + 2](0) = projections->points[idx_face*3 + 2].x;
00957         mesh.tex_coordinates[current_cam][cpt_visible_faces * 3 + 2](1) = projections->points[idx_face*3 + 2].y;
00958 
00959         visible_faces[cpt_visible_faces] = mesh.tex_polygons[current_cam][idx_face];
00960 
00961         cpt_visible_faces++;
00962       }
00963       else
00964       {
00965         // face is occluded copy face into temp vector
00966         occluded_faces[cpt_occluded_faces] = mesh.tex_polygons[current_cam][idx_face];
00967         cpt_occluded_faces++;
00968       }
00969     }
00970     mesh.tex_coordinates[current_cam].resize (cpt_visible_faces*3);
00971 
00972     occluded_faces.resize (cpt_occluded_faces);
00973     mesh.tex_polygons.push_back (occluded_faces);
00974 
00975     visible_faces.resize (cpt_visible_faces);
00976     mesh.tex_polygons[current_cam].clear ();
00977     mesh.tex_polygons[current_cam] = visible_faces;
00978 
00979     int nb_faces = 0;
00980     for (int i = 0; i < static_cast<int> (mesh.tex_polygons.size ()); i++)
00981       nb_faces += static_cast<int> (mesh.tex_polygons[i].size ());
00982   }
00983 
00984   // we have been through all the cameras.
00985   // if any faces are left, they were not visible by any camera
00986   // we still need to produce uv coordinates for them
00987 
00988   if (mesh.tex_coordinates.size() <= cameras.size ())
00989   {
00990 #if PCL_VERSION_COMPARE(>=, 1, 8, 0)
00991         std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > dummy_container;
00992 #else
00993         std::vector<Eigen::Vector2f> dummy_container;
00994 #endif
00995    mesh.tex_coordinates.push_back(dummy_container);
00996    }
00997 
00998 
00999   for(size_t idx_face = 0 ; idx_face < mesh.tex_polygons[cameras.size()].size() ; ++idx_face)
01000   {
01001     Eigen::Vector2f UV1, UV2, UV3;
01002     UV1(0) = -1.0; UV1(1) = -1.0;
01003     UV2(0) = -1.0; UV2(1) = -1.0;
01004     UV3(0) = -1.0; UV3(1) = -1.0;
01005     mesh.tex_coordinates[cameras.size()].push_back(UV1);
01006     mesh.tex_coordinates[cameras.size()].push_back(UV2);
01007     mesh.tex_coordinates[cameras.size()].push_back(UV3);
01008   }
01009 
01010 }
01011 
01012 class FaceInfo
01013 {
01014 public:
01015         FaceInfo(float d,
01016                         float a,
01017                         float edge,
01018                         bool facingCam,
01019                         const pcl::PointXY & uv1,
01020                         const pcl::PointXY & uv2,
01021                         const pcl::PointXY & uv3,
01022                         const pcl::PointXY & center) :
01023                                 distance(d),
01024                                 angle(a),
01025                                 longestEdgeSqrd(edge),
01026                                 facingTheCam(facingCam),
01027                                 uv_coord1(uv1),
01028                                 uv_coord2(uv2),
01029                                 uv_coord3(uv3),
01030                                 uv_center(center)
01031         {}
01032         float distance;
01033         float angle;
01034         float longestEdgeSqrd;
01035         bool facingTheCam;
01036         pcl::PointXY uv_coord1;
01037         pcl::PointXY uv_coord2;
01038         pcl::PointXY uv_coord3;
01039         pcl::PointXY uv_center;
01040 };
01041 
01042 bool ptInTriangle(const pcl::PointXY & p0, const pcl::PointXY & p1, const pcl::PointXY & p2, const pcl::PointXY & p) {
01043     float A = 1/2 * (-p1.y * p2.x + p0.y * (-p1.x + p2.x) + p0.x * (p1.y - p2.y) + p1.x * p2.y);
01044     float sign = A < 0 ? -1 : 1;
01045     float s = (p0.y * p2.x - p0.x * p2.y + (p2.y - p0.y) * p.x + (p0.x - p2.x) * p.y) * sign;
01046     float t = (p0.x * p1.y - p0.y * p1.x + (p0.y - p1.y) * p.x + (p1.x - p0.x) * p.y) * sign;
01047 
01048     return s > 0 && t > 0 && (s + t) < 2 * A * sign;
01049 }
01050 
01052 template<typename PointInT> bool
01053 pcl::TextureMapping<PointInT>::textureMeshwithMultipleCameras2 (
01054                 pcl::TextureMesh &mesh,
01055                 const pcl::texture_mapping::CameraVector &cameras,
01056                 const rtabmap::ProgressState * state,
01057                 std::vector<std::map<int, pcl::PointXY> > * vertexToPixels)
01058 {
01059 
01060         if (mesh.tex_polygons.size () != 1)
01061                 return false;
01062 
01063         typename pcl::PointCloud<PointInT>::Ptr mesh_cloud (new pcl::PointCloud<PointInT>);
01064 
01065         pcl::fromPCLPointCloud2 (mesh.cloud, *mesh_cloud);
01066 
01067         std::vector<pcl::Vertices> faces;
01068         faces.swap(mesh.tex_polygons[0]);
01069 
01070         mesh.tex_polygons.clear();
01071         mesh.tex_polygons.resize(cameras.size()+1);
01072         mesh.tex_coordinates.clear();
01073         mesh.tex_coordinates.resize(cameras.size()+1);
01074 
01075         // pre compute all cam inverse and visibility
01076         std::vector<std::map<int, FaceInfo > > visibleFaces(cameras.size());
01077         std::vector<Eigen::Affine3f> invCamTransform(cameras.size());
01078         std::vector<std::list<int> > faceCameras(faces.size());
01079         UINFO("Precompute visible faces per cam (%d faces, %d cams)", (int)faces.size(), (int)cameras.size());
01080         for (unsigned int current_cam = 0; current_cam < cameras.size(); ++current_cam)
01081         {
01082                 UDEBUG("Texture camera %d...", current_cam);
01083 
01084                 typename pcl::PointCloud<PointInT>::Ptr camera_cloud (new pcl::PointCloud<PointInT>);
01085                 pcl::transformPointCloud(*mesh_cloud, *camera_cloud, cameras[current_cam].pose.inverse());
01086 
01087                 std::vector<int> visibilityIndices;
01088                 visibilityIndices.resize (faces.size ());
01089                 pcl::PointCloud<pcl::PointXY>::Ptr projections (new pcl::PointCloud<pcl::PointXY>);
01090                 projections->resize(faces.size()*3);
01091                 std::map<float, int> sortedVisibleFaces;
01092                 int oi=0;
01093                 for(unsigned int idx_face=0; idx_face<faces.size(); ++idx_face)
01094                 {
01095                         pcl::Vertices & face = faces[idx_face];
01096 
01097                         int j=oi*3;
01098                         pcl::PointXY & uv_coords1 = projections->at(j);
01099                         pcl::PointXY & uv_coords2 = projections->at(j+1);
01100                         pcl::PointXY & uv_coords3 = projections->at(j+2);
01101                         PointInT & pt0 = camera_cloud->points[face.vertices[0]];
01102                         PointInT & pt1 = camera_cloud->points[face.vertices[1]];
01103                         PointInT & pt2 = camera_cloud->points[face.vertices[2]];
01104                         if (isFaceProjected (cameras[current_cam],
01105                                         pt0,
01106                                         pt1,
01107                                         pt2,
01108                                         uv_coords1,
01109                                         uv_coords2,
01110                                         uv_coords3))
01111                         {
01112                                 // check if the polygon is facing the camera, assuming counterclockwise normal
01113                                 Eigen::Vector3f v0(
01114                                                 uv_coords2.x - uv_coords1.x,
01115                                                 uv_coords2.y - uv_coords1.y,
01116                                                 0);
01117                                 Eigen::Vector3f v1(
01118                                                 uv_coords3.x - uv_coords1.x,
01119                                                 uv_coords3.y - uv_coords1.y,
01120                                                 0);
01121                                 Eigen::Vector3f normal = v0.cross(v1);
01122                                 float angle = normal.dot(Eigen::Vector3f(0.0f,0.0f,1.0f));
01123                                 bool facingTheCam = angle>0.0f;
01124                                 float distanceToCam = std::min(std::min(pt0.z, pt1.z), pt2.z);
01125                                 float angleToCam = 0.0f;
01126                                 Eigen::Vector3f e0 = Eigen::Vector3f(
01127                                                 pt1.x - pt0.x,
01128                                                 pt1.y - pt0.y,
01129                                                 pt1.z - pt0.z);
01130                                 Eigen::Vector3f e1 = Eigen::Vector3f(
01131                                                 pt2.x - pt0.x,
01132                                                 pt2.y - pt0.y,
01133                                                 pt2.z - pt0.z);
01134                                 Eigen::Vector3f e2 = Eigen::Vector3f(
01135                                                 pt2.x - pt1.x,
01136                                                 pt2.y - pt1.y,
01137                                                 pt2.z - pt1.z);
01138                                 if(facingTheCam && this->max_angle_)
01139                                 {
01140                                         Eigen::Vector3f normal3D;
01141                                         normal3D = e0.cross(e1);
01142                                         angleToCam = pcl::getAngle3D(Eigen::Vector4f(normal3D[0], normal3D[1], normal3D[2], 0.0f), Eigen::Vector4f(0.0f,0.0f,-1.0f,0.0f));
01143                                 }
01144 
01145                                 // longest edge
01146                                 float e0norm2 = e0[0]*e0[0] + e0[1]*e0[1] + e0[2]*e0[2];
01147                                 float e1norm2 = e1[0]*e1[0] + e1[1]*e1[1] + e1[2]*e1[2];
01148                                 float e2norm2 = e2[0]*e2[0] + e2[1]*e2[1] + e2[2]*e2[2];
01149                                 float longestEdgeSqrd = std::max(std::max(e0norm2, e1norm2), e2norm2);
01150 
01151                                 pcl::PointXY center;
01152                                 center.x = (uv_coords1.x+uv_coords2.x+uv_coords3.x)/3.0f;
01153                                 center.y = (uv_coords1.y+uv_coords2.y+uv_coords3.y)/3.0f;
01154                                 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)));
01155                                 sortedVisibleFaces.insert(std::make_pair(distanceToCam, idx_face));
01156                                 visibilityIndices[oi] = idx_face;
01157                                 ++oi;
01158                         }
01159                 }
01160                 visibilityIndices.resize(oi);
01161                 projections->resize(oi*3);
01162                 UASSERT(projections->size() == visibilityIndices.size()*3);
01163 
01164                 //filter occluded polygons
01165                 //create kdtree
01166                 pcl::KdTreeFLANN<pcl::PointXY> kdtree;
01167                 kdtree.setInputCloud (projections);
01168 
01169                 std::vector<int> idxNeighbors;
01170                 std::vector<float> neighborsSquaredDistance;
01171                 // af first (idx_pcan < current_cam), check if some of the faces attached to previous cameras occlude the current faces
01172                 // then (idx_pcam == current_cam), check for self occlusions. At this stage, we skip faces that were already marked as occluded
01173                 // project all faces
01174                 std::set<int> occludedFaces;
01175                 for (std::map<float, int>::iterator jter=sortedVisibleFaces.begin(); jter!=sortedVisibleFaces.end(); ++jter)
01176                 //for (unsigned int idx = 0; idx<visibilityIndices.size(); ++idx)
01177                 {
01178                         int idx_face = jter->second;
01179                         //int idx_face = visibilityIndices[idx];
01180                         std::map<int, FaceInfo>::iterator iter= visibleFaces[current_cam].find(idx_face);
01181                         UASSERT(iter != visibleFaces[current_cam].end());
01182 
01183                         FaceInfo & info = iter->second;
01184 
01185                         // face is in the camera's FOV
01186                         //get its circumsribed circle
01187                         double radius;
01188                         pcl::PointXY center;
01189                         // getTriangleCircumcenterAndSize (info.uv_coord1, info.uv_coord2, info.uv_coord3, center, radius);
01190                         getTriangleCircumcscribedCircleCentroid(info.uv_coord1, info.uv_coord2, info.uv_coord3, center, radius); // this function yields faster results than getTriangleCircumcenterAndSize
01191 
01192                         // get points inside circ.circle
01193                         if (kdtree.radiusSearch (center, radius, idxNeighbors, neighborsSquaredDistance) > 0 )
01194                         {
01195                                 // for each neighbor
01196                                 for (size_t i = 0; i < idxNeighbors.size (); ++i)
01197                                 {
01198                                         int neighborFaceIndex = idxNeighbors[i]/3;
01199                                         //std::map<int, FaceInfo>::iterator jter= visibleFaces[current_cam].find(visibilityIndices[neighborFaceIndex]);
01200                                         //if(jter != visibleFaces[current_cam].end())
01201                                         {
01202                                                 if (std::max(camera_cloud->points[faces[idx_face].vertices[0]].z,
01203                                                                         std::max (camera_cloud->points[faces[idx_face].vertices[1]].z,
01204                                                                                         camera_cloud->points[faces[idx_face].vertices[2]].z))
01205                                                         < camera_cloud->points[faces[visibilityIndices[neighborFaceIndex]].vertices[idxNeighbors[i]%3]].z)
01206                                                 //if (info.distance < jter->second.distance)
01207                                                 {
01208                                                         // neighbor is farther than all the face's points. Check if it falls into the triangle
01209                                                         if (checkPointInsideTriangle(info.uv_coord1, info.uv_coord2, info.uv_coord3, projections->at(idxNeighbors[i])))
01210                                                         {
01211                                                                 // current neighbor is inside triangle and is closer => the corresponding face
01212                                                                 occludedFaces.insert(visibilityIndices[neighborFaceIndex]);
01213                                                                 //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
01214                                                         }
01215                                                 }
01216                                         }
01217                                 }
01218                         }
01219                 }
01220 
01221                 // remove occluded faces
01222                 for(std::set<int>::iterator iter= occludedFaces.begin(); iter!=occludedFaces.end(); ++iter)
01223                 {
01224                         visibleFaces[current_cam].erase(*iter);
01225                 }
01226 
01227                 // filter clusters
01228                 int clusterFaces = 0;
01229 
01230                 std::vector<pcl::Vertices> polygons(visibleFaces[current_cam].size());
01231                 std::vector<int> polygon_to_face_index(visibleFaces[current_cam].size());
01232                 oi =0;
01233                 for(std::map<int, FaceInfo>::iterator iter=visibleFaces[current_cam].begin(); iter!=visibleFaces[current_cam].end(); ++iter)
01234                 {
01235                         polygons[oi].vertices.resize(3);
01236                         polygons[oi].vertices[0] = faces[iter->first].vertices[0];
01237                         polygons[oi].vertices[1] = faces[iter->first].vertices[1];
01238                         polygons[oi].vertices[2] = faces[iter->first].vertices[2];
01239                         polygon_to_face_index[oi] = iter->first;
01240                         ++oi;
01241                 }
01242 
01243                 std::vector<std::set<int> > neighbors;
01244                 std::vector<std::set<int> > vertexToPolygons;
01245                 rtabmap::util3d::createPolygonIndexes(polygons,
01246                                 (int)camera_cloud->size(),
01247                                 neighbors,
01248                                 vertexToPolygons);
01249                 std::list<std::list<int> > clusters = rtabmap::util3d::clusterPolygons(
01250                                 neighbors,
01251                                 min_cluster_size_);
01252                 std::set<int> polygonsKept;
01253                 for(std::list<std::list<int> >::iterator iter=clusters.begin(); iter!=clusters.end(); ++iter)
01254                 {
01255                         for(std::list<int>::iterator jter=iter->begin(); jter!=iter->end(); ++jter)
01256                         {
01257                                 polygonsKept.insert(polygon_to_face_index[*jter]);
01258                                 faceCameras[polygon_to_face_index[*jter]].push_back(current_cam);
01259                         }
01260                 }
01261 
01262                 for(std::map<int, FaceInfo>::iterator iter=visibleFaces[current_cam].begin(); iter!=visibleFaces[current_cam].end();)
01263                 {
01264                         if(polygonsKept.find(iter->first) == polygonsKept.end())
01265                         {
01266                                 visibleFaces[current_cam].erase(iter++);
01267                                 ++clusterFaces;
01268                         }
01269                         else
01270                         {
01271                                 ++iter;
01272                         }
01273                 }
01274 
01275                 std::string 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());
01276                 UINFO(msg.c_str());
01277                 if(state && !state->callback(msg))
01278                 {
01279                         //cancelled!
01280                         UWARN("Texturing cancelled!");
01281                         return false;
01282                 }
01283         }
01284 
01285         std::string msg = uFormat("Texturing %d polygons...", (int)faces.size());
01286         UINFO(msg.c_str());
01287         if(state && !state->callback(msg))
01288         {
01289                 //cancelled!
01290                 UWARN("Texturing cancelled!");
01291                 return false;
01292         }
01293         int textured = 0;
01294         if(vertexToPixels)
01295         {
01296                 *vertexToPixels = std::vector<std::map<int, pcl::PointXY> >(mesh_cloud->size());
01297         }
01298         for(unsigned int idx_face=0; idx_face<faces.size(); ++idx_face)
01299         {
01300                 if((idx_face+1)%10000 == 0)
01301                 {
01302                         UDEBUG("face %d/%d", idx_face+1, (int)faces.size());
01303                         if(state && !state->callback(uFormat("Textured %d/%d of %d polygons", textured, idx_face+1, (int)faces.size())))
01304                         {
01305                                 //cancelled!
01306                                 UWARN("Texturing cancelled!");
01307                                 return false;
01308                         }
01309                 }
01310                 pcl::Vertices & face = faces[idx_face];
01311 
01312                 int cameraIndex = -1;
01313                 float smallestWeight = std::numeric_limits<float>::max();
01314                 bool depthSet = false;
01315                 pcl::PointXY uv_coords[3];
01316                 for (std::list<int>::iterator camIter = faceCameras[idx_face].begin(); camIter!=faceCameras[idx_face].end(); ++camIter)
01317                 {
01318                         int current_cam = *camIter;
01319                         std::map<int, FaceInfo>::iterator iter = visibleFaces[current_cam].find(idx_face);
01320                         UASSERT(iter != visibleFaces[current_cam].end());
01321                         if (iter->second.facingTheCam && (max_angle_ <=0.0f || iter->second.angle <= max_angle_))
01322                         {
01323                                 float distanceToCam = iter->second.distance;
01324                                 float vx = (iter->second.uv_coord1.x+iter->second.uv_coord2.x+ iter->second.uv_coord3.x)/3.0f-0.5f;
01325                                 float vy = (iter->second.uv_coord1.y+iter->second.uv_coord2.y+ iter->second.uv_coord3.y)/3.0f-0.5f;
01326                                 float distanceToCenter = vx*vx+vy*vy;
01327 
01328                                 cv::Mat depth = cameras[current_cam].depth;
01329                                 bool currentDepthSet = false;
01330                                 float maxDepthError = max_depth_error_==0.0f?std::sqrt(iter->second.longestEdgeSqrd)*2.0f : max_depth_error_;
01331                                 if(!cameras[current_cam].depth.empty() && maxDepthError > 0.0f)
01332                                 {
01333                                         float d1 = depth.type() == CV_32FC1?
01334                                                         depth.at<float>((1.0f-iter->second.uv_coord1.y)*depth.rows, iter->second.uv_coord1.x*depth.cols):
01335                                                         float(depth.at<unsigned short>((1.0f-iter->second.uv_coord1.y)*depth.rows, iter->second.uv_coord1.x*depth.cols))/1000.0f;
01336                                         float d2 = depth.type() == CV_32FC1?
01337                                                         depth.at<float>((1.0f-iter->second.uv_coord2.y)*depth.rows, iter->second.uv_coord2.x*depth.cols):
01338                                                         float(depth.at<unsigned short>((1.0f-iter->second.uv_coord2.y)*depth.rows, iter->second.uv_coord2.x*depth.cols))/1000.0f;
01339                                         float d3 = depth.type() == CV_32FC1?
01340                                                         depth.at<float>((1.0f-iter->second.uv_coord3.y)*depth.rows, iter->second.uv_coord3.x*depth.cols):
01341                                                         float(depth.at<unsigned short>((1.0f-iter->second.uv_coord3.y)*depth.rows, iter->second.uv_coord3.x*depth.cols))/1000.0f;
01342                                         if(d1 <= 0.0f || !std::isfinite(d1) || d2 <= 0.0f || !std::isfinite(d2) || d3 <= 0.0f || !std::isfinite(d3))
01343                                         {
01344                                                 if(depthSet)
01345                                                 {
01346                                                         // ignore pixels with no depth
01347                                                         continue;
01348                                                 }
01349                                                 else if(d1 > 0.0f && std::isfinite(d1) && fabs(d1 - distanceToCam) > maxDepthError)
01350                                                 {
01351                                                         // ignore pixels with too much depth error
01352                                                         continue;
01353                                                 }
01354                                                 else if(d2 > 0.0f && std::isfinite(d2) && fabs(d2 - distanceToCam) > maxDepthError)
01355                                                 {
01356                                                         // ignore pixels with too much depth error
01357                                                         continue;
01358                                                 }
01359                                                 else if(d3 > 0.0f && std::isfinite(d3) && fabs(d3 - distanceToCam) > maxDepthError)
01360                                                 {
01361                                                         // ignore pixels with too much depth error
01362                                                         continue;
01363                                                 }
01364                                                 //else it could be a window for which no depth is available on any cameras
01365                                         }
01366                                         else
01367                                         {
01368                                                 if(fabs(d1 - distanceToCam) > maxDepthError ||
01369                                                         fabs(d2 - distanceToCam) > maxDepthError ||
01370                                                         fabs(d3 - distanceToCam) > maxDepthError)
01371                                                 {
01372                                                         // ignore pixels with too much depth error
01373                                                         continue;
01374                                                 }
01375                                                 currentDepthSet = true;
01376                                         }
01377                                 }
01378 
01379                                 if(vertexToPixels)
01380                                 {
01381                                         vertexToPixels->at(face.vertices[0]).insert(std::make_pair(current_cam, iter->second.uv_coord1));
01382                                         vertexToPixels->at(face.vertices[1]).insert(std::make_pair(current_cam, iter->second.uv_coord2));
01383                                         vertexToPixels->at(face.vertices[2]).insert(std::make_pair(current_cam, iter->second.uv_coord3));
01384                                 }
01385 
01386                                 //UDEBUG("Process polygon %d cam =%d distanceToCam=%f", idx_face, current_cam, distanceToCam);
01387 
01388                                 if(distanceToCenter <= smallestWeight || (!depthSet && currentDepthSet))
01389                                 {
01390                                         cameraIndex = current_cam;
01391                                         smallestWeight = distanceToCenter;
01392                                         uv_coords[0] = iter->second.uv_coord1;
01393                                         uv_coords[1] = iter->second.uv_coord2;
01394                                         uv_coords[2] = iter->second.uv_coord3;
01395                                         if(!depthSet && currentDepthSet)
01396                                         {
01397                                                 depthSet = true;
01398                                         }
01399                                 }
01400                         }
01401                 }
01402 
01403                 if(cameraIndex >= 0)
01404                 {
01405                         ++textured;
01406                         mesh.tex_polygons[cameraIndex].push_back(face);
01407                         mesh.tex_coordinates[cameraIndex].push_back(Eigen::Vector2f(uv_coords[0].x, uv_coords[0].y));
01408                         mesh.tex_coordinates[cameraIndex].push_back(Eigen::Vector2f(uv_coords[1].x, uv_coords[1].y));
01409                         mesh.tex_coordinates[cameraIndex].push_back(Eigen::Vector2f(uv_coords[2].x, uv_coords[2].y));
01410                 }
01411                 else
01412                 {
01413                         mesh.tex_polygons[cameras.size()].push_back(face);
01414                         mesh.tex_coordinates[cameras.size()].push_back(Eigen::Vector2f(-1.0,-1.0));
01415                         mesh.tex_coordinates[cameras.size()].push_back(Eigen::Vector2f(-1.0,-1.0));
01416                         mesh.tex_coordinates[cameras.size()].push_back(Eigen::Vector2f(-1.0,-1.0));
01417                 }
01418         }
01419         UINFO("Process %d polygons...done! (%d textured)", (int)faces.size(), textured);
01420 
01421         return true;
01422 }
01423 
01425 template<typename PointInT> inline void
01426 pcl::TextureMapping<PointInT>::getTriangleCircumcenterAndSize(const pcl::PointXY &p1, const pcl::PointXY &p2, const pcl::PointXY &p3, pcl::PointXY &circomcenter, double &radius)
01427 {
01428   // we simplify the problem by translating the triangle's origin to its first point
01429   pcl::PointXY ptB, ptC;
01430   ptB.x = p2.x - p1.x; ptB.y = p2.y - p1.y; // B'=B-A
01431   ptC.x = p3.x - p1.x; ptC.y = p3.y - p1.y; // C'=C-A
01432 
01433   double D = 2.0*(ptB.x*ptC.y - ptB.y*ptC.x); // D'=2(B'x*C'y - B'y*C'x)
01434 
01435   // Safety check to avoid division by zero
01436   if(D == 0)
01437   {
01438     circomcenter.x = p1.x;
01439     circomcenter.y = p1.y;
01440   }
01441   else
01442   {
01443     // compute squares once
01444     double bx2 = ptB.x * ptB.x; // B'x^2
01445     double by2 = ptB.y * ptB.y; // B'y^2
01446     double cx2 = ptC.x * ptC.x; // C'x^2
01447     double cy2 = ptC.y * ptC.y; // C'y^2
01448 
01449     // compute circomcenter's coordinates (translate back to original coordinates)
01450     circomcenter.x = static_cast<float> (p1.x + (ptC.y*(bx2 + by2) - ptB.y*(cx2 + cy2)) / D);
01451     circomcenter.y = static_cast<float> (p1.y + (ptB.x*(cx2 + cy2) - ptC.x*(bx2 + by2)) / D);
01452   }
01453 
01454   radius = 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));
01455 }
01456 
01458 template<typename PointInT> inline void
01459 pcl::TextureMapping<PointInT>::getTriangleCircumcscribedCircleCentroid ( const pcl::PointXY &p1, const pcl::PointXY &p2, const pcl::PointXY &p3, pcl::PointXY &circumcenter, double &radius)
01460 {
01461   // compute centroid's coordinates (translate back to original coordinates)
01462   circumcenter.x = static_cast<float> (p1.x + p2.x + p3.x ) / 3;
01463   circumcenter.y = static_cast<float> (p1.y + p2.y + p3.y ) / 3;
01464   double r1 = (circumcenter.x - p1.x) * (circumcenter.x - p1.x) + (circumcenter.y - p1.y) * (circumcenter.y - p1.y)  ;
01465   double r2 = (circumcenter.x - p2.x) * (circumcenter.x - p2.x) + (circumcenter.y - p2.y) * (circumcenter.y - p2.y)  ;
01466   double r3 = (circumcenter.x - p3.x) * (circumcenter.x - p3.x) + (circumcenter.y - p3.y) * (circumcenter.y - p3.y)  ;
01467 
01468   // radius
01469   radius = std::sqrt( std::max( r1, std::max( r2, r3) )) ;
01470 }
01471 
01472 
01474 template<typename PointInT> inline bool
01475 pcl::TextureMapping<PointInT>::getPointUVCoordinates(const PointInT &pt, const Camera &cam, pcl::PointXY &UV_coordinates)
01476 {
01477         if (pt.z > 0 && (max_distance_<=0.0f || pt.z<max_distance_))
01478         {
01479                 // compute image center and dimension
01480                 double sizeX = cam.width;
01481                 double sizeY = cam.height;
01482                 double cx, cy;
01483                 if (cam.center_w > 0)
01484                         cx = cam.center_w;
01485                 else
01486                         cx = sizeX / 2.0;
01487                 if (cam.center_h > 0)
01488                         cy = cam.center_h;
01489                 else
01490                         cy = sizeY / 2.0;
01491 
01492                 double focal_x, focal_y;
01493                 if (cam.focal_length_w > 0)
01494                         focal_x = cam.focal_length_w;
01495                 else
01496                         focal_x = cam.focal_length;
01497                 if (cam.focal_length_h > 0)
01498                         focal_y = cam.focal_length_h;
01499                 else
01500                         focal_y = cam.focal_length;
01501 
01502                 // project point on camera's image plane
01503                 UV_coordinates.x = static_cast<float> ((focal_x * (pt.x / pt.z) + cx) / sizeX); //horizontal
01504                 UV_coordinates.y = static_cast<float> ((focal_y * (pt.y / pt.z) + cy) / sizeY); //vertical
01505 
01506                 if(cam.roi.size() == 4)
01507                 {
01508                         if( UV_coordinates.x < cam.roi[0]/sizeX ||
01509                                 UV_coordinates.y < cam.roi[1]/sizeY ||
01510                                 UV_coordinates.x > (cam.roi[0]+cam.roi[2])/sizeX ||
01511                                 UV_coordinates.y > (cam.roi[1]+cam.roi[3])/sizeY)
01512                         {
01513                                 // point is NOT in region of interest of the camera
01514                                 UV_coordinates.x = -1.0f;
01515                                 UV_coordinates.y = -1.0f;
01516                                 return false;
01517                         }
01518                 }
01519 
01520                 // point is visible!
01521                 if (UV_coordinates.x >= 0.0 && UV_coordinates.x <= 1.0 && UV_coordinates.y >= 0.0 && UV_coordinates.y <= 1.0)
01522                 {
01523                         // point is visible by the camera
01524                         // original code of PCL inverted y
01525                         UV_coordinates.y = 1.0f - UV_coordinates.y;
01526                         return (true);
01527                 }
01528         }
01529 
01530         // point is NOT visible by the camera
01531         UV_coordinates.x = -1.0f;
01532         UV_coordinates.y = -1.0f;
01533         return (false); // point was not visible by the camera
01534 }
01535 
01537 template<typename PointInT> inline bool
01538 pcl::TextureMapping<PointInT>::checkPointInsideTriangle(const pcl::PointXY &p1, const pcl::PointXY &p2, const pcl::PointXY &p3, const pcl::PointXY &pt)
01539 {
01540    // Compute vectors
01541    Eigen::Vector2d v0, v1, v2;
01542    v0(0) = p3.x - p1.x; v0(1) = p3.y - p1.y; // v0= C - A
01543    v1(0) = p2.x - p1.x; v1(1) = p2.y - p1.y; // v1= B - A
01544    v2(0) = pt.x - p1.x; v2(1) = pt.y - p1.y; // v2= P - A
01545 
01546    // Compute dot products
01547    double dot00 = v0.dot(v0); // dot00 = dot(v0, v0)
01548    double dot01 = v0.dot(v1); // dot01 = dot(v0, v1)
01549    double dot02 = v0.dot(v2); // dot02 = dot(v0, v2)
01550    double dot11 = v1.dot(v1); // dot11 = dot(v1, v1)
01551    double dot12 = v1.dot(v2); // dot12 = dot(v1, v2)
01552 
01553    // Compute barycentric coordinates
01554    double invDenom = 1.0 / (dot00*dot11 - dot01*dot01);
01555    double u = (dot11*dot02 - dot01*dot12) * invDenom;
01556    double v = (dot00*dot12 - dot01*dot02) * invDenom;
01557 
01558    // Check if point is in triangle
01559    return ((u >= 0) && (v >= 0) && (u + v < 1));
01560 }
01561 
01563 template<typename PointInT> inline bool
01564 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)
01565 {
01566         return getPointUVCoordinates(p1, camera, proj1)
01567                         &&
01568                         getPointUVCoordinates(p2, camera, proj2)
01569                         &&
01570                         getPointUVCoordinates(p3, camera, proj3);
01571 }
01572 
01573 #define PCL_INSTANTIATE_TextureMapping(T)                \
01574     template class PCL_EXPORTS pcl::TextureMapping<T>;
01575 
01576 #endif /* TEXTURE_MAPPING_HPP_ */
01577 


rtabmap
Author(s): Mathieu Labbe
autogenerated on Thu Jun 6 2019 21:59:31