34#include "DGtal/base/Common.h"
36#include "DGtal/topology/CanonicDigitalSurfaceEmbedder.h"
37#include "DGtal/topology/DigitalSurface.h"
38#include "DGtal/topology/DigitalSetBoundary.h"
39#include "DGtal/topology/ImplicitDigitalSurface.h"
40#include "DGtal/topology/LightImplicitDigitalSurface.h"
41#include "DGtal/topology/ExplicitDigitalSurface.h"
42#include "DGtal/topology/LightExplicitDigitalSurface.h"
43#include "DGtal/graph/BreadthFirstVisitor.h"
44#include "DGtal/topology/helpers/FrontierPredicate.h"
45#include "DGtal/topology/helpers/BoundaryPredicate.h"
46#include "DGtal/graph/CUndirectedSimpleLocalGraph.h"
47#include "DGtal/graph/CUndirectedSimpleGraph.h"
49#include "DGtal/io/readers/VolReader.h"
50#include "DGtal/images/imagesSetsUtils/SetFromImage.h"
51#include "DGtal/images/SimpleThresholdForegroundPredicate.h"
52#include "DGtal/images/ImageSelector.h"
53#include "DGtal/shapes/Shapes.h"
54#include "DGtal/helpers/StdDefs.h"
55#include "DGtal/kernel/CanonicEmbedder.h"
57#include "DGtal/geometry/surfaces/estimation/DigitalSurfaceEmbedderWithNormalVectorEstimator.h"
59#include "DGtal/geometry/surfaces/estimation/LocalEstimatorFromSurfelFunctorAdapter.h"
60#include "DGtal/geometry/surfaces/estimation/estimationFunctors/ElementaryConvolutionNormalVectorEstimator.h"
61#include "DGtal/geometry/volumes/distance/LpMetric.h"
128void missingParam ( std::string param )
130 trace.error() <<
" Parameter: "<<param<<
" is required..";
131 trace.info() <<std::endl;
136int main (
int argc,
char**argv )
141 std::string filename;
142 std::string outputFileName;
143 unsigned int level {0};
145 unsigned int neighborhood {10};
146 double normExport {1.0};
148 app.description(
"Generates normal vector field from a vol file using DGtal library.\n Typical use example:\n \t vol2normalField[options] --input <volFileName> --o <outputFileName>\n");
149 app.add_option(
"-i,--input,1",filename,
"Input vol file.")->required()->check(CLI::ExistingFile);
150 app.add_option(
"-o,--output,2",outputFileName,
"Output file.")->required();
151 app.add_option(
"--level,-l",level,
"Iso-level for the surface construction (default 0).");
152 app.add_option(
"--sigma,-s", sigma,
"Sigma parameter of the Gaussian kernel (default 5.0).");
153 auto expOpt = app.add_flag(
"--exportOriginAndExtremity",
"exports the origin and extremity of the vector fields when exporting the vector field in TXT format (useful to be displayed in other viewer like meshViewer).");
154 app.add_option(
"--vectorsNorm,-N", normExport,
"set the norm of the exported vectors in TXT format (when the extremity points are exported with --exportOriginAndExtremity). By using a negative value you will invert the direction of the vectors (default 1.0).");
155 app.add_option(
"--neighborhood,-n", neighborhood,
"Size of the neighborhood for the convolution (distance on surfel graph, default 10).");
157 app.get_formatter()->column_width(40);
158 CLI11_PARSE(app, argc, argv);
161 typedef ImageSelector < Z3i::Domain, unsigned char>::Type Image;
162 Image image = VolReader<Image>::importVol ( filename );
164 trace.info() <<image<<std::endl;
166 functors::SimpleThresholdForegroundPredicate<Image> simplePredicate ( image, level );
169 bool space_ok = ks.init ( image.domain().lowerBound(),
170 image.domain().upperBound(),
true );
173 trace.error() <<
"Error in the Khamisky space construction."<<std::endl;
177 typedef SurfelAdjacency<KSpace::dimension> MySurfelAdjacency;
178 MySurfelAdjacency surfAdj (
true );
181 typedef LightImplicitDigitalSurface<KSpace, functors::SimpleThresholdForegroundPredicate<Image> > MyDigitalSurfaceContainer;
182 typedef DigitalSurface<MyDigitalSurfaceContainer> MyDigitalSurface;
183 SCell bel = Surfaces<KSpace>::findABel ( ks, simplePredicate );
185 MyDigitalSurfaceContainer* ptrSurfContainer =
186 new MyDigitalSurfaceContainer ( ks, simplePredicate, surfAdj, bel );
187 MyDigitalSurface digSurf ( ptrSurfContainer );
188 MyDigitalSurface::ConstIterator it = digSurf.begin();
191 typedef CanonicDigitalSurfaceEmbedder<MyDigitalSurface> SurfaceEmbedder;
192 SurfaceEmbedder surfaceEmbedder ( digSurf );
195 typedef typename MyDigitalSurface::Surfel Surfel;
196 typedef DGtal::functors::GaussianKernel GaussianFunctor;
197 typedef DGtal::functors::ElementaryConvolutionNormalVectorEstimator<Surfel, CanonicSCellEmbedder<KSpace>> Functor;
198 typedef LocalEstimatorFromSurfelFunctorAdapter<
199 MyDigitalSurfaceContainer,
200 LpMetric<Z3i::Space>,
201 Functor, GaussianFunctor> MyGaussianEstimator;
205 GaussianFunctor Gkernel(sigma);
206 LpMetric<Z3i::Space> l1(1.0);
207 CanonicSCellEmbedder<KSpace> embedder(digSurf.container().space());
208 Functor estimator(embedder, 1.0);
210 MyGaussianEstimator myNormalEstimatorG;
211 myNormalEstimatorG.attach(digSurf);
212 myNormalEstimatorG.setParams(l1, estimator, Gkernel, neighborhood);
215 typedef DigitalSurfaceEmbedderWithNormalVectorEstimator<SurfaceEmbedder,MyGaussianEstimator> SurfaceEmbedderWithGaussianNormal;
216 SurfaceEmbedderWithGaussianNormal mySurfelEmbedderG ( surfaceEmbedder, myNormalEstimatorG );
219 myNormalEstimatorG.init ( 1.0, digSurf.begin(), digSurf.end() );
221 trace.info() <<
"Generating the NOFF surface "<< std::endl;
222 ofstream out2 ( ( outputFileName +
".off" ).c_str() );
224 digSurf.exportAs3DNOFF ( out2 ,mySurfelEmbedderG );
227 trace.info() <<
"Generating the polar coordinates file"<< std::endl;
228 ofstream out3 ( ( outputFileName +
".txt" ).c_str() );
231 MyGaussianEstimator::Quantity res;
232 for ( MyDigitalSurface::ConstIterator it =digSurf.begin(),
233 itend = digSurf.end(); it != itend; ++it )
235 res = myNormalEstimatorG.eval ( it );
237 out3<< acos ( res [2] ) *180.0/M_PI <<
" " << ( atan2 ( res [1], res [0] ) + M_PI ) *180.0/M_PI;
239 if (expOpt->count()>0)
242 out3 <<
" " << mySurfelEmbedderG(*it)[0]
243 <<
" " << mySurfelEmbedderG(*it)[1]
244 <<
" " << mySurfelEmbedderG(*it)[2] <<
" "
245 << mySurfelEmbedderG(*it)[0]+res[0] <<
" "
246 << mySurfelEmbedderG(*it)[1]+res[1] <<
" "
247 << mySurfelEmbedderG(*it)[2]+res[2];