2 #include <DGtal/topology/SurfelAdjacency.h>
3 #include <DGtal/topology/helpers/Surfaces.h>
4 #include <DGtal/topology/SetOfSurfels.h>
5 #include <DGtal/topology/DigitalSurface.h>
6 #include <DGtal/dec/DiscreteExteriorCalculusFactory.h>
7 #include <DGtal/geometry/surfaces/estimation/IIGeometricFunctors.h>
8 #include <DGtal/geometry/surfaces/estimation/IntegralInvariantCovarianceEstimator.h>
9 #include <DGtal/geometry/surfaces/estimation/LocalEstimatorFromSurfelFunctorAdapter.h>
10 #include <DGtal/geometry/surfaces/estimation/estimationFunctors/ElementaryConvolutionNormalVectorEstimator.h>
11 #include <DGtal/geometry/volumes/KanungoNoise.h>
12 #include <DGtal/math/ScalarFunctors.h>
13 #include <DGtal/geometry/volumes/distance/LpMetric.h>
15 template <typename Shape>
17 createCalculusFromShapeBorder(const KSpace& kspace, const Shape& shape)
24 trace.beginBlock("extracting surfels");
26 typedef KSpace::SurfelSet MySurfelSet;
27 typedef DGtal::SurfelAdjacency<KSpace::dimension> MySurfelAdjacency;
28 typedef DGtal::SetOfSurfels<KSpace, MySurfelSet> MySetOfSurfels;
29 typedef std::vector<SCell> MySCellsVector;
30 typedef std::vector<MySCellsVector> MyConnectedSCells;
32 const MySurfelAdjacency surfel_adjacency(true);
33 const MySetOfSurfels set_of_surfels(kspace, surfel_adjacency);
34 MyConnectedSCells connected_scells;
35 DGtal::Surfaces<KSpace>::extractAllConnectedSCell(connected_scells, kspace, surfel_adjacency, shape, false);
36 trace.info() << "connected_components_size=" << connected_scells.size() << endl;
37 ASSERT( !connected_scells.empty() );
39 const MyConnectedSCells::const_iterator max_connected_scells = std::max_element(connected_scells.begin(), connected_scells.end(),
40 [](const MySCellsVector& aa, const MySCellsVector& bb) { return aa.size() < bb.size(); });
41 ASSERT( max_connected_scells != connected_scells.end() );
42 trace.info() << "scells_size=" << max_connected_scells->size() << endl;
46 trace.beginBlock("creating calculus");
48 typedef DGtal::DiscreteExteriorCalculusFactory<DGtal::EigenLinearAlgebraBackend> CalculusFactory;
49 const Calculus calculus = CalculusFactory::createFromNSCells<2>(max_connected_scells->begin(), max_connected_scells->end());
50 trace.info() << "calculus=" << calculus << endl;
53 const Calculus::PrimalForm2 primal_areas = calculus.hodge<0, DUAL>()*Calculus::DualForm0::ones(calculus);
54 const Calculus::DualForm2 dual_areas = calculus.hodge<0, PRIMAL>()*Calculus::PrimalForm0::ones(calculus);
55 const double primal_area = primal_areas.myContainer.array().sum();
56 const double dual_area = dual_areas.myContainer.array().sum();
57 trace.info() << "primal_area=" << primal_area << endl;
58 trace.info() << "dual_area=" << dual_area << endl;
59 ASSERT( primal_area == dual_area );
67 template <typename Shape>
69 computeFaceNormals(const Calculus& calculus, const Shape& shape, const double radius)
75 trace.beginBlock("estimating normals");
77 typedef DGtal::Z3i::RealVector RealVector;
78 typedef std::vector<RealVector> RealVectors;
80 const KSpace& kspace = calculus.myKSpace;
82 const auto buildFlatVector = [&kspace, &calculus](const RealVectors& real_vectors)
84 ASSERT( real_vectors.size() == calculus.kFormLength(2, PRIMAL) );
85 const int nsurfels = real_vectors.size();
86 FlatVector vectors(3*real_vectors.size());
88 for (const RealVector& real_vector : real_vectors)
90 for (int dim=0; dim<3; dim++)
91 vectors[index+nsurfels*dim] = real_vector[dim];
97 const Calculus::SCells& surfels = calculus.getIndexedSCells<2, PRIMAL>();
99 trace.info() << "radius=" << radius << endl;
101 RealVectors nii_normals_estimations;
103 typedef DGtal::Z3i::Space Space;
104 typedef DGtal::functors::IINormalDirectionFunctor<Space> IINormalFunctor;
105 typedef DGtal::IntegralInvariantCovarianceEstimator<KSpace, Shape, IINormalFunctor> IINormalEstimator;
107 IINormalEstimator nii_estimator(kspace, shape);
108 nii_estimator.setParams(radius);
109 nii_estimator.init(1, surfels.begin(), surfels.end());
111 nii_estimator.eval(surfels.begin(), surfels.end(), std::back_inserter(nii_normals_estimations));
112 trace.info() << "nii_estimations_size=" << nii_normals_estimations.size() << endl;
113 ASSERT( nii_normals_estimations.size() == surfels.size() );
116 RealVectors nt_normals_estimations;
118 typedef DGtal::Z3i::Space Space;
119 typedef DGtal::SurfelAdjacency<KSpace::dimension> MySurfelAdjacency;
120 typedef KSpace::SurfelSet MySurfelSet;
121 typedef DGtal::SetOfSurfels<KSpace, MySurfelSet> MySetOfSurfels;
122 typedef DGtal::DigitalSurface<MySetOfSurfels> MyDigitalSurface;
123 typedef DGtal::LpMetric<Space> MyMetric;
124 typedef DGtal::CanonicSCellEmbedder<KSpace> MyCanonicSCellEmbedder;
125 typedef DGtal::functors::ElementaryConvolutionNormalVectorEstimator<SCell, MyCanonicSCellEmbedder> MySurfelFunctor;
126 typedef RealVector::Component MyScalar;
127 typedef DGtal::functors::HatFunction<MyScalar> MyHatFunctor;
128 typedef DGtal::LocalEstimatorFromSurfelFunctorAdapter<MySetOfSurfels, MyMetric, MySurfelFunctor, MyHatFunctor> TrivialNormalEstimator;
130 const MySurfelAdjacency surfel_adjacency(true);
131 MySetOfSurfels surfels_set(kspace, surfel_adjacency);
132 std::copy(surfels.begin(), surfels.end(), std::inserter(surfels_set.surfelSet(), surfels_set.surfelSet().begin()));
133 const MyDigitalSurface digital_surface(surfels_set);
134 trace.info() << "digital_surface_size=" << digital_surface.size() << endl;
136 const MyHatFunctor hat_functor(1., radius);
137 const MyCanonicSCellEmbedder canonic_embedder(kspace);
138 MySurfelFunctor surfel_functor(canonic_embedder, 1.);
139 const MyMetric metric(2.0);
141 TrivialNormalEstimator nt_estimator;
142 nt_estimator.attach(digital_surface);
143 nt_estimator.setParams(metric, surfel_functor, hat_functor, radius);
144 nt_estimator.init(1, surfels.begin(), surfels.end());
146 nt_estimator.eval(surfels.begin(), surfels.end(), std::back_inserter(nt_normals_estimations));
147 trace.info() << "nt_estimations_size=" << nt_normals_estimations.size() << endl;
148 ASSERT( nt_normals_estimations.size() == surfels.size() );
151 RealVectors::iterator nt_normals_estimations_iter = nt_normals_estimations.begin();
152 for (RealVector& normal : nii_normals_estimations)
154 if (nt_normals_estimations_iter->dot(normal) > 0) normal = -normal;
155 nt_normals_estimations_iter++;
160 return buildFlatVector(nii_normals_estimations);
163 template <typename Shape>
164 std::tuple<Calculus, FlatVector>
165 initCalculusAndNormalsWithNoise(const KSpace& kspace, const Shape& shape, const double radius, const double noise)
170 if (noise <= 0) return initCalculusAndNormals(kspace, shape, radius);
172 typedef DGtal::Z3i::Domain Domain;
173 const Domain domain(kspace.lowerBound(), kspace.upperBound());
174 trace.info() << "noise=" << noise << endl;
175 trace.info() << "domain=" << domain << endl;
177 typedef DGtal::KanungoNoise<Shape, Domain> KanungoPredicate;
178 typedef DGtal::functors::DomainPredicate<Domain> DomainPredicate;
179 typedef DGtal::functors::BinaryPointPredicate<DomainPredicate, KanungoPredicate, DGtal::functors::AndBoolFct2> NoisyShape;
180 const KanungoPredicate kanungo_pred(shape, domain, noise);
181 const DomainPredicate domain_pred(domain);
182 const DGtal::functors::AndBoolFct2 and_functor = DGtal::functors::AndBoolFct2();
183 const NoisyShape noisy_shape(domain_pred, kanungo_pred, and_functor);
185 return initCalculusAndNormals(kspace, noisy_shape, radius);
188 template <typename Shape>
189 std::tuple<Calculus, FlatVector>
190 initCalculusAndNormals(const KSpace& kspace, const Shape& shape, const double radius)
192 Calculus calculus = createCalculusFromShapeBorder(kspace, shape);
193 FlatVector normals = computeFaceNormals(calculus, shape, radius);
194 return std::make_tuple(calculus, normals);