From f3bef2ed1c0469549cd9b4e28641a373b4f2159c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 5 Sep 2013 09:11:32 +0200 Subject: [PATCH] a few fixes in the refman following reviewers comments --- .../segment_from_sdf_values_example.cpp | 4 +- .../include/CGAL/mesh_segmentation.h | 132 +++++++++--------- 2 files changed, 71 insertions(+), 65 deletions(-) diff --git a/Surface_mesh_segmentation/examples/Surface_mesh_segmentation/segment_from_sdf_values_example.cpp b/Surface_mesh_segmentation/examples/Surface_mesh_segmentation/segment_from_sdf_values_example.cpp index d09d9c41ce1..f969e476255 100644 --- a/Surface_mesh_segmentation/examples/Surface_mesh_segmentation/segment_from_sdf_values_example.cpp +++ b/Surface_mesh_segmentation/examples/Surface_mesh_segmentation/segment_from_sdf_values_example.cpp @@ -46,11 +46,11 @@ int main() std::cout << segment_property_map[facet_it] << std::endl; } - const int number_of_levels = 4; // use 4 clusters in soft clustering + const int number_of_clusters = 4; // use 4 clusters in soft clustering const double smoothing_lambda = 0.3; // importance of surface features, suggested to be in-between [0,1] // Note that we can use the same SDF values (sdf_property_map) over and over again for segmentation. // This feature becomes important when we want to segment the mesh several times with different parameters. CGAL::segment_from_sdf_values( - mesh, sdf_property_map, segment_property_map, number_of_levels, smoothing_lambda); + mesh, sdf_property_map, segment_property_map, number_of_clusters, smoothing_lambda); } \ No newline at end of file diff --git a/Surface_mesh_segmentation/include/CGAL/mesh_segmentation.h b/Surface_mesh_segmentation/include/CGAL/mesh_segmentation.h index a173583e562..8c05f432629 100644 --- a/Surface_mesh_segmentation/include/CGAL/mesh_segmentation.h +++ b/Surface_mesh_segmentation/include/CGAL/mesh_segmentation.h @@ -20,12 +20,12 @@ template std::pair -compute_sdf_values(const Polyhedron& polyhedron, - SDFPropertyMap sdf_values, - double cone_angle = 2.0 / 3.0 * CGAL_PI, - int number_of_rays = 25, - bool postprocess = true, - GeomTraits traits = GeomTraits()) +compute_sdf_values( const Polyhedron& polyhedron, + SDFPropertyMap sdf_values, + double cone_angle = 2.0 / 3.0 * CGAL_PI, + int number_of_rays = 25, + bool postprocess = true, + GeomTraits traits = GeomTraits()) { internal::Surface_mesh_segmentation algorithm(polyhedron, traits); @@ -39,8 +39,8 @@ compute_sdf_values(const Polyhedron& polyhedron, * @brief Function computing the Shape Diameter Function over a surface mesh. * * This function implements the Shape Diameter Function (SDF) as described in \cgalCite{shapira2008consistent}. - * It is possible to compute raw SDF values (without post-processing). - * For raw SDF values, -1.0 is used to indicate that no SDF value could be computed for a facet. + * It is possible to compute raw SDF values (without post-processing). In such a case, + * -1 is used to indicate when no SDF value could be computed for a facet. * * @pre @a polyhedron.is_pure_triangle() * @tparam Polyhedron a %CGAL polyhedron @@ -48,10 +48,10 @@ compute_sdf_values(const Polyhedron& polyhedron, * @tparam GeomTraits a model of SegmentationGeomTraits * @param polyhedron surface mesh on which SDF values are computed * @param[out] sdf_values the SDF value of each facet - * @param cone_angle opening angle for cone, expressed in radians - * @param number_of_rays number of rays picked from cone for each facet. In general, increasing the number of rays beyond the default value has little influence upon the resulting segmentation. + * @param cone_angle opening angle in radians for the cone of each facet + * @param number_of_rays number of rays picked in the cone of each facet. In our experiments, we observe that increasing the number of rays beyond the default has a little effect on the quality of the segmentation result * @param postprocess if `true`, `CGAL::postprocess_sdf_values` is called on raw SDF value computed. - * @param traits traits object + * @param traits traits class * @return minimum and maximum raw SDF values if @a postprocess is `true`, otherwise minimum and maximum SDF values (before linear normalization) */ template std::pair -compute_sdf_values(const Polyhedron& polyhedron, - SDFPropertyMap sdf_values, - double cone_angle = 2.0 / 3.0 * CGAL_PI, - int number_of_rays = 25, - bool postprocess = true, - GeomTraits traits = GeomTraits()) +compute_sdf_values( const Polyhedron& polyhedron, + SDFPropertyMap sdf_values, + double cone_angle = 2.0 / 3.0 * CGAL_PI, + int number_of_rays = 25, + bool postprocess = true, + GeomTraits traits = GeomTraits()) { return compute_sdf_values (polyhedron, sdf_values, cone_angle, number_of_rays, postprocess, traits); @@ -77,16 +77,16 @@ compute_sdf_values(const Polyhedron& polyhedron, * @brief Function post-processing raw SDF values computed per facet. * * Post-processing steps applied : - * - Facets with -1.0 SDF values are assigned the average SDF value of their edge-adjacent neighbors. - * If there is still a facet having -1.0 SDF value, the minimum valid SDF value assigned to it. Note that this step is not inherited from the paper. - * The main reason for not assigning 0 to facets with no SDF values (i.e. -1.0) is that it can obstruct log-normalization process which takes place at the beginning of `CGAL::segment_from_sdf_values`. + * - Facets with -1 SDF values are assigned the average SDF value of their edge-adjacent neighbors. + * If there is still a facet having -1 SDF value, the minimum valid SDF value assigned to it. Note that this step is not inherited from the paper. + * The main reason for not assigning 0 to facets with no SDF values (i.e. -1) is that it can obstruct log-normalization process which takes place at the beginning of `CGAL::segment_from_sdf_values`. * - SDF values are smoothed with bilateral filtering. * - SDF values are linearly normalized between [0,1]. * * See the section \ref Surface_mesh_segmentationPostprocessing for more details. * * @pre @a polyhedron.is_pure_triangle() - * @pre Raw values should be either equal to -1.0 or, greater or equal than 0.0 + * @pre Raw values should be greater or equal to 0. -1 indicates when no value could be computed * @tparam Polyhedron a %CGAL polyhedron * @tparam SDFPropertyMap a `ReadWritePropertyMap` with `Polyhedron::Facet_const_handle` as key and `double` as value type * @@ -109,27 +109,31 @@ postprocess_sdf_values(const Polyhedron& polyhedron, SDFPropertyMap sdf_values) * \ingroup PkgSurfaceSegmentation * @brief Function computing the segmentation of a surface mesh given an SDF value per facet. * - * This function fills a property map which associates a segment-id (between [0, number of segments -1]) - * or a cluster-id (between [0, @a number_of_levels -1]) to each facet. - * A segment is a set of connected facets which are placed under the same cluster \cgalFigureRef{Cluster_vs_segment}. + * This function fills a property map which associates a segment-id (in [0, number of segments -1]) + * or a cluster-id (in [0, `number_of_clusters` -1]) to each facet. + * A segment is a set of connected facets which are placed under the same cluster (see \cgalFigureRef{Cluster_vs_segment}). * - * \note Log-normalization is applied on @a sdf_values before segmentation. - * \note There is no direct relation between the parameter @a number_of_levels - * and the final number of segments after segmentation. However, large number of clusters likely to result in detailed segmentation of the mesh with a large number of segments. + * \note Log-normalization is applied on `sdf_values` before segmentation. + * As described in the original paper \cgalCite{shapira2008consistent}, + * this normalization is done to preserve thin parts of the mesh + * by increasing the distance between smaller SDF values and reducing + * it between larger ones. + * \note There is no direct relation between the parameter `number_of_clusters` + * and the final number of segments after segmentation. However, setting a large number of clusters will result in a detailed segmentation of the mesh with a large number of segments. * * @pre @a polyhedron.is_pure_triangle() * @tparam Polyhedron a %CGAL polyhedron * @tparam SDFPropertyMap a `ReadablePropertyMap` with `Polyhedron::Facet_const_handle` as key and `double` as value type * @tparam SegmentPropertyMap a `ReadWritePropertyMap` with `Polyhedron::Facet_const_handle` as key and `int` as value type * @tparam GeomTraits a model of SegmentationGeomTraits - * @param polyhedron surface mesh on which SDF values are computed + * @param polyhedron surface mesh corresponding to the SDF values * @param sdf_values the SDF value of each facet between [0-1] - * @param[out] segment_ids the segment id of each facet - * @param number_of_levels number of clusters for soft clustering + * @param[out] segment_ids the segment or cluster id of each facet + * @param number_of_clusters number of clusters for the soft clustering * @param smoothing_lambda factor which indicates the importance of the surface features for the energy minimization. It is recommended to choose a value in the interval [0,1]. See the section \ref Surface_mesh_segmentationGraphCut for more details. - * @param extract_segments if true fill @a segment_ids with segment-ids, otherwise fill with cluster-ids \cgalFigureRef{Cluster_vs_segment} - * @param traits traits object - * @return number of segments if @a extract_segments true, @a number_of_levels otherwise + * @param extract_segments if `true` fill `segment_ids` with segment-ids and cluster-ids otherwise (see \cgalFigureRef{Cluster_vs_segment}) + * @param traits traits class + * @return number of segments if `extract_segments` is set to `true` and `number_of_clusters` otherwise */ template int -segment_from_sdf_values(const Polyhedron& polyhedron, - SDFPropertyMap sdf_values, - SegmentPropertyMap segment_ids, - int number_of_levels = 5, - double smoothing_lambda = 0.26, - bool extract_segments = true, - GeomTraits traits = GeomTraits()) +segment_from_sdf_values( const Polyhedron& polyhedron, + SDFPropertyMap sdf_values, + SegmentPropertyMap segment_ids, + int number_of_clusters = 5, + double smoothing_lambda = 0.26, + bool extract_segments = true, + GeomTraits traits = GeomTraits()) { internal::Surface_mesh_segmentation algorithm( polyhedron, traits); - return algorithm.partition(number_of_levels, smoothing_lambda, sdf_values, + return algorithm.partition(number_of_clusters, smoothing_lambda, sdf_values, segment_ids, extract_segments); } @@ -164,7 +168,7 @@ compute_sdf_values_and_segment(const Polyhedron& polyhedron, SegmentPropertyMap segment_ids, double cone_angle = 2.0 / 3.0 * CGAL_PI, int number_of_rays = 25, - int number_of_levels = 5, + int number_of_clusters = 5, double smoothing_lambda = 0.26, bool extract_segments = true, GeomTraits traits = GeomTraits()) @@ -178,8 +182,8 @@ compute_sdf_values_and_segment(const Polyhedron& polyhedron, compute_sdf_values, GeomTraits> (polyhedron, sdf_property_map, cone_angle, number_of_rays, true, traits); return segment_from_sdf_values, SegmentPropertyMap, GeomTraits> - (polyhedron, sdf_property_map, segment_ids, number_of_levels, smoothing_lambda, - extract_segments, traits); + (polyhedron, sdf_property_map, segment_ids, number_of_clusters, + smoothing_lambda, extract_segments, traits); } /// \endcond @@ -188,26 +192,28 @@ compute_sdf_values_and_segment(const Polyhedron& polyhedron, * \ingroup PkgSurfaceSegmentation * @brief Function computing the segmentation of a surface mesh. * - * This function combines `CGAL::compute_sdf_values` and - * `CGAL::segment_from_sdf_values` functions by computing SDF values and segmenting the mesh in one go. + * This function is equivalent to calling the functions `CGAL::compute_sdf_values()` and + * `CGAL::segment_from_sdf_values()` with the same parameters. * + * \note There is no direct relation between the parameter `number_of_clusters` + * and the final number of segments after segmentation. However, setting a large number of clusters will result in a detailed segmentation of the mesh with a large number of segments. * \note For computing segmentations of the mesh with different parameters (i.e. number of levels, and smoothing lambda), - * it is more efficient to first compute the SDF values using `CGAL::compute_sdf_values` and use them for each call to - * `CGAL::segment_from_sdf_values`. + * it is more efficient to first compute the SDF values using `CGAL::compute_sdf_values()` and use them in different calls to + * `CGAL::segment_from_sdf_values()`. * * @pre @a polyhedron.is_pure_triangle() * @tparam Polyhedron a %CGAL polyhedron * @tparam SegmentPropertyMap a `ReadWritePropertyMap` with `Polyhedron::Facet_const_handle` as key and `int` as value type * @tparam GeomTraits a model of SegmentationGeomTraits * @param polyhedron surface mesh on which SDF values are computed - * @param[out] segment_ids the segment id of each facet - * @param cone_angle opening angle for cone, expressed in radians - * @param number_of_rays number of rays picked from cone for each facet. In general, increasing the number of rays has a little effect on the quality of the result - * @param number_of_levels number of clusters for soft clustering + * @param[out] segment_ids the segment or cluster id of each facet + * @param cone_angle opening angle in radians for the cone of each facet + * @param number_of_rays number of rays picked in the cone of each facet. In our experiments, we observe that increasing the number of rays beyond the default has a little effect on the quality of the segmentation result + * @param number_of_clusters number of clusters for the soft clustering * @param smoothing_lambda factor which indicates the importance of the surface features for the energy minimization. It is recommended to choose a value in the interval [0,1]. See the section \ref Surface_mesh_segmentationGraphCut for more details. - * @param extract_segments if true fill @a segment_ids with segment-ids, otherwise fill with cluster-ids \cgalFigureRef{Cluster_vs_segment} - * @param traits traits object - * @return number of segments if @a extract_segments true, @a number_of_levels otherwise + * @param extract_segments if `true` fill `segment_ids` with segment-ids and cluster-ids otherwise (see \cgalFigureRef{Cluster_vs_segment}) + * @param traits traits class + * @return number of segments if `extract_segments` is set to `true` and `number_of_clusters` otherwise */ template < class Polyhedron, class SegmentPropertyMap, class GeomTraits #ifndef BOOST_NO_FUNCTION_TEMPLATE_DEFAULT_ARGS @@ -219,13 +225,13 @@ compute_sdf_values_and_segment(const Polyhedron& polyhedron, SegmentPropertyMap segment_ids, double cone_angle = 2.0 / 3.0 * CGAL_PI, int number_of_rays = 25, - int number_of_levels = 5, + int number_of_clusters = 5, double smoothing_lambda = 0.26, bool extract_segments = true, GeomTraits traits = GeomTraits()) { return compute_sdf_values_and_segment - (polyhedron, segment_ids, cone_angle, number_of_rays, number_of_levels, + (polyhedron, segment_ids, cone_angle, number_of_rays, number_of_clusters, smoothing_lambda, extract_segments, traits); } @@ -262,13 +268,13 @@ int segment_from_sdf_values(const Polyhedron& polyhedron, SDFPropertyMap sdf_values, SegmentPropertyMap segment_ids, - int number_of_levels = 5, + int number_of_clusters = 5, double smoothing_lambda = 0.26, bool extract_segments = true, typename Polyhedron::Traits traits = typename Polyhedron::Traits()) { return segment_from_sdf_values - (polyhedron, sdf_values, segment_ids, number_of_levels, smoothing_lambda, + (polyhedron, sdf_values, segment_ids, number_of_clusters, smoothing_lambda, extract_segments, traits); } @@ -278,13 +284,13 @@ compute_sdf_values_and_segment(const Polyhedron& polyhedron, SegmentPropertyMap segment_ids, double cone_angle = 2.0 / 3.0 * CGAL_PI, int number_of_rays = 25, - int number_of_levels = 5, + int number_of_clusters = 5, double smoothing_lambda = 0.26, bool extract_segments = true, typename Polyhedron::Traits traits = typename Polyhedron::Traits()) { return compute_sdf_values_and_segment< Fast_sdf_calculation_mode, Polyhedron, SegmentPropertyMap, typename Polyhedron::Traits> - (polyhedron, segment_ids, cone_angle, number_of_rays, number_of_levels, + (polyhedron, segment_ids, cone_angle, number_of_rays, number_of_clusters, smoothing_lambda, extract_segments, traits); } @@ -294,13 +300,13 @@ compute_sdf_values_and_segment(const Polyhedron& polyhedron, SegmentPropertyMap segment_ids, double cone_angle = 2.0 / 3.0 * CGAL_PI, int number_of_rays = 25, - int number_of_levels = 5, + int number_of_clusters = 5, double smoothing_lambda = 0.26, bool extract_segments = true, typename Polyhedron::Traits traits = typename Polyhedron::Traits()) { return compute_sdf_values_and_segment - (polyhedron, segment_ids, cone_angle, number_of_rays, number_of_levels, + (polyhedron, segment_ids, cone_angle, number_of_rays, number_of_clusters, smoothing_lambda, extract_segments, traits); }