DGtalTools 2.0.0
Loading...
Searching...
No Matches
3dVolMarchingCubes.cpp
1
31#include <iostream>
32#include <queue>
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>
48
49
50#include "CLI11.hpp"
51
53
54using namespace DGtal;
55using namespace Z3i;
56
58
115int main( int argc, char** argv )
116{
118
119 // parse command line using CLI ----------------------------------------------
120 CLI::App app;
121 std::string inputFileName;
122 std::string outputFileName {"marching-cubes.off"};
123 double noise;
124 double threshold {1.0};
125 unsigned int intAdjacency = 0;
126
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)." )
129 ->required()
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.");
135
136 app.get_formatter()->column_width(40);
137 CLI11_PARSE(app, argc, argv);
138 // END parse command line using CLI ----------------------------------------------
139
140
141
142 bool addNoise=false;
143 if (noiseOpt->count() > 0 )
144 {
145 addNoise=true;
146 }
148
150 trace.beginBlock( "Reading vol file into an image." );
151 typedef ImageSelector < Domain, int>::Type Image;
152 Image image = VolReader<Image>::importVol(inputFileName);
153
154 typedef functors::SimpleThresholdForegroundPredicate<Image> ThresholdedImage;
155 ThresholdedImage thresholdedImage( image, threshold );
156 trace.endBlock();
158
159
161 trace.beginBlock( "Construct the Khalimsky space from the image domain." );
162 KSpace ks;
163 bool space_ok =
164 ks.init( image.domain().lowerBound(), image.domain().upperBound(), true );
165 if (!space_ok)
166 {
167 trace.error() << "Error in the Khamisky space construction."<<std::endl;
168 return 2;
169 }
170 trace.endBlock();
172
174 typedef SurfelAdjacency<KSpace::dimension> MySurfelAdjacency;
175 MySurfelAdjacency surfAdj( intAdjacency ); // interior in all directions.
177
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 );
184
185 if (addNoise)
186 {
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,
192 kanungo, false);
193 if( vectConnectedSCell.size() == 0 )
194 {
195 trace.error()<< "No surface component exists. Please check the vol file --min and --max parameters." << std::endl;
196 return 3;
197 }
198
199 trace.info()<<vectConnectedSCell.size()<<" components."<<std::endl;
200
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() );
209 }
210 else
211 Surfaces<KSpace>::sMakeBoundary(
212 theSetOfSurfels.surfelSet(), ks, thresholdedImage,
213 image.domain().lowerBound(), image.domain().upperBound() );
214
215 MyDigitalSurface digSurf( theSetOfSurfels );
216 trace.info() << "Digital surface has " << digSurf.size() << " surfels."
217 << std::endl;
218 trace.endBlock();
220
221
223 trace.beginBlock( "Making OFF surface. " );
224 // Describes how voxels are embedded into Euclidean space.
225 typedef CanonicEmbedder< Space > MyEmbedder;
226 // Describes how the centroid surface elements is placed in-between embedded voxels.
227 typedef ImageLinearCellEmbedder< KSpace, Image, MyEmbedder > CellEmbedder;
228 CellEmbedder cellEmbedder;
229 MyEmbedder trivialEmbedder;
230
231 // The +0.5 is to avoid isosurface going exactly through a voxel
232 // center, especially for binary volumes.
233
234 //Making sure that we probe inside the domain.
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));
239
240 std::ofstream out( outputFileName.c_str() );
241 if (addNoise)
242 {
243 if ( out.good() )
244 digSurf.exportSurfaceAs3DOFF( out );
245 else
246 {
247 trace.error()<<"IO error while opening the output file"<<std::endl;
248 exit(2);
249 }
250 }
251 else
252 {
253 cellEmbedder.init( ks, image, trivialEmbedder,
254 ( (double) threshold ) + 0.5 );
255
256 if ( out.good() )
257 digSurf.exportEmbeddedSurfaceAs3DOFF( out, cellEmbedder );
258 else
259 {
260 trace.error()<<"IO error while opening the output file"<<std::endl;
261 exit(2);
262 }
263 }
264
265 out.close();
266 trace.endBlock();
268 return 0;
269}
270
Definition ATu0v1.h:57