DGtalTools 2.0.0
Loading...
Searching...
No Matches
homotopicThinning3D.cpp
1
30#include <iostream>
31#include <queue>
32
33#include "DGtal/io/Color.h"
34#include "DGtal/shapes/Shapes.h"
35#include "DGtal/helpers/StdDefs.h"
36#include "DGtal/io/viewers/PolyscopeViewer.h"
37#include "DGtal/io/readers/PointListReader.h"
38
39#include "DGtal/io/readers/GenericReader.h"
40#include "DGtal/images/imagesSetsUtils/SetFromImage.h"
41#include "DGtal/images/SimpleThresholdForegroundPredicate.h"
42#include "DGtal/images/ImageSelector.h"
43
44#include "CLI11.hpp"
45
46#include "DGtal/geometry/volumes/distance/DistanceTransformation.h"
47
49
50using namespace std;
51using namespace DGtal;
52using namespace Z3i;
53
54
56
105void missingParam ( std::string param )
106{
107 trace.error() <<" Parameter: "<<param<<" is required..";
108 trace.info() <<std::endl;
109 exit ( 1 );
110}
111
112
113int main( int argc, char** argv )
114{
115 // parse command line using CLI ----------------------------------------------
116 CLI::App app;
117 std::string inputFileName;
118 std::string exportSDPName;
119 std::string fixedPointSDPName;
120 double min {0};
121 double max {255};
122
123 std::vector<int> vectFixedPoints;
124
125 app.description("Applies an homotopic thinning of a 3d image file (vol,longvol,pgm3d...) with 3D viewer. \n Basic usage: \t homotopicThinning3D [options] --input <3dImageFileName> {vol,longvol,pgm3d...} \n Usage by forcing point to be left by the thinning: \n homotopicThinning3D --input ${DGtal}/examples/samples/Al.100.vol --fixedPoints 56 35 5 56 61 5 57 91 38 58 8 38 45 50 97 \n");
126 app.add_option("-i,--input,1", inputFileName, "Input volumetric file (.vol, .pgm3d or p3d)" )
127 ->required()
128 ->check(CLI::ExistingFile);
129 app.add_option("--min,-m", min, "Minimum (excluded) value for threshold.");
130 app.add_option("--max,-M", max, "Maximum (included) value for threshold.");
131 app.add_option("--exportSDP,-e",exportSDPName, "Export the resulting set of points in a simple (sequence of discrete point (sdp)).");
132 app.add_option("--fixedPoints",vectFixedPoints, "defines the coordinates of points which should not be removed.");
133 app.add_option("--fixedPointSDP,-s",fixedPointSDPName, "use fixed points from a file.")
134 ->check(CLI::ExistingFile);
135
136
137 app.get_formatter()->column_width(40);
138 CLI11_PARSE(app, argc, argv);
139 // END parse command line using CLI ----------------------------------------------
140
141
142 typedef ImageSelector < Z3i::Domain, unsigned char>::Type Image;
143 Image image = GenericReader<Image>::import ( inputFileName );
144
145 trace.beginBlock("DT Computation");
146 typedef functors::IntervalForegroundPredicate<Image> Predicate;
147 Predicate aPredicate(image, min, max );
148
149 const Z3i::L2Metric aMetric{};
150 DistanceTransformation<Z3i::Space, Predicate , Z3i::L2Metric> dt(image.domain(), aPredicate, aMetric );
151 trace.endBlock();
152 trace.info() <<image<<std::endl;
153
154 // Domain creation from two bounding points.
155 trace.beginBlock("Constructing Set");
156 DigitalSet shape_set( image.domain() );
157 DigitalSet fixedSet( image.domain() );
158
159 // Get the optional fixed points
160 if(vectFixedPoints.size() > 0){
161 if(vectFixedPoints.size()%3==0){
162 for( unsigned int i=0; i < vectFixedPoints.size()-2; i=i+3)
163 {
164 Z3i::Point pt(vectFixedPoints.at(i), vectFixedPoints.at(i+1), vectFixedPoints.at(i+2));
165 fixedSet.insertNew(pt);
166 }
167 }
168 else
169 {
170 trace.error()<< " The coordinates should be 3d coordinates, ignoring fixedPoints option." << std::endl;
171 }
172 }
173
174 if(fixedPointSDPName != "")
175 {
176 std::vector<Z3i::Point> vPt = PointListReader<Z3i::Point>::getPointsFromFile(fixedPointSDPName);
177 for( auto &p: vPt)
178 {
179 fixedSet.insert(p);
180 }
181 }
182
183 SetFromImage<DigitalSet>::append<Image>(shape_set, image, min, max );
184 trace.info() << shape_set<<std::endl;
185 trace.endBlock();
186
187 trace.beginBlock("Computing skeleton");
188 // (6,18), (18,6), (26,6) seem ok.
189 // (6,26) gives sometimes weird results (but perhaps ok !).
190 Object26_6 shape( dt26_6, shape_set );
191 int nb_simple=0;
192 int layer = 1;
193 std::queue<DigitalSet::Iterator> Q;
194 do
195 {
196 trace.info() << "Layer: "<< layer << std::endl;
197 int nb=0;
198 DigitalSet & S = shape.pointSet();
199
200 trace.progressBar(0, (double)S.size());
201 for ( DigitalSet::Iterator it = S.begin(); it != S.end(); ++it )
202 {
203 if ( nb % 100 == 0 ) trace.progressBar((double)nb, (double)S.size());
204 nb++;
205 if (dt( *it ) <= layer)
206 {
207 if ( shape.isSimple( *it ) )
208 Q.push( it );
209 }
210 }
211 trace.progressBar( (double)S.size(), (double)S.size() );
212 nb_simple = 0;
213 while ( ! Q.empty() )
214 {
215 DigitalSet::Iterator it = Q.front();
216 Q.pop();
217 if ( shape.isSimple( *it ) && fixedSet.find(*it) == fixedSet.end() )
218 {
219 S.erase( *it );
220 ++nb_simple;
221 }
222 }
223 trace.info() << "Nb simple points : "<<nb_simple<< " " << std::endl;
224 ++layer;
225 }
226 while ( nb_simple != 0 );
227 trace.endBlock();
228
229 DigitalSet & S = shape.pointSet();
230
231 trace.info() << "Skeleton--> "<<S<<std::endl;
232
233 // Display by using two different list to manage OpenGL transparency.
234 polyscope::options::programName = "DGtalTools: homotopicThinning3D";
235
236 PolyscopeViewer<> viewer;
237
238
239
240 viewer << Color(25,25,255, 255);
241 viewer << S ;
242 viewer << Color(255,25,255, 255);
243 viewer << fixedSet;
244 viewer << Color(250, 0,0, 25);
245 viewer << shape_set;
246
247 if (exportSDPName != "")
248 {
249 std::ofstream out;
250 out.open(exportSDPName.c_str());
251 for (auto &p : S)
252 {
253 out << p[0] << " " << p[1] << " " << p[2] << std::endl;
254 }
255 }
256 viewer.show();
257 return 0;
258
259}
260// //
262
263
Definition ATu0v1.h:57