diff --git a/Kinetic_surface_reconstruction/doc/Kinetic_surface_reconstruction/PackageDescription.txt b/Kinetic_surface_reconstruction/doc/Kinetic_surface_reconstruction/PackageDescription.txt index ac2861a1ea6..02a2e71b1b0 100644 --- a/Kinetic_surface_reconstruction/doc/Kinetic_surface_reconstruction/PackageDescription.txt +++ b/Kinetic_surface_reconstruction/doc/Kinetic_surface_reconstruction/PackageDescription.txt @@ -1,25 +1,19 @@ /*! \defgroup PkgKineticSurfaceReconstructionRef Kinetic Surface Reconstruction Reference -\defgroup PkgKineticSurfaceReconstructionConcepts Concepts -\ingroup PkgKineticSurfaceReconstructionRef - -\defgroup PkgKineticSurfaceReconstructionClasses Classes -\ingroup PkgKineticSurfaceReconstructionRef - \addtogroup PkgKineticSurfaceReconstructionRef \cgalPkgDescriptionBegin{Kinetic Surface Reconstruction, PkgKineticSurfaceReconstruction} \cgalPkgPicture{kinetic_logo.png} \cgalPkgSummaryBegin \cgalPkgAuthors{Sven Oesau and Florent Lafarge} -\cgalPkgDesc{This package implements kinetic shape partition. Based on a set of planar input shapes the bounding box of the input data is split into convex volumes. The complexity of the partition can be adjusted with a single parameter.} +\cgalPkgDesc{The package implements a piece-wise planar surface reconstruction pipeline from point clouds combining methods from the Shape Detection, Shape Regularization and Kinetic Shape Partition packages and graph-cut.} \cgalPkgManuals{Chapter_Kinetic_Surface_Reconstruction, PkgKineticSurfaceReconstructionRef} \cgalPkgSummaryEnd \cgalPkgShortInfoBegin \cgalPkgSince{6.0} -\cgalPkgDependsOn{\ref PkgSurfaceMesh, \ref PkgLinearCellComplex} +\cgalPkgDependsOn{\ref PkgKineticShapePartition, \ref PkgSurfaceMesh, \ref PkgLinearCellComplex, \ref PkgShapeDetection} \cgalPkgBib{cgal:ol-kinetic} \cgalPkgLicense{\ref licensesGPL "GPL"} \cgalPkgShortInfoEnd diff --git a/Kinetic_surface_reconstruction/examples/Kinetic_surface_reconstruction/kinetic_reconstruction.cpp b/Kinetic_surface_reconstruction/examples/Kinetic_surface_reconstruction/kinetic_reconstruction.cpp index 49c0527ba87..2507b249d9f 100644 --- a/Kinetic_surface_reconstruction/examples/Kinetic_surface_reconstruction/kinetic_reconstruction.cpp +++ b/Kinetic_surface_reconstruction/examples/Kinetic_surface_reconstruction/kinetic_reconstruction.cpp @@ -173,7 +173,7 @@ int main(const int argc, const char** argv) { Timer timer; timer.start(); - std::size_t num_shapes = ksr.detect_planar_shapes(false, param); + std::size_t num_shapes = ksr.detect_planar_shapes(param); std::cout << num_shapes << " detected planar shapes" << std::endl; @@ -190,7 +190,7 @@ int main(const int argc, const char** argv) { std::vector vtx; std::vector > polylist; - ksr.reconstruct(parameters.graphcut_beta, std::back_inserter(vtx), std::back_inserter(polylist)); + ksr.reconstruct_with_ground(parameters.graphcut_beta, std::back_inserter(vtx), std::back_inserter(polylist)); FT after_reconstruction = timer.time(); if (polylist.size() > 0) diff --git a/Kinetic_surface_reconstruction/include/CGAL/Kinetic_surface_reconstruction_3.h b/Kinetic_surface_reconstruction/include/CGAL/Kinetic_surface_reconstruction_3.h index 1e9ab368586..c3dbf98675b 100644 --- a/Kinetic_surface_reconstruction/include/CGAL/Kinetic_surface_reconstruction_3.h +++ b/Kinetic_surface_reconstruction/include/CGAL/Kinetic_surface_reconstruction_3.h @@ -42,7 +42,7 @@ namespace CGAL { /*! * \ingroup PkgKineticSurfaceReconstructionRef - \brief Piece-wise planar surface reconstruction via inside/outside labeling of a kinetic partition using graph cut. + \brief Reconstruction pipeline for piece-wise planar surface reconstruction from a point cloud via inside/outside labeling of a kinetic partition using graph cut. \tparam GeomTraits must be a model of `KineticShapePartitionTraits_3`. @@ -66,29 +66,15 @@ public: using Intersection_kernel = IntersectionKernel; using FT = typename Kernel::FT; - - using Point_2 = typename Kernel::Point_2; using Point_3 = typename Kernel::Point_3; - using Vector_3 = typename Kernel::Vector_3; using Plane_3 = typename Kernel::Plane_3; - using Triangle_2 = typename Kernel::Triangle_2; - using Point_set = PointSet; - using Indices = std::vector; - using Polygon_3 = std::vector; - using KSP = Kinetic_shape_partition_3; using Point_map = PointMap; using Normal_map = NormalMap; - using Region_type = CGAL::Shape_detection::Point_set::Least_squares_plane_fit_region_for_point_set; - using Neighbor_query = CGAL::Shape_detection::Point_set::K_neighbor_query_for_point_set; - using Sorting = CGAL::Shape_detection::Point_set::Least_squares_plane_fit_sorting_for_point_set; - using Region_growing = CGAL::Shape_detection::Region_growing; - using From_exact = typename CGAL::Cartesian_converter; - /*! \brief Creates a Kinetic_shape_reconstruction_3 object. @@ -130,65 +116,60 @@ public: \cgalParamType{a model of `ReadablePropertyMap` whose key type is the value type of the iterator of `PointSet` and whose value type is `GeomTraits::Vector_3`} \cgalParamDefault{`NormalMap()`} \cgalParamNBegin{k_neighbors} - \cgalParamDescription{the number of neighbors for each point considered during region growing} + \cgalParamDescription{Shape detection: the number of neighbors for each point considered during region growing} \cgalParamType{`std::size_t`} \cgalParamDefault{12} \cgalParamNEnd - \cgalParamNBegin{maximum_offset} - \cgalParamDescription{maximum angle in degrees between the normal of a point and the plane normal} + \cgalParamNBegin{maximum_distance} + \cgalParamDescription{Shape detection: the maximum distance from a point to a plane} \cgalParamType{`GeomTraits::FT`} - \cgalParamDefault{25 degrees} + \cgalParamDefault{2% of bounding box diagonal} \cgalParamNEnd \cgalParamNBegin{maximum_angle} - \cgalParamDescription{maximum angle in degrees between the normal of a point and the plane normal} + \cgalParamDescription{Shape detection: maximum angle in degrees between the normal of a point and the plane normal} \cgalParamType{`GeomTraits::FT`} - \cgalParamDefault{25 degrees} + \cgalParamDefault{15 degrees} \cgalParamNEnd \cgalParamNBegin{minimum_region_size} - \cgalParamDescription{minimum number of 3D points a region must have} + \cgalParamDescription{Shape detection: minimum number of 3D points a region must have} \cgalParamType{`std::size_t`} \cgalParamDefault{1% of input points} \cgalParamNEnd \cgalParamNBegin{angle_tolerance} - \cgalParamDescription{maximum allowed angle in degrees between plane normals used for parallelism, orthogonality, and axis symmetry} + \cgalParamDescription{Shape regularization: maximum allowed angle in degrees between plane normals used for parallelism, orthogonality, and axis symmetry} \cgalParamType{`GeomTraits::FT`} \cgalParamDefault{5 degrees} \cgalParamNEnd \cgalParamNBegin{maximum_offset} - \cgalParamDescription{maximum allowed orthogonal distance between two parallel planes such that they are considered to be coplanar} + \cgalParamDescription{Shape regularization: maximum allowed orthogonal distance between two parallel planes such that they are considered to be coplanar} \cgalParamType{`GeomTraits::FT`} - \cgalParamDefault{0.02 unit length} + \cgalParamDefault{0.5% of bounding box diagonal} \cgalParamNEnd \cgalParamNBegin{regularize_parallelism} - \cgalParamDescription{indicates whether parallelism should be regularized or not} + \cgalParamDescription{Shape regularization: indicates whether parallelism should be regularized or not} \cgalParamType{boolean} - \cgalParamDefault{true} + \cgalParamDefault{false} \cgalParamNEnd \cgalParamNBegin{regularize_orthogonality} - \cgalParamDescription{indicates whether orthogonality should be regularized or not} + \cgalParamDescription{Shape regularization: indicates whether orthogonality should be regularized or not} \cgalParamType{boolean} - \cgalParamDefault{true} + \cgalParamDefault{false} \cgalParamNEnd \cgalParamNBegin{regularize_coplanarity} - \cgalParamDescription{indicates whether coplanarity should be regularized or not} + \cgalParamDescription{Shape regularization: indicates whether coplanarity should be regularized or not} \cgalParamType{boolean} \cgalParamDefault{true} \cgalParamNEnd \cgalParamNBegin{regularize_axis_symmetry} - \cgalParamDescription{indicates whether axis symmetry should be regularized or not} + \cgalParamDescription{Shape regularization: indicates whether axis symmetry should be regularized or not} \cgalParamType{boolean} - \cgalParamDefault{true} + \cgalParamDefault{false} \cgalParamNEnd \cgalParamNBegin{symmetry_direction} - \cgalParamDescription{an axis for symmetry regularization} + \cgalParamDescription{Shape regularization: an axis for symmetry regularization} \cgalParamType{`GeomTraits::Vector_3`} \cgalParamDefault{Z axis that is `GeomTraits::Vector_3(0, 0, 1)`} \cgalParamNEnd - \cgalParamNBegin{estimate_ground} - \cgalParamDescription{Estimates a horizontal ground plane within the detected shapes. Cells in the partition below the ground plane receive a weight to be labelled as solid. The z axis is considered as vertical upwards pointing.} - \cgalParamType{bool} - \cgalParamDefault{false} - \cgalParamNEnd \cgalNamedParamsEnd */ @@ -205,7 +186,7 @@ public: m_point_map = Point_set_processing_3_np_helper::get_point_map(m_points, np); m_normal_map = Point_set_processing_3_np_helper::get_normal_map(m_points, np); - create_planar_shapes(estimate_ground, np); + create_planar_shapes(np); CGAL_assertion(m_planes.size() == m_polygons.size()); CGAL_assertion(m_polygons.size() == m_region_map.size()); @@ -214,10 +195,10 @@ public: } /*! - \brief Retrieves the detected shapes. + \brief Retrieves the support planes of the detected shapes. @return - vector with a plane equation for each detected planar shape. + vector with a `Plane_3` for each detected planar shape. \pre `shape detection performed` */ @@ -229,7 +210,7 @@ public: \brief Retrieves the indices of detected shapes. @return - indices into `input_range` for each detected planar shape. + indices into `points` for each detected planar shape. \pre `shape detection performed` */ @@ -292,12 +273,14 @@ public: \pre `partition created` */ - const Kinetic_shape_partition_3& partition() const { + const Kinetic_shape_partition_3& kinetic_partition() const { return m_kinetic_partition; } /*! - \brief Uses graph-cut to solve an solid/empty labeling of the volumes of the kinetic partition and provides the reconstructed surface as a list of indexed polygons. + \brief Uses graph-cut to solve an inside/outside labeling of the volumes of the kinetic partition and provides the reconstructed surface as a list of indexed polygons. + Estimates a horizontal ground plane within the detected shapes. Cells in the partition below the ground plane receive a weight to be labeled as inside. + The z axis is considered as vertical upwards pointing. \tparam OutputPointIterator an output iterator taking Point_3. @@ -317,15 +300,66 @@ public: \pre `partition created` */ template - void reconstruct(FT beta, OutputPointIterator pit, OutputPolygonIterator polyit) { + void reconstruct_with_ground(FT beta, OutputPointIterator pit, OutputPolygonIterator polyit) { KSR_3::Graphcut gc(beta); + // add ground consideration here + + gc.solve(m_face_neighbors_lcc, m_face_area_lcc, m_cost_matrix, m_labels); + + reconstructed_model_polylist_lcc(pit, polyit); + } + + /*! + \brief Uses graph-cut to solve an inside/outside labeling of the volumes of the kinetic partition and provides the reconstructed surface as a list of indexed polygons. + The `external_nodes` parameter allows to indicate the preferred labels for faces on the bounding box. + + \tparam OutputPointIterator + an output iterator taking `Point_3`. + + \tparam OutputPolygonIterator + an output iterator taking polygon indices `std::vector`. + + \param beta + trades the impact of the data term for impact of the regularization term. Should be in the range [0, 1). + + \param external_nodes + adds label preference for the faces on the bounding box. Bounding box sides without preset label are chosen by the graph-cut. + Setting `external_nodes[ZMIN] = true` sets the inside label as the prefered label for the ZMIN side of the bounding box. + + \param pit + output iterator to receive the vertices of the reconstructed surface. + + \param polyit + output iterator to store all polygonal faces of the reconstructed surface. + + \pre `partition created` + */ + template + void reconstruct(FT beta, std::map external_nodes, OutputPointIterator pit, OutputPolygonIterator polyit) { + KSR_3::Graphcut gc(beta); + + // add node consideration here + gc.solve(m_face_neighbors_lcc, m_face_area_lcc, m_cost_matrix, m_labels); reconstructed_model_polylist_lcc(pit, polyit); } private: + using Point_2 = typename Kernel::Point_2; + using Vector_3 = typename Kernel::Vector_3; + using Triangle_2 = typename Kernel::Triangle_2; + + using Indices = std::vector; + using Polygon_3 = std::vector; + + using Region_type = CGAL::Shape_detection::Point_set::Least_squares_plane_fit_region_for_point_set; + using Neighbor_query = CGAL::Shape_detection::Point_set::K_neighbor_query_for_point_set; + using Sorting = CGAL::Shape_detection::Point_set::Least_squares_plane_fit_sorting_for_point_set; + using Region_growing = CGAL::Shape_detection::Region_growing; + using From_exact = typename CGAL::Cartesian_converter; + struct Vertex_info { FT z = FT(0); }; struct Face_info { }; @@ -1596,7 +1630,7 @@ private: } template - void create_planar_shapes(bool estimate_ground, const NamedParameters& np) { + void create_planar_shapes(const NamedParameters& np) { if (m_points.size() < 3) { if (m_verbose) std::cout << "* no points found, skipping" << std::endl; @@ -1704,8 +1738,8 @@ private: } } + // Estimate ground plane by finding a low mostly horizontal plane if (estimate_ground) { - // How to estimate ground plane? Find low z peak std::vector candidates; FT low_z_peak = (std::numeric_limits::max)(); FT bbox_min[] = { (std::numeric_limits::max)(), (std::numeric_limits::max)(), (std::numeric_limits::max)() }; diff --git a/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h b/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h index 83d4ab929c0..b5826683c52 100644 --- a/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h +++ b/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h @@ -262,7 +262,6 @@ CGAL_add_named_parameter(maximum_normal_deviation_t, maximum_normal_deviation, m // kinetic parameters CGAL_add_named_parameter(bbox_dilation_ratio_t, bbox_dilation_ratio, bbox_dilation_ratio) CGAL_add_named_parameter(reorient_bbox_t, reorient_bbox, reorient_bbox) -CGAL_add_named_parameter(estimate_ground_t, estimate_ground, estimate_ground) CGAL_add_named_parameter(debug_t, debug, debug) CGAL_add_named_parameter(angle_tolerance_t, angle_tolerance, angle_tolerance) CGAL_add_named_parameter(max_octree_depth_t, max_octree_depth, max_octree_depth)