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/Viewer3D.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"
54 using namespace DGtal;
102 int main(
int argc,
char** argv )
104 typedef SpaceND<3,int> Space;
105 typedef KhalimskySpaceND<3,int> KSpace;
106 typedef HyperRectDomain<Space> Domain;
107 typedef ImageSelector<Domain, unsigned char>::Type Image;
108 typedef DigitalSetSelector< Domain, BIG_DS+HIGH_BEL_DS >::Type DigitalSet;
109 typedef SurfelAdjacency<KSpace::dimension> MySurfelAdjacency;
113 app.description(
"Display the boundary of a volume file by using QGLviewer. 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");
114 std::string inputFileName;
115 DGtal::int64_t rescaleInputMin {0};
116 DGtal::int64_t rescaleInputMax {255};
117 int dicomMin {-1000};
119 int thresholdMin {0};
120 int thresholdMax {255};
121 std::string mode {
"INNER"};
123 app.add_option(
"-i,--input,1", inputFileName,
"vol file (.vol, .longvol .p3d, .pgm3d and if 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." )
125 ->check(CLI::ExistingFile);
127 app.add_option(
"--thresholdMin,-m", thresholdMin,
"threshold min (excluded) to define binary shape.",
true);
128 app.add_option(
"--thresholdMax,-M", thresholdMax,
"threshold max (included) to define binary shape.",
true);
130 app.add_option(
"--dicomMin",dicomMin,
"set minimum density threshold on Hounsfield scale",
true );
131 app.add_option(
"--dicomMax",dicomMin,
"set maximum density threshold on Hounsfield scale",
true );
133 app.add_option(
"--mode", mode,
"set mode for display: INNER: inner voxels, OUTER: outer voxels, BDRY: surfels",
true )
134 -> check(CLI::IsMember({
"INNER",
"OUTER",
"BDRY"}));
137 app.get_formatter()->column_width(40);
138 CLI11_PARSE(app, argc, argv);
142 QApplication application(argc,argv);
144 string extension = inputFileName.substr(inputFileName.find_last_of(
".") + 1);
145 if(extension!=
"vol" && extension !=
"p3d" && extension !=
"pgm3D" && extension !=
"pgm3d" && extension !=
"sdp" && extension !=
"pgm"
150 trace.info() <<
"File extension not recognized: "<< extension << std::endl;
154 if(extension==
"vol" || extension==
"pgm3d" || extension==
"pgm3D"
159 trace.beginBlock(
"Loading image into memory." );
161 typedef DGtal::functors::Rescaling<int ,unsigned char > RescalFCT;
162 Image image = extension ==
"dcm" ? DicomReader< Image, RescalFCT >::importDicom( inputFileName,
166 GenericReader<Image>::import( inputFileName );
168 Image image = GenericReader<Image>::import (inputFileName );
170 trace.info() <<
"Image loaded: "<<image<< std::endl;
174 trace.beginBlock(
"Construct the Khalimsky space from the image domain." );
175 Domain domain = image.domain();
177 bool space_ok = ks.init( domain.lowerBound(), domain.upperBound(),
true );
180 trace.error() <<
"Error in the Khamisky space construction."<<std::endl;
187 trace.beginBlock(
"Wrapping a digital set around image. " );
188 typedef functors::IntervalForegroundPredicate<Image> ThresholdedImage;
189 ThresholdedImage thresholdedImage( image, thresholdMin, thresholdMax );
194 trace.beginBlock(
"Extracting boundary by scanning the space. " );
195 typedef KSpace::SurfelSet SurfelSet;
196 typedef SetOfSurfels< KSpace, SurfelSet > MySetOfSurfels;
197 typedef DigitalSurface< MySetOfSurfels > MyDigitalSurface;
198 MySurfelAdjacency surfAdj(
true );
199 MySetOfSurfels theSetOfSurfels( ks, surfAdj );
200 Surfaces<KSpace>::sMakeBoundary( theSetOfSurfels.surfelSet(),
201 ks, thresholdedImage,
203 domain.upperBound() );
204 MyDigitalSurface digSurf( theSetOfSurfels );
205 trace.info() <<
"Digital surface has " << digSurf.size() <<
" surfels."
211 trace.beginBlock(
"Displaying everything. " );
212 Viewer3D<Space,KSpace> viewer(ks);
213 viewer.setWindowTitle(
"Simple boundary of volume Viewer");
215 typedef MyDigitalSurface::ConstIterator ConstIterator;
216 if ( mode ==
"BDRY" )
218 viewer << SetMode3D(ks.unsigns( *(digSurf.begin()) ).className(),
"Basic");
219 for ( ConstIterator it = digSurf.begin(), itE = digSurf.end(); it != itE; ++it )
220 viewer << ks.unsigns( *it );
221 }
else if ( mode ==
"INNER" )
222 for ( ConstIterator it = digSurf.begin(), itE = digSurf.end(); it != itE; ++it )
223 viewer << ks.sCoords( ks.sDirectIncident( *it, ks.sOrthDir( *it ) ) );
224 else if ( mode ==
"OUTER" )
225 for ( ConstIterator it = digSurf.begin(), itE = digSurf.end(); it != itE; ++it )
226 viewer << ks.sCoords( ks.sIndirectIncident( *it, ks.sOrthDir( *it ) ) );
228 trace.error() <<
"Warning display mode (" << mode <<
") not implemented." << std::endl;
229 trace.error() <<
"The display will be empty." << std::endl;
231 viewer << Viewer3D<>::updateDisplay;
233 return application.exec();