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

Add Weighted Sample Elimination #8554

Open
wants to merge 24 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 18 commits
Commits
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
12 changes: 12 additions & 0 deletions Documentation/doc/biblio/cgal_manual.bib
Original file line number Diff line number Diff line change
Expand Up @@ -3310,6 +3310,18 @@ @techreport{cgal:hssz-gmcabonbc-97
year={1997}
}

@article{cgal:y-sefpdss,
author = {Yuksel, Cem},
title = {Sample Elimination for Generating Poisson Disk Sample Sets},
journal = {Computer Graphics Forum},
volume = {34},
number = {2},
pages = {25-32},
doi = {https://doi.org/10.1111/cgf.12538},
url = {https://onlinelibrary.wiley.com/doi/abs/10.1111/cgf.12538},
year = {2015}
}

% ----------------------------------------------------------------------------
% END OF BIBFILE
% ----------------------------------------------------------------------------
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ format.
\cgalPkgDescriptionBegin{Point Set Processing,PkgPointSetProcessing3}
\cgalPkgPicture{point_set_processing_detail.png}
\cgalPkgSummaryBegin
\cgalPkgAuthors{Pierre Alliez, Simon Giraudot, Clément Jamin, Florent Lafarge, Quentin Mérigot, Jocelyn Meyron, Laurent Saboret, Nader Salman, Shihao Wu, and Necip Fazil Yildiran}
\cgalPkgAuthors{Pierre Alliez, Simon Giraudot, Clément Jamin, Florent Lafarge, Quentin Mérigot, Jocelyn Meyron, Sven Oesau, Laurent Saboret, Nader Salman, Shihao Wu, and Necip Fazil Yildiran}
\cgalPkgDesc{This \cgal component implements methods to analyze and process unorganized point sets. The input is an unorganized point set, possibly with normal attributes (unoriented or oriented). The point set can be analyzed to measure its average spacing, and processed through functions devoted to the simplification, outlier removal, smoothing, normal estimation, normal orientation, feature edges estimation and registration.}
\cgalPkgManuals{Chapter_Point_Set_Processing,PkgPointSetProcessing3Ref}
\cgalPkgSummaryEnd
Expand Down Expand Up @@ -75,6 +75,7 @@ format.
- `CGAL::vcm_estimate_normals()`
- `CGAL::vcm_is_on_feature_edge()`
- `CGAL::structure_point_set()`
- `CGAL::poisson_eliminate()`

\cgalCRPSection{I/O (All Formats)}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -650,7 +650,7 @@ functions in this component.)
\section Point_set_processing_3Simplification Simplification


Four simplification functions are devised to reduce an input point set.
Five simplification functions are devised to reduce an input point set.

Function `random_simplify_point_set()` randomly deletes a
user-specified fraction of points from the input point set. This
Expand All @@ -674,6 +674,10 @@ Function `wlop_simplify_and_regularize_point_set()` not only simplifies,
but also regularizes downsampled points. This is an implementation of
the Weighted Locally Optimal Projection (WLOP) algorithm \cgalCite{wlop-2009}.

Function `poisson_eliminate()` is a greedy down sampling method that generates
a subset of the input points with poisson disk property. This is an implementation of the
Sample Elimination for Generating Poisson Disk Sample Sets \cgalCite{cgal:y-sefpdss}.
soesau marked this conversation as resolved.
Show resolved Hide resolved


\subsection Point_set_processing_3Example_grid_simplification Grid Simplification Example

Expand Down Expand Up @@ -755,6 +759,43 @@ for more details. We provide below a speed-up chart generated using the parallel
Parallel WLOP speed-up, compared to the sequential version of the algorithm.
\cgalFigureEnd

\subsection Point_set_processing_3PoissonElimination Poisson Sample Elimination
The poisson sample elimination is a greedy downsampling method that calculates a weight for each input point based on the density of its local neighborhood. Subsequently, the point with the highest weight is removed and the weights of the remaining points around it are updated until the target size is reached. A custom function to calculate the weight of a point can be provided.

The poisson sample elimination has the following parameters:
soesau marked this conversation as resolved.
Show resolved Hide resolved
- *dimensions*: The dimensions parameter specifies the dimension of the sampling domain of the point cloud, e.g., 2 if the point cloud is sampled from a surface, while the ambient dimension is typically 3. The default value is 2.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- *dimensions*: The dimensions parameter specifies the dimension of the sampling domain of the point cloud, e.g., 2 if the point cloud is sampled from a surface, while the ambient dimension is typically 3. The default value is 2.
- *dimension*: The dimension of the sampling domain of the point cloud, e.g., 2 if the point cloud is sampled from a surface, while the ambient dimension is typically 3. The default value is 2.

- *weight_function*: A custom *weight_function* can be provided to calculate the weight between two points. The type of the functor is as follows:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- *weight_function*: A custom *weight_function* can be provided to calculate the weight between two points. The type of the functor is as follows:
- *weight_function*: A custom function can be provided to calculate the weight between two points. The type of the functor is as follows:

\code{.cpp}
double(*func)(const Point &p, const Point &n, double squared_distance, double r_max)
\endcode
The default weight is \f$\left(1 - \frac{d_{p,n}}{2r_{max}}\right)^8\f$ with \f$d_{p,n}\f$ being the distance between the point p and its neighbor n.
- \f$r_{max}\f$: The \f$r_{max}\f$ parameter specifies the radius of the neighborhood, i.e., the neighboring points that are used to calculate the weight of a point. r_max has to be provided if a custom *weight_function* is used. Only points within a distance of \f$r_{max}\f$ are used to calculate the weight of a point. A large value can thus cause a large running time. The default is calculated based in the bounding volume \f$V\f$ of the input points, the *dimensions* parameter and the number of input points \f$N\f$:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- \f$r_{max}\f$: The \f$r_{max}\f$ parameter specifies the radius of the neighborhood, i.e., the neighboring points that are used to calculate the weight of a point. r_max has to be provided if a custom *weight_function* is used. Only points within a distance of \f$r_{max}\f$ are used to calculate the weight of a point. A large value can thus cause a large running time. The default is calculated based in the bounding volume \f$V\f$ of the input points, the *dimensions* parameter and the number of input points \f$N\f$:
- \f$r_{max}\f$: The \f$r_{max}\f$ parameter specifies the radius of the neighborhood, i.e., the neighboring points that are used to calculate the weight of a point. \f$r_{max}\f$ has to be provided if a custom *weight_function* is used. Only points within a distance of \f$r_{max}\f$ are used to calculate the weight of a point. A large value can thus cause a large running time. The default is calculated based in the bounding volume \f$V\f$ of the input points, the *dimensions* parameter and the number of input points \f$N\f$:


\f$dimensions = 2:\qquad\f$ \f$r_{max} = \sqrt{\frac{V}{2\sqrt{3}N}}\f$

\f$dimensions = 3:\qquad\f$ \f$r_{max} = \sqrt{\frac{V}{4\sqrt{2}N}}\f$

- *progressive*: The output points of the function can be reordered to be progressive. A progressive ordering will increase the running time by a factor of at most 2 as the function is internally applied several times on increasingly smaller subsets. The default value is false.

\cgalFigureAnchor{Point_set_processing_3figPoisson_elimination}
<center>
<img src="poisson_elimination.png" style="max-width:80%;"/>
</center>
\cgalFigureCaptionBegin{Point_set_processing_3figPoisson_elimination}
Poisson elimination on point cloud with 21k points and results with \f$\frac{1}{2}\f$, \f$\frac{1}{4}\f$ and \f$\frac{1}{8}\f$ of the input size.
\cgalFigureCaptionEnd

\subsubsection Point_set_processing_3Example_poisson_elimination Poisson Sample Elimination Example

The following example reads a point cloud, applies poisson elimination to reduce the point cloud to \f$\frac{1}{5}\f$ of its size and saves it into a file.

\cgalExample{Point_set_processing_3/poisson_eliminate_example.cpp}

\subsubsection Point_set_processing_3Example_poisson_elimination Poisson Sample Elimination from Mesh Example

The following example first samples a point cloud from a surface mesh and then uses poisson elimination to provide an evenly sampled point cloud.

\cgalExample{Point_set_processing_3/poisson_eliminate_from_mesh_example.cpp}

\section Point_set_processing_3Smoothing Smoothing

Expand Down Expand Up @@ -1009,7 +1050,7 @@ as well as the normal and feature edge estimation functions based on it.
Florent Lafarge with the help of Simon Giraudot contributed the point set structuring algorithm.
Started from GSoC'2019, Necip Fazil Yildiran with the help of Nicolas Mellado and Simon Giraudot introduced the wrappers for OpenGR and PointMatcher
libraries that perform registration on two point sets.

Poisson sample elimination is a reimplementation by Sven Oesau based on \cgalCite{cgal:y-sefpdss}. The original source code <a href="https://github.com/cemyuksel/cyCodeBase/">cyCodeBase</a> was used as a reference.

*/
} /* namespace CGAL */
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,6 @@
\example Point_set_processing_3/edges_example.cpp
\example Point_set_processing_3/structuring_example.cpp
\example Point_set_processing_3/callback_example.cpp
\example Point_set_processing_3/poisson_eliminate_example.cpp
\example Point_set_processing_3/poisson_eliminate_from_mesh_example.cpp
*/
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ foreach(
edge_aware_upsample_point_set_example
structuring_example
read_ply_points_with_colors_example
write_ply_points_example)
write_ply_points_example
poisson_eliminate_example
poisson_eliminate_from_mesh_example)
create_single_source_cgal_program("${target}.cpp")
target_link_libraries(${target} PRIVATE ${CGAL_libs})
endforeach()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#include <vector>
#include <iostream>
#include <fstream>
soesau marked this conversation as resolved.
Show resolved Hide resolved
#include <filesystem>
soesau marked this conversation as resolved.
Show resolved Hide resolved
#include <string>

#include <CGAL/Simple_cartesian.h>
#include <CGAL/poisson_eliminate.h>
#include <CGAL/IO/write_points.h>
#include <CGAL/IO/read_points.h>

typedef CGAL::Simple_cartesian<double> K;
typedef K::Point_3 Point_3;

void sampling(const std::string& filename, double size_factor = 0.2) {
if (size_factor >= 1.0) {
std::cout << "usage poisson_eliminate_example filename size_factor" << std::endl << "0 < size_factor < 1" << std::endl;
return;
}
std::vector<Point_3> points;

if (!CGAL::IO::read_points(
filename,
std::back_inserter(points))) {

std::cerr << "Error: cannot read file!" << std::endl;
return;
}

std::size_t target_size = std::size_t(points.size() * size_factor);
std::vector<Point_3> output;
output.reserve(target_size);

CGAL::poisson_eliminate(points, target_size, std::back_inserter(output));

CGAL::IO::write_points("out.xyz", output, CGAL::parameters::stream_precision(17));
}


int main(int argc, char* argv[])
{
if (argc < 2)
sampling(CGAL::data_file_path("points_3/radar.xyz"));
else if (argc < 3)
sampling(argv[1]);
else if (argc < 4)
sampling(argv[1], std::atof(argv[2]));

return 0;
}
Loading
Loading