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>
14 template <typename Shape>
16 createCalculusFromShapeBorder(const KSpace& kspace, const Shape& shape)
23 trace.beginBlock("extracting surfels");
25 typedef KSpace::SurfelSet MySurfelSet;
26 typedef DGtal::SurfelAdjacency<KSpace::dimension> MySurfelAdjacency;
27 typedef DGtal::SetOfSurfels<KSpace, MySurfelSet> MySetOfSurfels;
28 typedef std::vector<SCell> MySCellsVector;
29 typedef std::vector<MySCellsVector> MyConnectedSCells;
31 const MySurfelAdjacency surfel_adjacency(true);
32 const MySetOfSurfels set_of_surfels(kspace, surfel_adjacency);
33 MyConnectedSCells connected_scells;
34 DGtal::Surfaces<KSpace>::extractAllConnectedSCell(connected_scells, kspace, surfel_adjacency, shape, false);
35 trace.info() << "connected_components_size=" << connected_scells.size() << endl;
36 ASSERT( !connected_scells.empty() );
38 const MyConnectedSCells::const_iterator max_connected_scells = std::max_element(connected_scells.begin(), connected_scells.end(),
39 [](const MySCellsVector& aa, const MySCellsVector& bb) { return aa.size() < bb.size(); });
40 ASSERT( max_connected_scells != connected_scells.end() );
41 trace.info() << "scells_size=" << max_connected_scells->size() << endl;
45 trace.beginBlock("creating calculus");
47 typedef DGtal::DiscreteExteriorCalculusFactory<DGtal::EigenLinearAlgebraBackend> CalculusFactory;
48 const Calculus calculus = CalculusFactory::createFromNSCells<2>(max_connected_scells->begin(), max_connected_scells->end());
49 trace.info() << "calculus=" << calculus << endl;
52 const Calculus::PrimalForm2 primal_areas = calculus.hodge<0, DUAL>()*Calculus::DualForm0::ones(calculus);
53 const Calculus::DualForm2 dual_areas = calculus.hodge<0, PRIMAL>()*Calculus::PrimalForm0::ones(calculus);
54 const double primal_area = primal_areas.myContainer.array().sum();
55 const double dual_area = dual_areas.myContainer.array().sum();
56 trace.info() << "primal_area=" << primal_area << endl;
57 trace.info() << "dual_area=" << dual_area << endl;
58 ASSERT( primal_area == dual_area );
66 template <typename Shape>
68 computeFaceNormals(const Calculus& calculus, const Shape& shape, const double radius)
74 trace.beginBlock("estimating normals");
76 typedef DGtal::Z3i::RealVector RealVector;
77 typedef std::vector<RealVector> RealVectors;
79 const KSpace& kspace = calculus.myKSpace;
81 const auto buildFlatVector = [&kspace, &calculus](const RealVectors& real_vectors)
83 ASSERT( real_vectors.size() == calculus.kFormLength(2, PRIMAL) );
84 const int nsurfels = real_vectors.size();
85 FlatVector vectors(3*real_vectors.size());
87 for (const RealVector& real_vector : real_vectors)
89 for (int dim=0; dim<3; dim++)
90 vectors[index+nsurfels*dim] = real_vector[dim];
96 const Calculus::SCells& surfels = calculus.getIndexedSCells<2, PRIMAL>();
98 trace.info() << "radius=" << radius << endl;
100 RealVectors nii_normals_estimations;
102 typedef DGtal::Z3i::Space Space;
103 typedef DGtal::functors::IINormalDirectionFunctor<Space> IINormalFunctor;
104 typedef DGtal::IntegralInvariantCovarianceEstimator<KSpace, Shape, IINormalFunctor> IINormalEstimator;
106 IINormalEstimator nii_estimator(kspace, shape);
107 nii_estimator.setParams(radius);
108 nii_estimator.init(1, surfels.begin(), surfels.end());
110 nii_estimator.eval(surfels.begin(), surfels.end(), std::back_inserter(nii_normals_estimations));
111 trace.info() << "nii_estimations_size=" << nii_normals_estimations.size() << endl;
112 ASSERT( nii_normals_estimations.size() == surfels.size() );
115 RealVectors nt_normals_estimations;
117 typedef DGtal::Z3i::Space Space;
118 typedef DGtal::SurfelAdjacency<KSpace::dimension> MySurfelAdjacency;
119 typedef KSpace::SurfelSet MySurfelSet;
120 typedef DGtal::SetOfSurfels<KSpace, MySurfelSet> MySetOfSurfels;
121 typedef DGtal::DigitalSurface<MySetOfSurfels> MyDigitalSurface;
122 typedef DGtal::ExactPredicateLpSeparableMetric<Space,2> MyMetric;
123 typedef DGtal::CanonicSCellEmbedder<KSpace> MyCanonicSCellEmbedder;
124 typedef DGtal::functors::ElementaryConvolutionNormalVectorEstimator<SCell, MyCanonicSCellEmbedder> MySurfelFunctor;
125 typedef RealVector::Component MyScalar;
126 typedef DGtal::functors::HatFunction<MyScalar> MyHatFunctor;
127 typedef DGtal::LocalEstimatorFromSurfelFunctorAdapter<MySetOfSurfels, MyMetric, MySurfelFunctor, MyHatFunctor> TrivialNormalEstimator;
129 const MySurfelAdjacency surfel_adjacency(true);
130 MySetOfSurfels surfels_set(kspace, surfel_adjacency);
131 std::copy(surfels.begin(), surfels.end(), std::inserter(surfels_set.surfelSet(), surfels_set.surfelSet().begin()));
132 const MyDigitalSurface digital_surface(surfels_set);
133 trace.info() << "digital_surface_size=" << digital_surface.size() << endl;
135 const MyHatFunctor hat_functor(1., radius);
136 const MyCanonicSCellEmbedder canonic_embedder(kspace);
137 MySurfelFunctor surfel_functor(canonic_embedder, 1.);
138 const MyMetric metric;
140 TrivialNormalEstimator nt_estimator;
141 nt_estimator.attach(digital_surface);
142 nt_estimator.setParams(metric, surfel_functor, hat_functor, radius);
143 nt_estimator.init(1, surfels.begin(), surfels.end());
145 nt_estimator.eval(surfels.begin(), surfels.end(), std::back_inserter(nt_normals_estimations));
146 trace.info() << "nt_estimations_size=" << nt_normals_estimations.size() << endl;
147 ASSERT( nt_normals_estimations.size() == surfels.size() );
150 RealVectors::iterator nt_normals_estimations_iter = nt_normals_estimations.begin();
151 for (RealVector& normal : nii_normals_estimations)
153 if (nt_normals_estimations_iter->dot(normal) > 0) normal = -normal;
154 nt_normals_estimations_iter++;
159 return buildFlatVector(nii_normals_estimations);
162 template <typename Shape>
163 std::tuple<Calculus, FlatVector>
164 initCalculusAndNormalsWithNoise(const KSpace& kspace, const Shape& shape, const double radius, const double noise)
169 if (noise <= 0) return initCalculusAndNormals(kspace, shape, radius);
171 typedef DGtal::Z3i::Domain Domain;
172 const Domain domain(kspace.lowerBound(), kspace.upperBound());
173 trace.info() << "noise=" << noise << endl;
174 trace.info() << "domain=" << domain << endl;
176 typedef DGtal::KanungoNoise<Shape, Domain> KanungoPredicate;
177 typedef DGtal::functors::DomainPredicate<Domain> DomainPredicate;
178 typedef DGtal::functors::BinaryPointPredicate<DomainPredicate, KanungoPredicate, DGtal::functors::AndBoolFct2> NoisyShape;
179 const KanungoPredicate kanungo_pred(shape, domain, noise);
180 const DomainPredicate domain_pred(domain);
181 const DGtal::functors::AndBoolFct2 and_functor = DGtal::functors::AndBoolFct2();
182 const NoisyShape noisy_shape(domain_pred, kanungo_pred, and_functor);
184 return initCalculusAndNormals(kspace, noisy_shape, radius);
187 template <typename Shape>
188 std::tuple<Calculus, FlatVector>
189 initCalculusAndNormals(const KSpace& kspace, const Shape& shape, const double radius)
191 Calculus calculus = createCalculusFromShapeBorder(kspace, shape);
192 FlatVector normals = computeFaceNormals(calculus, shape, radius);
193 return std::make_tuple(calculus, normals);