bool compareShapeEstimators( const string & name, Shape & aShape, double h ) { // Types typedef typename Space::Point Point; typedef typename Space::Vector Vector; typedef typename Space::RealPoint RealPoint; typedef typename Space::Integer Integer; typedef HyperRectDomain<Space> Domain; typedef KhalimskySpaceND<Space::dimension,Integer> KSpace; typedef typename KSpace::SCell SCell; typedef typename GridCurve<KSpace>::PointsRange PointsRange; typedef typename GridCurve<KSpace>::ArrowsRange ArrowsRange; typedef typename PointsRange::ConstIterator ConstIteratorOnPoints; // Digitizer GaussDigitizer<Space,Shape> dig; dig.attach( aShape ); // attaches the shape. Vector vlow(-1,-1); Vector vup(1,1); dig.init( aShape.getLowerBound()+vlow, aShape.getUpperBound()+vup, h ); Domain domain = dig.getDomain(); // Create cellular space KSpace K; bool ok = K.init( dig.getLowerBound(), dig.getUpperBound(), true ); if ( ! ok ) { std::cerr << "[compareShapeEstimators]" << " error in creating KSpace." << std::endl; return false; } try { // Extracts shape boundary SurfelAdjacency<KSpace::dimension> SAdj( true ); SCell bel = Surfaces<KSpace>::findABel( K, dig, 10000 ); // Getting the consecutive surfels of the 2D boundary std::vector<Point> points; Surfaces<KSpace>::track2DBoundaryPoints( points, K, SAdj, dig, bel ); // Create GridCurve GridCurve<KSpace> gridcurve; gridcurve.initFromVector( points ); // Ranges PointsRange r = gridcurve.getPointsRange(); std::cout << "# range size = " << r.size() << std::endl; // Estimations // True values std::cout << "# True values computation" << std::endl; typedef ParametricShapeTangentFunctor< Shape > TangentFunctor; typedef ParametricShapeCurvatureFunctor< Shape > CurvatureFunctor; TrueLocalEstimatorOnPoints< ConstIteratorOnPoints, Shape, TangentFunctor > trueTangentEstimator; TrueLocalEstimatorOnPoints< ConstIteratorOnPoints, Shape, CurvatureFunctor > trueCurvatureEstimator; trueTangentEstimator.init( h, r.begin(), r.end(), &aShape, gridcurve.isClosed()); std::vector<RealPoint> trueTangents = estimateQuantity( trueTangentEstimator, r.begin(), r.end() ); trueCurvatureEstimator.init( h, r.begin(), r.end(), &aShape, gridcurve.isClosed()); std::vector<double> trueCurvatures = estimateQuantity( trueCurvatureEstimator, r.begin(), r.end() ); // Maximal Segments std::cout << "# Maximal DSS tangent estimation" << std::endl; typedef ArithmeticalDSS<ConstIteratorOnPoints,Integer,4> SegmentComputer; typedef TangentFromDSSFunctor<SegmentComputer> SCFunctor; SegmentComputer sc; SCFunctor f; MostCenteredMaximalSegmentEstimator<SegmentComputer,SCFunctor> MSTangentEstimator(sc, f); Clock c; c.startClock(); MSTangentEstimator.init( h, r.begin(), r.end(), gridcurve.isClosed() ); std::vector<typename SCFunctor::Value> MSTangents = estimateQuantity( MSTangentEstimator, r.begin(), r.end() ); double TMST = c.stopClock(); // Binomial std::cout << "# Tangent and curvature estimation from binomial convolution" << std::endl; typedef BinomialConvolver<ConstIteratorOnPoints, double> MyBinomialConvolver; std::cout << "# mask size = " << MyBinomialConvolver::suggestedSize( h, r.begin(), r.end() ) << std::endl; typedef TangentFromBinomialConvolverFunctor< MyBinomialConvolver, RealPoint > TangentBCFct; typedef CurvatureFromBinomialConvolverFunctor< MyBinomialConvolver, double > CurvatureBCFct; BinomialConvolverEstimator< MyBinomialConvolver, TangentBCFct> BCTangentEstimator; BinomialConvolverEstimator< MyBinomialConvolver, CurvatureBCFct> BCCurvatureEstimator; c.startClock(); BCTangentEstimator.init( h, r.begin(), r.end(), gridcurve.isClosed() ); std::vector<RealPoint> BCTangents = estimateQuantity( BCTangentEstimator, r.begin(), r.end() ); double TBCTan = c.stopClock(); c.startClock(); BCCurvatureEstimator.init( h, r.begin(), r.end(), gridcurve.isClosed() ); std::vector<double> BCCurvatures = estimateQuantity( BCCurvatureEstimator, r.begin(), r.end() ); double TBCCurv = c.stopClock(); // Output std::cout << "# Shape = "<< name <<std::endl << "# Time-BCtangent = "<<TBCTan <<std::endl << "# Time-BCcurvature = "<<TBCCurv<<std::endl << "# Time-MStangent = "<<TMST<<std::endl << "# id x y tangentx tangenty curvature" << " BCtangentx BCtangenty BCcurvature" << " MStangentx MStangenty" << std::endl; unsigned int i = 0; for ( ConstIteratorOnPoints it = r.begin(), it_end = r.end(); it != it_end; ++it, ++i ) { Point p = *it; std::cout << i << setprecision( 15 ) << " " << p[ 0 ] << " " << p[ 1 ] << " " << trueTangents[ i ][ 0 ] << " " << trueTangents[ i ][ 1 ] << " " << trueCurvatures[ i ] << " " << BCTangents[ i ][ 0 ] << " " << BCTangents[ i ][ 1 ] << " " << BCCurvatures[ i ] << " " << MSTangents[ i ][ 0 ] << " " << MSTangents[ i ][ 1 ] << std::endl; } return true; } catch ( InputException e ) { std::cerr << "[compareShapeEstimators]" << " error in finding a bel." << std::endl; return false; } }
bool lengthEstimators( const std::string & /*name*/, Shape & aShape, double h ) { // Types typedef typename Space::Point Point; typedef typename Space::Vector Vector; typedef typename Space::RealPoint RealPoint; typedef typename Space::Integer Integer; typedef HyperRectDomain<Space> Domain; typedef KhalimskySpaceND<Space::dimension,Integer> KSpace; typedef typename KSpace::SCell SCell; typedef typename GridCurve<KSpace>::PointsRange PointsRange; typedef typename GridCurve<KSpace>::ArrowsRange ArrowsRange; // Digitizer GaussDigitizer<Space,Shape> dig; dig.attach( aShape ); // attaches the shape. Vector vlow(-1,-1); Vector vup(1,1); dig.init( aShape.getLowerBound()+vlow, aShape.getUpperBound()+vup, h ); Domain domain = dig.getDomain(); // Create cellular space KSpace K; bool ok = K.init( dig.getLowerBound(), dig.getUpperBound(), true ); if ( ! ok ) { std::cerr << "[lengthEstimators]" << " error in creating KSpace." << std::endl; return false; } try { // Extracts shape boundary SurfelAdjacency<KSpace::dimension> SAdj( true ); SCell bel = Surfaces<KSpace>::findABel( K, dig, 10000 ); // Getting the consecutive surfels of the 2D boundary std::vector<Point> points; Surfaces<KSpace>::track2DBoundaryPoints( points, K, SAdj, dig, bel ); // Create GridCurve GridCurve<KSpace> gridcurve; gridcurve.initFromVector( points ); // Ranges ArrowsRange ra = gridcurve.getArrowsRange(); PointsRange rp = gridcurve.getPointsRange(); // Estimations typedef typename PointsRange::ConstIterator ConstIteratorOnPoints; typedef ParametricShapeArcLengthFunctor< Shape > Length; TrueGlobalEstimatorOnPoints< ConstIteratorOnPoints, Shape, Length > trueLengthEstimator; trueLengthEstimator.init( h, rp.begin(), rp.end(), &aShape, gridcurve.isClosed()); L1LengthEstimator< typename ArrowsRange::ConstCirculator > l1length; DSSLengthEstimator< typename PointsRange::ConstCirculator > DSSlength; MLPLengthEstimator< typename PointsRange::ConstIterator > MLPlength; FPLengthEstimator< typename PointsRange::ConstIterator > FPlength; BLUELocalLengthEstimator< typename ArrowsRange::ConstIterator > BLUElength; RosenProffittLocalLengthEstimator< typename ArrowsRange::ConstIterator > RosenProffittlength; // Output double trueValue = trueLengthEstimator.eval(); double l1, blue, rosen,dss,mlp,fp; double Tl1, Tblue, Trosen,Tdss,Tmlp,Tfp; Clock c; //Length evaluation & timing c.startClock(); l1length.init(h, ra.c(), ra.c()); l1 = l1length.eval(); Tl1 = c.stopClock(); c.startClock(); BLUElength.init(h, ra.begin(), ra.end(), gridcurve.isClosed()); blue = BLUElength.eval(); Tblue = c.stopClock(); c.startClock(); RosenProffittlength.init(h, ra.begin(), ra.end(), gridcurve.isClosed()); rosen = RosenProffittlength.eval(); Trosen = c.stopClock(); c.startClock(); DSSlength.init(h, rp.c(), rp.c()); dss = DSSlength.eval(); Tdss = c.stopClock(); c.startClock(); MLPlength.init(h, rp.begin(), rp.end(), gridcurve.isClosed()); mlp = MLPlength.eval(); Tmlp = c.stopClock(); c.startClock(); FPlength.init(h, rp.begin(), rp.end(), gridcurve.isClosed()); fp = FPlength.eval(); Tfp = c.stopClock(); std::cout << std::setprecision( 15 ) << h << " " << rp.size() << " " << trueValue << " " << l1 << " " << blue << " " << rosen << " " << dss << " " << mlp << " " << fp << " " << Tl1 << " " << Tblue << " " << Trosen << " " << Tdss << " " << Tmlp << " " << Tfp << std::endl; return true; } catch ( InputException e ) { std::cerr << "[lengthEstimators]" << " error in finding a bel." << std::endl; return false; } }
GridCurve<TKSpace> ballGenerator(double aCx, double aCy, double aR, bool aFlagIsCW) { // Types typedef TKSpace KSpace; typedef typename KSpace::SCell SCell; typedef GridCurve<KSpace> GridCurve; typedef typename KSpace::Space Space; typedef Ball2D<Space> Shape; typedef typename Space::Point Point; typedef typename Space::RealPoint RealPoint; typedef HyperRectDomain<Space> Domain; //Forme Shape aShape(Point(aCx,aCy), aR); // Window for the estimation RealPoint xLow ( -aR-1, -aR-1 ); RealPoint xUp( aR+1, aR+1 ); GaussDigitizer<Space,Shape> dig; dig.attach( aShape ); // attaches the shape. dig.init( xLow, xUp, 1 ); Domain domain = dig.getDomain(); // Create cellular space KSpace K; bool ok = K.init( dig.getLowerBound(), dig.getUpperBound(), true ); if ( ! ok ) { std::cerr << " " << " error in creating KSpace." << std::endl; return GridCurve(); } try { // Extracts shape boundary SurfelAdjacency<KSpace::dimension> SAdj( true ); SCell bel = Surfaces<KSpace>::findABel( K, dig, 10000 ); // Getting the consecutive surfels of the 2D boundary std::vector<Point> points, points2; Surfaces<KSpace>::track2DBoundaryPoints( points, K, SAdj, dig, bel ); //counter-clockwise oriented by default GridCurve c; if (aFlagIsCW) { points2.assign( points.rbegin(), points.rend() ); c.initFromVector(points2); } else { c.initFromVector(points); } return c; } catch ( InputException& e ) { std::cerr << " " << " error in finding a bel." << std::endl; return GridCurve(); } }
bool generateContour( Shape & aShape, double h, const std::string & outputFormat, bool withGeom, const std::string & outputFileName ) { // Types typedef typename Space::Point Point; typedef typename Space::Vector Vector; typedef typename Space::RealPoint RealPoint; typedef typename Space::Integer Integer; typedef HyperRectDomain<Space> Domain; typedef KhalimskySpaceND<Space::dimension,Integer> KSpace; typedef typename KSpace::SCell SCell; typedef typename GridCurve<KSpace>::PointsRange Range; typedef typename Range::ConstIterator ConstIteratorOnPoints; typedef typename GridCurve<KSpace>::MidPointsRange MidPointsRange; // Digitizer GaussDigitizer<Space,Shape> dig; dig.attach( aShape ); // attaches the shape. Vector vlow(-1,-1); Vector vup(1,1); dig.init( aShape.getLowerBound()+vlow, aShape.getUpperBound()+vup, h ); Domain domain = dig.getDomain(); // Create cellular space KSpace K; bool ok = K.init( dig.getLowerBound(), dig.getUpperBound(), true ); if ( ! ok ) { std::cerr << "[generateContour]" << " error in creating KSpace." << std::endl; return false; } try { // Extracts shape boundary SurfelAdjacency<KSpace::dimension> SAdj( true ); SCell bel = Surfaces<KSpace>::findABel( K, dig, 10000 ); // Getting the consecutive surfels of the 2D boundary std::vector<Point> points; Surfaces<KSpace>::track2DBoundaryPoints( points, K, SAdj, dig, bel ); // Create GridCurve GridCurve<KSpace> gridcurve; gridcurve.initFromVector( points ); // gridcurve contains the digital boundary to analyze. Range r = gridcurve.getPointsRange(); //building range if ( outputFormat == "pts" ) { for ( ConstIteratorOnPoints it = r.begin(), it_end = r.end(); it != it_end; ++it ) { Point p = *it; std::cout << p[ 0 ] << " " << p[ 1 ] << std::endl; } } else if ( outputFormat == "fc" ) { ConstIteratorOnPoints it = r.begin(); Point p = *it++; std::cout << p[ 0 ] << " " << p[ 1 ] << " "; for ( ConstIteratorOnPoints it_end = r.end(); it != it_end; ++it ) { Point p2 = *it; Vector v = p2 - p; if ( v[0 ]== 1 ) std::cout << '0'; if ( v[ 1 ] == 1 ) std::cout << '1'; if ( v[ 0 ] == -1 ) std::cout << '2'; if ( v[ 1 ] == -1 ) std::cout << '3'; p = p2; } // close freemanchain if necessary. Point p2= *(r.begin()); Vector v = p2 - p; if ( v.norm1() == 1 ) { if ( v[ 0 ] == 1 ) std::cout << '0'; if ( v[ 1 ] == 1 ) std::cout << '1'; if ( v[ 0 ] == -1 ) std::cout << '2'; if ( v[ 1 ] == -1 ) std::cout << '3'; } std::cout << std::endl; } if (withGeom) { // write geometry of the shape std::stringstream s; s << outputFileName << ".geom"; std::ofstream outstream(s.str().c_str()); //output stream if (!outstream.is_open()) return false; else { outstream << "# " << outputFileName << std::endl; outstream << "# Pointel (x,y), Midpoint of the following linel (x',y')" << std::endl; outstream << "# id x y tangentx tangenty curvaturexy" << " x' y' tangentx' tangenty' curvaturex'y'" << std::endl; std::vector<RealPoint> truePoints, truePoints2; std::vector<RealPoint> trueTangents, trueTangents2; std::vector<double> trueCurvatures, trueCurvatures2; estimateGeometry<Shape, Range, RealPoint, double> (aShape, h, r, truePoints, trueTangents, trueCurvatures); estimateGeometry<Shape, MidPointsRange, RealPoint, double> (aShape, h, gridcurve.getMidPointsRange(), truePoints2, trueTangents2, trueCurvatures2); unsigned int n = (unsigned int)r.size(); for (unsigned int i = 0; i < n; ++i ) { outstream << std::setprecision( 15 ) << i << " " << truePoints[ i ][ 0 ] << " " << truePoints[ i ][ 1 ] << " " << trueTangents[ i ][ 0 ] << " " << trueTangents[ i ][ 1 ] << " " << trueCurvatures[ i ] << " " << truePoints2[ i ][ 0 ] << " " << truePoints2[ i ][ 1 ] << " " << trueTangents2[ i ][ 0 ] << " " << trueTangents2[ i ][ 1 ] << " " << trueCurvatures2[ i ] << std::endl; } } outstream.close(); } ///////////////// } catch ( InputException e ) { std::cerr << "[generateContour]" << " error in finding a bel." << std::endl; return false; } return true; }
bool testCompareEstimator(const std::string &name, Shape & aShape, double h) { using namespace Z2i; trace.beginBlock ( ( "Testing CompareEstimator on digitization of " + name ). c_str() ); // Creates a digitizer on the window (xLow, xUp). typedef Space::RealPoint RealPoint; RealPoint xLow( -10.0, -10.0 ); RealPoint xUp( 10.0, 10.0 ); GaussDigitizer<Space,Shape> dig; dig.attach( aShape ); // attaches the shape. dig.init( xLow, xUp, h ); // The domain size is given by the digitizer according to the window // and the step. Domain domain = dig.getDomain(); // Create cellular space KSpace K; bool ok = K.init( dig.getLowerBound(), dig.getUpperBound(), true ); if ( ! ok ) { std::cerr << "[testCompareEstimators]" << " error in creating KSpace." << std::endl; } else try { // Extracts shape boundary SurfelAdjacency<KSpace::dimension> SAdj( true ); SCell bel = Surfaces<KSpace>::findABel( K, dig, 10000 ); // Getting the consecutive surfels of the 2D boundary std::vector<Point> points; Surfaces<KSpace>::track2DBoundaryPoints( points, K, SAdj, dig, bel ); // Create GridCurve GridCurve<KSpace> gridcurve; gridcurve.initFromVector( points ); typedef GridCurve<KhalimskySpaceND<2> >::PointsRange Range; typedef Range::ConstIterator ConstIteratorOnPoints; Range r = gridcurve.getPointsRange();//building range unsigned int nb = 0; unsigned int nbok = 0; //curvature typedef ParametricShapeCurvatureFunctor< Shape > Curvature; typedef TrueLocalEstimatorOnPoints< ConstIteratorOnPoints, Shape, Curvature > TrueCurvature; TrueCurvature curvatureEstimator; TrueCurvature curvatureEstimatorBis; curvatureEstimator.init( h, r.begin(), r.end() ); curvatureEstimator.attach( &aShape ); curvatureEstimatorBis.init( h, r.begin(), r.end() ); curvatureEstimatorBis.attach( &aShape ); typedef CompareLocalEstimators< TrueCurvature, TrueCurvature> Comparator; trace.info()<< "True curvature comparison at "<< *r.begin() << " = " << Comparator::compare(curvatureEstimator,curvatureEstimatorBis, r.begin()) << std::endl; typename Comparator::OutputStatistic error =Comparator::compare(curvatureEstimator, curvatureEstimatorBis, r.begin(), r.end()); trace.info() << "Nb samples= "<< error.samples()<<std::endl; trace.info() << "Error mean= "<< error.mean()<<std::endl; trace.info() << "Error max= "<< error.max()<<std::endl; nbok += ( (error.samples() == r.size())&&(error.max() == 0) )?1:0; nb++; trace.info() << nbok << "/" << nb << std::endl; //tangents typedef ParametricShapeTangentFunctor< Shape > Tangent; typedef TrueLocalEstimatorOnPoints< ConstIteratorOnPoints, Shape, Tangent > TrueTangent; typedef ArithmeticalDSS<ConstIteratorOnPoints,KSpace::Integer,4> SegmentComputer; typedef TangentFromDSSEstimator<SegmentComputer> Functor; typedef MostCenteredMaximalSegmentEstimator<SegmentComputer,Functor> MSTangentEstimator; SegmentComputer sc; Functor f; TrueTangent tang1; MSTangentEstimator tang2(sc, f); tang1.init( h, r.begin(), r.end() ); tang1.attach( &aShape ); tang2.init( h, r.begin(), r.end() ); typedef CompareLocalEstimators< TrueTangent, MSTangentEstimator> ComparatorTan; trace.info()<< "Tangent comparison at "<< *r.begin() << " = " << ComparatorTan::compareVectors( tang1, tang2, r.begin()) << std::endl; typename ComparatorTan::OutputVectorStatistic error2 =ComparatorTan::compareVectors(tang1, tang2, r.begin(), r.end()); trace.info()<< "Nb samples= "<< error2.samples()<<std::endl; trace.info()<< "Error mean= "<< error2.mean()<<std::endl; trace.info()<< "Error max= "<< error2.max()<<std::endl; nbok += (error.samples() == r.size())?1:0; nb++; trace.info() << nbok << "/" << nb << std::endl; ok += (nb == nbok); } catch ( InputException e ) { std::cerr << "[testCompareEstimator]" << " error in finding a bel." << std::endl; ok = false; } trace.emphase() << ( ok ? "Passed." : "Error." ) << endl; trace.endBlock(); return ok; }
bool estimatorOnShapeDigitization( const string& name, Shape & aShape, const RealPoint& low, const RealPoint& up, double h ) { using namespace Z2i; trace.beginBlock ( ( "Curvature estimation on digitization of " + name ). c_str() ); // Creates a digitizer on the window (low, up). GaussDigitizer<Space,Shape> dig; dig.attach( aShape ); // attaches the shape. dig.init( low, up, h ); // The domain size is given by the digitizer // according to the window and the step. Domain domain = dig.getDomain(); // Create cellular space KSpace K; bool ok = K.init( dig.getLowerBound(), dig.getUpperBound(), true ); if ( ! ok ) { std::cerr << "[estimatorOnShapeDigitization]" << " error in creating KSpace." << std::endl; } else try { // Extracts shape boundary SurfelAdjacency<KSpace::dimension> SAdj( true ); SCell bel = Surfaces<KSpace>::findABel( K, dig, 10000 ); // Getting the consecutive surfels of the 2D boundary std::vector<Point> points; Surfaces<KSpace>::track2DBoundaryPoints( points, K, SAdj, dig, bel ); // Create GridCurve GridCurve<KSpace> gridcurve( K ); gridcurve.initFromVector( points ); // Create range of incident points typedef GridCurve<KSpace>::IncidentPointsRange Range; typedef Range::ConstIterator ClassicIterator; typedef Range::ConstCirculator CircularIterator; Range r = gridcurve.getIncidentPointsRange();//building range // Estimation std::vector<double> estimations; if (gridcurve.isOpen()) { typedef StabbingCircleComputer<ClassicIterator> SegmentComputer; typedef CurvatureFromDCAEstimator<SegmentComputer> SCEstimator; typedef MostCenteredMaximalSegmentEstimator<SegmentComputer,SCEstimator> CurvatureEstimator; SegmentComputer sc; SCEstimator sce; CurvatureEstimator estimator(sc, sce); std::cout << "# open grid curve" << endl; estimator.init( h, r.begin(), r.end() ); estimator.eval( r.begin(), r.end(), std::back_inserter(estimations) ); } else { typedef StabbingCircleComputer<CircularIterator> SegmentComputer; typedef CurvatureFromDCAEstimator<SegmentComputer> SCEstimator; typedef MostCenteredMaximalSegmentEstimator<SegmentComputer,SCEstimator> CurvatureEstimator; SegmentComputer sc; SCEstimator sce; CurvatureEstimator estimator(sc, sce); std::cout << "# closed grid curve" << endl; estimator.init( h, r.c(), r.c() ); estimator.eval( r.c(), r.c(), std::back_inserter(estimations) ); } // Print (standard output) std::cout << "# idx kappa" << endl; unsigned int i = 0; for ( ClassicIterator it = r.begin(), ite = r.end(); it != ite; ++it, ++i ) { std::cout << i << " " << estimations.at(i) << std::endl; } } catch ( InputException e ) { std::cerr << "[estimatorOnShapeDigitization]" << " error in finding a bel." << std::endl; ok = false; } trace.emphase() << ( ok ? "Passed." : "Error." ) << endl; trace.endBlock(); return ok; }
int main () { Delaunay t; trace.beginBlock("Construction the shape"); typedef Ellipse2D<Z2i::Space> Ellipse; int a = 5, b = 3; Ellipse2D<Z2i::Space> ellipse(Z2i::Point(0,0), a, b, 0.3 ); // Ellipse2D<Z2i::Space> ellipse(Z2i::Point(0,0), 5.5, 5.5, 0 ); double h = 0.25; GaussDigitizer<Z2i::Space,Ellipse> dig; dig.attach( ellipse ); dig.init( ellipse.getLowerBound()+Z2i::Vector(-1,-1), ellipse.getUpperBound()+Z2i::Vector(1,1), h ); // typedef Flower2D<Z2i::Space> Flower; // Flower2D<Z2i::Space> flower(Z2i::Point(0,0), 15, 2, 5, 0); // double h = 0.25; // GaussDigitizer<Z2i::Space,Flower> dig; // dig.attach( flower ); // dig.init( flower.getLowerBound()+Z2i::Vector(-1,-1), // flower.getUpperBound()+Z2i::Vector(1,1), h ); Z2i::KSpace ks; ks.init( dig.getLowerBound(), dig.getUpperBound(), true ); SurfelAdjacency<2> sAdj( true ); Z2i::SCell bel = Surfaces<Z2i::KSpace>::findABel( ks, dig, 1000 ); std::vector<Z2i::Point> boundaryPoints; Surfaces<Z2i::KSpace> ::track2DBoundaryPoints( boundaryPoints, ks, sAdj, dig, bel ); Z2i::Curve c; c.initFromVector( boundaryPoints ); typedef Z2i::Curve::PointsRange Range; Range r = c.getPointsRange(); trace.endBlock(); trace.beginBlock("Delaunay"); for(Range::ConstIterator it=r.begin(), itend=r.end(); it != itend; ++it) { t.insert( Point( (*it)[0], (*it)[1])); t.insert( Point( (*it)[0] + 3 + (int) ceil( ((double)b)/h ), (*it)[1] - 3 - (int) ceil( ((double)a)/h ) )); } trace.endBlock(); std::cout << "number of vertices : " ; std::cout << t.number_of_vertices() << std::endl; std::cout << "number of faces : " ; std::cout << t.number_of_faces() << std::endl; trace.beginBlock("Area minimizing triangulation"); Edge_iterator itnext; bool flip = true; bool inverse = false; unsigned int pass = 0; while ( flip ) { std::cout << "----------- pass " << pass << " -------------------" << std::endl; inverse = false; flip = false; int nb_flip = 0; int nb_random_flip = 0; for( Edge_iterator it = t.edges_begin(), itend=t.edges_end(); it != itend; it = itnext ) { // vertex(cw(i)) and vertex(ccw(i)) of f. itnext = it; ++itnext; Edge e1 = *it; if ( isEdgeElementary( t, e1.first->vertex( t.ccw( e1.second ) ), e1.first->vertex( t.cw( e1.second ) ) ) ) continue; Edge e2 = t.mirror_edge( e1 ); if ( ! isQuadrilateral( t, e1.first->vertex( e1.second ), e1.first->vertex( t.ccw( e1.second ) ), e2.first->vertex( e2.second ), e1.first->vertex( t.cw( e1.second ) ) ) ) continue; int nb_f1 = twiceNbLatticePointsInTriangle( t, e1.first ); int nb_f2 = twiceNbLatticePointsInTriangle( t, e2.first ); int nb_flip_f1 = twiceNbLatticePointsInTriangle( t, e1.first->vertex( e1.second ), e1.first->vertex( t.ccw( e1.second ) ), e2.first->vertex( e2.second ) ); int nb_flip_f2 = twiceNbLatticePointsInTriangle( t, e1.first->vertex( e1.second ), e1.first->vertex( t.cw( e1.second ) ), e2.first->vertex( e2.second ) ); int nb_min = nb_f1 <= nb_f2 ? nb_f1 : nb_f2; int nb_flip_min = nb_flip_f1 <= nb_flip_f2 ? nb_flip_f1 : nb_flip_f2; if ( nb_flip_min < nb_min ) { std::cout << "flipped " << e1.first->vertex( e1.second )->point() << "->" << e1.first->vertex( e1.second )->point() << std::endl; t.flip( e1.first, e1.second ); nb_flip++; flip = true; } if ( nb_flip_min == nb_min ) { inverse = true; if ( random() % 2 == 1 ) { std::cout << "Random flipped " << e1.first->vertex( e1.second )->point() << "->" << e1.first->vertex( e1.second )->point() << std::endl; t.flip( e1.first, e1.second ); nb_random_flip++; } } // if ( ( empty_f1 == false ) // && ( empty_f2 == false ) ) // { // try if flip is better. // bool empty_flip_f1 // = twiceNbLatticePointsInTriangle( t, // e1.first->vertex( e1.second ), // e1.first->vertex( t.ccw( e1.second ) ), // e2.first->vertex( e2.second ) ) == 0; // bool empty_flip_f2 // = twiceNbLatticePointsInTriangle( t, // e2.first->vertex( e2.second ), // e2.first->vertex( t.ccw( e2.second ) ), // e1.first->vertex( e1.second ) ) == 0; // if ( empty_flip_f1 || empty_flip_f2 ) // { // if ( isEdgeElementary( t, // e1.first->vertex( t.ccw( e1.second ) ), // e1.first->vertex( t.cw( e1.second ) ) ) ) // { // std::cout << "Flip forbidden: " << e1.first->vertex( e1.second )->point() // << "->" << e1.first->vertex( e1.second )->point() // << std::endl; // } // else // { // std::cout << "flipped " << e1.first->vertex( e1.second )->point() // << "->" << e1.first->vertex( e1.second )->point() // << std::endl; // t.flip( e1.first, e1.second ); // flip = true; // } // } // } } std::cout << "----------- nb_flip " << nb_flip << ", nb_random " << nb_random_flip << " -------------" << std::endl; ++pass; if ( inverse && ( (nb_random_flip+4) > log(pass) ) ) flip = true; } trace.endBlock(); // GridCurve Z2i::Curve gc; gc.initFromPointsRange( r.begin(), r.end() ); typedef Z2i::Curve::PointsRange::ConstIterator ConstIterator; typedef ArithmeticalDSS<ConstIterator,int,4> DSS4; typedef SaturatedSegmentation<DSS4> Segmentation; //Segmentation Z2i::Curve::PointsRange range = gc.getPointsRange(); DSS4 dss4RecognitionAlgorithm; Segmentation theSegmentation( range.begin(), range.end(), dss4RecognitionAlgorithm ); DGtal::Board2D board; Z2i::Point dP; board << CustomStyle( dP.className(), new CustomPen( Color(0,0,0), Color(230,230,230), 1, Board2D::Shape::SolidStyle, Board2D::Shape::RoundCap, Board2D::Shape::RoundJoin )); for(Range::ConstIterator it=r.begin(), itend=r.end(); it != itend; ++it) board << *it; for(Faces_iterator it = t.finite_faces_begin(), itend=t.finite_faces_end(); it != itend; ++it) { Z2i::Point a( toDGtal(it->vertex(0)->point())), b(toDGtal(it->vertex(1)->point())), c(toDGtal(it->vertex(2)->point())); // Z2i::Vector ab( b - a ), ac( c - a ); // int d = ab[ 0 ] * ac[ 1 ] - ab[ 1 ] * ac[ 0 ]; if ( emptyLatticeTriangle( t, it ) ) //( ( d == 1 ) || (d == -1 ) ) { board.setPenColor(DGtal::Color::Blue); board.setFillColor( DGtal::Color::None ); board.setLineWidth( 3.0 ); board.drawTriangle(a[0],a[1],b[0],b[1],c[0],c[1]); } else { board.setPenColor(DGtal::Color::Red); board.setFillColor( DGtal::Color::None ); // board.setFillColorRGBi(200,200,200,128); board.setLineWidth( 2.0 ); board.drawTriangle(a[0],a[1],b[0],b[1],c[0],c[1]); } } Segmentation::SegmentComputerIterator i = theSegmentation.begin(); Segmentation::SegmentComputerIterator end = theSegmentation.end(); board.setPenColor(DGtal::Color::Green); board.setFillColor( DGtal::Color::None ); board << SetMode( "ArithmeticalDSS", "BoundingBox" ); std::string aStyleName = "ArithmeticalDSS/BoundingBox"; for ( ; i != end; ++i) { DSS4 current(*i); board << CustomStyle( aStyleName, new CustomPenColor( DGtal::Color::Green ) ) << current; } // Display Voronoi. // for(Edge_iterator it = t.edges_begin(), itend=t.edges_end(); // it != itend; ++it) // { // // vertex(cw(i)) and vertex(ccw(i)) of f. // Face_handle itf = it->first; // int i = it->second; // Z2i::Point a( toDGtal(itf->vertex( t.cw( i ) )->point())); // Z2i::Point b( toDGtal(itf->vertex( t.ccw( i ) )->point())); // CGAL::Object o = t.dual( it ); // if (CGAL::object_cast<K::Segment_2>(&o)) // { // const K::Segment_2* ptrSegment = CGAL::object_cast<K::Segment_2>(&o); // board.setPenColor(DGtal::Color::Black); // board.setFillColor( DGtal::Color::None ); // board.setLineWidth( 2.0 ); // board.drawLine( ptrSegment->source().x(), // ptrSegment->source().y(), // ptrSegment->target().x(), // ptrSegment->target().y() ); // } // else if (CGAL::object_cast<K::Ray_2>(&o)) // { // const K::Ray_2* ptrRay = CGAL::object_cast<K::Ray_2>(&o); // board.setPenColor(DGtal::Color::Black); // board.setFillColor( DGtal::Color::None ); // board.setLineWidth( 2.0 ); // double dx = ptrRay->to_vector().x(); // double dy = ptrRay->to_vector().y(); // double norm = sqrt( dx*dx+dy*dy ); // dx = 5.0 * dx / norm; // dy = 5.0 * dy / norm; // board.drawArrow( ptrRay->source().x(), // ptrRay->source().y(), // ptrRay->source().x() + dx, //1*ptrRay->to_vector().x(), // ptrRay->source().y() + dy ); //1*ptrRay->to_vector().y() ); // } // } board.saveSVG("delaunay.svg"); board.saveEPS("delaunay.eps"); return 0; }
int main() { //shape typedef Flower2D<Z2i::Space> Flower; Flower2D<Z2i::Space> flower(Z2i::Point(0,0), 20, 5, 5, 0); //! [shapeGridCurveEstimator-dig] //implicit digitization of a shape of type Flower //into a digital space of type Space double h = 1; GaussDigitizer<Z2i::Space,Flower> dig; dig.attach( flower ); dig.init( flower.getLowerBound()+Z2i::Vector(-1,-1), flower.getUpperBound()+Z2i::Vector(1,1), h ); //! [shapeGridCurveEstimator-dig] //! [shapeGridCurveEstimator-prepareTracking] //Khalimsky space Z2i::KSpace ks; ks.init( dig.getLowerBound(), dig.getUpperBound(), true ); //adjacency (4-connectivity) SurfelAdjacency<2> sAdj( true ); //! [shapeGridCurveEstimator-prepareTracking] //! [shapeGridCurveEstimator-tracking] //searching for one boundary element Z2i::SCell bel = Surfaces<Z2i::KSpace>::findABel( ks, dig, 1000 ); //tracking vector<Z2i::Point> boundaryPoints; Surfaces<Z2i::KSpace> ::track2DBoundaryPoints( boundaryPoints, ks, sAdj, dig, bel ); //! [shapeGridCurveEstimator-tracking] //! [shapeGridCurveEstimator-instantiation] Z2i::Curve c; c.initFromVector( boundaryPoints ); //! [shapeGridCurveEstimator-instantiation] DGtal::Board2D aBoard; aBoard << c; aBoard.saveEPS("DisplayGridCurve1.eps"); //! [shapeGridCurveEstimator-getRange] //range of points typedef Z2i::Curve::PointsRange Range; Range r = c.getPointsRange(); //! [shapeGridCurveEstimator-getRange] //! [shapeGridCurveEstimator-lengthEstimation] //length estimation DSSLengthEstimator< Range::ConstIterator > DSSlength; DSSlength.init( h, r.begin(), r.end(), c.isClosed() ); double length1 = DSSlength.eval(); trace.info() << "Length (h=" << h << "): " << length1 << endl; //! [shapeGridCurveEstimator-lengthEstimation] //@TODO correct init method of trueLengthEstimator (remove &flower) //! [shapeGridCurveEstimator-trueLengthEstimation] typedef ParametricShapeArcLengthFunctor< Flower > Length; TrueGlobalEstimatorOnPoints< Range::ConstIterator, Flower, Length > trueLengthEstimator; trueLengthEstimator.init( h, r.begin(), r.end(), &flower, c.isClosed()); double trueLength = trueLengthEstimator.eval(); trace.info() << "ground truth: " << trueLength << endl; //! [shapeGridCurveEstimator-trueLengthEstimation] //! [shapeGridCurveEstimator-higher] //implicit digitization at higher resolution h = 0.1; dig.init( flower.getLowerBound()+Z2i::Vector(-1,-1), flower.getUpperBound()+Z2i::Vector(1,1), h ); //a greater domain is needed in the Khalimsky space ks.init( dig.getLowerBound(), dig.getUpperBound(), true ); //searching for one boundary element bel = Surfaces<Z2i::KSpace>::findABel( ks, dig, 10000 ); //tracking Surfaces<Z2i::KSpace> ::track2DBoundaryPoints( boundaryPoints, ks, sAdj, dig, bel ); //reset grid curve and its points range c.initFromVector( boundaryPoints ); Range r2 = c.getPointsRange(); //estimate length DSSlength.init( h, r2.begin(), r2.end(), c.isClosed() ); double length2 = DSSlength.eval(); trace.info() << "Length (h=" << h << "): " << length2 << endl; //! [shapeGridCurveEstimator-higher] aBoard.clear(); aBoard << c; aBoard.saveEPS("DisplayGridCurve01.eps"); return 0; }
bool testTrueLocalEstimatorOnShapeDigitization( const string & name, Shape & aShape, double h ) { using namespace Z2i; trace.beginBlock ( ( "Testing TrueLocalEstimator on digitization of " + name ). c_str() ); // Creates a digitizer on the window (xLow, xUp). typedef Space::RealPoint RealPoint; RealPoint xLow( -10.0, -10.0 ); RealPoint xUp( 10.0, 10.0 ); GaussDigitizer<Space,Shape> dig; dig.attach( aShape ); // attaches the shape. dig.init( xLow, xUp, h ); // The domain size is given by the digitizer according to the window // and the step. Domain domain = dig.getDomain(); // Create cellular space KSpace K; bool ok = K.init( dig.getLowerBound(), dig.getUpperBound(), true ); if ( ! ok ) { std::cerr << "[testTrueLocalEstimatorOnShapeDigitization]" << " error in creating KSpace." << std::endl; } else try { // Extracts shape boundary SurfelAdjacency<KSpace::dimension> SAdj( true ); SCell bel = Surfaces<KSpace>::findABel( K, dig, 10000 ); // Getting the consecutive surfels of the 2D boundary std::vector<Point> points; Surfaces<KSpace>::track2DBoundaryPoints( points, K, SAdj, dig, bel ); // Create GridCurve GridCurve<KSpace> gridcurve; gridcurve.initFromVector( points ); typedef GridCurve<KhalimskySpaceND<2> >::PointsRange Range; typedef Range::ConstIterator ConstIteratorOnPoints; typedef ParametricShapeCurvatureFunctor< Shape > Curvature; TrueLocalEstimatorOnPoints< ConstIteratorOnPoints, Shape, Curvature > curvatureEstimator; Range r = gridcurve.getPointsRange();//building range curvatureEstimator.init( h, r.begin(), r.end(), &aShape, true); std::cout << "# idx x y kappa" << endl; unsigned int i = 0; for ( ConstIteratorOnPoints it = r.begin(), ite = r.end(); it != ite; ++it, ++i ) { RealPoint x = *it; double kappa = curvatureEstimator.eval( it ); std::cout << i << " " << x.at( 0 ) << " " << x.at( 1 ) << " " << kappa << std::endl; } } catch ( InputException e ) { std::cerr << "[testTrueLocalEstimatorOnShapeDigitization]" << " error in finding a bel." << std::endl; ok = false; } trace.emphase() << ( ok ? "Passed." : "Error." ) << endl; trace.endBlock(); return ok; }
bool testDigitization( const Shape & aShape, double h, const string & fileName ) { typedef typename Space::Point Point; typedef typename Space::RealPoint RealPoint; typedef HyperRectDomain<Space> Domain; typedef typename DigitalSetSelector < Domain, BIG_DS + HIGH_ITER_DS + HIGH_BEL_DS >::Type MySet; // Creates a digitizer on the window (xLow, xUp). RealPoint xLow( -5.3, -4.3 ); RealPoint xUp( 7.4, 4.7 ); GaussDigitizer<Space,Shape> dig; dig.attach( aShape ); // attaches the shape. dig.init( xLow, xUp, h ); // The domain size is given by the digitizer according to the window // and the step. Domain domain = dig.getDomain(); // ( dig.getLowerBound(), dig.getUpperBound() ); MySet aSet( domain ); // Creates a set from the digitizer. Shapes<Domain>::shaper( aSet, dig ); // Create cellular space typedef Z2i::KSpace KSpace; typedef Z2i::SCell SCell; KSpace K; bool ok = K.init( dig.getLowerBound(), dig.getUpperBound(), true ); ASSERT( ok ); SurfelAdjacency<KSpace::dimension> SAdj( true ); // Extracts shape boundary SCell bel = Surfaces<KSpace>::findABel( K, dig, 10000 ); // Getting the consecutive surfels of the 2D boundary std::vector<Point> points; Surfaces<KSpace>::track2DBoundaryPoints( points, K, SAdj, dig, bel ); GridCurve<KSpace> gridcurve; gridcurve.initFromVector( points ); // Display all Board2D board; board.setUnit( LibBoard::Board::UCentimeter ); board << SetMode( domain.styleName(), "Paving" ) << domain << aSet; board << SetMode( gridcurve.styleName(), "Edges" ) << CustomStyle( bel.styleName(), new CustomColors( DGtal::Color( 0, 0, 0 ), DGtal::Color( 0, 192, 0 ) ) ) << gridcurve; board << SetMode( gridcurve.styleName(), "Points" ) << CustomStyle( bel.styleName(), new CustomColors( DGtal::Color( 255, 0, 0 ), DGtal::Color( 200, 0, 0 ) ) ) << gridcurve; board.saveEPS( ( fileName + ".eps" ).c_str() ); board.saveSVG( ( fileName + ".svg" ).c_str() ); return true; }