Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

local feature size for point set processing #8006

Open
wants to merge 39 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
ecd26eb
lfs-v1
bizerfr Jan 22, 2024
c5ce18e
remove comments
bizerfr Jan 29, 2024
ed49e41
cmakelists for lfs_example
bizerfr Jan 29, 2024
772f36f
code style
bizerfr Jan 29, 2024
7240a15
code style-2
bizerfr Jan 29, 2024
bf2c0ed
fixes so that it compiles
afabri Jan 30, 2024
aa9f1cb
Pass property map as parameter
afabri Feb 5, 2024
c885e08
lfs_map v2
bizerfr Feb 5, 2024
7d4d040
reference
bizerfr Feb 5, 2024
9b1788d
doxygen & point_set example
bizerfr Feb 5, 2024
2baa49b
change reference back to copy
bizerfr Feb 5, 2024
f79f71a
put lfs_map in the back
bizerfr Feb 5, 2024
e722097
CGAL::data_file_path(points_3/kitten.xyz
bizerfr Feb 5, 2024
d9d84af
Update Point_set_processing_3/examples/Point_set_processing_3/lfs-exa…
bizerfr Feb 5, 2024
3607da4
Update Point_set_processing_3/examples/Point_set_processing_3/lfs-exa…
bizerfr Feb 5, 2024
b28da76
doxygen
bizerfr Feb 5, 2024
c2afd8c
cmakelists for examples
bizerfr Feb 5, 2024
962d3b1
cmakelists & doxygen
bizerfr Feb 5, 2024
5afb5af
trivial fixes
afabri Feb 5, 2024
4da4046
point_push_map instead of point_map, otherwise, read points will not …
bizerfr Feb 5, 2024
d20626d
Use CGAL::IO::read_point_set()
afabri Feb 6, 2024
2a18b4e
check normals are normalized or not
bizerfr Feb 6, 2024
6b3af0d
fix lfs_example_tuple
bizerfr Feb 6, 2024
d76a894
remove trailing whitespace
bizerfr Feb 6, 2024
e4b0152
remove trailing whitespace
bizerfr Feb 6, 2024
73fffec
remove trailing whitespace
bizerfr Feb 6, 2024
8733f9b
remove trailing whitespace
bizerfr Feb 6, 2024
78499bb
read_point_set() adds the property
afabri Feb 6, 2024
0358747
doc fixes
afabri Feb 6, 2024
8e44202
Update Point_set_processing_3/doc/Point_set_processing_3/Point_set_pr…
bizerfr Feb 6, 2024
3cb7ed6
Update Point_set_processing_3/include/CGAL/estimate_lfs.h
bizerfr Feb 6, 2024
9c7cb50
rename header file
bizerfr Feb 6, 2024
9a8f017
fix doc
bizerfr Feb 6, 2024
793b3a3
smooth
bizerfr Feb 29, 2024
d935d2b
doxygen
bizerfr Feb 29, 2024
7207ebc
test
bizerfr Feb 29, 2024
71ceedc
remove trailing whitespaces
bizerfr Feb 29, 2024
03b3d6c
remove trailing whilespace
bizerfr Feb 29, 2024
a81bfbf
remove trailing whilespace
bizerfr Feb 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ format.
- `CGAL::vcm_estimate_normals()`
- `CGAL::vcm_is_on_feature_edge()`
- `CGAL::structure_point_set()`
- `CGAL::estimate_local_feature_size()`

\cgalCRPSection{I/O (All Formats)}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,12 @@ typedef CGAL::First_of_pair_property_map<PointVectorPair> Point_map;
typedef CGAL::Second_of_pair_property_map<PointVectorPair> Vector_map;

CGAL::jet_estimate_normals
<CGAL::Parallel_tag> // concurrency tag
(points, // input range of points
12, // parameter: number of neighbors
CGAL::parameters:: // named parameters:
point_map (Point_map()). // * point map
normal_map (Vector_map())); // * normal map
<CGAL::Parallel_tag> // concurrency tag
(points, // input range of points
12, // parameter: number of neighbors
CGAL::parameters:: // named parameters:
point_map (Point_map()). // * point map
normal_map (Vector_map())); // * normal map
\endcode

This API was introduced in \cgal 4.12. Please refer to the
Expand Down Expand Up @@ -116,10 +116,10 @@ std::vector<PointVectorPair> points;

// Old pre-CGAL 4.12 API
CGAL::jet_estimate_normals<Concurrency_tag>
(points.begin(), points.end(),
CGAL::First_of_pair_property_map<PointVectorPair>(),
CGAL::Second_of_pair_property_map<PointVectorPair>(),
12); // Number of neighbors
(points.begin(), points.end(),
CGAL::First_of_pair_property_map<PointVectorPair>(),
CGAL::Second_of_pair_property_map<PointVectorPair>(),
12); // Number of neighbors
\endcode

The pair of iterators is replaced by a range and the optional
Expand All @@ -133,10 +133,10 @@ std::vector<PointVectorPair> points;

// New API
CGAL::jet_estimate_normals<Concurrency_tag>
(points,
12, // Number of neighbors
CGAL::parameters::point_map (CGAL::First_of_pair_property_map<PointVectorPair>()).
normal_map (CGAL::Second_of_pair_property_map<PointVectorPair>()));
(points,
12, // Number of neighbors
CGAL::parameters::point_map (CGAL::First_of_pair_property_map<PointVectorPair>()).
normal_map (CGAL::Second_of_pair_property_map<PointVectorPair>()));
\endcode

Please refer to the [Reference Manual](@ref PkgPointSetProcessing3Ref) for
Expand Down Expand Up @@ -524,66 +524,66 @@ above-mentioned example was used.
\cgalFigureAnchor{Point_set_processing_3tableRegistrationRegistration_visualization_table}
<table>
<tr>
<th> </th>
<th>Scan 1 </th>
<th>Scan 1 (possibly transformed, green) and Scan 2 (the reference, red)</th>
<th> </th>
<th>Scan 1 </th>
<th>Scan 1 (possibly transformed, green) and Scan 2 (the reference, red)</th>
</tr>
<tr>
<th>Unregistered</th>
<td>
\cgalFigureBegin{Point_set_processing_3figRegistrationUnregistered_hippo2_view1, registration_view1_hippo2_unregistered.png}
\cgalFigureEnd
</td>
<td>
\cgalFigureBegin{Point_set_processing_3figRegistrationUnregistered_hippo1_hippo2_view1, registration_view1_hippo1_hippo2_unregistered.png}
\cgalFigureEnd
</td>
<th>Unregistered</th>
<td>
\cgalFigureBegin{Point_set_processing_3figRegistrationUnregistered_hippo2_view1, registration_view1_hippo2_unregistered.png}
\cgalFigureEnd
</td>
<td>
\cgalFigureBegin{Point_set_processing_3figRegistrationUnregistered_hippo1_hippo2_view1, registration_view1_hippo1_hippo2_unregistered.png}
\cgalFigureEnd
</td>
</tr>
<tr>
<th>
Registered
using
%OpenGR
</th>
<td>
\cgalFigureBegin{Point_set_processing_3figRegistrationOpenGR_hippo2_view1, registration_view1_hippo2_opengr.png}
\cgalFigureEnd
</td>
<td>
\cgalFigureBegin{Point_set_processing_3figRegistrationOpenGR_hippo1_hippo2_view1, registration_view1_hippo1_hippo2_opengr.png}
\cgalFigureEnd
</td>
<th>
Registered
using
%OpenGR
</th>
<td>
\cgalFigureBegin{Point_set_processing_3figRegistrationOpenGR_hippo2_view1, registration_view1_hippo2_opengr.png}
\cgalFigureEnd
</td>
<td>
\cgalFigureBegin{Point_set_processing_3figRegistrationOpenGR_hippo1_hippo2_view1, registration_view1_hippo1_hippo2_opengr.png}
\cgalFigureEnd
</td>
</tr>
<tr>
<th>
Registered
using
PointMatcher
</th>
<td>
\cgalFigureBegin{Point_set_processing_3figRegistrationPointMatcher_hippo2_view1, registration_view1_hippo2_pointmatcher.png}
\cgalFigureEnd
</td>
<td>
\cgalFigureBegin{Point_set_processing_3figRegistrationPointMatcher_hippo1_hippo2_view1, registration_view1_hippo1_hippo2_pointmatcher.png}
\cgalFigureEnd
</td>
<th>
Registered
using
PointMatcher
</th>
<td>
\cgalFigureBegin{Point_set_processing_3figRegistrationPointMatcher_hippo2_view1, registration_view1_hippo2_pointmatcher.png}
\cgalFigureEnd
</td>
<td>
\cgalFigureBegin{Point_set_processing_3figRegistrationPointMatcher_hippo1_hippo2_view1, registration_view1_hippo1_hippo2_pointmatcher.png}
\cgalFigureEnd
</td>
</tr>
<tr>
<th>
Registered
using
OpenGR+PointMatcher
Pipeline
</th>
<td>
\cgalFigureBegin{Point_set_processing_3figRegistrationPipeline_hippo2_view1, registration_view1_hippo2_opengr_pointmatcher_pipeline.png}
\cgalFigureEnd
</td>
<td>
\cgalFigureBegin{Point_set_processing_3figRegistrationPipeline_hippo1_hippo2_view1, registration_view1_hippo1_hippo2_opengr_pointmatcher_pipeline.png}
\cgalFigureEnd
</td>
<th>
Registered
using
OpenGR+PointMatcher
Pipeline
</th>
<td>
\cgalFigureBegin{Point_set_processing_3figRegistrationPipeline_hippo2_view1, registration_view1_hippo2_opengr_pointmatcher_pipeline.png}
\cgalFigureEnd
</td>
<td>
\cgalFigureBegin{Point_set_processing_3figRegistrationPipeline_hippo1_hippo2_view1, registration_view1_hippo1_hippo2_opengr_pointmatcher_pipeline.png}
\cgalFigureEnd
</td>
</tr>
</table>
\cgalFigureCaptionBegin{Point_set_processing_3tableRegistrationRegistration_visualization_table}
Expand Down Expand Up @@ -698,15 +698,15 @@ in two until each cluster's size is less than the parameter `size`.
\cgalFigureBegin{Point_set_processing_3figHierarchy_simplification_size, hierarchical_clustering_size.jpg}
Input point set and hierarchy simplification with different `size`
parameter: \f$10\f$, \f$100\f$ and \f$1000\f$. In the 3 cases,
`var_max`\f$=1/3\f$. \cgalFigureEnd
`var_max`\f$=1/3\f$. \cgalFigureEnd


\subsubsection Point_set_processing_3Hierarchy_simplification_parameter_var_max Parameter: var_max
In addition to the size parameter, a variation parameter allows to
increase simplification in monotonous regions. For each cluster, a
surface variation measure is computed using the sorted eigenvalues of
the covariance matrix: \f[ \sigma(p) = \frac{\lambda_0}{\lambda_0 +
\lambda_1 + \lambda_2}. \f]
\lambda_1 + \lambda_2}. \f]

This function goes from \f$0\f$ if the cluster is coplanar to
\f$1/3\f$ if it is fully isotropic. If a cluster's variation is above
Expand All @@ -717,7 +717,7 @@ point set.
\cgalFigureBegin{Point_set_processing_3figHierarchical_clustering_var_max, hierarchical_clustering_var_max.jpg}
Input point set and hierarchy simplification with different `var_max`
parameter: \f$0.00001\f$, \f$0.001\f$ and \f$0.1\f$. In the 3 cases,
`size`\f$=1000\f$. \cgalFigureEnd
`size`\f$=1000\f$. \cgalFigureEnd


\subsection Point_set_processing_3Example_wlop WLOP Simplification Example
Expand Down Expand Up @@ -926,6 +926,30 @@ The following example reads a point set from a file, estimates the
points that are on sharp edges:
\cgalExample{Point_set_processing_3/edges_example.cpp}

\section Point_set_processing_3LFSEstimation Local Feature Size Estimation

Function `estimate_local_feature_size()` can estimate the local feature size for each point
by giving a raw point set. If the points have no normals, the function also estimates normals using jet fitting.
The function works by calculating the curvature and shape diameter.
Then, the local feature size will be the minimum of the curvature radius and half of the shape diameter.

Function `median_filter_smoothing_lfs()` performs the median filter to smooth the estimated local feature size.

Function `lipschitz_continuity_smoothing_lfs()` smooth the local feature size
based on the property of 1-Lipschitz continuity of the local feature size function.

Function `laplacian_smoothing_lfs()` performs the laplacian smoothing to smooth the estimated local feature size.

\subsection Point_set_processing_3Example_LFS_point_set Point_set_3 Example

The following example uses the `CGAL::Point_set_3<Point,Vector>` to store a point cloud and estimates the local feature size for each point:
\cgalExample{Point_set_processing_3/lfs_example_pointset.cpp}

\subsection Point_set_processing_3Example_LFS_tuple std::vector Example

The following example uses the `std::vector` to store a point cloud and estimates the local feature size for each point:
\cgalExample{Point_set_processing_3/lfs_example_tuple.cpp}


\section Point_set_processing_3Structuring Structuring

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
\example Point_set_processing_3/bilateral_smooth_point_set_example.cpp
\example Point_set_processing_3/edge_aware_upsample_point_set_example.cpp
\example Point_set_processing_3/edges_example.cpp
\example Point_set_processing_3/lfs_example_tuple.cpp
\example Point_set_processing_3/lfs_example_pointset.cpp
\example Point_set_processing_3/structuring_example.cpp
\example Point_set_processing_3/callback_example.cpp
*/
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ if(TARGET CGAL::Eigen3_support)
# Executables that require Eigen
foreach(
target
lfs_example_tuple
lfs_example_pointset
jet_smoothing_example
normal_estimation
clustering_example
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/estimate_local_feature_size.h>
#include <CGAL/IO/read_points.h>
#include <CGAL/Point_set_3.h>
#include <CGAL/Point_set_3/IO.h>

// types
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef Kernel::FT FT;
typedef Kernel::Point_3 Point;
typedef Kernel::Vector_3 Vector;

typedef CGAL::Point_set_3<Point, Vector> Point_set;
typedef Point_set::Property_map<Point> Point_map;
typedef Point_set::Property_map<FT> FT_map;


// Concurrency
typedef CGAL::Parallel_if_available_tag Concurrency_tag;

int main(void)
{
// read xyz
const std::string filename = CGAL::data_file_path("points_3/kitten.xyz");

Point_set point_set;

FT_map lfs_map;
boost::tie (lfs_map, boost::tuples::ignore) = point_set.add_property_map<FT> ("LFS", 0.);

if (!CGAL::IO::read_point_set(filename, point_set))
{
std::cerr << "Error: cannot read file " << filename<< std::endl;
return EXIT_FAILURE;
}


unsigned int jet_k = 24;
std::size_t N_rays = 60;
FT apex_angle = 30;
CGAL::estimate_local_feature_size<Concurrency_tag>(point_set, jet_k, N_rays, apex_angle, lfs_map,
CGAL::parameters::point_map(point_set.point_map())
.normal_map(point_set.normal_map()));

// optionally, smooth the raw LFS values for other purposes
unsigned int median_filter_k = 11, median_filter_T = 5;
CGAL::median_filter_smoothing_lfs<Concurrency_tag>(point_set, median_filter_k, median_filter_T, lfs_map,
CGAL::parameters::point_map(point_set.point_map()));

unsigned int lipschitz_continuity_smoothing_k = 11;
FT lipschitz = 1.0;
CGAL::lipschitz_continuity_smoothing_lfs<Concurrency_tag>(point_set, lipschitz_continuity_smoothing_k, lipschitz, lfs_map,
CGAL::parameters::point_map(point_set.point_map()));

unsigned int laplacian_smoothing_k = 11, laplacian_smoothing_T = 5;
FT laplacian_smoothing_lambda = 1.0;
CGAL::laplacian_smoothing_lfs<Concurrency_tag>(point_set, laplacian_smoothing_k, laplacian_smoothing_T, laplacian_smoothing_lambda, lfs_map,
CGAL::parameters::point_map(point_set.point_map()));

// print
for (Point_set::iterator it = point_set.begin(); it != point_set.end(); ++ it)
{
// Point p = point_set.point(*it);
// Vector n = point_set.normal(*it);
FT lfs = lfs_map[*it];
std::cout << lfs << std::endl;
}

return EXIT_SUCCESS;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/estimate_local_feature_size.h>
#include <CGAL/IO/read_points.h>

#include <vector>
#include <utility>
#include <tuple>

// types
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef Kernel::FT FT;
typedef Kernel::Point_3 Point;
typedef Kernel::Vector_3 Vector;

typedef std::tuple<Point, Vector, FT> Point_with_normal_and_lfs;

// Concurrency
typedef CGAL::Parallel_if_available_tag Concurrency_tag;

int main(void)
{
// read xyz
const std::string filename = CGAL::data_file_path("points_3/kitten.xyz");

std::vector<Point_with_normal_and_lfs> points;
if(!CGAL::IO::read_points(filename,
std::back_inserter(points),
CGAL::parameters::point_map(CGAL::Nth_of_tuple_property_map<0, Point_with_normal_and_lfs>())
.normal_map(CGAL::Nth_of_tuple_property_map<1, Point_with_normal_and_lfs>())))
{
std::cerr << "Error: cannot read file " << filename<< std::endl;
return EXIT_FAILURE;
}

unsigned int jet_k = 24;
std::size_t N_rays = 60;
FT apex_angle = 30;
auto lfs_map = CGAL::Nth_of_tuple_property_map<2, Point_with_normal_and_lfs>();
CGAL::estimate_local_feature_size<Concurrency_tag>(points,
jet_k,
N_rays,
apex_angle,
lfs_map,
CGAL::parameters::point_map(CGAL::Nth_of_tuple_property_map<0, Point_with_normal_and_lfs>())
.normal_map(CGAL::Nth_of_tuple_property_map<1, Point_with_normal_and_lfs>()));

// optionally, smooth the raw LFS values for other purposes
unsigned int median_filter_k = 11, median_filter_T = 5;
CGAL::median_filter_smoothing_lfs<Concurrency_tag>(points, median_filter_k, median_filter_T, lfs_map,
CGAL::parameters::point_map(CGAL::Nth_of_tuple_property_map<0, Point_with_normal_and_lfs>()));

unsigned int lipschitz_continuity_smoothing_k = 11;
FT lipschitz = 1.0; // 1 lipschitz_continuity for LFS function
CGAL::lipschitz_continuity_smoothing_lfs<Concurrency_tag>(points, lipschitz_continuity_smoothing_k, lipschitz, lfs_map,
CGAL::parameters::point_map(CGAL::Nth_of_tuple_property_map<0, Point_with_normal_and_lfs>()));

unsigned int laplacian_smoothing_k = 11, laplacian_smoothing_T = 5;
FT laplacian_smoothing_lambda = 1.0;
CGAL::laplacian_smoothing_lfs<Concurrency_tag>(points,
laplacian_smoothing_k, laplacian_smoothing_T, laplacian_smoothing_lambda, lfs_map,
CGAL::parameters::point_map(CGAL::Nth_of_tuple_property_map<0, Point_with_normal_and_lfs>()));

// print
for (const auto &pts : points)
{
// Point p = std::get<0>(pts);
// Vector n = std::get<1>(pts);
FT lfs = std::get<2>(pts);
std::cout << lfs << std::endl;
}

return EXIT_SUCCESS;
}
Loading