47 #include "DGtal/base/Common.h"
48 #include "DGtal/base/Clock.h"
51 #include "DGtal/shapes/ShapeFactory.h"
52 #include "DGtal/shapes/Shapes.h"
53 #include "DGtal/helpers/StdDefs.h"
54 #include "DGtal/topology/helpers/Surfaces.h"
55 #include "DGtal/topology/DigitalSurface.h"
58 #include "DGtal/shapes/GaussDigitizer.h"
59 #include "DGtal/geometry/curves/GridCurve.h"
60 #include "DGtal/topology/LightImplicitDigitalSurface.h"
61 #include "DGtal/graph/DepthFirstVisitor.h"
62 #include "DGtal/graph/GraphVisitorRange.h"
63 #include "DGtal/geometry/volumes/KanungoNoise.h"
67 #include "DGtal/geometry/curves/estimation/TrueLocalEstimatorOnPoints.h"
68 #include "DGtal/geometry/curves/estimation/TrueGlobalEstimatorOnPoints.h"
69 #include "DGtal/geometry/curves/estimation/ParametricShapeCurvatureFunctor.h"
70 #include "DGtal/geometry/curves/estimation/ParametricShapeTangentFunctor.h"
71 #include "DGtal/geometry/curves/estimation/ParametricShapeArcLengthFunctor.h"
73 #include "DGtal/geometry/curves/BinomialConvolver.h"
74 #include "DGtal/geometry/curves/estimation/MostCenteredMaximalSegmentEstimator.h"
75 #include "DGtal/geometry/curves/estimation/SegmentComputerEstimators.h"
76 #include "DGtal/geometry/curves/ArithmeticalDSSComputer.h"
77 #include "DGtal/geometry/curves/StabbingCircleComputer.h"
79 #include "DGtal/images/ImageHelper.h"
80 #include "DGtal/geometry/surfaces/estimation/IIGeometricFunctors.h"
81 #include "DGtal/geometry/surfaces/estimation/IntegralInvariantVolumeEstimator.h"
83 #include "DGtal/kernel/BasicPointFunctors.h"
85 using namespace DGtal;
168 std::vector<std::string> shapes2D;
169 std::vector<std::string> shapesDesc;
170 std::vector<std::string> shapesParam1;
171 std::vector<std::string> shapesParam2;
172 std::vector<std::string> shapesParam3;
173 std::vector<std::string> shapesParam4;
175 template<
typename RealPo
int >
176 struct OptionsIntegralInvariant
181 bool lambda_optimized;
191 shapes2D.push_back(
"ball");
192 shapesDesc.push_back(
"Ball for the Euclidean metric.");
193 shapesParam1.push_back(
"--radius [-R]");
194 shapesParam2.push_back(
"");
195 shapesParam3.push_back(
"");
196 shapesParam4.push_back(
"");
198 shapes2D.push_back(
"square");
199 shapesDesc.push_back(
"square (no signature).");
200 shapesParam1.push_back(
"--width [-w]");
201 shapesParam2.push_back(
"");
202 shapesParam3.push_back(
"");
203 shapesParam4.push_back(
"");
205 shapes2D.push_back(
"lpball");
206 shapesDesc.push_back(
"Ball for the l_power metric (no signature).");
207 shapesParam1.push_back(
"--radius [-R],");
208 shapesParam2.push_back(
"--power [-p]");
209 shapesParam3.push_back(
"");
210 shapesParam4.push_back(
"");
212 shapes2D.push_back(
"flower");
213 shapesDesc.push_back(
"Flower with k petals with radius ranging from R+/-v.");
214 shapesParam1.push_back(
"--radius [-R],");
215 shapesParam2.push_back(
"--varsmallradius [-v],");
216 shapesParam3.push_back(
"--k [-k],");
217 shapesParam4.push_back(
"--phi");
219 shapes2D.push_back(
"ngon");
220 shapesDesc.push_back(
"Regular k-gon.");
221 shapesParam1.push_back(
"--radius [-R],");
222 shapesParam2.push_back(
"--k [-k],");
223 shapesParam3.push_back(
"--phi");
224 shapesParam4.push_back(
"");
226 shapes2D.push_back(
"accflower");
227 shapesDesc.push_back(
"Accelerated Flower with k petals.");
228 shapesParam1.push_back(
"--radius [-R],");
229 shapesParam2.push_back(
"--varsmallradius [-v],");
230 shapesParam3.push_back(
"--k [-k],");
231 shapesParam4.push_back(
"--phi");
233 shapes2D.push_back(
"ellipse");
234 shapesDesc.push_back(
"Ellipse.");
235 shapesParam1.push_back(
"--axis1 [-A],");
236 shapesParam2.push_back(
"--axis2 [-a],");
237 shapesParam3.push_back(
"--phi");
238 shapesParam4.push_back(
"");
250 for(
unsigned int i=0; i<shapes2D.size(); ++i)
252 <<shapesDesc[i]<<std::endl
253 <<
"\t\tRequired parameter(s): "
254 << shapesParam1[i]<<
" "
255 << shapesParam2[i]<<
" "
256 << shapesParam3[i]<<
" "
257 << shapesParam4[i]<<std::endl;
270 unsigned int checkAndReturnIndex(
const std::string &shapeName)
274 while ((pos < shapes2D.size()) && (shapes2D[pos] != shapeName))
277 if (pos == shapes2D.size())
279 trace.
error() <<
"The specified shape has not found.";
292 void missingParam(std::string param)
294 trace.
error() <<
" Parameter: "<<param<<
" is required.";
305 void estimationError(
int currentSize,
int expectedSize)
307 if (currentSize != expectedSize)
310 <<
" (got " << currentSize <<
" values"
311 <<
" instead of " << expectedSize <<
")";
328 template <
typename Estimator,
typename ConstIterator,
typename OutputIterator>
330 estimation( Estimator & estimator,
double h,
331 const ConstIterator& itb,
const ConstIterator& ite,
const OutputIterator& ito )
335 estimator.eval( itb, ite, ito, h );
337 std::cout <<
"# Time: " << time << std::endl;
345 template<
typename ConstIteratorOnPo
ints,
typename RPo
int >
346 unsigned int suggestedSizeIntegralInvariant(
const double h,
347 const RPoint& center,
348 const ConstIteratorOnPoints& itb,
349 const ConstIteratorOnPoints& ite )
351 ConstIteratorOnPoints it = itb;
353 RPoint distance = p - center;
354 auto minRadius = distance.norm();
357 for ( ; it != ite; ++it )
360 distance = p - center;
361 if ( distance.norm() < minRadius )
363 minRadius = distance.norm();
367 return minRadius * h;
383 template <
typename Space,
typename Shape>
385 computeLocalEstimations(
const std::string & filename,
388 struct OptionsIntegralInvariant< Z2i::RealPoint > optionsII,
389 const std::string & options,
390 const std::string & properties,
391 const std::string & outShape,
392 double noiseLevel = 0.0 )
395 typedef typename Space::Vector
Vector;
396 typedef typename Space::RealPoint
RealPoint;
397 typedef typename Space::Integer
Integer;
404 bool withNoise = ( noiseLevel <= 0.0 ) ?
false :
true;
408 ASSERT (( noiseLevel < 1.0 ));
410 bool tangent = ( properties.at( 0 ) !=
'0' ) ?
true :
false;
411 bool curvature = ( properties.at( 1 ) !=
'0' ) ?
true :
false;
414 Digitizer* dig =
new Digitizer();
415 dig->attach( aShape );
417 dig->init( aShape.getLowerBound()+vlow, aShape.getUpperBound()+vup, h );
418 Domain domain = dig->getDomain();
426 bool ok = K.
init( dig->getLowerBound(), dig->getUpperBound(),
true );
429 std::cerr <<
"[2dLocalEstimators]"
430 <<
" error in creating KSpace." << std::endl;
438 std::vector< SCell > points;
440 KanungoPredicate *noisifiedObject;
443 noisifiedObject =
new KanungoPredicate( *dig, domain, noiseLevel );
447 double minsize = dig->getUpperBound()[0] - dig->getLowerBound()[0];
448 while( points.size() < 2 * minsize )
467 outS.open(outShape.c_str());
468 for(
const auto &p : points)
473 outS << K.
sCoords( pointel )[0] <<
" " << K.
sCoords( pointel )[1] << std::endl;
484 if (options.at(0) !=
'0')
488 char full_filename[360];
489 sprintf( full_filename,
"%s%s", filename.c_str(),
"_True_tangeant.dat" );
490 std::ofstream file( full_filename );
492 file <<
"# h = " << h << std::endl;
493 file <<
"# True tangents computation" << std::endl;
494 file <<
"# range size = " << pointsRange.size() << std::endl;
497 file <<
"# noise level (init) = " << noiseLevel/h << std::endl;
498 file <<
"# noise level (current) = " << noiseLevel << std::endl;
501 std::ostream_iterator< RealPoint > out_it( file,
"\n" );
504 typedef typename PointsRange::ConstCirculator C;
506 trueTangentEstimator;
507 trueTangentEstimator.
attach( aShape );
508 estimation( trueTangentEstimator, h,
509 pointsRange.c(), pointsRange.c(),
518 char full_filename[360];
519 sprintf( full_filename,
"%s%s", filename.c_str(),
"_True_curvature.dat" );
520 std::ofstream file( full_filename );
522 file <<
"# h = " << h << std::endl;
523 file <<
"# True curvature computation" << std::endl;
524 file <<
"# range size = " << pointsRange.size() << std::endl;
527 file <<
"# noise level (init) = " << noiseLevel/h << std::endl;
528 file <<
"# noise level (current) = " << noiseLevel << std::endl;
531 std::ostream_iterator< double > out_it( file,
"\n" );
534 typedef typename PointsRange::ConstCirculator C;
536 trueCurvatureEstimator;
537 trueCurvatureEstimator.
attach( aShape );
538 estimation( trueCurvatureEstimator, h,
539 pointsRange.c(), pointsRange.c(),
547 if (options.at(1) !=
'0')
551 char full_filename[360];
552 sprintf( full_filename,
"%s%s", filename.c_str(),
"_MDSS_tangeant.dat" );
553 std::ofstream file( full_filename );
555 file <<
"# h = " << h << std::endl;
556 file <<
"# Most centered maximal DSS tangent estimation" << std::endl;
557 file <<
"# range size = " << pointsRange.size() << std::endl;
560 file <<
"# noise level (init) = " << noiseLevel/h << std::endl;
561 file <<
"# noise level (current) = " << noiseLevel << std::endl;
564 std::ostream_iterator< RealPoint > out_it( file,
"\n" );
569 typedef typename PointsRange2::ConstCirculator C;
577 estimation( MDSSTangentEstimator, h,
578 pointsRange2.c(), pointsRange2.c(),
587 char full_filename[360];
588 sprintf( full_filename,
"%s%s", filename.c_str(),
"_MDSSl_curvature.dat" );
589 std::ofstream file( full_filename );
591 file <<
"# h = " << h << std::endl;
592 file <<
"# Most centered maximal DSS (length) curvature estimation" << std::endl;
593 file <<
"# range size = " << pointsRange.size() << std::endl;
596 file <<
"# noise level (init) = " << noiseLevel/h << std::endl;
597 file <<
"# noise level (current) = " << noiseLevel << std::endl;
600 std::ostream_iterator< double > out_it( file,
"\n" );
605 typedef typename PointsRange2::ConstCirculator C;
612 estimation( MDSSCurvatureEstimator, h,
613 pointsRange2.c(), pointsRange2.c(),
619 memset(&full_filename[0], 0,
sizeof(full_filename));
620 sprintf( full_filename,
"%s%s", filename.c_str(),
"_MDSSlw_curvature.dat" );
621 file.open( full_filename );
623 file <<
"# h = " << h << std::endl;
624 file <<
"# Most centered maximal DSS (length & width) curvature estimation" << std::endl;
625 file <<
"# range size = " << pointsRange.size() << std::endl;
628 file <<
"# noise level (init) = " << noiseLevel/h << std::endl;
629 file <<
"# noise level (current) = " << noiseLevel << std::endl;
632 std::ostream_iterator< double > out_it2( file,
"\n" );
638 estimation( MDSSCurvatureEstimator2, h,
639 pointsRange2.c(), pointsRange2.c(),
643 file <<
"# Time: " << time << std::endl;
651 if (options.at(2) !=
'0')
655 char full_filename[360];
656 sprintf( full_filename,
"%s%s", filename.c_str(),
"_MDCA_tangent.dat" );
657 std::ofstream file( full_filename );
659 file <<
"# h = " << h << std::endl;
660 file <<
"# Most centered maximal DCA tangents estimation" << std::endl;
661 file <<
"# range size = " << pointsRange.size() << std::endl;
664 file <<
"# noise level (init) = " << noiseLevel/h << std::endl;
665 file <<
"# noise level (current) = " << noiseLevel << std::endl;
668 std::ostream_iterator< RealPoint > out_it( file,
"\n" );
671 typedef typename Range::ConstCirculator C;
678 estimation( MDCATangentEstimator, h,
689 char full_filename[360];
690 sprintf( full_filename,
"%s%s", filename.c_str(),
"_MDCA_curvature.dat" );
691 std::ofstream file( full_filename );
693 file <<
"# h = " << h << std::endl;
694 file <<
"# Most centered maximal DCA curvature estimation" << std::endl;
695 file <<
"# range size = " << pointsRange.size() << std::endl;
698 file <<
"# noise level (init) = " << noiseLevel/h << std::endl;
699 file <<
"# noise level (current) = " << noiseLevel << std::endl;
702 std::ostream_iterator< double > out_it( file,
"\n" );
705 typedef typename Range::ConstCirculator C;
712 estimation( MDCACurvatureEstimator, h,
717 file <<
"# Time: " << time << std::endl;
724 if (options.at(3) !=
'0')
730 char full_filename[360];
731 sprintf( full_filename,
"%s%s", filename.c_str(),
"_BC_tangeant.dat" );
732 std::ofstream file( full_filename );
734 file <<
"# h = " << h << std::endl;
735 file <<
"# Tangents estimation from binomial convolution" << std::endl;
736 file <<
"# range size = " << pointsRange.size() << std::endl;
739 file <<
"# noise level (init) = " << noiseLevel/h << std::endl;
740 file <<
"# noise level (current) = " << noiseLevel << std::endl;
743 typedef typename PointsRange::ConstIterator I;
745 file <<
"# mask size = " <<
746 MyBinomialConvolver::suggestedSize( h, pointsRange.begin(), pointsRange.end() ) << std::endl;
752 std::ostream_iterator< RealPoint > out_it( file,
"\n" );
754 BCTangentEstimator.
init( h, pointsRange.begin(), pointsRange.end(),
true );
755 BCTangentEstimator.
eval( pointsRange.begin(), pointsRange.end(), out_it );
758 file <<
"# Time: " << time << std::endl;
767 char full_filename[360];
768 sprintf( full_filename,
"%s%s", filename.c_str(),
"_BC_curvature.dat" );
769 std::ofstream file( full_filename );
771 file <<
"# h = " << h << std::endl;
772 file <<
"# Curvature estimation from binomial convolution" << std::endl;
773 file <<
"# range size = " << pointsRange.size() << std::endl;
776 file <<
"# noise level (init) = " << noiseLevel/h << std::endl;
777 file <<
"# noise level (current) = " << noiseLevel << std::endl;
780 typedef typename PointsRange::ConstIterator I;
782 file <<
"# mask size = " <<
783 MyBinomialConvolver::suggestedSize( h, pointsRange.begin(), pointsRange.end() ) << std::endl;
785 std::ostream_iterator< double > out_it( file,
"\n" );
791 BCCurvatureEstimator.
init( h, pointsRange.begin(), pointsRange.end(),
true );
792 BCCurvatureEstimator.
eval( pointsRange.begin(), pointsRange.end(), out_it );
795 file <<
"# Time: " << time << std::endl;
803 if (options.at(4) !=
'0')
809 char full_filename[360];
810 sprintf( full_filename,
"%s%s", filename.c_str(),
"_II_curvature.dat" );
811 std::ofstream file( full_filename );
813 file <<
"# h = " << h << std::endl;
814 file <<
"# Integral Invariant curvature estimation" << std::endl;
815 file <<
"# range size = " << pointsRange.size() << std::endl;
818 file <<
"# noise level (init) = " << noiseLevel/h << std::endl;
819 file <<
"# noise level (current) = " << noiseLevel << std::endl;
822 if( optionsII.radius <= 0.0 )
824 optionsII.radius = suggestedSizeIntegralInvariant( h, optionsII.center, pointsRange.begin(), pointsRange.end() );
825 file <<
"# Estimated radius: " << optionsII.radius << std::endl;
827 double re = optionsII.radius * std::pow( h, optionsII.alpha );
828 file <<
"# full kernel (digital) size (with alpha = " << optionsII.alpha <<
") = " <<
831 std::ostream_iterator< double > out_it( file,
"\n" );
838 LightImplicitDigSurface LightImplDigSurf( K, *noisifiedObject, SAdj, bel );
839 DigSurface surf( LightImplDigSurf );
843 typedef typename VisitorRange::ConstIterator VisitorConstIterator;
845 VisitorRange range(
new Visitor( surf, *surf.begin() ));
846 VisitorConstIterator ibegin = range.begin();
847 VisitorConstIterator iend = range.end();
852 MyIICurvatureFunctor curvatureFunctor;
853 curvatureFunctor.
init( h, re );
855 MyIICurvatureEstimator curvatureEstimator( curvatureFunctor );
856 curvatureEstimator.attach( K, *noisifiedObject );
857 curvatureEstimator.setParams( re/h );
858 curvatureEstimator.init( h, ibegin, iend );
860 curvatureEstimator.eval( ibegin, iend, out_it );
867 LightImplicitDigSurface LightImplDigSurf( K, *dig, SAdj, bel );
868 DigSurface surf( LightImplDigSurf );
872 typedef typename VisitorRange::ConstIterator VisitorConstIterator;
874 VisitorRange range(
new Visitor( surf, *surf.begin() ));
875 VisitorConstIterator ibegin = range.begin();
876 VisitorConstIterator iend = range.end();
881 MyIICurvatureFunctor curvatureFunctor;
882 curvatureFunctor.
init( h, re );
884 MyIICurvatureEstimator curvatureEstimator( curvatureFunctor );
885 curvatureEstimator.attach( K, *dig );
886 curvatureEstimator.setParams( re/h );
887 curvatureEstimator.init( h, ibegin, iend );
889 curvatureEstimator.eval( ibegin, iend, out_it );
893 file <<
"# Time: " << time << std::endl;
906 std::cerr <<
"[computeLocalEstimations]"
907 <<
" error: open digital curve found." << std::endl;
913 std::cerr <<
"[computeLocalEstimations]"
914 <<
" error in finding a bel." << std::endl;
924 int main(
int argc,
char** argv )
928 std::string shapeName;
929 std::string filename;
930 double radius, kernelradius;
932 double smallradius {5};
933 double varsmallradius {5};
934 double cx {0.0}, cy {0.0};
940 double alpha {1.0/3.0};
941 double noiseLevel {0.0};
942 std::string properties {
"11"};
943 std::string outShape {
""};
945 std::string options {
"1000"};
947 app.description(
"Compares local estimators on implicit shapes using DGtal library.\n Typical use example:\n \t 2dlocalEstimators --output <output> --shape <shapeName> [required parameters] --estimators <binaryWord> --properties <binaryWord>\n");
948 auto listOpt = app.add_flag(
"--list,-l",
"List all available shapes");
949 auto outputOpt = app.add_option(
"--output,-o", filename,
"Output")->required();
950 auto shapeNameOpt = app.add_option(
"--shape,-s", shapeName,
"Shape name")->required();
951 auto radiusOpt = app.add_option(
"--radius,-R", radius,
"Radius of the shape" );
952 auto kernelradiusOpt = app.add_option(
"--kernelradius,-K", radius,
"Radius of the convolution kernel (Integral invariants estimators)",
true);
953 auto alphaOpt = app.add_option(
"--alpha", alpha,
"Alpha parameter for Integral Invariant computation",
true);
954 auto axis1Opt = app.add_option(
"--axis1,-A", axis1,
"Half big axis of the shape (ellipse)" );
955 auto axis2Opt = app.add_option(
"--axis2,-a", axis2,
"Half small axis of the shape (ellipse)" );
956 auto smallradiusOpt = app.add_option(
"--smallradius,-r", smallradius,
"Small radius of the shape",
true);
957 auto varsmallradiusOpt = app.add_option(
"--varsmallradius,-v", varsmallradius,
"Variable small radius of the shape",
true );
958 auto kOpt = app.add_option(
"-k", k,
"Number of branches or corners the shape (default 3)",
true );
959 auto phiOpt = app.add_option(
"--phi", phi,
"Phase of the shape (in radian)",
true );
960 auto widthOpt = app.add_option(
"--width,-w", width,
"Width of the shape",
true );
961 auto powerOpt = app.add_option(
"--power,-p", power,
"Power of the metric",
true );
962 app.add_option(
"--center_x,-x", cx,
"x-coordinate of the shape center",
true );
963 app.add_option(
"--center_y,-y", cy,
"y-coordinate of the shape center",
true );
964 app.add_option(
"--gridstep,-g", h,
"Gridstep for the digitization",
true );
965 app.add_option(
"--noise,-n", noiseLevel,
"Level of noise to perturb the shape",
true);
966 app.add_option(
"--properties", properties,
"the i-th property is disabled iff there is a 0 at position i",
true);
967 app.add_option(
"--estimators,-e", options,
"the i-th estimator is disabled iff there is a 0 at position i",
true);
968 app.add_option(
"--exportShape,-E", outShape,
"Exports the contour of the source shape as a sequence of discrete points (.sdp)",
true);
969 app.add_option(
"--lambda", lambda,
"Use the shape to get a better approximation of the surface (optional)",
true);
971 app.get_formatter()->column_width(40);
972 CLI11_PARSE(app, argc, argv);
978 if ( listOpt->count() > 0 )
985 if (options.size() < nb)
988 <<
" characters are required "
989 <<
" with option --estimators.";
995 if (properties.size() < nb)
998 <<
" characters are required "
999 <<
" with option --properties.";
1005 unsigned int id = checkAndReturnIndex(shapeName);
1013 struct OptionsIntegralInvariant<
RealPoint > optII;
1014 optII.radius = kernelradius;
1015 optII.alpha = alpha;
1016 optII.lambda_optimized = lambda;
1017 optII.center = center;
1021 if (radiusOpt->count()==0) missingParam(
"--radius");
1025 computeLocalEstimations<Space>( filename, ball, h, optII, options, properties, outShape, noiseLevel );
1038 if (radiusOpt->count()==0) missingParam(
"--radius");
1047 if (radiusOpt->count()==0) missingParam(
"--radius");
1053 computeLocalEstimations<Space>( filename, flower, h, optII, options, properties, outShape, noiseLevel );
1057 if (radiusOpt->count()==0) missingParam(
"--radius");
1063 computeLocalEstimations<Space>( filename,
object, h, optII, options, properties, outShape, noiseLevel );
1068 if (radiusOpt->count()==0) missingParam(
"--radius");
1074 computeLocalEstimations<Space>( filename, accflower, h, optII, options, properties, outShape, noiseLevel );
1078 if (axis1Opt->count()==0) missingParam(
"--axis1");
1079 if (axis2Opt->count()==0) missingParam(
"--axis2");
1085 computeLocalEstimations<Space>( filename, ellipse, h, optII, options, properties, outShape, noiseLevel );
int main(int argc, char **argv)
void init(const double h, const ConstIterator &itb, const ConstIterator &ite, const bool isClosed=true)
Quantity eval(const ConstIterator &it)
IncidentPointsRange getIncidentPointsRange() const
bool initFromSCellsVector(const std::vector< SCell > &aVectorOfSCells)
MidPointsRange getMidPointsRange() const
PointsRange getPointsRange() const
void init(const double _h, SurfelConstIterator itb, SurfelConstIterator ite)
typename Self::Domain Domain
bool init(const Point &lower, const Point &upper, bool isClosed)
DirIterator sDirs(const SCell &p) const
Point sCoords(const SCell &c) const
SCell sIndirectIncident(const SCell &p, Dimension k) const
static SCell findABel(const KSpace &K, const PointPredicate &pp, unsigned int nbtries=1000)
static void track2DBoundary(std::vector< SCell > &aSCellContour2D, const KSpace &K, const SurfelAdjacency< KSpace::dimension > &surfel_adj, const PointPredicate &pp, const SCell &start_surfel)
void attach(ParametricShape *aShapePtr)
SpaceND< 2, Integer > Space
T power(const T &aVal, const unsigned int exponent)
Trace trace(traceWriterTerm)
DGtal::uint32_t Dimension