78 #include <unordered_map>
80 #include <DGtal/io/viewers/Viewer3D.h>
82 #include <DGtal/base/Common.h>
83 #include <DGtal/helpers/StdDefs.h>
84 #include <DGtal/io/Color.h>
85 #include <DGtal/io/readers/GenericReader.h>
86 #include <DGtal/io/writers/GenericWriter.h>
87 #include "DGtal/images/imagesSetsUtils/SetFromImage.h"
88 #include "DGtal/images/SimpleThresholdForegroundPredicate.h"
89 #include "DGtal/images/ImageSelector.h"
90 #include "DGtal/images/imagesSetsUtils/ImageFromSet.h"
92 #include <DGtal/topology/SurfelAdjacency.h>
93 #include <DGtal/topology/CubicalComplex.h>
94 #include <DGtal/topology/CubicalComplexFunctions.h>
95 #include <DGtal/io/boards/Board3D.h>
97 #include <DGtal/topology/VoxelComplex.h>
98 #include <DGtal/topology/VoxelComplexFunctions.h>
99 #include "DGtal/topology/NeighborhoodConfigurations.h"
100 #include "DGtal/topology/tables/NeighborhoodTables.h"
103 #include "DGtal/geometry/volumes/distance/ExactPredicateLpSeparableMetric.h"
104 #include "DGtal/geometry/volumes/distance/VoronoiMap.h"
105 #include "DGtal/geometry/volumes/distance/DistanceTransformation.h"
110 using namespace DGtal;
114 int main(
int argc,
char*
const argv[]){
118 std::string inputFileName;
119 std::string sk_string {
"1isthmus"};
120 string select_string {
"dmax"};
121 string foreground {
"black"};
122 string outputFilenameImg;
123 string outputFilenameSDP;
124 string outputFilenameOBJ;
125 string outputFilenameInputOBJ;
127 int thresholdMin {0};
128 int thresholdMax {255};
130 bool profile {
false};
131 bool verbose {
false};
132 bool visualize {
false};
133 bool useInputImgToExp {
false};
135 app.description(
"Compute the thinning of a volume using the CriticalKernels framework\nBasic usage: criticalKernelsThinning3D --input <volFileName> --skel <ulti,end, 1isthmus, isthmus> --select [ -f <white,black> -m <minlevel> -M <maxlevel> -v ] [--persistence <value> ] --persistence <value> ] \n options for --skel {ulti end 1isthmus isthmus} \n options for --select = {dmax random first} \n Example: \n criticalKernelsThinning3D --input ${DGtal}/examples/samples/Al.100.vol --select dmax --skel 1isthmus --persistence 1 --visualize --verbose --exportImage ./Al100_dmax_1isthmus_p1.vol \n");
136 app.add_option(
"-i,--input,1", inputFileName,
"Input vol file." )
138 ->check(CLI::ExistingFile);
140 app.add_option(
"--skel,-s", sk_string,
"Type of skeletonization. Options: 1isthmus, isthmus, end, ulti.",
true )
141 -> check(CLI::IsMember({
"ulti",
"end",
"isthmus",
"1isthmus"}));
142 app.add_option(
"--select,-c", select_string,
"Select the ordering for skeletonization. Options: dmax, random, first",
true)
143 -> check(CLI::IsMember({
"random",
"dmax",
"first"}));
144 app.add_option(
"--foreground,-f",foreground,
"Foreground color in binary image",
true )
145 -> check(CLI::IsMember({
"white",
"black"}));
146 app.add_option(
"--thresholdMin,-m", thresholdMin,
"Threshold min (excluded) to define binary shape",
true );
147 app.add_option(
"--thresholdMax,-M", thresholdMax,
"Threshold max (included) to define binary shape",
true );
148 app.add_option(
"--persistence,-p",persistence,
"Persistence value, implies use of persistence algorithm if p>=1",
true )
149 ->check(CLI::PositiveNumber);
150 app.add_flag(
"--profile", profile,
"Profile algorithm");
151 app.add_flag(
"--verbose,-v",verbose,
"Verbose output");
152 app.add_option(
"--exportImage,-o",outputFilenameImg,
"Export the resulting set of points to a image compatible with GenericWriter.");
153 app.add_option(
"--exportSDP,-e",outputFilenameSDP,
"Export the resulting set of points in a simple (sequence of discrete point (sdp))." );
154 app.add_option(
"--exportOBJ,-O",outputFilenameOBJ,
"Export the resulting set of points in an OBJ file." );
155 app.add_option(
"--exportInputOBJ,-I",outputFilenameInputOBJ,
"Export the input set of points in an OBJ file." );
156 #ifdef WITH_QGLVIEWER
157 app.add_flag(
"--visualize,-t", visualize,
"Visualize result in viewer");
159 app.add_flag(
"--useInputImgToExp,-k", useInputImgToExp,
"Use input image type to export result (allowing to keep same domain (and same image spacing when using ITK)).");
161 app.get_formatter()->column_width(40);
162 CLI11_PARSE(app, argc, argv);
168 std::cout <<
"Skel: " << sk_string << std::endl;
169 std::cout <<
"Select: " << select_string << std::endl;
170 std::cout <<
"Persistence: " << persistence << std::endl;
171 std::cout <<
"Input: " << inputFileName << std::endl;
189 thresholdMin, thresholdMax);
197 std::unordered_set< typename Domain::Point> >;
198 using Complex = DGtal::VoxelComplex<KSpace>;
200 auto & sk = sk_string;
204 image.
domain().upperBound() + d1 ,
true);
211 boost::dynamic_bitset<> isthmus_table;
214 else if (sk ==
"1isthmus")
216 auto pointMap = *functions::mapZeroPointNeighborhoodToConfigurationMask<Point>();
221 std::function< bool(
const Complex&,
const Cell&) > Skel ;
222 if (sk ==
"ulti") Skel = skelUltimate<Complex>;
223 else if (sk ==
"end") Skel = skelEnd<Complex>;
224 else if (sk ==
"isthmus" || sk ==
"1isthmus")
225 Skel = [&isthmus_table, &pointMap](
const Complex & fc,
226 const Complex::Cell & c){
227 return skelWithTable(isthmus_table, pointMap, fc, c);
229 else throw std::runtime_error(
"Invalid skel string");
230 auto start = std::chrono::system_clock::now();
240 DT dt(image.
domain(), image_set, l3);
243 std::function< std::pair<typename Complex::Cell, typename Complex::Data>(
const Complex::Clique&) > Select ;
244 auto & sel = select_string;
245 if (sel ==
"random") Select = selectRandom<Complex>;
246 else if (sel ==
"first") Select = selectFirst<Complex>;
247 else if (sel ==
"dmax"){
249 [&dt](
const Complex::Clique & clique){
250 return selectMaxValue<DT, Complex>(dt,clique);
252 }
else throw std::runtime_error(
"Invalid skel string");
256 if (persistence == 0)
257 vc_new = asymetricThinningScheme< Complex >(
258 vc, Select, Skel, verbose);
260 vc_new = persistenceAsymetricThinningScheme< Complex >(
261 vc, Select, Skel, persistence, verbose);
264 auto end = std::chrono::system_clock::now();
265 auto elapsed = std::chrono::duration_cast<std::chrono::seconds> (end - start) ;
266 if (profile) std::cout <<
"Time elapsed: " << elapsed.count() << std::endl;
270 vc_new.dumpVoxels(thin_set);
271 const auto & all_set = image_set;
273 if (outputFilenameSDP !=
"")
276 out.open(outputFilenameSDP.c_str());
277 for (
auto &p : thin_set)
279 out << p[0] <<
" " << p[1] <<
" " << p[2] << std::endl;
285 if ( outputFilenameInputOBJ !=
"" )
292 board.setFillColor(
Color( 200, 200, 255, 255 ) );
293 for (
auto p : all_set )
299 if ( all_set.find( q ) == all_set.end() )
302 if ( all_set.find( q ) == all_set.end() )
303 board << ks.
sIncident( voxel, k,
false );
306 board.saveOBJ( outputFilenameInputOBJ );
310 if ( outputFilenameOBJ !=
"" )
318 for (
auto p : thin_set )
324 if ( thin_set.find( q ) == thin_set.end() )
327 if ( thin_set.find( q ) == thin_set.end() )
328 board << ks.
sIncident( voxel, k,
false );
331 board.saveOBJ( outputFilenameOBJ );
334 if (outputFilenameImg !=
"")
337 std::cout <<
"outputFilename" << outputFilenameImg << std::endl;
339 unsigned int foreground_value = 255;
340 if (useInputImgToExp){
343 image >> outputFilenameImg;
346 thin_image >> outputFilenameImg;
349 #ifdef WITH_QGLVIEWER
353 char** argv(
nullptr);
354 QApplication app(argc, argv);
356 viewer.setWindowTitle(
"criticalKernelsThinning3D");
359 viewer.setFillColor(
Color(255, 255, 255, 255));
363 viewer.setFillColor(
Color(40, 200, 55, 10));
366 viewer << Viewer3D<>::updateDisplay;
int main(int argc, char **argv)
const Domain & domain() const
void setValue(const Point &aPoint, const Value &aValue)
typename Self::Domain Domain
typename Self::Point Point
bool init(const Point &lower, const Point &upper, bool isClosed)
SCell sSpel(Point p, Sign sign=POS) const
SCell sIncident(const SCell &c, Dimension k, bool up) const
static Self diagonal(Component val=1)
void beginBlock(const std::string &keyword="")
HyperRectDomain< Space > Domain
DGtal::CountedPtr< boost::dynamic_bitset<> > loadTable(const std::string &input_filename, unsigned int known_size)
const std::string tableSimple26_6
Trace trace(traceWriterTerm)
DGtal::uint32_t Dimension
static TContainer import(const std::string &filename, std::vector< unsigned int > dimSpace=std::vector< unsigned int >())
static Image create(const Set &aSet, const Value &defaultValue, const bool addBorder, typename Set::ConstIterator itBegin, typename Set::ConstIterator itEnd)
static void append(Image &aImage, const Value &defaultValue, typename Set::ConstIterator itBegin, typename Set::ConstIterator itEnd)
std::string className() const