00001
00040 #include <pcl/pcl_config.h>
00041 #ifdef HAVE_QHULL
00042
00043 #ifndef PCL_SURFACE_IMPL_CONCAVE_HULL_H_
00044 #define PCL_SURFACE_IMPL_CONCAVE_HULL_H_
00045
00046 #include <map>
00047 #include <pcl/surface/concave_hull.h>
00048 #include <pcl/common/common.h>
00049 #include <pcl/common/eigen.h>
00050 #include <pcl/common/centroid.h>
00051 #include <pcl/common/transforms.h>
00052 #include <pcl/kdtree/kdtree_flann.h>
00053 #include <pcl/common/io.h>
00054 #include <stdio.h>
00055 #include <stdlib.h>
00056 #include <pcl/surface/qhull.h>
00057
00059 template <typename PointInT> void
00060 pcl::ConcaveHull<PointInT>::reconstruct (PointCloud &output)
00061 {
00062 output.header = input_->header;
00063 if (alpha_ <= 0)
00064 {
00065 PCL_ERROR ("[pcl::%s::reconstruct] Alpha parameter must be set to a positive number!\n", getClassName ().c_str ());
00066 output.points.clear ();
00067 return;
00068 }
00069
00070 if (!initCompute ())
00071 {
00072 output.points.clear ();
00073 return;
00074 }
00075
00076
00077 std::vector<pcl::Vertices> polygons;
00078 performReconstruction (output, polygons);
00079
00080 output.width = static_cast<uint32_t> (output.points.size ());
00081 output.height = 1;
00082 output.is_dense = true;
00083
00084 deinitCompute ();
00085 }
00086
00088 template <typename PointInT> void
00089 pcl::ConcaveHull<PointInT>::reconstruct (PointCloud &output, std::vector<pcl::Vertices> &polygons)
00090 {
00091 output.header = input_->header;
00092 if (alpha_ <= 0)
00093 {
00094 PCL_ERROR ("[pcl::%s::reconstruct] Alpha parameter must be set to a positive number!\n", getClassName ().c_str ());
00095 output.points.clear ();
00096 return;
00097 }
00098
00099 if (!initCompute ())
00100 {
00101 output.points.clear ();
00102 return;
00103 }
00104
00105
00106 performReconstruction (output, polygons);
00107
00108 output.width = static_cast<uint32_t> (output.points.size ());
00109 output.height = 1;
00110 output.is_dense = true;
00111
00112 deinitCompute ();
00113 }
00114
00115 #ifdef __GNUC__
00116 #pragma GCC diagnostic ignored "-Wold-style-cast"
00117 #endif
00118
00119 template <typename PointInT> void
00120 pcl::ConcaveHull<PointInT>::performReconstruction (PointCloud &alpha_shape, std::vector<pcl::Vertices> &polygons)
00121 {
00122 EIGEN_ALIGN16 Eigen::Matrix3f covariance_matrix;
00123 Eigen::Vector4f xyz_centroid;
00124 computeMeanAndCovarianceMatrix (*input_, *indices_, covariance_matrix, xyz_centroid);
00125
00126
00127 for (int i = 0; i < 3; ++i)
00128 for (int j = 0; j < 3; ++j)
00129 if (!pcl_isfinite (covariance_matrix.coeffRef (i, j)))
00130 return;
00131
00132 EIGEN_ALIGN16 Eigen::Vector3f eigen_values;
00133 EIGEN_ALIGN16 Eigen::Matrix3f eigen_vectors;
00134 pcl::eigen33 (covariance_matrix, eigen_vectors, eigen_values);
00135
00136 Eigen::Affine3f transform1;
00137 transform1.setIdentity ();
00138
00139
00140 if (dim_ == 0)
00141 {
00142 PCL_WARN ("[pcl::%s] WARNING: Input dimension not specified. Automatically determining input dimension.\n", getClassName ().c_str ());
00143 if (eigen_values[0] / eigen_values[2] < 1.0e-3)
00144 dim_ = 2;
00145 else
00146 dim_ = 3;
00147 }
00148
00149 if (dim_ == 2)
00150 {
00151
00152
00153
00154 transform1 (2, 0) = eigen_vectors (0, 0);
00155 transform1 (2, 1) = eigen_vectors (1, 0);
00156 transform1 (2, 2) = eigen_vectors (2, 0);
00157
00158 transform1 (1, 0) = eigen_vectors (0, 1);
00159 transform1 (1, 1) = eigen_vectors (1, 1);
00160 transform1 (1, 2) = eigen_vectors (2, 1);
00161 transform1 (0, 0) = eigen_vectors (0, 2);
00162 transform1 (0, 1) = eigen_vectors (1, 2);
00163 transform1 (0, 2) = eigen_vectors (2, 2);
00164 }
00165 else
00166 {
00167 transform1.setIdentity ();
00168 }
00169
00170 PointCloud cloud_transformed;
00171 pcl::demeanPointCloud (*input_, *indices_, xyz_centroid, cloud_transformed);
00172 pcl::transformPointCloud (cloud_transformed, cloud_transformed, transform1);
00173
00174
00175 boolT ismalloc = True;
00176
00177 char flags[] = "qhull d QJ";
00178
00179 FILE *outfile = NULL;
00180
00181 FILE *errfile = stderr;
00182
00183 int exitcode;
00184
00185
00186 coordT *points = reinterpret_cast<coordT*> (calloc (cloud_transformed.points.size () * dim_, sizeof(coordT)));
00187
00188 for (size_t i = 0; i < cloud_transformed.points.size (); ++i)
00189 {
00190 points[i * dim_ + 0] = static_cast<coordT> (cloud_transformed.points[i].x);
00191 points[i * dim_ + 1] = static_cast<coordT> (cloud_transformed.points[i].y);
00192
00193 if (dim_ > 2)
00194 points[i * dim_ + 2] = static_cast<coordT> (cloud_transformed.points[i].z);
00195 }
00196
00197
00198 exitcode = qh_new_qhull (dim_, static_cast<int> (cloud_transformed.points.size ()), points, ismalloc, flags, outfile, errfile);
00199
00200 if (exitcode != 0)
00201 {
00202 PCL_ERROR ("[pcl::%s::performReconstrution] ERROR: qhull was unable to compute a concave hull for the given point cloud (%zu)!\n", getClassName ().c_str (), cloud_transformed.points.size ());
00203
00204
00205 if (!cloud_transformed.is_dense)
00206 {
00207 bool NaNvalues = false;
00208 for (size_t i = 0; i < cloud_transformed.size (); ++i)
00209 {
00210 if (!pcl_isfinite (cloud_transformed.points[i].x) ||
00211 !pcl_isfinite (cloud_transformed.points[i].y) ||
00212 !pcl_isfinite (cloud_transformed.points[i].z))
00213 {
00214 NaNvalues = true;
00215 break;
00216 }
00217 }
00218
00219 if (NaNvalues)
00220 PCL_ERROR ("[pcl::%s::performReconstruction] ERROR: point cloud contains NaN values, consider running pcl::PassThrough filter first to remove NaNs!\n", getClassName ().c_str ());
00221 }
00222
00223 alpha_shape.points.resize (0);
00224 alpha_shape.width = alpha_shape.height = 0;
00225 polygons.resize (0);
00226
00227 qh_freeqhull (!qh_ALL);
00228 int curlong, totlong;
00229 qh_memfreeshort (&curlong, &totlong);
00230
00231 return;
00232 }
00233
00234 qh_setvoronoi_all ();
00235
00236 int num_vertices = qh num_vertices;
00237 alpha_shape.points.resize (num_vertices);
00238
00239 vertexT *vertex;
00240
00241 int max_vertex_id = 0;
00242 FORALLvertices
00243 {
00244 if (vertex->id + 1 > max_vertex_id)
00245 max_vertex_id = vertex->id + 1;
00246 }
00247
00248 facetT *facet;
00249
00250 ++max_vertex_id;
00251 std::vector<int> qhid_to_pcidx (max_vertex_id);
00252
00253 int num_facets = qh num_facets;
00254 int dd = 0;
00255
00256 if (dim_ == 3)
00257 {
00258 setT *triangles_set = qh_settemp (4 * num_facets);
00259 if (voronoi_centers_)
00260 voronoi_centers_->points.resize (num_facets);
00261
00262 int non_upper = 0;
00263 FORALLfacets
00264 {
00265
00266 if (!facet->upperdelaunay)
00267 {
00268 vertexT *anyVertex = static_cast<vertexT*> (facet->vertices->e[0].p);
00269 double *center = facet->center;
00270 double r = qh_pointdist (anyVertex->point,center,dim_);
00271 facetT *neighb;
00272
00273 if (voronoi_centers_)
00274 {
00275 voronoi_centers_->points[non_upper].x = static_cast<float> (facet->center[0]);
00276 voronoi_centers_->points[non_upper].y = static_cast<float> (facet->center[1]);
00277 voronoi_centers_->points[non_upper].z = static_cast<float> (facet->center[2]);
00278 }
00279
00280 non_upper++;
00281
00282 if (r <= alpha_)
00283 {
00284
00285 qh_makeridges (facet);
00286 facet->good = true;
00287 facet->visitid = qh visit_id;
00288 ridgeT *ridge, **ridgep;
00289 FOREACHridge_ (facet->ridges)
00290 {
00291 neighb = otherfacet_ (ridge, facet);
00292 if ((neighb->visitid != qh visit_id))
00293 qh_setappend (&triangles_set, ridge);
00294 }
00295 }
00296 else
00297 {
00298
00299 facet->good = false;
00300 facet->visitid = qh visit_id;
00301 qh_makeridges (facet);
00302 ridgeT *ridge, **ridgep;
00303 FOREACHridge_ (facet->ridges)
00304 {
00305 facetT *neighb;
00306 neighb = otherfacet_ (ridge, facet);
00307 if ((neighb->visitid != qh visit_id))
00308 {
00309
00310
00311 PointInT a, b, c;
00312 a.x = static_cast<float> ((static_cast<vertexT*>(ridge->vertices->e[0].p))->point[0]);
00313 a.y = static_cast<float> ((static_cast<vertexT*>(ridge->vertices->e[0].p))->point[1]);
00314 a.z = static_cast<float> ((static_cast<vertexT*>(ridge->vertices->e[0].p))->point[2]);
00315 b.x = static_cast<float> ((static_cast<vertexT*>(ridge->vertices->e[1].p))->point[0]);
00316 b.y = static_cast<float> ((static_cast<vertexT*>(ridge->vertices->e[1].p))->point[1]);
00317 b.z = static_cast<float> ((static_cast<vertexT*>(ridge->vertices->e[1].p))->point[2]);
00318 c.x = static_cast<float> ((static_cast<vertexT*>(ridge->vertices->e[2].p))->point[0]);
00319 c.y = static_cast<float> ((static_cast<vertexT*>(ridge->vertices->e[2].p))->point[1]);
00320 c.z = static_cast<float> ((static_cast<vertexT*>(ridge->vertices->e[2].p))->point[2]);
00321
00322 double r = pcl::getCircumcircleRadius (a, b, c);
00323 if (r <= alpha_)
00324 qh_setappend (&triangles_set, ridge);
00325 }
00326 }
00327 }
00328 }
00329 }
00330
00331 if (voronoi_centers_)
00332 voronoi_centers_->points.resize (non_upper);
00333
00334
00335
00336 int num_good_triangles = 0;
00337 ridgeT *ridge, **ridgep;
00338 FOREACHridge_ (triangles_set)
00339 {
00340 if (ridge->bottom->upperdelaunay || ridge->top->upperdelaunay || !ridge->top->good || !ridge->bottom->good)
00341 num_good_triangles++;
00342 }
00343
00344 polygons.resize (num_good_triangles);
00345
00346 int vertices = 0;
00347 std::vector<bool> added_vertices (max_vertex_id, false);
00348
00349 int triangles = 0;
00350 FOREACHridge_ (triangles_set)
00351 {
00352 if (ridge->bottom->upperdelaunay || ridge->top->upperdelaunay || !ridge->top->good || !ridge->bottom->good)
00353 {
00354 polygons[triangles].vertices.resize (3);
00355 int vertex_n, vertex_i;
00356 FOREACHvertex_i_ ((*ridge).vertices)
00357 {
00358 if (!added_vertices[vertex->id])
00359 {
00360 alpha_shape.points[vertices].x = static_cast<float> (vertex->point[0]);
00361 alpha_shape.points[vertices].y = static_cast<float> (vertex->point[1]);
00362 alpha_shape.points[vertices].z = static_cast<float> (vertex->point[2]);
00363
00364 qhid_to_pcidx[vertex->id] = vertices;
00365 added_vertices[vertex->id] = true;
00366 vertices++;
00367 }
00368
00369 polygons[triangles].vertices[vertex_i] = qhid_to_pcidx[vertex->id];
00370
00371 }
00372
00373 triangles++;
00374 }
00375 }
00376
00377 alpha_shape.points.resize (vertices);
00378 alpha_shape.width = static_cast<uint32_t> (alpha_shape.points.size ());
00379 alpha_shape.height = 1;
00380 }
00381 else
00382 {
00383
00384
00385 setT *edges_set = qh_settemp (3 * num_facets);
00386 if (voronoi_centers_)
00387 voronoi_centers_->points.resize (num_facets);
00388
00389 FORALLfacets
00390 {
00391
00392 if (!facet->upperdelaunay)
00393 {
00394
00395
00396 vertexT *anyVertex = static_cast<vertexT*>(facet->vertices->e[0].p);
00397 double r = (sqrt ((anyVertex->point[0] - facet->center[0]) *
00398 (anyVertex->point[0] - facet->center[0]) +
00399 (anyVertex->point[1] - facet->center[1]) *
00400 (anyVertex->point[1] - facet->center[1])));
00401 if (r <= alpha_)
00402 {
00403 pcl::Vertices facet_vertices;
00404 qh_makeridges (facet);
00405 facet->good = true;
00406
00407 ridgeT *ridge, **ridgep;
00408 FOREACHridge_ (facet->ridges)
00409 qh_setappend (&edges_set, ridge);
00410
00411 if (voronoi_centers_)
00412 {
00413 voronoi_centers_->points[dd].x = static_cast<float> (facet->center[0]);
00414 voronoi_centers_->points[dd].y = static_cast<float> (facet->center[1]);
00415 voronoi_centers_->points[dd].z = 0.0f;
00416 }
00417
00418 ++dd;
00419 }
00420 else
00421 facet->good = false;
00422 }
00423 }
00424
00425 int vertices = 0;
00426 std::vector<bool> added_vertices (max_vertex_id, false);
00427 std::map<int, std::vector<int> > edges;
00428
00429 ridgeT *ridge, **ridgep;
00430 FOREACHridge_ (edges_set)
00431 {
00432 if (ridge->bottom->upperdelaunay || ridge->top->upperdelaunay || !ridge->top->good || !ridge->bottom->good)
00433 {
00434 int vertex_n, vertex_i;
00435 int vertices_in_ridge=0;
00436 std::vector<int> pcd_indices;
00437 pcd_indices.resize (2);
00438
00439 FOREACHvertex_i_ ((*ridge).vertices)
00440 {
00441 if (!added_vertices[vertex->id])
00442 {
00443 alpha_shape.points[vertices].x = static_cast<float> (vertex->point[0]);
00444 alpha_shape.points[vertices].y = static_cast<float> (vertex->point[1]);
00445
00446 if (dim_ > 2)
00447 alpha_shape.points[vertices].z = static_cast<float> (vertex->point[2]);
00448 else
00449 alpha_shape.points[vertices].z = 0;
00450
00451 qhid_to_pcidx[vertex->id] = vertices;
00452 added_vertices[vertex->id] = true;
00453 pcd_indices[vertices_in_ridge] = vertices;
00454 vertices++;
00455 }
00456 else
00457 {
00458 pcd_indices[vertices_in_ridge] = qhid_to_pcidx[vertex->id];
00459 }
00460
00461 vertices_in_ridge++;
00462 }
00463
00464
00465 edges[pcd_indices[0]].push_back (pcd_indices[1]);
00466 edges[pcd_indices[1]].push_back (pcd_indices[0]);
00467 }
00468 }
00469
00470 alpha_shape.points.resize (vertices);
00471
00472 std::vector<std::vector<int> > connected;
00473 PointCloud alpha_shape_sorted;
00474 alpha_shape_sorted.points.resize (vertices);
00475
00476
00477 std::map<int, std::vector<int> >::iterator curr = edges.begin ();
00478 int next = - 1;
00479 std::vector<bool> used (vertices, false);
00480 std::vector<int> pcd_idx_start_polygons;
00481 pcd_idx_start_polygons.push_back (0);
00482
00483
00484 int sorted_idx = 0;
00485 while (!edges.empty ())
00486 {
00487 alpha_shape_sorted.points[sorted_idx] = alpha_shape.points[(*curr).first];
00488
00489 for (size_t i = 0; i < (*curr).second.size (); i++)
00490 {
00491 if (!used[((*curr).second)[i]])
00492 {
00493
00494 next = ((*curr).second)[i];
00495 break;
00496 }
00497 }
00498
00499 used[(*curr).first] = true;
00500 edges.erase (curr);
00501
00502 sorted_idx++;
00503
00504 if (edges.empty ())
00505 break;
00506
00507
00508 curr = edges.find (next);
00509 if (curr == edges.end ())
00510 {
00511
00512 curr = edges.begin ();
00513 pcd_idx_start_polygons.push_back (sorted_idx);
00514 }
00515 }
00516
00517 pcd_idx_start_polygons.push_back (sorted_idx);
00518
00519 alpha_shape.points = alpha_shape_sorted.points;
00520
00521 polygons.resize (pcd_idx_start_polygons.size () - 1);
00522
00523 for (size_t poly_id = 0; poly_id < polygons.size (); poly_id++)
00524 {
00525 polygons[poly_id].vertices.resize (pcd_idx_start_polygons[poly_id + 1] - pcd_idx_start_polygons[poly_id] + 1);
00526
00527 for (int j = pcd_idx_start_polygons[poly_id]; j < pcd_idx_start_polygons[poly_id + 1]; ++j)
00528 polygons[poly_id].vertices[j - pcd_idx_start_polygons[poly_id]] = static_cast<uint32_t> (j);
00529
00530 polygons[poly_id].vertices[polygons[poly_id].vertices.size () - 1] = pcd_idx_start_polygons[poly_id];
00531 }
00532
00533 if (voronoi_centers_)
00534 voronoi_centers_->points.resize (dd);
00535 }
00536
00537 qh_freeqhull (!qh_ALL);
00538 int curlong, totlong;
00539 qh_memfreeshort (&curlong, &totlong);
00540
00541 Eigen::Affine3f transInverse = transform1.inverse ();
00542 pcl::transformPointCloud (alpha_shape, alpha_shape, transInverse);
00543 xyz_centroid[0] = - xyz_centroid[0];
00544 xyz_centroid[1] = - xyz_centroid[1];
00545 xyz_centroid[2] = - xyz_centroid[2];
00546 pcl::demeanPointCloud (alpha_shape, xyz_centroid, alpha_shape);
00547
00548
00549 if (voronoi_centers_)
00550 {
00551 pcl::transformPointCloud (*voronoi_centers_, *voronoi_centers_, transInverse);
00552 pcl::demeanPointCloud (*voronoi_centers_, xyz_centroid, *voronoi_centers_);
00553 }
00554
00555 if (keep_information_)
00556 {
00557
00558 pcl::KdTreeFLANN<PointInT> tree (true);
00559 tree.setInputCloud (input_, indices_);
00560
00561 std::vector<int> neighbor;
00562 std::vector<float> distances;
00563 neighbor.resize (1);
00564 distances.resize (1);
00565
00566
00567
00568 std::vector<int> indices;
00569 indices.resize (alpha_shape.points.size ());
00570
00571 for (size_t i = 0; i < alpha_shape.points.size (); i++)
00572 {
00573 tree.nearestKSearch (alpha_shape.points[i], 1, neighbor, distances);
00574 indices[i] = neighbor[0];
00575 }
00576
00577
00578 pcl::copyPointCloud (*input_, indices, alpha_shape);
00579 }
00580 }
00581 #ifdef __GNUC__
00582 #pragma GCC diagnostic warning "-Wold-style-cast"
00583 #endif
00584
00586 template <typename PointInT> void
00587 pcl::ConcaveHull<PointInT>::performReconstruction (PolygonMesh &output)
00588 {
00589
00590 pcl::PointCloud<PointInT> hull_points;
00591 performReconstruction (hull_points, output.polygons);
00592
00593
00594 pcl::toROSMsg (hull_points, output.cloud);
00595 }
00596
00598 template <typename PointInT> void
00599 pcl::ConcaveHull<PointInT>::performReconstruction (std::vector<pcl::Vertices> &polygons)
00600 {
00601 pcl::PointCloud<PointInT> hull_points;
00602 performReconstruction (hull_points, polygons);
00603 }
00604
00605
00606 #define PCL_INSTANTIATE_ConcaveHull(T) template class PCL_EXPORTS pcl::ConcaveHull<T>;
00607
00608 #endif // PCL_SURFACE_IMPL_CONCAVE_HULL_H_
00609 #endif