33#include <boost/program_options/options_description.hpp>
34#include <boost/program_options/parsers.hpp>
35#include <boost/program_options/variables_map.hpp>
36#include <DGtal/io/readers/VolReader.h>
37#include <DGtal/images/ImageSelector.h>
38#include <DGtal/images/SimpleThresholdForegroundPredicate.h>
39#include <DGtal/images/ImageLinearCellEmbedder.h>
40#include <DGtal/shapes/Shapes.h>
41#include <DGtal/kernel/CanonicEmbedder.h>
42#include <DGtal/helpers/StdDefs.h>
43#include <DGtal/topology/helpers/Surfaces.h>
44#include <DGtal/topology/DigitalSurface.h>
45#include <DGtal/topology/SetOfSurfels.h>
46#include <DGtal/geometry/volumes/KanungoNoise.h>
115int main(
int argc,
char** argv )
121 std::string inputFileName;
122 std::string outputFileName {
"marching-cubes.off"};
124 double threshold {1.0};
125 unsigned int intAdjacency = 0;
127 app.description(
"Outputs the isosurface of value <threshold> of the volume <fileName.vol> as an OFF file <output.off>. The <adjacency> (0/1) allows to choose between interior (6,18) and exterior (18,6) adjacency.");
128 app.add_option(
"-i,--input,1", inputFileName,
"the volume file (.vol)." )
130 ->check(CLI::ExistingFile);
131 app.add_option(
"--threshold,-t",threshold,
"the value that defines the isosurface in the image (an integer between 0 and 255).");
132 app.add_option(
"--adjacency,-a",intAdjacency,
"0: interior adjacency, 1: exterior adjacency");
133 app.add_option(
"-o,--output,2", outputFileName,
"the output OFF file that represents the geometry of the isosurface");
134 auto noiseOpt = app.add_option(
"--noise,-n", noise,
"Kanungo noise level in ]0,1[. Note that only the largest connected component is considered and that no specific embedder is used.");
136 app.get_formatter()->column_width(40);
137 CLI11_PARSE(app, argc, argv);
143 if (noiseOpt->count() > 0 )
150 trace.beginBlock(
"Reading vol file into an image." );
151 typedef ImageSelector < Domain, int>::Type Image;
152 Image image = VolReader<Image>::importVol(inputFileName);
154 typedef functors::SimpleThresholdForegroundPredicate<Image> ThresholdedImage;
155 ThresholdedImage thresholdedImage( image, threshold );
161 trace.beginBlock(
"Construct the Khalimsky space from the image domain." );
164 ks.init( image.domain().lowerBound(), image.domain().upperBound(),
true );
167 trace.error() <<
"Error in the Khamisky space construction."<<std::endl;
174 typedef SurfelAdjacency<KSpace::dimension> MySurfelAdjacency;
175 MySurfelAdjacency surfAdj( intAdjacency );
179 trace.beginBlock(
"Extracting boundary by scanning the space. " );
180 typedef KSpace::SurfelSet SurfelSet;
181 typedef SetOfSurfels< KSpace, SurfelSet > MySetOfSurfels;
182 typedef DigitalSurface< MySetOfSurfels > MyDigitalSurface;
183 MySetOfSurfels theSetOfSurfels( ks, surfAdj );
187 trace.info()<<
"Adding some noise."<<std::endl;
188 KanungoNoise<ThresholdedImage, Z3i::Domain> kanungo(thresholdedImage, image.domain(), noise);
189 std::vector< std::vector<SCell > > vectConnectedSCell;
190 trace.info()<<
"Extracting all connected components."<<std::endl;
191 Surfaces<KSpace>::extractAllConnectedSCell( vectConnectedSCell, ks, surfAdj,
193 if( vectConnectedSCell.size() == 0 )
195 trace.error()<<
"No surface component exists. Please check the vol file --min and --max parameters." << std::endl;
199 trace.info()<<vectConnectedSCell.size()<<
" components."<<std::endl;
201 trace.info()<<
"Extracting the largest one."<<std::endl;
202 int cc_max_size_idx = -1;
203 auto it_max = std::max_element( vectConnectedSCell.begin(), vectConnectedSCell.end(),
204 [] (std::vector<SCell >& v1, std::vector<SCell >& v2)
205 { return v1.size() < v2.size(); } );
206 cc_max_size_idx = std::distance( vectConnectedSCell.begin(), it_max );
207 theSetOfSurfels.surfelSet().insert( vectConnectedSCell[ cc_max_size_idx ].begin(),
208 vectConnectedSCell[ cc_max_size_idx ].end() );
211 Surfaces<KSpace>::sMakeBoundary(
212 theSetOfSurfels.surfelSet(), ks, thresholdedImage,
213 image.domain().lowerBound(), image.domain().upperBound() );
215 MyDigitalSurface digSurf( theSetOfSurfels );
216 trace.info() <<
"Digital surface has " << digSurf.size() <<
" surfels."
223 trace.beginBlock(
"Making OFF surface. " );
225 typedef CanonicEmbedder< Space > MyEmbedder;
227 typedef ImageLinearCellEmbedder< KSpace, Image, MyEmbedder > CellEmbedder;
228 CellEmbedder cellEmbedder;
229 MyEmbedder trivialEmbedder;
235 Image largerImage( Domain( image.domain().lowerBound() - KSpace::Vector::diagonal(2),
236 image.domain().upperBound() + KSpace::Vector::diagonal(2)));
237 for(
auto p: image.domain())
238 largerImage.setValue( p, image(p));
240 std::ofstream out( outputFileName.c_str() );
244 digSurf.exportSurfaceAs3DOFF( out );
247 trace.error()<<
"IO error while opening the output file"<<std::endl;
253 cellEmbedder.init( ks, image, trivialEmbedder,
254 ( (
double) threshold ) + 0.5 );
257 digSurf.exportEmbeddedSurfaceAs3DOFF( out, cellEmbedder );
260 trace.error()<<
"IO error while opening the output file"<<std::endl;