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"
129void missingParam ( std::string param )
131 trace.error() <<
" Parameter: "<<param<<
" is required..";
132 trace.info() <<std::endl;
137int main (
int argc,
char**argv )
142 std::string filename;
143 std::string outputFileName;
144 unsigned int level {0};
146 unsigned int neighborhood {10};
147 double normExport {1.0};
149 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");
150 app.add_option(
"-i,--input,1",filename,
"Input vol file.")->required()->check(CLI::ExistingFile);
151 app.add_option(
"-o,--output,2",outputFileName,
"Output file.")->required();
152 app.add_option(
"--level,-l",level,
"Iso-level for the surface construction (default 0).");
153 app.add_option(
"--sigma,-s", sigma,
"Sigma parameter of the Gaussian kernel (default 5.0).");
154 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).");
155 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).");
156 app.add_option(
"--neighborhood,-n", neighborhood,
"Size of the neighborhood for the convolution (distance on surfel graph, default 10).");
158 app.get_formatter()->column_width(40);
159 CLI11_PARSE(app, argc, argv);
162 typedef ImageSelector < Z3i::Domain, unsigned char>::Type Image;
163 Image image = VolReader<Image>::importVol ( filename );
165 trace.info() <<image<<std::endl;
167 functors::SimpleThresholdForegroundPredicate<Image> simplePredicate ( image, level );
170 bool space_ok = ks.init ( image.domain().lowerBound(),
171 image.domain().upperBound(),
true );
174 trace.error() <<
"Error in the Khamisky space construction."<<std::endl;
178 typedef SurfelAdjacency<KSpace::dimension> MySurfelAdjacency;
179 MySurfelAdjacency surfAdj (
true );
182 typedef LightImplicitDigitalSurface<KSpace, functors::SimpleThresholdForegroundPredicate<Image> > MyDigitalSurfaceContainer;
183 typedef DigitalSurface<MyDigitalSurfaceContainer> MyDigitalSurface;
184 SCell bel = Surfaces<KSpace>::findABel ( ks, simplePredicate );
186 MyDigitalSurfaceContainer* ptrSurfContainer =
187 new MyDigitalSurfaceContainer ( ks, simplePredicate, surfAdj, bel );
188 MyDigitalSurface digSurf ( ptrSurfContainer );
189 MyDigitalSurface::ConstIterator it = digSurf.begin();
192 typedef CanonicDigitalSurfaceEmbedder<MyDigitalSurface> SurfaceEmbedder;
193 SurfaceEmbedder surfaceEmbedder ( digSurf );
196 typedef typename MyDigitalSurface::Surfel Surfel;
197 typedef DGtal::functors::GaussianKernel GaussianFunctor;
198 typedef DGtal::functors::ElementaryConvolutionNormalVectorEstimator<Surfel, CanonicSCellEmbedder<KSpace>> Functor;
199 typedef LocalEstimatorFromSurfelFunctorAdapter<
200 MyDigitalSurfaceContainer,
201 LpMetric<Z3i::Space>,
202 Functor, GaussianFunctor> MyGaussianEstimator;
206 GaussianFunctor Gkernel(sigma);
207 LpMetric<Z3i::Space> l1(1.0);
208 CanonicSCellEmbedder<KSpace> embedder(digSurf.container().space());
209 Functor estimator(embedder, 1.0);
211 MyGaussianEstimator myNormalEstimatorG;
212 myNormalEstimatorG.attach(digSurf);
213 myNormalEstimatorG.setParams(l1, estimator, Gkernel, neighborhood);
216 typedef DigitalSurfaceEmbedderWithNormalVectorEstimator<SurfaceEmbedder,MyGaussianEstimator> SurfaceEmbedderWithGaussianNormal;
217 SurfaceEmbedderWithGaussianNormal mySurfelEmbedderG ( surfaceEmbedder, myNormalEstimatorG );
220 myNormalEstimatorG.init ( 1.0, digSurf.begin(), digSurf.end() );
222 trace.info() <<
"Generating the NOFF surface "<< std::endl;
223 ofstream out2 ( ( outputFileName +
".off" ).c_str() );
225 digSurf.exportAs3DNOFF ( out2 ,mySurfelEmbedderG );
228 trace.info() <<
"Generating the polar coordinates file"<< std::endl;
229 ofstream out3 ( ( outputFileName +
".txt" ).c_str() );
232 MyGaussianEstimator::Quantity res;
233 for ( MyDigitalSurface::ConstIterator it =digSurf.begin(),
234 itend = digSurf.end(); it != itend; ++it )
236 res = myNormalEstimatorG.eval ( it );
238 out3<< acos ( res [2] ) *180.0/M_PI <<
" " << ( atan2 ( res [1], res [0] ) + M_PI ) *180.0/M_PI;
240 if (expOpt->count()>0)
243 out3 <<
" " << mySurfelEmbedderG(*it)[0]
244 <<
" " << mySurfelEmbedderG(*it)[1]
245 <<
" " << mySurfelEmbedderG(*it)[2] <<
" "
246 << mySurfelEmbedderG(*it)[0]+res[0] <<
" "
247 << mySurfelEmbedderG(*it)[1]+res[1] <<
" "
248 << mySurfelEmbedderG(*it)[2]+res[2];