diff --git a/Advancing_front_surface_reconstruction/doc/Advancing_front_surface_reconstruction/Advancing_front_surface_reconstruction.txt b/Advancing_front_surface_reconstruction/doc/Advancing_front_surface_reconstruction/Advancing_front_surface_reconstruction.txt index 5d996b0ceed..90502e1bdf6 100644 --- a/Advancing_front_surface_reconstruction/doc/Advancing_front_surface_reconstruction/Advancing_front_surface_reconstruction.txt +++ b/Advancing_front_surface_reconstruction/doc/Advancing_front_surface_reconstruction/Advancing_front_surface_reconstruction.txt @@ -47,6 +47,9 @@ not provide any guarantee on the topology of the surface. We describe next the algorithm and provide examples. +\note A \ref tuto_reconstruction "detailed tutorial on surface reconstruction" +is provided with a guide to choose the most appropriate method along +with pre- and post-processing. \section AFSR_Definitions Definitions and the Algorithm diff --git a/Documentation/doc/Documentation/Doxyfile.in b/Documentation/doc/Documentation/Doxyfile.in index c4efea1bc5e..e90d8b66149 100644 --- a/Documentation/doc/Documentation/Doxyfile.in +++ b/Documentation/doc/Documentation/Doxyfile.in @@ -11,7 +11,8 @@ HTML_HEADER = ${CGAL_DOC_HEADER} LAYOUT_FILE = ${CGAL_DOC_RESOURCE_DIR}/DoxygenLayout.xml GENERATE_TAGFILE = ${CGAL_DOC_TAG_GEN_DIR}/Manual.tag EXAMPLE_PATH = ${CGAL_Convex_hull_2_EXAMPLE_DIR} \ - ${CGAL_Kernel_23_EXAMPLE_DIR} + ${CGAL_Kernel_23_EXAMPLE_DIR} \ + ${CGAL_Poisson_surface_reconstruction_3_EXAMPLE_DIR} FILTER_PATTERNS = *.txt=${CMAKE_BINARY_DIR}/pkglist_filter HTML_EXTRA_FILES += ${CGAL_DOC_RESOURCE_DIR}/hacks.js \ diff --git a/Documentation/doc/Documentation/Tutorials/Tutorial_reconstruction.txt b/Documentation/doc/Documentation/Tutorials/Tutorial_reconstruction.txt new file mode 100644 index 00000000000..5601d6be977 --- /dev/null +++ b/Documentation/doc/Documentation/Tutorials/Tutorial_reconstruction.txt @@ -0,0 +1,294 @@ +namespace CGAL { +/*! +\example Poisson_surface_reconstruction_3/tutorial_example.cpp +*/ + +/*! + +\page tuto_reconstruction Surface Reconstruction from Point Clouds +\cgalAutoToc + +\author Simon Giraudot + +Surface reconstruction from point clouds is a core topic in geometry +processing \cgalCite{cgal:btsag-asosr-16}. It is an ill-posed problem: +there is an infinite number of surfaces that approximate a single +point cloud and a point cloud does not define a surface in +itself. Thus additional assumptions and constraints must be defined by +the user and reconstruction can be achieved in many different +ways. This tutorials provides guidances on how to use the different +algorithms of \cgal to effectively perform surface reconstruction. + +\section TutorialsReconstruction_algorithms Which algorithm should I use? + +\cgal offers three different algorithms for surface reconstruction: + +- \ref Chapter_Poisson_Surface_Reconstruction "Poisson Surface Reconstruction" +- \ref Chapter_Advancing_Front_Surface_Reconstruction "Advancing Front Surface Reconstruction" +- \ref Chapter_Scale_space_reconstruction "Scale Space Surface Reconstruction" + + +Because reconstruction is an ill-posed problem, it must be regularized +via prior knowledge. Differences in prior leads to different +algorithms, and choosing one or the other of these methods is +dependent on these priors. For example, Poisson always generates +closed shapes (bounding a volume) and requires normals but does not +interpolate input points (the output surface does not pass exactly +through the input points). The following table lists different +properties of the input and output to help the user choose the method +best suited to each problem: + +
+| | Poisson | Advancing front | Scale space | +|------------------------------------------|:-------:|:----------------:|:----------------:| +| Are normals required? | Yes | No | No | +| Is noise handled? | Yes | By preprocessing | Yes | +| Is variable sampling handled? | Yes | Yes | By preprocessing | +| Are input points exactly on the surface? | No | Yes | Yes | +| Is the output always closed? | Yes | No | No | +| Is the output always smooth? | Yes | No | No | +| Is the output always manifold? | Yes | Yes | Optional | +| Is the output always orientable? | Yes | Yes | Optional | +
+ +\cgalFigureBegin{TutorialsReconstructionFigComparisons, compare_reconstructions.png} +Comparison of reconstruction methods applied to the same input (full shape and close-up). From left to right: original point cloud; Poisson; advancing front; scale space. +\cgalFigureEnd + +More information on these different methods can be found on their +respective manual pages and in Section \ref TutorialsReconstruction_reconstruction. + +\section TutorialsReconstruction_overview Pipeline Overview + +This tutorial aims at providing a more comprehensive view of the +possibilities offered by \cgal for dealing with point clouds, for +surface reconstruction purposes. The following diagram shows an +overview (not exhaustive) of common reconstruction steps using \cgal +tools. + +\cgalFigureBegin{TutorialsReconstructionFigPipeline, reconstruction.svg} +Pipeline Overview +\cgalFigureEnd + +We now review some of these steps in more details. + + +\section TutorialsReconstruction_input Reading Input + +The reconstruction algorithms in \cgal take a range of iterators on a +container as input and use property maps to access the points (and the +normals when they are required). Points are typically stored in plain +text format (denoted as 'XYZ' format) where each point is separated by +a newline character and each coordinate separated by a white +space. Other formats available are 'OFF', 'PLY' and 'LAS'. \cgal +provides functions to read such formats: + +- `read_xyz_points()` +- `read_off_points()` +- `read_ply_points()` +- `read_ply_points_with_properties()` to read additional PLY properties +- `read_las_points()` +- `read_las_points_with_properties()` to read additional LAS properties + +\cgal also provides a dedicated container `CGAL::Point_set_3` to +handle point sets with additional properties such as normal +vectors. In this case, property maps are easily handled as shown in +the following sections. This structure also handles the stream +operator to read point sets in any of the formats previously +described. Using this method yields substantially shorter code, as can +be seen on the following example: + +\snippet Poisson_surface_reconstruction_3/tutorial_example.cpp Reading input + +\section TutorialsReconstruction_preprocessing Preprocessing + +Because reconstruction algorithms have some specific requirements that +point clouds do not always meet, some preprocessing might be necessary +to yield the best results. + +Note that this _preprocessing_ step is optional: when the input point +cloud has no imperfections, reconstruction can be applied to it +without any preprocessing. + + +\cgalFigureBegin{TutorialsReconstructionFigPreprocessing, reconstruction_preproc.png} +Comparison of advancing front reconstruction output using different +preprocessing on the same input. Smooth point cloud was generated +using _jet smoothing_; simplified point cloud was generated using _grid simplification_. +\cgalFigureEnd + + +\subsection TutorialsReconstruction_preprocessing_outliers Outlier removal + +Some acquisition techniques generate points which are far away from +the surface. These points, commonly referred to as "outliers", have no +relevance for reconstruction. Using the \cgal reconstruction +algorithms on outlier-ridden point clouds produce overly distorted +output, it is therefore strongly advised to filter these outliers +_before_ performing reconstruction. + +\snippet Poisson_surface_reconstruction_3/tutorial_example.cpp Outlier removal + +\subsection TutorialsReconstruction_preprocessing_simplification Simplification + +Some laser scanners generate points with widely variable +sampling. Typically, lines of scan are very densely sampled but the +gap between two lines of scan is much larger, leading to an overly +massive point cloud with large variations of sampling density. This +type of input point cloud might generate imperfect output using +algorithms which, in general, only handle small variations of sampling +density. + +\cgal provides several simplification algorithms. In addition to +reducing the size of the input point cloud and therefore decreasing +computation time, some of them can help making the input more +uniform. This is the case of the function `grid_simplify_point_set()` +which defines a grid of a user-specified size and keeps one point per +occupied cell. + +\snippet Poisson_surface_reconstruction_3/tutorial_example.cpp Simplification + + +\subsection TutorialsReconstruction_preprocessing_smoothing Smoothing + +Although reconstructions via 'Poisson' or 'Scale space' handle noise +internally, one may want to get tighter control over the smoothing +step. For example, a slightly noisy point cloud can benefit from some +reliable smoothing algorithms and be reconstructed via 'Advancing +front' which provides relevant properties (oriented mesh with +boundaries). + +Two functions are provided to smooth a noisy point cloud with a good +approximation (i.e. without degrading curvature, for example): + +- `jet_smooth_point_set()` +- `bilateral_smooth_point_set()` + +These functions directly modify the container: + +\snippet Poisson_surface_reconstruction_3/tutorial_example.cpp Smoothing + + +\subsection TutorialsReconstruction_preprocessing_normal Normal Estimation and Orientation + +\ref Chapter_Poisson_Surface_Reconstruction "Poisson Surface Reconstruction" +requires points with oriented normal vectors. To apply the algorithm +to a raw point cloud, normals must be estimated first, for example +with one of these two functions: + +- `pca_estimate_normals()` +- `jet_estimate_normals()` + +PCA is faster but jet is more accurate in the presence of high +curvatures. These function only estimates the _direction_ of the +normals, not their orientation (the orientation of the vectors might +not be locally consistent). To properly orient the normals, the +function `mst_orient_normals()` can be used. Notice that it can also +be used directly on input normals if their orientation is not +consistent. + +\snippet Poisson_surface_reconstruction_3/tutorial_example.cpp Normal estimation + +\section TutorialsReconstruction_reconstruction Reconstruction + +\subsection TutorialsReconstruction_reconstruction_poisson Poisson + +Poisson reconstruction consists in computing an implicit function +whose gradient matches the input normal vector field: this indicator +function has opposite signs inside and outside of the inferred shape +(hence the need for closed shapes). This method thus requires normals +and produces smooth closed surfaces. It is not appropriate if the +surface is expected to interpolate the input points. On the contrary, +it performs well if the aim is to approximate a noisy point cloud with +a smooth surface. + +\snippet Poisson_surface_reconstruction_3/tutorial_example.cpp Poisson reconstruction + +\subsection TutorialsReconstruction_reconstruction_advancing Advancing Front + +Advancing front is a Delaunay-based approach which interpolates a +subset of the input points. It generates triples of point indices +which describe the triangular facets of the reconstruction: it uses a +priority queue to sequentially pick the Delaunay facet the most likely +to be part of the surface, based on a size criterion (to favor the +small facets) and an angle criterion (to favor smoothness). Its main +virtue is to generate oriented manifold surfaces with boundaries: +contrary to Poisson, it does not require normals and is not bound to +reconstruct closed shapes. However, it requires preprocessing if the +point cloud is noisy. + +The \ref Chapter_Advancing_Front_Surface_Reconstruction "Advancing Front" +package provides several ways of constructing the function. Here is +a simple example: + +\snippet Poisson_surface_reconstruction_3/tutorial_example.cpp Advancing front reconstruction + +\subsection TutorialsReconstruction_reconstruction_scale_space Scale Space + +Scale space reconstruction aims at producing a surface which +interpolates the input points (interpolant) while offering some +robustness to noise. More specifically, it first applies several times +a smoothing filter (such as Jet Smoothing) to the input point set to +produce a scale space; then, the smoothest scale is meshed (using for +example the Advancing Front mesher); finally, the resulting +connectivity between smoothed points is propagated to the original raw +input point set. This method is the right choice if the input point +cloud is noisy but the user still wants the surface to pass exactly +through the points. + +\snippet Poisson_surface_reconstruction_3/tutorial_example.cpp Scale space reconstruction + +\section TutorialsReconstruction_postprocessing Output and Postprocessing + +Each of these methods produce a triangle mesh stored in different +ways. If this output mesh is hampered by defects such as holes or +self-intersections, \cgal provide several algorithms to post-process +it (hole filling, remeshing, etc.) in the package \ref +Chapter_PolygonMeshProcessing "Polygon Mesh Processing". + +We do not discuss these functions here as there are many +postprocessing possibilities whose relevance strongly depends on the +user's expectations on the output mesh. + +The mesh (postprocessed or not) can easily be saved in the PLY format +(here, using the binary variant): + +\snippet Poisson_surface_reconstruction_3/tutorial_example.cpp Output poisson + +A polygon soup can also be saved in the OFF format by iterating on the +points and faces: + +\snippet Poisson_surface_reconstruction_3/tutorial_example.cpp Output scale space + +Finally, if the polygon soup can be converted into a polygon mesh, it +can also be saved directly in the OFF format using the stream +operator: + +\snippet Poisson_surface_reconstruction_3/tutorial_example.cpp Output advancing front + +\section TutorialsReconstruction_recap Full Code Example + +All the code snippets used in this tutorial can be assembled to create +a full algorithm pipeline (provided the correct _includes_ are +used). We give a full code example which achieves all the steps +described in this tutorial. The reconstruction method can be selected +by the user at runtime with the second argument. + +\include Poisson_surface_reconstruction_3/tutorial_example.cpp + +\section TutorialsReconstruction_pipeline Full Pipeline Images + +The following figure an example of a full reconstruction pipeline +applied to a bear statue (courtesy _EPFL Computer Graphics and +Geometry Laboratory_ \cgalCite{cgal:e-esmr}). Two mesh processing +algorithms (hole filling and isotropic remeshing) are also applied +(refer to the chapter \ref Chapter_PolygonMeshProcessing "Polygon Mesh Processing" +for more information). + +\cgalFigureBegin{TutorialsReconstructionFigFull, reconstruction_pipeline.png} +Full reconstruction pipeline (with close-ups). +\cgalFigureEnd + + +*/ +} diff --git a/Documentation/doc/Documentation/Tutorials/Tutorials.txt b/Documentation/doc/Documentation/Tutorials/Tutorials.txt index aab618e954f..76aa5daf111 100644 --- a/Documentation/doc/Documentation/Tutorials/Tutorials.txt +++ b/Documentation/doc/Documentation/Tutorials/Tutorials.txt @@ -16,6 +16,8 @@ User Manual. geometric primitives, the notion of traits classes which define what primitives are used by a geometric algorithm, the notions of \em concept and \em model. +- \subpage tuto_reconstruction + \section tuto_examples Package Examples diff --git a/Documentation/doc/Documentation/fig/compare_reconstructions.png b/Documentation/doc/Documentation/fig/compare_reconstructions.png new file mode 100644 index 00000000000..5c9a41f0169 Binary files /dev/null and b/Documentation/doc/Documentation/fig/compare_reconstructions.png differ diff --git a/Documentation/doc/Documentation/fig/reconstruction.svg b/Documentation/doc/Documentation/fig/reconstruction.svg new file mode 100644 index 00000000000..d32ecdb5c75 --- /dev/null +++ b/Documentation/doc/Documentation/fig/reconstruction.svg @@ -0,0 +1,1447 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Input + + + Preprocessing + + + Reconstruction + + + Postprocessing + + + Output + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Poisson reconstruction + + + + + + Advancing front reconstruction + + + + + + Scale space reconstruction + + + + + + Normal estimation + + + + + + Simplification + + + + + + Smoothing + + + + + + Points + + + + + + Points with normals + + + + + + Outlier removal + + + + + + Simplification + + + + + + Smoothing + + + + + + Outlier removal + + + + + + Normal orientation + + + + + + XYZ file + + + + + + OFF file + + + + + + read_xyz_points + + + + + + read_off_points + + + + + + PLY file + + + + + + read_ply_points + + + + + + LAS/LAZ file + + + + + + read_las_points + + + + + + Mesh + + + + + + Hole filling + + + + + + Remeshing + + + + + + OFF file + + + + + + write_off + + + + + + PLY file + + + + + + write_ply + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Documentation/doc/Documentation/fig/reconstruction_pipeline.png b/Documentation/doc/Documentation/fig/reconstruction_pipeline.png new file mode 100644 index 00000000000..ce240b9fad8 Binary files /dev/null and b/Documentation/doc/Documentation/fig/reconstruction_pipeline.png differ diff --git a/Documentation/doc/Documentation/fig/reconstruction_preproc.png b/Documentation/doc/Documentation/fig/reconstruction_preproc.png new file mode 100644 index 00000000000..ddcab5a9e0b Binary files /dev/null and b/Documentation/doc/Documentation/fig/reconstruction_preproc.png differ diff --git a/Documentation/doc/biblio/cgal_manual.bib b/Documentation/doc/biblio/cgal_manual.bib index 41fe234c9dc..785b25e2e36 100644 --- a/Documentation/doc/biblio/cgal_manual.bib +++ b/Documentation/doc/biblio/cgal_manual.bib @@ -708,6 +708,12 @@ Teillaud" , year = 1999 } +@Misc{ cgal:e-esmr, + title = {{EPFL} statue model repository}, + howpublished = {{EPFL} Computer Graphics and Geometry Laboratory}, + url = {http://lgg.epfl.ch/statues_dataset.php} +} + @inproceedings{ cgal:eddhls-maam-95 ,author = {Matthias Eck and Tony DeRose and Tom Duchamp and Hugues Hoppe and Michael Lounsbery and Werner Stuetzle} @@ -1771,6 +1777,21 @@ ABSTRACT = {We present the first complete, exact and efficient C++ implementatio pages="" } +@article{cgal:btsag-asosr-16, + TITLE = {{A Survey of Surface Reconstruction from Point Clouds}}, + AUTHOR = {Berger, Matthew and Tagliasacchi, Andrea and Seversky, Lee and Alliez, Pierre and Guennebaud, Gael and Levine, Joshua and Sharf, Andrei and Silva, Claudio}, + URL = {https://hal.inria.fr/hal-01348404}, + JOURNAL = {{Computer Graphics Forum}}, + PUBLISHER = {{Wiley}}, + PAGES = {27}, + YEAR = {2016}, + DOI = {10.1111/cgf.12802}, + PDF = {https://hal.inria.fr/hal-01348404/file/survey-author.pdf}, + HAL_ID = {hal-01348404}, + HAL_VERSION = {v2} +} + + @TechReport{ cgal:pabl-cco-07, author = {Poudret, M. and Arnould, A. and Bertrand, Y. and Lienhardt, P.}, title = {Cartes Combinatoires Ouvertes.}, diff --git a/Poisson_surface_reconstruction_3/doc/Poisson_surface_reconstruction_3/Poisson_surface_reconstruction_3.txt b/Poisson_surface_reconstruction_3/doc/Poisson_surface_reconstruction_3/Poisson_surface_reconstruction_3.txt index 137fa4194b1..b9b836134fa 100644 --- a/Poisson_surface_reconstruction_3/doc/Poisson_surface_reconstruction_3/Poisson_surface_reconstruction_3.txt +++ b/Poisson_surface_reconstruction_3/doc/Poisson_surface_reconstruction_3/Poisson_surface_reconstruction_3.txt @@ -1,7 +1,7 @@ namespace CGAL { /*! -\mainpage User Manual +\mainpage User Manual \anchor Chapter_Poisson_Surface_Reconstruction \cgalAutoToc @@ -28,6 +28,11 @@ function of the inferred solid (Poisson Surface Reconstruction - referred to as Poisson). Poisson is a two steps process: it requires solving for the implicit function before function evaluation. +\note A \ref tuto_reconstruction "detailed tutorial on surface reconstruction" +is provided with a guide to choose the most appropriate method along +with pre- and post-processing. + + \section Poisson_surface_reconstruction_3Common Common Reconstruction Pipeline Surface reconstruction from point sets is often a sequential process @@ -38,7 +43,7 @@ reduce noise in the input data; 5) Normal estimation and orientation when the normals are not already provided by the acquisition device; and 6) Surface reconstruction. -\cgal provides algorithms for all steps listed above except alignment. +\cgal provides algorithms for all steps listed above except alignment. Chapter \ref chappoint_set_processing_3 "Point Set Processing" describes algorithms to pre-process the point set before @@ -115,12 +120,12 @@ The following example reads a point set, creates a Poisson implicit function and The computed implicit functions can be iso-contoured to reconstruct a -surface by using the \cgal surface mesh generator +surface by using the \cgal surface mesh generator \cgalCite{cgal:ry-gsddrm-06} \cgalCite{cgal:bo-pgsms-05} : -`make_surface_mesh()` +`make_surface_mesh()` -The parameter `Tag` affects the behavior of `make_surface_mesh()`: +The parameter `Tag` affects the behavior of `make_surface_mesh()`: - `Manifold_tag`: the output mesh is guaranteed to be a manifold surface without boundary. - `Manifold_with_boundary_tag`: the output mesh is guaranteed to be manifold and may have boundaries. - `Non_manifold_tag`: the output mesh has no guarantee and hence is outputted as a polygon soup. @@ -137,8 +142,8 @@ a three dimensional triangulation. Other \cgal components provide functions to write the reconstructed surface mesh to the %Object File Format (OFF) \cgalCite{cgal:p-gmgv16-96} and to convert it to a polyhedron (when it is manifold): -- `output_surface_facets_to_off()` -- `output_surface_facets_to_polyhedron()` +- `output_surface_facets_to_off()` +- `output_surface_facets_to_polyhedron()` See \ref Poisson_surface_reconstruction_3/poisson_reconstruction_example.cpp "poisson_reconstruction_example.cpp" example above. @@ -166,7 +171,7 @@ reconstruction method expects a dense 3D oriented point set (typically matching the epsilon-sampling condition \cgalCite{cgal:bo-pgsms-05}) and sampled over a closed, smooth surface. Oriented herein means that all 3D points must come with consistently oriented normals to the inferred -surface. \cgalFigureRef{Poisson_surface_reconstruction_3figbimba} and \cgalFigureRef{Poisson_surface_reconstruction_3figeros} +surface. \cgalFigureRef{Poisson_surface_reconstruction_3figbimba} and \cgalFigureRef{Poisson_surface_reconstruction_3figeros} illustrate cases where these ideal conditions are met. \cgalFigureBegin{Poisson_surface_reconstruction_3figbimba,bimba.jpg} @@ -343,7 +348,7 @@ with the 03 option which maximizes speed. All measurements were done using the The point set chosen for benchmarking the Poisson implicit function is the Bimba con Nastrino point set (1.6 million points) depicted by \cgalFigureRef{Poisson_surface_reconstruction_3-fig-contouring_bench}. -We measure the Poisson implicit function computation (i.e., the call to +We measure the Poisson implicit function computation (i.e., the call to `Poisson_reconstruction_function::compute_implicit_function()` denoted by Poisson solve hereafter) for this point set as well as for simplified versions obtained through random simplification. The following table provides Poisson solve computation times in seconds for an increasing number of points. @@ -353,9 +358,9 @@ The following table provides Poisson solve computation times in seconds for an i -Number of points (x1000) +Number of points (x1000) -Poisson solve duration (in s) +Poisson solve duration (in s)
@@ -405,16 +410,16 @@ in mm (the Bimba con Nastrino statue is 324 mm tall).
-Approx. distance (*average spacing) +Approx. distance (*average spacing) -Contouring duration (in s) +Contouring duration (in s) -Reconstruction error (mm) +Reconstruction error (mm)
-0.1 +0.1 19.2 @@ -442,7 +447,7 @@ Reconstruction error (mm) 0.36 -2 +2 0.8 @@ -461,16 +466,16 @@ for the Bimba con Nastrino point set simplified to 100k points. We measure the memory occupancy for the reconstruction of the full Bimba con Nastrino point set (1.8 millions points) as well as for simplified versions.\n -The Poisson implicit function computation has a memory peak when solving the Poisson linear +The Poisson implicit function computation has a memory peak when solving the Poisson linear system using the sparse linear solver.

-Number of points (x1000) +Number of points (x1000) -Memory occupancy (MBytes) +Memory occupancy (MBytes)

@@ -509,19 +514,19 @@ Memory occupancy (MBytes) \subsection SurfReconstPerfPSS Point Set Simplification Due to the memory limitations described above, we recommend to simplify the point sets captured by laser scanners.\n -We measure the reconstruction error for the Bimba con Nastrino point set (1.6M points) as well as for -simplified versions. All reconstructions use the recommended contouring parameter +We measure the reconstruction error for the Bimba con Nastrino point set (1.6M points) as well as for +simplified versions. All reconstructions use the recommended contouring parameter `approximation distance = 0.25 * the input point` set's average spacing. -The reconstruction error is expressed as the average distance from input points to the reconstructed surface in mm +The reconstruction error is expressed as the average distance from input points to the reconstructed surface in mm (the Bimba con Nastrino statue is 324 mm tall). @@ -570,10 +575,10 @@ as well as for simplified versions. \section SurfReconstDesignHistory Design and Implementation History -The initial implementation was essentially done by Laurent Saboret, guided by Pierre Alliez and Ga\"el Guennebaud. +The initial implementation was essentially done by Laurent Saboret, guided by Pierre Alliez and Ga\"el Guennebaud. For later releases of the package Andreas Fabri worked on performance improvements, and Laurent Rineau added the two passes for dealing with holes. -*/ +*/ } /* namespace CGAL */ diff --git a/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/CMakeLists.txt b/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/CMakeLists.txt index 85259f8bd2f..f2af58022ab 100644 --- a/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/CMakeLists.txt +++ b/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/CMakeLists.txt @@ -31,11 +31,13 @@ if ( CGAL_FOUND ) CGAL_target_use_Eigen(poisson_reconstruction) create_single_source_cgal_program( "poisson_reconstruction_function.cpp" ) CGAL_target_use_Eigen(poisson_reconstruction_function) + create_single_source_cgal_program( "tutorial_example.cpp" ) + CGAL_target_use_Eigen(tutorial_example) else() message(STATUS "NOTICE: The examples need Eigen 3.1 (or greater) will not be compiled.") endif() - + else() message(STATUS "NOTICE: This program requires the CGAL library, and will not be compiled.") diff --git a/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/tutorial_example.cmd b/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/tutorial_example.cmd new file mode 100644 index 00000000000..12b759aa160 --- /dev/null +++ b/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/tutorial_example.cmd @@ -0,0 +1,3 @@ +data/kitten.xyz +data/kitten.xyz 1 +data/kitten.xyz 2 diff --git a/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/tutorial_example.cpp b/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/tutorial_example.cpp new file mode 100644 index 00000000000..a51c9db41a0 --- /dev/null +++ b/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/tutorial_example.cpp @@ -0,0 +1,223 @@ +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +// types +typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; +typedef Kernel::FT FT; +typedef Kernel::Point_3 Point_3; +typedef Kernel::Vector_3 Vector_3; +typedef Kernel::Sphere_3 Sphere_3; +typedef CGAL::Point_set_3 Point_set; + +int main(int argc, char*argv[]) +{ + /////////////////////////////////////////////////////////////////// + //! [Reading input] + + Point_set points; + + if (argc < 2) + { + std::cerr << "Usage: " << argv[0] << " [input.xyz/off/ply/las]" << std::endl; + return EXIT_FAILURE; + } + + const char* input_file = argv[1]; + std::ifstream stream (input_file, std::ios_base::binary); + if (!stream) + { + std::cerr << "Error: cannot read file " << input_file << std::endl; + return EXIT_FAILURE; + } + + stream >> points; + + std::cout << "Read " << points.size () << " point(s)" << std::endl; + if (points.empty()) + return EXIT_FAILURE; + + //! [Reading input] + /////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////// + //! [Outlier removal] + + CGAL::remove_outliers (points, + 24, // Number of neighbors considered for evaluation + points.parameters().threshold_percent (5.0)); // Percentage of points to remove + + std::cout << points.number_of_removed_points() + << " point(s) are outliers." << std::endl; + + // Applying point set processing algorithm to a CGAL::Point_set_3 + // object does not erase the points from memory but place them in + // the garbage of the object: memory can be freeed by the user. + points.collect_garbage(); + + //! [Outlier removal] + /////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////// + //! [Simplification] + + // Compute average spacing using neighborhood of 6 points + double spacing = CGAL::compute_average_spacing (points, 6); + + // Simplify using a grid of size 2 * average spacing + CGAL::grid_simplify_point_set (points, 2. * spacing); + + std::cout << points.number_of_removed_points() + << " point(s) removed after simplification." << std::endl; + + points.collect_garbage(); + + //! [Simplification] + /////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////// + //! [Smoothing] + + CGAL::jet_smooth_point_set (points, 24); + + //! [Smoothing] + /////////////////////////////////////////////////////////////////// + + unsigned int reconstruction_choice + = (argc < 3 ? 0 : atoi(argv[2])); + + if (reconstruction_choice == 0) // Poisson + { + /////////////////////////////////////////////////////////////////// + //! [Normal estimation] + + CGAL::jet_estimate_normals + (points, 24); // Use 24 neighbors + + // Orientation of normals, returns iterator to first unoriented point + typename Point_set::iterator unoriented_points_begin = + CGAL::mst_orient_normals(points, 24); // Use 24 neighbors + + points.remove (unoriented_points_begin, points.end()); + + //! [Normal estimation] + /////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////// + //! [Poisson reconstruction] + + CGAL::Surface_mesh output_mesh; + CGAL::poisson_surface_reconstruction_delaunay + (points.begin(), points.end(), + points.point_map(), points.normal_map(), + output_mesh, spacing); + + //! [Poisson reconstruction] + /////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////// + //! [Output poisson] + + std::ofstream f ("out.ply", std::ios_base::binary); + CGAL::set_binary_mode (f); + CGAL::write_ply (f, output_mesh); + f.close (); + + //! [Output poisson] + /////////////////////////////////////////////////////////////////// + } + else if (reconstruction_choice == 1) // Advancing front + { + /////////////////////////////////////////////////////////////////// + //! [Advancing front reconstruction] + + typedef std::array Facet; // Triple of indices + + std::vector facets; + + // The function is called using directly the points raw iterators + CGAL::advancing_front_surface_reconstruction(points.points().begin(), + points.points().end(), + std::back_inserter(facets)); + std::cout << facets.size () + << " facet(s) generated by reconstruction." << std::endl; + + //! [Advancing front reconstruction] + /////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////// + //! [Output advancing front] + + // copy points for random access + std::vector vertices; + vertices.reserve (points.size()); + std::copy (points.points().begin(), points.points().end(), std::back_inserter (vertices)); + + CGAL::Surface_mesh output_mesh; + CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh (vertices, facets, output_mesh); + std::ofstream f ("out.off"); + f << output_mesh; + f.close (); + + //! [Output advancing front] + /////////////////////////////////////////////////////////////////// + } + else if (reconstruction_choice == 2) // Scale space + { + /////////////////////////////////////////////////////////////////// + //! [Scale space reconstruction] + + CGAL::Scale_space_surface_reconstruction_3 reconstruct + (points.points().begin(), points.points().end()); + + // Smooth using 4 iterations of Jet Smoothing + reconstruct.increase_scale (4, CGAL::Scale_space_reconstruction_3::Jet_smoother()); + // Mesh with the Advancing Front mesher with a maximum facet length of 0.5 + reconstruct.reconstruct_surface (CGAL::Scale_space_reconstruction_3::Advancing_front_mesher(0.5)); + + //! [Scale space reconstruction] + /////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////// + //! [Output scale space] + + std::ofstream f ("out.off"); + f << "OFF" << std::endl << points.size () << " " + << reconstruct.number_of_facets() << " 0" << std::endl; + for (Point_set::Index idx : points) + f << points.point (idx) << std::endl; + for (const auto& facet : CGAL::make_range (reconstruct.facets_begin(), reconstruct.facets_end())) + f << "3 "<< facet << std::endl; + f.close (); + + //! [Output scale space] + /////////////////////////////////////////////////////////////////// + } + else // Handle error + { + std::cerr << "Error: invalid reconstruction id: " << reconstruction_choice << std::endl; + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/Scale_space_reconstruction_3/doc/Scale_space_reconstruction_3/Scale_space_reconstruction_3.txt b/Scale_space_reconstruction_3/doc/Scale_space_reconstruction_3/Scale_space_reconstruction_3.txt index db6d7281b90..6b86b672c8f 100644 --- a/Scale_space_reconstruction_3/doc/Scale_space_reconstruction_3/Scale_space_reconstruction_3.txt +++ b/Scale_space_reconstruction_3/doc/Scale_space_reconstruction_3/Scale_space_reconstruction_3.txt @@ -1,7 +1,7 @@ namespace CGAL { /*! -\mainpage User Manual +\mainpage User Manual \anchor Chapter_Scale_space_reconstruction \anchor chapterScaleSpaceReconstruction3 \cgalAutoToc @@ -17,6 +17,10 @@ Left: 5760 points on a synthetic knot data set. Right: reconstructed surface mes A triangulated surface mesh is generated by first computing the point set at a coarse scale, then constructing a mesh of the point set at this scale, and finally reverting the points of the mesh back to their original scale. +\note A \ref tuto_reconstruction "detailed tutorial on surface reconstruction" +is provided with a guide to choose the most appropriate method along +with pre- and post-processing. + \section ScaleSpaceReconstruction3secMethod Scale-Space @@ -174,7 +178,7 @@ We have evaluated the scale-space surface reconstruction method on several data \cgalFigureAnchor{chapterScaleSpaceReconstruction3figSettings}
-| Data set | Neighbors | Samples | Iterations | +| Data set | Neighbors | Samples | Iterations | | ----: | ----: | ----: | ----: | Mushroom (s) | 10 | 200 | 2 | Elephant (s) | 15 | 200 | 1 | @@ -269,6 +273,6 @@ This last example shows how to use the alternative operators [Jet_smoother](@ref This method was developed by Julie Digne et al. in 2011 \cgalCite{cgal:dmsl-ssmrp-11} and implemented by Thijs van Lankveld at Inria - Sophia Antipolis in 2014. -*/ +*/ } /* namespace CGAL */

-Number of points (x1000) +Number of points (x1000) -Reconstruction error (mm) +Reconstruction error (mm)

@@ -530,7 +535,7 @@ Reconstruction error (mm) 0.27
-120 +120 0.15