00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
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
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
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
00064 Eigen::Vector3f f_normal = p1p2.cross (p1p3);
00065 f_normal = f_normal / std::sqrt (f_normal.dot (f_normal));
00066
00067
00068 Eigen::Vector3f f_vector_field = vector_field_ - vector_field_.dot (f_normal) * f_normal;
00069
00070
00071 f_vector_field = f_vector_field / std::sqrt (f_vector_field.dot (f_vector_field));
00072
00073
00074 Eigen::Vector2f tp1, tp2, tp3;
00075
00076 double alpha = std::acos (f_vector_field.dot (p1p2));
00077
00078
00079 double e1 = (p2 - p3).norm () / f_;
00080 double e2 = (p1 - p3).norm () / f_;
00081 double e3 = (p1 - p2).norm () / f_;
00082
00083
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
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
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
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
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
00152 float x, y, z;
00153
00154 Eigen::Vector3f facet[3];
00155
00156
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
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
00169 for (size_t i = 0; i < tex_mesh.tex_polygons[m].size (); ++i)
00170 {
00171 size_t idx;
00172
00173
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
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 }
00190
00191
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
00199 tex_mesh.tex_coordinates.push_back (texture_map_tmp);
00200 }
00201 }
00202
00204 template<typename PointInT> void
00205 pcl::TextureMapping<PointInT>::mapTexture2MeshUV (pcl::TextureMesh &tex_mesh)
00206 {
00207
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
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
00225 if (x_ <= x_lowest)
00226 x_lowest = x_;
00227 if (x_ > x_lowest)
00228 x_highest = x_;
00229
00230
00231 if (y_ <= y_lowest)
00232 y_lowest = y_;
00233
00234
00235
00236 if (z_ <= z_lowest)
00237 z_lowest = z_;
00238 if (z_ > z_lowest)
00239 z_highest = z_;
00240 }
00241
00242 float x_range = (x_lowest - x_highest) * -1;
00243 float x_offset = 0 - x_lowest;
00244
00245
00246
00247
00248 float z_range = (z_lowest - z_highest) * -1;
00249 float z_offset = 0 - z_lowest;
00250
00251
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
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
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
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 }
00281
00282
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
00290 tex_mesh.tex_coordinates.push_back (texture_map_tmp);
00291 }
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
00312 pcl::fromPCLPointCloud2 (tex_mesh.cloud, *originalCloud);
00313
00314
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
00320 Camera current_cam = cams[m];
00321
00322
00323 Eigen::Affine3f cam_trans = current_cam.pose;
00324
00325
00326 pcl::transformPointCloud (*originalCloud, *camera_transformed_cloud, cam_trans.inverse ());
00327
00328
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
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
00342 for (size_t j = 0; j < tex_mesh.tex_polygons[m][i].vertices.size (); ++j)
00343 {
00344
00345 idx = tex_mesh.tex_polygons[m][i].vertices[j];
00346 pt = camera_transformed_cloud->points[idx];
00347
00348
00349 getPointUVCoordinates (pt, current_cam, tmp_VT);
00350 texture_map_tmp.push_back (tmp_VT);
00351
00352 }
00353 }
00354
00355
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
00363 tex_mesh.tex_coordinates.push_back (texture_map_tmp);
00364 }
00365
00366
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
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
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
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
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
00442 double maxDeltaZ = octree_voxel_size;
00443
00444
00445 OctreePtr octree (new Octree (octree_voxel_size));
00446
00447 octree->setInputCloud (input_cloud);
00448
00449 octree->defineBoundingBox ();
00450
00451 octree->addPointsFromInputCloud ();
00452
00453 visible_indices.clear ();
00454
00455
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
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
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
00480 nbocc--;
00481 }
00482 }
00483
00484 if (nbocc == 0)
00485 {
00486
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
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
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
00515
00516 for (size_t polygons = 0; polygons < cleaned_mesh.tex_polygons.size (); ++polygons)
00517 {
00518
00519 cleaned_mesh.tex_polygons[polygons].clear ();
00520
00521 for (size_t faces = 0; faces < tex_mesh.tex_polygons[polygons].size (); ++faces)
00522 {
00523
00524 bool faceIsVisible = true;
00525 std::vector<int>::iterator it;
00526
00527
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
00535
00536 }
00537 else
00538 {
00539
00540
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
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
00588 sorted_mesh = tex_mesh;
00589
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
00597 pcl::fromPCLPointCloud2 (tex_mesh.cloud, *original_cloud);
00598
00599
00600 for (size_t cam = 0; cam < cameras.size (); ++cam)
00601 {
00602
00603 Eigen::Affine3f cam_trans = cameras[cam].pose;
00604
00605
00606 pcl::transformPointCloud (*original_cloud, *transformed_cloud, cam_trans.inverse ());
00607
00608
00609 std::vector<int> visible, occluded;
00610 removeOccludedPoints (transformed_cloud, filtered_cloud, octree_voxel_size, visible, occluded);
00611 visible_pts = *filtered_cloud;
00612
00613
00614
00615 std::vector<pcl::Vertices> visibleFaces_currentCam;
00616
00617 for (size_t faces = 0; faces < tex_mesh.tex_polygons[0].size (); ++faces)
00618 {
00619
00620 bool faceIsVisible = true;
00621 std::vector<int>::iterator it;
00622
00623
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
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
00632
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
00638 faceIsVisible = false;
00639 }
00640 }
00641 else
00642 {
00643 faceIsVisible = false;
00644 }
00645 }
00646
00647 if (faceIsVisible)
00648 {
00649
00650 visibleFaces_currentCam.push_back (tex_mesh.tex_polygons[0][faces]);
00651
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
00661
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
00674 double maxDeltaZ = octree_voxel_size * 2.0;
00675
00676
00677 pcl::octree::OctreePointCloudSearch<PointInT> *octree;
00678 octree = new pcl::octree::OctreePointCloudSearch<PointInT> (octree_voxel_size);
00679
00680 octree->setInputCloud (input_cloud);
00681
00682 octree->defineBoundingBox ();
00683
00684 octree->addPointsFromInputCloud ();
00685
00686
00687 Eigen::Vector3f direction;
00688
00689 std::vector<int> indices;
00690
00691 pcl::PointXYZI pt;
00692
00693 std::vector<double> zDist;
00694 std::vector<double> ptDist;
00695
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
00706 indices.clear ();
00707 int nbocc = octree->getIntersectedVoxelIndices (direction, -direction, indices);
00708
00709 nbocc = static_cast<int> (indices.size ());
00710
00711
00712 for (size_t j = 0; j < indices.size (); j++)
00713 {
00714
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
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
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
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
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
00787
00788
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
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
00813
00814
00815 projections->points.push_back (uv_coord1);
00816 projections->points.push_back (uv_coord2);
00817 projections->points.push_back (uv_coord3);
00818
00819
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
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
00841 visibility[idx_face] = false;
00842 cpt_invisible++;
00843 }
00844 }
00845
00846
00847
00848
00849
00850
00851 if (visibility.size () - cpt_invisible !=0)
00852 {
00853
00854 pcl::KdTreeFLANN<pcl::PointXY> kdtree;
00855 kdtree.setInputCloud (projections);
00856
00857 std::vector<int> idxNeighbors;
00858 std::vector<float> neighborsSquaredDistance;
00859
00860
00861 cpt_invisible = 0;
00862 for (int idx_pcam = 0 ; idx_pcam <= current_cam ; ++idx_pcam)
00863 {
00864
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
00871
00872
00873 continue;
00874 }
00875
00876
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
00890
00891 double radius;
00892 pcl::PointXY center;
00893
00894 getTriangleCircumcscribedCircleCentroid(uv_coord1, uv_coord2, uv_coord3, center, radius);
00895
00896
00897 if (kdtree.radiusSearch (center, radius, idxNeighbors, neighborsSquaredDistance) > 0 )
00898 {
00899
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
00908 if (checkPointInsideTriangle(uv_coord1, uv_coord2, uv_coord3, projections->points[idxNeighbors[i]]))
00909 {
00910
00911 visibility[indexes_uv_to_points[idxNeighbors[i]].idx_face] = false;
00912 cpt_invisible++;
00913
00914 }
00915 }
00916 }
00917 }
00918 }
00919 }
00920 }
00921 }
00922
00923
00924
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
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
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
00985
00986
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
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
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
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
01165
01166 pcl::KdTreeFLANN<pcl::PointXY> kdtree;
01167 kdtree.setInputCloud (projections);
01168
01169 std::vector<int> idxNeighbors;
01170 std::vector<float> neighborsSquaredDistance;
01171
01172
01173
01174 std::set<int> occludedFaces;
01175 for (std::map<float, int>::iterator jter=sortedVisibleFaces.begin(); jter!=sortedVisibleFaces.end(); ++jter)
01176
01177 {
01178 int idx_face = jter->second;
01179
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
01186
01187 double radius;
01188 pcl::PointXY center;
01189
01190 getTriangleCircumcscribedCircleCentroid(info.uv_coord1, info.uv_coord2, info.uv_coord3, center, radius);
01191
01192
01193 if (kdtree.radiusSearch (center, radius, idxNeighbors, neighborsSquaredDistance) > 0 )
01194 {
01195
01196 for (size_t i = 0; i < idxNeighbors.size (); ++i)
01197 {
01198 int neighborFaceIndex = idxNeighbors[i]/3;
01199
01200
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
01207 {
01208
01209 if (checkPointInsideTriangle(info.uv_coord1, info.uv_coord2, info.uv_coord3, projections->at(idxNeighbors[i])))
01210 {
01211
01212 occludedFaces.insert(visibilityIndices[neighborFaceIndex]);
01213
01214 }
01215 }
01216 }
01217 }
01218 }
01219 }
01220
01221
01222 for(std::set<int>::iterator iter= occludedFaces.begin(); iter!=occludedFaces.end(); ++iter)
01223 {
01224 visibleFaces[current_cam].erase(*iter);
01225 }
01226
01227
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
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
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
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
01347 continue;
01348 }
01349 else if(d1 > 0.0f && std::isfinite(d1) && fabs(d1 - distanceToCam) > maxDepthError)
01350 {
01351
01352 continue;
01353 }
01354 else if(d2 > 0.0f && std::isfinite(d2) && fabs(d2 - distanceToCam) > maxDepthError)
01355 {
01356
01357 continue;
01358 }
01359 else if(d3 > 0.0f && std::isfinite(d3) && fabs(d3 - distanceToCam) > maxDepthError)
01360 {
01361
01362 continue;
01363 }
01364
01365 }
01366 else
01367 {
01368 if(fabs(d1 - distanceToCam) > maxDepthError ||
01369 fabs(d2 - distanceToCam) > maxDepthError ||
01370 fabs(d3 - distanceToCam) > maxDepthError)
01371 {
01372
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
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
01429 pcl::PointXY ptB, ptC;
01430 ptB.x = p2.x - p1.x; ptB.y = p2.y - p1.y;
01431 ptC.x = p3.x - p1.x; ptC.y = p3.y - p1.y;
01432
01433 double D = 2.0*(ptB.x*ptC.y - ptB.y*ptC.x);
01434
01435
01436 if(D == 0)
01437 {
01438 circomcenter.x = p1.x;
01439 circomcenter.y = p1.y;
01440 }
01441 else
01442 {
01443
01444 double bx2 = ptB.x * ptB.x;
01445 double by2 = ptB.y * ptB.y;
01446 double cx2 = ptC.x * ptC.x;
01447 double cy2 = ptC.y * ptC.y;
01448
01449
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));
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
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
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
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
01503 UV_coordinates.x = static_cast<float> ((focal_x * (pt.x / pt.z) + cx) / sizeX);
01504 UV_coordinates.y = static_cast<float> ((focal_y * (pt.y / pt.z) + cy) / sizeY);
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
01514 UV_coordinates.x = -1.0f;
01515 UV_coordinates.y = -1.0f;
01516 return false;
01517 }
01518 }
01519
01520
01521 if (UV_coordinates.x >= 0.0 && UV_coordinates.x <= 1.0 && UV_coordinates.y >= 0.0 && UV_coordinates.y <= 1.0)
01522 {
01523
01524
01525 UV_coordinates.y = 1.0f - UV_coordinates.y;
01526 return (true);
01527 }
01528 }
01529
01530
01531 UV_coordinates.x = -1.0f;
01532 UV_coordinates.y = -1.0f;
01533 return (false);
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
01541 Eigen::Vector2d v0, v1, v2;
01542 v0(0) = p3.x - p1.x; v0(1) = p3.y - p1.y;
01543 v1(0) = p2.x - p1.x; v1(1) = p2.y - p1.y;
01544 v2(0) = pt.x - p1.x; v2(1) = pt.y - p1.y;
01545
01546
01547 double dot00 = v0.dot(v0);
01548 double dot01 = v0.dot(v1);
01549 double dot02 = v0.dot(v2);
01550 double dot11 = v1.dot(v1);
01551 double dot12 = v1.dot(v2);
01552
01553
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
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
01577