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