DGtalTools  1.2.0
surface_extract.ih
1 
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>
14 
15 template <typename Shape>
16 Calculus
17 createCalculusFromShapeBorder(const KSpace& kspace, const Shape& shape)
18 {
19  using DGtal::trace;
20  using std::endl;
21  using DGtal::PRIMAL;
22  using DGtal::DUAL;
23 
24  trace.beginBlock("extracting surfels");
25 
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;
31 
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() );
38 
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;
43 
44  trace.endBlock();
45 
46  trace.beginBlock("creating calculus");
47 
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;
51 
52  {
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 );
60  }
61 
62  trace.endBlock();
63 
64  return calculus;
65 }
66 
67 template <typename Shape>
68 FlatVector
69 computeFaceNormals(const Calculus& calculus, const Shape& shape, const double radius)
70 {
71  using DGtal::trace;
72  using std::endl;
73  using DGtal::PRIMAL;
74 
75  trace.beginBlock("estimating normals");
76 
77  typedef DGtal::Z3i::RealVector RealVector;
78  typedef std::vector<RealVector> RealVectors;
79 
80  const KSpace& kspace = calculus.myKSpace;
81 
82  const auto buildFlatVector = [&kspace, &calculus](const RealVectors& real_vectors)
83  {
84  ASSERT( real_vectors.size() == calculus.kFormLength(2, PRIMAL) );
85  const int nsurfels = real_vectors.size();
86  FlatVector vectors(3*real_vectors.size());
87  int index = 0;
88  for (const RealVector& real_vector : real_vectors)
89  {
90  for (int dim=0; dim<3; dim++)
91  vectors[index+nsurfels*dim] = real_vector[dim];
92  index ++;
93  }
94  return vectors;
95  };
96 
97  const Calculus::SCells& surfels = calculus.getIndexedSCells<2, PRIMAL>();
98 
99  trace.info() << "radius=" << radius << endl;
100 
101  RealVectors nii_normals_estimations;
102  {
103  typedef DGtal::Z3i::Space Space;
104  typedef DGtal::functors::IINormalDirectionFunctor<Space> IINormalFunctor;
105  typedef DGtal::IntegralInvariantCovarianceEstimator<KSpace, Shape, IINormalFunctor> IINormalEstimator;
106 
107  IINormalEstimator nii_estimator(kspace, shape);
108  nii_estimator.setParams(radius);
109  nii_estimator.init(1, surfels.begin(), surfels.end());
110 
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() );
114  }
115 
116  RealVectors nt_normals_estimations;
117  {
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;
129 
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;
135 
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);
140 
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());
145 
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() );
149  }
150 
151  RealVectors::iterator nt_normals_estimations_iter = nt_normals_estimations.begin();
152  for (RealVector& normal : nii_normals_estimations)
153  {
154  if (nt_normals_estimations_iter->dot(normal) > 0) normal = -normal;
155  nt_normals_estimations_iter++;
156  }
157 
158  trace.endBlock();
159 
160  return buildFlatVector(nii_normals_estimations);
161 }
162 
163 template <typename Shape>
164 std::tuple<Calculus, FlatVector>
165 initCalculusAndNormalsWithNoise(const KSpace& kspace, const Shape& shape, const double radius, const double noise)
166 {
167  using DGtal::trace;
168  using std::endl;
169 
170  if (noise <= 0) return initCalculusAndNormals(kspace, shape, radius);
171 
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;
176 
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);
184 
185  return initCalculusAndNormals(kspace, noisy_shape, radius);
186 }
187 
188 template <typename Shape>
189 std::tuple<Calculus, FlatVector>
190 initCalculusAndNormals(const KSpace& kspace, const Shape& shape, const double radius)
191 {
192  Calculus calculus = createCalculusFromShapeBorder(kspace, shape);
193  FlatVector normals = computeFaceNormals(calculus, shape, radius);
194  return std::make_tuple(calculus, normals);
195 }
196 
197