77 #include <unordered_map> 79 #include <DGtal/io/viewers/Viewer3D.h> 80 #include <DGtal/base/Common.h> 81 #include <DGtal/helpers/StdDefs.h> 82 #include <DGtal/io/readers/GenericReader.h> 83 #include <DGtal/io/writers/GenericWriter.h> 84 #include "DGtal/images/imagesSetsUtils/SetFromImage.h" 85 #include "DGtal/images/SimpleThresholdForegroundPredicate.h" 86 #include "DGtal/images/ImageSelector.h" 87 #include "DGtal/images/imagesSetsUtils/ImageFromSet.h" 89 #include <DGtal/topology/SurfelAdjacency.h> 90 #include <DGtal/io/boards/Board2D.h> 91 #include <DGtal/topology/CubicalComplex.h> 92 #include <DGtal/topology/CubicalComplexFunctions.h> 94 #include <DGtal/topology/VoxelComplex.h> 95 #include <DGtal/topology/VoxelComplexFunctions.h> 96 #include "DGtal/topology/NeighborhoodConfigurations.h" 97 #include "DGtal/topology/tables/NeighborhoodTables.h" 100 #include "DGtal/geometry/volumes/distance/ExactPredicateLpSeparableMetric.h" 101 #include "DGtal/geometry/volumes/distance/VoronoiMap.h" 102 #include "DGtal/geometry/volumes/distance/DistanceTransformation.h" 107 using namespace DGtal;
111 int main(
int argc,
char*
const argv[]){
115 std::string inputFileName;
116 std::string sk_string {
"1isthmus"};
117 string select_string {
"dmax"};
118 string foreground {
"black"};
119 string outputFilenameImg;
120 string outputFilenameSDP;
122 int thresholdMin {0};
123 int thresholdMax {255};
125 bool profile {
false};
126 bool verbose {
false};
127 bool visualize {
false};
129 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");
130 app.add_option(
"-i,--input,1", inputFileName,
"Input vol file." )
132 ->check(CLI::ExistingFile);
134 app.add_option(
"--skel,-s", sk_string,
"Type of skeletonization. Options: 1isthmus, isthmus, end, ulti.",
true )
135 -> check(CLI::IsMember({
"ulti",
"end",
"isthmus",
"1isthmus"}));
136 app.add_option(
"--select,-c", select_string,
"Select the ordering for skeletonization. Options: dmax, random, first",
true)
137 -> check(CLI::IsMember({
"random",
"dmax",
"first"}));
138 app.add_option(
"--foreground,-f",foreground,
"Foreground color in binary image",
true )
139 -> check(CLI::IsMember({
"white",
"black"}));
140 app.add_option(
"--thresholdMin,-m", thresholdMin,
"Threshold min (excluded) to define binary shape",
true );
141 app.add_option(
"--thresholdMax,-M", thresholdMax,
"Threshold max (included) to define binary shape",
true );
142 app.add_option(
"--persistence,-p",persistence,
"Persistence value, implies use of persistence algorithm if p>=1",
true )
143 ->check(CLI::PositiveNumber);
144 app.add_flag(
"--profile", profile,
"Profile algorithm");
145 app.add_flag(
"--verbose,-v",verbose,
"Verbose output");
146 app.add_option(
"--exportImage,-o",outputFilenameImg,
"Export the resulting set of points to a image compatible with GenericWriter.");
147 app.add_option(
"--exportSDP,-e",outputFilenameSDP,
"Export the resulting set of points in a simple (sequence of discrete point (sdp))." );
148 app.add_flag(
"--visualize,-t", visualize,
"Visualize result in viewer");
150 app.get_formatter()->column_width(40);
151 CLI11_PARSE(app, argc, argv);
157 std::cout <<
"Skel: " << sk_string << std::endl;
158 std::cout <<
"Select: " << select_string << std::endl;
159 std::cout <<
"Persistence: " << persistence << std::endl;
160 std::cout <<
"Input: " << inputFileName << std::endl;
171 thresholdMin, thresholdMax);
179 std::unordered_set< typename Domain::Point> >;
180 using Complex = DGtal::VoxelComplex<KSpace>;
182 auto & sk = sk_string;
185 ks.
init(image.domain().lowerBound() - d1 ,
186 image.domain().upperBound() + d1 ,
true);
193 boost::dynamic_bitset<> isthmus_table;
196 else if (sk ==
"1isthmus")
198 auto pointMap = *functions::mapZeroPointNeighborhoodToConfigurationMask<Point>();
203 std::function< bool(const Complex&, const Cell&) > Skel ;
204 if (sk ==
"ulti") Skel = skelUltimate<Complex>;
205 else if (sk ==
"end") Skel = skelEnd<Complex>;
206 else if (sk ==
"isthmus" || sk ==
"1isthmus")
207 Skel = [&isthmus_table, &pointMap](
const Complex & fc,
208 const Complex::Cell & c){
209 return skelWithTable(isthmus_table, pointMap, fc, c);
211 else throw std::runtime_error(
"Invalid skel string");
212 auto start = std::chrono::system_clock::now();
222 DT dt(image.domain(), image_set, l3);
225 std::function< std::pair<typename Complex::Cell, typename Complex::Data>(
const Complex::Clique&) > Select ;
226 auto & sel = select_string;
227 if (sel ==
"random") Select = selectRandom<Complex>;
228 else if (sel ==
"first") Select = selectFirst<Complex>;
229 else if (sel ==
"dmax"){
231 [&dt](
const Complex::Clique & clique){
232 return selectMaxValue<DT, Complex>(dt,clique);
234 }
else throw std::runtime_error(
"Invalid skel string");
238 if (persistence == 0)
239 vc_new = asymetricThinningScheme< Complex >(
240 vc, Select, Skel, verbose);
242 vc_new = persistenceAsymetricThinningScheme< Complex >(
243 vc, Select, Skel, persistence, verbose);
246 auto end = std::chrono::system_clock::now();
247 auto elapsed = std::chrono::duration_cast<std::chrono::seconds> (end - start) ;
248 if (profile) std::cout <<
"Time elapsed: " << elapsed.count() << std::endl;
252 vc_new.dumpVoxels(thin_set);
253 const auto & all_set = image_set;
255 if (outputFilenameSDP !=
"")
258 out.open(outputFilenameSDP.c_str());
259 for (
auto &p : thin_set)
261 out << p[0] <<
" " << p[1] <<
" " << p[2] << std::endl;
265 if (outputFilenameImg !=
"")
268 std::cout <<
"outputFilename" << outputFilenameImg << std::endl;
270 unsigned int foreground_value = 255;
272 thin_image >> outputFilenameImg;
278 char** argv(
nullptr);
279 QApplication app(argc, argv);
281 viewer.setWindowTitle(
"criticalKernelsThinning3D");
291 viewer << Viewer3D<>::updateDisplay;
virtual void setFillColor(DGtal::Color aColor)
void beginBlock(const std::string &keyword="")
static Self diagonal(Component val=1)
HyperRectDomain< Space > Domain
int main(int argc, char **argv)
static TContainer import(const std::string &filename, std::vector< unsigned int > dimSpace=std::vector< unsigned int >())
DGtal::CountedPtr< boost::dynamic_bitset<> > loadTable(const std::string &input_filename, unsigned int known_size)
const std::string tableSimple26_6
bool init(const Point &lower, const Point &upper, bool isClosed)
Trace trace(traceWriterTerm)
const Domain & domain() const
static Image create(const Set &aSet, const Value &defaultValue, const bool addBorder, typename Set::ConstIterator itBegin, typename Set::ConstIterator itEnd)
typename Self::Domain Domain