76 #include <unordered_map>
78 #include <DGtal/io/viewers/Viewer3D.h>
79 #include <DGtal/base/Common.h>
80 #include <DGtal/helpers/StdDefs.h>
81 #include <DGtal/io/readers/GenericReader.h>
82 #include <DGtal/io/writers/GenericWriter.h>
83 #include "DGtal/images/imagesSetsUtils/SetFromImage.h"
84 #include "DGtal/images/SimpleThresholdForegroundPredicate.h"
85 #include "DGtal/images/ImageSelector.h"
86 #include "DGtal/images/imagesSetsUtils/ImageFromSet.h"
88 #include <DGtal/topology/SurfelAdjacency.h>
89 #include <DGtal/io/boards/Board2D.h>
90 #include <DGtal/topology/CubicalComplex.h>
91 #include <DGtal/topology/CubicalComplexFunctions.h>
93 #include <DGtal/topology/VoxelComplex.h>
94 #include <DGtal/topology/VoxelComplexFunctions.h>
95 #include "DGtal/topology/NeighborhoodConfigurations.h"
96 #include "DGtal/topology/tables/NeighborhoodTables.h"
99 #include <boost/program_options/options_description.hpp>
100 #include <boost/program_options/parsers.hpp>
101 #include <boost/program_options/variables_map.hpp>
103 #include "DGtal/kernel/BasicPointPredicates.h"
104 #include "DGtal/images/SimpleThresholdForegroundPredicate.h"
105 #include "DGtal/geometry/volumes/distance/ExactPredicateLpSeparableMetric.h"
106 #include "DGtal/geometry/volumes/distance/VoronoiMap.h"
107 #include "DGtal/geometry/volumes/distance/DistanceTransformation.h"
108 using namespace DGtal;
111 namespace po = boost::program_options;
113 int main(
int argc,
char*
const argv[]){
116 po::options_description general_opt (
"Allowed options are: " );
117 general_opt.add_options()
118 (
"help,h",
"display this message." )
119 (
"input,i", po::value<string>()->required(),
"Input vol file." )
120 (
"skel,s", po::value<string>()->required(),
"type of skeletonization" )
121 (
"select,c", po::value<string>()->required(),
"select method for skeletonization" )
122 (
"foreground,f", po::value<string>()->default_value(
"black"),
"foreground color in binary image" )
123 (
"thresholdMin,m", po::value<int>()->default_value(0),
"threshold min (excluded) to define binary shape" )
124 (
"thresholdMax,M", po::value<int>()->default_value(255),
"threshold max (included) to define binary shape" )
125 (
"persistence,p", po::value<int>()->default_value(0),
"persistence value, implies use of persistence algorithm if p>=1" )
126 (
"profile", po::bool_switch()->default_value(
false),
"profile algorithm" )
127 (
"verbose,v", po::bool_switch()->default_value(
false),
"verbose output" )
128 (
"exportImage,o", po::value<std::string>(),
"Export the resulting set of points to a image compatible with GenericWriter.")
129 (
"exportSDP,e", po::value<std::string>(),
"Export the resulting set of points in a simple (sequence of discrete point (sdp)).")
130 (
"visualize,t", po::bool_switch()->default_value(
false),
"visualize result in viewer" );
132 po::variables_map vm;
135 po::store(po::parse_command_line(argc, argv, general_opt), vm);
137 }
catch(
const exception& ex) {
139 trace.
info()<<
"Error checking program options: "<< ex.what()<< std::endl;
142 if (!parseOK || vm.count (
"help" ) || !vm.count(
"input"))
145 "Compute the thinning of a volume using the CriticalKernels framework"<< std::endl
146 << std::endl <<
"Basic usage: "<< std::endl
147 <<
"criticalKernelsThinning3D --input <volFileName> --skel <ulti,end, 1isthmus, isthmus> --select "
148 " [ -f <white,black> -m <minlevel> -M <maxlevel> -v ] "
149 " [--persistence <value> ]" << std::endl
150 <<
"options for --skel {ulti end 1isthmus isthmus}" << std::endl
151 <<
"options for --select = {dmax random first}" << std::endl
152 << general_opt <<
"\n"
154 <<
"criticalKernelsThinning3D --input ${DGtal}/examples/samples/Al.100.vol --select dmax --skel 1isthmus --persistence 1 --visualize --verbose --outputImage ./Al100_dmax_1isthmus_p1.vol \n";
158 string filename = vm[
"input"].as<
string>();
159 bool verbose = vm[
"verbose"].as<
bool>();
160 bool visualize = vm[
"visualize"].as<
bool>();
161 bool profile = vm[
"profile"].as<
bool>();
162 int thresholdMin = vm[
"thresholdMin"].as<
int>();
163 int thresholdMax = vm[
"thresholdMax"].as<
int>();
164 int persistence = vm[
"persistence"].as<
int>();
165 if (vm.count(
"persistence") && persistence < 0 )
166 throw po::validation_error(po::validation_error::invalid_option_value,
"persistence");
167 string foreground = vm[
"foreground"].as<
string>();
168 if (vm.count(
"foreground") && (!(foreground ==
"white" || foreground ==
"black")))
169 throw po::validation_error(po::validation_error::invalid_option_value,
"foreground");
171 string sk_string = vm[
"skel"].as<
string>();
172 if (vm.count(
"skel") &&
173 (!( sk_string ==
"ulti" || sk_string ==
"end" ||
174 sk_string ==
"isthmus" || sk_string ==
"1isthmus"))
176 throw po::validation_error(po::validation_error::invalid_option_value,
"skel");
177 string select_string = vm[
"select"].as<
string>();
178 if (vm.count(
"select") &&
179 (!( select_string ==
"random" || select_string ==
"dmax" ||
180 select_string ==
"first" ))
182 throw po::validation_error(po::validation_error::invalid_option_value,
"select");
186 std::cout <<
"Skel: " << sk_string << std::endl;
187 std::cout <<
"Select: " << select_string << std::endl;
188 std::cout <<
"Persistence: " << persistence << std::endl;
189 std::cout <<
"Input: " << filename << std::endl;
200 thresholdMin, thresholdMax);
208 std::unordered_set< typename Domain::Point> >;
212 DGtal::VoxelComplex<KSpace, Object>;
214 auto & sk = sk_string;
217 ks.
init(image.domain().lowerBound() - d1 ,
218 image.domain().upperBound() + d1 ,
true);
222 DigitalTopology topo(adjF, adjB, DGtal::DigitalTopologyProperties::JORDAN_DT);
223 Object obj(topo,image_set);
230 boost::dynamic_bitset<> isthmus_table;
233 else if (sk ==
"1isthmus")
235 auto pointMap = *functions::mapZeroPointNeighborhoodToConfigurationMask<Point>();
240 std::function< bool(const Complex&, const Cell&) > Skel ;
241 if (sk ==
"ulti") Skel = skelUltimate<Complex>;
242 else if (sk ==
"end") Skel = skelEnd<Complex>;
243 else if (sk ==
"isthmus" || sk ==
"1isthmus")
244 Skel = [&isthmus_table, &pointMap](
const Complex & fc,
245 const Complex::Cell & c){
246 return skelWithTable(isthmus_table, pointMap, fc, c);
248 else throw std::runtime_error(
"Invalid skel string");
249 auto start = std::chrono::system_clock::now();
260 DT dt(obj.domain(),obj.pointSet(), l3);
263 std::function< std::pair<typename Complex::Cell, typename Complex::Data>(
const Complex::Clique&) > Select ;
264 auto & sel = select_string;
265 if (sel ==
"random") Select = selectRandom<Complex>;
266 else if (sel ==
"first") Select = selectFirst<Complex>;
267 else if (sel ==
"dmax"){
269 [&dt](
const Complex::Clique & clique){
270 return selectMaxValue<DT, Complex>(dt,clique);
272 }
else throw std::runtime_error(
"Invalid skel string");
276 if (persistence == 0)
277 vc_new = asymetricThinningScheme< Complex >(
278 vc, Select, Skel, verbose);
280 vc_new = persistenceAsymetricThinningScheme< Complex >(
281 vc, Select, Skel, persistence, verbose);
284 auto end = std::chrono::system_clock::now();
285 auto elapsed = std::chrono::duration_cast<std::chrono::seconds> (end - start) ;
286 if (profile) std::cout <<
"Time elapsed: " << elapsed.count() << std::endl;
288 const auto & thin_set = vc_new.objectSet();
289 const auto & all_set = obj.pointSet();
291 if (vm.count(
"exportSDP"))
294 out.open(vm[
"exportSDP"].as<std::string>().c_str());
295 for (
auto &p : thin_set)
297 out << p[0] <<
" " << p[1] <<
" " << p[2] << std::endl;
301 if (vm.count(
"exportImage"))
303 auto outputFilename = vm[
"exportImage"].as<std::string>();
305 std::cout <<
"outputFilename" << outputFilename << std::endl;
307 unsigned int foreground_value = 255;
309 thin_image >> outputFilename;
321 char** argv(
nullptr);
322 QApplication app(argc, argv);
324 viewer.setWindowTitle(
"criticalKernelsThinning3D");
334 viewer << Viewer3D<>::updateDisplay;
virtual void setFillColor(DGtal::Color aColor)
void beginBlock(const std::string &keyword="")
static Self diagonal(Component val=1)
HyperRectDomain< Space > Domain
TForegroundAdjacency ForegroundAdjacency
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)
TBackgroundAdjacency BackgroundAdjacency
const std::string tableSimple26_6
DigitalSetSelector< Domain, BIG_DS+HIGH_BEL_DS >::Type DigitalSet
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