DGtalTools 2.1.0
Loading...
Searching...
No Matches
volSegment.cpp
1
29#include <iostream>
30#include <fstream>
31
32#include "DGtal/base/Common.h"
33#include "DGtal/helpers/StdDefs.h"
34#include "DGtal/topology/helpers/Surfaces.h"
35
36#include "DGtal/images/ImageContainerBySTLVector.h"
37#include "DGtal/io/readers/GenericReader.h"
38#include "DGtal/io/writers/GenericWriter.h"
39
40#include "DGtal/images/IntervalForegroundPredicate.h"
41#include <DGtal/topology/SetOfSurfels.h>
42#include "DGtal/topology/DigitalSurface.h"
43#include "DGtal/topology/helpers/Surfaces.h"
44
45#include "CLI11.hpp"
46
47
48using namespace std;
49using namespace DGtal;
50
51
106typedef ImageContainerBySTLVector < Z3i::Domain, unsigned char > Image3D;
107typedef ImageContainerBySTLVector < Z3i::Domain, DGtal::uint64_t > Image3DI;
108
109typedef Z3i::KSpace::SurfelSet SurfelSet;
110typedef SetOfSurfels< Z3i::KSpace, SurfelSet > MySetOfSurfels;
111
112
113std::vector<unsigned int> getHistoFromImage(const Image3D &image){
114 const Image3D::Domain &imgDom = image.domain();
115 std::vector<unsigned int> vectHisto(UCHAR_MAX);
116 for(Image3D::Domain::ConstIterator it=imgDom.begin(); it!= imgDom.end(); ++it){
117 vectHisto[image(*it)]++;
118 }
119 return vectHisto;
120}
121
122
123unsigned int
124getOtsuThreshold(const Image3D &image){
125 std::vector<unsigned int> histo = getHistoFromImage(image);
126 unsigned int imageSize = image.domain().size();
127 unsigned int sumA = 0;
128 unsigned int sumB = imageSize;
129 unsigned int muA=0;
130 unsigned int muB=0;
131 unsigned int sumMuAll= 0;
132 for( unsigned int t=0; t< histo.size();t++){
133 sumMuAll+=histo[t]*t;
134 }
135
136 unsigned int thresholdRes=0;
137 double valMax=0.0;
138 for( unsigned int t=0; t< histo.size(); t++){
139 sumA+=histo[t];
140 if(sumA==0)
141 continue;
142 sumB=imageSize-sumA;
143 if(sumB==0){
144 break;
145 }
146
147 muA+=histo[t]*t;
148 muB=sumMuAll-muA;
149 double muAr=muA/(double)sumA;
150 double muBr=muB/(double)sumB;
151 double sigma= (double)sumA*(double)sumB*(muAr-muBr)*(muAr-muBr);
152 if(valMax<=sigma){
153 valMax=sigma;
154 thresholdRes=t;
155 }
156 }
157 return thresholdRes;
158}
159
160
161template<typename TImageOutput>
162void
163applySegmentation(TImageOutput &imageResuSegmentation, const Image3D &inputImage, CLI::Option *labelOpt, int maxTh, int minTh) {
164 functors::IntervalForegroundPredicate<Image3D> simplePredicate ( inputImage, minTh, maxTh );
165 SurfelAdjacency< Z3i::KSpace::dimension > SAdj ( true );
166 Z3i::KSpace K;
167 bool space_ok = K.init( inputImage.domain().lowerBound(), inputImage.domain().upperBound(), false );
168 if(!space_ok){
169 trace.error() << "problem initializing 3d space" << endl;
170 }
171
172 std::vector< std::vector<Z3i::SCell > > vectConnectedSCell;
173 Surfaces<Z3i::KSpace>::extractAllConnectedSCell(vectConnectedSCell,K, SAdj, simplePredicate, false);
174 trace.progressBar(0, vectConnectedSCell.size());
175 for(unsigned int i = 0; i<vectConnectedSCell.size(); i++)
176 {
177 trace.progressBar(i, vectConnectedSCell.size());
178 MySetOfSurfels aSet(K, SAdj);
179 Z3i::Point lowerPoint, upperPoint;
180 Z3i::Point p1;
181 Z3i::Point p2;
182 for(std::vector<Z3i::SCell>::const_iterator it= vectConnectedSCell.at(i).begin(); it != vectConnectedSCell.at(i).end(); ++it)
183 {
184 aSet.surfelSet().insert(aSet.surfelSet().begin(), *it);
185 unsigned int orth_dir = K.sOrthDir( *it );
186 p1 = K.sCoords( K.sIncident( *it, orth_dir, true ) );
187 p2 = K.sCoords( K.sIncident( *it, orth_dir, false ) );
188 if(p1[0] < lowerPoint[0]) lowerPoint[0]= p1[0];
189 if(p1[1] < lowerPoint[1]) lowerPoint[1]= p1[1];
190 if(p1[2] < lowerPoint[2]) lowerPoint[2]= p1[2];
191
192 if(p1[0] > upperPoint[0]) upperPoint[0]= p1[0];
193 if(p1[1] > upperPoint[1]) upperPoint[1]= p1[1];
194 if(p1[2] > upperPoint[2]) upperPoint[2]= p1[2];
195
196 if(p2[0] < lowerPoint[0]) lowerPoint[0]= p2[0];
197 if(p2[1] < lowerPoint[1]) lowerPoint[1]= p2[1];
198 if(p2[2] < lowerPoint[2]) lowerPoint[2]= p2[2];
199
200 if(p2[0] > upperPoint[0]) upperPoint[0]= p2[0];
201 if(p2[1] > upperPoint[1]) upperPoint[1]= p2[1];
202 if(p2[2] > upperPoint[2]) upperPoint[2]= p2[2];
203
204 }
205
206 Z3i::KSpace kRestr ;
207 kRestr.init( lowerPoint, upperPoint, false );
208 if(simplePredicate(p2)){
209 DGtal::Surfaces<Z3i::KSpace>::uFillInterior( kRestr, aSet.surfelPredicate(),
210 imageResuSegmentation,
211 i, false, false);
212 }else if (labelOpt->count() > 0){
213 DGtal::Surfaces<Z3i::KSpace>::uFillExterior( kRestr, aSet.surfelPredicate(),
214 imageResuSegmentation,
215 i+1, false, false);
216 }
217 }
218 trace.progressBar(vectConnectedSCell.size(), vectConnectedSCell.size());
219 trace.info() << std::endl;
220}
221
222
223
224
225
226int main( int argc, char** argv )
227{
228
229 // parse command line using CLI ----------------------------------------------
230 CLI::App app;
231 std::string inputFileName;
232 std::string outputFileName {"result.vol"};
233 bool labelBackground {false};
234 int minTh {0};
235 int maxTh {255};
236 bool outputTypeInt {false};
237
238 app.description("Segment volumetric file from a simple threshold which can be set automatically from the otsu estimation.\n The segmentation result is given by an integer label given in the resulting image. Example:\n volSegment ${DGtal}/examples/samples/lobster.vol segmentation.vol \n");
239 app.add_option("-i,--input,1", inputFileName, "volumetric input file (.vol, .pgm, .pgm3d, .longvol)." )
240 ->required()
241 ->check(CLI::ExistingFile);
242 app.add_option("-o,--output,2", outputFileName, "volumetric output file (.vol, .pgm, .pgm3d, .longvol)");
243
244 app.add_flag("--outputTypeUInt", outputTypeInt, "to specify the output image type (unsigned int) instead using the default unsigned char. If this flag is selected you have to check the output file format type (longvol, or an ITK image type if the DGtal DGTAL_WITH_ITK option is selected).");
245
246 auto labelOpt = app.add_flag("--labelBackground",labelBackground, "option to define a label to regions associated to object background.");
247 app.add_option("-m,--thresholdMin",minTh, "min threshold (if not given the max threshold is computed with Otsu algorithm)." );
248 auto maxThOpt = app.add_option("-M,--thresholdMax", maxTh, "max threshold" );
249
250
251 app.get_formatter()->column_width(40);
252 CLI11_PARSE(app, argc, argv);
253 // END parse command line using CLI ----------------------------------------------
254
255 trace.info() << "Reading input file " << inputFileName ;
256 Image3D inputImage = DGtal::GenericReader<Image3D>::import(inputFileName);
257 trace.info() << " [done] " << std::endl ;
258
259 std::ofstream outStream;
260 outStream.open(outputFileName.c_str());
261 if(maxThOpt->count()==0){
262 maxTh = getOtsuThreshold(inputImage);
263 trace.info() << "maximal threshold value not specified, using Otsu value: " << maxTh << std::endl;
264 }
265 trace.info() << "Processing image to output file " << outputFileName << std::endl;
266
267
268 if (outputTypeInt)
269 {
270 Image3DI imageResuSegmentation(inputImage.domain());
271 applySegmentation(imageResuSegmentation, inputImage, labelOpt, maxTh, minTh);
272 GenericWriter<Image3DI>::exportFile(outputFileName, imageResuSegmentation);
273
274 }else{
275 Image3D imageResuSegmentation(inputImage.domain());
276 applySegmentation(imageResuSegmentation, inputImage, labelOpt, maxTh, minTh);
277 GenericWriter<Image3D>::exportFile(outputFileName, imageResuSegmentation);
278 }
279 return 0;
280}
281
Definition ATu0v1.h:57