- Author(s) of this documentation:
- David Coeurjolly
Part of the Geometry package.
Introduction
Many estimators of local quantities, such as curvature or normal vector field, on a digital surface can be defined locally as a function which associates a quantity to a local surface patch centered at the surfel s. Such local estimators can be characterized by:
- a digital surface in which the computation is performed;
- a functor to call on surfels in the neighborhood;
- a metric to specify the shape of the neighborhood to consider;
- a radius to define the neighborhood (ball for the specified metric);
- as any estimator, a gridstep h.
When evaluating the estimator at a given surfel, neighboring surfels are traversed (using a DistanceBreadthFirstVisitor parametrized by the specified metric) and each surfel is sent to the surfel functor.
Implementation details
In DGtal, we implement this class of estimator using the generic LocalEstimatorsFromSurfel class. Such class is parametrized by the following template parameters:
This class provides three main methods:
- init(h,radius): to init the estimators for a given gridstep and a given kernel neighborhood.
- eval( aSurfelIterator ): the evaluate the functor at aSurfelIterator.
- eval( aSurfelItBegin, aSurfelItEnd): evaluate the estimator on a range of surfels.
The core of the estimators are thus specified in the surfel functor (model of concepts::CLocalEstimatorFromSurfelFunctor). In DGtal, we have defined several functors:
- Advanced:
- Implementing your own surfel patch based estimator is quite simple. Please have a look to concepts::CLocalEstimatorFromSurfelFunctor or the source code of any of its models.
Usage Example
In this section, we give a step by step example (see exampleEstimatorFromSurfelFunctors.cpp) . Let's start by defining a digital surface from a implicit digital ellipse.
using namespace Z3i;
typedef ImplicitDigitalEllipse3<Point> ImplicitDigitalEllipse;
typedef LightImplicitDigitalSurface<KSpace,ImplicitDigitalEllipse> SurfaceContainer;
typedef DigitalSurface< SurfaceContainer >
Surface;
typedef SurfaceContainer::Surfel
Surfel;
Point p1( -10, -10, -10 );
ImplicitDigitalEllipse ellipse( 6.0, 4.5, 3.4 );
SurfaceContainer* surfaceContainer = new SurfaceContainer
(
K, ellipse, SurfelAdjacency<KSpace::dimension>(
true ), bel );
Surface surface( surfaceContainer );
Aim: Represents a set of n-1-cells in a nD space, together with adjacency relation between these cell...
static SCell findABel(const KSpace &K, const PointPredicate &pp, unsigned int nbtries=1000)
SH3::DigitalSurface Surface
We then define some types (note that we use the WITH_CGAL define to make sure that the user has enabled CGAL). Since local functors based on Monge Jet Fitting and CGAL do not require any weigths, we just consider a constant weight functor returning 1.0 for each surfel. For the functors::ElementaryConvolutionNormalVectorEstimator, we consider a Gaussian kernel with \( \sigma=2.0\). Please aslo note that the distance visitor is based on a Euclidean \( l_2\) metric:
#ifdef WITH_CGAL
typedef functors::MongeJetFittingMeanCurvatureEstimator<Surfel, CanonicSCellEmbedder<KSpace> > FunctorMean;
typedef functors::MongeJetFittingNormalVectorEstimator<Surfel, CanonicSCellEmbedder<KSpace> > FunctorNormal;
typedef functors::LinearLeastSquareFittingNormalVectorEstimator<Surfel, CanonicSCellEmbedder<KSpace> > FunctorNormalLeast;
typedef functors::ConstValue<double> ConstFunctor;
typedef LocalEstimatorFromSurfelFunctorAdapter<SurfaceContainer, LpMetric<Z3i::Space>, FunctorGaussian, ConstFunctor> ReporterK;
typedef LocalEstimatorFromSurfelFunctorAdapter<SurfaceContainer, LpMetric<Z3i::Space>, FunctorMean, ConstFunctor> ReporterH;
typedef LocalEstimatorFromSurfelFunctorAdapter<SurfaceContainer, LpMetric<Z3i::Space>, FunctorNormal, ConstFunctor> ReporterNormal;
typedef LocalEstimatorFromSurfelFunctorAdapter<SurfaceContainer, LpMetric<Z3i::Space>, FunctorNormalLeast, ConstFunctor> ReporterNormalLeast;
#endif
typedef functors::ElementaryConvolutionNormalVectorEstimator<Surfel, CanonicSCellEmbedder<KSpace> > FunctorNormalElem;
typedef LocalEstimatorFromSurfelFunctorAdapter<SurfaceContainer, LpMetric<Z3i::Space>,
Aim: Estimates Gaussian curvature using CGAL Jet Fitting and Monge Form.
Aim: defines a functor on double numbers which corresponds to a Gaussian convolution kernel....
We now create the instances for gridstep \( h=1.0 \) and a kernel radius 5.0:
CanonicSCellEmbedder<KSpace> embedder(surface.container().space());
#ifdef WITH_CGAL
FunctorGaussian estimatorK(embedder,1.0);
FunctorMean estimatorH(embedder, 1.0);
FunctorNormal estimatorN(embedder,1.0);
FunctorNormalLeast estimatorL(embedder,1.0);
ConstFunctor constFunctor(1.0);
ReporterK reporterK;
ReporterH reporterH;
ReporterNormal reporterN;
ReporterNormalLeast reporterL;
#endif
LpMetric<Z3i::Space> l2(2.0);
FunctorNormalElem estimatorNormalElem(embedder,1.0);
ReporterNormalElem reporterElem(surface, l2,
estimatorNormalElem, gaussian);
We can now estimate the quantities at a surfel given by an iterator (here, the iterator at surface.begin()):
#ifdef WITH_CGAL
reporterK.attach(surface);
reporterH.attach(surface);
reporterN.attach(surface);
reporterL.attach(surface);
reporterK.init(1, surface.begin(), surface.end());
reporterH.init(1, surface.begin(), surface.end());
reporterN.init(1, surface.begin(), surface.end());
reporterL.init(1, surface.begin(), surface.end());
reporterK.setParams(l2, estimatorK, constFunctor, 5.0);
reporterH.setParams(l2, estimatorH, constFunctor, 5.0);
reporterN.setParams(l2, estimatorN, constFunctor, 5.0);
reporterL.setParams(l2, estimatorL, constFunctor, 5.0);
FunctorGaussian::Quantity valK = reporterK.eval( surface.begin());
FunctorMean::Quantity valH = reporterH.eval( surface.begin());
FunctorNormal::Quantity valN = reporterN.eval( surface.begin());
FunctorNormalLeast::Quantity valL = reporterL.eval( surface.begin());
#endif
reporterElem.attach(surface);
reporterElem.setParams(l2,
estimatorNormalElem, gaussian, 5.0);
reporterElem.init(1.0, surface.begin(), surface.end());
FunctorNormalElem::Quantity valElem = reporterElem.eval( surface.begin());
#ifdef WITH_CGAL
trace.
info() <<
"Gaussian = "<<valK <<std::endl;
trace.
info() <<
"Normal Vector (from Monge form) = "<<valN<< std::endl;
trace.
info() <<
"Normal Vector (linear least square) = "<<valL<< std::endl;
#endif
trace.
info() <<
"Normal Vector (Elementary conv) = "<<valElem<< std::endl;
- See also
- exampleEstimatorFromSurfelFunctors.cpp