Merge branch 'Classification-GF-old' into Classification-GF
|
|
@ -18,7 +18,7 @@ int main(int argc, char* argv[])
|
|||
std::ifstream in((argc>1)?argv[1]:"data/prim.off");
|
||||
in >> sm;
|
||||
|
||||
Mesh::Property_map<vertex_descriptor,int> ccmap;
|
||||
CGAL::Properties::Property_map<vertex_descriptor,int> ccmap;
|
||||
ccmap = sm.add_property_map<vertex_descriptor,int>("v:CC").first;
|
||||
|
||||
int num = connected_components(sm, ccmap);
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ int main(int, char* argv[])
|
|||
//std::cin >> P;
|
||||
std::ifstream in(argv[1]);
|
||||
in >> P;
|
||||
Mesh::Property_map<vertex_descriptor,vertex_descriptor> predecessor;
|
||||
CGAL::Properties::Property_map<vertex_descriptor,vertex_descriptor> predecessor;
|
||||
predecessor = P.add_property_map<vertex_descriptor,vertex_descriptor>("v:predecessor").first;
|
||||
|
||||
boost::prim_minimum_spanning_tree(P, predecessor, boost::root_vertex(*vertices(P).first));
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ int main(int argc, char* argv[])
|
|||
}
|
||||
|
||||
// the storage of a property map is in primal
|
||||
Mesh::Property_map<face_descriptor,int> fccmap;
|
||||
CGAL::Properties::Property_map<face_descriptor,int> fccmap;
|
||||
fccmap = primal.add_property_map<face_descriptor,int>("f:CC").first;
|
||||
int num = connected_components(finite_dual, fccmap);
|
||||
|
||||
|
|
@ -77,7 +77,7 @@ int main(int argc, char* argv[])
|
|||
std::cout << f << " in connected component " << fccmap[f] << std::endl;
|
||||
}
|
||||
|
||||
Mesh::Property_map<vertex_descriptor,int> vccmap;
|
||||
CGAL::Properties::Property_map<vertex_descriptor,int> vccmap;
|
||||
vccmap = primal.add_property_map<vertex_descriptor,int>("v:CC").first;
|
||||
num = connected_components(primal, vccmap);
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,256 @@
|
|||
namespace CGAL {
|
||||
/*!
|
||||
|
||||
\mainpage User Manual
|
||||
\anchor Chapter_Classification
|
||||
\cgalAutoToc
|
||||
\author Simon Giraudot
|
||||
|
||||
This component implements a generalization of the algorithm described in \cgalCite{cgal:lm-clscm-12}. It classifies a data set into a user-defined set of classes (such as ground, vegetation, buildings, etc.). A flexible API is provided so that the user can classify any type of data, compute its own local attributes on the point cloud and define its own classes based on these attributes.
|
||||
|
||||
\section Classification_Organization Package Organization
|
||||
|
||||
%Classification of point sets is achieved as follows:
|
||||
|
||||
- some analysis is performed on the input point set;
|
||||
- attributes are computed based on this analysis;
|
||||
- a set of classification types (for example: ground, building, vegetation) is defined by the user;
|
||||
- attributes are given weights and each pair of attribute/type is assigned a relationship;
|
||||
- classification is computed pointwise by minimizing an energy defined as the sum of the values taken by attributes on input points (which depend on the attribute/type relationship)
|
||||
- additional regularization can be used by smoothing either locally or globally through an Alpha Expansion approach.
|
||||
|
||||
This package is designed to be easily extended by the user: more specifically, attributes and types can be defined by the user to handle any data he/she needs to classify (although \cgal provides a predefined framework for common urban scenes).
|
||||
|
||||
\cgalFigureBegin{Classification_Organization,organization.png}
|
||||
Organization of the package.
|
||||
\cgalFigureEnd
|
||||
|
||||
\section Classification_structures Data Structures
|
||||
|
||||
\subsection Classification_analysis Analysis
|
||||
|
||||
%Classification is based on the computation of local attributes of points. These attributes often require precomputed analysis structures: such data structures might be shared by several attributes and are therefore computed separately.
|
||||
|
||||
\cgal provides the following structures:
|
||||
|
||||
- `CGAL::Classification::Point_set_neighborhood` stores spatial searching structures and provides adapted queries for points;
|
||||
- `CGAL::Classification::Local_eigen_analysis` precomputes covariance matrices on local neighborhood of points and stores the associated eigenvectors and eigenvalues;
|
||||
- `CGAL::Classification::Planimetric_grid` is a 2D grid used for digital terrain modeling.
|
||||
|
||||
The following code snippet shows how to instantiate such data structures from an input PLY point set (the full example is given at the end of the manual).
|
||||
|
||||
\snippet Classification/example_point_set_classification.cpp Analysis
|
||||
|
||||
\subsection Classification_attributes Attributes
|
||||
|
||||
Attributes are defined as scalar fields that associate each input point with a specific value. In the \cgal classification framework, an abstract class `CGAL::Classification::Attribute` defines what method the attribute must provide. All attributes must inherit this class. The attributes provided by \cgal are generally sufficient to handle most cases. However, the user may want to define its own attributes, especially if the input point set comes with additional properties that were not anticipated by \cgal. A user-defined attribute must inherit `CGAL::Classification::Attribute` and provide a method `value()` that associate a scalar value to each input point.
|
||||
|
||||
Attributes are accessed through `Handle` objects, `CGAL::Classification::Attribute_handle`.
|
||||
|
||||
\cgal provides some predefined attributes that make sense in urban scene classification:
|
||||
|
||||
- `CGAL::Classification::Attribute_distance_to_plane` measures how far away a point is from a locally estimated plane
|
||||
- `CGAL::Classification::Attribute_elevation` estimates the local distance to an estimated ground
|
||||
- `CGAL::Classification::Attribute_vertical_dispersion` computes how noisy the point set is on a local Z-cylinder
|
||||
- `CGAL::Classification::Attribute_verticality` compares the local normal vector to the vertical vector.
|
||||
|
||||
For more details about how these different attributes can help identifying one classification type or the other, please refer to their associated reference manual pages. In addition, \cgal also provides attributes solely based on the local eigen values \cgalCite{cgal:mbrsh-raofw-11}. Such attributes are less easy to relate to a specific classification type but can still be useful:
|
||||
|
||||
- `CGAL::Classification::Attribute_anisotropy`
|
||||
- `CGAL::Classification::Attribute_eigentropy`
|
||||
- `CGAL::Classification::Attribute_linearity`
|
||||
- `CGAL::Classification::Attribute_omnivariance`
|
||||
- `CGAL::Classification::Attribute_planarity`
|
||||
- `CGAL::Classification::Attribute_sphericity`
|
||||
- `CGAL::Classification::Attribute_sum_eigenvalues`
|
||||
- `CGAL::Classification::Attribute_surface_variation`.
|
||||
|
||||
Finally, if the input point set has additional properties, these can also be used as attributes. For example, \cgal provides the following attributes:
|
||||
|
||||
- `CGAL::Classification::Attribute_echo_scatter` uses the number of returns (echo) provided by most LIDAR scanners if available
|
||||
- `CGAL::Classification::Attribute_hsv` uses input color information if available.
|
||||
|
||||
In the following code snippet, a subset of these attributes are instantiated, their weights are set and they are added to a newly created classification object:
|
||||
|
||||
\snippet Classification/example_point_set_classification.cpp Attributes
|
||||
|
||||
\subsection Classification_types Classification Types
|
||||
|
||||
A classification type represents how a point should be classified, for example: vegetation, building, road, etc. It is defined by the values the attributes are expected to take for a specific type. For example, vegetation is expected to have a high distance to plane and have a color close to green (if colors are available); facades have a low distance to plane and a low verticality; etc.
|
||||
|
||||
\cgal provides a class `CGAL::Classification::Type` to define such a set of attribute effects, along with the associated `Handle` object: `CGAL::Classification::Type_handle`. Each type may define how a specific attribute affects it:
|
||||
|
||||
- `FAVORED_ATT`: the type is favored by high values of the attribute
|
||||
- `NEUTRAL_ATT`: the type is not affected by the attribute
|
||||
- `PENALIZED_ATT`: the type is favored by low values of the attribute
|
||||
|
||||
Let \f$x=(x_i)_{i=1..N_c}\f$ be a potential classification result with \f$N_c\f$ the number of input points and \f$x_i\f$ the class of the \f$i^{th}\f$ point (for example: vegetation, ground, etc.). Let \f$a_j(i)\f$ be the raw value of the \f$j^{th}\f$ attribute at the \f$i^{th}\f$ point and \f$w_j\f$ be the weight of this attribute. We define the normalized value of the \f$j^{th}\f$ attribute at the \f$i^{th}\f$ point as follows:
|
||||
|
||||
\f{eqnarray*}{
|
||||
A_j(x_i) = & (1 - \min(\max(0,\frac{a_j(i)}{w_j}), 1)) & \mbox{if } a_j \mbox{ favors } x_i \\
|
||||
& 0.5 & \mbox{if } a_j \mbox{ is neutral for } x_i \\
|
||||
& \min(\max(0,\frac{a_j(i)}{w_j}), 1) & \mbox{if } a_j \mbox{ penalizes } x_i
|
||||
\f}
|
||||
|
||||
|
||||
The following code snippet shows how to add types to the classification object and how to set the effects of the attributes on these types:
|
||||
|
||||
\snippet Classification/example_point_set_classification.cpp Classification Types
|
||||
|
||||
\subsection Classification_regularization Regularization
|
||||
|
||||
%Classification is performed by minizing an energy over the input point set. This energy can be regularized with different methods. \cgal provides 3 different methods for classification, ranging from high speed / low quality to low speed / high quality:
|
||||
|
||||
- `CGAL::Point_set_classification::run()`
|
||||
- `CGAL::Point_set_classification::run_with_local_smoothing()`
|
||||
- `CGAL::Point_set_classification::run_with_graphcut()`
|
||||
|
||||
On a point set of 3 millions points, the first method takes about 4 seconds, the second about 40 seconds and the third about 2 minutes.
|
||||
|
||||
\cgalFigureBegin{Classification_image,classif.png}
|
||||
Top-Left: input point set. Top-Right: raw output classification represented by a set of colors (ground is orange, facades are blue, roofs are pink and vegetation is green). Bottom-Left: output classification using local smoothing. Bottom-Right: output classification using graphcut.
|
||||
\cgalFigureEnd
|
||||
|
||||
|
||||
Mathematical details are provided hereafter.
|
||||
|
||||
\subsubsection Classification_regularized_no No Regularization
|
||||
|
||||
- `CGAL::Point_set_classification::run()`: this is the fastest method
|
||||
that provides acceptable but usually noisy results (see Figure
|
||||
\cgalFigureRef{Classification_image}, top-right).
|
||||
|
||||
Let \f$x=(x_i)_{i=1..N_c}\f$ be a potential classification result with \f$N_c\f$ the number of input points and \f$x_i\f$ the class of the \f$i^{th}\f$ point (for example: vegetation, ground, etc.). The classification is performed by minimizing the following energy:
|
||||
|
||||
\f[
|
||||
E(x) = \sum_{i = 1..N_c} E_{di}(x_i)
|
||||
\f]
|
||||
|
||||
This energy is a sum of pointwise energies and involves no regularization. Let \f$A=(A_j)_{j=1..N_a}\f$ be the set of normalized attributes
|
||||
(see \ref Classification_types). The pointwise energy measures the coherence of the class \f$x_i\f$ at the \f$i^{th}\f$ point and is defined as:
|
||||
|
||||
\f[
|
||||
E_{di}(x_i) = \sum_{j = 1..N_a} A_j(x_i)
|
||||
\f]
|
||||
|
||||
|
||||
|
||||
\subsubsection Classification_regularized_local Local Smoothing
|
||||
|
||||
- `CGAL::Point_set_classification::run_with_local_smoothing()`: this
|
||||
method is a tradeoff between quality and efficiency (see Figure
|
||||
\cgalFigureRef{Classification_image}, bottom-left). The minimized
|
||||
energy is defined as follows:
|
||||
|
||||
|
||||
\f[
|
||||
E(x) = \sum_{i = 1..N_c} E_{di}(x_i)
|
||||
\f]
|
||||
|
||||
The pointwise energy \f$E_{di}(x_i)\f$ is replaced by
|
||||
\f$E_{si}(x_i)\f$ defined on a small local neighborhood \f$N(i)\f$ of
|
||||
the \f$i^{th}\f$ point:
|
||||
|
||||
\f[
|
||||
E_{si}(x_i) = \sum_{j = 1..N_a} \frac{\sum_{k \in N(i)} A_j(x_k)}{\left| N(i) \right|}
|
||||
\f]
|
||||
|
||||
This allows to eliminate local noisy variations of assigned
|
||||
classification types. Increasing the size of the neighborhood
|
||||
increases the noise reduction at the cost of higher computation times.
|
||||
|
||||
|
||||
\subsubsection Classification_regularized_graphcut Global Regularization (Graph Cut)
|
||||
|
||||
- `CGAL::Point_set_classification::run_with_graphcut()`: this method
|
||||
offers the best quality but requires longer computation time (see
|
||||
Figure \cgalFigureRef{Classification_image}, bottom-right). The
|
||||
total energy that is minimized is the sum of the partial data term
|
||||
\f$E_{di}(x_i)\f$ and of a pairwise interaction energy defined by the
|
||||
standard Potts model:
|
||||
|
||||
\f[
|
||||
E(x) = \sum_{i = 1..N_c} E_{di}(x_i) + \gamma \sum_{i \sim j} \mathbf{1}_{x_i \neq x_j}
|
||||
\f]
|
||||
|
||||
where \f$\gamma>0\f$ is the parameter of the Potts model that
|
||||
quantifies the strengh of the regularization, \f$i \sim j\f$
|
||||
represents the pairs of neighboring points and
|
||||
\f$\mathbf{1}_{\{.\}}\f$ the characteristic function.
|
||||
|
||||
A Graph Cut based algorithm (Alpha Expansion) is used to quickly reach
|
||||
an approximate solution close to the global optimum of this energy.
|
||||
|
||||
This method allows to consistently segment the input point set in
|
||||
piecewise constant parts and to eliminate global variations of
|
||||
assigned classification types. Increasing \f$\gamma\f$ produces more
|
||||
regular result with a constant computation time.
|
||||
|
||||
|
||||
|
||||
\subsection Classification_example Example
|
||||
|
||||
The following example:
|
||||
|
||||
- reads an input file (LIDAR point set in PLY format);
|
||||
- computes useful structures from this input;
|
||||
- computes segmentation attributes from the input and the precomputed structures;
|
||||
- defines 3 classification types (vegetation, ground and roof) along with the effects of attributes on them;
|
||||
- classifies the point set;
|
||||
- saves the result in a colored PLY format.
|
||||
|
||||
\cgalExample{Classification/example_point_set_classification.cpp}
|
||||
|
||||
\section Classification_helper Helper
|
||||
|
||||
The classification algorithm is designed to be as flexible as possible: the user may define its own attributes and classification types. Nevertheless, \cgal provides a predefined framework that should work correctly on common urban point sets. The class `CGAL::Classification::Helper` is designed to make it easier for the user to classify its input point set:
|
||||
|
||||
- it takes care of generating all needed analysis structure;
|
||||
- it generates all possible attributes (among all the \cgal predefined ones) based on which property maps are available (it uses colors if available, etc.);
|
||||
- multiple scales can be used to increase the quality of the results
|
||||
- input/ouput methods are provided to save and recover a specific configuration (with all attributes, types and relationships between them).
|
||||
- classification can be saved as a PLY format with colors and labels.
|
||||
|
||||
\section Classification_training Training
|
||||
|
||||
%Classification is based on relationships between attributes and types. Each attribute has a specific weight and each pair of attribute/type has a specific effect. This means that the number of parameters to set up becomes rapidly large: if 6 attributes are used to classify between 4 classification types, 30 parameters have to be set up.
|
||||
|
||||
Though it is possible to set them one by one, \cgal also provides a training algorithm that requires a small set of ground truth points provided by the user. More specifically, the user must provide, for each classification type he/she wants to classify, a set of known inliers among the input point set (for example, selecting one roof, one tree, one section of the ground). The training algorithm works as follows:
|
||||
|
||||
- for each attribute, a range of weights is tested: the effects each attribute have on each type is estimated. For a given weight, if an attribute has the same effect on each type, it is non-relevant for classification. The range of weights such that the attribute is relevant is estimated;
|
||||
|
||||
- for each attribute, uniformly picked weight values are tested and their effects estimated;
|
||||
|
||||
- each ground truth points provided by the user is classified using this set of weights and effects;
|
||||
|
||||
- for each classification type, the ratio of correctly classified ground truth points is computed. The minimum of this ratios is used as a score for this set of weights and effects: a ratio of 0.8 means that for each classification type, at least 80\% of the provided ground truth point were correctly classified;
|
||||
|
||||
- the same mechanism is repeated until all attributes' ranges have been tested. Weights are only changed one by one, the other ones kept to the previous value that gave the best score.
|
||||
|
||||
This usually converges to a satisfying solution. The number of trials is user defined, set to 300 by default. Using at least 10 times the number of attributes is advised. If the solution is not satisfying, more ground truth points can be selected,for example, in a region that the user identifies as misclassified with the current configuration. The training algorithm keeps the best weights found as initialization and carries on trying new weights by taking new ground truth points into account.
|
||||
|
||||
\cgalFigureBegin{Classification_training_fig,classif_training.png}
|
||||
Example of evolution of training score. Purple curve is the score computed at the current iteration, green curve is the best score found so far. Iterations where better solutions are found are marked by vertical gray lines.
|
||||
\cgalFigureEnd
|
||||
|
||||
|
||||
\subsection Classification_helper_example Example with Helper and Training
|
||||
|
||||
The following example:
|
||||
|
||||
- reads a point set with a training set (embedded as a PLY attribute _label_);
|
||||
- uses the helper to generate attributes on 5 scales;
|
||||
- trains the algorithm using 800 trials;
|
||||
- runs the algorithm using the graphcut regularization;
|
||||
- saves the output using the helper.
|
||||
|
||||
\cgalExample{Classification/example_helper.cpp}
|
||||
|
||||
\section Classification_history History
|
||||
|
||||
This package is based on a research code by Florent Lafarge that was generalized, extended and packaged by Simon Giraudot.
|
||||
|
||||
|
||||
|
||||
*/
|
||||
} /* namespace CGAL */
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
@INCLUDE = ${CGAL_DOC_PACKAGE_DEFAULTS}
|
||||
PROJECT_NAME = "CGAL ${CGAL_DOC_VERSION} - Classification"
|
||||
INPUT = ${CMAKE_SOURCE_DIR}/Classification/doc/Classification/ \
|
||||
${CMAKE_SOURCE_DIR}/Classification/include/CGAL/Classification/ \
|
||||
${CMAKE_SOURCE_DIR}/Classification/include/CGAL/Classifier.h
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
/*!
|
||||
\defgroup PkgClassification Classification Reference
|
||||
|
||||
\defgroup PkgClassificationConcepts Concepts
|
||||
\ingroup PkgClassification
|
||||
|
||||
\defgroup PkgClassificationShapes Shapes
|
||||
\ingroup PkgClassification
|
||||
|
||||
\addtogroup PkgClassification
|
||||
|
||||
\cgalPkgDescriptionBegin{Classification, PkgClassificationSummary}
|
||||
\cgalPkgPicture{data_classif.png}
|
||||
|
||||
\cgalPkgSummaryBegin
|
||||
\cgalPkgAuthors{Simon Giraudot}
|
||||
\cgalPkgDesc{This component implements an algorithm that classifies a data set into a user-defined set of classes (such as ground, vegetation, buildings, etc.). A flexible API is provided so that the user can classify any type of data, compute its own local attributes on the data set and define its own classes based on these attributes.}
|
||||
\cgalPkgManuals{Chapter_Classification, PkgClassification}
|
||||
\cgalPkgSummaryEnd
|
||||
|
||||
\cgalPkgShortInfoBegin
|
||||
\cgalPkgSince{4.9}
|
||||
\cgalPkgBib{cgal:ovja-pssd}
|
||||
\cgalPkgLicense{\ref licensesGPL "GPL"}
|
||||
\cgalPkgDemo{Operations on Polyhedra,polyhedron_3.zip}
|
||||
\cgalPkgShortInfoEnd
|
||||
|
||||
\cgalPkgDescriptionEnd
|
||||
|
||||
\cgalClassifedRefPages
|
||||
|
||||
## Concepts ##
|
||||
- `CGAL::NeighborQuery`
|
||||
|
||||
## Classification ##
|
||||
- `CGAL::Classifier<RandomAccessIterator, ItemMap>`
|
||||
|
||||
## Data Structures ##
|
||||
|
||||
- `CGAL::Classification::Helper<Kernel, RandomAccessIterator, PointMap, DiagonalizeTraits>`
|
||||
- `CGAL::Classification::Point_set_neighborhood<Kernel, RandomAccessIterator, PointMap>`
|
||||
- `CGAL::Classification::Local_eigen_analysis<Kernel, RandomAccessIterator, PointMap, DiagonalizeTraits>`
|
||||
- `CGAL::Classification::Planimetric_grid<Kernel, RandomAccessIterator, PointMap>`
|
||||
|
||||
## Classification Type ##
|
||||
|
||||
- `CGAL::Classification::Type`
|
||||
- `CGAL::Classification::Type_handle`
|
||||
|
||||
## Attribute ##
|
||||
|
||||
- `CGAL::Classification::Attribute`
|
||||
- `CGAL::Classification::Attribute_handle`
|
||||
|
||||
## Predefined Attributes ##
|
||||
|
||||
- `CGAL::Classification::Attribute_anisotropy<Kernel, RandomAccessIterator, PointMap, DiagonalizeTraits>`
|
||||
- `CGAL::Classification::Attribute_distance_to_plane<Kernel, RandomAccessIterator, PointMap, DiagonalizeTraits>`
|
||||
- `CGAL::Classification::Attribute_echo_scatter<Kernel, RandomAccessIterator, PointMap, EchoMap>`
|
||||
- `CGAL::Classification::Attribute_eigentropy<Kernel, RandomAccessIterator, PointMap, DiagonalizeTraits>`
|
||||
- `CGAL::Classification::Attribute_elevation<Kernel, RandomAccessIterator, PointMap>`
|
||||
- `CGAL::Classification::Attribute_hsv<Kernel, RandomAccessIterator, ColorMap>`
|
||||
- `CGAL::Classification::Attribute_linearity<Kernel, RandomAccessIterator, PointMap, DiagonalizeTraits>`
|
||||
- `CGAL::Classification::Attribute_omnivariance<Kernel, RandomAccessIterator, PointMap, DiagonalizeTraits>`
|
||||
- `CGAL::Classification::Attribute_planarity<Kernel, RandomAccessIterator, PointMap, DiagonalizeTraits>`
|
||||
- `CGAL::Classification::Attribute_sphericity<Kernel, RandomAccessIterator, PointMap, DiagonalizeTraits>`
|
||||
- `CGAL::Classification::Attribute_sum_eigenvalues<Kernel, RandomAccessIterator, PointMap, DiagonalizeTraits>`
|
||||
- `CGAL::Classification::Attribute_surface_variation<Kernel, RandomAccessIterator, PointMap, DiagonalizeTraits>`
|
||||
- `CGAL::Classification::Attribute_vertical_dispersion<Kernel, RandomAccessIterator, PointMap>`
|
||||
- `CGAL::Classification::Attribute_verticality<Kernel, RandomAccessIterator, PointMap, DiagonalizeTraits>`
|
||||
|
||||
|
||||
*/
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
Manual
|
||||
Kernel_23
|
||||
STL_Extension
|
||||
Algebraic_foundations
|
||||
Circulator
|
||||
Stream_support
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
/*!
|
||||
\example Classification/example_point_set_classification.cpp
|
||||
\example Classification/example_helper.cpp
|
||||
*/
|
||||
|
After Width: | Height: | Size: 66 KiB |
|
After Width: | Height: | Size: 154 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
|
@ -0,0 +1,48 @@
|
|||
# Created by the script cgal_create_CMakeLists
|
||||
# This is the CMake script for compiling a set of CGAL applications.
|
||||
|
||||
project( Classification )
|
||||
|
||||
|
||||
cmake_minimum_required(VERSION 2.8.11)
|
||||
|
||||
# CGAL and its components
|
||||
find_package( CGAL QUIET COMPONENTS )
|
||||
|
||||
if ( NOT CGAL_FOUND )
|
||||
|
||||
message(STATUS "This project requires the CGAL library, and will not be compiled.")
|
||||
return()
|
||||
|
||||
endif()
|
||||
|
||||
# include helper file
|
||||
include( ${CGAL_USE_FILE} )
|
||||
|
||||
|
||||
# Boost and its components
|
||||
find_package( Boost REQUIRED )
|
||||
|
||||
if ( NOT Boost_FOUND )
|
||||
|
||||
message(STATUS "This project requires the Boost library, and will not be compiled.")
|
||||
|
||||
return()
|
||||
|
||||
endif()
|
||||
|
||||
# include for local directory
|
||||
include_directories( BEFORE include )
|
||||
|
||||
# include for local package
|
||||
include_directories( BEFORE ../../include )
|
||||
|
||||
|
||||
# Creating entries for all C++ files with "main" routine
|
||||
# ##########################################################
|
||||
|
||||
include( CGAL_CreateSingleSourceCGALProgram )
|
||||
|
||||
create_single_source_cgal_program( "example_point_set_classification.cpp" )
|
||||
create_single_source_cgal_program( "example_helper.cpp" )
|
||||
|
||||
|
|
@ -0,0 +1,136 @@
|
|||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
#include <CGAL/Classifier.h>
|
||||
#include <CGAL/Classification/Helper.h>
|
||||
#include <CGAL/IO/read_ply_points.h>
|
||||
|
||||
typedef CGAL::Simple_cartesian<double> Kernel;
|
||||
typedef Kernel::Point_3 Point;
|
||||
typedef Kernel::Iso_cuboid_3 Iso_cuboid_3;
|
||||
typedef std::vector<Point>::iterator Iterator;
|
||||
typedef CGAL::Identity_property_map<Point> Pmap;
|
||||
|
||||
typedef CGAL::Classifier<Iterator, Pmap> Classification;
|
||||
typedef CGAL::Classification::Helper<Kernel, Iterator, Pmap> Helper;
|
||||
|
||||
|
||||
/*
|
||||
This interpreter is used to read a PLY input that contains training
|
||||
attributes (with the PLY "label" property).
|
||||
*/
|
||||
class My_ply_interpreter
|
||||
{
|
||||
std::vector<Point>& points;
|
||||
std::vector<int>& labels;
|
||||
|
||||
public:
|
||||
My_ply_interpreter (std::vector<Point>& points,
|
||||
std::vector<int>& labels)
|
||||
: points (points), labels (labels)
|
||||
{ }
|
||||
|
||||
// Init and test if input file contains the right properties
|
||||
bool is_applicable (CGAL::Ply_reader& reader)
|
||||
{
|
||||
return reader.does_tag_exist<double> ("x")
|
||||
&& reader.does_tag_exist<double> ("y")
|
||||
&& reader.does_tag_exist<double> ("z")
|
||||
&& reader.does_tag_exist<int> ("label");
|
||||
}
|
||||
|
||||
// Describes how to process one line (= one point object)
|
||||
void process_line (CGAL::Ply_reader& reader)
|
||||
{
|
||||
double x = 0., y = 0., z = 0.;
|
||||
int l = 0;
|
||||
|
||||
reader.assign (x, "x");
|
||||
reader.assign (y, "y");
|
||||
reader.assign (z, "z");
|
||||
reader.assign (l, "label");
|
||||
|
||||
points.push_back (Point (x, y, z));
|
||||
labels.push_back(l);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
int main (int argc, char** argv)
|
||||
{
|
||||
std::string filename (argc > 1 ? argv[1] : "data/b9_training.ply");
|
||||
std::ifstream in (filename.c_str());
|
||||
std::vector<Point> pts;
|
||||
std::vector<int> labels;
|
||||
|
||||
std::cerr << "Reading input" << std::endl;
|
||||
My_ply_interpreter interpreter (pts, labels);
|
||||
if (!in
|
||||
|| !(CGAL::read_ply_custom_points (in, interpreter, Kernel())))
|
||||
{
|
||||
std::cerr << "Error: cannot read " << filename << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
Classification psc (pts.begin (), pts.end(), Pmap());
|
||||
|
||||
std::cerr << "Generating attributes" << std::endl;
|
||||
Helper helper (pts.begin(), pts.end(), Pmap(),
|
||||
5); // Using 5 scales
|
||||
|
||||
helper.generate_attributes (psc, pts.begin(), pts.end(), Pmap());
|
||||
|
||||
// Add types to PSC
|
||||
CGAL::Classification::Type_handle ground
|
||||
= psc.add_classification_type ("ground");
|
||||
CGAL::Classification::Type_handle vege
|
||||
= psc.add_classification_type ("vegetation");
|
||||
CGAL::Classification::Type_handle roof
|
||||
= psc.add_classification_type ("roof");
|
||||
|
||||
// Set training sets
|
||||
for (std::size_t i = 0; i < labels.size(); ++ i)
|
||||
{
|
||||
switch (labels[i])
|
||||
{
|
||||
case 0:
|
||||
psc.add_training_index(ground, i);
|
||||
break;
|
||||
case 1:
|
||||
psc.add_training_index(vege, i);
|
||||
break;
|
||||
case 2:
|
||||
psc.add_training_index(roof, i);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::cerr << "Training" << std::endl;
|
||||
psc.training(800); // 800 trials
|
||||
|
||||
psc.run_with_graphcut (helper.neighborhood().k_neighbor_query(12), 0.5);
|
||||
|
||||
// Save the output in a colored PLY format
|
||||
std::ofstream f ("classification.ply");
|
||||
f.precision(18);
|
||||
|
||||
std::vector<CGAL::Classification::RGB_Color> colors;
|
||||
colors.push_back(CGAL::make_array ((unsigned char)245, 180, 0)); // Ground
|
||||
colors.push_back(CGAL::make_array ((unsigned char)0, 255, 27)); // Vegetation
|
||||
colors.push_back(CGAL::make_array ((unsigned char)255, 0, 170)); // Roof
|
||||
|
||||
helper.write_ply (f, pts.begin(), pts.end(), Pmap(), psc, &colors);
|
||||
|
||||
/// Save the configuration to be able to reload it later
|
||||
helper.save ("config.xml", psc);
|
||||
|
||||
std::cerr << "All done" << std::endl;
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -0,0 +1,187 @@
|
|||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
#include <CGAL/Classifier.h>
|
||||
#include <CGAL/Classification/Point_set_neighborhood.h>
|
||||
#include <CGAL/Classification/Planimetric_grid.h>
|
||||
#include <CGAL/Classification/Attribute.h>
|
||||
#include <CGAL/Classification/Attributes_eigen.h>
|
||||
#include <CGAL/Classification/Attribute_distance_to_plane.h>
|
||||
#include <CGAL/Classification/Attribute_vertical_dispersion.h>
|
||||
#include <CGAL/Classification/Attribute_elevation.h>
|
||||
|
||||
#include <CGAL/IO/read_ply_points.h>
|
||||
|
||||
typedef CGAL::Simple_cartesian<double> Kernel;
|
||||
typedef Kernel::Point_3 Point;
|
||||
typedef Kernel::Iso_cuboid_3 Iso_cuboid_3;
|
||||
typedef std::vector<Point>::iterator Iterator;
|
||||
typedef CGAL::Identity_property_map<Point> Pmap;
|
||||
|
||||
typedef CGAL::Classifier<Iterator, Pmap> Classification;
|
||||
|
||||
typedef CGAL::Classification::Planimetric_grid<Kernel, Iterator, Pmap> Planimetric_grid;
|
||||
typedef CGAL::Classification::Point_set_neighborhood<Kernel, Iterator, Pmap> Neighborhood;
|
||||
typedef CGAL::Classification::Local_eigen_analysis<Kernel, Iterator, Pmap> Local_eigen_analysis;
|
||||
|
||||
typedef CGAL::Classification::Type_handle Type_handle;
|
||||
typedef CGAL::Classification::Attribute_handle Attribute_handle;
|
||||
|
||||
typedef CGAL::Classification::Attribute_distance_to_plane<Kernel, Iterator, Pmap> Distance_to_plane;
|
||||
typedef CGAL::Classification::Attribute_linearity<Kernel, Iterator, Pmap> Linearity;
|
||||
typedef CGAL::Classification::Attribute_omnivariance<Kernel, Iterator, Pmap> Omnivariance;
|
||||
typedef CGAL::Classification::Attribute_planarity<Kernel, Iterator, Pmap> Planarity;
|
||||
typedef CGAL::Classification::Attribute_surface_variation<Kernel, Iterator, Pmap> Surface_variation;
|
||||
typedef CGAL::Classification::Attribute_elevation<Kernel, Iterator, Pmap> Elevation;
|
||||
typedef CGAL::Classification::Attribute_vertical_dispersion<Kernel, Iterator, Pmap> Dispersion;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
//! [Analysis]
|
||||
|
||||
int main (int argc, char** argv)
|
||||
{
|
||||
std::string filename (argc > 1 ? argv[1] : "data/b9.ply");
|
||||
std::ifstream in (filename.c_str());
|
||||
std::vector<Point> pts;
|
||||
|
||||
std::cerr << "Reading input" << std::endl;
|
||||
if (!in
|
||||
|| !(CGAL::read_ply_points (in, std::back_inserter (pts))))
|
||||
{
|
||||
std::cerr << "Error: cannot read " << filename << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
double grid_resolution = 0.34;
|
||||
double radius_neighbors = 1.7;
|
||||
double radius_dtm = 15.0;
|
||||
|
||||
std::cerr << "Computing useful structures" << std::endl;
|
||||
|
||||
Iso_cuboid_3 bbox = CGAL::bounding_box (pts.begin(), pts.end());
|
||||
|
||||
Planimetric_grid grid (pts.begin(), pts.end(), Pmap(), bbox, grid_resolution);
|
||||
Neighborhood neighborhood (pts.begin(), pts.end(), Pmap());
|
||||
double garbage;
|
||||
Local_eigen_analysis eigen (pts.begin(), pts.end(), Pmap(), neighborhood.k_neighbor_query(6), garbage);
|
||||
|
||||
//! [Analysis]
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
//! [Attributes]
|
||||
|
||||
std::cerr << "Computing attributes" << std::endl;
|
||||
Attribute_handle d2p (new Distance_to_plane (pts.begin(), pts.end(), Pmap(), eigen));
|
||||
Attribute_handle lin (new Linearity (pts.begin(), pts.end(), eigen));
|
||||
Attribute_handle omni (new Omnivariance (pts.begin(), pts.end(), eigen));
|
||||
Attribute_handle plan (new Planarity (pts.begin(), pts.end(), eigen));
|
||||
Attribute_handle surf (new Surface_variation (pts.begin(), pts.end(), eigen));
|
||||
Attribute_handle disp (new Dispersion (pts.begin(), pts.end(), Pmap(), grid,
|
||||
grid_resolution,
|
||||
radius_neighbors));
|
||||
Attribute_handle elev (new Elevation (pts.begin(), pts.end(), Pmap(), grid,
|
||||
grid_resolution,
|
||||
radius_dtm));
|
||||
|
||||
std::cerr << "Setting weights" << std::endl;
|
||||
d2p->weight = 6.75e-2;
|
||||
lin->weight = 1.19;
|
||||
omni->weight = 1.34e-1;
|
||||
plan->weight = 7.32e-1;
|
||||
surf->weight = 1.36e-1;
|
||||
disp->weight = 5.45e-1;
|
||||
elev->weight = 1.47e1;
|
||||
|
||||
|
||||
// Add attributes to classification object
|
||||
Classification psc (pts.begin (), pts.end(), Pmap());
|
||||
psc.add_attribute (d2p);
|
||||
psc.add_attribute (lin);
|
||||
psc.add_attribute (omni);
|
||||
psc.add_attribute (plan);
|
||||
psc.add_attribute (surf);
|
||||
psc.add_attribute (disp);
|
||||
psc.add_attribute (elev);
|
||||
|
||||
//! [Attributes]
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
//! [Classification Types]
|
||||
|
||||
std::cerr << "Setting up classification types" << std::endl;
|
||||
|
||||
// Create classification type and define how attributes affect them
|
||||
Type_handle ground = psc.add_classification_type ("ground");
|
||||
ground->set_attribute_effect (d2p, CGAL::Classification::Type::NEUTRAL_ATT);
|
||||
ground->set_attribute_effect (lin, CGAL::Classification::Type::PENALIZED_ATT);
|
||||
ground->set_attribute_effect (omni, CGAL::Classification::Type::NEUTRAL_ATT);
|
||||
ground->set_attribute_effect (plan, CGAL::Classification::Type::FAVORED_ATT);
|
||||
ground->set_attribute_effect (surf, CGAL::Classification::Type::PENALIZED_ATT);
|
||||
ground->set_attribute_effect (disp, CGAL::Classification::Type::NEUTRAL_ATT);
|
||||
ground->set_attribute_effect (elev, CGAL::Classification::Type::PENALIZED_ATT);
|
||||
|
||||
Type_handle vege = psc.add_classification_type ("vegetation");
|
||||
vege->set_attribute_effect (d2p, CGAL::Classification::Type::FAVORED_ATT);
|
||||
vege->set_attribute_effect (lin, CGAL::Classification::Type::NEUTRAL_ATT);
|
||||
vege->set_attribute_effect (omni, CGAL::Classification::Type::FAVORED_ATT);
|
||||
vege->set_attribute_effect (plan, CGAL::Classification::Type::NEUTRAL_ATT);
|
||||
vege->set_attribute_effect (surf, CGAL::Classification::Type::NEUTRAL_ATT);
|
||||
vege->set_attribute_effect (disp, CGAL::Classification::Type::FAVORED_ATT);
|
||||
vege->set_attribute_effect (elev, CGAL::Classification::Type::NEUTRAL_ATT);
|
||||
|
||||
Type_handle roof = psc.add_classification_type ("roof");
|
||||
roof->set_attribute_effect (d2p, CGAL::Classification::Type::NEUTRAL_ATT);
|
||||
roof->set_attribute_effect (lin, CGAL::Classification::Type::PENALIZED_ATT);
|
||||
roof->set_attribute_effect (omni, CGAL::Classification::Type::FAVORED_ATT);
|
||||
roof->set_attribute_effect (plan, CGAL::Classification::Type::FAVORED_ATT);
|
||||
roof->set_attribute_effect (surf, CGAL::Classification::Type::PENALIZED_ATT);
|
||||
roof->set_attribute_effect (disp, CGAL::Classification::Type::NEUTRAL_ATT);
|
||||
roof->set_attribute_effect (elev, CGAL::Classification::Type::FAVORED_ATT);
|
||||
|
||||
//! [Classification Types]
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
// Run classification
|
||||
psc.run_with_graphcut (neighborhood.k_neighbor_query(12), 0.2);
|
||||
|
||||
// Save the output in a colored PLY format
|
||||
|
||||
std::ofstream f ("classification.ply");
|
||||
f << "ply" << std::endl
|
||||
<< "format ascii 1.0" << std::endl
|
||||
<< "element vertex " << pts.size() << std::endl
|
||||
<< "property float x" << std::endl
|
||||
<< "property float y" << std::endl
|
||||
<< "property float z" << std::endl
|
||||
<< "property uchar red" << std::endl
|
||||
<< "property uchar green" << std::endl
|
||||
<< "property uchar blue" << std::endl
|
||||
<< "end_header" << std::endl;
|
||||
|
||||
for (std::size_t i = 0; i < pts.size(); ++ i)
|
||||
{
|
||||
f << pts[i] << " ";
|
||||
|
||||
Type_handle type = psc.classification_type_of (i);
|
||||
if (type == ground)
|
||||
f << "245 180 0" << std::endl;
|
||||
else if (type == vege)
|
||||
f << "0 255 27" << std::endl;
|
||||
else if (type == roof)
|
||||
f << "255 0 170" << std::endl;
|
||||
else
|
||||
{
|
||||
f << "0 0 0" << std::endl;
|
||||
std::cerr << "Error: unknown classification type" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
std::cerr << "All done" << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
// Copyright (c) 2016 INRIA Sophia-Antipolis (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
//
|
||||
// Author(s) : Simon Giraudot
|
||||
|
||||
#ifndef CGAL_CLASSIFICATION_ATTRIBUTE_H
|
||||
#define CGAL_CLASSIFICATION_ATTRIBUTE_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
namespace Classification {
|
||||
|
||||
/*!
|
||||
\ingroup PkgClassification
|
||||
|
||||
\brief Abstract class describing a classification attribute.
|
||||
|
||||
A classification attribute associates a scalar value to each item
|
||||
of the classification input.
|
||||
*/
|
||||
|
||||
|
||||
class Attribute
|
||||
{
|
||||
public:
|
||||
double weight; ///< Weight of the attribute between 0 and +∞.
|
||||
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
double mean;
|
||||
double max;
|
||||
|
||||
virtual ~Attribute() { }
|
||||
/// \endcond
|
||||
|
||||
/*!
|
||||
\brief Returns the ID of the attribute.
|
||||
|
||||
This method returns _abstract\_attribute_ and should be overloaded
|
||||
by a child class with a specific ID.
|
||||
*/
|
||||
virtual std::string id() { return "abstract_attribute"; }
|
||||
|
||||
/*!
|
||||
\brief Returns the value taken by the attribute on the given item.
|
||||
|
||||
This method must be implemented by inherited classes.
|
||||
|
||||
\param index Index of the input item.
|
||||
|
||||
\return the value of the attribute on the item of index `index`
|
||||
*/
|
||||
virtual double value (std::size_t index) = 0;
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
virtual double normalized (std::size_t index)
|
||||
{
|
||||
return (std::max) (0., (std::min) (1., value(index) / weight));
|
||||
}
|
||||
virtual double favored (std::size_t index) { return (1. - normalized (index)); }
|
||||
virtual double penalized (std::size_t index) { return normalized (index); }
|
||||
// virtual double ignored (std::size_t index) { return (std::min) (favored(index), penalized(index)); }
|
||||
virtual double ignored (std::size_t) { return 0.5; }
|
||||
|
||||
void compute_mean_max (std::vector<double>& vect, double& mean, double& max)
|
||||
{
|
||||
mean = 0.;
|
||||
max = -std::numeric_limits<double>::max();
|
||||
double min = std::numeric_limits<double>::max();
|
||||
|
||||
for (std::size_t i = 0; i < vect.size(); ++ i)
|
||||
{
|
||||
mean += vect[i];
|
||||
if (vect[i] > max)
|
||||
max = vect[i];
|
||||
if (vect[i] < min)
|
||||
min = vect[i];
|
||||
}
|
||||
// std::cerr << id() << " Min/max = " << min << " / " << max << std::endl;
|
||||
mean /= vect.size();
|
||||
|
||||
}
|
||||
/// \endcond
|
||||
};
|
||||
|
||||
|
||||
#ifdef DOXYGEN_RUNNING
|
||||
/*!
|
||||
\ingroup PkgClassification
|
||||
|
||||
\brief Handle to a classification `Attribute`.
|
||||
|
||||
\cgalModels Handle
|
||||
*/
|
||||
class Attribute_handle { };
|
||||
#else
|
||||
typedef boost::shared_ptr<Attribute> Attribute_handle;
|
||||
#endif
|
||||
|
||||
} // namespace Classification
|
||||
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_CLASSIFICATION_ATTRIBUTE_H
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
// Copyright (c) 2016 INRIA Sophia-Antipolis (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
//
|
||||
// Author(s) : Simon Giraudot
|
||||
|
||||
#ifndef CGAL_CLASSIFICATION_ATTRIBUTE_COLOR_H
|
||||
#define CGAL_CLASSIFICATION_ATTRIBUTE_COLOR_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <CGAL/Classification/Color.h>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
namespace Classification {
|
||||
|
||||
/*!
|
||||
\ingroup PkgClassification
|
||||
|
||||
\brief Attribute based on HSV colorimetric information.
|
||||
|
||||
If the input point cloud has colorimetric information, it can be
|
||||
used for classification purposes. This attribute is based on
|
||||
Gaussian probabilistic model on one of the three HSV channels
|
||||
(hue, saturation or value).
|
||||
|
||||
It computes the probability of the color of the input point to
|
||||
match this specific color channel defined by a mean and a standard
|
||||
deviation.
|
||||
|
||||
For example, such an attribute using the channel 0 (hue) with a
|
||||
mean of 90 (which corresponds to a green hue) can help identifying
|
||||
trees.
|
||||
|
||||
\tparam Kernel The geometric kernel used.
|
||||
\tparam RandomAccessIterator Iterator over the input.
|
||||
\tparam ColorMap is a model of `ReadablePropertyMap` with value type `CGAL::Classification::RGB_Color`.A
|
||||
*/
|
||||
template <typename Kernel, typename RandomAccessIterator, typename ColorMap>
|
||||
class Attribute_hsv : public Attribute
|
||||
{
|
||||
typedef typename Classification::RGB_Color RGB_Color;
|
||||
typedef typename Classification::HSV_Color HSV_Color;
|
||||
|
||||
std::vector<double> color_attribute;
|
||||
std::string m_id;
|
||||
|
||||
public:
|
||||
|
||||
/*!
|
||||
|
||||
\brief Constructs an attribute based on the given color channel,
|
||||
mean and standard deviation.
|
||||
|
||||
\param begin Iterator to the first input object
|
||||
\param end Past-the-end iterator
|
||||
\param color_map Property map to access the colors of the input points
|
||||
\param channel Chosen HSV channel (0 for hue, 1 for saturation, 2 for value).
|
||||
\param mean Mean value of the specified channel
|
||||
\param sd Standard deviation of the specified channel
|
||||
*/
|
||||
Attribute_hsv (RandomAccessIterator begin,
|
||||
RandomAccessIterator end,
|
||||
ColorMap color_map,
|
||||
std::size_t channel,
|
||||
double mean, double sd)
|
||||
{
|
||||
this->weight = 1.;
|
||||
for(std::size_t i = 0; i < (std::size_t)(end - begin);i++)
|
||||
{
|
||||
HSV_Color c = Classification::rgb_to_hsv (get(color_map, begin[i]));
|
||||
color_attribute.push_back (std::exp (-(c[channel] - mean) * (c[channel] - mean) / (2. * sd * sd)));
|
||||
}
|
||||
this->compute_mean_max (color_attribute, this->mean, this->max);
|
||||
|
||||
std::ostringstream oss;
|
||||
if (channel == 0) oss << "hue";
|
||||
else if (channel == 1) oss << "saturation";
|
||||
else if (channel == 2) oss << "value";
|
||||
oss << "_" << mean;
|
||||
m_id = oss.str();
|
||||
}
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
virtual double value (std::size_t pt_index)
|
||||
{
|
||||
return color_attribute[pt_index];
|
||||
}
|
||||
|
||||
virtual std::string id() { return m_id; }
|
||||
/// \endcond
|
||||
};
|
||||
|
||||
} // namespace Classification
|
||||
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_CLASSIFICATION_ATTRIBUTE_COLOR_H
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
// Copyright (c) 2016 INRIA Sophia-Antipolis (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
//
|
||||
// Author(s) : Simon Giraudot, Florent Lafarge
|
||||
|
||||
#ifndef CGAL_CLASSIFICATION_ATTRIBUTE_DISTANCE_TO_PLANE_H
|
||||
#define CGAL_CLASSIFICATION_ATTRIBUTE_DISTANCE_TO_PLANE_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <CGAL/Classifier.h>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
namespace Classification {
|
||||
|
||||
/*!
|
||||
\ingroup PkgClassification
|
||||
|
||||
\brief Attribute based on local distance to a fitted plane.
|
||||
|
||||
Characterizing a level of non-planarity can help identify noisy
|
||||
parts of the input such as vegetation. This attribute computes the
|
||||
distance of a point to a locally fitted plane.
|
||||
|
||||
\tparam Kernel The geometric kernel used.
|
||||
\tparam RandomAccessIterator Iterator over the input.
|
||||
\tparam PointMap is a model of `ReadablePropertyMap` with value type `Point_3<Kernel>`.
|
||||
\tparam DiagonalizeTraits Solver used for matrix diagonalization.
|
||||
*/
|
||||
template <typename Kernel, typename RandomAccessIterator, typename PointMap,
|
||||
typename DiagonalizeTraits = CGAL::Default_diagonalize_traits<double,3> >
|
||||
class Attribute_distance_to_plane : public Attribute
|
||||
{
|
||||
typedef Classification::Local_eigen_analysis<Kernel, RandomAccessIterator,
|
||||
PointMap, DiagonalizeTraits> Local_eigen_analysis;
|
||||
|
||||
std::vector<double> distance_to_plane_attribute;
|
||||
|
||||
public:
|
||||
/*!
|
||||
\brief Constructs the attribute.
|
||||
|
||||
\param begin Iterator to the first input object
|
||||
\param end Past-the-end iterator
|
||||
\param point_map Property map to access the input points
|
||||
\param eigen Class with precompute eigenvectors and eigenvalues
|
||||
*/
|
||||
Attribute_distance_to_plane (RandomAccessIterator begin,
|
||||
RandomAccessIterator end,
|
||||
PointMap point_map,
|
||||
const Local_eigen_analysis& eigen)
|
||||
{
|
||||
this->weight = 1.;
|
||||
for(std::size_t i = 0; i < (std::size_t)(end - begin); i++)
|
||||
distance_to_plane_attribute.push_back
|
||||
(CGAL::sqrt (CGAL::squared_distance (get(point_map, begin[i]), eigen.plane(i))));
|
||||
|
||||
this->compute_mean_max (distance_to_plane_attribute, this->mean, this->max);
|
||||
// max *= 2;
|
||||
}
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
virtual double value (std::size_t pt_index)
|
||||
{
|
||||
return distance_to_plane_attribute[pt_index];
|
||||
}
|
||||
|
||||
virtual std::string id() { return "distance_to_plane"; }
|
||||
/// \endcond
|
||||
};
|
||||
|
||||
|
||||
} // namespace Classification
|
||||
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_CLASSIFICATION_ATTRIBUTE_DISTANCE_TO_PLANE_H
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
#ifndef CGAL_CLASSIFICATION_ATTRIBUTE_ECHO_SCATTER_H
|
||||
#define CGAL_CLASSIFICATION_ATTRIBUTE_ECHO_SCATTER_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
namespace Classification {
|
||||
|
||||
/*!
|
||||
\ingroup PkgClassification
|
||||
|
||||
\brief Attribute based on echo scatter.
|
||||
|
||||
The number of returns (echo number) is a useful information
|
||||
provided by most LIDAR sensor. It can help identifying trees.
|
||||
|
||||
\tparam Kernel The geometric kernel used.
|
||||
\tparam RandomAccessIterator Iterator over the input.
|
||||
\tparam PointMap is a model of `ReadablePropertyMap` with value type `Point_3<Kernel>`.
|
||||
\tparam EchoMap is a model of `ReadablePropertyMap` with value type `std::size_t`.
|
||||
*/
|
||||
template <typename Kernel, typename RandomAccessIterator, typename PointMap, typename EchoMap>
|
||||
class Attribute_echo_scatter : public Attribute
|
||||
{
|
||||
typedef Classification::Image<float> Image_float;
|
||||
typedef Classification::Planimetric_grid<Kernel, RandomAccessIterator, PointMap> Grid;
|
||||
|
||||
std::vector<double> echo_scatter;
|
||||
|
||||
public:
|
||||
/*!
|
||||
\brief Constructs the attribute.
|
||||
|
||||
\param begin Iterator to the first input object
|
||||
\param end Past-the-end iterator
|
||||
\param echo_map Property map to access the echo values of the input points
|
||||
\param grid Precomputed `Planimetric_grid`
|
||||
\param grid_resolution Resolution of the planimetric grid
|
||||
\param radius_neighbors Radius of local neighborhoods
|
||||
*/
|
||||
Attribute_echo_scatter (RandomAccessIterator begin,
|
||||
RandomAccessIterator end,
|
||||
EchoMap echo_map,
|
||||
Grid& grid,
|
||||
const double grid_resolution,
|
||||
double radius_neighbors = 1.)
|
||||
{
|
||||
this->weight = 1.;
|
||||
Image_float Scatter(grid.width(), grid.height());
|
||||
for (std::size_t j = 0; j < grid.height(); j++)
|
||||
for (std::size_t i = 0; i < grid.width(); i++)
|
||||
Scatter(i,j)=0;
|
||||
|
||||
std::size_t square = (std::size_t)(0.5 * radius_neighbors / grid_resolution) + 1;
|
||||
|
||||
for (std::size_t j = 0; j < grid.height(); j++){
|
||||
for (std::size_t i = 0; i < grid.width(); i++){
|
||||
|
||||
if(grid.mask(i,j)){
|
||||
|
||||
std::size_t squareXmin = (i < square ? 0 : i - square);
|
||||
std::size_t squareXmax = (std::min) (grid.width()-1, i + square);
|
||||
std::size_t squareYmin = (j < square ? 0 : j - square);
|
||||
std::size_t squareYmax = (std::min) (grid.height()-1, j + square);
|
||||
|
||||
std::size_t NB_echo_sup=0;
|
||||
std::size_t NB_echo_total=0;
|
||||
|
||||
for(std::size_t k = squareXmin; k <= squareXmax; k++){
|
||||
for(std::size_t l = squareYmin; l <= squareYmax; l++){
|
||||
|
||||
if(CGAL::sqrt(pow((double)k-i,2)+pow((double)l-j,2))<=(double)0.5*radius_neighbors/grid_resolution){
|
||||
|
||||
if(grid.indices(k,l).size()>0){
|
||||
|
||||
for(std::size_t t=0; t<grid.indices(k,l).size();t++){
|
||||
|
||||
std::size_t ip = grid.indices(k,l)[t];
|
||||
if(get(echo_map, begin[ip]) > 1)
|
||||
NB_echo_sup++;
|
||||
}
|
||||
|
||||
NB_echo_total=NB_echo_total+grid.indices(k,l).size();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Scatter(i,j)=(float)NB_echo_sup/NB_echo_total;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
for(std::size_t i = 0; i < (std::size_t)(end - begin); i++){
|
||||
std::size_t I= grid.x(i);
|
||||
std::size_t J= grid.y(i);
|
||||
echo_scatter.push_back((double)Scatter(I,J));
|
||||
}
|
||||
this->compute_mean_max (echo_scatter, this->mean, this->max);
|
||||
}
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
virtual double value (std::size_t pt_index)
|
||||
{
|
||||
return echo_scatter[pt_index];
|
||||
}
|
||||
|
||||
virtual std::string id() { return "echo_scatter"; }
|
||||
/// \endcond
|
||||
};
|
||||
|
||||
} // namespace Classification
|
||||
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_CLASSIFICATION_ATTRIBUTE_ECHO_SCATTER_H
|
||||
|
|
@ -0,0 +1,167 @@
|
|||
// Copyright (c) 2016 INRIA Sophia-Antipolis (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
//
|
||||
// Author(s) : Simon Giraudot
|
||||
|
||||
#ifndef CGAL_CLASSIFICATION_ATTRIBUTE_ELEVATION_H
|
||||
#define CGAL_CLASSIFICATION_ATTRIBUTE_ELEVATION_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <CGAL/Classification/Attribute.h>
|
||||
#include <CGAL/Classification/Image.h>
|
||||
#include <CGAL/Classification/Planimetric_grid.h>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
namespace Classification {
|
||||
|
||||
/*!
|
||||
\ingroup PkgClassification
|
||||
|
||||
\brief Attribute based on local elevation.
|
||||
|
||||
The local position of the ground can be computed for urban
|
||||
scenes. This attribute computes the distance to the local
|
||||
estimation of the ground.
|
||||
|
||||
It is useful to discriminate the ground from horizontal roofs.
|
||||
|
||||
\tparam Kernel The geometric kernel used.
|
||||
\tparam RandomAccessIterator Iterator over the input.
|
||||
\tparam PointMap is a model of `ReadablePropertyMap` with value type `Point_3<Kernel>`.
|
||||
|
||||
*/
|
||||
template <typename Kernel, typename RandomAccessIterator, typename PointMap>
|
||||
class Attribute_elevation : public Attribute
|
||||
{
|
||||
typedef typename Kernel::Iso_cuboid_3 Iso_cuboid_3;
|
||||
|
||||
typedef Image<float> Image_float;
|
||||
typedef Planimetric_grid<Kernel, RandomAccessIterator, PointMap> Grid;
|
||||
|
||||
std::vector<double> elevation_attribute;
|
||||
|
||||
public:
|
||||
/*!
|
||||
\brief Constructs the attribute.
|
||||
|
||||
\param begin Iterator to the first input object
|
||||
\param end Past-the-end iterator
|
||||
\param point_map Property map to access the input points
|
||||
\param grid Precomputed `Planimetric_grid`
|
||||
\param grid_resolution Resolution of the planimetric grid
|
||||
\param radius_dtm Radius for digital terrain modeling (must be bigger than the size of a building)
|
||||
|
||||
*/
|
||||
Attribute_elevation (RandomAccessIterator begin,
|
||||
RandomAccessIterator end,
|
||||
PointMap point_map,
|
||||
const Grid& grid,
|
||||
const double grid_resolution,
|
||||
double radius_dtm = -1.)
|
||||
{
|
||||
this->weight = 1.;
|
||||
if (radius_dtm < 0.)
|
||||
radius_dtm = 100. * grid_resolution;
|
||||
|
||||
//DEM
|
||||
Image_float dem(grid.width(),grid.height());
|
||||
|
||||
for (std::size_t j = 0; j < grid.height(); ++ j)
|
||||
for (std::size_t i = 0; i < grid.width(); ++ i)
|
||||
{
|
||||
if (grid.indices(i,j).empty())
|
||||
continue;
|
||||
double mean = 0.;
|
||||
for (std::size_t k = 0; k < grid.indices(i,j).size(); ++ k)
|
||||
mean += get(point_map, begin[grid.indices(i,j)[k]]).z();
|
||||
mean /= grid.indices(i,j).size();
|
||||
dem(i,j) = mean;
|
||||
}
|
||||
|
||||
std::size_t square = (std::size_t)(0.5 * radius_dtm / grid_resolution) + 1;
|
||||
|
||||
Image_float dtm_x(grid.width(),grid.height());
|
||||
|
||||
for (std::size_t j = 0; j < grid.height(); ++ j)
|
||||
{
|
||||
for (std::size_t i = 0; i < grid.width(); ++ i)
|
||||
{
|
||||
std::size_t squareXmin = (i < square ? 0 : i - square);
|
||||
std::size_t squareXmax = (std::min)(grid.width() - 1, i + square);
|
||||
|
||||
std::vector<double> z;
|
||||
z.reserve(squareXmax - squareXmin +1 );
|
||||
for(std::size_t k = squareXmin; k <= squareXmax; k++)
|
||||
if (dem(k,j) != 0.)
|
||||
z.push_back (dem(k,j));
|
||||
if (z.empty())
|
||||
continue;
|
||||
std::nth_element (z.begin(), z.begin() + (z.size() / 10), z.end());
|
||||
dtm_x(i,j) = z[z.size() / 10];
|
||||
}
|
||||
}
|
||||
dem.free();
|
||||
|
||||
Image_float dtm(grid.width(),grid.height());
|
||||
|
||||
for (std::size_t i = 0; i < grid.width(); ++ i)
|
||||
{
|
||||
for (std::size_t j = 0; j < grid.height(); ++ j)
|
||||
{
|
||||
std::size_t squareYmin = (j < square ? 0 : j - square);
|
||||
std::size_t squareYmax = (std::min)(grid.height() - 1, j + square);
|
||||
std::vector<double> z;
|
||||
z.reserve(squareYmax - squareYmin +1 );
|
||||
for(std::size_t l = squareYmin; l <= squareYmax; l++)
|
||||
if (dtm_x(i,l) != 0.)
|
||||
z.push_back (dtm_x(i,l));
|
||||
if (z.empty())
|
||||
continue;
|
||||
std::nth_element (z.begin(), z.begin() + (z.size() / 10), z.end());
|
||||
dtm(i,j) = z[z.size() / 10];
|
||||
}
|
||||
}
|
||||
dtm_x.free();
|
||||
|
||||
elevation_attribute.reserve(end - begin);
|
||||
for (std::size_t i = 0; i < (std::size_t)(end - begin); i++){
|
||||
std::size_t I = grid.x(i);
|
||||
std::size_t J = grid.y(i);
|
||||
elevation_attribute.push_back ((double)(get(point_map, begin[i]).z()-dtm(I,J)));
|
||||
}
|
||||
|
||||
this->compute_mean_max (elevation_attribute, this->mean, this->max);
|
||||
}
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
virtual double value (std::size_t pt_index)
|
||||
{
|
||||
return elevation_attribute[pt_index];
|
||||
}
|
||||
|
||||
virtual std::string id() { return "elevation"; }
|
||||
/// \endcond
|
||||
};
|
||||
|
||||
} // namespace Classification
|
||||
|
||||
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_CLASSIFICATION_ATTRIBUTE_ELEVATION_H
|
||||
|
|
@ -0,0 +1,159 @@
|
|||
// Copyright (c) 2016 INRIA Sophia-Antipolis (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
//
|
||||
// Author(s) : Simon Giraudot
|
||||
|
||||
#ifndef CGAL_CLASSIFICATION_ATTRIBUTE_VERTICAL_DISPERSION_H
|
||||
#define CGAL_CLASSIFICATION_ATTRIBUTE_VERTICAL_DISPERSION_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <CGAL/Classification/Image.h>
|
||||
#include <CGAL/Classification/Planimetric_grid.h>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
namespace Classification {
|
||||
|
||||
/*!
|
||||
\ingroup PkgClassification
|
||||
|
||||
\brief Attribute based on local vertical dispersion of points.
|
||||
|
||||
Urban scenes can often be decomposed as a set of 2D regions with
|
||||
different heights. While these heights are usually piecewise
|
||||
constant or piecewise linear, on some specific parts of the scene
|
||||
such as vegetation, they can become extremely unstable. This
|
||||
attribute quantifies the vertical dispersion of the points on a
|
||||
local Z-cylinder around the points.
|
||||
|
||||
\tparam Kernel The geometric kernel used.
|
||||
\tparam RandomAccessIterator Iterator over the input.
|
||||
\tparam PointMap is a model of `ReadablePropertyMap` with value type `Point_3<Kernel>`.
|
||||
*/
|
||||
template <typename Kernel, typename RandomAccessIterator, typename PointMap>
|
||||
class Attribute_vertical_dispersion : public Attribute
|
||||
{
|
||||
typedef Classification::Image<float> Image_float;
|
||||
typedef Classification::Planimetric_grid<Kernel, RandomAccessIterator, PointMap> Grid;
|
||||
std::vector<double> vertical_dispersion;
|
||||
|
||||
public:
|
||||
/*!
|
||||
\brief Constructs the attribute.
|
||||
|
||||
\param begin Iterator to the first input object
|
||||
\param end Past-the-end iterator
|
||||
\param point_map Property map to access the input points
|
||||
\param grid Precomputed `Planimetric_grid`
|
||||
\param grid_resolution Resolution of the planimetric grid
|
||||
\param radius_neighbors Radius of local neighborhoods
|
||||
*/
|
||||
Attribute_vertical_dispersion (RandomAccessIterator begin,
|
||||
RandomAccessIterator end,
|
||||
PointMap point_map,
|
||||
const Grid& grid,
|
||||
const double grid_resolution,
|
||||
double radius_neighbors = -1.)
|
||||
{
|
||||
this->weight = 1.;
|
||||
if (radius_neighbors < 0.)
|
||||
radius_neighbors = 5. * grid_resolution;
|
||||
|
||||
Image_float Dispersion(grid.width(), grid.height());
|
||||
for (std::size_t j = 0; j < grid.height(); j++)
|
||||
for (std::size_t i = 0; i < grid.width(); i++)
|
||||
Dispersion(i,j)=0;
|
||||
|
||||
std::size_t square = (std::size_t)(0.5 * radius_neighbors / grid_resolution) + 1;
|
||||
typename Kernel::Vector_3 verti (0., 0., 1.);
|
||||
|
||||
for (std::size_t j = 0; j < grid.height(); j++){
|
||||
for (std::size_t i = 0; i < grid.width(); i++){
|
||||
|
||||
if(!(grid.mask(i,j)))
|
||||
continue;
|
||||
std::vector<double> hori;
|
||||
|
||||
std::size_t squareXmin = (i < square ? 0 : i - square);
|
||||
std::size_t squareXmax = (std::min) (grid.width()-1, i + square);
|
||||
std::size_t squareYmin = (j < square ? 0 : j - square);
|
||||
std::size_t squareYmax = (std::min) (grid.height()-1, j + square);
|
||||
|
||||
for(std::size_t k = squareXmin; k <= squareXmax; k++)
|
||||
for(std::size_t l = squareYmin; l <= squareYmax; l++)
|
||||
if(CGAL::sqrt(pow((double)k-i,2)+pow((double)l-j,2))
|
||||
<=(double)0.5*radius_neighbors/grid_resolution
|
||||
&& (grid.indices(k,l).size()>0))
|
||||
for(std::size_t t=0; t<grid.indices(k,l).size();t++)
|
||||
{
|
||||
std::size_t ip = grid.indices(k,l)[t];
|
||||
hori.push_back (get(point_map, begin[ip]).z());
|
||||
}
|
||||
if (hori.empty())
|
||||
continue;
|
||||
|
||||
std::sort (hori.begin(), hori.end());
|
||||
|
||||
std::size_t nb_layers = 1;
|
||||
|
||||
std::vector<bool> occupy (1 + (std::size_t)((hori.back() - hori.front()) / grid_resolution), false);
|
||||
|
||||
std::size_t last_index = 0;
|
||||
for (std::size_t k = 0; k < hori.size(); ++ k)
|
||||
{
|
||||
std::size_t index = (std::size_t)((hori[k] - hori.front()) / grid_resolution);
|
||||
occupy[index] = true;
|
||||
if (index > last_index + 1)
|
||||
++ nb_layers;
|
||||
last_index = index;
|
||||
}
|
||||
|
||||
std::size_t nb_occ = 0;
|
||||
for (std::size_t k = 0; k < occupy.size(); ++ k)
|
||||
if (occupy[k])
|
||||
++ nb_occ;
|
||||
|
||||
Dispersion(i,j)= 1.f - (nb_occ / (float)(occupy.size()));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
for (std::size_t i = 0; i < (std::size_t)(end - begin);i++)
|
||||
{
|
||||
std::size_t I= grid.x(i);
|
||||
std::size_t J= grid.y(i);
|
||||
vertical_dispersion.push_back((double)Dispersion(I,J));
|
||||
}
|
||||
|
||||
this->compute_mean_max (vertical_dispersion, this->mean, this->max);
|
||||
}
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
virtual double value (std::size_t pt_index)
|
||||
{
|
||||
return vertical_dispersion[pt_index];
|
||||
}
|
||||
|
||||
virtual std::string id() { return "vertical_dispersion"; }
|
||||
/// \endcond
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // CGAL_CLASSIFICATION_ATTRIBUTE_VERTICAL_DISPERSION_H
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
// Copyright (c) 2016 INRIA Sophia-Antipolis (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
//
|
||||
// Author(s) : Simon Giraudot
|
||||
|
||||
#ifndef CGAL_CLASSIFICATION_ATTRIBUTE_VERTICALITY_H
|
||||
#define CGAL_CLASSIFICATION_ATTRIBUTE_VERTICALITY_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <CGAL/Classification/Local_eigen_analysis.h>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
namespace Classification {
|
||||
|
||||
/*!
|
||||
\ingroup PkgClassification
|
||||
|
||||
\brief Attribute based on local verticality.
|
||||
|
||||
The orientation of the best fitting plane of a local neighborhood
|
||||
of the considered point can be useful to discriminate facades from
|
||||
the ground.
|
||||
|
||||
\tparam Kernel The geometric kernel used.
|
||||
\tparam RandomAccessIterator Iterator over the input.
|
||||
\tparam PointMap is a model of `ReadablePropertyMap` with value type `Point_3<Kernel>`.
|
||||
\tparam DiagonalizeTraits Solver used for matrix diagonalization.
|
||||
*/
|
||||
template <typename Kernel, typename RandomAccessIterator, typename PointMap,
|
||||
typename DiagonalizeTraits = CGAL::Default_diagonalize_traits<double,3> >
|
||||
class Attribute_verticality : public Attribute
|
||||
{
|
||||
typedef Classification::Local_eigen_analysis<Kernel, RandomAccessIterator,
|
||||
PointMap, DiagonalizeTraits> Local_eigen_analysis;
|
||||
std::vector<double> verticality_attribute;
|
||||
|
||||
public:
|
||||
/*!
|
||||
\brief Constructs the attribute using local eigen analysis.
|
||||
|
||||
\param begin Iterator to the first input object
|
||||
\param end Past-the-end iterator
|
||||
\param eigen Class with precompute eigenvectors and eigenvalues
|
||||
*/
|
||||
Attribute_verticality (RandomAccessIterator begin,
|
||||
RandomAccessIterator end,
|
||||
const Local_eigen_analysis& eigen)
|
||||
{
|
||||
this->weight = 1.;
|
||||
typename Kernel::Vector_3 vertical (0., 0., 1.);
|
||||
|
||||
for (std::size_t i = 0; i < (std::size_t)(end - begin); i++)
|
||||
{
|
||||
typename Kernel::Vector_3 normal = eigen.normal_vector(i);
|
||||
normal = normal / CGAL::sqrt (normal * normal);
|
||||
verticality_attribute.push_back (1. - CGAL::abs(normal * vertical));
|
||||
}
|
||||
|
||||
this->compute_mean_max (verticality_attribute, this->mean, this->max);
|
||||
// max *= 2;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Constructs the attribute using provided normals of points.
|
||||
|
||||
\tparam VectorMap is a model of `ReadablePropertyMap` with value type `Vector_3<Kernel>`.
|
||||
\param begin Iterator to the first input object
|
||||
\param end Past-the-end iterator
|
||||
\param normal_map Property map to access the normal vectors of the input points.
|
||||
*/
|
||||
template <typename VectorMap>
|
||||
Attribute_verticality (const RandomAccessIterator& begin,
|
||||
const RandomAccessIterator& end,
|
||||
VectorMap normal_map)
|
||||
{
|
||||
this->weight = 1.;
|
||||
typename Kernel::Vector_3 vertical (0., 0., 1.);
|
||||
|
||||
for (std::size_t i = 0; i < (std::size_t)(end - begin); i++)
|
||||
{
|
||||
typename Kernel::Vector_3 normal = get(normal_map, begin[i]);
|
||||
normal = normal / CGAL::sqrt (normal * normal);
|
||||
verticality_attribute.push_back (1. - std::fabs(normal * vertical));
|
||||
}
|
||||
|
||||
this->compute_mean_max (verticality_attribute, this->mean, this->max);
|
||||
// max *= 2;
|
||||
}
|
||||
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
virtual double value (std::size_t pt_index)
|
||||
{
|
||||
return verticality_attribute[pt_index];
|
||||
}
|
||||
|
||||
virtual std::string id() { return "verticality"; }
|
||||
/// \endcond
|
||||
};
|
||||
|
||||
} // namespace Classification
|
||||
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_CLASSIFICATION_ATTRIBUTE_VERTICALITY_H
|
||||
|
|
@ -0,0 +1,500 @@
|
|||
// Copyright (c) 2016 INRIA Sophia-Antipolis (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
//
|
||||
// Author(s) : Simon Giraudot
|
||||
|
||||
#ifndef CGAL_CLASSIFICATION_ATTRIBUTES_EIGEN_H
|
||||
#define CGAL_CLASSIFICATION_ATTRIBUTES_EIGEN_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <CGAL/Classification/Local_eigen_analysis.h>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
namespace Classification {
|
||||
|
||||
|
||||
/*!
|
||||
\ingroup PkgClassification
|
||||
|
||||
\brief Attribute based on the eigenvalues of the covariance matrix
|
||||
of a local neighborhood.
|
||||
|
||||
Linearity is defined, for the 3 eigenvalues \f$\lambda_1 \ge
|
||||
\lambda_2 \ge \lambda_3 \ge 0\f$, as:
|
||||
|
||||
\f[
|
||||
\frac{\lambda_1 - \lambda_2}{\lambda_1}
|
||||
\f]
|
||||
\tparam Kernel The geometric kernel used.
|
||||
\tparam RandomAccessIterator Iterator over the input.
|
||||
\tparam PointMap is a model of `ReadablePropertyMap` with value type `Point_3<Kernel>`.
|
||||
\tparam DiagonalizeTraits Solver used for matrix diagonalization.
|
||||
*/
|
||||
template <typename Kernel, typename RandomAccessIterator, typename PointMap,
|
||||
typename DiagonalizeTraits = CGAL::Default_diagonalize_traits<double,3> >
|
||||
class Attribute_linearity : public Attribute
|
||||
{
|
||||
typedef Classification::Local_eigen_analysis<Kernel, RandomAccessIterator,
|
||||
PointMap, DiagonalizeTraits> Local_eigen_analysis;
|
||||
std::vector<double> attrib;
|
||||
public:
|
||||
/*!
|
||||
\brief Constructs the attribute.
|
||||
|
||||
\param begin Iterator to the first input object
|
||||
\param end Past-the-end iterator
|
||||
\param eigen Class with precompute eigenvectors and eigenvalues
|
||||
*/
|
||||
Attribute_linearity (RandomAccessIterator begin,
|
||||
RandomAccessIterator end,
|
||||
Local_eigen_analysis& eigen)
|
||||
{
|
||||
this->weight = 1.;
|
||||
std::size_t size = (std::size_t)(end - begin);
|
||||
attrib.reserve (size);
|
||||
for (std::size_t i = 0; i < size; ++ i)
|
||||
{
|
||||
const typename Local_eigen_analysis::Eigenvalues& ev = eigen.eigenvalue(i);
|
||||
if (ev[2] < 1e-15)
|
||||
attrib.push_back (0.);
|
||||
else
|
||||
attrib.push_back ((ev[2] - ev[1]) / ev[2]);
|
||||
}
|
||||
this->compute_mean_max (attrib, mean, this->max);
|
||||
}
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
virtual double value (std::size_t pt_index)
|
||||
{
|
||||
return attrib[pt_index];
|
||||
}
|
||||
virtual std::string id() { return "linearity"; }
|
||||
/// \endcond
|
||||
};
|
||||
|
||||
/*!
|
||||
\ingroup PkgClassification
|
||||
|
||||
\brief Attribute based on the eigenvalues of the covariance matrix
|
||||
of a local neighborhood.
|
||||
|
||||
Planarity is defined, for the 3 eigenvalues \f$\lambda_1 \ge
|
||||
\lambda_2 \ge \lambda_3 \ge 0\f$, as:
|
||||
|
||||
\f[
|
||||
\frac{\lambda_2 - \lambda_3}{\lambda_1}
|
||||
\f]
|
||||
\tparam Kernel The geometric kernel used.
|
||||
\tparam RandomAccessIterator Iterator over the input.
|
||||
\tparam PointMap is a model of `ReadablePropertyMap` with value type `Point_3<Kernel>`.
|
||||
\tparam DiagonalizeTraits Solver used for matrix diagonalization.
|
||||
*/
|
||||
template <typename Kernel, typename RandomAccessIterator, typename PointMap,
|
||||
typename DiagonalizeTraits = CGAL::Default_diagonalize_traits<double,3> >
|
||||
class Attribute_planarity : public Attribute
|
||||
{
|
||||
typedef Classification::Local_eigen_analysis<Kernel, RandomAccessIterator,
|
||||
PointMap, DiagonalizeTraits> Local_eigen_analysis;
|
||||
std::vector<double> attrib;
|
||||
public:
|
||||
/*!
|
||||
\brief Constructs the attribute.
|
||||
|
||||
\param begin Iterator to the first input object
|
||||
\param end Past-the-end iterator
|
||||
\param eigen Class with precompute eigenvectors and eigenvalues
|
||||
*/
|
||||
Attribute_planarity (RandomAccessIterator begin,
|
||||
RandomAccessIterator end,
|
||||
Local_eigen_analysis& eigen)
|
||||
{
|
||||
this->weight = 1.;
|
||||
std::size_t size = (std::size_t)(end - begin);
|
||||
attrib.reserve (size);
|
||||
for (std::size_t i = 0; i < size; ++ i)
|
||||
{
|
||||
const typename Local_eigen_analysis::Eigenvalues& ev = eigen.eigenvalue(i);
|
||||
if (ev[2] < 1e-15)
|
||||
attrib.push_back (0.);
|
||||
else
|
||||
attrib.push_back ((ev[1] - ev[0]) / ev[2]);
|
||||
}
|
||||
this->compute_mean_max (attrib, mean, this->max);
|
||||
}
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
virtual double value (std::size_t pt_index)
|
||||
{
|
||||
return attrib[pt_index];
|
||||
}
|
||||
virtual std::string id() { return "planarity"; }
|
||||
/// \endcond
|
||||
|
||||
};
|
||||
|
||||
/*!
|
||||
\ingroup PkgClassification
|
||||
|
||||
\brief Attribute based on the eigenvalues of the covariance matrix
|
||||
of a local neighborhood.
|
||||
|
||||
Sphericity is defined, for the 3 eigenvalues \f$\lambda_1 \ge
|
||||
\lambda_2 \ge \lambda_3 \ge 0\f$, as:
|
||||
|
||||
\f[
|
||||
\frac{\lambda_3}{\lambda_1}
|
||||
\f]
|
||||
\tparam Kernel The geometric kernel used.
|
||||
\tparam RandomAccessIterator Iterator over the input.
|
||||
\tparam PointMap is a model of `ReadablePropertyMap` with value type `Point_3<Kernel>`.
|
||||
\tparam DiagonalizeTraits Solver used for matrix diagonalization.
|
||||
*/
|
||||
template <typename Kernel, typename RandomAccessIterator, typename PointMap,
|
||||
typename DiagonalizeTraits = CGAL::Default_diagonalize_traits<double,3> >
|
||||
class Attribute_sphericity : public Attribute
|
||||
{
|
||||
typedef Classification::Local_eigen_analysis<Kernel, RandomAccessIterator,
|
||||
PointMap, DiagonalizeTraits> Local_eigen_analysis;
|
||||
std::vector<double> attrib;
|
||||
public:
|
||||
/*!
|
||||
\brief Constructs the attribute.
|
||||
|
||||
\param begin Iterator to the first input object
|
||||
\param end Past-the-end iterator
|
||||
\param eigen Class with precompute eigenvectors and eigenvalues
|
||||
*/
|
||||
Attribute_sphericity (RandomAccessIterator begin,
|
||||
RandomAccessIterator end,
|
||||
Local_eigen_analysis& eigen)
|
||||
{
|
||||
this->weight = 1.;
|
||||
std::size_t size = (std::size_t)(end - begin);
|
||||
attrib.reserve (size);
|
||||
for (std::size_t i = 0; i < size; ++ i)
|
||||
{
|
||||
const typename Local_eigen_analysis::Eigenvalues& ev = eigen.eigenvalue(i);
|
||||
if (ev[2] < 1e-15)
|
||||
attrib.push_back (0.);
|
||||
else
|
||||
attrib.push_back (ev[0] / ev[2]);
|
||||
}
|
||||
this->compute_mean_max (attrib, mean, this->max);
|
||||
}
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
virtual double value (std::size_t pt_index)
|
||||
{
|
||||
return attrib[pt_index];
|
||||
}
|
||||
virtual std::string id() { return "sphericity"; }
|
||||
/// \endcond
|
||||
};
|
||||
|
||||
/*!
|
||||
\ingroup PkgClassification
|
||||
|
||||
\brief Attribute based on the eigenvalues of the covariance matrix
|
||||
of a local neighborhood.
|
||||
|
||||
Omnivariance is defined, for the 3 eigenvalues \f$\lambda_1 \ge
|
||||
\lambda_2 \ge \lambda_3 \ge 0\f$, as:
|
||||
|
||||
\f[
|
||||
(\lambda_1 \times \lambda_2 \times \lambda_3)^{\frac{1}{3}}
|
||||
\f]
|
||||
\tparam Kernel The geometric kernel used.
|
||||
\tparam RandomAccessIterator Iterator over the input.
|
||||
\tparam PointMap is a model of `ReadablePropertyMap` with value type `Point_3<Kernel>`.
|
||||
\tparam DiagonalizeTraits Solver used for matrix diagonalization.
|
||||
*/
|
||||
template <typename Kernel, typename RandomAccessIterator, typename PointMap,
|
||||
typename DiagonalizeTraits = CGAL::Default_diagonalize_traits<double,3> >
|
||||
class Attribute_omnivariance : public Attribute
|
||||
{
|
||||
typedef Classification::Local_eigen_analysis<Kernel, RandomAccessIterator,
|
||||
PointMap, DiagonalizeTraits> Local_eigen_analysis;
|
||||
std::vector<double> attrib;
|
||||
public:
|
||||
/*!
|
||||
\brief Constructs the attribute.
|
||||
|
||||
\param begin Iterator to the first input object
|
||||
\param end Past-the-end iterator
|
||||
\param eigen Class with precompute eigenvectors and eigenvalues
|
||||
*/
|
||||
Attribute_omnivariance (RandomAccessIterator begin,
|
||||
RandomAccessIterator end,
|
||||
Local_eigen_analysis& eigen)
|
||||
{
|
||||
this->weight = 1.;
|
||||
std::size_t size = (std::size_t)(end - begin);
|
||||
attrib.reserve (size);
|
||||
for (std::size_t i = 0; i < size; ++ i)
|
||||
{
|
||||
const typename Local_eigen_analysis::Eigenvalues& ev = eigen.eigenvalue(i);
|
||||
attrib.push_back (std::pow (std::fabs(ev[0] * ev[1] * ev[2]), 0.333333333));
|
||||
}
|
||||
this->compute_mean_max (attrib, mean, this->max);
|
||||
}
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
virtual double value (std::size_t pt_index)
|
||||
{
|
||||
return attrib[pt_index];
|
||||
}
|
||||
virtual std::string id() { return "omnivariance"; }
|
||||
/// \endcond
|
||||
};
|
||||
|
||||
/*!
|
||||
\ingroup PkgClassification
|
||||
|
||||
\brief Attribute based on the eigenvalues of the covariance matrix
|
||||
of a local neighborhood.
|
||||
|
||||
Anisotropy is defined, for the 3 eigenvalues \f$\lambda_1 \ge
|
||||
\lambda_2 \ge \lambda_3 \ge 0\f$, as:
|
||||
|
||||
\f[
|
||||
\frac{\lambda_1 - \lambda_3}{\lambda_1}
|
||||
\f]
|
||||
\tparam Kernel The geometric kernel used.
|
||||
\tparam RandomAccessIterator Iterator over the input.
|
||||
\tparam PointMap is a model of `ReadablePropertyMap` with value type `Point_3<Kernel>`.
|
||||
\tparam DiagonalizeTraits Solver used for matrix diagonalization.
|
||||
*/
|
||||
template <typename Kernel, typename RandomAccessIterator, typename PointMap,
|
||||
typename DiagonalizeTraits = CGAL::Default_diagonalize_traits<double,3> >
|
||||
class Attribute_anisotropy : public Attribute
|
||||
{
|
||||
typedef Classification::Local_eigen_analysis<Kernel, RandomAccessIterator,
|
||||
PointMap, DiagonalizeTraits> Local_eigen_analysis;
|
||||
std::vector<double> attrib;
|
||||
public:
|
||||
/*!
|
||||
\brief Constructs the attribute.
|
||||
|
||||
\param begin Iterator to the first input object
|
||||
\param end Past-the-end iterator
|
||||
\param eigen Class with precompute eigenvectors and eigenvalues
|
||||
*/
|
||||
Attribute_anisotropy (RandomAccessIterator begin,
|
||||
RandomAccessIterator end,
|
||||
Local_eigen_analysis& eigen)
|
||||
{
|
||||
this->weight = 1.;
|
||||
std::size_t size = (std::size_t)(end - begin);
|
||||
attrib.reserve (size);
|
||||
for (std::size_t i = 0; i < size; ++ i)
|
||||
{
|
||||
const typename Local_eigen_analysis::Eigenvalues& ev = eigen.eigenvalue(i);
|
||||
if (ev[2] < 1e-15)
|
||||
attrib.push_back (0.);
|
||||
else
|
||||
attrib.push_back ((ev[2] - ev[0]) / ev[2]);
|
||||
}
|
||||
this->compute_mean_max (attrib, mean, this->max);
|
||||
}
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
virtual double value (std::size_t pt_index)
|
||||
{
|
||||
return attrib[pt_index];
|
||||
}
|
||||
virtual std::string id() { return "anisotropy"; }
|
||||
/// \endcond
|
||||
};
|
||||
|
||||
/*!
|
||||
\ingroup PkgClassification
|
||||
|
||||
\brief Attribute based on the eigenvalues of the covariance matrix
|
||||
of a local neighborhood.
|
||||
|
||||
Eigentropy is defined, for the 3 eigenvalues \f$\lambda_1 \ge
|
||||
\lambda_2 \ge \lambda_3 \ge 0\f$, as:
|
||||
|
||||
\f[
|
||||
- \sum_{i=1}^3 \lambda_i \times \log{\lambda_i}
|
||||
\f]
|
||||
\tparam Kernel The geometric kernel used.
|
||||
\tparam RandomAccessIterator Iterator over the input.
|
||||
\tparam PointMap is a model of `ReadablePropertyMap` with value type `Point_3<Kernel>`.
|
||||
\tparam DiagonalizeTraits Solver used for matrix diagonalization.
|
||||
*/
|
||||
template <typename Kernel, typename RandomAccessIterator, typename PointMap,
|
||||
typename DiagonalizeTraits = CGAL::Default_diagonalize_traits<double,3> >
|
||||
class Attribute_eigentropy : public Attribute
|
||||
{
|
||||
typedef Classification::Local_eigen_analysis<Kernel, RandomAccessIterator,
|
||||
PointMap, DiagonalizeTraits> Local_eigen_analysis;
|
||||
std::vector<double> attrib;
|
||||
public:
|
||||
/*!
|
||||
\brief Constructs the attribute.
|
||||
|
||||
\param begin Iterator to the first input object
|
||||
\param end Past-the-end iterator
|
||||
\param eigen Class with precompute eigenvectors and eigenvalues
|
||||
*/
|
||||
Attribute_eigentropy (RandomAccessIterator begin,
|
||||
RandomAccessIterator end,
|
||||
Local_eigen_analysis& eigen)
|
||||
{
|
||||
this->weight = 1.;
|
||||
std::size_t size = (std::size_t)(end - begin);
|
||||
attrib.reserve (size);
|
||||
for (std::size_t i = 0; i < size; ++ i)
|
||||
{
|
||||
const typename Local_eigen_analysis::Eigenvalues& ev = eigen.eigenvalue(i);
|
||||
if (ev[0] < 1e-15
|
||||
|| ev[1] < 1e-15
|
||||
|| ev[2] < 1e-15)
|
||||
attrib.push_back (0.);
|
||||
else
|
||||
attrib.push_back (- ev[0] * std::log(ev[0])
|
||||
- ev[1] * std::log(ev[1])
|
||||
- ev[2] * std::log(ev[2]));
|
||||
}
|
||||
this->compute_mean_max (attrib, mean, this->max);
|
||||
}
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
virtual double value (std::size_t pt_index)
|
||||
{
|
||||
return attrib[pt_index];
|
||||
}
|
||||
virtual std::string id() { return "eigentropy"; }
|
||||
/// \endcond
|
||||
};
|
||||
|
||||
/*!
|
||||
\ingroup PkgClassification
|
||||
|
||||
\brief Attribute based on the eigenvalues of the covariance matrix
|
||||
of a local neighborhood.
|
||||
|
||||
The sum of the eigenvalues is defined, for the 3 eigenvalues
|
||||
\f$\lambda_1 \ge \lambda_2 \ge \lambda_3 \ge 0\f$, as:
|
||||
|
||||
\f[
|
||||
\lambda_1 + \lambda_2 + \lambda_3
|
||||
\f]
|
||||
\tparam Kernel The geometric kernel used.
|
||||
\tparam RandomAccessIterator Iterator over the input.
|
||||
\tparam PointMap is a model of `ReadablePropertyMap` with value type `Point_3<Kernel>`.
|
||||
\tparam DiagonalizeTraits Solver used for matrix diagonalization.
|
||||
*/
|
||||
template <typename Kernel, typename RandomAccessIterator, typename PointMap,
|
||||
typename DiagonalizeTraits = CGAL::Default_diagonalize_traits<double,3> >
|
||||
class Attribute_sum_eigenvalues : public Attribute
|
||||
{
|
||||
typedef Classification::Local_eigen_analysis<Kernel, RandomAccessIterator,
|
||||
PointMap, DiagonalizeTraits> Local_eigen_analysis;
|
||||
std::vector<double> attrib;
|
||||
public:
|
||||
/*!
|
||||
\brief Constructs the attribute.
|
||||
|
||||
\param begin Iterator to the first input object
|
||||
\param end Past-the-end iterator
|
||||
\param eigen Class with precompute eigenvectors and eigenvalues
|
||||
*/
|
||||
Attribute_sum_eigenvalues (RandomAccessIterator begin,
|
||||
RandomAccessIterator end,
|
||||
Local_eigen_analysis& eigen)
|
||||
{
|
||||
this->weight = 1.;
|
||||
std::size_t size = (std::size_t)(end - begin);
|
||||
attrib.reserve (size);
|
||||
for (std::size_t i = 0; i < size; ++ i)
|
||||
attrib.push_back (eigen.sum_eigenvalues(i));
|
||||
|
||||
this->compute_mean_max (attrib, mean, this->max);
|
||||
}
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
virtual double value (std::size_t pt_index)
|
||||
{
|
||||
return attrib[pt_index];
|
||||
}
|
||||
virtual std::string id() { return "sum_eigen"; }
|
||||
/// \endcond
|
||||
};
|
||||
|
||||
/*!
|
||||
\ingroup PkgClassification
|
||||
|
||||
\brief Attribute based on the eigenvalues of the covariance matrix
|
||||
of a local neighborhood.
|
||||
|
||||
Surface variation is defined, for the 3 eigenvalues \f$\lambda_1
|
||||
\ge \lambda_2 \ge \lambda_3 \ge 0\f$, as:
|
||||
|
||||
\f[
|
||||
\frac{\lambda_3}{\lambda_1 + \lambda_2 + \lambda_3}
|
||||
\f]
|
||||
\tparam Kernel The geometric kernel used.
|
||||
\tparam RandomAccessIterator Iterator over the input.
|
||||
\tparam PointMap is a model of `ReadablePropertyMap` with value type `Point_3<Kernel>`.
|
||||
\tparam DiagonalizeTraits Solver used for matrix diagonalization.
|
||||
*/
|
||||
template <typename Kernel, typename RandomAccessIterator, typename PointMap,
|
||||
typename DiagonalizeTraits = CGAL::Default_diagonalize_traits<double,3> >
|
||||
class Attribute_surface_variation : public Attribute
|
||||
{
|
||||
typedef Classification::Local_eigen_analysis<Kernel, RandomAccessIterator,
|
||||
PointMap, DiagonalizeTraits> Local_eigen_analysis;
|
||||
std::vector<double> attrib;
|
||||
public:
|
||||
/*!
|
||||
\brief Constructs the attribute.
|
||||
|
||||
\param begin Iterator to the first input object
|
||||
\param end Past-the-end iterator
|
||||
\param eigen Class with precompute eigenvectors and eigenvalues
|
||||
*/
|
||||
Attribute_surface_variation (RandomAccessIterator begin,
|
||||
RandomAccessIterator end,
|
||||
Local_eigen_analysis& eigen)
|
||||
{
|
||||
this->weight = 1.;
|
||||
std::size_t size = (std::size_t)(end - begin);
|
||||
attrib.reserve (size);
|
||||
for (std::size_t i = 0; i < size; ++ i)
|
||||
{
|
||||
const typename Local_eigen_analysis::Eigenvalues& ev = eigen.eigenvalue(i);
|
||||
|
||||
if (ev[0] + ev[1] + ev[2] < 1e-15)
|
||||
attrib.push_back (0.);
|
||||
else
|
||||
attrib.push_back (ev[0] / (ev[0] + ev[1] + ev[2]));
|
||||
}
|
||||
this->compute_mean_max (attrib, mean, this->max);
|
||||
}
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
virtual double value (std::size_t pt_index)
|
||||
{
|
||||
return attrib[pt_index];
|
||||
}
|
||||
virtual std::string id() { return "surface_variation"; }
|
||||
/// \endcond
|
||||
};
|
||||
|
||||
|
||||
} // namespace Classification
|
||||
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_CLASSIFICATION_ATTRIBUTES_EIGEN_H
|
||||
|
|
@ -0,0 +1,136 @@
|
|||
// Copyright (c) 2016 INRIA Sophia-Antipolis (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
//
|
||||
// Author(s) : Simon Giraudot
|
||||
|
||||
#ifndef CGAL_CLASSIFICATION_COLOR_H
|
||||
#define CGAL_CLASSIFICATION_COLOR_H
|
||||
|
||||
#include <CGAL/array.h>
|
||||
|
||||
namespace CGAL {
|
||||
namespace Classification {
|
||||
|
||||
/*!
|
||||
\ingroup PkgClassificationColor
|
||||
|
||||
Color described in red/green/blue space. Each component is stored
|
||||
as an unsigned char ranging from 0 (no color) to 255 (
|
||||
*/
|
||||
typedef CGAL::cpp11::array<unsigned char, 3> RGB_Color;
|
||||
/*!
|
||||
\ingroup PkgClassificationColor
|
||||
|
||||
Color described in hue/saturation/value space. Each component is stored
|
||||
as a double:
|
||||
|
||||
- `hue` ranges from 0° to 360° (corresponding to the color tint)
|
||||
- `saturation` ranges from 0.0 (gray) to 100.0 (full saturation)
|
||||
- `value` ranges from 0.0 (black) to 100.0 (white)
|
||||
*/
|
||||
typedef CGAL::cpp11::array<double, 3> HSV_Color;
|
||||
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
inline HSV_Color rgb_to_hsv (const RGB_Color& c)
|
||||
{
|
||||
double r = (double)(c[0]) / 255.;
|
||||
double g = (double)(c[1]) / 255.;
|
||||
double b = (double)(c[2]) / 255.;
|
||||
double Cmax = (std::max) (r, (std::max) (g, b));
|
||||
double Cmin = (std::min) (r, (std::min) (g, b));
|
||||
double delta = Cmax - Cmin;
|
||||
double H = 0.;
|
||||
|
||||
if (delta != 0.)
|
||||
{
|
||||
if (Cmax == r)
|
||||
H = 60. * ((g - b) / delta);
|
||||
else if (Cmax == g)
|
||||
H = 60. * (((b - r) / delta) + 2.);
|
||||
else
|
||||
H = 60. * (((r - g) / delta) + 4.);
|
||||
}
|
||||
if (H < 0.) H += 360.;
|
||||
double S = (Cmax == 0. ? 0. : 100. * (delta / Cmax));
|
||||
double V = 100. * Cmax;
|
||||
HSV_Color out = {{ H, S, V }};
|
||||
return out;
|
||||
}
|
||||
|
||||
inline RGB_Color hsv_to_rgb (const HSV_Color& c)
|
||||
{
|
||||
double h = c[0];
|
||||
double s = c[1];
|
||||
double v = c[2];
|
||||
|
||||
s /= 100.;
|
||||
v /= 100.;
|
||||
double C = v*s;
|
||||
int hh = (int)(h/60.);
|
||||
double X = C * (1-CGAL::abs (hh % 2 - 1));
|
||||
double r = 0, g = 0, b = 0;
|
||||
|
||||
if( hh>=0 && hh<1 )
|
||||
{
|
||||
r = C;
|
||||
g = X;
|
||||
}
|
||||
else if( hh>=1 && hh<2 )
|
||||
{
|
||||
r = X;
|
||||
g = C;
|
||||
}
|
||||
else if( hh>=2 && hh<3 )
|
||||
{
|
||||
g = C;
|
||||
b = X;
|
||||
}
|
||||
else if( hh>=3 && hh<4 )
|
||||
{
|
||||
g = X;
|
||||
b = C;
|
||||
}
|
||||
else if( hh>=4 && hh<5 )
|
||||
{
|
||||
r = X;
|
||||
b = C;
|
||||
}
|
||||
else
|
||||
{
|
||||
r = C;
|
||||
b = X;
|
||||
}
|
||||
double m = v-C;
|
||||
r += m;
|
||||
g += m;
|
||||
b += m;
|
||||
r *= 255.0;
|
||||
g *= 255.0;
|
||||
b *= 255.0;
|
||||
|
||||
RGB_Color out = {{ (unsigned char)r, (unsigned char)g, (unsigned char)b }};
|
||||
return out;
|
||||
}
|
||||
/// \endcond
|
||||
|
||||
} // namespace Classification
|
||||
} // namespace CGAL
|
||||
|
||||
|
||||
|
||||
#endif // CGAL_CLASSIFICATION_COLOR_H
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
// Copyright (c) 2016 INRIA Sophia-Antipolis (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
//
|
||||
// Author(s) : Simon Giraudot
|
||||
|
||||
#ifndef CGAL_CLASSIFICATION_IMAGE_H
|
||||
#define CGAL_CLASSIFICATION_IMAGE_H
|
||||
|
||||
namespace CGAL {
|
||||
namespace Classification {
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
|
||||
template <typename Type>
|
||||
class Image
|
||||
{
|
||||
std::size_t m_width;
|
||||
std::size_t m_height;
|
||||
Type* m_raw;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
Image () : m_width(0), m_height(0), m_raw (NULL)
|
||||
{
|
||||
}
|
||||
|
||||
Image (std::size_t width, std::size_t height)
|
||||
: m_width (width),
|
||||
m_height (height)
|
||||
{
|
||||
if (m_width * m_height > 0)
|
||||
m_raw = new Type[width * height]();
|
||||
else
|
||||
m_raw = NULL;
|
||||
}
|
||||
|
||||
~Image ()
|
||||
{
|
||||
free();
|
||||
}
|
||||
|
||||
void free()
|
||||
{
|
||||
if (m_raw != NULL)
|
||||
delete[] m_raw;
|
||||
m_raw = NULL;
|
||||
}
|
||||
|
||||
Image (const Image& other)
|
||||
: m_width (other.width()),
|
||||
m_height (other.height())
|
||||
|
||||
{
|
||||
if (m_width * m_height > 0)
|
||||
{
|
||||
m_raw = new Type[m_width * m_height];
|
||||
std::copy (other.m_raw, other.m_raw + (m_width * m_height), this->m_raw);
|
||||
}
|
||||
else
|
||||
m_raw = NULL;
|
||||
}
|
||||
Image& operator= (const Image& other)
|
||||
{
|
||||
if (m_raw != NULL)
|
||||
delete[] m_raw;
|
||||
|
||||
m_raw = NULL;
|
||||
m_width = other.width();
|
||||
m_height = other.height();
|
||||
if (m_width * m_height > 0)
|
||||
{
|
||||
m_raw = new Type[m_width * m_height];
|
||||
std::copy (other.m_raw, other.m_raw + (m_width * m_height), this->m_raw);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::size_t width() const { return m_width; }
|
||||
std::size_t height() const { return m_height; }
|
||||
|
||||
Type& operator() (const std::size_t& x, const std::size_t& y)
|
||||
{
|
||||
// return m_raw[y * m_width + x];
|
||||
return m_raw[x * m_height + y];
|
||||
}
|
||||
const Type& operator() (const std::size_t& x, const std::size_t& y) const
|
||||
{
|
||||
// return m_raw[y * m_width + x];
|
||||
return m_raw[x * m_height + y];
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
/// \endcond
|
||||
|
||||
} // namespace Classification
|
||||
} // namespace CGAL
|
||||
|
||||
|
||||
|
||||
#endif // CGAL_CLASSIFICATION_IMAGE_H
|
||||
|
|
@ -0,0 +1,185 @@
|
|||
#ifndef CGAL_CLASSIFICATION_LOCAL_EIGEN_ANALYSIS_H
|
||||
#define CGAL_CLASSIFICATION_LOCAL_EIGEN_ANALYSIS_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <CGAL/Search_traits_3.h>
|
||||
#include <CGAL/Fuzzy_sphere.h>
|
||||
#include <CGAL/Orthogonal_k_neighbor_search.h>
|
||||
#include <CGAL/Default_diagonalize_traits.h>
|
||||
#include <CGAL/centroid.h>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
namespace Classification {
|
||||
|
||||
/*!
|
||||
\ingroup PkgClassification
|
||||
|
||||
\brief Class that precomputes and stored the eigenvectors and
|
||||
eigenvalues of the covariance matrices of all points of a point
|
||||
set, using a local neighborhood.
|
||||
|
||||
\tparam Kernel The geometric kernel used.
|
||||
\tparam RandomAccessIterator Iterator over the input.
|
||||
\tparam PointMap is a model of `ReadablePropertyMap` with value type `Point_3<Kernel>`.
|
||||
\tparam DiagonalizeTraits Solver used for matrix diagonalization.
|
||||
*/
|
||||
template <typename Kernel, typename RandomAccessIterator, typename PointMap,
|
||||
typename DiagonalizeTraits = CGAL::Default_diagonalize_traits<double,3> >
|
||||
class Local_eigen_analysis
|
||||
{
|
||||
public:
|
||||
typedef typename Kernel::Point_3 Point;
|
||||
typedef typename Kernel::Vector_3 Vector;
|
||||
typedef typename Kernel::Plane_3 Plane;
|
||||
|
||||
typedef CGAL::cpp11::array<double, 3> Eigenvalues; ///< Eigenvalues (sorted in ascending order)
|
||||
|
||||
|
||||
private:
|
||||
std::vector<Eigenvalues> m_eigenvalues;
|
||||
std::vector<double> m_sum_eigenvalues;
|
||||
std::vector<Point> m_centroids;
|
||||
std::vector<Vector> m_smallest_eigenvectors;
|
||||
std::vector<Vector> m_middle_eigenvectors;
|
||||
std::vector<Vector> m_largest_eigenvectors;
|
||||
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
Local_eigen_analysis () { }
|
||||
/// \endcond
|
||||
|
||||
/*!
|
||||
|
||||
\brief Computes the local eigen analysis of an input range based
|
||||
on a local neighborhood.
|
||||
|
||||
\tparam NeighborQuery is a model of `NeighborQuery`
|
||||
\param begin Iterator to the first input object
|
||||
\param end Past-the-end iterator
|
||||
\param point_map Property map to access the input points
|
||||
\param neighbor_query Object used to access neighborhoods of points
|
||||
|
||||
\param mean_range The mean value of the range corresponding to the
|
||||
`knn` number of neighbors is returned by the constructor through
|
||||
this reference.
|
||||
*/
|
||||
template <typename NeighborQuery>
|
||||
Local_eigen_analysis (RandomAccessIterator begin,
|
||||
RandomAccessIterator end,
|
||||
PointMap point_map,
|
||||
const NeighborQuery& neighbor_query,
|
||||
double& mean_range)
|
||||
{
|
||||
std::size_t size = end - begin;
|
||||
m_eigenvalues.reserve (size);
|
||||
m_centroids.reserve (size);
|
||||
m_smallest_eigenvectors.reserve (size);
|
||||
m_middle_eigenvectors.reserve (size);
|
||||
m_largest_eigenvectors.reserve (size);
|
||||
|
||||
mean_range = 0.;
|
||||
|
||||
for (std::size_t i = 0; i < size; i++)
|
||||
{
|
||||
std::vector<std::size_t> neighbors;
|
||||
neighbor_query (get(point_map, begin[i]), std::back_inserter (neighbors));
|
||||
|
||||
std::vector<Point> neighbor_points;
|
||||
for (std::size_t j = 0; j < neighbors.size(); ++ j)
|
||||
neighbor_points.push_back (get(point_map, begin[neighbors[j]]));
|
||||
|
||||
mean_range += CGAL::sqrt (CGAL::squared_distance (get(point_map, begin[i]),
|
||||
get(point_map, begin[neighbors.back()])));
|
||||
|
||||
compute (get(point_map, begin[i]), neighbor_points);
|
||||
}
|
||||
|
||||
mean_range /= size;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Returns the estimated normal vector of the indexed point.
|
||||
*/
|
||||
const Vector& normal_vector (std::size_t index) const { return m_smallest_eigenvectors[index]; }
|
||||
|
||||
/*!
|
||||
\brief Returns the estimated local tangent plane of the index point.
|
||||
*/
|
||||
Plane plane (std::size_t index) const { return Plane (m_centroids[index], m_smallest_eigenvectors[index]); }
|
||||
|
||||
/*!
|
||||
\brief Returns the normalized eigenvalues of the index point.
|
||||
*/
|
||||
const Eigenvalues& eigenvalue (std::size_t index) const { return m_eigenvalues[index]; }
|
||||
|
||||
/*!
|
||||
\brief Returns the sum of eigenvalues of the index point.
|
||||
*/
|
||||
const double& sum_eigenvalues (std::size_t index) const { return m_sum_eigenvalues[index]; }
|
||||
|
||||
private:
|
||||
|
||||
void compute (const Point& query, std::vector<Point>& neighbor_points)
|
||||
{
|
||||
if (neighbor_points.size() == 0)
|
||||
{
|
||||
Eigenvalues v = {{ 0., 0., 0. }};
|
||||
m_eigenvalues.push_back (v);
|
||||
m_centroids.push_back (query);
|
||||
m_smallest_eigenvectors.push_back (Vector (0., 0., 1.));
|
||||
m_middle_eigenvectors.push_back (Vector (0., 1., 0.));
|
||||
m_largest_eigenvectors.push_back (Vector (1., 0., 0.));
|
||||
return;
|
||||
}
|
||||
|
||||
Point centroid = CGAL::centroid (neighbor_points.begin(), neighbor_points.end());
|
||||
m_centroids.push_back (centroid);
|
||||
|
||||
CGAL::cpp11::array<double, 6> covariance = {{ 0., 0., 0., 0., 0., 0. }};
|
||||
|
||||
for (std::size_t i = 0; i < neighbor_points.size(); ++ i)
|
||||
{
|
||||
Vector d = neighbor_points[i] - centroid;
|
||||
covariance[0] += d.x () * d.x ();
|
||||
covariance[1] += d.x () * d.y ();
|
||||
covariance[2] += d.x () * d.z ();
|
||||
covariance[3] += d.y () * d.y ();
|
||||
covariance[4] += d.y () * d.z ();
|
||||
covariance[5] += d.z () * d.z ();
|
||||
}
|
||||
|
||||
Eigenvalues evalues = {{ 0., 0., 0. }};
|
||||
CGAL::cpp11::array<double, 9> evectors = {{ 0., 0., 0.,
|
||||
0., 0., 0.,
|
||||
0., 0., 0. }};
|
||||
|
||||
DiagonalizeTraits::diagonalize_selfadjoint_covariance_matrix
|
||||
(covariance, evalues, evectors);
|
||||
|
||||
// Normalize
|
||||
double sum = evalues[0] + evalues[1] + evalues[2];
|
||||
if (sum > 0.)
|
||||
for (std::size_t i = 0; i < 3; ++ i)
|
||||
evalues[i] = evalues[i] / sum;
|
||||
m_sum_eigenvalues.push_back(sum);
|
||||
m_eigenvalues.push_back (evalues);
|
||||
m_smallest_eigenvectors.push_back (Vector (evectors[0], evectors[1], evectors[2]));
|
||||
m_middle_eigenvectors.push_back (Vector (evectors[3], evectors[4], evectors[5]));
|
||||
m_largest_eigenvectors.push_back (Vector (evectors[6], evectors[7], evectors[8]));
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // CGAL_CLASSIFICATION_LOCAL_EIGEN_ANALYSIS_H
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
#ifndef CGAL_CLASSIFICATION_PLANIMETRIC_GRID_H
|
||||
#define CGAL_CLASSIFICATION_PLANIMETRIC_GRID_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <CGAL/Classification/Image.h>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
namespace Classification {
|
||||
|
||||
/*!
|
||||
\ingroup PkgClassification
|
||||
|
||||
\brief Class that precomputes a 2D planimetric grid used for
|
||||
digital terrain modeling.
|
||||
|
||||
\tparam Kernel The geometric kernel used.
|
||||
\tparam RandomAccessIterator Iterator over the input.
|
||||
\tparam PointMap is a model of `ReadablePropertyMap` with value type `Point_3<Kernel>`.
|
||||
*/
|
||||
|
||||
template <typename Kernel, typename RandomAccessIterator, typename PointMap>
|
||||
class Planimetric_grid
|
||||
{
|
||||
public:
|
||||
typedef typename Kernel::Point_3 Point_3;
|
||||
typedef typename Kernel::Iso_cuboid_3 Iso_cuboid_3;
|
||||
|
||||
private:
|
||||
typedef Image<std::vector<std::size_t> > Image_indices;
|
||||
typedef Image<bool> Image_bool;
|
||||
|
||||
Image_indices m_grid;
|
||||
std::vector<std::size_t> m_x;
|
||||
std::vector<std::size_t> m_y;
|
||||
|
||||
public:
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
Planimetric_grid () { }
|
||||
/// \endcond
|
||||
|
||||
/*
|
||||
\brief Constructs a planimetric grid based on the input range.
|
||||
|
||||
\param begin Iterator to the first input object
|
||||
\param end Past-the-end iterator
|
||||
\param point_map Property map to access the input points
|
||||
\param bbox The bounding box of the input range
|
||||
\param grid_resolution Resolution of the planimetric grid
|
||||
*/
|
||||
Planimetric_grid (const RandomAccessIterator& begin,
|
||||
const RandomAccessIterator& end,
|
||||
PointMap point_map,
|
||||
const Iso_cuboid_3& bbox,
|
||||
const double grid_resolution)
|
||||
{
|
||||
|
||||
std::size_t size = (std::size_t)(end - begin);
|
||||
std::size_t width = (std::size_t)((bbox.xmax() - bbox.xmin()) / grid_resolution) + 1;
|
||||
std::size_t height = (std::size_t)((bbox.ymax() - bbox.ymin()) / grid_resolution) + 1;
|
||||
m_grid = Image_indices (width, height);
|
||||
|
||||
for (std::size_t i = 0; i < size; ++ i)
|
||||
{
|
||||
const Point_3& p = get(point_map, begin[i]);
|
||||
m_x.push_back ((std::size_t)((p.x() - bbox.xmin()) / grid_resolution));
|
||||
m_y.push_back ((std::size_t)((p.y() - bbox.ymin()) / grid_resolution));
|
||||
m_grid(m_x.back(), m_y.back()).push_back (i);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::size_t width() const { return m_grid.width(); }
|
||||
std::size_t height() const { return m_grid.height(); }
|
||||
|
||||
/*!
|
||||
\brief Returns the indices of points lying in the given indexed cell.
|
||||
*/
|
||||
const std::vector<std::size_t>& indices(std::size_t x, std::size_t y) const { return m_grid(x,y); }
|
||||
/*!
|
||||
\brief Returns `true` if the indexed cell is to be used for classification.
|
||||
*/
|
||||
bool mask(std::size_t x, std::size_t y) const { return (!(m_grid(x,y).empty())); }
|
||||
|
||||
/*!
|
||||
\brief Returns the `x` coordinate of the indexed point in the grid.
|
||||
*/
|
||||
std::size_t x(std::size_t index) const { return m_x[index]; }
|
||||
/*!
|
||||
\brief Returns the `y` coordinate of the indexed point in the grid.
|
||||
*/
|
||||
std::size_t y(std::size_t index) const { return m_y[index]; }
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // CGAL_CLASSIFICATION_PLANIMETRIC_GRID_H
|
||||
|
|
@ -0,0 +1,291 @@
|
|||
#ifndef CGAL_CLASSIFICATION_POINT_SET_NEIGHBORHOOD_H
|
||||
#define CGAL_CLASSIFICATION_POINT_SET_NEIGHBORHOOD_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <boost/iterator/counting_iterator.hpp>
|
||||
|
||||
#include <CGAL/Search_traits_3.h>
|
||||
#include <CGAL/Fuzzy_sphere.h>
|
||||
#include <CGAL/Orthogonal_k_neighbor_search.h>
|
||||
#include <CGAL/Default_diagonalize_traits.h>
|
||||
#include <CGAL/centroid.h>
|
||||
#include <CGAL/grid_simplify_point_set.h>
|
||||
|
||||
#include <CGAL/Classification/Image.h>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
namespace Classification {
|
||||
|
||||
/*!
|
||||
\ingroup PkgClassification
|
||||
|
||||
\brief Class that precomputes spatial searching structures and
|
||||
gives easy access to local neighborhoods of points.
|
||||
|
||||
\tparam Kernel The geometric kernel used.
|
||||
\tparam RandomAccessIterator Iterator over the input.
|
||||
\tparam PointMap is a model of `ReadablePropertyMap` with value type `Point_3<Kernel>`.
|
||||
*/
|
||||
template <typename Kernel, typename RandomAccessIterator, typename PointMap>
|
||||
class Point_set_neighborhood
|
||||
{
|
||||
|
||||
typedef typename Kernel::FT FT;
|
||||
typedef typename Kernel::Point_3 Point;
|
||||
|
||||
class My_point_property_map{
|
||||
RandomAccessIterator begin;
|
||||
PointMap point_map;
|
||||
|
||||
public:
|
||||
typedef Point value_type;
|
||||
typedef const value_type& reference;
|
||||
typedef std::size_t key_type;
|
||||
typedef boost::lvalue_property_map_tag category;
|
||||
My_point_property_map () { }
|
||||
My_point_property_map (RandomAccessIterator begin, PointMap point_map)
|
||||
: begin (begin), point_map (point_map) { }
|
||||
reference operator[] (key_type k) const { return get(point_map, begin[k]); }
|
||||
friend inline reference get (const My_point_property_map& ppmap, key_type i)
|
||||
{ return ppmap[i]; }
|
||||
};
|
||||
|
||||
typedef Search_traits_3<Kernel> SearchTraits_3;
|
||||
typedef Search_traits_adapter <std::size_t, My_point_property_map, SearchTraits_3> Search_traits;
|
||||
typedef Sliding_midpoint<Search_traits> Splitter;
|
||||
typedef Distance_adapter<std::size_t, My_point_property_map, Euclidean_distance<SearchTraits_3> > Distance;
|
||||
typedef Kd_tree<Search_traits, Splitter, Tag_true> Tree;
|
||||
typedef Fuzzy_sphere<Search_traits> Sphere;
|
||||
typedef Orthogonal_k_neighbor_search<Search_traits, Distance, Splitter, Tree> Knn;
|
||||
|
||||
|
||||
Tree* m_tree;
|
||||
Distance m_distance;
|
||||
|
||||
std::vector<std::vector<std::size_t> > m_precomputed_neighbors;
|
||||
|
||||
public:
|
||||
|
||||
/*!
|
||||
Functor that returns a neighborhood with a fixed number of points.
|
||||
|
||||
\cgalModels NeighborQuery
|
||||
*/
|
||||
class K_neighbor_query
|
||||
{
|
||||
public:
|
||||
typedef Point_set_neighborhood::Point value_type; ///<
|
||||
private:
|
||||
const Point_set_neighborhood& neighborhood;
|
||||
std::size_t k;
|
||||
public:
|
||||
/*!
|
||||
\brief Constructs a K neighbor query object.
|
||||
\param neighborhood The point set neighborhood structure.
|
||||
\param k The number of neighbors per query.
|
||||
*/
|
||||
K_neighbor_query (const Point_set_neighborhood& neighborhood, std::size_t k)
|
||||
: neighborhood (neighborhood), k(k) { }
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
template <typename OutputIterator>
|
||||
void operator() (const value_type& query, OutputIterator output) const
|
||||
{
|
||||
neighborhood.k_neighbors (query, k, output);
|
||||
}
|
||||
/// \endcond
|
||||
};
|
||||
|
||||
/*!
|
||||
Functor that returns a neighborhood with a fixed radius.
|
||||
|
||||
\cgalModels NeighborQuery
|
||||
*/
|
||||
class Range_neighbor_query
|
||||
{
|
||||
public:
|
||||
typedef Point_set_neighborhood::Point value_type; ///<
|
||||
private:
|
||||
const Point_set_neighborhood& neighborhood;
|
||||
double radius;
|
||||
public:
|
||||
/*!
|
||||
\brief Constructs a range neighbor query object.
|
||||
\param neighborhood The point set neighborhood structure.
|
||||
\param radius The radius of the neighbor query.
|
||||
*/
|
||||
Range_neighbor_query (const Point_set_neighborhood& neighborhood, double radius)
|
||||
: neighborhood (neighborhood), radius(radius) { }
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
template <typename OutputIterator>
|
||||
void operator() (const value_type& query, OutputIterator output) const
|
||||
{
|
||||
neighborhood.range_neighbors (query, radius, output);
|
||||
}
|
||||
/// \endcond
|
||||
};
|
||||
|
||||
friend class K_neighbor_query;
|
||||
friend class Range_neighbor_query;
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
Point_set_neighborhood () : m_tree (NULL) { }
|
||||
/// \endcond
|
||||
|
||||
/*!
|
||||
\brief Constructs a neighborhood object based on the input range.
|
||||
|
||||
\param begin Iterator to the first input object
|
||||
\param end Past-the-end iterator
|
||||
\param point_map Property map to access the input points
|
||||
*/
|
||||
Point_set_neighborhood (const RandomAccessIterator& begin,
|
||||
const RandomAccessIterator& end,
|
||||
PointMap point_map)
|
||||
: m_tree (NULL)
|
||||
{
|
||||
std::size_t size = end - begin;
|
||||
|
||||
My_point_property_map pmap (begin, point_map);
|
||||
m_tree = new Tree (boost::counting_iterator<std::size_t> (0),
|
||||
boost::counting_iterator<std::size_t> (size),
|
||||
Splitter(),
|
||||
Search_traits (pmap));
|
||||
m_distance = Distance (pmap);
|
||||
m_tree->build();
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Constructs a simplified neighborhood object based on the input range.
|
||||
|
||||
This method first computes a simplified version of the input point
|
||||
set by voxelization: a 3D grid is defined and for each subset
|
||||
present in one cell, only the point closest to the centroid of
|
||||
this subset is used.
|
||||
|
||||
\param begin Iterator to the first input object
|
||||
\param end Past-the-end iterator
|
||||
\param point_map Property map to access the input points
|
||||
\param voxel_size
|
||||
*/
|
||||
Point_set_neighborhood (const RandomAccessIterator& begin,
|
||||
const RandomAccessIterator& end,
|
||||
PointMap point_map,
|
||||
double voxel_size)
|
||||
: m_tree (NULL)
|
||||
{
|
||||
// First, simplify
|
||||
std::size_t size = end - begin;
|
||||
std::vector<std::size_t> indices (size);
|
||||
for (std::size_t i = 0; i < indices.size(); ++ i)
|
||||
indices[i] = i;
|
||||
My_point_property_map pmap (begin, point_map);
|
||||
|
||||
voxelize_point_set(indices, pmap, voxel_size);
|
||||
|
||||
m_tree = new Tree (indices.begin(), indices.end(),
|
||||
Splitter(),
|
||||
Search_traits (pmap));
|
||||
m_distance = Distance (pmap);
|
||||
m_tree->build();
|
||||
}
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
~Point_set_neighborhood ()
|
||||
{
|
||||
if (m_tree != NULL)
|
||||
delete m_tree;
|
||||
}
|
||||
/// \endcond
|
||||
|
||||
/*!
|
||||
\brief Returns a neighbor query object with fixed number of neighbors `k`.
|
||||
*/
|
||||
K_neighbor_query k_neighbor_query (const std::size_t k) const
|
||||
{
|
||||
return K_neighbor_query (*this, k);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Returns a neighbor query object with fixed radius `radius`.
|
||||
*/
|
||||
Range_neighbor_query range_neighbor_query (const double radius) const
|
||||
{
|
||||
return Range_neighbor_query (*this, radius);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
template <typename OutputIterator>
|
||||
void range_neighbors (const Point& query, const FT radius_neighbors, OutputIterator output) const
|
||||
{
|
||||
CGAL_assertion (m_tree != NULL);
|
||||
Sphere fs (query, radius_neighbors, 0, m_tree->traits());
|
||||
m_tree->search (output, fs);
|
||||
}
|
||||
|
||||
template <typename OutputIterator>
|
||||
void k_neighbors (const Point& query, const std::size_t k, OutputIterator output) const
|
||||
{
|
||||
CGAL_assertion (m_tree != NULL);
|
||||
Knn search (*m_tree, query, (unsigned int)k, 0, true, m_distance);
|
||||
for (typename Knn::iterator it = search.begin(); it != search.end(); ++ it)
|
||||
*(output ++) = it->first;
|
||||
}
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
template <typename Map>
|
||||
void voxelize_point_set (std::vector<std::size_t>& indices, Map point_map,
|
||||
double voxel_size)
|
||||
{
|
||||
std::map<Point, std::vector<std::size_t> > grid;
|
||||
|
||||
for (std::size_t i = 0; i < indices.size(); ++ i)
|
||||
{
|
||||
const Point& p = get(point_map, indices[i]);
|
||||
Point ref (std::floor(p.x() / voxel_size),
|
||||
std::floor(p.y() / voxel_size),
|
||||
std::floor(p.z() / voxel_size));
|
||||
typename std::map<Point, std::vector<std::size_t> >::iterator it;
|
||||
boost::tie (it, boost::tuples::ignore)
|
||||
= grid.insert (std::make_pair (ref, std::vector<std::size_t>()));
|
||||
it->second.push_back (indices[i]);
|
||||
}
|
||||
indices.clear();
|
||||
for (typename std::map<Point, std::vector<std::size_t> >::iterator
|
||||
it = grid.begin(); it != grid.end(); ++ it)
|
||||
{
|
||||
const std::vector<std::size_t>& pts = it->second;
|
||||
Point centroid = CGAL::centroid (boost::make_transform_iterator
|
||||
(pts.begin(),
|
||||
CGAL::Property_map_to_unary_function<Map>(point_map)),
|
||||
boost::make_transform_iterator
|
||||
(pts.end(),
|
||||
CGAL::Property_map_to_unary_function<Map>(point_map)));
|
||||
std::size_t chosen = 0;
|
||||
double min_dist = (std::numeric_limits<double>::max)();
|
||||
for (std::size_t i = 0; i < pts.size(); ++ i)
|
||||
{
|
||||
double dist = CGAL::squared_distance(get(point_map, pts[i]), centroid);
|
||||
if (dist < min_dist)
|
||||
{
|
||||
min_dist = dist;
|
||||
chosen = pts[i];
|
||||
}
|
||||
}
|
||||
indices.push_back (chosen);
|
||||
}
|
||||
}
|
||||
/// \endcond
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // CGAL_CLASSIFICATION_POINT_SET_POINT_SET_NEIGHBORHOOD_H
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
#ifndef CGAL_CLASSIFICATION_TYPE_H
|
||||
#define CGAL_CLASSIFICATION_TYPE_H
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
namespace Classification {
|
||||
|
||||
/*!
|
||||
\ingroup PkgClassification
|
||||
|
||||
\brief Classification type.
|
||||
|
||||
A type is what is sought after when performing classification on an
|
||||
input set (for example: vegetation, ground, etc.). It is defined
|
||||
as a set of relationship with classification attributes.
|
||||
|
||||
*/
|
||||
class Type
|
||||
{
|
||||
public:
|
||||
|
||||
enum Attribute_effect /// Defines how an attribute affects this type.
|
||||
{
|
||||
FAVORED_ATT = 0, ///< High values of the attribute favor this type
|
||||
NEUTRAL_ATT = 1, ///< The attribute has no effect on this type
|
||||
PENALIZED_ATT = 2 ///< Low values of the attribute favor this type
|
||||
};
|
||||
|
||||
private:
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
std::string m_id;
|
||||
std::map<Attribute_handle, Attribute_effect> m_attribute_effects;
|
||||
/// \endcond
|
||||
|
||||
public:
|
||||
|
||||
/*!
|
||||
\param id The name of the classification type
|
||||
(e.g. vegetation).
|
||||
*/
|
||||
Type (std::string id) : m_id (id) { }
|
||||
|
||||
/*!
|
||||
\brief Sets how an attribute affects the classification type.
|
||||
|
||||
\param att Attribute whose effect on the classification type is set
|
||||
|
||||
\param effect The effect the attribute has on the classification type
|
||||
|
||||
*/
|
||||
void set_attribute_effect (Attribute_handle att, Attribute_effect effect)
|
||||
{
|
||||
m_attribute_effects[att] = effect;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Returns the effect of attribute `att` on the classification type.
|
||||
*/
|
||||
Attribute_effect attribute_effect (Attribute_handle att)
|
||||
{
|
||||
std::map<Attribute_handle, Attribute_effect>::iterator
|
||||
search = m_attribute_effects.find (att);
|
||||
return (search == m_attribute_effects.end () ? NEUTRAL_ATT : search->second);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Returns the ID of the classification type.
|
||||
*/
|
||||
const std::string& id() const { return m_id; }
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
void info()
|
||||
{
|
||||
std::cerr << "Attribute " << m_id << ": ";
|
||||
for (std::map<Attribute_handle, Attribute_effect>::iterator it = m_attribute_effects.begin();
|
||||
it != m_attribute_effects.end(); ++ it)
|
||||
{
|
||||
if (it->second == NEUTRAL_ATT)
|
||||
continue;
|
||||
|
||||
std::cerr << it->first;
|
||||
if (it->second == FAVORED_ATT) std::cerr << " (favored), ";
|
||||
else if (it->second == PENALIZED_ATT) std::cerr << " (penalized), ";
|
||||
}
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
/// \endcond
|
||||
|
||||
};
|
||||
|
||||
#ifdef DOXYGEN_RUNNING
|
||||
/*!
|
||||
\ingroup PkgClassification
|
||||
|
||||
\brief Handle to a classification `Type`.
|
||||
|
||||
\cgalModels Handle
|
||||
*/
|
||||
class Type_handle { };
|
||||
#else
|
||||
typedef boost::shared_ptr<Type> Type_handle;
|
||||
#endif
|
||||
|
||||
} // namespace Classification
|
||||
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_CLASSIFICATION_TYPE_H
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
# Created by the script cgal_create_CMakeLists
|
||||
# This is the CMake script for compiling a set of CGAL applications.
|
||||
|
||||
project( Classification )
|
||||
|
||||
|
||||
cmake_minimum_required(VERSION 2.8.11)
|
||||
|
||||
# CGAL and its components
|
||||
find_package( CGAL QUIET COMPONENTS )
|
||||
|
||||
if ( NOT CGAL_FOUND )
|
||||
|
||||
message(STATUS "This project requires the CGAL library, and will not be compiled.")
|
||||
return()
|
||||
|
||||
endif()
|
||||
|
||||
# include helper file
|
||||
include( ${CGAL_USE_FILE} )
|
||||
|
||||
|
||||
# Boost and its components
|
||||
find_package( Boost REQUIRED )
|
||||
|
||||
# Use Eigen
|
||||
find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater)
|
||||
if (EIGEN3_FOUND)
|
||||
include( ${EIGEN3_USE_FILE} )
|
||||
endif()
|
||||
|
||||
if ( NOT Boost_FOUND )
|
||||
|
||||
message(STATUS "This project requires the Boost library, and will not be compiled.")
|
||||
|
||||
return()
|
||||
|
||||
endif()
|
||||
|
||||
# include for local directory
|
||||
include_directories( BEFORE include )
|
||||
|
||||
# include for local package
|
||||
include_directories( BEFORE ../../include )
|
||||
|
||||
|
||||
# Creating entries for all C++ files with "main" routine
|
||||
# ##########################################################
|
||||
|
||||
include( CGAL_CreateSingleSourceCGALProgram )
|
||||
|
||||
#add_definitions("-DCGAL_DO_NOT_USE_BOYKOV_KOLMOGOROV_MAXFLOW_SOFTWARE")
|
||||
|
||||
|
||||
create_single_source_cgal_program( "test_features.cpp" )
|
||||
create_single_source_cgal_program( "test_graphcut.cpp" )
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
//#include <CGAL/Simple_cartesian.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Classifier.h>
|
||||
#include <CGAL/Classification/Helper.h>
|
||||
#include <CGAL/IO/read_ply_points.h>
|
||||
|
||||
#include <CGAL/Timer.h>
|
||||
|
||||
#include <CGAL/Point_set_3.h>
|
||||
#include <CGAL/Point_set_3/IO.h>
|
||||
|
||||
//typedef CGAL::Simple_cartesian<double> Kernel;
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
|
||||
typedef Kernel::Point_3 Point;
|
||||
|
||||
typedef CGAL::Point_set_3<Point> Point_set;
|
||||
typedef Point_set::iterator Iterator;
|
||||
typedef Point_set::Point_map Pmap;
|
||||
|
||||
typedef CGAL::Classifier<Iterator, Pmap> Classification;
|
||||
typedef CGAL::Classification::Helper<Kernel, Iterator, Pmap> Helper;
|
||||
|
||||
int main (int argc, char** argv)
|
||||
{
|
||||
|
||||
std::string filename (argc > 1 ? argv[1] : "data/portland_mini.ply");
|
||||
std::ifstream in (filename.c_str());
|
||||
|
||||
Point_set pts;
|
||||
std::cerr << "[READING INPUT]" << std::endl;
|
||||
if (!in
|
||||
|| !(CGAL::read_ply_point_set (in, pts)))
|
||||
{
|
||||
std::cerr << "Error: cannot read " << filename << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
std::string configname (argc > 2 ? argv[2] : "data/portland_mini.xml");
|
||||
|
||||
std::cerr << "[LOADING CONFIG]" << std::endl;
|
||||
|
||||
Classification psc (pts.begin (), pts.end(), pts.point_map());
|
||||
|
||||
Helper helper (configname.c_str(), // load XML config
|
||||
psc,
|
||||
pts.begin(), pts.end(), pts.point_map());
|
||||
|
||||
std::cerr << "[RUNNING WITH GRAPHCUT]" << std::endl;
|
||||
|
||||
CGAL::Timer t;
|
||||
t.start();
|
||||
psc.run_with_graphcut (helper.neighborhood(), 0.5);
|
||||
t.stop();
|
||||
std::cerr << "Grapcut computed in " << t.time() << " second(s)" << std::endl;
|
||||
|
||||
std::cerr << std::endl << "[WRITING OUTPUT]" << std::endl;
|
||||
|
||||
std::ofstream f ("output.ply");
|
||||
f.precision(18);
|
||||
srand (time (NULL)); // to get different colors everytime
|
||||
|
||||
helper.write_ply (f, pts.begin(), pts.end(), pts.point_map(), psc);
|
||||
|
||||
std::cerr << "[ALL DONE]" << std::endl;
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -66,6 +66,7 @@ Three
|
|||
Triangulation_3
|
||||
Triangulation
|
||||
Ridges_3
|
||||
Point_set_3
|
||||
Point_set_processing_3
|
||||
Point_set_shape_detection_3
|
||||
Polyline_simplification_2
|
||||
|
|
@ -95,6 +96,6 @@ Barycentric_coordinates_2
|
|||
Surface_mesh
|
||||
Surface_mesh_shortest_path
|
||||
Polygon_mesh_processing
|
||||
|
||||
Classification
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -115,9 +115,11 @@ h1 {
|
|||
\package_listing{Surface_mesh_skeletonization}
|
||||
\package_listing{Ridges_3}
|
||||
\package_listing{Jet_fitting_3}
|
||||
\package_listing{Point_set_3}
|
||||
\package_listing{Point_set_processing_3}
|
||||
\package_listing{Point_set_shape_detection_3}
|
||||
\package_listing{Stream_lines_2}
|
||||
\package_listing{Classification}
|
||||
|
||||
|
||||
\section PartSearchStructures Spatial Searching and Sorting
|
||||
|
|
|
|||
|
|
@ -1060,6 +1060,16 @@ note = {\url{ttp://hal.inria.fr/inria-00090522}}
|
|||
annote = {map,generalized map},
|
||||
}
|
||||
|
||||
@article{cgal:lm-clscm-12,
|
||||
author = {Lafarge, Florent and Mallet, Clement},
|
||||
title = {{Creating large-scale city models from 3D-point clouds: a robust approach with hybrid representation}},
|
||||
journal = {International Journal of Computer Vision},
|
||||
volume = {99},
|
||||
number = {1},
|
||||
pages = {69-85},
|
||||
year = {2012},
|
||||
}
|
||||
|
||||
@inproceedings{ cgal:lt-fmeps-98,
|
||||
author = "Peter Lindstrom and Greg Turk",
|
||||
title = "Fast and memory efficient polygonal simplification",
|
||||
|
|
@ -1295,6 +1305,20 @@ ABSTRACT = {We present the first complete, exact and efficient C++ implementatio
|
|||
update = "09.11 penarand"
|
||||
}
|
||||
|
||||
@article{cgal:mbrsh-raofw-11,
|
||||
title = "Relevance assessment of full-waveform lidar data for urban area classification ",
|
||||
journal = "\{ISPRS\} Journal of Photogrammetry and Remote Sensing ",
|
||||
volume = "66",
|
||||
number = "6, Supplement",
|
||||
pages = "S71 - S84",
|
||||
year = "2011",
|
||||
note = "Advances in \{LIDAR\} Data Processing and Applications ",
|
||||
issn = "0924-2716",
|
||||
doi = "http://dx.doi.org/10.1016/j.isprsjprs.2011.09.008",
|
||||
url = "http://www.sciencedirect.com/science/article/pii/S0924271611001055",
|
||||
author = "Clément Mallet and Frédéric Bretar and Michel Roux and Uwe Soergel and Christian Heipke"
|
||||
}
|
||||
|
||||
@article{cgal:ml-cfsg-00
|
||||
, author = "G. Medioni and M. Lee and C. Tang"
|
||||
, title = "A Computational Framework for Segmentation and Grouping"
|
||||
|
|
|
|||
|
|
@ -262,6 +262,13 @@ and <code>src/</code> directories).
|
|||
This API was deprecated since CGAL 4.4.
|
||||
</li>
|
||||
</ul>
|
||||
<h3>3D Point Set</h3>
|
||||
<ul>
|
||||
<li>New package providing a flexible data
|
||||
structure <code>CGAL::Point_set_3</code> that allows the user to
|
||||
easily handle point sets with an arbitrary number of attributes
|
||||
(such as normal vectors, colors, labeling, etc.).</li>
|
||||
</ul>
|
||||
<h3>Point Set Processing</h3>
|
||||
<ul>
|
||||
<li>New function <code>CGAL::read_ply_custom_points()</code> that
|
||||
|
|
@ -478,6 +485,13 @@ and <code>src/</code> directories).
|
|||
<code>CGAL::write_ply_points()</code>
|
||||
and <code>CGAL::write_ply_points_and_normals()</code>.</li>
|
||||
</ul>
|
||||
<h3>Point Set Shape Detection</h3>
|
||||
<ul>
|
||||
<li>New post-processing
|
||||
algorithm: <code>CGAL::regularize_planes()</code>. This allows the user
|
||||
to favor parallelism, orthogonality, coplanarity and/or axial
|
||||
symmetry between detected planes.</li>
|
||||
</ul>
|
||||
<h3>Surface Mesh Parameterization</h3>
|
||||
<ul>
|
||||
<li><code>LSCM_parameterizer_3</code> now uses by default Eigen
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
@INCLUDE = ${CGAL_DOC_PACKAGE_DEFAULTS}
|
||||
PROJECT_NAME = "CGAL ${CGAL_DOC_VERSION} - 3D Point Set"
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
/*!
|
||||
\defgroup PkgPointSet3 3D Point Set Reference
|
||||
|
||||
\cgalPkgDescriptionBegin{3D Point Set, PkgPointSet3Summary}
|
||||
\cgalPkgPicture{point_set_3.png}
|
||||
|
||||
\cgalPkgSummaryBegin
|
||||
\cgalPkgAuthors{Simon Giraudot}
|
||||
\cgalPkgDesc{This component provides the user with a flexible 3D point set data structure. The user can define any additional property needed such as normal vectors, colors or labels. \cgal algorithms can be easily applied to this data structure.}
|
||||
|
||||
\cgalPkgManuals{Chapter_Point_Set_3, PkgPointSet3}
|
||||
\cgalPkgSummaryEnd
|
||||
|
||||
\cgalPkgShortInfoBegin
|
||||
\cgalPkgSince{4.10}
|
||||
\cgalPkgBib{cgal:g-ps}
|
||||
\cgalPkgLicense{\ref licensesGPL "GPL"}
|
||||
\cgalPkgDemo{Operations on Polyhedra,polyhedron_3.zip}
|
||||
\cgalPkgShortInfoEnd
|
||||
|
||||
\cgalPkgDescriptionEnd
|
||||
|
||||
\cgalClassifedRefPages
|
||||
|
||||
## Class ##
|
||||
- `CGAL::Point_set_3<Point,Vector>`
|
||||
|
||||
|
||||
\defgroup PkgPointSet3PointSetProcessing3 Point Set Processing
|
||||
\ingroup PkgPointSet3
|
||||
|
||||
\brief This module offers convenience overloads of functions available in the
|
||||
\ref PkgPointSetProcessingSummary package. These overloads allow the
|
||||
user to call point set processing algorithms without having to handle
|
||||
manually property maps and iterators.
|
||||
|
||||
The overloads, available after including
|
||||
`CGAL/Point_set_3/Point_set_processing_3.h`, all follow the same
|
||||
pattern based on the original point set processing functions:
|
||||
|
||||
- Iterators and property maps of the original functions are replaced
|
||||
with a single parameter `CGAL::Point_set_3<Point,Vector>`
|
||||
|
||||
- The other parameters (and their potential default values) are
|
||||
following in the same order as the original function.
|
||||
|
||||
For a complete documentation of these functions, please refer to the
|
||||
\ref PkgPointSetProcessing manual.
|
||||
|
||||
\defgroup PkgPointSet3IO Input/Output
|
||||
\ingroup PkgPointSet3
|
||||
|
||||
\brief This module offers convenience overloads of input/ouput
|
||||
functions available in the \ref PkgPointSetProcessingSummary package.
|
||||
These overloads, available after including `CGAL/Point_set_3/IO.h`,
|
||||
allow the user to call point set processing algorithms without having
|
||||
to handle manually property maps and iterators.
|
||||
|
||||
Input functions instanciate all the necessary property maps:
|
||||
|
||||
- if found in the input, normal vectors are stored in the usual
|
||||
`CGAL::Point_set_3` property `normal` with template type `Vector`
|
||||
|
||||
- for PLY input only, other properties are stored as properties in the
|
||||
`Point_set_3` class with the name and type given by the PLY header
|
||||
|
||||
For a complete documentation of these functions, please refer to the
|
||||
\ref PkgPointSetProcessing manual.
|
||||
|
||||
*/
|
||||
|
|
@ -0,0 +1,178 @@
|
|||
namespace CGAL {
|
||||
/*!
|
||||
|
||||
\mainpage User Manual
|
||||
\anchor Chapter_Point_Set_3
|
||||
\cgalAutoToc
|
||||
\author Simon Giraudot
|
||||
|
||||
|
||||
\cgal provides several algorithms for processing point sets, ranging from
|
||||
\ref Chapter_Point_Set_Shape_Detection "Shape Detection" to
|
||||
\ref Chapter_Advancing_Front_Surface_Reconstruction "Surface Reconstruction"
|
||||
through standard \ref Chapter_Point_Set_Processing "Point Set Processing" tools.
|
||||
|
||||
While these algorithms do not impose specific data structures to work
|
||||
on, \cgal provides a 3D point set structure to make it easier for the
|
||||
user to handle additional properties such as normal vectors, colors,
|
||||
labels, and to call \cgal algorithms on them.
|
||||
|
||||
|
||||
\section Point_set_3_Principle General Principle
|
||||
|
||||
`CGAL::Point_set_3<Point,Vector>` is a vector based data structure
|
||||
that contains by default a property named _point_ with template
|
||||
`Point` type.
|
||||
|
||||
Any property the user needs can be easily added, modified and
|
||||
removed. A property is identified by a unique name and a
|
||||
type. Convenience methods are provided to handle the property named
|
||||
_normal_ with template type `Vector` that is a very common property on
|
||||
point sets.
|
||||
|
||||
Reordering is achieved by swapping index values: this guarantees that
|
||||
these operations have a constant complexity no matter how many
|
||||
properties are defined. To avoid frequent memory allocation and
|
||||
deallocation, removal of points is also handled by swapping the index
|
||||
values, putting the points marked as removed at the back of the index
|
||||
property and keeping track of the number of points marked as
|
||||
removed. If the user needs memory to be deallocated, the element
|
||||
marked as removed can be actually deleted from memory.
|
||||
|
||||
\section Point_set_3_Usage Simple Usage
|
||||
|
||||
The data structure is designed to be easy to use despite its potential
|
||||
complexity when using properties. Several convenience methods are
|
||||
provided to handle points and normals without having to handle
|
||||
properties directly.
|
||||
|
||||
The following example shows how to fill a point set with points, add a
|
||||
normal property, set the normal values, add or remove an item, etc.
|
||||
|
||||
\cgalExample{Point_set_3/point_set.cpp}
|
||||
|
||||
\section Point_set_3_Properties Using Additional Properties
|
||||
|
||||
Every information in the point set is a property. A raw point set
|
||||
comes with a _point_ property only. As we saw in the previous section,
|
||||
the user can easily add a _normal_ property. But this mechanism is
|
||||
generalized to any type of property.
|
||||
|
||||
The following example shows how to define a color property and an
|
||||
intensity property, and how to modify the point set according to this.
|
||||
|
||||
\cgalExample{Point_set_3/point_set_property.cpp}
|
||||
|
||||
\section Point_set_3_Algorithms Applying CGAL Algorithms
|
||||
|
||||
Most \cgal algorithms let the user free to choose whatever data
|
||||
structures he/she needs: the points and attributes are then access
|
||||
through iterators and property maps. The `CGAL::Point_set_3`
|
||||
structure directly provides these iterators and property maps so that
|
||||
applying \cgal algorithms to it is straightforward.
|
||||
|
||||
In addition, all functions of the package
|
||||
\ref Chapter_Point_Set_Processing "Point Set Processing" are overloaded so
|
||||
that the user only has to call them with the `CGAL::Point_set_3`
|
||||
object as a parameter to replace all property maps and iterators.
|
||||
|
||||
\subsection Point_set_3_PSP Point Set Processing
|
||||
|
||||
The following example shows how to apply some algorithms from the
|
||||
\cgal library using a point set object:
|
||||
|
||||
- generating a point set around a sphere
|
||||
|
||||
- estimating the normals with `CGAL::jet_estimate_normals()`
|
||||
|
||||
- simplifying the point set with `CGAL::grid_simplify_point_set()`
|
||||
|
||||
- detecting the sphere shape with `CGAL::Shape_detection_3::Efficient_RANSAC`
|
||||
|
||||
\cgalExample{Point_set_3/point_set_algo.cpp}
|
||||
|
||||
\subsection Point_set_3_IO Input/Output
|
||||
|
||||
The following example reads a point set in the XYZ format, normalizes
|
||||
and inverts the normal vectors and write the result in the OFF
|
||||
format.
|
||||
|
||||
\cgalExample{Point_set_3/point_set_read_xyz.cpp}
|
||||
|
||||
The PLY format is the usual choice when storing an arbitrary number of
|
||||
additional properties of points is needed. \cgal provides a function
|
||||
`read_ply_point_set()` that allows the user to recover any PLY
|
||||
property he/she wants, provided the adapted PLY interpreter is
|
||||
implemented.
|
||||
|
||||
The `CGAL::Point_set_3` object is filled with all readable properties
|
||||
of a PLY input. Each PLY property is read and stored into a point set
|
||||
property with similar name and type.
|
||||
|
||||
For example, if the following line is found in the PLY header:
|
||||
|
||||
> property uchar red
|
||||
|
||||
Then a property named _red_ and with type `boost::uint8_t` (`boost`
|
||||
types are used because of their fixed memory size) will be
|
||||
instantiated in the point set and filled with the corresponding
|
||||
values.
|
||||
|
||||
Only points and normals are recovered as properties with complex class
|
||||
types (namely the template types `Point` and `Vector`). Other
|
||||
properties are stored with simple number types. For example, if a
|
||||
color is given with integer red, green and blue values, 3 integer
|
||||
properties _red_, _green_ and _blue_ will be instantiated. A
|
||||
user-defined interpreter must be implemented if such properties should
|
||||
be stored all together (a unique property _color_ of type
|
||||
`CGAL::cpp11::array` for example).
|
||||
|
||||
The following example shows how to use this interpreter and how to
|
||||
recover a specific property afterwards:
|
||||
|
||||
\cgalExample{Point_set_3/point_set_read_ply.cpp}
|
||||
|
||||
\subsection Point_set_3_Avdanced Advanced Usage
|
||||
|
||||
Using functions of \cgal to read files requires a slightly different
|
||||
behavior because, internally, the properties of an item are defined
|
||||
_before_ this item is inserted into the point set (which is not
|
||||
possible with `CGAL::Point_set_3`). Although using the provided
|
||||
overloads presented in the previous subsection should cover most
|
||||
usages, we document the specific back inserters and property maps that
|
||||
are used internally:
|
||||
|
||||
- `CGAL::Point_set_3::index_back_inserter()` is used as an output iterator that creates
|
||||
new item
|
||||
|
||||
- `CGAL::Point_set_3::point_push_map()` is a property map that is allowed to create a
|
||||
new item if it was not yet created by the back inserter
|
||||
|
||||
- `CGAL::Point_set_3::normal_push_map()` works similarly
|
||||
|
||||
Such _push property maps_ are also available for other user-defined
|
||||
properties (see `CGAL::Point_set_3::push_property_map()`).
|
||||
|
||||
The following example shows how to read OFF point without using the
|
||||
overload provided for `CGAL::Point_set_3`:
|
||||
|
||||
\cgalExample{Point_set_3/point_set_advanced.cpp}
|
||||
|
||||
\section Point_set_3_History History
|
||||
|
||||
This package has been created to fill the need for a practical data
|
||||
structure that handles points with a user-defined set of
|
||||
properties. This property mechanism was already implemented in the
|
||||
\ref Chapter_3D_Surface_mesh "Surface Mesh" package: all the classes
|
||||
dedicated to the management of properties were extracted so that they
|
||||
can be used in this _3D Point Set_
|
||||
package. `CGAL::Surface_mesh<Point>` and
|
||||
`CGAL::Point_set_3<Point,Vector>` follow a similar API for property
|
||||
management.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
*/
|
||||
} /* namespace CGAL */
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
Manual
|
||||
Kernel_23
|
||||
STL_Extension
|
||||
Algebraic_foundations
|
||||
Circulator
|
||||
Stream_support
|
||||
Point_set_processing_3
|
||||
Point_set_shape_detection_3
|
||||
Advancing_front_surface_reconstruction
|
||||
Surface_mesh
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
/*!
|
||||
\example Point_set_3/point_set.cpp
|
||||
\example Point_set_3/point_set_property.cpp
|
||||
\example Point_set_3/point_set_algo.cpp
|
||||
\example Point_set_3/point_set_read_xyz.cpp
|
||||
\example Point_set_3/point_set_read_ply.cpp
|
||||
\example Point_set_3/point_set_advanced.cpp
|
||||
*/
|
||||
|
After Width: | Height: | Size: 9.1 KiB |
|
|
@ -0,0 +1,64 @@
|
|||
# Created by the script cgal_create_CMakeLists
|
||||
# This is the CMake script for compiling a set of CGAL applications.
|
||||
|
||||
project( Point_set_3 )
|
||||
|
||||
|
||||
cmake_minimum_required(VERSION 2.8.11)
|
||||
|
||||
# CGAL and its components
|
||||
find_package( CGAL QUIET COMPONENTS )
|
||||
|
||||
if ( NOT CGAL_FOUND )
|
||||
|
||||
message(STATUS "This project requires the CGAL library, and will not be compiled.")
|
||||
return()
|
||||
|
||||
endif()
|
||||
|
||||
# include helper file
|
||||
include( ${CGAL_USE_FILE} )
|
||||
|
||||
|
||||
# Boost and its components
|
||||
find_package( Boost REQUIRED )
|
||||
|
||||
if ( NOT Boost_FOUND )
|
||||
|
||||
message(STATUS "This project requires the Boost library, and will not be compiled.")
|
||||
|
||||
return()
|
||||
|
||||
endif()
|
||||
|
||||
# include for local directory
|
||||
include_directories( BEFORE include )
|
||||
|
||||
# include for local package
|
||||
include_directories( BEFORE ../../include )
|
||||
|
||||
|
||||
# Creating entries for all C++ files with "main" routine
|
||||
# ##########################################################
|
||||
|
||||
include( CGAL_CreateSingleSourceCGALProgram )
|
||||
|
||||
create_single_source_cgal_program( "point_set.cpp" )
|
||||
create_single_source_cgal_program( "point_set_property.cpp" )
|
||||
create_single_source_cgal_program( "point_set_read_xyz.cpp" )
|
||||
create_single_source_cgal_program( "point_set_read_ply.cpp" )
|
||||
create_single_source_cgal_program( "point_set_advanced.cpp" )
|
||||
|
||||
find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater)
|
||||
if (NOT EIGEN3_FOUND)
|
||||
find_package(LAPACK)
|
||||
if(LAPACK_FOUND)
|
||||
include( ${LAPACK_USE_FILE} )
|
||||
endif(LAPACK_FOUND)
|
||||
else()
|
||||
include( ${EIGEN3_USE_FILE} )
|
||||
create_single_source_cgal_program( "point_set_algo.cpp" )
|
||||
endif()
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
ply
|
||||
format ascii 1.0
|
||||
comment Example for CGAL PLY reader
|
||||
element vertex 3
|
||||
property double x
|
||||
property double y
|
||||
property double z
|
||||
property double nx
|
||||
property double ny
|
||||
property double nz
|
||||
property uchar red
|
||||
property uchar green
|
||||
property uchar blue
|
||||
property double intensity
|
||||
property int label
|
||||
end_header
|
||||
0.0 0.0 0.0 0.0 0.0 1.0 255 0 0 0.8 1
|
||||
0.0 0.0 1.0 0.0 0.0 1.0 0 255 0 0.76 0
|
||||
0.0 1.0 0.0 0.0 0.0 1.0 0 0 255 0.99 1
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Point_set_3.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
|
||||
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> Point_set;
|
||||
|
||||
void print_point_set (const Point_set& point_set)
|
||||
{
|
||||
std::cerr << "Content of point set:" << std::endl;
|
||||
for (Point_set::const_iterator it = point_set.begin();
|
||||
it != point_set.end(); ++ it)
|
||||
std::cerr << "* Point " << *it
|
||||
<< ": " << point_set.point(*it) // or point_set[it]
|
||||
<< " with normal " << point_set.normal(*it)
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
int main (int, char**)
|
||||
{
|
||||
Point_set point_set;
|
||||
|
||||
// Add points
|
||||
point_set.insert (Point (0., 0., 0.));
|
||||
point_set.insert (Point (0., 0., 1.));
|
||||
point_set.insert (Point (0., 1., 0.));
|
||||
|
||||
point_set.add_normal_map();
|
||||
|
||||
print_point_set(point_set); // Normals have default values
|
||||
|
||||
// Change normal values
|
||||
Point_set::iterator it = point_set.begin();
|
||||
point_set.normal(*(it++)) = Vector (1., 0., 0.);
|
||||
point_set.normal(*(it++)) = Vector (0., 1., 0.);
|
||||
point_set.normal(*(it++)) = Vector (0., 0., 1.);
|
||||
|
||||
// Add point + normal
|
||||
point_set.insert (Point (1., 2., 3.), Vector (4., 5., 6.));
|
||||
|
||||
print_point_set(point_set);
|
||||
|
||||
// Add new item
|
||||
Point_set::iterator new_item = point_set.insert(Point (7., 8., 9.));
|
||||
point_set.normal(*new_item) = Vector (10., 11., 12.);
|
||||
|
||||
print_point_set(point_set); // New item has default values
|
||||
|
||||
point_set.remove (point_set.begin() + 2,
|
||||
point_set.begin() + 4);
|
||||
|
||||
print_point_set(point_set); // New item has default values
|
||||
|
||||
// Display information
|
||||
std::cerr << "Number of removed points: " <<point_set.number_of_removed_points() << std::endl;
|
||||
|
||||
point_set.collect_garbage();
|
||||
|
||||
// Display information (garbage should be gone)
|
||||
std::cerr << "After garbage collection: " <<point_set.number_of_removed_points() << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Point_set_3.h>
|
||||
#include <CGAL/IO/read_off_points.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
|
||||
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> Point_set;
|
||||
|
||||
int main (int argc, char** argv)
|
||||
{
|
||||
std::ifstream f (argc > 1 ? argv[1] : "data/camel.off");
|
||||
|
||||
Point_set point_set;
|
||||
point_set.add_normal_map();
|
||||
// Reading input in OFF format
|
||||
if (!f || !CGAL::read_off_points_and_normals
|
||||
(f,
|
||||
point_set.index_back_inserter(), // OutputIterator
|
||||
point_set.point_push_map(),
|
||||
point_set.normal_push_map()))
|
||||
{
|
||||
std::cerr << "Can't read input file " << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Point_set_3.h>
|
||||
#include <CGAL/Point_set_3/Point_set_processing_3.h>
|
||||
#include <CGAL/Point_set_3/IO.h>
|
||||
#include <CGAL/grid_simplify_point_set.h>
|
||||
#include <CGAL/point_generators_3.h>
|
||||
|
||||
#include <CGAL/Shape_detection_3.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
|
||||
typedef Kernel::FT FT;
|
||||
typedef Kernel::Point_3 Point;
|
||||
typedef Kernel::Vector_3 Vector;
|
||||
|
||||
typedef CGAL::Random_points_on_sphere_3<Point> Point_generator;
|
||||
|
||||
typedef CGAL::Point_set_3<Point> Point_set;
|
||||
|
||||
typedef CGAL::Shape_detection_3::Efficient_RANSAC_traits
|
||||
<Kernel, Point_set, Point_set::Point_map, Point_set::Vector_map> Traits;
|
||||
typedef CGAL::Shape_detection_3::Efficient_RANSAC<Traits> Efficient_ransac;
|
||||
typedef CGAL::Shape_detection_3::Sphere<Traits> Sphere;
|
||||
|
||||
|
||||
int main (int, char**)
|
||||
{
|
||||
Point_set point_set;
|
||||
|
||||
// Generate points on a unit sphere
|
||||
Point_generator generator(1.);
|
||||
std::size_t nb_pts = 10000;
|
||||
point_set.reserve (nb_pts);
|
||||
for (std::size_t i = 0; i < nb_pts; ++ i)
|
||||
point_set.insert (*(generator ++));
|
||||
|
||||
|
||||
// Add normal property and estimate normal values
|
||||
CGAL::jet_estimate_normals<CGAL::Sequential_tag> (point_set,
|
||||
12); // Number of neighbors
|
||||
|
||||
|
||||
// Simplify point set
|
||||
CGAL::grid_simplify_point_set (point_set,
|
||||
0.1); // Size of grid cell
|
||||
|
||||
std::vector<std::string> properties = point_set.properties();
|
||||
std::cerr << "Properties:" << std::endl;
|
||||
for (std::size_t i = 0; i < properties.size(); ++ i)
|
||||
std::cerr << " * " << properties[i] << std::endl;
|
||||
|
||||
// Detect sphere with RANSAC
|
||||
Efficient_ransac ransac;
|
||||
ransac.set_input(point_set,
|
||||
point_set.point_map(), // Call built-in property map
|
||||
point_set.normal_map()); // Call built-in property map
|
||||
ransac.add_shape_factory<Sphere>();
|
||||
Efficient_ransac::Parameters parameters;
|
||||
parameters.probability = 0.05;
|
||||
parameters.min_points = point_set.size() / 3.;
|
||||
parameters.epsilon = 0.01;
|
||||
parameters.cluster_epsilon = 0.5;
|
||||
parameters.normal_threshold = 0.9;
|
||||
ransac.detect(parameters);
|
||||
|
||||
BOOST_FOREACH(boost::shared_ptr<Efficient_ransac::Shape> shape, ransac.shapes())
|
||||
if (Sphere* sphere = dynamic_cast<Sphere*>(shape.get()))
|
||||
std::cerr << "Detected sphere of center " << sphere->center() // Center should be approx 0, 0, 0
|
||||
<< " and of radius " << sphere->radius() << std::endl; // Radius should be approx 1
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Point_set_3.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
|
||||
typedef Kernel::FT FT;
|
||||
typedef Kernel::Point_3 Point;
|
||||
typedef Kernel::Vector_3 Vector;
|
||||
typedef CGAL::cpp11::array<unsigned char, 3> Color;
|
||||
|
||||
typedef CGAL::Point_set_3<Point> Point_set;
|
||||
typedef Point_set::Property_map<Color> Color_map;
|
||||
typedef Point_set::Property_map<FT> FT_map;
|
||||
|
||||
void print_point_set (const Point_set& point_set)
|
||||
{
|
||||
Color_map color;
|
||||
boost::tie (color, boost::tuples::ignore) = point_set.property_map<Color>("color");
|
||||
FT_map intensity;
|
||||
boost::tie (intensity, boost::tuples::ignore) = point_set.property_map<FT>("intensity");
|
||||
|
||||
std::cerr << "Content of point set:" << std::endl;
|
||||
for (Point_set::const_iterator it = point_set.begin();
|
||||
it != point_set.end(); ++ it)
|
||||
std::cerr << "* Point " << point_set.point(*it) // or point_set[it]
|
||||
<< " with color [" << (int)(color[*it][0])
|
||||
<< " " << (int)(color[*it][1])
|
||||
<< " " << (int)(color[*it][2])
|
||||
<< "] and intensity " << intensity[*it]
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
|
||||
int main (int, char**)
|
||||
{
|
||||
srand (time (NULL));
|
||||
|
||||
Point_set point_set;
|
||||
|
||||
Color black = {{ 0, 0, 0 }};
|
||||
bool success = false;
|
||||
Color_map color;
|
||||
|
||||
boost::tie (color, success) = point_set.add_property_map<Color> ("color", black);
|
||||
assert (success);
|
||||
|
||||
FT_map intensity;
|
||||
boost::tie (intensity, success) = point_set.add_property_map<FT> ("intensity", 0.);
|
||||
assert (success);
|
||||
|
||||
point_set.reserve (10); // For memory optimization
|
||||
for (std::size_t i = 0; i < 10; ++ i)
|
||||
{
|
||||
Point_set::iterator it = point_set.insert (Point (i, i, i));
|
||||
Color c = {{ (unsigned char)(rand() % 256),
|
||||
(unsigned char)(rand() % 256),
|
||||
(unsigned char)(rand() % 256) }};
|
||||
color[*it] = c;
|
||||
intensity[*it] = rand() / (double)(RAND_MAX);
|
||||
}
|
||||
|
||||
print_point_set (point_set);
|
||||
|
||||
// Remove points with intensity less than 0.5
|
||||
Point_set::iterator it = point_set.begin();
|
||||
while (it != point_set.end())
|
||||
{
|
||||
if (intensity[*it] < 0.5)
|
||||
point_set.remove(it);
|
||||
else
|
||||
++ it;
|
||||
}
|
||||
|
||||
print_point_set (point_set); // point set is filtered
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Point_set_3.h>
|
||||
#include <CGAL/Point_set_3/IO.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
|
||||
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> Point_set;
|
||||
|
||||
int main (int argc, char** argv)
|
||||
{
|
||||
std::ifstream f (argc > 1 ? argv[1] : "data/example.ply");
|
||||
|
||||
Point_set point_set;
|
||||
|
||||
if (!f || !CGAL::read_ply_point_set (f, point_set))
|
||||
{
|
||||
std::cerr << "Can't read input file " << std::endl;
|
||||
}
|
||||
|
||||
// Shows which properties are defined
|
||||
std::vector<std::string> properties = point_set.properties();
|
||||
std::cerr << "Properties:" << std::endl;
|
||||
for (std::size_t i = 0; i < properties.size(); ++ i)
|
||||
std::cerr << " * " << properties[i] << std::endl;
|
||||
|
||||
// Recover "label" property of type int
|
||||
Point_set::Property_map<boost::int32_t> label_prop;
|
||||
bool found = false;
|
||||
boost::tie (label_prop, found) = point_set.property_map<boost::int32_t> ("label");
|
||||
|
||||
if (found)
|
||||
{
|
||||
std::cerr << "Point set has an integer \"label\" property with values:" << std::endl;
|
||||
for (Point_set::iterator it = point_set.begin(); it != point_set.end(); ++ it)
|
||||
std::cerr << " * " << label_prop[*it] << std::endl;
|
||||
}
|
||||
|
||||
std::ofstream out ("out.ply");
|
||||
CGAL::write_ply_point_set (out, point_set);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Point_set_3.h>
|
||||
#include <CGAL/Point_set_3/IO.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
|
||||
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> Point_set;
|
||||
|
||||
int main (int argc, char** argv)
|
||||
{
|
||||
std::ifstream f (argc > 1 ? argv[1] : "data/oni.xyz");
|
||||
|
||||
Point_set point_set;
|
||||
|
||||
// Reading input in XYZ format
|
||||
if (!f || !CGAL::read_xyz_point_set (f, point_set))
|
||||
{
|
||||
std::cerr << "Can't read input file " << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (point_set.has_normal_map())
|
||||
{
|
||||
// Normalization + inversion of normal vectors
|
||||
for (Point_set::iterator it = point_set.begin(); it != point_set.end(); ++ it)
|
||||
{
|
||||
Vector n = point_set.normal(*it);
|
||||
n = - n / std::sqrt (n * n);
|
||||
point_set.normal(*it) = n;
|
||||
}
|
||||
}
|
||||
|
||||
// Writing result in OFF format
|
||||
std::ofstream out("normalized_normals.off");
|
||||
if (!out || !CGAL::write_off_point_set (out, point_set))
|
||||
{
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -0,0 +1,232 @@
|
|||
// Copyright (c) 2016 Geometry Factory
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
//
|
||||
// Author(s) : Simon Giraudot
|
||||
|
||||
#ifndef CGAL_READ_PLY_POINT_SET_3_H
|
||||
#define CGAL_READ_PLY_POINT_SET_3_H
|
||||
|
||||
#include <CGAL/Point_set_3.h>
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
namespace CGAL
|
||||
{
|
||||
|
||||
/*!
|
||||
|
||||
\ingroup PkgPointSet3
|
||||
|
||||
\brief PLY interpreter designed to fill a `CGAL::Point_set_3` object.
|
||||
|
||||
This interpreter will instanciate any number of property needed to
|
||||
store all PLY properties read in the header:
|
||||
|
||||
- points and normals are stored as usual `CGAL::Point_set_3`
|
||||
properties (property "point" of type `CGAL::Point_3` and property
|
||||
"normal" of type `CGAL::Vector_3`)
|
||||
|
||||
- other PLY properties are stored on point set properties with the
|
||||
name and type given by the PLY header
|
||||
|
||||
\tparam Point Point type.
|
||||
\tparam Vector Normal vector type.
|
||||
|
||||
\cgalModels `PlyInterpreter`
|
||||
*/
|
||||
|
||||
template <typename Point,
|
||||
typename Vector = typename Kernel_traits<Point>::Kernel::Vector_3>
|
||||
class Ply_interpreter_point_set_3
|
||||
{
|
||||
public:
|
||||
typedef Point_set_3<Point> Point_set;
|
||||
|
||||
private:
|
||||
|
||||
struct Abstract_ply_property_to_point_set_property
|
||||
{
|
||||
virtual void assign (Ply_reader& reader, typename Point_set::Index index) = 0;
|
||||
};
|
||||
|
||||
template <typename Type>
|
||||
class Ply_property_to_point_set_property : public Abstract_ply_property_to_point_set_property
|
||||
{
|
||||
typedef typename Point_set::template Property_map<Type> Map;
|
||||
typedef typename Point_set::template Push_property_map<Map> Pmap;
|
||||
Map m_map;
|
||||
Pmap m_pmap;
|
||||
std::string m_name;
|
||||
public:
|
||||
Ply_property_to_point_set_property (Point_set& ps, const std::string& name)
|
||||
: m_name (name)
|
||||
{
|
||||
boost::tie (m_map, boost::tuples::ignore) = ps.add_property_map(name, Type());
|
||||
m_pmap = ps.push_property_map (m_map);
|
||||
}
|
||||
|
||||
virtual void assign (Ply_reader& reader, typename Point_set::Index index)
|
||||
{
|
||||
Type t;
|
||||
reader.assign (t, m_name.c_str());
|
||||
put(m_pmap, index, t);
|
||||
}
|
||||
};
|
||||
|
||||
Point_set& m_point_set;
|
||||
bool m_use_floats;
|
||||
std::vector<Abstract_ply_property_to_point_set_property*> m_properties;
|
||||
|
||||
public:
|
||||
|
||||
Ply_interpreter_point_set_3 (Point_set& point_set)
|
||||
: m_point_set (point_set), m_use_floats (false)
|
||||
{ }
|
||||
|
||||
bool is_applicable (Ply_reader& reader)
|
||||
{
|
||||
const std::vector<internal::Ply_read_number*>& readers
|
||||
= reader.readers();
|
||||
|
||||
bool has_normal[3] = { false, false, false };
|
||||
|
||||
|
||||
for (std::size_t i = 0; i < readers.size(); ++ i)
|
||||
{
|
||||
const std::string& name = readers[i]->name();
|
||||
if (name == "x" ||
|
||||
name == "y" ||
|
||||
name == "z")
|
||||
{
|
||||
if (dynamic_cast<internal::Ply_read_typed_number<float>*>(readers[i]))
|
||||
m_use_floats = true;
|
||||
continue;
|
||||
}
|
||||
if (name == "nx")
|
||||
{
|
||||
has_normal[0] = true;
|
||||
continue;
|
||||
}
|
||||
if (name == "ny")
|
||||
{
|
||||
has_normal[1] = true;
|
||||
continue;
|
||||
}
|
||||
if (name == "nz")
|
||||
{
|
||||
has_normal[2] = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dynamic_cast<internal::Ply_read_typed_number<boost::int8_t>*>(readers[i]))
|
||||
{
|
||||
m_properties.push_back
|
||||
(new Ply_property_to_point_set_property<boost::int8_t>(m_point_set,
|
||||
name));
|
||||
}
|
||||
else if (dynamic_cast<internal::Ply_read_typed_number<boost::uint8_t>*>(readers[i]))
|
||||
{
|
||||
m_properties.push_back
|
||||
(new Ply_property_to_point_set_property<boost::uint8_t>(m_point_set,
|
||||
name));
|
||||
}
|
||||
else if (dynamic_cast<internal::Ply_read_typed_number<boost::int16_t>*>(readers[i]))
|
||||
{
|
||||
m_properties.push_back
|
||||
(new Ply_property_to_point_set_property<boost::int16_t>(m_point_set,
|
||||
name));
|
||||
}
|
||||
else if (dynamic_cast<internal::Ply_read_typed_number<boost::uint16_t>*>(readers[i]))
|
||||
{
|
||||
m_properties.push_back
|
||||
(new Ply_property_to_point_set_property<boost::uint16_t>(m_point_set,
|
||||
name));
|
||||
}
|
||||
else if (dynamic_cast<internal::Ply_read_typed_number<boost::int32_t>*>(readers[i]))
|
||||
{
|
||||
m_properties.push_back
|
||||
(new Ply_property_to_point_set_property<boost::int32_t>(m_point_set,
|
||||
name));
|
||||
}
|
||||
else if (dynamic_cast<internal::Ply_read_typed_number<boost::uint32_t>*>(readers[i]))
|
||||
{
|
||||
m_properties.push_back
|
||||
(new Ply_property_to_point_set_property<boost::uint32_t>(m_point_set,
|
||||
name));
|
||||
}
|
||||
else if (dynamic_cast<internal::Ply_read_typed_number<float>*>(readers[i]))
|
||||
{
|
||||
m_properties.push_back
|
||||
(new Ply_property_to_point_set_property<float>(m_point_set,
|
||||
name));
|
||||
}
|
||||
else if (dynamic_cast<internal::Ply_read_typed_number<double>*>(readers[i]))
|
||||
{
|
||||
m_properties.push_back
|
||||
(new Ply_property_to_point_set_property<double>(m_point_set,
|
||||
name));
|
||||
}
|
||||
}
|
||||
|
||||
if (has_normal[0] && has_normal[1] && has_normal[2])
|
||||
m_point_set.add_normal_map();
|
||||
|
||||
|
||||
return (reader.does_tag_exist<float> ("x") || reader.does_tag_exist<double> ("x"))
|
||||
&& (reader.does_tag_exist<float> ("y") || reader.does_tag_exist<double> ("y"))
|
||||
&& (reader.does_tag_exist<float> ("z") || reader.does_tag_exist<double> ("z"));
|
||||
}
|
||||
|
||||
void process_line (Ply_reader& reader)
|
||||
{
|
||||
m_point_set.insert();
|
||||
|
||||
if (m_use_floats)
|
||||
process_line<float>(reader);
|
||||
else
|
||||
process_line<double>(reader);
|
||||
|
||||
for (std::size_t i = 0; i < m_properties.size(); ++ i)
|
||||
m_properties[i]->assign (reader, *(m_point_set.end() - 1));
|
||||
}
|
||||
|
||||
template <typename FT>
|
||||
void process_line (Ply_reader& reader)
|
||||
{
|
||||
FT x = (FT)0.,y = (FT)0., z = (FT)0.,
|
||||
nx = (FT)0., ny = (FT)0., nz = (FT)0.;
|
||||
reader.assign (x, "x");
|
||||
reader.assign (y, "y");
|
||||
reader.assign (z, "z");
|
||||
Point point (x, y, z);
|
||||
m_point_set.point(*(m_point_set.end() - 1)) = point;
|
||||
|
||||
if (m_point_set.has_normal_map())
|
||||
{
|
||||
reader.assign (nx, "nx");
|
||||
reader.assign (ny, "ny");
|
||||
reader.assign (nz, "nz");
|
||||
Vector normal (nx, ny, nz);
|
||||
m_point_set.normal(*(m_point_set.end() - 1)) = normal;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
/// \endcond
|
||||
|
||||
|
||||
#endif // CGAL_READ_PLY_POINT_SET_3_H
|
||||
|
|
@ -0,0 +1,400 @@
|
|||
// Copyright (c) 2016 GeometryFactory Sarl (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
//
|
||||
//
|
||||
// Author(s) : Simon Giraudot
|
||||
|
||||
#ifndef CGAL_POINT_SET_3_IO
|
||||
#define CGAL_POINT_SET_3_IO
|
||||
|
||||
#include <CGAL/IO/read_xyz_points.h>
|
||||
#include <CGAL/IO/read_off_points.h>
|
||||
#include <CGAL/IO/read_ply_points.h>
|
||||
#include <CGAL/IO/read_ply_point_set_3.h>
|
||||
#include <CGAL/IO/write_xyz_points.h>
|
||||
#include <CGAL/IO/write_off_points.h>
|
||||
#include <CGAL/IO/write_ply_points.h>
|
||||
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
/*!
|
||||
\ingroup PkgPointSet3IO
|
||||
*/
|
||||
template <typename Point, typename Vector>
|
||||
bool
|
||||
read_xyz_point_set(
|
||||
std::istream& stream, ///< input stream.
|
||||
CGAL::Point_set_3<Point, Vector>& point_set) ///< point set
|
||||
{
|
||||
point_set.add_normal_map();
|
||||
|
||||
bool out = CGAL::read_xyz_points_and_normals
|
||||
(stream,
|
||||
point_set.index_back_inserter(),
|
||||
point_set.point_push_map(),
|
||||
point_set.normal_push_map());
|
||||
|
||||
bool has_normals = false;
|
||||
for (typename CGAL::Point_set_3<Point, Vector>::const_iterator it = point_set.begin();
|
||||
it != point_set.end(); ++ it)
|
||||
if (point_set.normal(*it) != CGAL::NULL_VECTOR)
|
||||
{
|
||||
has_normals = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!has_normals)
|
||||
point_set.remove_normal_map();
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/*!
|
||||
\ingroup PkgPointSet3IO
|
||||
*/
|
||||
template <typename Point, typename Vector>
|
||||
bool
|
||||
read_off_point_set(
|
||||
std::istream& stream, ///< input stream.
|
||||
CGAL::Point_set_3<Point, Vector>& point_set) ///< point set
|
||||
{
|
||||
point_set.add_normal_map();
|
||||
|
||||
bool out = CGAL::read_off_points_and_normals
|
||||
(stream,
|
||||
point_set.index_back_inserter(),
|
||||
point_set.point_push_map(),
|
||||
point_set.normal_push_map());
|
||||
|
||||
bool has_normals = false;
|
||||
for (typename CGAL::Point_set_3<Point, Vector>::const_iterator it = point_set.begin();
|
||||
it != point_set.end(); ++ it)
|
||||
if (point_set.normal(*it) != CGAL::NULL_VECTOR)
|
||||
{
|
||||
has_normals = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!has_normals)
|
||||
point_set.remove_normal_map();
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*!
|
||||
\ingroup PkgPointSet3IO
|
||||
*/
|
||||
template <typename Point, typename Vector>
|
||||
bool
|
||||
read_ply_point_set(
|
||||
std::istream& stream, ///< input stream.
|
||||
CGAL::Point_set_3<Point, Vector>& point_set) ///< point set
|
||||
{
|
||||
CGAL::Ply_interpreter_point_set_3<Point, Vector> interpreter (point_set);
|
||||
|
||||
return CGAL::read_ply_custom_points
|
||||
(stream, interpreter,
|
||||
typename Kernel_traits<Point>::Kernel());
|
||||
}
|
||||
|
||||
/*!
|
||||
\ingroup PkgPointSet3IO
|
||||
*/
|
||||
template <typename Point, typename Vector>
|
||||
bool
|
||||
write_xyz_point_set(
|
||||
std::ostream& stream, ///< output stream.
|
||||
const CGAL::Point_set_3<Point, Vector>& point_set) ///< point set
|
||||
{
|
||||
if (point_set.has_normal_map())
|
||||
return CGAL::write_xyz_points_and_normals
|
||||
(stream, point_set.begin(), point_set.end(),
|
||||
point_set.point_map(), point_set.normal_map());
|
||||
|
||||
return CGAL::write_xyz_points
|
||||
(stream, point_set.begin(), point_set.end(),
|
||||
point_set.point_map());
|
||||
}
|
||||
|
||||
/*!
|
||||
\ingroup PkgPointSet3IO
|
||||
*/
|
||||
template <typename Point, typename Vector>
|
||||
bool
|
||||
write_off_point_set(
|
||||
std::ostream& stream, ///< output stream.
|
||||
const CGAL::Point_set_3<Point, Vector>& point_set) ///< point set
|
||||
{
|
||||
if (point_set.has_normal_map())
|
||||
return CGAL::write_off_points_and_normals
|
||||
(stream, point_set.begin(), point_set.end(),
|
||||
point_set.point_map(), point_set.normal_map());
|
||||
|
||||
return CGAL::write_off_points
|
||||
(stream, point_set.begin(), point_set.end(),
|
||||
point_set.point_map());
|
||||
}
|
||||
|
||||
/*!
|
||||
\ingroup PkgPointSet3IO
|
||||
*/
|
||||
template <typename Point, typename Vector>
|
||||
bool
|
||||
write_ply_point_set(
|
||||
std::ostream& stream, ///< output stream.
|
||||
const CGAL::Point_set_3<Point, Vector>& point_set) ///< point set
|
||||
{
|
||||
|
||||
stream << point_set;
|
||||
return true;
|
||||
// if (point_set.has_normal_map())
|
||||
// return CGAL::write_ply_points_and_normals
|
||||
// (stream, point_set.begin(), point_set.end(),
|
||||
// point_set.point_map(), point_set.normal_map());
|
||||
|
||||
// return CGAL::write_ply_points
|
||||
// (stream, point_set.begin(), point_set.end(),
|
||||
// point_set.point_map());
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
|
||||
\ingroup PkgPointSet3IO
|
||||
|
||||
\brief Reads the point set from an input stream that can be either:
|
||||
|
||||
- XYZ
|
||||
- OFF
|
||||
- PLY
|
||||
|
||||
The format is detected from the stream. If the stream contains
|
||||
normal vectors, the normal map is added to the point set. For PLY
|
||||
input, all point properties found in the header are added.
|
||||
\relates Point_set_3
|
||||
*/
|
||||
template <typename Point, typename Vector>
|
||||
std::istream& operator>>(std::istream& is,
|
||||
CGAL::Point_set_3<Point, Vector>& ps)
|
||||
{
|
||||
// Check format identifier on first line
|
||||
std::string line;
|
||||
if (!getline(is, line))
|
||||
return is;
|
||||
is.seekg(0);
|
||||
if (line == "OFF" || line == "NOFF")
|
||||
CGAL::read_off_point_set (is, ps);
|
||||
else if (line == "ply")
|
||||
CGAL::read_ply_point_set (is, ps);
|
||||
else
|
||||
CGAL::read_xyz_point_set (is, ps);
|
||||
|
||||
return is;
|
||||
}
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
namespace internal
|
||||
{
|
||||
template <typename Point, typename Vector>
|
||||
class Abstract_property_printer
|
||||
{
|
||||
public:
|
||||
virtual std::string get_string(const typename CGAL::Point_set_3<Point,Vector>::Index& index) = 0;
|
||||
};
|
||||
|
||||
template <typename Point, typename Vector, typename Type>
|
||||
class Property_printer : public Abstract_property_printer<Point, Vector>
|
||||
{
|
||||
typedef typename CGAL::Point_set_3<Point, Vector> Point_set;
|
||||
typedef typename Point_set::template Property_map<Type> Pmap;
|
||||
Pmap m_pmap;
|
||||
public:
|
||||
Property_printer (const Pmap& pmap) : m_pmap (pmap)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual std::string get_string(const typename CGAL::Point_set_3<Point,Vector>::Index& index)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss.precision (std::numeric_limits<double>::digits10 + 2);
|
||||
oss << get(m_pmap, index);
|
||||
return oss.str();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Point, typename Vector, typename Type>
|
||||
class Char_property_printer : public Abstract_property_printer<Point, Vector>
|
||||
{
|
||||
typedef typename CGAL::Point_set_3<Point, Vector> Point_set;
|
||||
typedef typename Point_set::template Property_map<Type> Pmap;
|
||||
Pmap m_pmap;
|
||||
public:
|
||||
Char_property_printer (const Pmap& pmap) : m_pmap (pmap)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual std::string get_string(const typename CGAL::Point_set_3<Point,Vector>::Index& index)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << (int)(get(m_pmap, index));
|
||||
return oss.str();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
/// \endcond
|
||||
|
||||
/*!
|
||||
|
||||
\ingroup PkgPointSet3IO
|
||||
|
||||
\brief Inserts the point set in an output stream in ASCII PLY
|
||||
format. All properties are inserted in their instantiation order.
|
||||
|
||||
\relates Point_set_3
|
||||
*/
|
||||
template <typename Point, typename Vector>
|
||||
std::ostream& operator<<(std::ostream& os,
|
||||
const CGAL::Point_set_3<Point, Vector>& ps)
|
||||
{
|
||||
typedef CGAL::Point_set_3<Point, Vector> Point_set;
|
||||
|
||||
os << "ply" << std::endl
|
||||
<< "format ascii 1.0" << std::endl
|
||||
<< "comment Generated by the CGAL library" << std::endl
|
||||
<< "element vertex " << ps.number_of_points() << std::endl;
|
||||
|
||||
std::vector<std::string> prop = ps.base().properties();
|
||||
std::vector<internal::Abstract_property_printer<Point, Vector>*> printers;
|
||||
|
||||
for (std::size_t i = 0; i < prop.size(); ++ i)
|
||||
{
|
||||
if (prop[i] == "index")
|
||||
continue;
|
||||
|
||||
if (prop[i] == "point")
|
||||
{
|
||||
os << "property double x" << std::endl
|
||||
<< "property double y" << std::endl
|
||||
<< "property double z" << std::endl;
|
||||
printers.push_back (new internal::Property_printer<Point,Vector,Point>(ps.point_map()));
|
||||
continue;
|
||||
}
|
||||
if (prop[i] == "normal")
|
||||
{
|
||||
os << "property double nx" << std::endl
|
||||
<< "property double ny" << std::endl
|
||||
<< "property double nz" << std::endl;
|
||||
printers.push_back (new internal::Property_printer<Point,Vector,Vector>(ps.normal_map()));
|
||||
continue;
|
||||
}
|
||||
|
||||
bool okay = false;
|
||||
{
|
||||
typename Point_set::template Property_map<boost::int8_t> pmap;
|
||||
boost::tie (pmap, okay) = ps.template property_map<boost::int8_t>(prop[i]);
|
||||
if (okay)
|
||||
{
|
||||
os << "property char " << prop[i] << std::endl;
|
||||
printers.push_back (new internal::Char_property_printer<Point,Vector,boost::int8_t>(pmap));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
{
|
||||
typename Point_set::template Property_map<boost::uint8_t> pmap;
|
||||
boost::tie (pmap, okay) = ps.template property_map<boost::uint8_t>(prop[i]);
|
||||
if (okay)
|
||||
{
|
||||
os << "property uchar " << prop[i] << std::endl;
|
||||
printers.push_back (new internal::Char_property_printer<Point,Vector,boost::uint8_t>(pmap));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
{
|
||||
typename Point_set::template Property_map<boost::int16_t> pmap;
|
||||
boost::tie (pmap, okay) = ps.template property_map<boost::int16_t>(prop[i]);
|
||||
if (okay)
|
||||
{
|
||||
os << "property short " << prop[i] << std::endl;
|
||||
printers.push_back (new internal::Property_printer<Point,Vector,boost::int16_t>(pmap));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
{
|
||||
typename Point_set::template Property_map<boost::uint16_t> pmap;
|
||||
boost::tie (pmap, okay) = ps.template property_map<boost::uint16_t>(prop[i]);
|
||||
if (okay)
|
||||
{
|
||||
os << "property ushort " << prop[i] << std::endl;
|
||||
printers.push_back (new internal::Property_printer<Point,Vector,boost::uint16_t>(pmap));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
{
|
||||
typename Point_set::template Property_map<boost::int32_t> pmap;
|
||||
boost::tie (pmap, okay) = ps.template property_map<boost::int32_t>(prop[i]);
|
||||
if (okay)
|
||||
{
|
||||
os << "property int " << prop[i] << std::endl;
|
||||
printers.push_back (new internal::Property_printer<Point,Vector,boost::int32_t>(pmap));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
{
|
||||
typename Point_set::template Property_map<float> pmap;
|
||||
boost::tie (pmap, okay) = ps.template property_map<float>(prop[i]);
|
||||
if (okay)
|
||||
{
|
||||
os << "property float " << prop[i] << std::endl;
|
||||
printers.push_back (new internal::Property_printer<Point,Vector,float>(pmap));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
{
|
||||
typename Point_set::template Property_map<double> pmap;
|
||||
boost::tie (pmap, okay) = ps.template property_map<double>(prop[i]);
|
||||
if (okay)
|
||||
{
|
||||
os << "property double " << prop[i] << std::endl;
|
||||
printers.push_back (new internal::Property_printer<Point,Vector,double>(pmap));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
os << "end_header" << std::endl;
|
||||
|
||||
for (typename Point_set::const_iterator it = ps.begin(); it != ps.end(); ++ it)
|
||||
{
|
||||
for (std::size_t i = 0; i < printers.size(); ++ i)
|
||||
os << printers[i]->get_string(*it) << " ";
|
||||
os << std::endl;
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace CGAL
|
||||
|
||||
|
||||
#endif // CGAL_POINT_SET_3_IO
|
||||
|
|
@ -0,0 +1,304 @@
|
|||
// Copyright (c) 2016 GeometryFactory Sarl (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
//
|
||||
//
|
||||
// Author(s) : Simon Giraudot
|
||||
|
||||
#ifndef CGAL_POINT_SET_3_POINT_SET_PROCESSING_3_H
|
||||
#define CGAL_POINT_SET_3_POINT_SET_PROCESSING_3_H
|
||||
|
||||
#include <CGAL/bilateral_smooth_point_set.h>
|
||||
#include <CGAL/compute_average_spacing.h>
|
||||
#include <CGAL/edge_aware_upsample_point_set.h>
|
||||
#include <CGAL/grid_simplify_point_set.h>
|
||||
#include <CGAL/hierarchy_simplify_point_set.h>
|
||||
#include <CGAL/jet_estimate_normals.h>
|
||||
#include <CGAL/jet_smooth_point_set.h>
|
||||
#include <CGAL/mst_orient_normals.h>
|
||||
#include <CGAL/pca_estimate_normals.h>
|
||||
#include <CGAL/random_simplify_point_set.h>
|
||||
#include <CGAL/remove_outliers.h>
|
||||
#include <CGAL/vcm_estimate_normals.h>
|
||||
#include <CGAL/wlop_simplify_and_regularize_point_set.h>
|
||||
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
/*!
|
||||
\ingroup PkgPointSet3PointSetProcessing3
|
||||
*/
|
||||
template <typename Concurrency_tag,
|
||||
typename Point,
|
||||
typename Vector>
|
||||
double
|
||||
bilateral_smooth_point_set(
|
||||
CGAL::Point_set_3<Point, Vector>& point_set, ///< point set
|
||||
const unsigned int k, ///< number of neighbors.
|
||||
double sharpness_angle) ///< control sharpness(0-90)
|
||||
{
|
||||
return CGAL::bilateral_smooth_point_set<Concurrency_tag>
|
||||
(point_set.begin(), point_set.end(),
|
||||
point_set.point_map(), point_set.normal_map(),
|
||||
k, sharpness_angle);
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
\ingroup PkgPointSet3PointSetProcessing3
|
||||
*/
|
||||
template <typename Concurrency_tag,
|
||||
typename Point, typename Vector>
|
||||
double
|
||||
compute_average_spacing(
|
||||
const CGAL::Point_set_3<Point, Vector>& point_set, ///< point set
|
||||
unsigned int k) ///< number of neighbors.
|
||||
{
|
||||
return CGAL::compute_average_spacing<Concurrency_tag>
|
||||
(point_set.begin(), point_set.end(), point_set.point_map(), k);
|
||||
}
|
||||
|
||||
/*!
|
||||
\ingroup PkgPointSet3PointSetProcessing3
|
||||
*/
|
||||
template <typename Concurrency_tag,
|
||||
typename Point, typename Vector>
|
||||
void
|
||||
edge_aware_upsample_point_set(
|
||||
CGAL::Point_set_3<Point, Vector>& point_set, ///< point set
|
||||
double sharpness_angle = 30, ///< control sharpness(0-90)
|
||||
double edge_sensitivity = 1, ///< edge sensitivity(0-5)
|
||||
double neighbor_radius = -1, ///< initial size of neighbors.
|
||||
const std::size_t number_of_output_points = 1000)///< number of output points.
|
||||
{
|
||||
CGAL::edge_aware_upsample_point_set<Concurrency_tag>
|
||||
(point_set.begin(), point_set.end(),
|
||||
point_set.point_back_inserter(),
|
||||
point_set.point_map(), point_set.normal_map(),
|
||||
sharpness_angle, edge_sensitivity, neighbor_radius, number_of_output_points);
|
||||
}
|
||||
|
||||
/*!
|
||||
\ingroup PkgPointSet3PointSetProcessing3
|
||||
|
||||
\note No iterator is returned, points simplified are directly
|
||||
removed from the point set.
|
||||
*/
|
||||
template <typename Point, typename Vector>
|
||||
void grid_simplify_point_set(
|
||||
CGAL::Point_set_3<Point, Vector>& point_set, ///< point set
|
||||
double epsilon) ///< tolerance value when merging 3D points.
|
||||
{
|
||||
point_set.remove_from
|
||||
(CGAL::grid_simplify_point_set
|
||||
(point_set.begin(), point_set.end(), point_set.point_map(), epsilon));
|
||||
}
|
||||
|
||||
/*!
|
||||
\ingroup PkgPointSet3PointSetProcessing3
|
||||
|
||||
\note No iterator is returned, points simplified are directly
|
||||
removed from the point set.
|
||||
*/
|
||||
template <typename Point, typename Vector>
|
||||
void hierarchy_simplify_point_set(
|
||||
CGAL::Point_set_3<Point, Vector>& point_set, ///< point set
|
||||
const unsigned int size = 10, ///< maximum cluster size
|
||||
const double var_max = 0.333) ///< maximal surface variation
|
||||
{
|
||||
point_set.remove_from
|
||||
(CGAL::hierarchy_simplify_point_set
|
||||
(point_set.begin(), point_set.end(), point_set.point_map(), size, var_max,
|
||||
CGAL::Default_diagonalize_traits<double, 3>()));
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
\ingroup PkgPointSet3PointSetProcessing3
|
||||
|
||||
\note This function adds a normal map to the point set.
|
||||
*/
|
||||
template <typename Concurrency_tag,
|
||||
typename Point, typename Vector>
|
||||
void
|
||||
jet_estimate_normals(
|
||||
CGAL::Point_set_3<Point, Vector>& point_set, ///< point set
|
||||
unsigned int k, ///< number of neighbors.
|
||||
unsigned int degree_fitting = 2) ///< fitting degree
|
||||
{
|
||||
point_set.add_normal_map();
|
||||
|
||||
CGAL::jet_estimate_normals<Concurrency_tag>
|
||||
(point_set.begin(), point_set.end(),
|
||||
point_set.point_map(), point_set.normal_map(),
|
||||
k, degree_fitting);
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
\ingroup PkgPointSet3PointSetProcessing3
|
||||
*/
|
||||
template <typename Concurrency_tag,
|
||||
typename Point, typename Vector>
|
||||
void
|
||||
jet_smooth_point_set(
|
||||
CGAL::Point_set_3<Point, Vector>& point_set, ///< point set
|
||||
unsigned int k, ///< number of neighbors.
|
||||
unsigned int degree_fitting = 2, ///< fitting degree
|
||||
unsigned int degree_monge = 2) ///< Monge degree
|
||||
{
|
||||
CGAL::jet_smooth_point_set<Concurrency_tag>
|
||||
(point_set.begin(), point_set.end(), point_set.point_map(),
|
||||
k, degree_fitting, degree_monge);
|
||||
|
||||
}
|
||||
|
||||
/*!
|
||||
\ingroup PkgPointSet3PointSetProcessing3
|
||||
*/
|
||||
template <typename Point, typename Vector>
|
||||
typename CGAL::Point_set_3<Point, Vector>::iterator
|
||||
mst_orient_normals(
|
||||
CGAL::Point_set_3<Point, Vector>& point_set, ///< point set
|
||||
unsigned int k) ///< number of neighbors
|
||||
{
|
||||
return CGAL::mst_orient_normals
|
||||
(point_set.begin(), point_set.end(),
|
||||
point_set.point_map(), point_set.normal_map(), k);
|
||||
}
|
||||
|
||||
/*!
|
||||
\ingroup PkgPointSet3PointSetProcessing3
|
||||
|
||||
\note This function adds a normal map to the point set.
|
||||
*/
|
||||
template <typename Concurrency_tag,
|
||||
typename Point, typename Vector>
|
||||
void
|
||||
pca_estimate_normals(
|
||||
CGAL::Point_set_3<Point, Vector>& point_set, ///< point set
|
||||
unsigned int k) ///< number of neighbors.
|
||||
{
|
||||
point_set.add_normal_map();
|
||||
|
||||
CGAL::pca_estimate_normals<Concurrency_tag>
|
||||
(point_set.begin(), point_set.end(),
|
||||
point_set.point_map(), point_set.normal_map(),
|
||||
k);
|
||||
}
|
||||
|
||||
/*!
|
||||
\ingroup PkgPointSet3PointSetProcessing3
|
||||
|
||||
\note No iterator is returned, points simplified are directly
|
||||
removed from the point set.
|
||||
*/
|
||||
template <typename Point, typename Vector>
|
||||
void random_simplify_point_set(
|
||||
CGAL::Point_set_3<Point, Vector>& point_set, ///< point set
|
||||
double removed_percentage) ///< percentage of points to remove
|
||||
{
|
||||
point_set.remove_from
|
||||
(CGAL::random_simplify_point_set
|
||||
(point_set.begin(), point_set.end(), point_set.point_map(), removed_percentage));
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
\ingroup PkgPointSet3PointSetProcessing3
|
||||
|
||||
\note No iterator is returned, points simplified are directly
|
||||
removed from the point set.
|
||||
*/
|
||||
template <typename Point, typename Vector>
|
||||
void remove_outliers(
|
||||
CGAL::Point_set_3<Point, Vector>& point_set, ///< point set
|
||||
unsigned int k, ///< number of neighbors.
|
||||
double threshold_percent) ///< percentage of points to remove
|
||||
{
|
||||
point_set.remove_from
|
||||
(CGAL::remove_outliers
|
||||
(point_set.begin(), point_set.end(), point_set.point_map(), k, threshold_percent));
|
||||
}
|
||||
|
||||
/*!
|
||||
\ingroup PkgPointSet3PointSetProcessing3
|
||||
|
||||
\note This function adds a normal map to the point set.
|
||||
*/
|
||||
template <typename Point, typename Vector>
|
||||
void
|
||||
vcm_estimate_normals(
|
||||
CGAL::Point_set_3<Point, Vector>& point_set, ///< point set
|
||||
double offset_radius, ///< offset radius.
|
||||
double convolution_radius) ///< convolution radius.
|
||||
{
|
||||
point_set.add_normal_map();
|
||||
|
||||
CGAL::vcm_estimate_normals
|
||||
(point_set.begin(), point_set.end(),
|
||||
point_set.point_map(), point_set.normal_map(),
|
||||
offset_radius, convolution_radius);
|
||||
}
|
||||
|
||||
/*!
|
||||
\ingroup PkgPointSet3PointSetProcessing3
|
||||
|
||||
\note This function adds a normal map to the point set.
|
||||
*/
|
||||
template <typename Point, typename Vector>
|
||||
void
|
||||
vcm_estimate_normals(
|
||||
CGAL::Point_set_3<Point, Vector>& point_set, ///< point set
|
||||
double offset_radius, ///< offset radius.
|
||||
unsigned int nb_neighbors_convolve) ///< number of neighbors used during the convolution.
|
||||
{
|
||||
point_set.add_normal_map();
|
||||
|
||||
CGAL::vcm_estimate_normals
|
||||
(point_set.begin(), point_set.end(),
|
||||
point_set.point_map(), point_set.normal_map(),
|
||||
offset_radius, nb_neighbors_convolve);
|
||||
}
|
||||
|
||||
/*!
|
||||
\ingroup PkgPointSet3PointSetProcessing3
|
||||
*/
|
||||
template <typename Concurrency_tag,
|
||||
typename Point, typename Vector>
|
||||
void
|
||||
wlop_simplify_and_regularize_point_set(
|
||||
const CGAL::Point_set_3<Point, Vector>& input_point_set, ///< input point set
|
||||
CGAL::Point_set_3<Point, Vector>& output_point_set, ///< output point set
|
||||
const double select_percentage = 5, ///< percentage of points to retain
|
||||
double neighbor_radius = -1, ///< size of neighbors.
|
||||
const unsigned int max_iter_number = 35, ///< number of iterations.
|
||||
const bool require_uniform_sampling = false ///< if needed to compute density
|
||||
/// to generate more rugularized result.
|
||||
)
|
||||
{
|
||||
CGAL::wlop_simplify_and_regularize_point_set
|
||||
(input_point_set.begin(), input_point_set.end(),
|
||||
output_point_set.point_back_inserter(),
|
||||
input_point_set.point_map(),
|
||||
neighbor_radius, max_iter_number, require_uniform_sampling);
|
||||
}
|
||||
|
||||
|
||||
} // namespace CGAL
|
||||
|
||||
|
||||
#endif // CGAL_POINT_SET_3_POINT_SET_PROCESSING_3_H
|
||||
|
|
@ -0,0 +1 @@
|
|||
GeometryFactory (France)
|
||||
|
|
@ -0,0 +1 @@
|
|||
GPL (v3 or later)
|
||||
|
|
@ -0,0 +1 @@
|
|||
Simon Giraudot (simon.giraudot@geometryfactory.com)
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
# Created by the script cgal_create_CMakeLists
|
||||
# This is the CMake script for compiling a set of CGAL applications.
|
||||
|
||||
project( Point_set_3 )
|
||||
|
||||
|
||||
cmake_minimum_required(VERSION 2.8.11)
|
||||
|
||||
# CGAL and its components
|
||||
find_package( CGAL QUIET COMPONENTS )
|
||||
|
||||
if ( NOT CGAL_FOUND )
|
||||
|
||||
message(STATUS "This project requires the CGAL library, and will not be compiled.")
|
||||
return()
|
||||
|
||||
endif()
|
||||
|
||||
# include helper file
|
||||
include( ${CGAL_USE_FILE} )
|
||||
|
||||
|
||||
# Boost and its components
|
||||
find_package( Boost REQUIRED )
|
||||
|
||||
if ( NOT Boost_FOUND )
|
||||
|
||||
message(STATUS "This project requires the Boost library, and will not be compiled.")
|
||||
|
||||
return()
|
||||
|
||||
endif()
|
||||
|
||||
# include for local directory
|
||||
|
||||
# include for local package
|
||||
include_directories( BEFORE ../../include )
|
||||
|
||||
|
||||
# Creating entries for all C++ files with "main" routine
|
||||
# ##########################################################
|
||||
|
||||
include( CGAL_CreateSingleSourceCGALProgram )
|
||||
|
||||
create_single_source_cgal_program( "point_set_test.cpp" )
|
||||
create_single_source_cgal_program( "point_set_test_join.cpp" )
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
|
||||
#include <CGAL/Point_set_3.h>
|
||||
#include <CGAL/Point_set_3/Point_set_processing_3.h>
|
||||
#include <CGAL/Point_set_3/IO.h>
|
||||
#include <CGAL/grid_simplify_point_set.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
|
||||
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> Point_set;
|
||||
typedef CGAL::cpp11::array<unsigned char, 3> Color;
|
||||
|
||||
std::size_t nb_test = 0;
|
||||
std::size_t nb_success = 0;
|
||||
|
||||
void test (bool expr, const char* msg)
|
||||
{
|
||||
++ nb_test;
|
||||
if (!expr)
|
||||
std::cerr << "Error on test " << nb_test << ": " << msg << std::endl;
|
||||
else
|
||||
++ nb_success;
|
||||
}
|
||||
|
||||
|
||||
int main (int, char**)
|
||||
{
|
||||
Point_set point_set;
|
||||
|
||||
test (!(point_set.has_normal_map()), "point set shouldn't have normals.");
|
||||
point_set.add_normal_map();
|
||||
test (point_set.has_normal_map(), "point set should have normals.");
|
||||
|
||||
std::ifstream f ("data/oni.pwn");
|
||||
CGAL::read_xyz_point_set(f, point_set);
|
||||
|
||||
f.close ();
|
||||
|
||||
Point_set::iterator
|
||||
first_to_remove = CGAL::grid_simplify_point_set (point_set.begin(),
|
||||
point_set.end(),
|
||||
point_set.point_map(),
|
||||
0.1);
|
||||
|
||||
std::size_t size = point_set.size ();
|
||||
point_set.remove_from (first_to_remove);
|
||||
test ((point_set.size() + point_set.garbage_size() == size), "sizes before and after removal do not match.");
|
||||
|
||||
Point_set::Point_range
|
||||
range = point_set.points();
|
||||
|
||||
{
|
||||
Point_set::const_iterator psit = point_set.begin();
|
||||
bool range_okay = true;
|
||||
for (Point_set::Point_range::const_iterator it = range.begin(); it != range.end(); ++ it)
|
||||
{
|
||||
if (*it != point_set.point (*psit))
|
||||
{
|
||||
range_okay = false;
|
||||
break;
|
||||
}
|
||||
++ psit;
|
||||
}
|
||||
test (range_okay, "range access does not follow property map based access.");
|
||||
}
|
||||
|
||||
test (point_set.has_garbage(), "point set should have garbage.");
|
||||
point_set.collect_garbage();
|
||||
test (!(point_set.has_garbage()), "point set shouldn't have garbage.");
|
||||
|
||||
test (!(point_set.has_property_map<Color> ("color")), "point set shouldn't have colors.");
|
||||
typename Point_set::Property_map<Color> color_prop;
|
||||
bool garbage;
|
||||
boost::tie (color_prop, garbage) = point_set.add_property_map ("color", Color());
|
||||
test (point_set.has_property_map<Color> ("color"), "point set should have colors.");
|
||||
|
||||
for (Point_set::iterator it = point_set.begin(); it != point_set.end(); ++ it)
|
||||
{
|
||||
Color c = {{ static_cast<unsigned char>(rand() % 255),
|
||||
static_cast<unsigned char>(rand() % 255),
|
||||
static_cast<unsigned char>(rand() % 255) }};
|
||||
put (color_prop, *it, c);
|
||||
test ((get (color_prop, *it) == c), "recovered color is incorrect.");
|
||||
}
|
||||
|
||||
typename Point_set::Property_map<Color> color_prop_2;
|
||||
boost::tie (color_prop_2, garbage) = point_set.property_map<Color>("color");
|
||||
test ((color_prop_2 == color_prop), "color property not recovered correctly.");
|
||||
|
||||
point_set.remove_normal_map ();
|
||||
test (!(point_set.has_normal_map()), "point set shouldn't have normals.");
|
||||
|
||||
test (point_set.has_property_map<Color> ("color"), "point set should have colors.");
|
||||
point_set.remove_property_map<Color> (color_prop);
|
||||
test (!(point_set.has_property_map<Color> ("color")), "point set shouldn't have colors.");
|
||||
|
||||
point_set.add_property_map<int> ("label", 0);
|
||||
point_set.add_property_map<double> ("intensity", 0.0);
|
||||
|
||||
test (point_set.base().n_properties() == 4, "point set should have 4 properties.");
|
||||
|
||||
Point p_before = *(point_set.points().begin());
|
||||
point_set.clear_properties();
|
||||
|
||||
test (point_set.base().n_properties() == 2, "point set should have 2 properties.");
|
||||
test (!(point_set.has_property_map<int>("label")), "point set shouldn' have labels.");
|
||||
test (!(point_set.has_property_map<double>("intensity")), "point set shouldn' have intensity.");
|
||||
test (!(point_set.empty()), "point set shouldn' be empty.");
|
||||
|
||||
Point p_after = *(point_set.points().begin());
|
||||
|
||||
test (p_before == p_after, "points should not change when clearing properties.");
|
||||
|
||||
std::cerr << nb_success << "/" << nb_test << " test(s) succeeded." << std::endl;
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
|
||||
#include <CGAL/Point_set_3.h>
|
||||
#include <CGAL/IO/read_xyz_points.h>
|
||||
#include <CGAL/IO/write_xyz_points.h>
|
||||
#include <CGAL/grid_simplify_point_set.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
|
||||
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> Point_set;
|
||||
typedef CGAL::cpp11::array<unsigned char, 3> Color;
|
||||
|
||||
std::size_t nb_test = 0;
|
||||
std::size_t nb_success = 0;
|
||||
|
||||
void test (bool expr, const char* msg)
|
||||
{
|
||||
++ nb_test;
|
||||
if (!expr)
|
||||
std::cerr << "Error on test " << nb_test << ": " << msg << std::endl;
|
||||
else
|
||||
++ nb_success;
|
||||
}
|
||||
|
||||
void print_point_set (const Point_set& ps, const char* msg)
|
||||
{
|
||||
std::cerr << msg << std::endl;
|
||||
if (ps.has_normal_map())
|
||||
for (Point_set::const_iterator it = ps.begin(); it != ps.end(); ++ it)
|
||||
std::cerr << *it << ": " << ps.point(*it)
|
||||
<< ", normal " << ps.normal(*it) << std::endl;
|
||||
else
|
||||
for (Point_set::const_iterator it = ps.begin(); it != ps.end(); ++ it)
|
||||
std::cerr << *it << ": " << ps.point(*it) << std::endl;
|
||||
}
|
||||
|
||||
|
||||
int main (int, char**)
|
||||
{
|
||||
Point_set ps1, ps2;
|
||||
ps1.add_normal_map();
|
||||
|
||||
for (std::size_t i = 0; i < 5; ++ i)
|
||||
ps1.insert (Point (i, i, i), Vector (i, i, i));
|
||||
|
||||
ps1.remove (ps1.end() - 3);
|
||||
|
||||
for (std::size_t i = 5; i < 10; ++ i)
|
||||
ps2.insert (Point (i, i, i));
|
||||
|
||||
ps2.remove (ps2.end() - 3);
|
||||
|
||||
print_point_set (ps1, "PS1 = ");
|
||||
print_point_set (ps2, "PS2 = ");
|
||||
|
||||
ps1 += ps2;
|
||||
print_point_set (ps1, "JOINT PS1 = ");
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
};
|
||||
|
|
@ -24,6 +24,7 @@
|
|||
#include <CGAL/value_type_traits.h>
|
||||
#include <CGAL/point_set_processing_assertions.h>
|
||||
#include <CGAL/Kernel_traits.h>
|
||||
#include <CGAL/IO/io.h>
|
||||
|
||||
#include <boost/version.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
|
|
@ -83,6 +84,16 @@ namespace internal {
|
|||
c = static_cast<unsigned char>(s);
|
||||
}
|
||||
|
||||
void read_ascii (std::istream& stream, float& t) const
|
||||
{
|
||||
stream >> iformat(t);
|
||||
}
|
||||
|
||||
void read_ascii (std::istream& stream, double& t) const
|
||||
{
|
||||
stream >> iformat(t);
|
||||
}
|
||||
|
||||
// Default template when Type is not a char type
|
||||
template <typename Type>
|
||||
void read_ascii (std::istream& stream, Type& t) const
|
||||
|
|
@ -90,6 +101,7 @@ namespace internal {
|
|||
stream >> t;
|
||||
}
|
||||
|
||||
|
||||
template <typename Type>
|
||||
Type read (std::istream& stream) const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -234,7 +234,7 @@ jet_smooth_point_set(
|
|||
{
|
||||
for(it = first; it != beyond; it++)
|
||||
{
|
||||
typename boost::property_traits<PointPMap>::reference p = get(point_pmap, *it);
|
||||
const typename boost::property_traits<PointPMap>::reference p = get(point_pmap, *it);
|
||||
put(point_pmap, *it ,
|
||||
internal::jet_smooth_point<Kernel, SvdTraits>(
|
||||
p,tree,k,degree_fitting,degree_monge) );
|
||||
|
|
|
|||
|
|
@ -242,6 +242,9 @@ if(CGAL_Qt5_FOUND AND Qt5_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND)
|
|||
add_item(scene_polyhedron_selection_item Scene_polyhedron_selection_item.cpp)
|
||||
target_link_libraries(scene_polyhedron_selection_item scene_polyhedron_item_decorator scene_polyhedron_item_k_ring_selection)
|
||||
|
||||
add_item(scene_point_set_classification_item Scene_point_set_classification_item.cpp)
|
||||
target_link_libraries(scene_point_set_classification_item scene_points_with_normal_item scene_color_ramp)
|
||||
|
||||
add_item(scene_polyhedron_shortest_path_item Plugins/Surface_mesh/Scene_polyhedron_shortest_path_item.cpp)
|
||||
|
||||
add_item(scene_surface_mesh_item Scene_surface_mesh_item.cpp)
|
||||
|
|
@ -270,9 +273,6 @@ if(CGAL_Qt5_FOUND AND Qt5_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND)
|
|||
|
||||
target_link_libraries( demo_framework gl_splat)
|
||||
|
||||
|
||||
|
||||
|
||||
foreach( lib
|
||||
demo_framework
|
||||
scene_basic_objects
|
||||
|
|
|
|||
|
|
@ -57,3 +57,13 @@ target_link_libraries(xyz_plugin scene_points_with_normal_item)
|
|||
|
||||
polyhedron_demo_plugin(ply_to_xyz_plugin PLY_to_xyz_io_plugin)
|
||||
target_link_libraries(ply_to_xyz_plugin scene_points_with_normal_item)
|
||||
|
||||
find_package(libLAS)
|
||||
if (libLAS_FOUND)
|
||||
include_directories(${libLAS_INCLUDE_DIRS})
|
||||
|
||||
polyhedron_demo_plugin(las_to_xyz_plugin LAS_to_xyz_io_plugin)
|
||||
target_link_libraries(las_to_xyz_plugin scene_points_with_normal_item ${libLAS_LIBRARIES})
|
||||
else()
|
||||
message(STATUS "NOTICE : the las IO plugin needs LAS libraries and will not be compiled.")
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,63 @@
|
|||
#include "Scene_points_with_normal_item.h"
|
||||
#include <CGAL/Three/Polyhedron_demo_io_plugin_interface.h>
|
||||
|
||||
#include "read_las_point_set.h"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
class Polyhedron_demo_las_to_xyz_plugin :
|
||||
public QObject,
|
||||
public CGAL::Three::Polyhedron_demo_io_plugin_interface
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(CGAL::Three::Polyhedron_demo_io_plugin_interface)
|
||||
Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.IOPluginInterface/1.0")
|
||||
|
||||
public:
|
||||
QString name() const { return "las_to_xyz_plugin"; }
|
||||
QString nameFilters() const { return "LAS files as Point set (*.las);;Compressed LAZ files as Point set (*.laz)"; }
|
||||
bool canLoad() const;
|
||||
CGAL::Three::Scene_item* load(QFileInfo fileinfo);
|
||||
|
||||
bool canSave(const CGAL::Three::Scene_item*);
|
||||
bool save(const CGAL::Three::Scene_item*, QFileInfo fileinfo);
|
||||
};
|
||||
|
||||
bool Polyhedron_demo_las_to_xyz_plugin::canLoad() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
CGAL::Three::Scene_item*
|
||||
Polyhedron_demo_las_to_xyz_plugin::load(QFileInfo fileinfo) {
|
||||
std::ifstream in(fileinfo.filePath().toUtf8(), std::ios_base::binary);
|
||||
|
||||
if(!in)
|
||||
std::cerr << "Error!\n";
|
||||
|
||||
Scene_points_with_normal_item* item;
|
||||
item = new Scene_points_with_normal_item();
|
||||
if(!read_las_point_set(in, *(item->point_set())) || item->isEmpty())
|
||||
{
|
||||
delete item;
|
||||
return 0;
|
||||
}
|
||||
item->point_set()->check_colors();
|
||||
std::cerr << item->point_set()->info();
|
||||
|
||||
item->setName(fileinfo.completeBaseName());
|
||||
return item;
|
||||
}
|
||||
|
||||
bool Polyhedron_demo_las_to_xyz_plugin::canSave(const CGAL::Three::Scene_item*)
|
||||
{
|
||||
// No save function yet
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Polyhedron_demo_las_to_xyz_plugin::save(const CGAL::Three::Scene_item*, QFileInfo)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
#include "LAS_to_xyz_io_plugin.moc"
|
||||
|
|
@ -10,3 +10,6 @@ polyhedron_demo_plugin(trivial_plugin Trivial_plugin)
|
|||
|
||||
polyhedron_demo_plugin(create_bbox_mesh_plugin Create_bbox_mesh_plugin)
|
||||
target_link_libraries(create_bbox_mesh_plugin scene_polyhedron_item)
|
||||
|
||||
polyhedron_demo_plugin(recenter_plugin Recenter_plugin)
|
||||
target_link_libraries(recenter_plugin scene_points_with_normal_item)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,81 @@
|
|||
#include "config.h"
|
||||
#include "Scene_points_with_normal_item.h"
|
||||
#include <CGAL/Three/Polyhedron_demo_plugin_helper.h>
|
||||
#include <CGAL/Three/Polyhedron_demo_plugin_interface.h>
|
||||
|
||||
#include <CGAL/centroid.h>
|
||||
|
||||
|
||||
#include <QObject>
|
||||
#include <QAction>
|
||||
#include <QMainWindow>
|
||||
#include <QApplication>
|
||||
#include <QtPlugin>
|
||||
#include <QMessageBox>
|
||||
|
||||
using namespace CGAL::Three;
|
||||
class Polyhedron_demo_recenter_plugin :
|
||||
public QObject,
|
||||
public Polyhedron_demo_plugin_helper
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(CGAL::Three::Polyhedron_demo_plugin_interface)
|
||||
Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.PluginInterface/1.0")
|
||||
|
||||
private:
|
||||
QAction* actionRecenter;
|
||||
|
||||
public:
|
||||
void init(QMainWindow* mainWindow, CGAL::Three::Scene_interface* scene_interface, Messages_interface*) {
|
||||
scene = scene_interface;
|
||||
mw = mainWindow;
|
||||
actionRecenter = new QAction(tr("Recenter"), mainWindow);
|
||||
actionRecenter->setObjectName("actionRecenter");
|
||||
autoConnectActions();
|
||||
}
|
||||
|
||||
QList<QAction*> actions() const {
|
||||
return QList<QAction*>() << actionRecenter;
|
||||
}
|
||||
|
||||
//! Applicable if the currently selected item is a
|
||||
//! points_with_normal_item (can be extended to other items).
|
||||
bool applicable(QAction*) const {
|
||||
return qobject_cast<Scene_points_with_normal_item*>(scene->item(scene->mainSelectionIndex()));
|
||||
}
|
||||
|
||||
public Q_SLOTS:
|
||||
void on_actionRecenter_triggered();
|
||||
}; // end Polyhedron_demo_recenter_plugin
|
||||
|
||||
void Polyhedron_demo_recenter_plugin::on_actionRecenter_triggered()
|
||||
{
|
||||
const CGAL::Three::Scene_interface::Item_id index = scene->mainSelectionIndex();
|
||||
|
||||
Scene_points_with_normal_item* item =
|
||||
qobject_cast<Scene_points_with_normal_item*>(scene->item(index));
|
||||
|
||||
if(item)
|
||||
{
|
||||
Point_set* points = item->point_set();
|
||||
if(points == NULL)
|
||||
return;
|
||||
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
|
||||
Kernel::Point_3 centroid = CGAL::centroid (points->points().begin(),
|
||||
points->points().end());
|
||||
Kernel::Vector_3 recenter (centroid, CGAL::ORIGIN);
|
||||
std::cerr << "Recenter by " << recenter << std::endl;
|
||||
for (Point_set::iterator it = points->begin(); it != points->end(); ++ it)
|
||||
points->point(*it) = points->point(*it) + recenter;
|
||||
|
||||
QApplication::restoreOverrideCursor();
|
||||
points->invalidate_bounds();
|
||||
item->invalidateOpenGLBuffers();
|
||||
scene->itemChanged(index);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#include "Recenter_plugin.moc"
|
||||
|
|
@ -39,6 +39,10 @@ endif()
|
|||
polyhedron_demo_plugin(point_set_selection_plugin Point_set_selection_plugin ${point_set_selectionUI_FILES})
|
||||
target_link_libraries(point_set_selection_plugin scene_points_with_normal_item scene_polylines_item)
|
||||
|
||||
qt5_wrap_ui( point_set_classificationUI_FILES Point_set_classification_widget.ui)
|
||||
polyhedron_demo_plugin(point_set_classification_plugin Point_set_classification_plugin ${point_set_classificationUI_FILES})
|
||||
target_link_libraries(point_set_classification_plugin scene_point_set_classification_item scene_points_with_normal_item scene_polylines_item scene_polygon_soup_item)
|
||||
|
||||
qt5_wrap_ui(point_set_shape_detectionUI_FILES Point_set_shape_detection_plugin.ui)
|
||||
polyhedron_demo_plugin(point_set_shape_detection_plugin Point_set_shape_detection_plugin ${point_set_shape_detectionUI_FILES})
|
||||
target_link_libraries(point_set_shape_detection_plugin scene_polyhedron_item scene_points_with_normal_item scene_polygon_soup_item)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,894 @@
|
|||
#include <QtCore/qglobal.h>
|
||||
#include <QFileDialog>
|
||||
#include <QColorDialog>
|
||||
#include <fstream>
|
||||
#include "opengl_tools.h"
|
||||
|
||||
#include "Messages_interface.h"
|
||||
#include "Scene_points_with_normal_item.h"
|
||||
#include "Scene_point_set_classification_item.h"
|
||||
#include "Scene_polylines_item.h"
|
||||
#include "Scene_polygon_soup_item.h"
|
||||
|
||||
#include <CGAL/Three/Scene_interface.h>
|
||||
#include <CGAL/Three/Polyhedron_demo_plugin_helper.h>
|
||||
|
||||
#include <CGAL/Random.h>
|
||||
|
||||
#include "ui_Point_set_classification_widget.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QMainWindow>
|
||||
#include <QApplication>
|
||||
#include <QCheckBox>
|
||||
#include <QInputDialog>
|
||||
#include <QSlider>
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <boost/graph/adjacency_list.hpp>
|
||||
#include <CGAL/boost/graph/split_graph_into_polylines.h>
|
||||
|
||||
using namespace CGAL::Three;
|
||||
|
||||
class Polyhedron_demo_point_set_classification_plugin :
|
||||
public QObject,
|
||||
public Polyhedron_demo_plugin_helper
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(CGAL::Three::Polyhedron_demo_plugin_interface)
|
||||
Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.PluginInterface/1.0")
|
||||
|
||||
struct ClassRow
|
||||
{
|
||||
QLabel* label;
|
||||
|
||||
QPushButton* color_button;
|
||||
QPushButton* train;
|
||||
QPushButton* remove;
|
||||
QColor color;
|
||||
|
||||
QLabel* label2;
|
||||
QComboBox* effect;
|
||||
|
||||
ClassRow (QWidget* parent, const char* name, const QColor& color)
|
||||
: color (color)
|
||||
{
|
||||
label = new QLabel (name, parent);
|
||||
color_button = new QPushButton ("", parent);
|
||||
|
||||
QString s("background: #"
|
||||
+ QString(color.red() < 16? "0" : "") + QString::number(color.red(),16)
|
||||
+ QString(color.green() < 16? "0" : "") + QString::number(color.green(),16)
|
||||
+ QString(color.blue() < 16? "0" : "") + QString::number(color.blue(),16) + ";");
|
||||
color_button->setStyleSheet(s);
|
||||
|
||||
train = new QPushButton ("Add selection");
|
||||
remove = new QPushButton ("Remove");
|
||||
label2 = new QLabel (name, parent);
|
||||
effect = new QComboBox;
|
||||
effect->addItem("Penalized");
|
||||
effect->addItem("Neutral");
|
||||
effect->addItem("Favored");
|
||||
|
||||
}
|
||||
~ClassRow ()
|
||||
{
|
||||
}
|
||||
void change_color (const QColor& color)
|
||||
{
|
||||
this->color = color;
|
||||
QString s("background: #"
|
||||
+ QString(color.red() < 16? "0" : "") + QString::number(color.red(),16)
|
||||
+ QString(color.green() < 16? "0" : "") + QString::number(color.green(),16)
|
||||
+ QString(color.blue() < 16? "0" : "") + QString::number(color.blue(),16) + ";");
|
||||
color_button->setStyleSheet(s);
|
||||
color_button->update();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public:
|
||||
bool applicable(QAction*) const {
|
||||
return
|
||||
qobject_cast<Scene_points_with_normal_item*>(scene->item(scene->mainSelectionIndex()));
|
||||
}
|
||||
void print_message(QString message) { messages->information(message); }
|
||||
QList<QAction*> actions() const { return QList<QAction*>() << actionPointSetClassification; }
|
||||
|
||||
using Polyhedron_demo_plugin_helper::init;
|
||||
void init(QMainWindow* mainWindow, CGAL::Three::Scene_interface* scene_interface, Messages_interface* m) {
|
||||
mw = mainWindow;
|
||||
scene = scene_interface;
|
||||
messages = m;
|
||||
actionPointSetClassification = new QAction(tr("Point Set Classification"), mw);
|
||||
connect(actionPointSetClassification, SIGNAL(triggered()), this, SLOT(point_set_classification_action()));
|
||||
|
||||
dock_widget = new QDockWidget("Point Set Classification", mw);
|
||||
dock_widget->setVisible(false);
|
||||
|
||||
ui_widget.setupUi(dock_widget);
|
||||
addDockWidget(dock_widget);
|
||||
|
||||
color_att = QColor (75, 75, 77);
|
||||
|
||||
connect(ui_widget.create_from_item, SIGNAL(clicked()), this,
|
||||
SLOT(on_create_from_item_button_clicked()));
|
||||
connect(ui_widget.compute_features, SIGNAL(clicked()), this,
|
||||
SLOT(on_compute_features_button_clicked()));
|
||||
connect(ui_widget.display, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(on_display_button_clicked(int)));
|
||||
connect(ui_widget.run, SIGNAL(clicked()), this,
|
||||
SLOT(on_run_button_clicked()));
|
||||
connect(ui_widget.save_config, SIGNAL(clicked()), this,
|
||||
SLOT(on_save_config_button_clicked()));
|
||||
connect(ui_widget.load_config, SIGNAL(clicked()), this,
|
||||
SLOT(on_load_config_button_clicked()));
|
||||
connect(ui_widget.run_smoothed, SIGNAL(clicked()), this,
|
||||
SLOT(on_run_smoothed_button_clicked()));
|
||||
connect(ui_widget.run_graphcut, SIGNAL(clicked()), this,
|
||||
SLOT(on_run_graphcut_button_clicked()));
|
||||
connect(ui_widget.smoothingDoubleSpinBox, SIGNAL(valueChanged(double)), this,
|
||||
SLOT(on_smoothing_value_changed(double)));
|
||||
connect(ui_widget.save, SIGNAL(clicked()), this,
|
||||
SLOT(on_save_button_clicked()));
|
||||
connect(ui_widget.generate_point_set_items, SIGNAL(clicked()), this,
|
||||
SLOT(on_generate_point_set_items_button_clicked()));
|
||||
|
||||
connect(ui_widget.numberOfScalesSpinBox, SIGNAL(valueChanged(int)), this,
|
||||
SLOT(on_update_nb_scales()));
|
||||
connect(ui_widget.number_of_trials, SIGNAL(valueChanged(int)), this,
|
||||
SLOT(on_update_number_of_trials()));
|
||||
|
||||
connect(ui_widget.add_new_class, SIGNAL(clicked()), this,
|
||||
SLOT(on_add_new_class_clicked()));
|
||||
connect(ui_widget.reset_training_sets, SIGNAL(clicked()), this,
|
||||
SLOT(on_reset_training_sets_clicked()));
|
||||
connect(ui_widget.validate_selection, SIGNAL(clicked()), this,
|
||||
SLOT(on_validate_selection_clicked()));
|
||||
connect(ui_widget.train, SIGNAL(clicked()), this,
|
||||
SLOT(on_train_clicked()));
|
||||
|
||||
connect(ui_widget.selected_attribute, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(on_selected_attribute_changed(int)));
|
||||
connect(ui_widget.attribute_weight, SIGNAL(valueChanged(int)), this,
|
||||
SLOT(on_attribute_weight_changed(int)));
|
||||
|
||||
QObject* scene_obj = dynamic_cast<QObject*>(scene_interface);
|
||||
if(scene_obj)
|
||||
{
|
||||
connect(scene_obj, SIGNAL(itemAboutToBeDestroyed(CGAL::Three::Scene_item*)), this,
|
||||
SLOT(item_about_to_be_destroyed(CGAL::Three::Scene_item*)));
|
||||
|
||||
connect(scene_obj, SIGNAL(itemIndexSelected(int)), this,
|
||||
SLOT(update_plugin(int)));
|
||||
}
|
||||
}
|
||||
virtual void closure()
|
||||
{
|
||||
dock_widget->hide();
|
||||
}
|
||||
|
||||
|
||||
public Q_SLOTS:
|
||||
|
||||
void item_about_to_be_destroyed(CGAL::Three::Scene_item* scene_item) {
|
||||
// if points item
|
||||
Scene_points_with_normal_item* points_item = qobject_cast<Scene_points_with_normal_item*>(scene_item);
|
||||
if(points_item)
|
||||
{
|
||||
Item_map::iterator it = item_map.find(points_item);
|
||||
if (it != item_map.end())
|
||||
{
|
||||
Scene_point_set_classification_item* classif_item = it->second;
|
||||
item_map.erase(it); // first erase from map, because scene->erase will cause a call to this function
|
||||
scene->erase( scene->item_id(classif_item) );
|
||||
}
|
||||
}
|
||||
|
||||
// if classification item
|
||||
Scene_point_set_classification_item* classif_item = qobject_cast<Scene_point_set_classification_item*>(scene_item);
|
||||
if(classif_item)
|
||||
item_map.erase (classif_item->points_item());
|
||||
}
|
||||
|
||||
void point_set_classification_action()
|
||||
{
|
||||
dock_widget->show();
|
||||
dock_widget->raise();
|
||||
Scene_points_with_normal_item* points_item = getSelectedItem<Scene_points_with_normal_item>();
|
||||
|
||||
if (item_map.find(points_item) == item_map.end())
|
||||
on_create_from_item_button_clicked();
|
||||
}
|
||||
|
||||
void update_plugin(int)
|
||||
{
|
||||
update_plugin_from_item(get_classification_item());
|
||||
}
|
||||
|
||||
void disable_everything ()
|
||||
{
|
||||
ui_widget.load_config->setEnabled(false);
|
||||
ui_widget.save_config->setEnabled(false);
|
||||
ui_widget.compute_features->setEnabled(false);
|
||||
ui_widget.numberOfScalesSpinBox->setEnabled(false);
|
||||
ui_widget.display->setEnabled(false);
|
||||
ui_widget.tabWidget->setEnabled(false);
|
||||
ui_widget.run->setEnabled(false);
|
||||
ui_widget.run_smoothed->setEnabled(false);
|
||||
ui_widget.frame->setEnabled(false);
|
||||
ui_widget.save->setEnabled(false);
|
||||
ui_widget.generate_point_set_items->setEnabled(false);
|
||||
}
|
||||
|
||||
void enable_computation()
|
||||
{
|
||||
ui_widget.load_config->setEnabled(true);
|
||||
ui_widget.compute_features->setEnabled(true);
|
||||
ui_widget.numberOfScalesSpinBox->setEnabled(true);
|
||||
ui_widget.display->setEnabled(true);
|
||||
}
|
||||
|
||||
void enable_classif()
|
||||
{
|
||||
ui_widget.save_config->setEnabled(true);
|
||||
ui_widget.tabWidget->setEnabled(true);
|
||||
ui_widget.run->setEnabled(true);
|
||||
ui_widget.run_smoothed->setEnabled(true);
|
||||
ui_widget.frame->setEnabled(true);
|
||||
ui_widget.save->setEnabled(true);
|
||||
ui_widget.generate_point_set_items->setEnabled(true);
|
||||
}
|
||||
|
||||
|
||||
void update_plugin_from_item(Scene_point_set_classification_item* item)
|
||||
{
|
||||
if (item == NULL) // Deactivate plugin
|
||||
{
|
||||
disable_everything();
|
||||
ui_widget.tabWidget->setCurrentIndex(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
disable_everything();
|
||||
enable_computation();
|
||||
|
||||
ui_widget.numberOfScalesSpinBox->setValue((int)(item->nb_scales()));
|
||||
ui_widget.number_of_trials->setValue((int)(item->number_of_trials()));
|
||||
ui_widget.smoothingDoubleSpinBox->setValue((int)(item->smoothing()));
|
||||
|
||||
// Clear class types
|
||||
for (std::size_t i = 0; i < class_rows.size(); ++ i)
|
||||
{
|
||||
|
||||
ui_widget.gridLayout_3->removeWidget (class_rows[i].label);
|
||||
delete class_rows[i].label;
|
||||
ui_widget.gridLayout_3->removeWidget (class_rows[i].color_button);
|
||||
delete class_rows[i].color_button;
|
||||
ui_widget.gridLayout_3->removeWidget (class_rows[i].train);
|
||||
delete class_rows[i].train;
|
||||
ui_widget.gridLayout_3->removeWidget (class_rows[i].remove);
|
||||
delete class_rows[i].remove;
|
||||
ui_widget.gridLayout->removeWidget (class_rows[i].label2);
|
||||
delete class_rows[i].label2;
|
||||
ui_widget.gridLayout->removeWidget (class_rows[i].effect);
|
||||
delete class_rows[i].effect;
|
||||
}
|
||||
class_rows.clear();
|
||||
|
||||
// Add types
|
||||
for (std::size_t i = 0; i < item->types().size(); ++ i)
|
||||
add_new_class (ClassRow (dock_widget, item->types()[i].first->id().c_str(),
|
||||
item->types()[i].second));
|
||||
|
||||
// Enabled classif if features computed
|
||||
if (!(item->features_computed()))
|
||||
ui_widget.tabWidget->setCurrentIndex(0);
|
||||
else
|
||||
enable_classif();
|
||||
|
||||
int index = ui_widget.display->currentIndex();
|
||||
ui_widget.display->clear();
|
||||
ui_widget.display->addItem("Real colors");
|
||||
ui_widget.display->addItem("Classification");
|
||||
ui_widget.display->addItem("Training sets");
|
||||
ui_widget.selected_attribute->clear();
|
||||
item->fill_display_combo_box(ui_widget.display, ui_widget.selected_attribute);
|
||||
if (index >= ui_widget.display->count())
|
||||
ui_widget.display->setCurrentIndex(1);
|
||||
else
|
||||
ui_widget.display->setCurrentIndex(index);
|
||||
ui_widget.selected_attribute->setCurrentIndex(0);
|
||||
}
|
||||
}
|
||||
|
||||
void on_update_nb_scales()
|
||||
{
|
||||
Scene_point_set_classification_item* classification_item
|
||||
= get_classification_item();
|
||||
if(!classification_item)
|
||||
return;
|
||||
classification_item->nb_scales() = ui_widget.numberOfScalesSpinBox->value();
|
||||
}
|
||||
void on_update_number_of_trials()
|
||||
{
|
||||
Scene_point_set_classification_item* classification_item
|
||||
= get_classification_item();
|
||||
if(!classification_item)
|
||||
return;
|
||||
classification_item->number_of_trials() = ui_widget.number_of_trials->value();
|
||||
}
|
||||
|
||||
|
||||
Scene_point_set_classification_item* get_classification_item()
|
||||
{
|
||||
Scene_point_set_classification_item* out =
|
||||
qobject_cast<Scene_point_set_classification_item*>(scene->item(scene->mainSelectionIndex()));
|
||||
if (out)
|
||||
return out;
|
||||
|
||||
Scene_points_with_normal_item* points_item =
|
||||
qobject_cast<Scene_points_with_normal_item*>(scene->item(scene->mainSelectionIndex()));
|
||||
if (!points_item)
|
||||
return NULL;
|
||||
|
||||
Item_map::iterator it = item_map.find(points_item);
|
||||
if (it != item_map.end())
|
||||
return it->second;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void on_create_from_item_button_clicked()
|
||||
{
|
||||
Scene_points_with_normal_item* points_item = getSelectedItem<Scene_points_with_normal_item>();
|
||||
if(!points_item)
|
||||
{
|
||||
print_message("Error: there is no selected point set item!");
|
||||
return;
|
||||
}
|
||||
if (item_map.find(points_item) != item_map.end())
|
||||
return;
|
||||
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
Scene_point_set_classification_item* new_item
|
||||
= new Scene_point_set_classification_item (points_item);
|
||||
scene->addItem(new_item);
|
||||
new_item->setName(QString("%1 (classification)").arg(points_item->name()));
|
||||
points_item->setVisible (false);
|
||||
item_map.insert (std::make_pair (points_item, new_item));
|
||||
QApplication::restoreOverrideCursor();
|
||||
connect(points_item, &Scene_points_with_normal_item::itemChanged,
|
||||
new_item, &Scene_point_set_classification_item::invalidateOpenGLBuffers);
|
||||
|
||||
update_plugin_from_item(new_item);
|
||||
}
|
||||
|
||||
void run (Scene_point_set_classification_item* classification_item, int method)
|
||||
{
|
||||
classification_item->run (method);
|
||||
}
|
||||
|
||||
void on_compute_features_button_clicked()
|
||||
{
|
||||
Scene_point_set_classification_item* classification_item
|
||||
= get_classification_item();
|
||||
if(!classification_item)
|
||||
{
|
||||
print_message("Error: there is no point set classification item!");
|
||||
return;
|
||||
}
|
||||
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
QTime time;
|
||||
time.start();
|
||||
classification_item->compute_features ();
|
||||
// run (classification_item, 0);
|
||||
std::cerr << "Features computed in " << time.elapsed() / 1000 << " second(s)" << std::endl;
|
||||
update_plugin_from_item(classification_item);
|
||||
QApplication::restoreOverrideCursor();
|
||||
scene->itemChanged(classification_item);
|
||||
}
|
||||
|
||||
void on_save_config_button_clicked()
|
||||
{
|
||||
Scene_point_set_classification_item* classification_item
|
||||
= get_classification_item();
|
||||
if(!classification_item)
|
||||
{
|
||||
print_message("Error: there is no point set classification item!");
|
||||
return;
|
||||
}
|
||||
|
||||
QString filename = QFileDialog::getSaveFileName(mw,
|
||||
tr("Save classification configuration"),
|
||||
QString("config.xml"),
|
||||
"Config file (*.xml);;");
|
||||
if (filename == QString())
|
||||
return;
|
||||
|
||||
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
|
||||
classification_item->save_config (filename.toStdString().c_str());
|
||||
|
||||
QApplication::restoreOverrideCursor();
|
||||
|
||||
}
|
||||
|
||||
void on_load_config_button_clicked()
|
||||
{
|
||||
Scene_point_set_classification_item* classification_item
|
||||
= get_classification_item();
|
||||
if(!classification_item)
|
||||
{
|
||||
print_message("Error: there is no point set classification item!");
|
||||
return;
|
||||
}
|
||||
QString filename = QFileDialog::getOpenFileName(mw,
|
||||
tr("Open classification configuration"),
|
||||
".",
|
||||
"Config file (*.xml);;All Files (*)");
|
||||
|
||||
if (filename == QString())
|
||||
return;
|
||||
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
|
||||
classification_item->load_config (filename.toStdString().c_str());
|
||||
update_plugin_from_item(classification_item);
|
||||
run (classification_item, 0);
|
||||
|
||||
QApplication::restoreOverrideCursor();
|
||||
scene->itemChanged(classification_item);
|
||||
}
|
||||
|
||||
|
||||
void on_display_button_clicked(int index)
|
||||
{
|
||||
Scene_point_set_classification_item* classification_item
|
||||
= get_classification_item();
|
||||
if(!classification_item)
|
||||
return;
|
||||
|
||||
classification_item->change_color (index);
|
||||
scene->itemChanged(classification_item);
|
||||
}
|
||||
|
||||
void on_run_button_clicked()
|
||||
{
|
||||
Scene_point_set_classification_item* classification_item
|
||||
= get_classification_item();
|
||||
if(!classification_item)
|
||||
{
|
||||
print_message("Error: there is no point set classification item!");
|
||||
return;
|
||||
}
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
run (classification_item, 0);
|
||||
QApplication::restoreOverrideCursor();
|
||||
scene->itemChanged(classification_item);
|
||||
}
|
||||
|
||||
void on_run_smoothed_button_clicked()
|
||||
{
|
||||
Scene_point_set_classification_item* classification_item
|
||||
= get_classification_item();
|
||||
if(!classification_item)
|
||||
{
|
||||
print_message("Error: there is no point set classification item!");
|
||||
return;
|
||||
}
|
||||
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
QTime time;
|
||||
time.start();
|
||||
run (classification_item, 1);
|
||||
std::cerr << "Smoothed classification computed in " << time.elapsed() / 1000 << " second(s)" << std::endl;
|
||||
QApplication::restoreOverrideCursor();
|
||||
scene->itemChanged(classification_item);
|
||||
}
|
||||
|
||||
void on_run_graphcut_button_clicked()
|
||||
{
|
||||
Scene_point_set_classification_item* classification_item
|
||||
= get_classification_item();
|
||||
if(!classification_item)
|
||||
{
|
||||
print_message("Error: there is no point set classification item!");
|
||||
return;
|
||||
}
|
||||
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
QTime time;
|
||||
time.start();
|
||||
run (classification_item, 2);
|
||||
std::cerr << "Graphcut classification computed in " << time.elapsed() / 1000 << " second(s)" << std::endl;
|
||||
QApplication::restoreOverrideCursor();
|
||||
scene->itemChanged(classification_item);
|
||||
}
|
||||
|
||||
void on_smoothing_value_changed(double v)
|
||||
{
|
||||
Scene_point_set_classification_item* classification_item
|
||||
= get_classification_item();
|
||||
if(!classification_item)
|
||||
return;
|
||||
classification_item->smoothing() = v;
|
||||
}
|
||||
|
||||
void on_save_button_clicked()
|
||||
{
|
||||
Scene_point_set_classification_item* classification_item
|
||||
= get_classification_item();
|
||||
if(!classification_item)
|
||||
{
|
||||
print_message("Error: there is no point set classification item!");
|
||||
return;
|
||||
}
|
||||
|
||||
QString filename = QFileDialog::getSaveFileName(mw,
|
||||
tr("Save PLY classified point set"),
|
||||
QString("%1.ply").arg(classification_item->name()),
|
||||
"PLY point set (*.ply);;");
|
||||
|
||||
if (filename == QString())
|
||||
return;
|
||||
|
||||
std::ofstream out(filename.toUtf8());
|
||||
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
classification_item->write_ply_point_set (out);
|
||||
QApplication::restoreOverrideCursor();
|
||||
|
||||
out.close();
|
||||
}
|
||||
|
||||
void on_generate_point_set_items_button_clicked()
|
||||
{
|
||||
Scene_point_set_classification_item* classification_item
|
||||
= get_classification_item();
|
||||
if(!classification_item)
|
||||
{
|
||||
print_message("Error: there is no point set classification item!");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
|
||||
std::vector<Scene_points_with_normal_item*> new_items;
|
||||
classification_item->generate_point_set_items<Scene_points_with_normal_item>
|
||||
(new_items, classification_item->points_item()->name().toStdString().c_str());
|
||||
|
||||
for (std::size_t i = 0; i < new_items.size(); ++ i)
|
||||
{
|
||||
if (new_items[i]->point_set()->empty())
|
||||
delete new_items[i];
|
||||
else
|
||||
scene->addItem (new_items[i]);
|
||||
}
|
||||
|
||||
QApplication::restoreOverrideCursor();
|
||||
}
|
||||
|
||||
void on_add_new_class_clicked()
|
||||
{
|
||||
Scene_point_set_classification_item* classification_item
|
||||
= get_classification_item();
|
||||
if(!classification_item)
|
||||
{
|
||||
print_message("Error: there is no point set classification item!");
|
||||
return;
|
||||
}
|
||||
|
||||
bool ok;
|
||||
QString name =
|
||||
QInputDialog::getText((QWidget*)mw,
|
||||
tr("Add new classification type"), // dialog title
|
||||
tr("Name:"), // field label
|
||||
QLineEdit::Normal,
|
||||
tr("type%1").arg(class_rows.size() + 1),
|
||||
&ok);
|
||||
if (!ok)
|
||||
return;
|
||||
|
||||
add_new_class (ClassRow (dock_widget, name.toStdString().c_str(),
|
||||
QColor (192 + rand() % 60,
|
||||
192 + rand() % 60,
|
||||
192 + rand() % 60)));
|
||||
classification_item->add_new_type (class_rows.back().label->text().toStdString().c_str(),
|
||||
class_rows.back().color);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void on_reset_training_sets_clicked()
|
||||
{
|
||||
Scene_point_set_classification_item* classification_item
|
||||
= get_classification_item();
|
||||
if(!classification_item)
|
||||
{
|
||||
print_message("Error: there is no point set classification item!");
|
||||
return;
|
||||
}
|
||||
|
||||
classification_item->reset_training_sets();
|
||||
}
|
||||
|
||||
void on_validate_selection_clicked()
|
||||
{
|
||||
Scene_point_set_classification_item* classification_item
|
||||
= get_classification_item();
|
||||
if(!classification_item)
|
||||
{
|
||||
print_message("Error: there is no point set classification item!");
|
||||
return;
|
||||
}
|
||||
|
||||
classification_item->validate_selection();
|
||||
}
|
||||
|
||||
void on_train_clicked()
|
||||
{
|
||||
Scene_point_set_classification_item* classification_item
|
||||
= get_classification_item();
|
||||
if(!classification_item)
|
||||
{
|
||||
print_message("Error: there is no point set classification item!");
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::string> classes;
|
||||
std::vector<QColor> colors;
|
||||
|
||||
for (std::size_t i = 0; i < class_rows.size(); ++ i)
|
||||
{
|
||||
classes.push_back (class_rows[i].label->text().toStdString());
|
||||
colors.push_back (class_rows[i].color);
|
||||
}
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
classification_item->train();
|
||||
QApplication::restoreOverrideCursor();
|
||||
update_plugin_from_item(classification_item);
|
||||
}
|
||||
|
||||
void add_new_class (const ClassRow& class_row)
|
||||
{
|
||||
class_rows.push_back (class_row);
|
||||
int position = static_cast<int>(class_rows.size());
|
||||
|
||||
ui_widget.gridLayout_3->addWidget (class_rows.back().label, position, 0);
|
||||
ui_widget.gridLayout_3->addWidget (class_rows.back().color_button, position, 1);
|
||||
ui_widget.gridLayout_3->addWidget (class_rows.back().train, position, 3);
|
||||
ui_widget.gridLayout_3->addWidget (class_rows.back().remove, position, 5);
|
||||
|
||||
connect(class_rows.back().remove, SIGNAL(clicked()), this,
|
||||
SLOT(on_remove_class_clicked()));
|
||||
connect(class_rows.back().color_button, SIGNAL(clicked()), this,
|
||||
SLOT(on_color_changed_clicked()));
|
||||
connect(class_rows.back().train, SIGNAL(clicked()), this,
|
||||
SLOT(on_add_selection_to_training_set_clicked()));
|
||||
|
||||
ui_widget.gridLayout->addWidget (class_rows.back().label2, position, 0);
|
||||
ui_widget.gridLayout->addWidget (class_rows.back().effect, position, 2);
|
||||
|
||||
connect(class_rows.back().effect, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(on_effect_changed(int)));
|
||||
|
||||
}
|
||||
|
||||
void on_remove_class_clicked()
|
||||
{
|
||||
Scene_point_set_classification_item* classification_item
|
||||
= get_classification_item();
|
||||
if(!classification_item)
|
||||
{
|
||||
print_message("Error: there is no point set classification item!");
|
||||
return;
|
||||
}
|
||||
|
||||
int index = ui_widget.gridLayout_3->indexOf(qobject_cast<QWidget*>(QObject::sender()));
|
||||
|
||||
int row_index, column_index, row_span, column_span;
|
||||
ui_widget.gridLayout_3->getItemPosition(index, &row_index, &column_index, &row_span, &column_span);
|
||||
--row_index;
|
||||
|
||||
classification_item->remove_type (class_rows[row_index].label->text().toStdString().c_str());
|
||||
|
||||
ui_widget.gridLayout_3->removeWidget (class_rows[row_index].label);
|
||||
delete class_rows[row_index].label;
|
||||
ui_widget.gridLayout_3->removeWidget (class_rows[row_index].color_button);
|
||||
delete class_rows[row_index].color_button;
|
||||
ui_widget.gridLayout_3->removeWidget (class_rows[row_index].train);
|
||||
delete class_rows[row_index].train;
|
||||
ui_widget.gridLayout_3->removeWidget (class_rows[row_index].remove);
|
||||
delete class_rows[row_index].remove;
|
||||
|
||||
ui_widget.gridLayout->removeWidget (class_rows[row_index].label2);
|
||||
delete class_rows[row_index].label2;
|
||||
ui_widget.gridLayout->removeWidget (class_rows[row_index].effect);
|
||||
delete class_rows[row_index].effect;
|
||||
|
||||
if (class_rows.size() > 1)
|
||||
for (std::size_t i = row_index + 1; i < class_rows.size(); ++ i)
|
||||
{
|
||||
ui_widget.gridLayout_3->addWidget (class_rows[i].label, (int)i, 0);
|
||||
ui_widget.gridLayout_3->addWidget (class_rows[i].color_button, (int)i, 1);
|
||||
ui_widget.gridLayout_3->addWidget (class_rows[i].train, (int)i, 3);
|
||||
ui_widget.gridLayout_3->addWidget (class_rows[i].remove, (int)i, 5);
|
||||
ui_widget.gridLayout->addWidget (class_rows[i].label2, (int)i, 0);
|
||||
ui_widget.gridLayout->addWidget (class_rows[i].effect, (int)i, 2);
|
||||
}
|
||||
|
||||
class_rows.erase (class_rows.begin() + row_index);
|
||||
|
||||
scene->itemChanged(classification_item);
|
||||
}
|
||||
|
||||
void on_color_changed_clicked()
|
||||
{
|
||||
Scene_point_set_classification_item* classification_item
|
||||
= get_classification_item();
|
||||
if(!classification_item)
|
||||
{
|
||||
print_message("Error: there is no point set classification item!");
|
||||
return;
|
||||
}
|
||||
|
||||
QPushButton* color_button = qobject_cast<QPushButton*>(QObject::sender());
|
||||
int index = ui_widget.gridLayout_3->indexOf(color_button);
|
||||
int row_index, column_index, row_span, column_span;
|
||||
ui_widget.gridLayout_3->getItemPosition(index, &row_index, &column_index, &row_span, &column_span);
|
||||
-- row_index;
|
||||
|
||||
QColor color = class_rows[row_index].color;
|
||||
color = QColorDialog::getColor(color, (QWidget*)mw, "Change of color of classification type");
|
||||
class_rows[row_index].change_color (color);
|
||||
classification_item->change_type_color (class_rows[row_index].label->text().toStdString().c_str(),
|
||||
color);
|
||||
|
||||
scene->itemChanged(classification_item);
|
||||
}
|
||||
|
||||
void on_add_selection_to_training_set_clicked()
|
||||
{
|
||||
Scene_point_set_classification_item* classification_item
|
||||
= get_classification_item();
|
||||
if(!classification_item)
|
||||
{
|
||||
print_message("Error: there is no point set classification item!");
|
||||
return;
|
||||
}
|
||||
|
||||
int index = ui_widget.gridLayout_3->indexOf(qobject_cast<QWidget*>(QObject::sender()));
|
||||
int row_index, column_index, row_span, column_span;
|
||||
ui_widget.gridLayout_3->getItemPosition(index, &row_index, &column_index, &row_span, &column_span);
|
||||
--row_index;
|
||||
|
||||
classification_item->add_selection_to_training_set
|
||||
(class_rows[row_index].label->text().toStdString().c_str());
|
||||
}
|
||||
|
||||
void on_selected_attribute_changed(int v)
|
||||
{
|
||||
Scene_point_set_classification_item* classification_item
|
||||
= get_classification_item();
|
||||
if(!classification_item)
|
||||
{
|
||||
print_message("Error: there is no point set classification item!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (classification_item->number_of_attributes() <= (std::size_t)v)
|
||||
return;
|
||||
|
||||
Scene_point_set_classification_item::Attribute_handle
|
||||
att = classification_item->attribute(v);
|
||||
|
||||
if (att == Scene_point_set_classification_item::Attribute_handle())
|
||||
return;
|
||||
|
||||
// std::cerr << att->weight
|
||||
// << " " << (int)(1001. * 2. * std::atan(att->weight) / CGAL_PI) << std::endl;
|
||||
ui_widget.attribute_weight->setValue ((int)(1001. * 2. * std::atan(att->weight) / CGAL_PI));
|
||||
|
||||
for (std::size_t i = 0; i < classification_item->types().size(); ++ i)
|
||||
{
|
||||
CGAL::Classification::Type::Attribute_effect
|
||||
eff = classification_item->types()[i].first->attribute_effect(att);
|
||||
if (eff == CGAL::Classification::Type::PENALIZED_ATT)
|
||||
class_rows[i].effect->setCurrentIndex(0);
|
||||
else if (eff == CGAL::Classification::Type::NEUTRAL_ATT)
|
||||
class_rows[i].effect->setCurrentIndex(1);
|
||||
else
|
||||
class_rows[i].effect->setCurrentIndex(2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void on_attribute_weight_changed(int v)
|
||||
{
|
||||
Scene_point_set_classification_item* classification_item
|
||||
= get_classification_item();
|
||||
if(!classification_item)
|
||||
{
|
||||
print_message("Error: there is no point set classification item!");
|
||||
return;
|
||||
}
|
||||
Scene_point_set_classification_item::Attribute_handle
|
||||
att = classification_item->attribute(ui_widget.selected_attribute->currentIndex());
|
||||
|
||||
if (att == Scene_point_set_classification_item::Attribute_handle())
|
||||
return;
|
||||
|
||||
att->weight = std::tan ((CGAL_PI/2.) * v / 1001.);
|
||||
// std::cerr << att->weight << std::endl;
|
||||
|
||||
for (std::size_t i = 0; i < class_rows.size(); ++ i)
|
||||
class_rows[i].effect->setEnabled(att->weight != 0.);
|
||||
}
|
||||
|
||||
void on_effect_changed (int v)
|
||||
{
|
||||
Scene_point_set_classification_item* classification_item
|
||||
= get_classification_item();
|
||||
if(!classification_item)
|
||||
{
|
||||
print_message("Error: there is no point set classification item!");
|
||||
return;
|
||||
}
|
||||
Scene_point_set_classification_item::Attribute_handle
|
||||
att = classification_item->attribute(ui_widget.selected_attribute->currentIndex());
|
||||
|
||||
if (att == Scene_point_set_classification_item::Attribute_handle())
|
||||
return;
|
||||
|
||||
QComboBox* combo = qobject_cast<QComboBox*>(QObject::sender());
|
||||
for (std::size_t i = 0;i < class_rows.size(); ++ i)
|
||||
if (class_rows[i].effect == combo)
|
||||
{
|
||||
// std::cerr << att->id() << " is ";
|
||||
if (v == 0)
|
||||
{
|
||||
classification_item->types()[i].first->set_attribute_effect
|
||||
(att, CGAL::Classification::Type::PENALIZED_ATT);
|
||||
// std::cerr << " penalized for ";
|
||||
}
|
||||
else if (v == 1)
|
||||
{
|
||||
classification_item->types()[i].first->set_attribute_effect
|
||||
(att, CGAL::Classification::Type::NEUTRAL_ATT);
|
||||
// std::cerr << " neutral for ";
|
||||
}
|
||||
else
|
||||
{
|
||||
classification_item->types()[i].first->set_attribute_effect
|
||||
(att, CGAL::Classification::Type::FAVORED_ATT);
|
||||
// std::cerr << " favored for ";
|
||||
}
|
||||
// std::cerr << classification_item->types()[i].first->id() << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Messages_interface* messages;
|
||||
QAction* actionPointSetClassification;
|
||||
|
||||
QDockWidget* dock_widget;
|
||||
|
||||
std::vector<ClassRow> class_rows;
|
||||
|
||||
Ui::PointSetClassification ui_widget;
|
||||
|
||||
QColor color_att;
|
||||
|
||||
typedef std::map<Scene_points_with_normal_item*, Scene_point_set_classification_item*> Item_map;
|
||||
Item_map item_map;
|
||||
|
||||
}; // end Polyhedron_demo_point_set_classification_plugin
|
||||
|
||||
#include "Point_set_classification_plugin.moc"
|
||||
|
|
@ -0,0 +1,722 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>PointSetClassification</class>
|
||||
<widget class="QDockWidget" name="PointSetClassification">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>630</width>
|
||||
<height>960</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Point set classification</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="dockWidgetContents">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<spacer name="verticalSpacer_12">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||
<item>
|
||||
<widget class="QPushButton" name="create_from_item">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Create classification item</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="load_config">
|
||||
<property name="text">
|
||||
<string>Load config</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="save_config">
|
||||
<property name="text">
|
||||
<string>Save config</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||
<item>
|
||||
<widget class="QPushButton" name="compute_features">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Compute features</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="numberOfScalesSpinBox">
|
||||
<property name="suffix">
|
||||
<string> scale(s)</string>
|
||||
</property>
|
||||
<property name="prefix">
|
||||
<string>using </string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>5</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>View:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="display">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Real colors</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Classification</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Training sets</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::NoContextMenu</enum>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab_classif">
|
||||
<attribute name="title">
|
||||
<string>Classification</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<spacer name="verticalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Classes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="frame_2">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_12">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetDefaultConstraint</enum>
|
||||
</property>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Color</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Training set</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Name</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="5">
|
||||
<widget class="QPushButton" name="add_new_class">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Add new</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="4">
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_5">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>Training</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="frame_3">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="1" column="0">
|
||||
<widget class="QPushButton" name="train">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Train</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="number_of_trials">
|
||||
<property name="suffix">
|
||||
<string> trials</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1000000000</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>300</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QPushButton" name="reset_training_sets">
|
||||
<property name="text">
|
||||
<string>Reset training sets</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QPushButton" name="validate_selection">
|
||||
<property name="text">
|
||||
<string>Validate selection for training</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_11">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_advanced">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<attribute name="title">
|
||||
<string>Advanced</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4" stretch="0,2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Attribute:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="selected_attribute">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_10">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="attribute_weight">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1000</number>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<number>50</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>500</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="invertedAppearance">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="invertedControls">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="tickPosition">
|
||||
<enum>QSlider::TicksBothSides</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_7">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="1">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Class type</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Effect</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<spacer name="horizontalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_9">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_8">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>41</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QPushButton" name="run">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>50</weight>
|
||||
<bold>false</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Run (quick)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="run_smoothed">
|
||||
<property name="text">
|
||||
<string>Run (smoothed)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="frame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_10">
|
||||
<item>
|
||||
<widget class="QPushButton" name="run_graphcut">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>50</weight>
|
||||
<bold>false</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Run (graphcut)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="smoothingDoubleSpinBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Smoothing strenght</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>10.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.500000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_6">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QPushButton" name="save">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Save classified point set</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="generate_point_set_items">
|
||||
<property name="text">
|
||||
<string>Generate point set items</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_14">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
@ -406,6 +406,7 @@ protected:
|
|||
(points->begin() + unselected.size());
|
||||
}
|
||||
point_set_item->invalidateOpenGLBuffers();
|
||||
point_set_item->itemChanged();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,547 @@
|
|||
#include "Scene_point_set_classification_item.h"
|
||||
#include "Color_ramp.h"
|
||||
|
||||
#include <CGAL/Timer.h>
|
||||
#include <CGAL/Memory_sizer.h>
|
||||
|
||||
#include <CGAL/Three/Viewer_interface.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QMenu>
|
||||
#include <QGLViewer/manipulatedCameraFrame.h>
|
||||
|
||||
#include <set>
|
||||
#include <stack>
|
||||
#include <algorithm>
|
||||
#include <boost/array.hpp>
|
||||
|
||||
Scene_point_set_classification_item::Scene_point_set_classification_item(PSC* psc)
|
||||
: Scene_item(NbOfVbos,NbOfVaos),
|
||||
m_points (NULL),
|
||||
m_psc (psc),
|
||||
m_helper (NULL)
|
||||
{
|
||||
setRenderingMode(PointsPlusNormals);
|
||||
m_nb_scales = 5;
|
||||
m_nb_trials = 300;
|
||||
m_smoothing = 0.5;
|
||||
m_index_color = 1;
|
||||
is_selected = true;
|
||||
nb_points = 0;
|
||||
nb_lines = 0;
|
||||
}
|
||||
|
||||
Scene_point_set_classification_item::Scene_point_set_classification_item(Scene_points_with_normal_item* points)
|
||||
: Scene_item(NbOfVbos,NbOfVaos),
|
||||
m_points (points),
|
||||
m_psc (NULL),
|
||||
m_helper (NULL)
|
||||
{
|
||||
setRenderingMode(PointsPlusNormals);
|
||||
m_nb_scales = 5;
|
||||
m_index_color = 1;
|
||||
m_nb_trials = 300;
|
||||
m_smoothing = 0.5;
|
||||
|
||||
reset_indices();
|
||||
|
||||
m_psc = new PSC(m_points->point_set()->begin(), m_points->point_set()->end(), m_points->point_set()->point_map());
|
||||
|
||||
Type_handle ground = m_psc->add_classification_type("ground");
|
||||
Type_handle vegetation = m_psc->add_classification_type("vegetation");
|
||||
Type_handle roof = m_psc->add_classification_type("roof");
|
||||
Type_handle facade = m_psc->add_classification_type("facade");
|
||||
m_types.push_back (std::make_pair(ground, QColor(245, 180, 0)));
|
||||
m_types.push_back (std::make_pair(vegetation, QColor(0, 255, 27)));
|
||||
m_types.push_back (std::make_pair(roof, QColor(255, 0, 170)));
|
||||
m_types.push_back (std::make_pair(facade, QColor(100, 0, 255)));
|
||||
|
||||
is_selected = true;
|
||||
nb_points = 0;
|
||||
nb_lines = 0;
|
||||
}
|
||||
|
||||
|
||||
// Copy constructor
|
||||
Scene_point_set_classification_item::Scene_point_set_classification_item(const Scene_point_set_classification_item&)
|
||||
:Scene_item(NbOfVbos,NbOfVaos), // do not call superclass' copy constructor
|
||||
m_points (NULL),
|
||||
m_psc (NULL),
|
||||
m_helper (NULL)
|
||||
{
|
||||
setRenderingMode(PointsPlusNormals);
|
||||
m_nb_scales = 5;
|
||||
m_index_color = 1;
|
||||
m_nb_trials = 300;
|
||||
m_smoothing = 0.5;
|
||||
|
||||
nb_points = 0;
|
||||
invalidateOpenGLBuffers();
|
||||
}
|
||||
|
||||
Scene_point_set_classification_item::~Scene_point_set_classification_item()
|
||||
{
|
||||
if (m_psc != NULL)
|
||||
delete m_psc;
|
||||
if (m_helper != NULL)
|
||||
delete m_helper;
|
||||
}
|
||||
|
||||
void Scene_point_set_classification_item::initializeBuffers(CGAL::Three::Viewer_interface *viewer) const
|
||||
{
|
||||
compute_normals_and_vertices();
|
||||
//vao for the edges
|
||||
{
|
||||
program = getShaderProgram(PROGRAM_NO_SELECTION, viewer);
|
||||
program->bind();
|
||||
|
||||
vaos[Edges]->bind();
|
||||
buffers[Edges_vertices].bind();
|
||||
buffers[Edges_vertices].allocate(positions_lines.data(),
|
||||
static_cast<int>(positions_lines.size()*sizeof(double)));
|
||||
program->enableAttributeArray("vertex");
|
||||
program->setAttributeBuffer("vertex",GL_DOUBLE,0,3);
|
||||
buffers[Edges_vertices].release();
|
||||
|
||||
vaos[Edges]->release();
|
||||
nb_lines = positions_lines.size();
|
||||
positions_lines.resize(0);
|
||||
std::vector<double>(positions_lines).swap(positions_lines);
|
||||
program->release();
|
||||
}
|
||||
//vao for the points
|
||||
{
|
||||
program = getShaderProgram(PROGRAM_NO_SELECTION, viewer);
|
||||
program->bind();
|
||||
|
||||
vaos[ThePoints]->bind();
|
||||
buffers[Points_vertices].bind();
|
||||
buffers[Points_vertices].allocate(positions_points.data(),
|
||||
static_cast<int>(positions_points.size()*sizeof(double)));
|
||||
program->enableAttributeArray("vertex");
|
||||
program->setAttributeBuffer("vertex",GL_DOUBLE,0,3);
|
||||
buffers[Points_vertices].release();
|
||||
if (!(colors_points.empty()))
|
||||
{
|
||||
buffers[Points_colors].bind();
|
||||
buffers[Points_colors].allocate (colors_points.data(),
|
||||
static_cast<int>(colors_points.size()*sizeof(double)));
|
||||
program->enableAttributeArray("colors");
|
||||
program->setAttributeBuffer("colors",GL_DOUBLE,0,3);
|
||||
buffers[Points_colors].release();
|
||||
std::vector<double>(colors_points).swap(colors_points);
|
||||
}
|
||||
|
||||
vaos[ThePoints]->release();
|
||||
nb_points = positions_points.size();
|
||||
positions_points.resize(0);
|
||||
std::vector<double>(positions_points).swap(positions_points);
|
||||
program->release();
|
||||
}
|
||||
are_buffers_filled = true;
|
||||
}
|
||||
|
||||
void Scene_point_set_classification_item::compute_normals_and_vertices() const
|
||||
{
|
||||
int index_color = real_index_color();
|
||||
|
||||
positions_lines.resize(0);
|
||||
positions_points.resize(0);
|
||||
colors_points.resize(0);
|
||||
if (index_color == 9) // Show clusters centroids
|
||||
{
|
||||
// positions_points.reserve(m_psc->clusters().size() * 3);
|
||||
// colors_points.reserve(m_psc->clusters().size() * 3);
|
||||
|
||||
// for (std::size_t i = 0; i < m_psc->clusters().size(); ++ i)
|
||||
// {
|
||||
// const Kernel::Point_3& p = m_psc->clusters()[i].centroid;
|
||||
// positions_points.push_back(p.x());
|
||||
// positions_points.push_back(p.y());
|
||||
// positions_points.push_back(p.z());
|
||||
|
||||
// for (std::set<std::size_t>::iterator it = m_psc->clusters()[i].neighbors.begin ();
|
||||
// it != m_psc->clusters()[i].neighbors.end (); ++ it)
|
||||
// {
|
||||
// const Kernel::Point_3& q = m_psc->clusters()[*it].centroid;
|
||||
// positions_lines.push_back(p.x());
|
||||
// positions_lines.push_back(p.y());
|
||||
// positions_lines.push_back(p.z());
|
||||
|
||||
// positions_lines.push_back(q.x());
|
||||
// positions_lines.push_back(q.y());
|
||||
// positions_lines.push_back(q.z());
|
||||
// }
|
||||
// }
|
||||
}
|
||||
else // Show points
|
||||
{
|
||||
positions_points.reserve(m_points->point_set()->size() * 3);
|
||||
colors_points.reserve(m_points->point_set()->size() * 3);
|
||||
|
||||
for (Point_set::const_iterator it = m_points->point_set()->begin();
|
||||
it != m_points->point_set()->end(); ++ it)
|
||||
{
|
||||
const Kernel::Point_3& p = m_points->point_set()->point(*it);
|
||||
positions_points.push_back(p.x());
|
||||
positions_points.push_back(p.y());
|
||||
positions_points.push_back(p.z());
|
||||
}
|
||||
}
|
||||
|
||||
// Colors
|
||||
static Color_ramp ramp;
|
||||
ramp.build_red();
|
||||
|
||||
if (index_color == -1) // item color
|
||||
{
|
||||
|
||||
for (Point_set::const_iterator it = m_points->point_set()->begin();
|
||||
it != m_points->point_set()->first_selected(); ++ it)
|
||||
{
|
||||
colors_points.push_back (color().redF());
|
||||
colors_points.push_back (color().greenF());
|
||||
colors_points.push_back (color().blueF());
|
||||
}
|
||||
}
|
||||
else if (index_color == 0) // real colors
|
||||
{
|
||||
|
||||
for (Point_set::const_iterator it = m_points->point_set()->begin();
|
||||
it != m_points->point_set()->first_selected(); ++ it)
|
||||
{
|
||||
colors_points.push_back ((double)(m_points->point_set()->red(*it)) / 255.);
|
||||
colors_points.push_back ((double)(m_points->point_set()->green(*it)) / 255.);
|
||||
colors_points.push_back ((double)(m_points->point_set()->blue(*it)) / 255.);
|
||||
}
|
||||
}
|
||||
else if (index_color == 1) // classif
|
||||
{
|
||||
std::map<Type_handle, QColor> map_colors;
|
||||
for (std::size_t i = 0; i < m_types.size(); ++ i)
|
||||
map_colors.insert (m_types[i]);
|
||||
|
||||
for (Point_set::const_iterator it = m_points->point_set()->begin();
|
||||
it != m_points->point_set()->first_selected(); ++ it)
|
||||
{
|
||||
QColor color (0, 0, 0);
|
||||
Type_handle c = m_psc->classification_type_of(*it);
|
||||
|
||||
if (c != Type_handle())
|
||||
color = map_colors[c];
|
||||
|
||||
colors_points.push_back ((double)(color.red()) / 255.);
|
||||
colors_points.push_back ((double)(color.green()) / 255.);
|
||||
colors_points.push_back ((double)(color.blue()) / 255.);
|
||||
}
|
||||
}
|
||||
else if (index_color == 2) // training
|
||||
{
|
||||
std::map<Type_handle, QColor> map_colors;
|
||||
for (std::size_t i = 0; i < m_types.size(); ++ i)
|
||||
map_colors.insert (m_types[i]);
|
||||
|
||||
for (Point_set::const_iterator it = m_points->point_set()->begin();
|
||||
it != m_points->point_set()->first_selected(); ++ it)
|
||||
{
|
||||
QColor color (0, 0, 0);
|
||||
Type_handle c = m_psc->training_type_of(*it);
|
||||
Type_handle c2 = m_psc->classification_type_of(*it);
|
||||
|
||||
if (c != Type_handle())
|
||||
color = map_colors[c];
|
||||
double div = 255.;
|
||||
if (c != c2)
|
||||
div = 400.;
|
||||
|
||||
colors_points.push_back ((double)(color.red()) / div);
|
||||
colors_points.push_back ((double)(color.green()) / div);
|
||||
colors_points.push_back ((double)(color.blue()) / div);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Attribute_handle att = m_psc->get_attribute(index_color - 3);
|
||||
double weight = att->weight;
|
||||
att->weight = att->max;
|
||||
for (Point_set::const_iterator it = m_points->point_set()->begin();
|
||||
it != m_points->point_set()->first_selected(); ++ it)
|
||||
{
|
||||
colors_points.push_back (ramp.r(att->normalized(*it)));
|
||||
colors_points.push_back (ramp.g(att->normalized(*it)));
|
||||
colors_points.push_back (ramp.b(att->normalized(*it)));
|
||||
}
|
||||
att->weight = weight;
|
||||
}
|
||||
|
||||
for (Point_set::const_iterator it = m_points->point_set()->first_selected();
|
||||
it != m_points->point_set()->end(); ++ it)
|
||||
{
|
||||
colors_points.push_back (1.);
|
||||
colors_points.push_back (0.);
|
||||
colors_points.push_back (0.);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Duplicates scene item
|
||||
Scene_point_set_classification_item*
|
||||
Scene_point_set_classification_item::clone() const
|
||||
{
|
||||
return new Scene_point_set_classification_item(*this);
|
||||
}
|
||||
|
||||
// Write point set to .PLY file
|
||||
bool Scene_point_set_classification_item::write_ply_point_set(std::ostream& stream)
|
||||
{
|
||||
if (m_helper == NULL)
|
||||
return false;
|
||||
|
||||
stream.precision (std::numeric_limits<double>::digits10 + 2);
|
||||
|
||||
reset_indices();
|
||||
|
||||
std::vector<Color> colors;
|
||||
for (std::size_t i = 0; i < m_types.size(); ++ i)
|
||||
{
|
||||
Color c = {{ (unsigned char)(m_types[i].second.red()),
|
||||
(unsigned char)(m_types[i].second.green()),
|
||||
(unsigned char)(m_types[i].second.blue()) }};
|
||||
colors.push_back (c);
|
||||
}
|
||||
|
||||
m_helper->write_ply (stream,
|
||||
m_points->point_set()->begin(),
|
||||
m_points->point_set()->end(),
|
||||
m_points->point_set()->point_map(),
|
||||
*m_psc,
|
||||
&colors);
|
||||
return true;
|
||||
}
|
||||
|
||||
QString
|
||||
Scene_point_set_classification_item::toolTip() const
|
||||
{
|
||||
return QObject::tr("<p><b>%1</b><br />"
|
||||
"<i>Point set classification</i></p>"
|
||||
"<p>Number of points: %2</p>")
|
||||
.arg(name())
|
||||
.arg(m_points->point_set()->size());
|
||||
}
|
||||
|
||||
bool Scene_point_set_classification_item::supportsRenderingMode(RenderingMode m) const
|
||||
{
|
||||
return m==PointsPlusNormals;
|
||||
|
||||
}
|
||||
|
||||
void Scene_point_set_classification_item::drawSplats(CGAL::Three::Viewer_interface*) const
|
||||
{
|
||||
}
|
||||
|
||||
void Scene_point_set_classification_item::drawEdges(CGAL::Three::Viewer_interface* viewer) const
|
||||
{
|
||||
if(!are_buffers_filled)
|
||||
initializeBuffers(viewer);
|
||||
vaos[Edges]->bind();
|
||||
program=getShaderProgram(PROGRAM_NO_SELECTION);
|
||||
attribBuffers(viewer,PROGRAM_NO_SELECTION);
|
||||
program->bind();
|
||||
program->setAttributeValue("colors", this->color());
|
||||
viewer->glDrawArrays(GL_LINES, 0,
|
||||
static_cast<GLsizei>((nb_lines)/3));
|
||||
vaos[Edges]->release();
|
||||
program->release();
|
||||
}
|
||||
|
||||
void Scene_point_set_classification_item::drawPoints(CGAL::Three::Viewer_interface* viewer) const
|
||||
{
|
||||
if(!are_buffers_filled)
|
||||
initializeBuffers(viewer);
|
||||
GLfloat point_size;
|
||||
viewer->glGetFloatv(GL_POINT_SIZE, &point_size);
|
||||
if (m_index_color == 9)
|
||||
viewer->glPointSize(15.f);
|
||||
else
|
||||
viewer->glPointSize(3.f);
|
||||
|
||||
vaos[ThePoints]->bind();
|
||||
program=getShaderProgram(PROGRAM_NO_SELECTION);
|
||||
attribBuffers(viewer,PROGRAM_NO_SELECTION);
|
||||
program->bind();
|
||||
if (colors_points.empty())
|
||||
program->setAttributeValue("colors", this->color());
|
||||
viewer->glDrawArrays(GL_POINTS, 0,
|
||||
static_cast<GLsizei>(((std::size_t)(nb_points)/3)));
|
||||
vaos[ThePoints]->release();
|
||||
program->release();
|
||||
viewer->glPointSize(point_size);
|
||||
}
|
||||
|
||||
bool
|
||||
Scene_point_set_classification_item::isEmpty() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
Scene_point_set_classification_item::compute_bbox() const
|
||||
{
|
||||
if (m_points->point_set()->empty())
|
||||
return;
|
||||
|
||||
double xmin = std::numeric_limits<double>::max();
|
||||
double ymin = std::numeric_limits<double>::max();
|
||||
double zmin = std::numeric_limits<double>::max();
|
||||
double xmax = -std::numeric_limits<double>::max();
|
||||
double ymax = -std::numeric_limits<double>::max();
|
||||
double zmax = -std::numeric_limits<double>::max();
|
||||
|
||||
for (Point_set::const_iterator it = m_points->point_set()->begin();
|
||||
it != m_points->point_set()->end(); ++ it)
|
||||
{
|
||||
const Kernel::Point_3& p = m_points->point_set()->point(*it);
|
||||
xmin = (std::min)(xmin, p.x());
|
||||
ymin = (std::min)(ymin, p.y());
|
||||
zmin = (std::min)(zmin, p.z());
|
||||
xmax = (std::max)(xmax, p.x());
|
||||
ymax = (std::max)(ymax, p.y());
|
||||
zmax = (std::max)(zmax, p.z());
|
||||
}
|
||||
|
||||
_bbox = Bbox(xmin,ymin,zmin,
|
||||
xmax,ymax,zmax);
|
||||
}
|
||||
|
||||
QMenu* Scene_point_set_classification_item::contextMenu()
|
||||
{
|
||||
QMenu* menu = Scene_item::contextMenu();
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
void Scene_point_set_classification_item::setRenderingMode(RenderingMode m)
|
||||
{
|
||||
Scene_item::setRenderingMode(m);
|
||||
}
|
||||
|
||||
void Scene_point_set_classification_item::invalidateOpenGLBuffers()
|
||||
{
|
||||
are_buffers_filled = false;
|
||||
compute_bbox();
|
||||
}
|
||||
|
||||
void Scene_point_set_classification_item::change_color (int index)
|
||||
{
|
||||
m_index_color = index;
|
||||
invalidateOpenGLBuffers();
|
||||
}
|
||||
|
||||
int Scene_point_set_classification_item::real_index_color() const
|
||||
{
|
||||
int out = m_index_color;
|
||||
|
||||
if (out == 0 && !(m_points->point_set()->has_colors()))
|
||||
out = -1;
|
||||
return out;
|
||||
}
|
||||
|
||||
void Scene_point_set_classification_item::reset_indices ()
|
||||
{
|
||||
Point_set::Property_map<Point_set::Index> indices;
|
||||
|
||||
boost::tie (indices, boost::tuples::ignore)
|
||||
= m_points->point_set()->property_map<Point_set::Index>("index");
|
||||
|
||||
m_points->point_set()->unselect_all();
|
||||
Point_set::Index idx;
|
||||
++ idx;
|
||||
for (std::size_t i = 0; i < m_points->point_set()->size(); ++ i)
|
||||
*(indices.begin() + i) = idx ++;
|
||||
}
|
||||
|
||||
void Scene_point_set_classification_item::compute_features ()
|
||||
{
|
||||
Q_ASSERT (!(m_points->point_set()->empty()));
|
||||
Q_ASSERT (m_psc != NULL);
|
||||
m_psc->clear_attributes();
|
||||
reset_indices();
|
||||
|
||||
std::cerr << "Computing features with " << m_nb_scales << " scale(s)" << std::endl;
|
||||
compute_bbox();
|
||||
if (m_helper != NULL) delete m_helper;
|
||||
|
||||
|
||||
m_helper = new Helper (m_points->point_set()->begin(),
|
||||
m_points->point_set()->end(),
|
||||
m_points->point_set()->point_map(),
|
||||
m_nb_scales);
|
||||
|
||||
m_helper->generate_point_based_attributes (*m_psc,
|
||||
m_points->point_set()->begin(),
|
||||
m_points->point_set()->end(),
|
||||
m_points->point_set()->point_map());
|
||||
|
||||
if (m_points->point_set()->has_normal_map())
|
||||
m_helper->generate_normal_based_attributes (*m_psc,
|
||||
m_points->point_set()->begin(),
|
||||
m_points->point_set()->end(),
|
||||
m_points->point_set()->normal_map());
|
||||
else
|
||||
m_helper->generate_normal_based_attributes (*m_psc,
|
||||
m_points->point_set()->begin(),
|
||||
m_points->point_set()->end());
|
||||
|
||||
Point_set::Property_map<boost::uint8_t> echo_map;
|
||||
bool okay;
|
||||
boost::tie (echo_map, okay) = m_points->point_set()->template property_map<boost::uint8_t>("echo");
|
||||
if (okay)
|
||||
m_helper->generate_echo_based_attributes (*m_psc,
|
||||
m_points->point_set()->begin(),
|
||||
m_points->point_set()->end(),
|
||||
echo_map);
|
||||
|
||||
if (m_points->point_set()->has_colors())
|
||||
m_helper->generate_color_based_attributes (*m_psc,
|
||||
m_points->point_set()->begin(),
|
||||
m_points->point_set()->end(),
|
||||
Color_map(m_points->point_set()));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Scene_point_set_classification_item::train()
|
||||
{
|
||||
if (m_helper == NULL)
|
||||
{
|
||||
std::cerr << "Error: features not computed" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
m_psc->training(m_nb_trials);
|
||||
m_psc->run();
|
||||
m_helper->info();
|
||||
|
||||
}
|
||||
|
||||
bool Scene_point_set_classification_item::run (int method)
|
||||
{
|
||||
if (m_helper == NULL)
|
||||
{
|
||||
std::cerr << "Error: features not computed" << std::endl;
|
||||
return false;
|
||||
}
|
||||
reset_indices();
|
||||
|
||||
if (method == 0)
|
||||
m_psc->run();
|
||||
else if (method == 1)
|
||||
m_psc->run_with_local_smoothing (m_helper->neighborhood().range_neighbor_query(m_helper->radius_neighbors()));
|
||||
else if (method == 2)
|
||||
m_psc->run_with_graphcut (m_helper->neighborhood().k_neighbor_query(12), m_smoothing);
|
||||
invalidateOpenGLBuffers();
|
||||
Q_EMIT itemChanged();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -0,0 +1,405 @@
|
|||
#ifndef POINT_SET_CLASSIFICATION_ITEM_H
|
||||
#define POINT_SET_CLASSIFICATION_ITEM_H
|
||||
|
||||
#include <CGAL/Three/Scene_item.h>
|
||||
#include <CGAL/Classifier.h>
|
||||
#include <CGAL/Classification/Attribute.h>
|
||||
#include <CGAL/Classification/Attribute_vertical_dispersion.h>
|
||||
#include <CGAL/Classification/Attribute_elevation.h>
|
||||
#include <CGAL/Classification/Attribute_verticality.h>
|
||||
#include <CGAL/Classification/Attribute_distance_to_plane.h>
|
||||
#include <CGAL/Classification/Attribute_color.h>
|
||||
#include <CGAL/Classification/Attribute_echo_scatter.h>
|
||||
#include <CGAL/Classification/Attributes_eigen.h>
|
||||
#include <CGAL/Classification/Helper.h>
|
||||
|
||||
#include "Scene_point_set_classification_item_config.h"
|
||||
#include "Scene_points_with_normal_item.h"
|
||||
#include "Polyhedron_type_fwd.h"
|
||||
#include "Kernel_type.h"
|
||||
#include "Point_set_3.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
||||
class QMenu;
|
||||
class QAction;
|
||||
|
||||
// This class represents a point set in the OpenGL scene
|
||||
class SCENE_POINT_SET_CLASSIFICATION_ITEM_EXPORT Scene_point_set_classification_item
|
||||
: public CGAL::Three::Scene_item
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
template <typename PointSet>
|
||||
class Point_set_color_map
|
||||
{
|
||||
public:
|
||||
typedef CGAL::Classification::RGB_Color Color;
|
||||
typedef typename PointSet::Index key_type;
|
||||
typedef Color value_type;
|
||||
typedef value_type& reference;
|
||||
typedef boost::lvalue_property_map_tag category;
|
||||
|
||||
PointSet* ps;
|
||||
|
||||
Point_set_color_map(PointSet* ps = NULL)
|
||||
: ps(ps) { }
|
||||
|
||||
friend value_type get (const Point_set_color_map& pm, const key_type& i)
|
||||
{
|
||||
Color out = {{ pm.ps->red(i),
|
||||
pm.ps->green(i),
|
||||
pm.ps->blue(i) }};
|
||||
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
typedef Kernel::Point_3 Point_3;
|
||||
typedef Kernel::Vector_3 Vector_3;
|
||||
typedef CGAL::Classification::RGB_Color Color;
|
||||
|
||||
typedef Point_set::iterator Iterator;
|
||||
typedef Point_set::Point_map Point_map;
|
||||
typedef Point_set::Vector_map Vector_map;
|
||||
typedef Point_set_color_map<Point_set> Color_map;
|
||||
|
||||
typedef CGAL::Classifier<Iterator, Point_map> PSC;
|
||||
typedef CGAL::Classification::Helper<Kernel, Iterator, Point_map> Helper;
|
||||
typedef CGAL::Classification::Type_handle Type_handle;
|
||||
typedef CGAL::Classification::Attribute_handle Attribute_handle;
|
||||
typedef CGAL::Classification::Attribute_vertical_dispersion<Kernel, Iterator, Point_map> Dispersion;
|
||||
typedef CGAL::Classification::Attribute_elevation<Kernel, Iterator, Point_map> Elevation;
|
||||
typedef CGAL::Classification::Attribute_verticality<Kernel, Iterator, Point_map> Verticality;
|
||||
typedef CGAL::Classification::Attribute_distance_to_plane<Kernel, Iterator, Point_map> Distance_to_plane;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
Scene_point_set_classification_item(PSC* psc = NULL);
|
||||
Scene_point_set_classification_item(Scene_points_with_normal_item* points);
|
||||
Scene_point_set_classification_item(const Scene_point_set_classification_item& toCopy);
|
||||
~Scene_point_set_classification_item();
|
||||
|
||||
Scene_point_set_classification_item* clone() const;
|
||||
|
||||
// Function to override the context menu
|
||||
QMenu* contextMenu();
|
||||
|
||||
// IO
|
||||
bool write_ply_point_set(std::ostream& out);
|
||||
// Function for displaying meta-data of the item
|
||||
virtual QString toolTip() const;
|
||||
|
||||
virtual void invalidateOpenGLBuffers();
|
||||
|
||||
// Indicate if rendering mode is supported
|
||||
virtual bool supportsRenderingMode(RenderingMode m) const;
|
||||
|
||||
virtual void drawEdges(CGAL::Three::Viewer_interface* viewer) const;
|
||||
virtual void drawPoints(CGAL::Three::Viewer_interface*) const;
|
||||
virtual void drawSplats(CGAL::Three::Viewer_interface*) const;
|
||||
|
||||
|
||||
// Gets dimensions
|
||||
virtual bool isFinite() const { return true; }
|
||||
virtual bool isEmpty() const;
|
||||
virtual void compute_bbox() const;
|
||||
|
||||
virtual void setRenderingMode(RenderingMode m);
|
||||
|
||||
void change_color (int index);
|
||||
int real_index_color() const;
|
||||
|
||||
void reset_indices();
|
||||
void compute_features ();
|
||||
bool run (int method);
|
||||
|
||||
template <typename Item>
|
||||
void generate_point_set_items(std::vector<Item*>& items,
|
||||
const char* name)
|
||||
{
|
||||
std::map<Type_handle, std::size_t> map_types;
|
||||
for (std::size_t i = 0; i < m_types.size(); ++ i)
|
||||
{
|
||||
items.push_back (new Item);
|
||||
items.back()->setName (QString("%1 (%2)").arg(name).arg(m_types[i].first->id().c_str()));
|
||||
items.back()->setColor (m_types[i].second);
|
||||
map_types[m_types[i].first] = i;
|
||||
}
|
||||
|
||||
for (Point_set::const_iterator it = m_points->point_set()->begin();
|
||||
it != m_points->point_set()->end(); ++ it)
|
||||
{
|
||||
Type_handle c = m_psc->classification_type_of(*it);
|
||||
if (c != Type_handle())
|
||||
items[map_types[c]]->point_set()->insert (m_points->point_set()->point(*it));
|
||||
}
|
||||
}
|
||||
|
||||
Scene_points_with_normal_item* points_item() { return m_points; }
|
||||
|
||||
void reset_training_sets()
|
||||
{
|
||||
m_psc->prepare_classification();
|
||||
m_psc->reset_training_sets();
|
||||
invalidateOpenGLBuffers();
|
||||
Q_EMIT itemChanged();
|
||||
}
|
||||
|
||||
void train();
|
||||
|
||||
void callback()
|
||||
{
|
||||
invalidateOpenGLBuffers();
|
||||
Q_EMIT itemChanged();
|
||||
}
|
||||
|
||||
|
||||
Type_handle get_classification_type (const char* name)
|
||||
{
|
||||
for (std::size_t i = 0; i < m_types.size(); ++ i)
|
||||
if (m_types[i].first->id() == name)
|
||||
return m_types[i].first;
|
||||
return Type_handle();
|
||||
}
|
||||
|
||||
void add_selection_to_training_set (const char* name)
|
||||
{
|
||||
Type_handle class_type = get_classification_type (name);
|
||||
|
||||
if (!(m_psc->classification_prepared()))
|
||||
m_psc->prepare_classification();
|
||||
|
||||
for (Point_set::const_iterator it = m_points->point_set()->first_selected();
|
||||
it != m_points->point_set()->end(); ++ it)
|
||||
m_psc->set_classification_type_of(*it, class_type);
|
||||
|
||||
m_psc->add_training_set(class_type,
|
||||
m_points->point_set()->first_selected(),
|
||||
m_points->point_set()->end());
|
||||
m_points->resetSelection();
|
||||
}
|
||||
|
||||
void validate_selection ()
|
||||
{
|
||||
if (!(m_psc->classification_prepared()))
|
||||
m_psc->prepare_classification();
|
||||
|
||||
for (Point_set::const_iterator it = m_points->point_set()->first_selected();
|
||||
it != m_points->point_set()->end(); ++ it)
|
||||
{
|
||||
Type_handle t = m_psc->classification_type_of(*it);
|
||||
m_psc->add_training_index (t, *it);
|
||||
}
|
||||
|
||||
m_points->resetSelection();
|
||||
}
|
||||
|
||||
double& smoothing() { return m_smoothing; }
|
||||
std::size_t& nb_scales() { return m_nb_scales; }
|
||||
std::size_t& number_of_trials() { return m_nb_trials; }
|
||||
bool features_computed() const { return (m_helper != NULL); }
|
||||
|
||||
std::vector<std::pair<Type_handle, QColor> >& types() { return m_types; }
|
||||
std::size_t number_of_attributes() const { return m_psc->number_of_attributes(); }
|
||||
Attribute_handle attribute(std::size_t i) { return m_psc->get_attribute(i); }
|
||||
void add_new_type (const char* name, const QColor& color)
|
||||
{
|
||||
m_types.push_back (std::make_pair (m_psc->add_classification_type(name),
|
||||
color));
|
||||
}
|
||||
|
||||
void remove_type (const char* name)
|
||||
{
|
||||
for (std::size_t i = 0; i < m_types.size(); ++ i)
|
||||
if (m_types[i].first->id() == name)
|
||||
{
|
||||
m_psc->remove_classification_type (m_types[i].first);
|
||||
m_types.erase (m_types.begin() + i);
|
||||
break;
|
||||
}
|
||||
invalidateOpenGLBuffers();
|
||||
Q_EMIT itemChanged();
|
||||
}
|
||||
|
||||
void change_type_color (const char* name, const QColor& color)
|
||||
{
|
||||
for (std::size_t i = 0; i < m_types.size(); ++ i)
|
||||
if (m_types[i].first->id() == name)
|
||||
{
|
||||
m_types[i].second = color;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ComboBox>
|
||||
void fill_display_combo_box (ComboBox* cb, ComboBox* cb1)
|
||||
{
|
||||
for (std::size_t i = 0; i < m_psc->number_of_attributes(); ++ i)
|
||||
{
|
||||
std::size_t scale = m_helper->scale_of_attribute(m_psc->get_attribute(i));
|
||||
std::ostringstream oss;
|
||||
oss << "Attribute " << m_psc->get_attribute(i)->id() << "_" << scale;
|
||||
cb->addItem (oss.str().c_str());
|
||||
cb1->addItem (oss.str().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void save_config(const char* filename)
|
||||
{
|
||||
if (m_helper == NULL)
|
||||
{
|
||||
std::cerr << "Error: features not computed" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
m_helper->save (filename, *m_psc);
|
||||
}
|
||||
|
||||
void load_config(const char* filename)
|
||||
{
|
||||
if (m_helper != NULL)
|
||||
delete m_helper;
|
||||
|
||||
m_psc->clear_classification_types();
|
||||
m_psc->clear_attributes();
|
||||
reset_indices();
|
||||
|
||||
bool normals = m_points->point_set()->has_normal_map();
|
||||
bool colors = m_points->point_set()->has_colors();
|
||||
Point_set::Property_map<boost::uint8_t> echo_map;
|
||||
bool echo;
|
||||
boost::tie (echo_map, echo) = m_points->point_set()->template property_map<boost::uint8_t>("echo");
|
||||
|
||||
if (!normals && !colors && !echo)
|
||||
m_helper = new Helper (filename, *m_psc,
|
||||
m_points->point_set()->begin(),
|
||||
m_points->point_set()->end(),
|
||||
m_points->point_set()->point_map());
|
||||
else if (!normals && !colors && echo)
|
||||
m_helper = new Helper (filename, *m_psc,
|
||||
m_points->point_set()->begin(),
|
||||
m_points->point_set()->end(),
|
||||
m_points->point_set()->point_map(),
|
||||
CGAL::Empty_property_map<Iterator, Vector_3>(),
|
||||
CGAL::Empty_property_map<Iterator, Color>(),
|
||||
echo_map);
|
||||
else if (!normals && colors && !echo)
|
||||
m_helper = new Helper (filename, *m_psc,
|
||||
m_points->point_set()->begin(),
|
||||
m_points->point_set()->end(),
|
||||
m_points->point_set()->point_map(),
|
||||
CGAL::Empty_property_map<Iterator, Vector_3>(),
|
||||
Color_map(m_points->point_set()));
|
||||
else if (!normals && colors && echo)
|
||||
m_helper = new Helper (filename, *m_psc,
|
||||
m_points->point_set()->begin(),
|
||||
m_points->point_set()->end(),
|
||||
m_points->point_set()->point_map(),
|
||||
CGAL::Empty_property_map<Iterator, Vector_3>(),
|
||||
Color_map(m_points->point_set()),
|
||||
echo_map);
|
||||
else if (normals && !colors && !echo)
|
||||
m_helper = new Helper (filename, *m_psc,
|
||||
m_points->point_set()->begin(),
|
||||
m_points->point_set()->end(),
|
||||
m_points->point_set()->point_map(),
|
||||
m_points->point_set()->normal_map());
|
||||
else if (normals && !colors && echo)
|
||||
m_helper = new Helper (filename, *m_psc,
|
||||
m_points->point_set()->begin(),
|
||||
m_points->point_set()->end(),
|
||||
m_points->point_set()->point_map(),
|
||||
m_points->point_set()->normal_map(),
|
||||
CGAL::Empty_property_map<Iterator, Color>(),
|
||||
echo_map);
|
||||
else if (normals && colors && !echo)
|
||||
m_helper = new Helper (filename, *m_psc,
|
||||
m_points->point_set()->begin(),
|
||||
m_points->point_set()->end(),
|
||||
m_points->point_set()->point_map(),
|
||||
m_points->point_set()->normal_map(),
|
||||
CGAL::Empty_property_map<Iterator, Color>());
|
||||
else
|
||||
m_helper = new Helper (filename, *m_psc,
|
||||
m_points->point_set()->begin(),
|
||||
m_points->point_set()->end(),
|
||||
m_points->point_set()->point_map(),
|
||||
m_points->point_set()->normal_map(),
|
||||
Color_map(m_points->point_set()),
|
||||
echo_map);
|
||||
|
||||
std::vector<std::pair<Type_handle, QColor> > new_types;
|
||||
for (std::size_t i = 0; i < m_psc->number_of_classification_types(); ++ i)
|
||||
{
|
||||
Type_handle t = m_psc->get_classification_type(i);
|
||||
QColor color (192 + rand() % 60,
|
||||
192 + rand() % 60,
|
||||
192 + rand() % 60);
|
||||
|
||||
for (std::size_t j = 0; j < m_types.size(); ++ j)
|
||||
if (t->id() == m_types[j].first->id())
|
||||
{
|
||||
color = m_types[j].second;
|
||||
break;
|
||||
}
|
||||
|
||||
new_types.push_back (std::make_pair (t, color));
|
||||
}
|
||||
m_types.swap (new_types);
|
||||
}
|
||||
|
||||
public Q_SLOTS:
|
||||
|
||||
// Data
|
||||
private:
|
||||
|
||||
Scene_points_with_normal_item* m_points;
|
||||
PSC* m_psc;
|
||||
Helper* m_helper;
|
||||
|
||||
std::size_t m_nb_scales;
|
||||
|
||||
std::vector<std::pair<Type_handle, QColor> > m_types;
|
||||
std::size_t m_nb_trials;
|
||||
double m_smoothing;
|
||||
|
||||
int m_index_color;
|
||||
|
||||
enum VAOs {
|
||||
Edges=0,
|
||||
ThePoints,
|
||||
NbOfVaos = ThePoints+1
|
||||
};
|
||||
enum VBOs {
|
||||
Edges_vertices = 0,
|
||||
Points_vertices,
|
||||
Points_colors,
|
||||
NbOfVbos = Points_colors+1
|
||||
};
|
||||
|
||||
mutable std::vector<double> positions_lines;
|
||||
mutable std::vector<double> positions_points;
|
||||
mutable std::vector<double> colors_points;
|
||||
mutable std::size_t nb_points;
|
||||
mutable std::size_t nb_lines;
|
||||
|
||||
|
||||
mutable QOpenGLShaderProgram *program;
|
||||
|
||||
using CGAL::Three::Scene_item::initializeBuffers;
|
||||
void initializeBuffers(CGAL::Three::Viewer_interface *viewer) const;
|
||||
|
||||
void compute_normals_and_vertices() const;
|
||||
|
||||
|
||||
}; // end class Scene_point_set_classification_item
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // POINT_SET_CLASSIFICATION_ITEM_H
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
#ifndef SCENE_POINT_SET_CLASSIFICATION_ITEM_CONFIG_H
|
||||
#define SCENE_POINT_SET_CLASSIFICATION_ITEM_CONFIG_H
|
||||
|
||||
#ifdef scene_point_set_classification_item_EXPORTS
|
||||
# define SCENE_POINT_SET_CLASSIFICATION_ITEM_EXPORT Q_DECL_EXPORT
|
||||
#else
|
||||
# define SCENE_POINT_SET_CLASSIFICATION_ITEM_EXPORT Q_DECL_IMPORT
|
||||
#endif
|
||||
|
||||
#endif // SCENE_POINT_SET_CLASSIFICATION_ITEM_CONFIG_H
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
#ifndef READ_LAS_POINT_SET_H
|
||||
#define READ_LAS_POINT_SET_H
|
||||
|
||||
#include <liblas/liblas.hpp>
|
||||
|
||||
template <typename Point, typename Vector>
|
||||
bool read_las_point_set(
|
||||
std::istream& stream, ///< input stream.
|
||||
CGAL::Point_set_3<Point, Vector>& point_set) ///< point set
|
||||
{
|
||||
typename CGAL::Point_set_3<Point, Vector> Point_set;
|
||||
|
||||
liblas::ReaderFactory f;
|
||||
liblas::Reader reader = f.CreateWithStream(stream);
|
||||
|
||||
Point_set::Property_map<unsigned char> echo_map;
|
||||
boost::tie(echo_map, boost::tuples::ignore)
|
||||
= point_set.template add_property_map<unsigned char>("echo", 0);
|
||||
|
||||
Point_set::Property_map<unsigned char> red_map;
|
||||
boost::tie(red_map, boost::tuples::ignore)
|
||||
= point_set.template add_property_map<unsigned char>("red", 0);
|
||||
|
||||
Point_set::Property_map<unsigned char> green_map;
|
||||
boost::tie(green_map, boost::tuples::ignore)
|
||||
= point_set.template add_property_map<unsigned char>("green", 0);
|
||||
|
||||
Point_set::Property_map<unsigned char> blue_map;
|
||||
boost::tie(blue_map, boost::tuples::ignore)
|
||||
= point_set.template add_property_map<unsigned char>("blue", 0);
|
||||
|
||||
unsigned int bit_short_to_char = 0;
|
||||
|
||||
while (reader.ReadNextPoint())
|
||||
{
|
||||
const liblas::Point& p = reader.GetPoint();
|
||||
Point_set::iterator it = point_set.insert (Kernel::Point_3 (p.GetX(), p.GetY(), p.GetZ()));
|
||||
put(echo_map, *it, p.GetReturnNumber());
|
||||
const liblas::Color& c = p.GetColor();
|
||||
if (bit_short_to_char == 0
|
||||
&& (c[0] > 255 || c[1] > 255 || c[2] > 255))
|
||||
{
|
||||
// if a value is above 255, shorts are used (that should be
|
||||
// default but not always the case, hence this test)
|
||||
bit_short_to_char = 8;
|
||||
for (Point_set::iterator it2 = point_set.begin(); it2 != it; ++ it2)
|
||||
{
|
||||
// Correct previously added values
|
||||
put(red_map, *it2, ((get(red_map, *it2)) >> 8));
|
||||
put(green_map, *it2, ((get(green_map, *it2)) >> 8));
|
||||
put(blue_map, *it2, ((get(blue_map, *it2)) >> 8));
|
||||
}
|
||||
}
|
||||
put(red_map, *it, (c.GetRed() >> bit_short_to_char));
|
||||
put(green_map, *it, (c.GetGreen() >> bit_short_to_char));
|
||||
put(blue_map, *it, (c.GetBlue() >> bit_short_to_char));
|
||||
}
|
||||
|
||||
bool remove_echo = true;
|
||||
bool remove_colors = true;
|
||||
|
||||
for (Point_set::iterator it = point_set.begin(); it != point_set.end(); ++ it)
|
||||
{
|
||||
if (get(echo_map, *it) != 0)
|
||||
remove_echo = false;
|
||||
if (get(red_map, *it) != 0 ||
|
||||
get(green_map, *it) != 0 ||
|
||||
get(blue_map, *it) != 0)
|
||||
remove_colors = false;
|
||||
if (!remove_echo && !remove_colors)
|
||||
break;
|
||||
}
|
||||
|
||||
if (remove_echo)
|
||||
point_set.remove_property_map(echo_map);
|
||||
if (remove_colors)
|
||||
{
|
||||
point_set.remove_property_map(red_map);
|
||||
point_set.remove_property_map(green_map);
|
||||
point_set.remove_property_map(blue_map);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#endif // READ_LAS_POINT_SET_H
|
||||
|
|
@ -348,6 +348,23 @@ make_property_map(const std::vector<T>& v)
|
|||
return make_property_map(&v[0]);
|
||||
}
|
||||
|
||||
/// Empty property map that only returns the default value type
|
||||
///
|
||||
/// \cgalModels `ReadablePropertyMap`
|
||||
///
|
||||
/// \endcond
|
||||
template<class InputIterator, class ValueType>
|
||||
struct Empty_property_map{
|
||||
typedef typename InputIterator::value_type key_type;
|
||||
typedef boost::readable_property_map_tag category;
|
||||
|
||||
/// Free function to use a get the value from an iterator using Input_iterator_property_map.
|
||||
inline friend ValueType
|
||||
get (const Empty_property_map&, const key_type&){ return ValueType(); }
|
||||
};
|
||||
|
||||
} // namespace CGAL
|
||||
|
||||
|
||||
|
||||
#endif // CGAL_POINT_SET_PROPERTY_MAP_H
|
||||
|
|
|
|||
|
|
@ -174,6 +174,59 @@ public:
|
|||
return is;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
class Input_rep<float> {
|
||||
float& t;
|
||||
public:
|
||||
//! initialize with a reference to \a t.
|
||||
Input_rep( float& tt) : t(tt) {}
|
||||
|
||||
std::istream& operator()( std::istream& is) const
|
||||
{
|
||||
typedef std::istream istream;
|
||||
typedef istream::char_type char_type;
|
||||
typedef istream::int_type int_type;
|
||||
typedef istream::traits_type traits_type;
|
||||
|
||||
std::string buffer;
|
||||
buffer.reserve(32);
|
||||
|
||||
char_type c;
|
||||
do {
|
||||
const int_type i = is.get();
|
||||
if(i == traits_type::eof()) {
|
||||
return is;
|
||||
}
|
||||
c = static_cast<char_type>(i);
|
||||
}while (std::isspace(c));
|
||||
if(c == '-'){
|
||||
buffer += '-';
|
||||
} else if(c != '+'){
|
||||
is.unget();
|
||||
}
|
||||
do {
|
||||
const int_type i = is.get();
|
||||
if(i == traits_type::eof()) {
|
||||
is.clear(is.rdstate() & ~std::ios_base::failbit);
|
||||
break;
|
||||
}
|
||||
c = static_cast<char_type>(i);
|
||||
if(std::isdigit(c) || (c =='.') || (c =='E') || (c =='e') || (c =='+') || (c =='-')){
|
||||
buffer += c;
|
||||
}else{
|
||||
is.unget();
|
||||
break;
|
||||
}
|
||||
}while(true);
|
||||
|
||||
if(sscanf(buffer.c_str(), "%f", &t) != 1) {
|
||||
// if a 'buffer' does not contain a double, set the fail bit.
|
||||
is.setstate(std::ios_base::failbit);
|
||||
}
|
||||
return is;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
/*! \relates Input_rep
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ int main(int /* argc */, char* argv[])
|
|||
Mesh sm;
|
||||
std::ifstream in(argv[1]);
|
||||
in >> sm;
|
||||
Mesh::Property_map<vertex_descriptor,vertex_descriptor> predecessor;
|
||||
CGAL::Properties::Property_map<vertex_descriptor,vertex_descriptor> predecessor;
|
||||
predecessor = sm.add_property_map<vertex_descriptor,vertex_descriptor>("v:predecessor").first;
|
||||
|
||||
boost::prim_minimum_spanning_tree(sm, predecessor, boost::root_vertex(*vertices(sm).first));
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ int main(int argc, char* argv[])
|
|||
|
||||
std::ifstream in2((argc>2)?argv[2]:"data/quad.off");
|
||||
|
||||
Mesh::Property_map<vertex_descriptor,std::string> name1, name2;
|
||||
CGAL::Properties::Property_map<vertex_descriptor,std::string> name1, name2;
|
||||
bool created;
|
||||
sm1.add_property_map<vertex_descriptor,int>("v:weight",7812);
|
||||
boost::tie(name1, created) = sm1.add_property_map<vertex_descriptor,std::string>("v:name","hello");
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ int main()
|
|||
}
|
||||
|
||||
// The status of being used or removed is stored in a property map
|
||||
Mesh::Property_map<Mesh::Vertex_index,bool> removed
|
||||
CGAL::Properties::Property_map<Mesh::Vertex_index,bool> removed
|
||||
= m.property_map<Mesh::Vertex_index,bool>("v:removed").first;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ int main()
|
|||
|
||||
|
||||
// give each vertex a name, the default is empty
|
||||
Mesh::Property_map<vertex_descriptor,std::string> name;
|
||||
CGAL::Properties::Property_map<vertex_descriptor,std::string> name;
|
||||
bool created;
|
||||
boost::tie(name, created) = m.add_property_map<vertex_descriptor,std::string>("v:name","");
|
||||
assert(created);
|
||||
|
|
@ -36,20 +36,20 @@ int main()
|
|||
|
||||
{
|
||||
// You get an existing property, and created will be false
|
||||
Mesh::Property_map<vertex_descriptor,std::string> name;
|
||||
CGAL::Properties::Property_map<vertex_descriptor,std::string> name;
|
||||
bool created;
|
||||
boost::tie(name, created) = m.add_property_map<vertex_descriptor,std::string>("v:name", "");
|
||||
assert(! created);
|
||||
}
|
||||
|
||||
// You can't get a property that does not exist
|
||||
Mesh::Property_map<face_descriptor,std::string> gnus;
|
||||
CGAL::Properties::Property_map<face_descriptor,std::string> gnus;
|
||||
bool found;
|
||||
boost::tie(gnus, found) = m.property_map<face_descriptor,std::string>("v:gnus");
|
||||
assert(! found);
|
||||
|
||||
// retrieve the point property for which exists a convenience function
|
||||
Mesh::Property_map<vertex_descriptor, K::Point_3> location = m.points();
|
||||
CGAL::Properties::Property_map<vertex_descriptor, K::Point_3> location = m.points();
|
||||
BOOST_FOREACH( vertex_descriptor vd, m.vertices()) {
|
||||
std::cout << name[vd] << " @ " << location[vd] << std::endl;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -396,6 +396,11 @@ public:
|
|||
parrays_[i]->swap(i0, i1);
|
||||
}
|
||||
|
||||
// swap content with other Property_container
|
||||
void swap (Property_container& other)
|
||||
{
|
||||
this->parrays_.swap (other.parrays_);
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<Base_property_array*> parrays_;
|
||||
|
|
|
|||
|
|
@ -1748,4 +1748,6 @@ inline Graph::termtype Graph::what_segment(node_id i)
|
|||
return SINK;
|
||||
}
|
||||
|
||||
#undef last_node
|
||||
|
||||
#endif
|
||||
|
|
|
|||