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