Update with first reviews

This commit is contained in:
Simon Giraudot 2017-01-05 10:25:32 +01:00
parent 2dbff97e6c
commit 37b29b0944
25 changed files with 542 additions and 478 deletions

View File

@ -4,18 +4,18 @@ namespace CGAL {
\mainpage User Manual
\anchor Chapter_Classification
\cgalAutoToc
\author Simon Giraudot
\author Simon Giraudot, Florent Lafarge
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 classification types (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 classification types based on these attributes.
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 classification types, such as ground, vegetation and buildings. 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 classification types based on these attributes.
\section Classification_Organization Package Organization
%Classification of data sets is achieved as follows:
- some analysis is performed on the input data 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;
- some analysis is performed on the input data 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 item-wise by minimizing an energy defined as the sum of the values taken by attributes on input items (which depend on the attribute/type relationship)
- additional regularization can be used by smoothing either locally or globally through an Alpha Expansion approach.
@ -35,8 +35,8 @@ Organization of the package.
\cgal provides the following structures:
- [Point_set_neighborhood](@ref CGAL::Classification::Point_set_neighborhood) stores spatial searching structures and provides adapted queries for points;
- [Local_eigen_analysis](@ref CGAL::Classification::Local_eigen_analysis) precomputes covariance matrices on local neighborhoods of points and stores the associated eigenvectors and eigenvalues;
- [Point_set_neighborhood](@ref CGAL::Classification::Point_set_neighborhood) stores spatial searching structures and provides adapted queries for points
- [Local_eigen_analysis](@ref CGAL::Classification::Local_eigen_analysis) precomputes covariance matrices on local neighborhoods of points and stores the associated eigenvectors and eigenvalues
- [Planimetric_grid](@ref 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).
@ -45,34 +45,34 @@ The following code snippet shows how to instantiate such data structures from an
\subsection Classification_attributes Attributes
Attributes are defined as scalar fields that associate each input point with a specific value. 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.
Attributes are defined as scalar fields that associate each input point with a specific value. 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.
A user-defined attribute must inherit from `CGAL::Classification::Attribute` and provide a method [value()](@ref CGAL::Classification::Attribute_base::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 are relevant for classification of urban scenes:
- [Attribute_distance_to_plane](@ref CGAL::Classification::Attribute_distance_to_plane) measures how far away a point is from a locally estimated plane
- [Attribute_elevation](@ref CGAL::Classification::Attribute_elevation) computes the local distance to an estimation of the ground
- [Attribute_vertical_dispersion](@ref CGAL::Classification::Attribute_vertical_dispersion) computes how noisy the point set is on a local Z-cylinder
- [Attribute_verticality](@ref CGAL::Classification::Attribute_verticality) compares the local normal vector to the vertical vector.
- [Distance_to_plane](@ref CGAL::Classification::Attribute::Distance_to_plane) measures how far away a point is from a locally estimated plane
- [Elevation](@ref CGAL::Classification::Attribute::Elevation) computes the local distance to an estimation of the ground
- [Vertical_dispersion](@ref CGAL::Classification::Attribute::Vertical_dispersion) computes how noisy the point set is on a local Z-cylinder
- [Verticality](@ref 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 more theoretical and harder to relate to a specific use case, but they can help differenciating some classification types:
- [Attribute_anisotropy](@ref CGAL::Classification::Attribute_anisotropy)
- [Attribute_eigentropy](@ref CGAL::Classification::Attribute_eigentropy)
- [Attribute_linearity](@ref CGAL::Classification::Attribute_linearity)
- [Attribute_omnivariance](@ref CGAL::Classification::Attribute_omnivariance)
- [Attribute_planarity](@ref CGAL::Classification::Attribute_planarity)
- [Attribute_sphericity](@ref CGAL::Classification::Attribute_sphericity)
- [Attribute_sum_eigenvalues](@ref CGAL::Classification::Attribute_sum_eigenvalues)
- [Attribute_surface_variation](@ref CGAL::Classification::Attribute_surface_variation)
- [Anisotropy](@ref CGAL::Classification::Attribute::Anisotropy)
- [Eigentropy](@ref CGAL::Classification::Attribute::Eigentropy)
- [Linearity](@ref CGAL::Classification::Attribute::Linearity)
- [Omnivariance](@ref CGAL::Classification::Attribute::Omnivariance)
- [Planarity](@ref CGAL::Classification::Attribute::Planarity)
- [Sphericity](@ref CGAL::Classification::Attribute::Sphericity)
- [Sum_eigenvalues](@ref CGAL::Classification::Attribute::Sum_eigenvalues)
- [Surface_variation](@ref 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:
- [Attribute_echo_scatter](@ref CGAL::Classification::Attribute_echo_scatter) uses the number of returns (echo) provided by most LIDAR scanners if available
- [Attribute_hsv](@ref CGAL::Classification::Attribute_hsv) uses input color information if available.
- [Echo_scatter](@ref CGAL::Classification::Attribute::Echo_scatter) uses the number of returns (echo) provided by most LIDAR scanners if available
- [Hsv](@ref 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 classifier:
@ -84,9 +84,9 @@ A classification type represents how a point should be classified, for example:
\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](@ref CGAL::Classification::Type::FAVORED_ATT): the type is favored by high values of the attribute
- [NEUTRAL_ATT](@ref CGAL::Classification::Type::NEUTRAL_ATT): the type is not affected by the attribute
- [PENALIZED_ATT](@ref CGAL::Classification::Type::PENALIZED_ATT): the type is favored by low values of the attribute
- [FAVORING](@ref CGAL::Classification::Attribute::FAVORING): the type is favored by high values of the attribute
- [NEUTRAL](@ref CGAL::Classification::Attribute::NEUTRAL): the type is not affected by the attribute
- [PENALIZING](@ref CGAL::Classification::Attribute::PENALIZING): 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:
@ -171,7 +171,7 @@ 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:
standard Potts model \cgalCite{cgal:l-mrfmi-09} :
\f[
E(x) = \sum_{i = 1..N_c} E_{di}(x_i) + \gamma \sum_{i \sim j} \mathbf{1}_{x_i \neq x_j}
@ -196,23 +196,23 @@ constant computation time.
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;
- 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:
The classification algorithm is designed to be as flexible as possible: users may define their 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` makes 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).
- it takes care of generating all needed analysis structures
- 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 \cgalCite{cgal:hws-fsso3-16}
- 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
@ -221,20 +221,20 @@ The classification algorithm is designed to be as flexible as possible: the user
Though it is possible to set them up 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 and 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, a range of weights is tested: the effect 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;
- 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;
- each ground truth point 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 these 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;
- for each classification type, the ratio of correctly classified ground truth points is computed. The minimum of these 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.
Example of evolution of training score. The 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
@ -242,10 +242,10 @@ Example of evolution of training score. Purple curve is the score computed at th
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;
- 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}

View File

@ -1,5 +1,6 @@
@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
${CMAKE_SOURCE_DIR}/Classification/include/CGAL/Classifier.h \
${CMAKE_SOURCE_DIR}/Classification/include/CGAL/Classification/Attribute/ \
${CMAKE_SOURCE_DIR}/Classification/include/CGAL/Classification/

View File

@ -4,23 +4,27 @@
\defgroup PkgClassificationConcepts Concepts
\ingroup PkgClassification
\defgroup PkgClassificationShapes Shapes
\defgroup PkgClassificationDataStructures Data Structures
\ingroup PkgClassification
\defgroup PkgClassificationAttributes Predefined Attributes
\ingroup PkgClassification
\addtogroup PkgClassification
\cgalPkgDescriptionBegin{Classification, PkgClassificationSummary}
\cgalPkgPicture{data_classif.png}
\cgalPkgSummaryBegin
\cgalPkgAuthors{Simon Giraudot}
\cgalPkgAuthors{Simon Giraudot, Florent Lafarge}
\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}
\cgalPkgBib{cgal:lm-clscm-12}
\cgalPkgLicense{\ref licensesGPL "GPL"}
\cgalPkgDemo{Operations on Polyhedra,polyhedron_3.zip}
\cgalPkgShortInfoEnd
@ -54,20 +58,20 @@
## 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>`
- `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>`
*/

View File

@ -112,7 +112,7 @@ int main (int argc, char** argv)
}
std::cerr << "Training" << std::endl;
psc.training(800); // 800 trials
psc.train (800); // 800 trials
psc.run_with_graphcut (helper.neighborhood().k_neighbor_query(12), 0.5);
@ -128,7 +128,8 @@ int main (int argc, char** argv)
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::ofstream fconfig ("config.xml");
helper.save (fconfig, psc);
std::cerr << "All done" << std::endl;

View File

@ -30,13 +30,13 @@ typedef CGAL::Classification::Local_eigen_analysis<Kernel, Iterator, Pmap> Loc
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;
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;
///////////////////////////////////////////////////////////////////
@ -89,13 +89,13 @@ int main (int argc, char** argv)
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;
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
@ -118,31 +118,31 @@ int main (int argc, char** argv)
// 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);
ground->set_attribute_effect (d2p, CGAL::Classification::Attribute::NEUTRAL);
ground->set_attribute_effect (lin, CGAL::Classification::Attribute::PENALIZING);
ground->set_attribute_effect (omni, CGAL::Classification::Attribute::NEUTRAL);
ground->set_attribute_effect (plan, CGAL::Classification::Attribute::FAVORING);
ground->set_attribute_effect (surf, CGAL::Classification::Attribute::PENALIZING);
ground->set_attribute_effect (disp, CGAL::Classification::Attribute::NEUTRAL);
ground->set_attribute_effect (elev, CGAL::Classification::Attribute::PENALIZING);
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);
vege->set_attribute_effect (d2p, CGAL::Classification::Attribute::FAVORING);
vege->set_attribute_effect (lin, CGAL::Classification::Attribute::NEUTRAL);
vege->set_attribute_effect (omni, CGAL::Classification::Attribute::FAVORING);
vege->set_attribute_effect (plan, CGAL::Classification::Attribute::NEUTRAL);
vege->set_attribute_effect (surf, CGAL::Classification::Attribute::NEUTRAL);
vege->set_attribute_effect (disp, CGAL::Classification::Attribute::FAVORING);
vege->set_attribute_effect (elev, CGAL::Classification::Attribute::NEUTRAL);
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);
roof->set_attribute_effect (d2p, CGAL::Classification::Attribute::NEUTRAL);
roof->set_attribute_effect (lin, CGAL::Classification::Attribute::PENALIZING);
roof->set_attribute_effect (omni, CGAL::Classification::Attribute::FAVORING);
roof->set_attribute_effect (plan, CGAL::Classification::Attribute::FAVORING);
roof->set_attribute_effect (surf, CGAL::Classification::Attribute::PENALIZING);
roof->set_attribute_effect (disp, CGAL::Classification::Attribute::NEUTRAL);
roof->set_attribute_effect (elev, CGAL::Classification::Attribute::FAVORING);
//! [Classification Types]
///////////////////////////////////////////////////////////////////

View File

@ -28,8 +28,10 @@ namespace CGAL {
namespace Classification {
namespace Attribute {
/*!
\ingroup PkgClassification
\ingroup PkgClassificationAttributes
\brief Attribute based on local distance to a fitted plane.
@ -44,10 +46,10 @@ namespace Classification {
*/
template <typename Kernel, typename RandomAccessIterator, typename PointMap,
typename DiagonalizeTraits = CGAL::Default_diagonalize_traits<double,3> >
class Attribute_distance_to_plane : public Attribute
class Distance_to_plane : public Attribute_base
{
typedef Classification::Local_eigen_analysis<Kernel, RandomAccessIterator,
PointMap, DiagonalizeTraits> Local_eigen_analysis;
PointMap, DiagonalizeTraits> Local_eigen_analysis;
std::vector<double> distance_to_plane_attribute;
@ -60,12 +62,12 @@ public:
\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)
Distance_to_plane (RandomAccessIterator begin,
RandomAccessIterator end,
PointMap point_map,
const Local_eigen_analysis& eigen)
{
this->weight = 1.;
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))));
@ -84,6 +86,7 @@ public:
/// \endcond
};
} // namespace Attribute
} // namespace Classification

View File

@ -7,14 +7,16 @@
namespace CGAL {
namespace Classification {
namespace Attribute {
/*!
\ingroup PkgClassification
\ingroup PkgClassificationAttributes
\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.
provided by most LIDAR sensors. It can help identify trees.
\tparam Kernel The geometric kernel used.
\tparam RandomAccessIterator Iterator over the input.
@ -22,10 +24,13 @@ namespace Classification {
\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
class Echo_scatter : public Attribute_base
{
typedef Classification::Image<float> Image_float;
public:
typedef Classification::Planimetric_grid<Kernel, RandomAccessIterator, PointMap> Grid;
private:
typedef Classification::Image<float> Image_float;
std::vector<double> echo_scatter;
@ -40,14 +45,14 @@ public:
\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.)
Echo_scatter (RandomAccessIterator begin,
RandomAccessIterator end,
EchoMap echo_map,
Grid& grid,
const double grid_resolution,
double radius_neighbors = 1.)
{
this->weight = 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++)
@ -117,6 +122,8 @@ public:
/// \endcond
};
} // namespace Attribute
} // namespace Classification
} // namespace CGAL

View File

@ -28,9 +28,10 @@ namespace CGAL {
namespace Classification {
namespace Attribute {
/*!
\ingroup PkgClassification
\ingroup PkgClassificationAttributes
\brief Attribute based on the eigenvalues of the covariance matrix
of a local neighborhood.
@ -48,7 +49,7 @@ namespace Classification {
*/
template <typename Kernel, typename RandomAccessIterator, typename PointMap,
typename DiagonalizeTraits = CGAL::Default_diagonalize_traits<double,3> >
class Attribute_linearity : public Attribute
class Linearity : public Attribute_base
{
typedef Classification::Local_eigen_analysis<Kernel, RandomAccessIterator,
PointMap, DiagonalizeTraits> Local_eigen_analysis;
@ -61,11 +62,11 @@ public:
\param end Past-the-end iterator
\param eigen Class with precompute eigenvectors and eigenvalues
*/
Attribute_linearity (RandomAccessIterator begin,
RandomAccessIterator end,
Local_eigen_analysis& eigen)
Linearity (RandomAccessIterator begin,
RandomAccessIterator end,
Local_eigen_analysis& eigen)
{
this->weight = 1.;
this->weight() = 1.;
std::size_t size = (std::size_t)(end - begin);
attrib.reserve (size);
for (std::size_t i = 0; i < size; ++ i)
@ -89,7 +90,7 @@ public:
};
/*!
\ingroup PkgClassification
\ingroup PkgClassificationAttributes
\brief Attribute based on the eigenvalues of the covariance matrix
of a local neighborhood.
@ -107,10 +108,10 @@ public:
*/
template <typename Kernel, typename RandomAccessIterator, typename PointMap,
typename DiagonalizeTraits = CGAL::Default_diagonalize_traits<double,3> >
class Attribute_planarity : public Attribute
class Planarity : public Attribute_base
{
typedef Classification::Local_eigen_analysis<Kernel, RandomAccessIterator,
PointMap, DiagonalizeTraits> Local_eigen_analysis;
PointMap, DiagonalizeTraits> Local_eigen_analysis;
std::vector<double> attrib;
public:
/*!
@ -120,11 +121,11 @@ public:
\param end Past-the-end iterator
\param eigen Class with precompute eigenvectors and eigenvalues
*/
Attribute_planarity (RandomAccessIterator begin,
RandomAccessIterator end,
Local_eigen_analysis& eigen)
Planarity (RandomAccessIterator begin,
RandomAccessIterator end,
Local_eigen_analysis& eigen)
{
this->weight = 1.;
this->weight() = 1.;
std::size_t size = (std::size_t)(end - begin);
attrib.reserve (size);
for (std::size_t i = 0; i < size; ++ i)
@ -148,7 +149,7 @@ public:
};
/*!
\ingroup PkgClassification
\ingroup PkgClassificationAttributes
\brief Attribute based on the eigenvalues of the covariance matrix
of a local neighborhood.
@ -166,10 +167,10 @@ public:
*/
template <typename Kernel, typename RandomAccessIterator, typename PointMap,
typename DiagonalizeTraits = CGAL::Default_diagonalize_traits<double,3> >
class Attribute_sphericity : public Attribute
class Sphericity : public Attribute_base
{
typedef Classification::Local_eigen_analysis<Kernel, RandomAccessIterator,
PointMap, DiagonalizeTraits> Local_eigen_analysis;
PointMap, DiagonalizeTraits> Local_eigen_analysis;
std::vector<double> attrib;
public:
/*!
@ -179,11 +180,11 @@ public:
\param end Past-the-end iterator
\param eigen Class with precompute eigenvectors and eigenvalues
*/
Attribute_sphericity (RandomAccessIterator begin,
RandomAccessIterator end,
Local_eigen_analysis& eigen)
Sphericity (RandomAccessIterator begin,
RandomAccessIterator end,
Local_eigen_analysis& eigen)
{
this->weight = 1.;
this->weight() = 1.;
std::size_t size = (std::size_t)(end - begin);
attrib.reserve (size);
for (std::size_t i = 0; i < size; ++ i)
@ -206,7 +207,7 @@ public:
};
/*!
\ingroup PkgClassification
\ingroup PkgClassificationAttributes
\brief Attribute based on the eigenvalues of the covariance matrix
of a local neighborhood.
@ -224,10 +225,10 @@ public:
*/
template <typename Kernel, typename RandomAccessIterator, typename PointMap,
typename DiagonalizeTraits = CGAL::Default_diagonalize_traits<double,3> >
class Attribute_omnivariance : public Attribute
class Omnivariance : public Attribute_base
{
typedef Classification::Local_eigen_analysis<Kernel, RandomAccessIterator,
PointMap, DiagonalizeTraits> Local_eigen_analysis;
PointMap, DiagonalizeTraits> Local_eigen_analysis;
std::vector<double> attrib;
public:
/*!
@ -237,11 +238,11 @@ public:
\param end Past-the-end iterator
\param eigen Class with precompute eigenvectors and eigenvalues
*/
Attribute_omnivariance (RandomAccessIterator begin,
RandomAccessIterator end,
Local_eigen_analysis& eigen)
Omnivariance (RandomAccessIterator begin,
RandomAccessIterator end,
Local_eigen_analysis& eigen)
{
this->weight = 1.;
this->weight() = 1.;
std::size_t size = (std::size_t)(end - begin);
attrib.reserve (size);
for (std::size_t i = 0; i < size; ++ i)
@ -261,7 +262,7 @@ public:
};
/*!
\ingroup PkgClassification
\ingroup PkgClassificationAttributes
\brief Attribute based on the eigenvalues of the covariance matrix
of a local neighborhood.
@ -279,10 +280,10 @@ public:
*/
template <typename Kernel, typename RandomAccessIterator, typename PointMap,
typename DiagonalizeTraits = CGAL::Default_diagonalize_traits<double,3> >
class Attribute_anisotropy : public Attribute
class Anisotropy : public Attribute_base
{
typedef Classification::Local_eigen_analysis<Kernel, RandomAccessIterator,
PointMap, DiagonalizeTraits> Local_eigen_analysis;
PointMap, DiagonalizeTraits> Local_eigen_analysis;
std::vector<double> attrib;
public:
/*!
@ -292,11 +293,11 @@ public:
\param end Past-the-end iterator
\param eigen Class with precompute eigenvectors and eigenvalues
*/
Attribute_anisotropy (RandomAccessIterator begin,
RandomAccessIterator end,
Local_eigen_analysis& eigen)
Anisotropy (RandomAccessIterator begin,
RandomAccessIterator end,
Local_eigen_analysis& eigen)
{
this->weight = 1.;
this->weight() = 1.;
std::size_t size = (std::size_t)(end - begin);
attrib.reserve (size);
for (std::size_t i = 0; i < size; ++ i)
@ -319,7 +320,7 @@ public:
};
/*!
\ingroup PkgClassification
\ingroup PkgClassificationAttributes
\brief Attribute based on the eigenvalues of the covariance matrix
of a local neighborhood.
@ -337,7 +338,7 @@ public:
*/
template <typename Kernel, typename RandomAccessIterator, typename PointMap,
typename DiagonalizeTraits = CGAL::Default_diagonalize_traits<double,3> >
class Attribute_eigentropy : public Attribute
class Eigentropy : public Attribute_base
{
typedef Classification::Local_eigen_analysis<Kernel, RandomAccessIterator,
PointMap, DiagonalizeTraits> Local_eigen_analysis;
@ -350,11 +351,11 @@ public:
\param end Past-the-end iterator
\param eigen Class with precompute eigenvectors and eigenvalues
*/
Attribute_eigentropy (RandomAccessIterator begin,
RandomAccessIterator end,
Local_eigen_analysis& eigen)
Eigentropy (RandomAccessIterator begin,
RandomAccessIterator end,
Local_eigen_analysis& eigen)
{
this->weight = 1.;
this->weight() = 1.;
std::size_t size = (std::size_t)(end - begin);
attrib.reserve (size);
for (std::size_t i = 0; i < size; ++ i)
@ -381,7 +382,7 @@ public:
};
/*!
\ingroup PkgClassification
\ingroup PkgClassificationAttributes
\brief Attribute based on the eigenvalues of the covariance matrix
of a local neighborhood.
@ -399,7 +400,7 @@ public:
*/
template <typename Kernel, typename RandomAccessIterator, typename PointMap,
typename DiagonalizeTraits = CGAL::Default_diagonalize_traits<double,3> >
class Attribute_sum_eigenvalues : public Attribute
class Sum_eigenvalues : public Attribute_base
{
typedef Classification::Local_eigen_analysis<Kernel, RandomAccessIterator,
PointMap, DiagonalizeTraits> Local_eigen_analysis;
@ -412,15 +413,15 @@ public:
\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)
Sum_eigenvalues (RandomAccessIterator begin,
RandomAccessIterator end,
Local_eigen_analysis& eigen)
{
this->weight = 1.;
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));
attrib.push_back (eigen.sum_of_eigenvalues(i));
this->compute_mean_max (attrib, mean, this->max);
}
@ -434,7 +435,7 @@ public:
};
/*!
\ingroup PkgClassification
\ingroup PkgClassificationAttributes
\brief Attribute based on the eigenvalues of the covariance matrix
of a local neighborhood.
@ -452,10 +453,10 @@ public:
*/
template <typename Kernel, typename RandomAccessIterator, typename PointMap,
typename DiagonalizeTraits = CGAL::Default_diagonalize_traits<double,3> >
class Attribute_surface_variation : public Attribute
class Surface_variation : public Attribute_base
{
typedef Classification::Local_eigen_analysis<Kernel, RandomAccessIterator,
PointMap, DiagonalizeTraits> Local_eigen_analysis;
PointMap, DiagonalizeTraits> Local_eigen_analysis;
std::vector<double> attrib;
public:
/*!
@ -465,11 +466,11 @@ public:
\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)
Surface_variation (RandomAccessIterator begin,
RandomAccessIterator end,
Local_eigen_analysis& eigen)
{
this->weight = 1.;
this->weight() = 1.;
std::size_t size = (std::size_t)(end - begin);
attrib.reserve (size);
for (std::size_t i = 0; i < size; ++ i)
@ -492,6 +493,7 @@ public:
/// \endcond
};
} // namespace Attribute
} // namespace Classification

View File

@ -30,8 +30,10 @@ namespace CGAL {
namespace Classification {
namespace Attribute {
/*!
\ingroup PkgClassification
\ingroup PkgClassificationAttributes
\brief Attribute based on local elevation.
@ -47,7 +49,7 @@ namespace Classification {
*/
template <typename Kernel, typename RandomAccessIterator, typename PointMap>
class Attribute_elevation : public Attribute
class Elevation : public Attribute_base
{
typedef typename Kernel::Iso_cuboid_3 Iso_cuboid_3;
@ -68,14 +70,14 @@ public:
\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.)
Elevation (RandomAccessIterator begin,
RandomAccessIterator end,
PointMap point_map,
const Grid& grid,
const double grid_resolution,
double radius_dtm = -1.)
{
this->weight = 1.;
this->weight() = 1.;
if (radius_dtm < 0.)
radius_dtm = 100. * grid_resolution;
@ -159,6 +161,8 @@ public:
/// \endcond
};
} // namespace Attribute
} // namespace Classification

View File

@ -17,8 +17,8 @@
//
// Author(s) : Simon Giraudot
#ifndef CGAL_CLASSIFICATION_ATTRIBUTE_COLOR_H
#define CGAL_CLASSIFICATION_ATTRIBUTE_COLOR_H
#ifndef CGAL_CLASSIFICATION_ATTRIBUTE_HSV_H
#define CGAL_CLASSIFICATION_ATTRIBUTE_HSV_H
#include <vector>
@ -28,13 +28,15 @@ namespace CGAL {
namespace Classification {
namespace Attribute {
/*!
\ingroup PkgClassification
\ingroup PkgClassificationAttributes
\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
used for classification purposes. This attribute is based on a
Gaussian probabilistic model on one of the three HSV channels
(hue, saturation or value).
@ -43,15 +45,15 @@ namespace Classification {
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
mean of 90 (which corresponds to a green hue) can help identify
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
\tparam ColorMap is a model of `ReadablePropertyMap` with value type `CGAL::Classification::RGB_Color`.
*/
template <typename Kernel, typename RandomAccessIterator, typename ColorMap>
class Attribute_hsv : public Attribute
class Hsv : public Attribute_base
{
typedef typename Classification::RGB_Color RGB_Color;
typedef typename Classification::HSV_Color HSV_Color;
@ -73,13 +75,13 @@ public:
\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)
Hsv (RandomAccessIterator begin,
RandomAccessIterator end,
ColorMap color_map,
std::size_t channel,
double mean, double sd)
{
this->weight = 1.;
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]));
@ -105,8 +107,10 @@ public:
/// \endcond
};
} // namespace Attribute
} // namespace Classification
} // namespace CGAL
#endif // CGAL_CLASSIFICATION_ATTRIBUTE_COLOR_H
#endif // CGAL_CLASSIFICATION_ATTRIBUTE_HSV_H

View File

@ -28,9 +28,11 @@
namespace CGAL {
namespace Classification {
namespace Attribute {
/*!
\ingroup PkgClassification
\ingroup PkgClassificationAttributes
\brief Attribute based on local vertical dispersion of points.
@ -46,7 +48,7 @@ namespace Classification {
\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
class Vertical_dispersion : public Attribute_base
{
typedef Classification::Image<float> Image_float;
typedef Classification::Planimetric_grid<Kernel, RandomAccessIterator, PointMap> Grid;
@ -63,14 +65,14 @@ public:
\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.)
Vertical_dispersion (RandomAccessIterator begin,
RandomAccessIterator end,
PointMap point_map,
const Grid& grid,
const double grid_resolution,
double radius_neighbors = -1.)
{
this->weight = 1.;
this->weight() = 1.;
if (radius_neighbors < 0.)
radius_neighbors = 5. * grid_resolution;
@ -152,6 +154,8 @@ public:
/// \endcond
};
}
}
}

View File

@ -28,8 +28,10 @@ namespace CGAL {
namespace Classification {
namespace Attribute {
/*!
\ingroup PkgClassification
\ingroup PkgClassificationAttributes
\brief Attribute based on local verticality.
@ -44,7 +46,7 @@ namespace Classification {
*/
template <typename Kernel, typename RandomAccessIterator, typename PointMap,
typename DiagonalizeTraits = CGAL::Default_diagonalize_traits<double,3> >
class Attribute_verticality : public Attribute
class Verticality : public Attribute_base
{
typedef Classification::Local_eigen_analysis<Kernel, RandomAccessIterator,
PointMap, DiagonalizeTraits> Local_eigen_analysis;
@ -58,11 +60,11 @@ public:
\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)
Verticality (RandomAccessIterator begin,
RandomAccessIterator end,
const Local_eigen_analysis& eigen)
{
this->weight = 1.;
this->weight() = 1.;
typename Kernel::Vector_3 vertical (0., 0., 1.);
for (std::size_t i = 0; i < (std::size_t)(end - begin); i++)
@ -85,11 +87,11 @@ public:
\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)
Verticality (const RandomAccessIterator& begin,
const RandomAccessIterator& end,
VectorMap normal_map)
{
this->weight = 1.;
this->weight() = 1.;
typename Kernel::Vector_3 vertical (0., 0., 1.);
for (std::size_t i = 0; i < (std::size_t)(end - begin); i++)
@ -114,6 +116,8 @@ public:
/// \endcond
};
} // namespace Attribute
} // namespace Classification
} // namespace CGAL

View File

@ -17,8 +17,8 @@
//
// Author(s) : Simon Giraudot
#ifndef CGAL_CLASSIFICATION_ATTRIBUTE_H
#define CGAL_CLASSIFICATION_ATTRIBUTE_H
#ifndef CGAL_CLASSIFICATION_ATTRIBUTE_BASE_H
#define CGAL_CLASSIFICATION_ATTRIBUTE_BASE_H
#include <vector>
@ -29,49 +29,44 @@ 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.
\brief Abstract class describing a classification attribute that
associates a scalar value to each item of the classification input.
*/
class Attribute
class Attribute_base
{
double m_weight;
public:
double weight; ///< Weight of the attribute between 0 and +&infin;.
/// \cond SKIP_IN_MANUAL
double mean;
double max;
virtual ~Attribute() { }
virtual ~Attribute_base() { }
/// \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.
\brief Returns the weight of the attribute between 0 and +&infin;.
*/
virtual std::string id() { return "abstract_attribute"; }
double& weight() { return m_weight; }
/*!
\brief Returns `abstract_attribute` and should be overloaded
by a inherited class with a specific name.
*/
virtual std::string name() { 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`
\brief Returns the value taken by the attribute at the given
index. This method must be implemented by inherited classes.
*/
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));
return (std::max) (0., (std::min) (1., value(index) / m_weight));
}
virtual double favored (std::size_t index) { return (1. - normalized (index)); }
virtual double penalized (std::size_t index) { return normalized (index); }
@ -92,7 +87,7 @@ public:
if (vect[i] < min)
min = vect[i];
}
// std::cerr << id() << " Min/max = " << min << " / " << max << std::endl;
// std::cerr << name() << " Min/max = " << min << " / " << max << std::endl;
mean /= vect.size();
}
@ -104,17 +99,18 @@ public:
/*!
\ingroup PkgClassification
\brief Handle to a classification `Attribute`.
\brief Handle to a classification `Attribute_base`.
\cgalModels Handle
*/
class Attribute_handle { };
#else
typedef boost::shared_ptr<Attribute> Attribute_handle;
typedef boost::shared_ptr<Attribute_base> Attribute_handle;
#endif
} // namespace Classification
} // namespace CGAL
#endif // CGAL_CLASSIFICATION_ATTRIBUTE_H
#endif // CGAL_CLASSIFICATION_ATTRIBUTE_BASE_H

View File

@ -51,29 +51,27 @@ namespace Classification {
/*!
\ingroup PkgClassification
\ingroup PkgClassificationDataStructures
\brief Class designed to help the user using the classification
algorithm.
The classification algorithm is designed to be as flexible as
possible, letting the user free to use its own data structures,
attributes and classification types.
Nevertheless, \cgal provides a predefined framework that should work
correctly on common urban point sets. Using this class, classification
can be performed without having to instanciate all attributes and data
structures separately.
This class also provides functions to save and load a specific
algorithm. The classification algorithm is designed to be as flexible
as possible, letting the user free to use its own data structures,
attributes and classification types. Nevertheless, \cgal provides a
predefined framework that should work correctly on common urban point
sets. Using this class, classification can be performed without having
to instantiate all attributes and data structures separately. This
class also provides functions to save and load a specific
configuration (attribute effects and weights), as well as a function
to write a classified point set in a PLY format with colors and
labels.
\tparam Kernel The geometric kernel used
\tparam Kernel is a model of \cgal Kernel
\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.
\tparam PointMap is a model of `ReadablePropertyMap` whose key
type is the value type of `RandomAccessIterator` and value type is
`Point_3<Kernel>`.
\tparam DiagonalizeTraits is a model of `DiagonalizeTraits` used
for matrix diagonalization.
*/
template <typename Kernel,
typename RandomAccessIterator,
@ -102,29 +100,29 @@ public:
/// \cond SKIP_IN_MANUAL
typedef typename Kernel::Point_3 Point;
typedef Attribute_anisotropy
typedef Attribute::Anisotropy
<Kernel, RandomAccessIterator, PointMap, DiagonalizeTraits> Anisotropy;
typedef Attribute_distance_to_plane
typedef Attribute::Distance_to_plane
<Kernel, RandomAccessIterator, PointMap, DiagonalizeTraits> Distance_to_plane;
typedef Attribute_eigentropy
typedef Attribute::Eigentropy
<Kernel, RandomAccessIterator, PointMap, DiagonalizeTraits> Eigentropy;
typedef Attribute_elevation
typedef Attribute::Elevation
<Kernel, RandomAccessIterator, PointMap> Elevation;
typedef Attribute_linearity
typedef Attribute::Linearity
<Kernel, RandomAccessIterator, PointMap, DiagonalizeTraits> Linearity;
typedef Attribute_omnivariance
typedef Attribute::Omnivariance
<Kernel, RandomAccessIterator, PointMap, DiagonalizeTraits> Omnivariance;
typedef Attribute_planarity
typedef Attribute::Planarity
<Kernel, RandomAccessIterator, PointMap, DiagonalizeTraits> Planarity;
typedef Attribute_sphericity
typedef Attribute::Sphericity
<Kernel, RandomAccessIterator, PointMap, DiagonalizeTraits> Sphericity;
typedef Attribute_sum_eigenvalues
typedef Attribute::Sum_eigenvalues
<Kernel, RandomAccessIterator, PointMap, DiagonalizeTraits> Sum_eigen;
typedef Attribute_surface_variation
typedef Attribute::Surface_variation
<Kernel, RandomAccessIterator, PointMap, DiagonalizeTraits> Surface_variation;
typedef Attribute_vertical_dispersion
typedef Attribute::Vertical_dispersion
<Kernel, RandomAccessIterator, PointMap> Dispersion;
typedef Attribute_verticality
typedef Attribute::Verticality
<Kernel, RandomAccessIterator, PointMap, DiagonalizeTraits> Verticality;
/// \endcond
@ -197,9 +195,9 @@ public:
/*!
\brief Constructs an helper object.
\brief Constructs a helper object.
This triggers the instanciation of all necessary data structures
This triggers the instantiation of all necessary data structures
(neighborhood, eigen analysis, etc.) on the specified number of
scales.
@ -207,7 +205,7 @@ public:
\param end Past-the-end iterator
\param point_map Property map to access the input points
\param nb_scales Number of scales. Default only uses the first
\param nb_scales Number of scales. %Default only uses the first
scale (unaltered point set). Increasing this value generates
recursively simplified point set and computes the associated
attributes. Using `nb_scales=5` usually provides satisfying
@ -238,16 +236,16 @@ public:
/*!
\brief Constructs an helper object by loading a configuration file.
\brief Constructs an helper object by loading the stream `input`.
All data structures, attributes and types specified in the input
file `filename` are instanciated if possible (in particular,
stream `input` are instantiated if possible (in particular,
property maps needed should be provided).
\tparam VectorMap is a model of `ReadablePropertyMap` with value type `Vector_3<Kernel>`.
\tparam ColorMap is a model of `ReadablePropertyMap` with value type `CGAL::Classification::RGB_Color`.
\tparam EchoMap is a model of `ReadablePropertyMap` with value type `std::size_`.
\param filename Name of the output file
\tparam EchoMap is a model of `ReadablePropertyMap` with value type `std::size_t`.
\param input Input stream
\param psc Classification object where to store attributes and types
\param begin Iterator to the first input object
\param end Past-the-end iterator
@ -259,14 +257,14 @@ public:
template<typename VectorMap = CGAL::Empty_property_map<RandomAccessIterator, typename Kernel::Vector_3>,
typename ColorMap = CGAL::Empty_property_map<RandomAccessIterator, RGB_Color>,
typename EchoMap = CGAL::Empty_property_map<RandomAccessIterator, std::size_t> >
Helper (const char* filename, Classifier& psc,
Helper (std::istream& input, Classifier& psc,
RandomAccessIterator begin, RandomAccessIterator end,
PointMap point_map,
VectorMap normal_map = VectorMap(),
ColorMap color_map = ColorMap(),
EchoMap echo_map = EchoMap())
{
load (filename, psc, begin, end, point_map, normal_map, color_map, echo_map);
load (input, psc, begin, end, point_map, normal_map, color_map, echo_map);
}
/// \cond SKIP_IN_MANUAL
@ -313,16 +311,16 @@ public:
{
std::size_t nb_useful = 0;
for (std::size_t j = 0; j < m_scales[i]->attributes.size(); ++ j)
if (m_scales[i]->attributes[j]->weight != 0.)
if (m_scales[i]->attributes[j]->weight() != 0.)
nb_useful ++;
std::cerr << " * scale " << i << " with size " << m_scales[i]->voxel_size
<< ", " << nb_useful << " useful attribute(s)";
if (nb_useful != 0) std::cerr << ":" << std::endl;
else std::cerr << std::endl;
for (std::size_t j = 0; j < m_scales[i]->attributes.size(); ++ j)
if (m_scales[i]->attributes[j]->weight != 0.)
if (m_scales[i]->attributes[j]->weight() != 0.)
std::cerr << " - " << m_scales[i]->attributes[j]->id()
<< " (weight = " << m_scales[i]->attributes[j]->weight << ")" << std::endl;
<< " (weight = " << m_scales[i]->attributes[j]->weight() << ")" << std::endl;
}
}
/// \endcond
@ -383,17 +381,17 @@ public:
Generate, for all precomputed scales, the following attributes:
- `CGAL::Classification::Attribute_anisotropy`
- `CGAL::Classification::Attribute_distance_to_plane`
- `CGAL::Classification::Attribute_eigentropy`
- `CGAL::Classification::Attribute_elevation`
- `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`
- `CGAL::Classification::Attribute_vertical_dispersion`
- `CGAL::Classification::Attribute::Anisotropy`
- `CGAL::Classification::Attribute::Distance_to_plane`
- `CGAL::Classification::Attribute::Eigentropy`
- `CGAL::Classification::Attribute::Elevation`
- `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`
- `CGAL::Classification::Attribute::Vertical_dispersion`
\param psc The classification object where to store the attributes
\param begin Iterator to the first input object
@ -430,7 +428,7 @@ public:
Generate, for all precomputed scales, the following attribute:
- `CGAL::Classification::Attribute_verticality`
- `CGAL::Classification::Attribute::Verticality`
If the normal map is left to its default type
`CGAL::Empty_property_map`, then the verticality attributes are
@ -480,15 +478,15 @@ public:
Generate the following attributes:
- 9 attributes `CGAL::Classification::Attribute_hsv` on
- 9 attributes `CGAL::Classification::Attribute::Hsv` on
channel 0 (hue) with mean ranging from 0° to 360° and standard
deviation of 22.5.
- 5 attributes `CGAL::Classification::Attribute_hsv` on
- 5 attributes `CGAL::Classification::Attribute::Hsv` on
channel 1 (saturation) with mean ranging from 0 to 100 and standard
deviation of 12.5
- 5 attributes `CGAL::Classification::Attribute_hsv` on
- 5 attributes `CGAL::Classification::Attribute::Hsv` on
channel 2 (value) with mean ranging from 0 to 100 and standard
deviation of 12.5
@ -507,7 +505,7 @@ public:
ColorMap color_map)
{
typedef Attribute_hsv<Kernel, RandomAccessIterator, ColorMap> Hsv;
typedef Attribute::Hsv<Kernel, RandomAccessIterator, ColorMap> Hsv;
CGAL::Timer t; t.start();
for (std::size_t i = 0; i <= 8; ++ i)
{
@ -541,7 +539,7 @@ public:
Generate, for all precomputed scales, the following attribute:
- `CGAL::Classification::Attribute_echo_scatter`
- `CGAL::Classification::Attribute::Echo_scatter`
\tparam EchoMap Property map to access the echo values of the input points (if any).
\param psc The classification object where to store the attributes
@ -554,7 +552,7 @@ public:
RandomAccessIterator begin, RandomAccessIterator end,
EchoMap echo_map)
{
typedef Attribute_echo_scatter<Kernel, RandomAccessIterator, PointMap, EchoMap> Echo_scatter;
typedef Attribute::Echo_scatter<Kernel, RandomAccessIterator, PointMap, EchoMap> Echo_scatter;
CGAL::Timer t; t.start();
for (std::size_t i = 0; i < m_scales.size(); ++ i)
{
@ -601,7 +599,7 @@ public:
/*!
\brief Saves the current configuration in the file `filename`.
\brief Saves the current configuration in the stream `output`.
This allows to easily save and recover a specific classification
configuration, that is to say:
@ -614,10 +612,10 @@ public:
the `load()` method and the constructor that takes a file name
as parameter.
\param filename Name of the output file
\param output Output stream
\param psc Classification object whose attributes and types must be saved
*/
void save (const char* filename, Classifier& psc)
void save (std::ostream& output, Classifier& psc)
{
boost::property_tree::ptree tree;
@ -631,12 +629,12 @@ public:
for (std::size_t i = 0; i < psc.number_of_attributes(); ++ i)
{
Attribute_handle att = psc.get_attribute(i);
if (att->weight == 0)
if (att->weight() == 0)
continue;
boost::property_tree::ptree ptr;
ptr.put("id", name_att (att, map_scale));
ptr.put("weight", att->weight);
ptr.put("weight", att->weight());
tree.add_child("classification.attributes.attribute", ptr);
}
@ -649,16 +647,16 @@ public:
for (std::size_t j = 0; j < psc.number_of_attributes(); ++ j)
{
Attribute_handle att = psc.get_attribute(j);
if (att->weight == 0)
if (att->weight() == 0)
continue;
boost::property_tree::ptree ptr2;
ptr2.put("id", name_att (att, map_scale));
Type::Attribute_effect effect = type->attribute_effect(att);
if (effect == Type::Attribute_effect::PENALIZED_ATT)
Attribute::Effect effect = type->attribute_effect(att);
if (effect == Attribute::PENALIZING)
ptr2.put("effect", "penalized");
else if (effect == Type::Attribute_effect::NEUTRAL_ATT)
else if (effect == Attribute::NEUTRAL)
ptr2.put("effect", "neutral");
else if (effect == Type::Attribute_effect::FAVORED_ATT)
else if (effect == Attribute::FAVORING)
ptr2.put("effect", "favored");
ptr.add_child("attribute", ptr2);
}
@ -667,15 +665,15 @@ public:
// Write property tree to XML file
boost::property_tree::xml_writer_settings<std::string> settings(' ', 3);
boost::property_tree::write_xml(filename, tree, std::locale(), settings);
boost::property_tree::write_xml(output, tree, settings);
}
/*!
\brief Load a configuration from the file `filename`.
\brief Load a configuration from the stream `input`.
All data structures, attributes and types specified in the input
file `filename` are instanciated if possible (in particular,
stream `input` are instantiated if possible (in particular,
property maps needed should be provided).
The input file is written in an XML format written by the `save()`
@ -684,7 +682,7 @@ public:
\tparam VectorMap is a model of `ReadablePropertyMap` with value type `Vector_3<Kernel>`.
\tparam ColorMap is a model of `ReadablePropertyMap` with value type `CGAL::Classification::RGB_Color`.
\tparam EchoMap is a model of `ReadablePropertyMap` with value type `std::size_`.
\param filename Name of the output file
\param input Input stream
\param psc Classification object where to store attributes and types
\param begin Iterator to the first input object
\param end Past-the-end iterator
@ -696,7 +694,7 @@ public:
template<typename VectorMap = CGAL::Empty_property_map<RandomAccessIterator, typename Kernel::Vector_3>,
typename ColorMap = CGAL::Empty_property_map<RandomAccessIterator, RGB_Color>,
typename EchoMap = CGAL::Empty_property_map<RandomAccessIterator, std::size_t> >
bool load (const char* filename, Classifier& psc,
bool load (std::istream& input, Classifier& psc,
RandomAccessIterator begin, RandomAccessIterator end,
PointMap point_map,
VectorMap normal_map = VectorMap(),
@ -704,8 +702,8 @@ public:
EchoMap echo_map = EchoMap())
{
typedef Attribute_echo_scatter<Kernel, RandomAccessIterator, PointMap, EchoMap> Echo_scatter;
typedef Attribute_hsv<Kernel, RandomAccessIterator, ColorMap> Hsv;
typedef Attribute::Echo_scatter<Kernel, RandomAccessIterator, PointMap, EchoMap> Echo_scatter;
typedef Attribute::Hsv<Kernel, RandomAccessIterator, ColorMap> Hsv;
clear();
@ -714,7 +712,7 @@ public:
boost::make_transform_iterator (end, CGAL::Property_map_to_unary_function<PointMap>(point_map)));
boost::property_tree::ptree tree;
boost::property_tree::read_xml(filename, tree);
boost::property_tree::read_xml(input, tree);
double voxel_size = tree.get<double>("classification.parameters.voxel_size");
@ -829,7 +827,7 @@ public:
Attribute_handle att = psc.get_attribute (psc.number_of_attributes() - 1);
m_scales[scale]->attributes.push_back (att);
att->weight = weight;
att->weight() = weight;
att_map[full_id] = att;
}
std::cerr << "Elevation took " << t.time() << " second(s)" << std::endl;
@ -851,11 +849,11 @@ public:
Attribute_handle att = it->second;
std::string effect = v2.second.get<std::string>("effect");
if (effect == "penalized")
new_type->set_attribute_effect (att, Type::PENALIZED_ATT);
new_type->set_attribute_effect (att, Attribute::PENALIZING);
else if (effect == "neutral")
new_type->set_attribute_effect (att, Type::NEUTRAL_ATT);
new_type->set_attribute_effect (att, Attribute::NEUTRAL);
else
new_type->set_attribute_effect (att, Type::FAVORED_ATT);
new_type->set_attribute_effect (att, Attribute::FAVORING);
}
}

View File

@ -14,16 +14,19 @@ namespace CGAL {
namespace Classification {
/*!
\ingroup PkgClassification
\ingroup PkgClassificationDataStructures
\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.
set using a local neighborhood.
\tparam Kernel The geometric kernel used.
\tparam Kernel is a model of \cgal Kernel.
\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.
\tparam PointMap is a model of `ReadablePropertyMap` whose key
type is the value type of `RandomAccessIterator` and value type is
`Point_3<Kernel>`.
\tparam DiagonalizeTraits is a model of `DiagonalizeTraits` used
for matrix diagonalization.
*/
template <typename Kernel, typename RandomAccessIterator, typename PointMap,
typename DiagonalizeTraits = CGAL::Default_diagonalize_traits<double,3> >
@ -44,7 +47,7 @@ private:
std::vector<Vector> m_smallest_eigenvectors;
std::vector<Vector> m_middle_eigenvectors;
std::vector<Vector> m_largest_eigenvectors;
double m_mean_range;
public:
@ -62,18 +65,13 @@ public:
\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.
\param neighbor_query %Object used to access neighborhoods of points
*/
template <typename NeighborQuery>
Local_eigen_analysis (RandomAccessIterator begin,
RandomAccessIterator end,
PointMap point_map,
const NeighborQuery& neighbor_query,
double& mean_range)
const NeighborQuery& neighbor_query)
{
std::size_t size = end - begin;
m_eigenvalues.reserve (size);
@ -82,7 +80,7 @@ public:
m_middle_eigenvectors.reserve (size);
m_largest_eigenvectors.reserve (size);
mean_range = 0.;
m_mean_range = 0.;
for (std::size_t i = 0; i < size; i++)
{
@ -93,17 +91,17 @@ public:
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]),
m_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;
m_mean_range /= size;
}
/*!
\brief Returns the estimated normal vector of the indexed point.
\brief Returns the estimated unoriented normal vector of the indexed point.
*/
const Vector& normal_vector (std::size_t index) const { return m_smallest_eigenvectors[index]; }
@ -120,7 +118,11 @@ public:
/*!
\brief Returns the sum of eigenvalues of the index point.
*/
const double& sum_eigenvalues (std::size_t index) const { return m_sum_eigenvalues[index]; }
const double& sum_of_eigenvalues (std::size_t index) const { return m_sum_eigenvalues[index]; }
/// \cond SKIP_IN_MANUAL
double mean_range() const { return m_mean_range; }
/// \endcond
private:

View File

@ -10,14 +10,20 @@ namespace CGAL {
namespace Classification {
/*!
\ingroup PkgClassification
\ingroup PkgClassificationDataStructures
\brief Class that precomputes a 2D planimetric grid used for
digital terrain modeling.
\brief Class that precomputes a 2D planimetric grid.
The grid is composed of squared cells with a user defined size,
each cell containing the list of indices of the points whose
projection along the Z-axis lies within this cell. The mapping
from each point to the its cell is also stored.
\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 PointMap is a model of `ReadablePropertyMap` whose key
type is the value type of `RandomAccessIterator` and value type is
`Point_3<Kernel>`.
*/
template <typename Kernel, typename RandomAccessIterator, typename PointMap>
@ -72,15 +78,22 @@ public:
}
/*!
\brief Returns the number of cells along the X-axis.
*/
std::size_t width() const { return m_grid.width(); }
/*!
\brief Returns the number of cells along the Y-axis.
*/
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.
\brief Returns `false` if the cell indexed by `(x,y)` is empty, `true` otherwise.
*/
bool mask(std::size_t x, std::size_t y) const { return (!(m_grid(x,y).empty())); }

View File

@ -19,14 +19,24 @@ namespace CGAL {
namespace Classification {
/*!
\ingroup PkgClassification
\ingroup PkgClassificationDataStructures
\brief Class that precomputes spatial searching structures and
gives easy access to local neighborhoods of points.
\brief Class that precomputes spatial searching structures for an
input point set and gives easy access to local neighborhoods of
points.
\tparam Kernel The geometric kernel used.
It allows the user to generate models of `NeighborQuery` based on
a fixed range neighborhood or on a fixed K number of neighbors. In
addition, the spatial searching structures can be computed on a
simplified version of the point set to allow for neighbor queries
at a higher scale.
\tparam Kernel is a model of \cgal Kernel.
\tparam RandomAccessIterator Iterator over the input.
\tparam PointMap is a model of `ReadablePropertyMap` with value type `Point_3<Kernel>`.
\tparam PointMap is a model of `ReadablePropertyMap` whose key
type is the value type of `RandomAccessIterator` and value type is
`Point_3<Kernel>`.
*/
template <typename Kernel, typename RandomAccessIterator, typename PointMap>
class Point_set_neighborhood
@ -69,7 +79,8 @@ class Point_set_neighborhood
public:
/*!
Functor that returns a neighborhood with a fixed number of points.
Functor that computes the neighborhood of an input point with a
fixed number of neighbors.
\cgalModels NeighborQuery
*/
@ -99,7 +110,9 @@ public:
};
/*!
Functor that returns a neighborhood with a fixed radius.
Functor that computes the neighborhood of an input point defined
as the points lying in a sphere of fixed radius centered at the
input point.
\cgalModels NeighborQuery
*/

View File

@ -8,37 +8,27 @@ 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.
\brief %Classification type (for example: vegetation, ground, etc.)
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::string m_name;
std::map<Attribute_handle, Attribute_effect> m_attribute_effects;
/// \endcond
public:
/*!
\param id The name of the classification type
\param name The name of the classification type
(e.g. vegetation).
*/
Type (std::string id) : m_id (id) { }
Type (std::string name) : m_name (name) { }
/*!
\brief Sets how an attribute affects the classification type.
@ -60,27 +50,24 @@ public:
{
std::map<Attribute_handle, Attribute_effect>::iterator
search = m_attribute_effects.find (att);
return (search == m_attribute_effects.end () ? NEUTRAL_ATT : search->second);
return (search == m_attribute_effects.end () ? NEUTRAL : search->second);
}
/*!
\brief Returns the ID of the classification type.
*/
const std::string& id() const { return m_id; }
const std::string& name() const { return m_name; }
/// \cond SKIP_IN_MANUAL
void info()
{
std::cerr << "Attribute " << m_id << ": ";
std::cerr << "Attribute " << m_name << ": ";
for (std::map<Attribute_handle, Attribute_effect>::iterator it = m_attribute_effects.begin();
it != m_attribute_effects.end(); ++ it)
{
if (it->second == NEUTRAL_ATT)
if (it->second == NEUTRAL)
continue;
std::cerr << it->first;
if (it->second == FAVORED_ATT) std::cerr << " (favored), ";
else if (it->second == PENALIZED_ATT) std::cerr << " (penalized), ";
if (it->second == FAVORING) std::cerr << " (favored), ";
else if (it->second == PENALIZING) std::cerr << " (penalized), ";
}
std::cerr << std::endl;
}

View File

@ -60,31 +60,31 @@ namespace CGAL {
\brief Classifies a data set based on a set of attribute and a set of classification types.
This class implement the core of the algorithm. It uses a data set as
input and assign each input iterator to a classification type among a
set of user defined classification types.
This class implements the core of the classification algorithm
\cgalCite{cgal:lm-clscm-12}. It uses a data set as input and assignes
each input iterator to a classification type among a set of user
defined classification types.
To achieve this classification algorithm, a set of local geometric
attributes are used, such as:
attributes are used, such as planarity, elevation or vertical
dispersion.
- planarity
- elevation
- vertical dispersion
The user must define a set of classification types such as building,
ground or vegetation.
The user must define a set of classification types such as:
Each pair of attribute and type must be assigned an
[Attribute::Effect](@ref CGAL::Classification::Attribute::Effect) (for
example, vegetation has a low planarity and a high vertical
dispersion) and each attribute must be assigned a weight. These
parameters can be set up by hand or by providing a training set for
each classification type.
- building
- ground
- vegetation
\tparam RandomAccessIterator %Iterator over the input items, model of
`RandomAccessIterator`
Each pair of attribute/type must be assigned an effect (for example,
vegetation has a low planarity and a high vertical dispersion) and
each attribute must be assigned a weight. These parameters can be set
up by hand or by providing a training set for each classification
type.
\tparam ItemMap is a model of `ReadablePropertyMap` that accesses the
item type from the value_type of `RandomAccessIterator`
\tparam RandomAccessIterator Iterator over the input items
\tparam ItemMap is a model of `ReadablePropertyMap`
*/
template <typename RandomAccessIterator,
@ -143,7 +143,7 @@ private:
std::vector<Type_handle> m_types;
std::vector<Attribute_handle> m_attributes;
typedef Classification::Type::Attribute_effect Attribute_effect;
typedef Classification::Attribute::Effect Attribute_effect;
std::vector<std::vector<Attribute_effect> > m_effect_table;
/// \endcond
@ -155,10 +155,7 @@ public:
/// @{
/*!
\brief Constructs a classification object based on the input iterators.
This method just initializes the structure and does not compute
anything.
\brief Initializes a classification object based on the input iterators.
\param begin Iterator to the first input object
@ -288,10 +285,10 @@ public:
/*!
\brief Runs the classification algorithm with a global
regularizarion based on a graphcut.
regularization based on a graphcut.
The computed classification energy is globally regularized through
and alpha-expansion algorithm. This method is slow but provides
an alpha-expansion algorithm. This method is slow but provides
the user with good quality results.
\tparam NeighborQuery is a model of `NeighborQuery`
@ -357,7 +354,7 @@ public:
/// @{
/*!
\brief Instanciates and adds a classification type.
\brief Instantiates and adds a classification type.
\param name ID of the classification type.
@ -450,7 +447,7 @@ public:
/*!
\brief Adds an attribute.
\param attribute Handle of the attribute to add.
\param attribute %Handle of the attribute to add.
*/
void add_attribute (Attribute_handle attribute)
{
@ -487,11 +484,11 @@ public:
\note If classification was not performed (using `run()`,
`run_with_local_smoothing()` or `run_with_graphcut()`), this
function always returns the default empty `Type_handle`.
function always returns the default `Type_handle`.
\param index Index of the input item
\param index %Index of the input item
\return Pointer to the classification type
\return %Handle to the classification type
*/
Type_handle classification_type_of (std::size_t index) const
{
@ -527,7 +524,7 @@ public:
`run_with_local_smoothing()` or `run_with_graphcut()`), this
function always returns 0.
\param index Index of the input item
\param index %Index of the input item
\return Confidence ranging from 0 (not confident at all) to 1 (very confident).
*/
double confidence_of (std::size_t index) const
@ -546,9 +543,9 @@ public:
/*!
\brief Runs the training algorithm.
The object must have been filled with the `Classification::Type`
and `Classification::Attribute` objects before running this
function.
All the `Classification::Type` and `Classification::Attribute`
necessary for the classification should have been registered in
the object before running this function.
Each classification type must be given a small set of user-defined
inliers to provide the training algorithm with a ground truth.
@ -563,7 +560,7 @@ public:
configuration found.
*/
double training (std::size_t nb_tests = 300)
double train (std::size_t nb_tests = 300)
{
if (m_training_type.empty())
return 0.;
@ -594,13 +591,13 @@ public:
for (std::size_t j = 0; j < m_attributes.size(); ++ j)
{
Attribute_handle att = m_attributes[j];
best_weights[j] = att->weight;
best_weights[j] = att->weight();
std::size_t nb_useful = 0;
double min = (std::numeric_limits<double>::max)();
double max = -(std::numeric_limits<double>::max)();
att->weight = wmin;
att->weight() = wmin;
for (std::size_t i = 0; i < 100; ++ i)
{
estimate_attribute_effect(training_sets, att);
@ -608,12 +605,12 @@ public:
{
CGAL_CLASSTRAINING_CERR << "#";
nb_useful ++;
min = (std::min) (min, att->weight);
max = (std::max) (max, att->weight);
min = (std::min) (min, att->weight());
max = (std::max) (max, att->weight());
}
else
CGAL_CLASSTRAINING_CERR << "-";
att->weight *= factor;
att->weight() *= factor;
}
CGAL_CLASSTRAINING_CERR << std::endl;
CGAL_CLASSTRAINING_CERR << att->id() << " useful in "
@ -626,18 +623,18 @@ public:
if (nb_useful < 2)
{
att_train.back().skipped = true;
att->weight = 0.;
best_weights[j] = att->weight;
att->weight() = 0.;
best_weights[j] = att->weight();
}
else if (best_weights[j] == 1.)
{
att->weight = 0.5 * (att_train.back().wmin + att_train.back().wmax);
best_weights[j] = att->weight;
att->weight() = 0.5 * (att_train.back().wmin + att_train.back().wmax);
best_weights[j] = att->weight();
++ att_used;
}
else
{
att->weight = best_weights[j];
att->weight() = best_weights[j];
++ att_used;
}
estimate_attribute_effect(training_sets, att);
@ -677,7 +674,7 @@ public:
if (j == current_att_changed)
continue;
m_attributes[j]->weight = best_weights[j];
m_attributes[j]->weight() = best_weights[j];
estimate_attribute_effect(training_sets, m_attributes[j]);
if (attribute_useful(m_attributes[j]))
nb_used ++;
@ -685,7 +682,7 @@ public:
Attribute_handle current_att = m_attributes[current_att_changed];
const Attribute_training& tr = att_train[current_att_changed];
current_att->weight = tr.wmin;
current_att->weight() = tr.wmin;
for (std::size_t j = 0; j < nb_trials_per_attribute; ++ j)
{
estimate_attribute_effect(training_sets, current_att);
@ -709,11 +706,11 @@ public:
for (std::size_t k = 0; k < m_attributes.size(); ++ k)
{
Attribute_handle att = m_attributes[k];
best_weights[k] = att->weight;
best_weights[k] = att->weight();
}
}
current_att->weight *= tr.factor;
current_att->weight() *= tr.factor;
}
++ current_att_changed;
@ -722,7 +719,7 @@ public:
for (std::size_t i = 0; i < best_weights.size(); ++ i)
{
Attribute_handle att = m_attributes[i];
att->weight = best_weights[i];
att->weight() = best_weights[i];
}
estimate_attributes_effects(training_sets);
@ -735,16 +732,16 @@ public:
{
Attribute_handle att = m_attributes[i];
CGAL_CLASSTRAINING_CERR << "ATTRIBUTE " << att->id() << ": " << best_weights[i] << std::endl;
att->weight = best_weights[i];
att->weight() = best_weights[i];
Classification::Type::Attribute_effect side = m_types[0]->attribute_effect(att);
bool to_remove = true;
for (std::size_t j = 0; j < m_types.size(); ++ j)
{
Type_handle ctype = m_types[j];
if (ctype->attribute_effect(att) == Classification::Type::FAVORED_ATT)
if (ctype->attribute_effect(att) == Classification::Type::FAVORING)
CGAL_CLASSTRAINING_CERR << " * Favored for ";
else if (ctype->attribute_effect(att) == Classification::Type::PENALIZED_ATT)
else if (ctype->attribute_effect(att) == Classification::Type::PENALIZING)
CGAL_CLASSTRAINING_CERR << " * Penalized for ";
else
CGAL_CLASSTRAINING_CERR << " * Neutral for ";
@ -777,9 +774,9 @@ public:
\brief Adds the input item specified by index `idx` as an inlier
of `class_type` for the training algorithm.
\param class_type Handle to the classification type.
\param class_type %Handle to the classification type.
\param idx Index of the input item.
\param idx %Index of the input item.
*/
bool add_training_index (Type_handle class_type,
std::size_t idx)
@ -805,7 +802,7 @@ public:
\brief Adds input items specified by a range of indices as
inliers of `class_type` for the training algorithm.
\param class_type Handle to the classification type.
\param class_type %Handle to the classification type.
\param first Iterator to the first index to add
\param beyond Past-the-end iterator
@ -856,7 +853,7 @@ public:
m_effect_table = std::vector<std::vector<Attribute_effect> >
(m_types.size(), std::vector<Attribute_effect> (m_attributes.size(),
Classification::Type::NEUTRAL_ATT));
Classification::Type::NEUTRAL));
for (std::size_t i = 0; i < m_effect_table.size (); ++ i)
for (std::size_t j = 0; j < m_effect_table[i].size (); ++ j)
@ -875,13 +872,13 @@ private:
double out = 0.;
for (std::size_t i = 0; i < m_effect_table[class_type].size(); ++ i)
{
if (m_attributes[i]->weight == 0.)
if (m_attributes[i]->weight() == 0.)
continue;
if (m_effect_table[class_type][i] == Classification::Type::FAVORED_ATT)
if (m_effect_table[class_type][i] == Classification::Type::FAVORING)
out += m_attributes[i]->favored (pt_index);
else if (m_effect_table[class_type][i] == Classification::Type::PENALIZED_ATT)
else if (m_effect_table[class_type][i] == Classification::Type::PENALIZING)
out += m_attributes[i]->penalized (pt_index);
else if (m_effect_table[class_type][i] == Classification::Type::NEUTRAL_ATT)
else if (m_effect_table[class_type][i] == Classification::Type::NEUTRAL)
out += m_attributes[i]->ignored (pt_index);
}
return out;
@ -924,11 +921,11 @@ private:
}
sd[j] = std::sqrt (sd[j] / training_sets[j].size());
if (mean[j] - sd[j] > 0.5)
ctype->set_attribute_effect (att, Classification::Type::FAVORED_ATT);
ctype->set_attribute_effect (att, Classification::Type::FAVORING);
else if (mean[j] + sd[j] < 0.5)
ctype->set_attribute_effect (att, Classification::Type::PENALIZED_ATT);
ctype->set_attribute_effect (att, Classification::Type::PENALIZING);
else
ctype->set_attribute_effect (att, Classification::Type::NEUTRAL_ATT);
ctype->set_attribute_effect (att, Classification::Type::NEUTRAL);
}
}

View File

@ -20,7 +20,6 @@
%
% ----------------------------------------------------------------------------
@article{ cgal:afh-pdecm-02,
author = "P. K. Agarwal and E. Flato and D. Halperin",
title = "Polygon Decomposition for Efficient Construction of {Minkowski} Sums",
@ -977,6 +976,15 @@ note = {\url{ttp://hal.inria.fr/inria-00090522}}
, pages = "209--225"
}
@article{cgal:hws-fsso3-16,
title={Fast semantic segmentation of 3D point clouds with strongly varying density},
author={Hackel, Timo and Wegner, Jan D and Schindler, Konrad},
journal={ISPRS Annals of the Photogrammetry, Remote Sensing and Spatial Information Sciences, Prague, Czech Republic},
volume={3},
pages={177--184},
year={2016}
}
@book{ cgal:hw-vrml2h-96
,author = {Jed Hartman and Josie Wernecke}
,title = {The {VRML} 2.0 Handbook: Building Moving Worlds on the
@ -1038,6 +1046,15 @@ note = {\url{ttp://hal.inria.fr/inria-00090522}}
,pages = "307--320"
}
@book{ cgal:l-mrfmi-09,
author = {Li, Stan Z.},
title = {Markov Random Field Modeling in Image Analysis},
year = {2009},
isbn = {9781848002784},
edition = {3rd},
publisher = {Springer Publishing Company, Incorporated}
}
@inproceedings { cgal:l-nmdgp-05,
AUTHOR = {Bruno Levy},
TITLE = {Numerical Methods for Digital Geometry Processing},

View File

@ -1395,7 +1395,7 @@ EXTRA_SEARCH_MAPPINGS =
# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
# generate Latex output.
GENERATE_LATEX = NO
GENERATE_LATEX = YES
# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be

View File

@ -793,15 +793,15 @@ public Q_SLOTS:
// 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));
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)
if (eff == CGAL::Classification::Type::PENALIZING)
class_rows[i].effect->setCurrentIndex(0);
else if (eff == CGAL::Classification::Type::NEUTRAL_ATT)
else if (eff == CGAL::Classification::Type::NEUTRAL)
class_rows[i].effect->setCurrentIndex(1);
else
class_rows[i].effect->setCurrentIndex(2);
@ -824,11 +824,11 @@ public Q_SLOTS:
if (att == Scene_point_set_classification_item::Attribute_handle())
return;
att->weight = std::tan ((CGAL_PI/2.) * v / 1001.);
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.);
class_rows[i].effect->setEnabled(att->weight() != 0.);
}
void on_effect_changed (int v)
@ -854,19 +854,19 @@ public Q_SLOTS:
if (v == 0)
{
classification_item->types()[i].first->set_attribute_effect
(att, CGAL::Classification::Type::PENALIZED_ATT);
(att, CGAL::Classification::Type::PENALIZING);
// std::cerr << " penalized for ";
}
else if (v == 1)
{
classification_item->types()[i].first->set_attribute_effect
(att, CGAL::Classification::Type::NEUTRAL_ATT);
(att, CGAL::Classification::Type::NEUTRAL);
// std::cerr << " neutral for ";
}
else
{
classification_item->types()[i].first->set_attribute_effect
(att, CGAL::Classification::Type::FAVORED_ATT);
(att, CGAL::Classification::Type::FAVORING);
// std::cerr << " favored for ";
}
// std::cerr << classification_item->types()[i].first->id() << std::endl;

View File

@ -210,9 +210,9 @@ void Scene_point_set_classification_item::compute_normals_and_vertices() const
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.);
colors_points.push_back (m_points->point_set()->red(*it));
colors_points.push_back (m_points->point_set()->green(*it));
colors_points.push_back (m_points->point_set()->blue(*it));
}
}
else if (index_color == 1) // classif
@ -262,8 +262,8 @@ void Scene_point_set_classification_item::compute_normals_and_vertices() const
else
{
Attribute_handle att = m_psc->get_attribute(index_color - 3);
double weight = att->weight;
att->weight = att->max;
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)
{
@ -271,7 +271,7 @@ void Scene_point_set_classification_item::compute_normals_and_vertices() const
colors_points.push_back (ramp.g(att->normalized(*it)));
colors_points.push_back (ramp.b(att->normalized(*it)));
}
att->weight = weight;
att->weight() = weight;
}
for (Point_set::const_iterator it = m_points->point_set()->first_selected();
@ -519,7 +519,7 @@ void Scene_point_set_classification_item::train()
return;
}
m_psc->training(m_nb_trials);
m_psc->train(m_nb_trials);
m_psc->run();
m_helper->info();

View File

@ -49,9 +49,9 @@ class SCENE_POINT_SET_CLASSIFICATION_ITEM_EXPORT Scene_point_set_classification_
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) }};
Color out = {{ (unsigned char)(255 * pm.ps->red(i)),
(unsigned char)(255 * pm.ps->green(i)),
(unsigned char)(255 * pm.ps->blue(i)) }};
return out;
}
@ -257,7 +257,8 @@ class SCENE_POINT_SET_CLASSIFICATION_ITEM_EXPORT Scene_point_set_classification_
return;
}
m_helper->save (filename, *m_psc);
std::ofstream f (filename);
m_helper->save (f, *m_psc);
}
void load_config(const char* filename)
@ -275,13 +276,14 @@ class SCENE_POINT_SET_CLASSIFICATION_ITEM_EXPORT Scene_point_set_classification_
bool echo;
boost::tie (echo_map, echo) = m_points->point_set()->template property_map<boost::uint8_t>("echo");
std::ifstream f (filename);
if (!normals && !colors && !echo)
m_helper = new Helper (filename, *m_psc,
m_helper = new Helper (f, *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_helper = new Helper (f, *m_psc,
m_points->point_set()->begin(),
m_points->point_set()->end(),
m_points->point_set()->point_map(),
@ -289,14 +291,14 @@ class SCENE_POINT_SET_CLASSIFICATION_ITEM_EXPORT Scene_point_set_classification_
CGAL::Empty_property_map<Iterator, Color>(),
echo_map);
else if (!normals && colors && !echo)
m_helper = new Helper (filename, *m_psc,
m_helper = new Helper (f, *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_helper = new Helper (f, *m_psc,
m_points->point_set()->begin(),
m_points->point_set()->end(),
m_points->point_set()->point_map(),
@ -304,13 +306,13 @@ class SCENE_POINT_SET_CLASSIFICATION_ITEM_EXPORT Scene_point_set_classification_
Color_map(m_points->point_set()),
echo_map);
else if (normals && !colors && !echo)
m_helper = new Helper (filename, *m_psc,
m_helper = new Helper (f, *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_helper = new Helper (f, *m_psc,
m_points->point_set()->begin(),
m_points->point_set()->end(),
m_points->point_set()->point_map(),
@ -318,14 +320,14 @@ class SCENE_POINT_SET_CLASSIFICATION_ITEM_EXPORT Scene_point_set_classification_
CGAL::Empty_property_map<Iterator, Color>(),
echo_map);
else if (normals && colors && !echo)
m_helper = new Helper (filename, *m_psc,
m_helper = new Helper (f, *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_helper = new Helper (f, *m_psc,
m_points->point_set()->begin(),
m_points->point_set()->end(),
m_points->point_set()->point_map(),

View File

@ -348,21 +348,26 @@ make_property_map(const std::vector<T>& v)
return make_property_map(&v[0]);
}
/// Empty property map that only returns the default value type
///
/// \ingroup PkgProperty_map
/// Property map that only returns the default value type
/// \cgalModels `ReadablePropertyMap`
///
/// \endcond
template<class InputIterator, class ValueType>
struct Empty_property_map{
struct Default_property_map{
const ValueType default_value;
typedef typename InputIterator::value_type key_type;
typedef boost::readable_property_map_tag category;
Default_property_map(const Value_Type& default_value) : default_value (default_value) { }
/// 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(); }
};
/// \endcond
} // namespace CGAL