32#include "DGtal/base/Common.h"
33#include "DGtal/base/BasicFunctors.h"
34#include "DGtal/kernel/SpaceND.h"
35#include "DGtal/kernel/domains/HyperRectDomain.h"
36#include "DGtal/images/ImageSelector.h"
37#include "DGtal/images/IntervalForegroundPredicate.h"
38#include "DGtal/topology/KhalimskySpaceND.h"
39#include "DGtal/topology/DigitalSurface.h"
40#include "DGtal/topology/SetOfSurfels.h"
41#include "DGtal/io/viewers/PolyscopeViewer.h"
42#include "DGtal/io/readers/PointListReader.h"
43#include "DGtal/io/readers/GenericReader.h"
45#include "DGtal/io/readers/DicomReader.h"
47#include "DGtal/io/Color.h"
48#include "DGtal/io/colormaps/GradientColorMap.h"
103int main(
int argc,
char** argv )
105 typedef SpaceND<3,int> Space;
106 typedef KhalimskySpaceND<3,int> KSpace;
107 typedef HyperRectDomain<Space> Domain;
108 typedef ImageSelector<Domain, unsigned char>::Type Image;
109 typedef DigitalSetSelector< Domain, BIG_DS+HIGH_BEL_DS >::Type DigitalSet;
110 typedef SurfelAdjacency<KSpace::dimension> MySurfelAdjacency;
114 app.description(
"Display the boundary of a volume file by using PolyscopeViewer. The mode specifies if you wish to see surface elements (BDRY), the inner voxels (INNER) or the outer voxels (OUTER) that touch the boundary. \n \t Example: 3dVolBoundaryViewer $DGtal/examples/samples/lobster.vol -m 60");
115 std::string inputFileName;
116 DGtal::int64_t rescaleInputMin {0};
117 DGtal::int64_t rescaleInputMax {255};
118 int dicomMin {-1000};
120 int thresholdMin {0};
121 int thresholdMax {255};
122 std::string mode {
"INNER"};
124 app.add_option(
"-i,--input,1", inputFileName,
"vol file (.vol, .longvol .p3d, .pgm3d and if DGTAL_WITH_ITK is selected: dicom, dcm, mha, mhd). For longvol, dicom, dcm, mha or mhd formats, the input values are linearly scaled between 0 and 255." )
126 ->check(CLI::ExistingFile);
128 app.add_option(
"--thresholdMin,-m", thresholdMin,
"threshold min (excluded) to define binary shape.");
129 app.add_option(
"--thresholdMax,-M", thresholdMax,
"threshold max (included) to define binary shape.");
131 app.add_option(
"--dicomMin",dicomMin,
"set minimum density threshold on Hounsfield scale" );
132 app.add_option(
"--dicomMax",dicomMin,
"set maximum density threshold on Hounsfield scale" );
134 app.add_option(
"--mode", mode,
"set mode for display: INNER: inner voxels, OUTER: outer voxels, BDRY: surfels" )
135 -> check(CLI::IsMember({
"INNER",
"OUTER",
"BDRY"}));
138 app.get_formatter()->column_width(40);
139 CLI11_PARSE(app, argc, argv);
143 string extension = inputFileName.substr(inputFileName.find_last_of(
".") + 1);
144 if(extension!=
"vol" && extension !=
"p3d" && extension !=
"pgm3D" && extension !=
"pgm3d" && extension !=
"sdp" && extension !=
"pgm"
149 trace.info() <<
"File extension not recognized: "<< extension << std::endl;
153 if(extension==
"vol" || extension==
"pgm3d" || extension==
"pgm3D"
158 trace.beginBlock(
"Loading image into memory." );
160 typedef DGtal::functors::Rescaling<int ,unsigned char > RescalFCT;
161 Image image = extension ==
"dcm" ? DicomReader< Image, RescalFCT >::importDicom( inputFileName,
165 GenericReader<Image>::import( inputFileName );
167 Image image = GenericReader<Image>::import (inputFileName );
169 trace.info() <<
"Image loaded: "<<image<< std::endl;
173 trace.beginBlock(
"Construct the Khalimsky space from the image domain." );
174 Domain domain = image.domain();
176 bool space_ok = ks.init( domain.lowerBound(), domain.upperBound(),
true );
179 trace.error() <<
"Error in the Khamisky space construction."<<std::endl;
186 trace.beginBlock(
"Wrapping a digital set around image. " );
187 typedef functors::IntervalForegroundPredicate<Image> ThresholdedImage;
188 ThresholdedImage thresholdedImage( image, thresholdMin, thresholdMax );
193 trace.beginBlock(
"Extracting boundary by scanning the space. " );
194 typedef KSpace::SurfelSet SurfelSet;
195 typedef SetOfSurfels< KSpace, SurfelSet > MySetOfSurfels;
196 typedef DigitalSurface< MySetOfSurfels > MyDigitalSurface;
197 MySurfelAdjacency surfAdj(
true );
198 MySetOfSurfels theSetOfSurfels( ks, surfAdj );
199 Surfaces<KSpace>::sMakeBoundary( theSetOfSurfels.surfelSet(),
200 ks, thresholdedImage,
202 domain.upperBound() );
203 MyDigitalSurface digSurf( theSetOfSurfels );
204 trace.info() <<
"Digital surface has " << digSurf.size() <<
" surfels."
210 trace.beginBlock(
"Displaying everything. " );
211 PolyscopeViewer<Space,KSpace> viewer(ks);
212 viewer.allowReuseList =
true;
213 typedef MyDigitalSurface::ConstIterator ConstIterator;
214 if ( mode ==
"BDRY" )
216 viewer.drawAsSimplified();
217 for ( ConstIterator it = digSurf.begin(), itE = digSurf.end(); it != itE; ++it )
218 viewer << ks.unsigns( *it );
219 }
else if ( mode ==
"INNER" )
220 for ( ConstIterator it = digSurf.begin(), itE = digSurf.end(); it != itE; ++it )
221 viewer << ks.sCoords( ks.sDirectIncident( *it, ks.sOrthDir( *it ) ) );
222 else if ( mode ==
"OUTER" )
223 for ( ConstIterator it = digSurf.begin(), itE = digSurf.end(); it != itE; ++it )
224 viewer << ks.sCoords( ks.sIndirectIncident( *it, ks.sOrthDir( *it ) ) );
226 trace.error() <<
"Warning display mode (" << mode <<
") not implemented." << std::endl;
227 trace.error() <<
"The display will be empty." << std::endl;