bool testNormaliation() { trace.beginBlock ( "Testing normalization ..." ); Point p1( 0, 0, 0 ); Point p2( 0, 10 , 0); Point p3( 10, 10, 0); Point p4(10, 0, 100 ); Point p5( 20, 0 , 0); Point p6( 20, 10, 0); KSpace k; k.init(Point(2,2,2), Point(4,4,4), true); Board3D<Space,KSpace> board(k); board << p1<<p2<<p3<<p4; board.saveOBJ("dgtalBoard3D-norm.obj", true); board.saveOBJ("dgtalBoard3D-wonorm.obj"); trace.endBlock(); return true; }
int main() { KSpace K; Point plow(-3,-2); Point pup(5,3); Domain domain( plow, pup ); Board2D board; // for 2D display K.init( plow, pup, true ); board << SetMode( domain.styleName(), "Paving" ) << domain; Cell pixlow = K.uSpel( plow ); // pixel (-3*2+1,-2*2+1) Cell ptlow = K.uPointel( plow ); // pointel (-3*2,-2*2) Cell pixup = K.uSpel( pup ); // pixel (5*2+1,3*2+1) Cell ptup1 = K.uPointel( pup ); // pointel (5*2,3*2) Cell ptup2 = K.uTranslation( ptup1, Point::diagonal() ); // pointel (6*2,4*2) Cell linelb = K.uCell( Point( 1, 0 ) ); // linel (1,0) bottom Cell linelt = K.uCell( Point( 1, 2 ) ); // linel (1,2) top Cell linell = K.uCell( Point( 0, 1 ) ); // linel (0,1) left Cell linelr = K.uCell( Point( 2, 1 ) ); // linel (2,1) right board << CustomStyle( ptlow.styleName(), new CustomColors( Color( 0, 0, 200 ), Color( 100, 100, 255 ) ) ) << ptlow << ptup2; board << CustomStyle( pixlow.styleName(), new CustomColors( Color( 200, 0, 0 ), Color( 255, 100, 100 ) ) ) << pixlow << pixup; board << CustomStyle( linelb.styleName(), new CustomColors( Color( 0, 200, 0 ), Color( 100, 255, 100 ) ) ) << linelb << linelt << linell << linelr; board.saveSVG("ctopo-1.svg"); board.saveEPS("ctopo-1.eps"); return 0; }
void ballGenerator(const int& size, double aCx, double aCy, double aR, GridCurve<TKSpace>& gc) { ASSERT( aR < (double) size ); // Types typedef TKSpace KSpace; typedef typename KSpace::SCell SCell; typedef typename KSpace::Space Space; typedef typename Space::Point Point; KSpace K; bool ok = K.init( Point(-size,-size), Point(size,size), true ); if ( ! ok ) { std::cerr << " error in creating KSpace." << std::endl; } try { BallPredicate<Point> dig(aCx, aCy, aR); // 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 ); gc.initFromVector(points); } catch ( InputException e ) { std::cerr << " error in finding a bel." << std::endl; } }
int main( int argc, char** argv ) { if ( argc < 4 ) { usage( argc, argv ); return 1; } std::string inputFilename = argv[ 1 ]; unsigned int minThreshold = atoi( argv[ 2 ] ); unsigned int maxThreshold = atoi( argv[ 3 ] ); //! [volScanBoundary-readVol] trace.beginBlock( "Reading vol file into an image." ); typedef ImageSelector < Domain, int>::Type Image; Image image = VolReader<Image>::importVol(inputFilename); DigitalSet set3d (image.domain()); SetFromImage<DigitalSet>::append<Image>(set3d, image, minThreshold, maxThreshold); trace.endBlock(); //! [volScanBoundary-readVol] //! [volScanBoundary-KSpace] trace.beginBlock( "Construct the Khalimsky space from the image domain." ); KSpace ks; bool space_ok = ks.init( image.domain().lowerBound(), image.domain().upperBound(), true ); if (!space_ok) { trace.error() << "Error in the Khamisky space construction."<<std::endl; return 2; } trace.endBlock(); //! [volScanBoundary-KSpace] //! [volScanBoundary-ExtractingSurface] trace.beginBlock( "Extracting boundary by scanning the space. " ); KSpace::SCellSet boundary; Surfaces<KSpace>::sMakeBoundary( boundary, ks, set3d, image.domain().lowerBound(), image.domain().upperBound() ); trace.endBlock(); //! [volScanBoundary-ExtractingSurface] //! [volScanBoundary-DisplayingSurface] trace.beginBlock( "Displaying surface in Viewer3D." ); QApplication application(argc,argv); Viewer3D viewer; viewer.show(); viewer << CustomColors3D(Color(250, 0, 0 ), Color( 128, 128, 128 ) ); unsigned long nbSurfels = 0; for ( KSpace::SCellSet::const_iterator it = boundary.begin(), it_end = boundary.end(); it != it_end; ++it, ++nbSurfels ) viewer << *it; viewer << Viewer3D::updateDisplay; trace.info() << "nb surfels = " << nbSurfels << std::endl; trace.endBlock(); return application.exec(); //! [volScanBoundary-DisplayingSurface] }
bool testFindABel() { typedef typename KSpace::Point Point; typedef SpaceND< KSpace::dimension, typename KSpace::Integer > Space; typedef HyperRectDomain<Space> Domain; typedef typename DigitalSetSelector< Domain, BIG_DS+HIGH_BEL_DS >::Type DigitalSet; typedef typename KSpace::SCell SCell; typedef SetPredicate<DigitalSet> PointPredicate; trace.beginBlock("Test FindABel"); Point low(-3,-3,-3), high(3,3,3); Domain domain( low, high ); DigitalSet shape_set( domain ); PointPredicate pp( shape_set ); KSpace K; K.init( low, high, true ); Point p000(0,0,0), p001(0,0,1), p010(0,1,0), p011(0,1,1), p100(1,0,0), p101(1,0,1), p110(1,1,0), p111(1,1,1); shape_set.insert( p000 ); shape_set.insert( p100 ); Surfaces<KSpace>::findABel( K, pp , p000 , p011 ); Surfaces<KSpace>::findABel( K, pp , p000 , p110 ); Surfaces<KSpace>::findABel( K, pp , p000 , p111 ); Surfaces<KSpace>::findABel( K, pp , p000 , p101 ); SCell s010 = Surfaces<KSpace>::findABel( K, pp , p000 , p010 ); SCell s001 = Surfaces<KSpace>::findABel( K, pp , p000 , p001 ); trace.endBlock(); return ( (s010 == SCell( Point(1,2,1), true ) ) && (s001 == SCell( Point(1,1,2), false ) ) ); }
//----------------------------------------------------------------------------- // Testing LightImplicitDigitalSurface //----------------------------------------------------------------------------- bool testLightImplicitDigitalSurface() { using namespace Z3i; typedef ImplicitDigitalEllipse3<Point> ImplicitDigitalEllipse; typedef LightImplicitDigitalSurface<KSpace,ImplicitDigitalEllipse> Boundary; typedef Boundary::SurfelConstIterator ConstIterator; typedef Boundary::Tracker Tracker; typedef Boundary::Surfel Surfel; unsigned int nbok = 0; unsigned int nb = 0; trace.beginBlock ( "Testing block ... LightImplicitDigitalSurface" ); Point p1( -10, -10, -10 ); Point p2( 10, 10, 10 ); KSpace K; nbok += K.init( p1, p2, true ) ? 1 : 0; nb++; trace.info() << "(" << nbok << "/" << nb << ") " << "K.init() is ok" << std::endl; ImplicitDigitalEllipse ellipse( 6.0, 4.5, 3.4 ); Surfel bel = Surfaces<KSpace>::findABel( K, ellipse, 10000 ); Boundary boundary( K, ellipse, SurfelAdjacency<KSpace::dimension>( true ), bel ); unsigned int nbsurfels = 0; for ( ConstIterator it = boundary.begin(), it_end = boundary.end(); it != it_end; ++it ) { ++nbsurfels; } trace.info() << nbsurfels << " surfels found." << std::endl; trace.beginBlock ( "Checks if adjacent surfels are part of the surface." ); for ( ConstIterator it = boundary.begin(), it_end = boundary.end(); it != it_end; ++it ) { Tracker* ptrTracker = boundary.newTracker( *it ); Surfel s = ptrTracker->current(); Dimension trackDir = * K.sDirs( s ); Surfel s1, s2; // unsigned int m1 = ptrTracker->adjacent( s1, trackDir, true ); // unsigned int m2 = ptrTracker->adjacent( s2, trackDir, false ); // trace.info() << "s = " << s << std::endl; // trace.info() << "s1 = " << s1 << " m1 = " << m1 << std::endl; // trace.info() << "s2 = " << s2 << " m2 = " << m2 << std::endl; nb++, nbok += boundary.isInside( s1 ) ? 1 : 0; // trace.info() << "(" << nbok << "/" << nb << ") " // << "boundary.isInside( s1 )" << std::endl; nb++, nbok += boundary.isInside( s2 ) ? 1 : 0; // trace.info() << "(" << nbok << "/" << nb << ") " // << "boundary.isInside( s2 )" << std::endl; delete ptrTracker; } trace.info() << "(" << nbok << "/" << nb << ") isInside tests." << std::endl; trace.endBlock(); trace.endBlock(); return nbok == nb; }
FixtureComplex &create_complex_from_object(FixtureObject &input_obj) { ks_fixture.init(input_obj.domain().lowerBound(), input_obj.domain().upperBound(), true); complex_fixture = FixtureComplex(ks_fixture); complex_fixture.construct(input_obj); return complex_fixture; }
FixtureComplex &create_complex_from_set(const FixtureDigitalSet &input_set) { ks_fixture.init(input_set.domain().lowerBound(), input_set.domain().upperBound(), true); complex_fixture = FixtureComplex(ks_fixture); complex_fixture.construct(input_set); return complex_fixture; }
/** * Example of a test. To be completed. * */ bool testDigitalSetBoundary() { unsigned int nbok = 0; unsigned int nb = 0; trace.beginBlock ( "Testing block ... DigitalSetBoundary" ); using namespace Z2i; typedef DigitalSetBoundary<KSpace,DigitalSet> Boundary; typedef Boundary::SurfelConstIterator ConstIterator; typedef Boundary::Tracker Tracker; typedef Boundary::Surfel Surfel; Point p1( -10, -10 ); Point p2( 10, 10 ); Domain domain( p1, p2 ); DigitalSet dig_set( domain ); Shapes<Domain>::addNorm2Ball( dig_set, Point( 0, 0 ), 5 ); Shapes<Domain>::removeNorm2Ball( dig_set, Point( 0, 0 ), 1 ); KSpace K; nbok += K.init( domain.lowerBound(), domain.upperBound(), true ) ? 1 : 0; nb++; trace.info() << "(" << nbok << "/" << nb << ") " << "K.init() is ok" << std::endl; Boundary boundary( K, dig_set ); unsigned int nbsurfels = 0; for ( ConstIterator it = boundary.begin(), it_end = boundary.end(); it != it_end; ++it ) { ++nbsurfels; } trace.info() << nbsurfels << " surfels found." << std::endl; nb++, nbok += nbsurfels == ( 12 + 44 ) ? 1 : 0; trace.info() << "(" << nbok << "/" << nb << ") " << "nbsurfels == (12 + 44 )" << std::endl; for ( ConstIterator it = boundary.begin(), it_end = boundary.end(); it != it_end; ++it ) { Tracker* ptrTracker = boundary.newTracker( *it ); Surfel s = ptrTracker->current(); Dimension trackDir = * K.sDirs( s ); Surfel s1, s2; unsigned int m1 = ptrTracker->adjacent( s1, trackDir, true ); unsigned int m2 = ptrTracker->adjacent( s2, trackDir, false ); trace.info() << "s = " << s << std::endl; trace.info() << "s1 = " << s1 << " m1 = " << m1 << std::endl; trace.info() << "s2 = " << s2 << " m2 = " << m2 << std::endl; nb++, nbok += boundary.isInside( s1 ) ? 1 : 0; trace.info() << "(" << nbok << "/" << nb << ") " << "boundary.isInside( s1 )" << std::endl; nb++, nbok += boundary.isInside( s2 ) ? 1 : 0; trace.info() << "(" << nbok << "/" << nb << ") " << "boundary.isInside( s2 )" << std::endl; delete ptrTracker; } trace.endBlock(); return nbok == nb; }
bool testBallQuad() { unsigned int nbok = 0; unsigned int nb = 0; trace.beginBlock ( "Testing... Ball with quadnormal"); using namespace Z3i; typedef ImplicitDigitalBall3<Point> ImplicitDigitalBall; typedef ImplicitDigitalSurface<KSpace,ImplicitDigitalBall> Boundary; typedef Boundary::SurfelConstIterator ConstIterator; typedef Boundary::Surfel Surfel; Point p1( -50, -50, -50 ); Point p2( 50, 50, 50 ); KSpace K; nbok += K.init( p1, p2, true ) ? 1 : 0; nb++; trace.info() << "(" << nbok << "/" << nb << ") " << "K.init() is ok" << std::endl; ImplicitDigitalBall ball( 30.0 ); Surfel bel = Surfaces<KSpace>::findABel( K, ball, 10000 ); Boundary boundary( K, ball, SurfelAdjacency<KSpace::dimension>( true ), bel ); unsigned int nbsurfels = 0; Board3D<Space,KSpace> board(K); for ( ConstIterator it = boundary.begin(), it_end = boundary.end(); it != it_end; ++it ) { ++nbsurfels; Display3DFactory<>::drawOrientedSurfelWithNormal(board, *it, board.embedKS(*it).getNormalized()); } trace.info() << nbsurfels << " surfels found." << std::endl; board.saveOBJ("testball.obj"); nbok += true ? 1 : 0; nb++; trace.info() << "(" << nbok << "/" << nb << ") " << "true == true" << std::endl; trace.endBlock(); return nbok == nb; }
bool testBallQuad(int argc, char **argv) { unsigned int nbok = 0; unsigned int nb = 0; QApplication application(argc, argv); trace.beginBlock ( "Testing... Ball with quadnormal"); using namespace Z3i; typedef ImplicitDigitalBall3<Point> ImplicitDigitalBall; typedef ImplicitDigitalSurface<KSpace,ImplicitDigitalBall> Boundary; typedef Boundary::SurfelConstIterator ConstIterator; typedef Boundary::Surfel Surfel; Point p1( -100, -100, -100 ); Point p2( 100, 100, 100 ); KSpace K; nbok += K.init( p1, p2, true ) ? 1 : 0; nb++; trace.info() << "(" << nbok << "/" << nb << ") " << "K.init() is ok" << std::endl; ImplicitDigitalBall ball( 60.0 ); Surfel bel = Surfaces<KSpace>::findABel( K, ball, 10000 ); Boundary boundary( K, ball, SurfelAdjacency<KSpace::dimension>( true ), bel ); unsigned int nbsurfels = 0; Viewer3D<Space,KSpace> viewer(K); viewer.setWindowTitle("simpleViewer"); viewer.show(); for ( ConstIterator it = boundary.begin(), it_end = boundary.end(); it != it_end; ++it ) { ++nbsurfels; Display3DFactory<>::drawOrientedSurfelWithNormal(viewer, *it, viewer.embedKS(*it).getNormalized()); } trace.info() << nbsurfels << " surfels found." << std::endl; viewer << Display3D<Space, KSpace>::updateDisplay; bool res = application.exec(); return res; }
bool testQuadNorm() { unsigned int nbok = 0; unsigned int nb = 0; trace.beginBlock ( "Testing Board3D Quads ..." ); Point p1( 0, 0, 0 ); Point p2( 0, 1 , 0); Point p3( 1, 1, 0); Point p4(1, 0, 0 ); Point p5( 2, 0 , 0); Point p6( 2, 1, 0); RealVector n(1,1,1); RealVector n2(0,1,1); KSpace k; k.init(Point(2,2,2), Point(4,4,4), true); Board3D<Space,KSpace> board(k); board << CustomColors3D(Color(0, 255,0),Color(0, 255, 0)); board.addQuadWithNormal(p1,p2,p3,p4, n.getNormalized(), true); board << CustomColors3D(Color(0, 0, 255),Color(0, 0, 255)); board.addQuadWithNormal(p4,p5,p6,p3, n2.getNormalized(), true); Cell surfel = k.uCell( Point( 4,5,5) ); Display3DFactory<Space,KSpace>::drawUnorientedSurfelWithNormal( board, surfel, n2.getNormalized()); board.saveOBJ("dgtalBoard3D.quad.obj"); nbok += true ? 1 : 0; nb++; trace.info() << "(" << nbok << "/" << nb << ") " << "true == true" << std::endl; trace.endBlock(); return nbok == nb; }
bool testRaySurfelIntersection() { unsigned int nbok = 0; unsigned int nb = 0; trace.beginBlock ( "Testing RaySurfel ..." ); using namespace Z3i; KSpace k; k.init(Point(0,0,0), Point(10,10,10), true); typedef RayIntersectionPredicate<KSpace::Cell::Point> Ray; Ray ray(KSpace::Cell::Point(0,0,0), KSpace::Cell::Point(2,1,1)); KSpace::Surfel surf = k.sCell( Point( 2,1,1) ); KSpace::Surfel surf2 = k.sCell( Point( 2,7,7) ); trace.info() << "Ray intersection with surf "<<std::endl; nbok += ray(surf) ? 1 : 0; nb++; trace.info() << "(" << nbok << "/" << nb << ") " << "true " << std::endl; trace.info()<<std::endl; trace.info() << "Ray intersection with surf2 "<<std::endl; nbok += !ray(surf2 ) ? 1 : 0; nb++; trace.info() << "(" << nbok << "/" << nb << ") " << "false " << std::endl; trace.info()<<std::endl; trace.endBlock(); return nbok == nb; }
int main( int, char** ) { using namespace Z3i; typedef DGtal::ImplicitDigitalEllipse3<Point> ImplicitDigitalEllipse; typedef KSpace::SCell Surfel; bool res; trace.beginBlock ( "Testing class Object" ); Point p1( -200, -200, -200 ); Point p2( 200, 200, 200 ); KSpace K; if ( K.init( p1, p2, true ) ) { ImplicitDigitalEllipse ellipse( 180.0, 135.0, 102.0 ); Surfel bel = Surfaces<KSpace>::findABel( K, ellipse, 10000 ); res = testLightImplicitDigitalSurface<KSpace, ImplicitDigitalEllipse> ( K, ellipse, bel ); } else res = false; trace.emphase() << ( res ? "Passed." : "Error." ) << endl; trace.endBlock(); return res ? 0 : 1; }
int main( int argc, char** argv ) { //! [greedy-plane-segmentation-parseCommandLine] // parse command line ---------------------------------------------- po::options_description general_opt("Allowed options are: "); general_opt.add_options() ("help,h", "display this message") ("input-file,i", po::value<std::string>()->default_value( examplesPath + "samples/Al.100.vol" ), "the volume file (.vol)" ) ("threshold,t", po::value<unsigned int>()->default_value(1), "the value that defines the isosurface in the image (an integer between 0 and 255)." ) ("width-num,w", po::value<unsigned int>()->default_value(1), "the numerator of the rational width (a non-null integer)." ) ("width-den,d", po::value<unsigned int>()->default_value(1), "the denominator of the rational width (a non-null integer)." ); bool parseOK = true; po::variables_map vm; try { po::store(po::parse_command_line(argc, argv, general_opt), vm); } catch ( const std::exception & ex ) { parseOK = false; trace.info() << "Error checking program options: "<< ex.what()<< endl; } po::notify(vm); if ( ! parseOK || vm.count("help") || ( argc <= 1 ) ) { std::cout << "Usage: " << argv[0] << " [-i <fileName.vol>] [-t <threshold>] [-w <num>] [-d <den>]" << std::endl << "Segments the surface at given threshold within given volume into digital planes of rational width num/den." << std::endl << general_opt << std::endl; return 0; } string inputFilename = vm["input-file"].as<std::string>(); unsigned int threshold = vm["threshold"].as<unsigned int>(); unsigned int widthNum = vm["width-num"].as<unsigned int>(); unsigned int widthDen = vm["width-den"].as<unsigned int>(); //! [greedy-plane-segmentation-parseCommandLine] //! [greedy-plane-segmentation-loadVolume] QApplication application(argc,argv); typedef ImageSelector < Domain, int>::Type Image; Image image = VolReader<Image>::importVol(inputFilename); DigitalSet set3d (image.domain()); SetFromImage<DigitalSet>::append<Image>(set3d, image, threshold,255); //! [greedy-plane-segmentation-loadVolume] //! [greedy-plane-segmentation-makeSurface] trace.beginBlock( "Set up digital surface." ); // We initializes the cellular grid space used for defining the // digital surface. KSpace ks; bool ok = ks.init( set3d.domain().lowerBound(), set3d.domain().upperBound(), true ); if ( ! ok ) std::cerr << "[KSpace.init] Failed." << std::endl; SurfelAdjacency<KSpace::dimension> surfAdj( true ); // interior in all directions. MyDigitalSurfaceContainer* ptrSurfContainer = new MyDigitalSurfaceContainer( ks, set3d, surfAdj ); MyDigitalSurface digSurf( ptrSurfContainer ); // acquired trace.endBlock(); //! [greedy-plane-segmentation-makeSurface] //! [greedy-plane-segmentation-segment] trace.beginBlock( "Segment into planes." ); std::set<Vertex> processedVertices; std::vector<SegmentedPlane*> segmentedPlanes; std::map<Vertex,SegmentedPlane*> v2plane; Point p; Dimension axis; unsigned int j = 0; unsigned int nb = digSurf.size(); for ( ConstIterator it = digSurf.begin(), itE= digSurf.end(); it != itE; ++it ) { if ( ( (++j) % 50 == 0 ) || ( j == nb ) ) trace.progressBar( j, nb ); Vertex v = *it; if ( processedVertices.find( v ) != processedVertices.end() ) // already in set continue; // process to next vertex SegmentedPlane* ptrSegment = new SegmentedPlane; segmentedPlanes.push_back( ptrSegment ); // to delete them afterwards. axis = ks.sOrthDir( v ); ptrSegment->plane.init( axis, 500, widthNum, widthDen ); // The visitor takes care of all the breadth-first traversal. Visitor visitor( digSurf, v ); while ( ! visitor.finished() ) { Visitor::Node node = visitor.current(); v = node.first; if ( processedVertices.find( v ) == processedVertices.end() ) { // Vertex is not in processedVertices axis = ks.sOrthDir( v ); p = ks.sCoords( ks.sDirectIncident( v, axis ) ); bool isExtended = ptrSegment->plane.extend( p ); if ( isExtended ) { // surfel is in plane. processedVertices.insert( v ); v2plane[ v ] = ptrSegment; visitor.expand(); } else // surfel is not in plane and should not be used in the visit. visitor.ignore(); } else // surfel is already in some plane. visitor.ignore(); } // Assign random color for each plane. ptrSegment->color = Color( random() % 256, random() % 256, random() % 256, 255 ); } trace.endBlock(); //! [greedy-plane-segmentation-segment] //! [greedy-plane-segmentation-visualization] Viewer3D viewer; viewer.show(); for ( std::map<Vertex,SegmentedPlane*>::const_iterator it = v2plane.begin(), itE = v2plane.end(); it != itE; ++it ) { viewer << CustomColors3D( it->second->color, it->second->color ); viewer << ks.unsigns( it->first ); } viewer << Display3D::updateDisplay; //! [greedy-plane-segmentation-visualization] //! [greedy-plane-segmentation-freeMemory] for ( std::vector<SegmentedPlane*>::iterator it = segmentedPlanes.begin(), itE = segmentedPlanes.end(); it != itE; ++it ) delete *it; segmentedPlanes.clear(); v2plane.clear(); //! [greedy-plane-segmentation-freeMemory] return application.exec(); }
int main( int argc, char** argv ) { QApplication application(argc,argv); // parse command line ---------------------------------------------- using namespace DGtal::functors; namespace po = boost::program_options; po::options_description general_opt("Allowed options are: "); general_opt.add_options() ("help,h", "display this message") ("polynomial,p", po::value<string>(), "the implicit polynomial whose zero-level defines the shape of interest." ) ("minAABB,a", po::value<double>()->default_value( -10.0 ), "the min value of the AABB bounding box (domain)" ) ("maxAABB,A", po::value<double>()->default_value( 10.0 ), "the max value of the AABB bounding box (domain)" ) ("gridstep,g", po::value< double >()->default_value( 1.0 ), "the gridstep that defines the digitization (often called h). " ) ("estimator,e", po::value<string>()->default_value( "True" ), "the chosen normal estimator: True | VCM | II | Trivial" ) ("R-radius,R", po::value<double>()->default_value( 5 ), "the constant for parameter R in R(h)=R h^alpha (VCM)." ) ("r-radius,r", po::value<double>()->default_value( 3 ), "the constant for parameter r in r(h)=r h^alpha (VCM,II,Trivial)." ) ("kernel,k", po::value<string>()->default_value( "hat" ), "the function chi_r, either hat or ball." ) ("alpha", po::value<double>()->default_value( 0.0 ), "the parameter alpha in r(h)=r h^alpha (VCM)." ) ("trivial-radius,t", po::value<double>()->default_value( 3 ), "the parameter t defining the radius for the Trivial estimator. Also used for reorienting the VCM." ) ("embedding,E", po::value<int>()->default_value( 0 ), "the surfel -> point embedding for VCM estimator: 0: Pointels, 1: InnerSpel, 2: OuterSpel." ) ("maxiter", po::value<int>()->default_value( 20 ), "the maximal number of iterations for True estimator (default is 20).") ("accuracy", po::value<double>()->default_value( 0.1 ), "the maximal accuracy for True estimator (default is 0.1).") ("gamma", po::value<double>()->default_value( 0.01 ), "the maximal gamma step for True estimator (default is 0.01).") ("output,o", po::value<string>()->default_value( "output" ), "the output basename. All generated files will have the form <arg>-*, for instance <arg>-area-<gridstep>.txt." ) ; bool parseOK=true; po::variables_map vm; try{ po::store(po::parse_command_line(argc, argv, general_opt), vm); }catch(const exception& ex){ parseOK=false; trace.info()<< "Error checking program options: "<< ex.what()<< endl; } po::notify(vm); if( !parseOK || vm.count("help")) { cout << "Usage: " << argv[0] << " -p \"90-x^2-y^2-z^2\" -h 1 -R 5 -r 6 -t 2\n" << "Computes the area of a digital surface, defined as an implicit polynomial surface, by integration of normal estimation." << endl << general_opt << "\n"; cout << "Example:\n" << "./area-integration -p \"81-x^2-y^2-z^2\" -e VCM -R 3 -r 3 -g 0.5 # aire de la sphere de rayon 9, discrétisé au pas 0.5" << endl << " - ellipse : 90-3*x^2-2*y^2-z^2 " << endl << " - torus : -1*(x^2+y^2+z^2+6*6-2*2)^2+4*6*6*(x^2+y^2) " << endl << " - rcube : 6561-x^4-y^4-z^4" << endl << " - goursat : 8-0.03*x^4-0.03*y^4-0.03*z^4+2*x^2+2*y^2+2*z^2" << endl << " - distel : 10000-(x^2+y^2+z^2+1000*(x^2+y^2)*(x^2+z^2)*(y^2+z^2))" << endl << " - leopold : 100-(x^2*y^2*z^2+4*x^2+4*y^2+3*z^2)" << endl << " - diabolo : x^2-(y^2+z^2)^2" << endl << " - heart : -1*(x^2+2.25*y^2+z^2-1)^3+x^2*z^3+0.1125*y^2*z^3" << endl << " - crixxi : -0.9*(y^2+z^2-1)^2-(x^2+y^2-1)^3" << endl << " - goursat_dodecahedron: z^6-5*(x^2+y^2)*z^4+5*(x^2+y^2)^2*z^2-2*(x^4-10*x^2*y^2+5*y^4)*x*z+1*(x^2+y^2+z^2)^3+(-1)*(5)^2*(x^2+y^2+z^2)^2+1*(5)^4*(x^2+y^2+z^2)+(-1)*(5)^6" << endl << " - goursat_icosahedron : z^6-5*(x^2+y^2)*z^4+5*(x^2+y^2)^2*z^2-2*(x^4-10*x^2*y^2+5*y^4)*x*z+(-1)*(x^2+y^2+z^2)^3+(0)*(5)^2*(x^2+y^2+z^2)^2+(-1)*(5)^4*(x^2+y^2+z^2)+(1)*(5)^6" << endl << " - goursat_60lines : z^6-5*(x^2+y^2)*z^4+5*(x^2+y^2)^2*z^2-2*(x^4-10*x^2*y^2+5*y^4)*x*z+(0)*(x^2+y^2+z^2)^3+(5)*(5)^2*(x^2+y^2+z^2)^2+(-45)*(5)^4*(x^2+y^2+z^2)+(71)*(5)^6" << endl; return 0; } if ( ! vm.count( "polynomial" ) ) { cerr << "Need parameter --polynomial" << endl; return 1; } trace.beginBlock( "Make implicit shape..." ); typedef Z3i::Space Space; typedef double Scalar; typedef MPolynomial< 3, Scalar > Polynomial3; typedef MPolynomialReader<3, Scalar> Polynomial3Reader; typedef ImplicitPolynomial3Shape<Space> ImplicitShape; string poly_str = vm[ "polynomial" ].as<string>(); Polynomial3 poly; Polynomial3Reader reader; string::const_iterator iter = reader.read( poly, poly_str.begin(), poly_str.end() ); if ( iter != poly_str.end() ) { trace.error() << "ERROR reading polynomial: I read only <" << poly_str.substr( 0, iter - poly_str.begin() ) << ">, and I built P=" << poly << std::endl; return 2; } CountedPtr<ImplicitShape> shape( new ImplicitShape( poly ) ); // smart pointer trace.endBlock(); trace.beginBlock( "Make implicit digital shape..." ); typedef Z3i::KSpace KSpace; typedef KSpace::Point Point; typedef Space::RealPoint RealPoint; typedef GaussDigitizer< Space, ImplicitShape > ImplicitDigitalShape; typedef ImplicitDigitalShape::Domain Domain; Scalar min_x = vm[ "minAABB" ].as<double>(); Scalar max_x = vm[ "maxAABB" ].as<double>(); Scalar h = vm[ "gridstep" ].as<double>(); RealPoint p1( min_x, min_x, min_x ); RealPoint p2( max_x, max_x, max_x ); CountedPtr<ImplicitDigitalShape> dshape( new ImplicitDigitalShape() ); dshape->attach( *shape ); dshape->init( p1, p2, h ); Domain domain = dshape->getDomain(); KSpace K; K.init( domain.lowerBound(), domain.upperBound(), true ); trace.info() << "- domain is " << domain << std::endl; trace.endBlock(); trace.beginBlock( "Make digital surface..." ); typedef LightImplicitDigitalSurface<KSpace,ImplicitDigitalShape> SurfaceContainer; typedef DigitalSurface< SurfaceContainer > Surface; typedef Surface::ConstIterator ConstIterator; typedef typename Surface::Surfel Surfel; SurfelAdjacency< KSpace::dimension > surfAdj( true ); Surfel bel; try { bel = Surfaces<KSpace>::findABel( K, *dshape, 10000 ); } catch (DGtal::InputException e) { trace.error() << "ERROR Unable to find bel." << std::endl; return 3; } SurfaceContainer* surfaceContainer = new SurfaceContainer( K, *dshape, surfAdj, bel ); CountedPtr<Surface> ptrSurface( new Surface( surfaceContainer ) ); // acquired trace.info() << "- surface component has " << ptrSurface->size() << " surfels." << std::endl; trace.endBlock(); string kernel = vm[ "kernel" ].as<string>(); double r = vm["r-radius"].as<double>(); double alpha = vm["alpha"].as<double>(); if ( alpha != 0.0 ) r *= pow( h, alpha-1.0 ); if ( kernel == "hat" ) { typedef typename KSpace::Point Point; typedef HatPointFunction<Point,double> KernelFunction; KernelFunction chi_r( 1.0, r ); trace.info() << "- kernel hat r = " << r << std::endl; chooseEstimator( vm, K, *shape, *ptrSurface, chi_r, *dshape ); } else if ( kernel == "ball" ) { typedef typename KSpace::Point Point; typedef BallConstantPointFunction<Point,double> KernelFunction; KernelFunction chi_r( 1.0, r ); trace.info() << "- kernel ball r = " << r << std::endl; chooseEstimator( vm, K, *shape, *ptrSurface, chi_r, *dshape ); } return 0; }
int main( ) { KSpace K; Point plow(0,0,0); Point pup(1,1,0); Domain domain( plow, pup ); K.init( plow, pup, true ); Board3D<Space, KSpace> board(K); // drawing cells of dimension 3 SCell v2 = K.sSpel( Point( 1, 0, 0 ), KSpace::POS ); // +v SCell v3 = K.sSpel( Point( 0, 1, 0 ), KSpace::POS ); // +v SCell v4 = K.sSpel( Point( 1, 1, 0 ), KSpace::NEG ); // +v //! [SetKSIllustrationMode3D] SCell v = K.sSpel( Point( 0, 0, 0 ), KSpace::POS ); // +v board << SetMode3D( v.className(), "Illustration" ); //! [SetKSIllustrationMode3D] board << v << v2 << v3; board.saveOBJ("board3D-2-ks.obj"); Board3D<Space, KSpace> board2(K); // Surfel of Voxel (0,0) //! [KSIllustrationModeTransformed] SCell sx = K.sIncident( v, 0, true ); // surfel further along x DGtal::TransformedPrism tsx (sx, v); //! [KSIllustrationModeTransformed] SCell sy = K.sIncident( v, 1, true ); // surfel further along y SCell sz = K.sIncident( v, 2, true ); // surfel further along z SCell sxn = K.sIncident( v, 0, false ); // surfel further along x SCell syn = K.sIncident( v, 1, false ); // surfel further along y SCell szn = K.sIncident( v, 2, false ); // surfel further along z // Resizing and shifting the surfel towords its associated voxel (v). DGtal::TransformedPrism tsy (sy, v); DGtal::TransformedPrism tsz (sz, v); DGtal::TransformedPrism tsxn (sxn, v); DGtal::TransformedPrism tsyn (syn, v); DGtal::TransformedPrism tszn (szn, v); board2 << tsx << tsy << tsz << tsxn << tsyn << tszn; // Surfel of Voxel (1,0) SCell sx2 = K.sIncident( v2, 0, true ); // surfel further along x SCell sy2 = K.sIncident( v2, 1, true ); // surfel further along y SCell sz2 = K.sIncident( v2, 2, true ); // surfel further along z SCell sxn2 = K.sIncident( v2, 0, false ); // surfel further along x SCell syn2 = K.sIncident( v2, 1, false ); // surfel further along y SCell szn2 = K.sIncident( v2, 2, false ); // surfel further along z // Resizing and shifting the surfel towords its associated voxel (v2). DGtal::TransformedPrism tsx2 (sx2, v2); DGtal::TransformedPrism tsy2 (sy2, v2); DGtal::TransformedPrism tsz2 (sz2, v2); DGtal::TransformedPrism tsxn2 (sxn2, v2); DGtal::TransformedPrism tsyn2 (syn2, v2); DGtal::TransformedPrism tszn2 (szn2, v2); board2 << tsx2 << tsy2 << tsz2 << tsxn2 << tsyn2 << tszn2; // Surfel of Voxel (0,1) SCell sx3 = K.sIncident( v3, 0, true ); // surfel further along x SCell sy3 = K.sIncident( v3, 1, true ); // surfel further along y SCell sz3 = K.sIncident( v3, 2, true ); // surfel further along z SCell sxn3 = K.sIncident( v3, 0, false ); // surfel further along x SCell syn3 = K.sIncident( v3, 1, false ); // surfel further along y SCell szn3 = K.sIncident( v3, 2, false ); // surfel further along z // Shifting the surfel to its associated voxel (v3). DGtal::TransformedPrism tsx3 (sx3, v3); DGtal::TransformedPrism tsy3 (sy3, v3); DGtal::TransformedPrism tsz3 (sz3, v3); DGtal::TransformedPrism tsxn3 (sxn3, v3); DGtal::TransformedPrism tsyn3 (syn3, v3); DGtal::TransformedPrism tszn3 (szn3, v3); board2 << tsx3 << tsy3 << tsz3 << tsxn3 << tsyn3 << tszn3; std::cout << "save obj" << std::endl; board2.saveOBJ("board3D-2bis-ks.obj"); }
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; } }
int main( int argc, char** argv ) { typedef DGtal::ImageContainerBySTLVector<DGtal::Z3i::Domain, unsigned char > Image3D; typedef DGtal::ImageContainerBySTLVector<DGtal::Z2i::Domain, unsigned char > Image2D; // parse command line ---------------------------------------------- po::options_description general_opt("Allowed options are "); general_opt.add_options() ("help,h", "display this message") ("input,i", po::value<std::string>(), "vol file (.vol) , pgm3d (.p3d or .pgm3d) file or sdp (sequence of discrete points)" ) ("grid", "draw slice images using grid mode. " ) ("intergrid", "draw slice images using inter grid mode. " ) ("emptyMode", "remove the default boundingbox display " ) ("thresholdImage", "threshold the image to define binary shape" ) ("thresholdMin,m", po::value<int>()->default_value(0), "threshold min to define binary shape" ) ("thresholdMax,M", po::value<int>()->default_value(255), "threshold max to define binary shape" ) ("displaySDP,s", po::value<std::string>(), "display a set of discrete points (.sdp)" ) ("SDPindex", po::value<std::vector <unsigned int> >()->multitoken(), "specify the sdp index (by default 0,1,2).") ("SDPball", po::value<double>()->default_value(0.5), "use balls to display a set of discrete points (used with displaySDP option)") ("displayMesh", po::value<std::string>(), "display a Mesh given in OFF or OFS format. " ) ("displayDigitalSurface", "display the digital surface instead of display all the set of voxels (used with thresholdImage or displaySDP options)" ) ("colorizeCC", "colorize each Connected Components of the surface displayed by displayDigitalSurface option." ) ("colorSDP,c", po::value<std::vector <int> >()->multitoken(), "set the color discrete points: r g b a " ) ("colorMesh", po::value<std::vector <int> >()->multitoken(), "set the color of Mesh (given from displayMesh option) : r g b a " ) ("scaleX,x", po::value<float>()->default_value(1.0), "set the scale value in the X direction (default 1.0)" ) ("scaleY,y", po::value<float>()->default_value(1.0), "set the scale value in the Y direction (default 1.0)" ) ("scaleZ,z", po::value<float>()->default_value(1.0), "set the scale value in the Z direction (default 1.0)") #ifdef WITH_ITK ("dicomMin", po::value<int>()->default_value(-1000), "set minimum density threshold on Hounsfield scale") ("dicomMax", po::value<int>()->default_value(3000), "set maximum density threshold on Hounsfield scale") #endif ("transparency,t", po::value<uint>()->default_value(255), "transparency") ; bool parseOK=true; po::variables_map vm; try{ po::store(po::parse_command_line(argc, argv, general_opt), vm); }catch(const std::exception& ex){ parseOK=false; trace.info()<< "Error checking program options: "<< ex.what()<< endl; } po::notify(vm); if( !parseOK || vm.count("help")||argc<=1) { std::cout << "Usage: " << argv[0] << " [input]\n" << "Displays volume file as a voxel set by using QGLviewer" << general_opt << "\n"; return 0; } if(! vm.count("input")) { trace.error() << " The file name was defined" << endl; return 0; } string inputFilename = vm["input"].as<std::string>(); int thresholdMin = vm["thresholdMin"].as<int>(); int thresholdMax = vm["thresholdMax"].as<int>(); unsigned char transp = vm["transparency"].as<uint>(); QApplication application(argc,argv); float sx = vm["scaleX"].as<float>(); float sy = vm["scaleY"].as<float>(); float sz = vm["scaleZ"].as<float>(); double ballRadius = vm["SDPball"].as<double>(); string extension = inputFilename.substr(inputFilename.find_last_of(".") + 1); if(extension!="vol" && extension != "p3d" && extension != "pgm3D" && extension != "pgm3d" && extension != "sdp" && extension != "pgm" #ifdef WITH_ITK && extension !="dcm" #endif ){ trace.info() << "File extension not recognized: "<< extension << std::endl; return 0; } Viewer3DImage<>::ModeVisu mode; if(vm.count("emptyMode")) mode=Viewer3DImage<>::Empty; else if(vm.count("grid")) mode=Viewer3DImage<>::Grid; else if(vm.count("intergrid")) mode=Viewer3DImage<>::InterGrid; else mode=Viewer3DImage<>::BoundingBox; Viewer3DImage<> viewer(mode); viewer.setWindowTitle("simple Volume Viewer"); viewer.show(); viewer.setGLScale(sx, sy, sz); #ifdef WITH_ITK int dicomMin = vm["dicomMin"].as<int>(); int dicomMax = vm["dicomMax"].as<int>(); typedef DGtal::functors::Rescaling<int ,unsigned char > RescalFCT; Image3D image = extension == "dcm" ? DicomReader< Image3D, RescalFCT >::importDicom( inputFilename, RescalFCT(dicomMin, dicomMax, 0, 255) ) : GenericReader<Image3D>::import( inputFilename ); #else Image3D image = GenericReader<Image3D>::import( inputFilename ); #endif Domain domain = image.domain(); trace.info() << "Image loaded: "<<image<< std::endl; viewer.setVolImage(&image); viewer << Z3i::Point(512, 512, 0); // Used to display 3D surface Z3i::DigitalSet set3d(domain); viewer << Viewer3D<>::updateDisplay; if(vm.count("thresholdImage")){ GradientColorMap<long> gradient( thresholdMin, thresholdMax); gradient.addColor(Color::Blue); gradient.addColor(Color::Green); gradient.addColor(Color::Yellow); gradient.addColor(Color::Red); for(Domain::ConstIterator it = domain.begin(), itend=domain.end(); it!=itend; ++it){ unsigned char val= image( (*it) ); Color c= gradient(val); if(val<=thresholdMax && val >=thresholdMin){ if(!vm.count("displayDigitalSurface")){ viewer << CustomColors3D(Color((float)(c.red()), (float)(c.green()),(float)(c.blue()), transp), Color((float)(c.red()), (float)(c.green()),(float)(c.blue()), transp)); viewer << *it; } }else{ set3d.insert(*it); } } } if(vm.count("displaySDP")){ if(vm.count("colorSDP")){ std::vector<int> vcol= vm["colorSDP"].as<std::vector<int > >(); if(vcol.size()<4){ trace.error() << "Not enough parameter: color specification should contains four elements: red, green, blue and alpha values." << std::endl; return 0; } Color c(vcol[0], vcol[1], vcol[2], vcol[3]); viewer << CustomColors3D(c, c); } vector<Z3i::Point> vectVoxels; if(vm.count("SDPindex")) { std::vector<unsigned int > vectIndex = vm["SDPindex"].as<std::vector<unsigned int > >(); if(vectIndex.size()!=3){ trace.error() << "you need to specify the three indexes of vertex." << std::endl; return 0; } vectVoxels = PointListReader<Z3i::Point>::getPointsFromFile(vm["displaySDP"].as<std::string>(), vectIndex); }else{ vectVoxels = PointListReader<Z3i::Point>::getPointsFromFile(vm["displaySDP"].as<std::string>()); } for(unsigned int i=0;i< vectVoxels.size(); i++){ if(!vm.count("displayDigitalSurface")){ if(vm.count("SDPball")){ viewer.addBall (vectVoxels.at(i), ballRadius); }else{ viewer << vectVoxels.at(i); } }else{ set3d.insert(vectVoxels.at(i)); } } } if(vm.count("displayMesh")){ if(vm.count("colorMesh")){ std::vector<int> vcol= vm["colorMesh"].as<std::vector<int > >(); if(vcol.size()<4){ trace.error() << "Not enough parameter: color specification should contains four elements: red, green, blue and alpha values." << std::endl; return 0; } Color c(vcol[0], vcol[1], vcol[2], vcol[3]); viewer.setFillColor(c); } DGtal::Mesh<Z3i::RealPoint> aMesh(!vm.count("colorMesh")); MeshReader<Z3i::RealPoint>::importOFFFile(vm["displayMesh"].as<std::string>(), aMesh); viewer << aMesh; } if(vm.count("displayDigitalSurface")){ KSpace K; Point low = domain.lowerBound(); low[0]=low[0]-1; low[1]=low[1]-1; low[2]=low[2]-1; Point upp = domain.upperBound(); upp[0]=upp[0]+1; upp[1]=upp[1]+1; upp[2]=upp[2]+1; K.init(low, upp , true); SurfelAdjacency<3> SAdj( true ); vector<vector<SCell> > vectConnectedSCell; trace.info() << "Extracting surface set ... " ; Surfaces<KSpace>::extractAllConnectedSCell(vectConnectedSCell,K, SAdj, set3d, true); trace.info()<< " [done] " <<std::endl; GradientColorMap<long> gradient( 0, vectConnectedSCell.size()); gradient.addColor(DGtal::Color::Red); gradient.addColor(DGtal::Color::Yellow); gradient.addColor(DGtal::Color::Green); gradient.addColor(DGtal::Color::Cyan); gradient.addColor(DGtal::Color::Blue); gradient.addColor(DGtal::Color::Magenta); gradient.addColor(DGtal::Color::Red); viewer << DGtal::SetMode3D(vectConnectedSCell.at(0).at(0).className(), "Basic"); for(unsigned int i= 0; i <vectConnectedSCell.size(); i++){ for(unsigned int j= 0; j <vectConnectedSCell.at(i).size(); j++){ if(vm.count("colorizeCC")){ DGtal::Color c= gradient(i); viewer << CustomColors3D(Color(250, 0,0, transp), Color(c.red(), c.green(), c.blue(), transp)); }else if(vm.count("colorSDP")){ std::vector<int> vcol= vm["colorSDP"].as<std::vector<int > >(); Color c(vcol[0], vcol[1], vcol[2], vcol[3]); viewer << CustomColors3D(c, c); } viewer << vectConnectedSCell.at(i).at(j); } } } viewer << Viewer3D<>::updateDisplay; return application.exec(); }
int main(int argc, char* const argv[]) { /*-------------- Parse command line -----------------------------*/ po::options_description opt_desc("Allowed options are: "); opt_desc.add_options()("help,h", "display this message."); opt_desc.add_options()("input,i", po::value<string>()->required(), "Input thin image."); opt_desc.add_options()("reduceGraph,r", po::bool_switch()->default_value(false), "Reduce obj graph into a new SpatialGraph, converting " "chain nodes (degree=2) into edge_points."); opt_desc.add_options()( "removeExtraEdges,c", po::bool_switch()->default_value(false), "Remove extra edges created because connectivity of object."); opt_desc.add_options()( "mergeThreeConnectedNodes,m", po::bool_switch()->default_value(false), "Merge three connected nodes (between themselves) into one node."); opt_desc.add_options()( "mergeFourConnectedNodes,q", po::bool_switch()->default_value(false), "Merge 4 connected nodes (between themselves) into one node."); opt_desc.add_options()( "mergeTwoThreeConnectedNodes,l", po::bool_switch()->default_value(false), "Merge 2 connected nodes of degree 3 (and edge with no " "points) into one node."); opt_desc.add_options()("checkParallelEdges,e", po::bool_switch()->default_value(false), "Check and print info about parallel edges in the " "graph. Use verbose option for output."); opt_desc.add_options()("ignoreAngleBetweenParallelEdges,g", po::bool_switch()->default_value(false), "Don't compute angles between parallel edges."); opt_desc.add_options()( "ignoreEdgesShorterThan,s", po::value<size_t>()->default_value(0), "Ignore distance and angles between edges shorter than this value."); opt_desc.add_options()("ignoreEdgesToEndNodes,x", po::bool_switch()->default_value(false), "Ignore distance and angles between edges to/from end " "nodes (degree = 1)."); opt_desc.add_options()( "avoid_transformToPhysicalPoints,p", po::bool_switch()->default_value(false), "Positions in Spatial Graph takes into account metadata of the " "(origin,spacing,direction) itk image."); opt_desc.add_options()("spacing", po::value<string>()->default_value(""), "Provide external spacing between voxels. Ignores " "metadata of itk image and apply it."); opt_desc.add_options()( "output_filename_simple,z", po::bool_switch()->default_value(false), "Filename does not contain the parameters used for this filter."); opt_desc.add_options()("exportReducedGraph,o", po::value<string>(), "Write .dot file with the reduced spatial graph."); opt_desc.add_options()( "exportData,d", po::value<string>(), "Write degrees, ete_distances, contour_lengths, etc. Histograms can be " "generated from these files afterwards."); opt_desc.add_options()( "exportSerialized,u", po::value<string>(), "Write serialized graph with the reduced spatial graph."); #ifdef VISUALIZE opt_desc.add_options()("visualize,t", po::bool_switch()->default_value(false), "Visualize object with DGtal. Requires VISUALIZE " "option enabled at build."); #endif // ( "exportHistograms,e", po::value<string>(), "Export histogram." ) // ( "binsHistoDegrees,d", po::value<size_t>()->default_value(0), "Bins for // the histogram of degrees. Default [0] get the breaks between 0 and // max_degree" ) ( "widthHistoDistances,l", // po::value<double>()->default_value(0.3), "Width between breaks for // histogram of ete distances. Use 0.0 to automatically compute breaks (not // recommended)." ) ( "binsHistoAngles,a", // po::value<size_t>()->default_value(100), "Bins for the histogram of angles // . Use 0 for automatic computation of breaks (not recommended)" ) ( // "binsHistoCosines,n", po::value<size_t>()->default_value(100), "Bins for // the histogram of cosines .Use 0 for automatic computation of breaks (not // recommended)" ) opt_desc.add_options()("verbose,v", po::bool_switch()->default_value(false), "verbose output."); po::variables_map vm; try { po::store(po::parse_command_line(argc, argv, opt_desc), vm); if(vm.count("help") || argc <= 1) { std::cout << "Basic usage:\n" << opt_desc << "\n"; return EXIT_SUCCESS; } po::notify(vm); } catch(const std::exception& e) { std::cerr << e.what() << std::endl; return EXIT_FAILURE; } string filename = vm["input"].as<string>(); bool verbose = vm["verbose"].as<bool>(); if(verbose) std::cout << "Filename: " << filename << std::endl; bool output_filename_simple = vm["output_filename_simple"].as<bool>(); bool reduceGraph = vm["reduceGraph"].as<bool>(); bool avoid_transformToPhysicalPoints = vm["avoid_transformToPhysicalPoints"].as<bool>(); string spacing = vm["spacing"].as<string>(); bool removeExtraEdges = vm["removeExtraEdges"].as<bool>(); bool mergeThreeConnectedNodes = vm["mergeThreeConnectedNodes"].as<bool>(); bool mergeFourConnectedNodes = vm["mergeFourConnectedNodes"].as<bool>(); bool mergeTwoThreeConnectedNodes = vm["mergeTwoThreeConnectedNodes"].as<bool>(); bool checkParallelEdges = vm["checkParallelEdges"].as<bool>(); size_t ignoreEdgesShorterThan = vm["ignoreEdgesShorterThan"].as<size_t>(); bool ignoreAngleBetweenParallelEdges = vm["ignoreAngleBetweenParallelEdges"].as<bool>(); bool ignoreEdgesToEndNodes = vm["ignoreEdgesToEndNodes"].as<bool>(); bool exportReducedGraph = vm.count("exportReducedGraph"); bool exportSerialized = vm.count("exportSerialized"); bool exportData = vm.count("exportData"); // bool exportHistograms = vm.count("exportHistograms"); // size_t binsHistoDegrees = vm["binsHistoDegrees"].as<size_t>(); // double widthHistoDistances = vm["widthHistoDistances"].as<double>(); // size_t binsHistoAngles = vm["binsHistoAngles"].as<size_t>(); // size_t binsHistoCosines = vm["binsHistoCosines"].as<size_t>(); #ifdef VISUALIZE bool visualize = vm["visualize"].as<bool>(); #endif // Get filename without extension (and without folders). const fs::path input_stem = fs::path(filename).stem(); const fs::path output_file_path = fs::path(input_stem.string() + "_REDUCED"); using Domain = Z3i::Domain; using Image = ImageContainerByITKImage<Domain, unsigned char>; const unsigned int Dim = 3; using PixelType = unsigned char; using ItkImageType = itk::Image<PixelType, Dim>; // Read Image using ITK using ReaderType = itk::ImageFileReader<ItkImageType>; auto reader = ReaderType::New(); reader->SetFileName(filename); reader->Update(); // Convert to DGtal Container Image image(reader->GetOutput()); using DigitalTopology = DT26_6; using DigitalSet = DGtal::DigitalSetByAssociativeContainer< Domain, std::unordered_set<typename Domain::Point> >; using Object = DGtal::Object<DigitalTopology, DigitalSet>; DigitalSet image_set(image.domain()); SetFromImage<Z3i::DigitalSet>::append<Image>(image_set, image, 0, 255); KSpace ks; // Domain of kspace must be padded. ks.init(image.domain().lowerBound(), image.domain().upperBound(), true); DigitalTopology::ForegroundAdjacency adjF; DigitalTopology::BackgroundAdjacency adjB; DigitalTopology topo(adjF, adjB, DGtal::DigitalTopologyProperties::JORDAN_DT); Object obj(topo, image_set); #ifdef VISUALIZE if(visualize) { int argc(1); char** argv(nullptr); QApplication app(argc, argv); Viewer3D<> viewer(ks); viewer.show(); viewer.setFillColor(Color(255, 255, 255, 255)); viewer << image_set; // All kspace voxels // viewer.setFillColor(Color(40, 200, 55, 10)); // viewer << all_set; viewer << Viewer3D<>::updateDisplay; app.exec(); } #endif if(reduceGraph) { using Graph = Object; const Graph& graph = obj; using SpatialGraph = SG::GraphAL; SpatialGraph sg = SG::spatial_graph_from_object<Object, SpatialGraph>(graph); // Remove extra edges if(removeExtraEdges) { if(verbose) std::cout << "Removing extra edges" << std::endl; size_t iterations = 0; while(true) { bool any_edge_removed = SG::remove_extra_edges(sg); if(any_edge_removed) iterations++; else break; } if(verbose) std::cout << "Removed extra edges iteratively " << iterations << " times" << std::endl; } SpatialGraph reduced_g = SG::reduce_spatial_graph_via_dfs(sg); bool inPlace = true; if(mergeThreeConnectedNodes) { if(verbose) { std::cout << "Merging three connecting nodes... " << std::endl; } auto nodes_merged = SG::merge_three_connected_nodes(reduced_g, inPlace); if(verbose) { std::cout << nodes_merged << " interconnected nodes with degree 3 were merged." "Those nodes have now degree 0 if inPlace is not set" << std::endl; } } if(mergeFourConnectedNodes) { if(verbose) { std::cout << "Merging four connecting nodes... " << std::endl; } auto nodes_merged = SG::merge_four_connected_nodes(reduced_g, inPlace); if(verbose) { std::cout << nodes_merged << " interconnected nodes with degree 4 were merged." "Those nodes have now degree 0 if inPlace is not set" << std::endl; } } if(mergeTwoThreeConnectedNodes) { if(verbose) { std::cout << "Merging two degree 3 nodes... " << std::endl; } auto nodes_merged = SG::merge_two_three_connected_nodes(reduced_g, inPlace); if(verbose) { std::cout << nodes_merged << " two interconnected nodes with degree 3 " "and no edge points between them were merged. " "Those nodes have now degree 0 if inPlace is not set" << std::endl; } } if(checkParallelEdges) { if(verbose) std::cout << "Checking parallel edges... " << std::endl; auto parallel_edges = SG::get_parallel_edges(reduced_g); auto equal_parallel_edges = SG::get_equal_parallel_edges(parallel_edges, reduced_g); if(verbose) { std::cout << "Found " << parallel_edges.size() << " parallel edges. " << equal_parallel_edges.size() << " are equal!." << std::endl; if(!equal_parallel_edges.empty()) { std::cout << "Equal parallel edges between vertex:\n"; for(const auto& edge_pair : equal_parallel_edges) std::cout << boost::source(edge_pair.first, reduced_g) << "---" << boost::target(edge_pair.first, reduced_g) << std::endl; } } } ItkImageType::SpacingType itk_spacing; itk_spacing.Fill(1.0); if(!avoid_transformToPhysicalPoints) { if(verbose) { // Print metadata of itk image std::cout << "Origin: " << reader->GetOutput()->GetOrigin() << std::endl; std::cout << "Spacing: " << reader->GetOutput()->GetSpacing() << std::endl; std::cout << "Direction:\n " << reader->GetOutput()->GetDirection() << std::endl; } itk_spacing = reader->GetOutput()->GetSpacing(); SG::transform_graph_to_physical_space<ItkImageType>(reduced_g, reader->GetOutput()); if(spacing != "") { std::istringstream in(spacing); double sp; for(size_t i = 0; i < ItkImageType::ImageDimension; i++) { in >> sp; itk_spacing[i] = sp; } if(verbose) { std::cout << "Changing Spacing to: " << itk_spacing << std::endl; } reader->GetOutput()->SetSpacing(itk_spacing); SG::transform_graph_to_physical_space<ItkImageType>( reduced_g, reader->GetOutput()); } } // Format itk_spacing into a string: std::ostringstream sp_stream; sp_stream << itk_spacing[0] << "_" << itk_spacing[1] << "_" << itk_spacing[2]; auto sp_string = sp_stream.str(); std::cout << "spacing: " << sp_string << std::endl; // Check unique points of graph auto repeated_points = SG::check_unique_points_in_graph(reduced_g); if(repeated_points.second) { std::cout << "Warning: duplicated points exist in reduced_g" "Repeated Points: " << repeated_points.first.size() << std::endl; for(const auto& p : repeated_points.first) { SG::print_pos(std::cout, p); std::cout << std::endl; } } if(exportReducedGraph) { string exportReducedGraph_filename = vm["exportReducedGraph"].as<string>(); boost::dynamic_properties dp; dp.property("node_id", boost::get(boost::vertex_index, reduced_g)); dp.property("spatial_node", boost::get(boost::vertex_bundle, reduced_g)); dp.property("spatial_edge", boost::get(boost::edge_bundle, reduced_g)); { const fs::path output_folder_path{exportReducedGraph_filename}; if(!fs::exists(output_folder_path)) { throw std::runtime_error("output folder doesn't exist : " + output_folder_path.string()); } std::string output_full_string = output_file_path.string(); if(!output_filename_simple) { output_full_string += "_sp" + sp_string + (removeExtraEdges ? "_c" : "") + (mergeThreeConnectedNodes ? "_m" : ""); } fs::path output_full_path = output_folder_path / fs::path(output_full_string + ".dot"); std::ofstream out; out.open(output_full_path.string().c_str()); boost::write_graphviz_dp(out, reduced_g, dp); if(verbose) std::cout << "Output reduced graph (graphviz) to: " << output_full_path.string() << std::endl; } } if(exportSerialized) { string exportReducedGraph_filename = vm["exportReducedGraph"].as<string>(); const fs::path output_folder_path{exportReducedGraph_filename}; if(!fs::exists(output_folder_path)) { throw std::runtime_error("output folder doesn't exist : " + output_folder_path.string()); } std::string output_full_string = output_file_path.string(); if(!output_filename_simple) { output_full_string += "_sp" + sp_string + (removeExtraEdges ? "_c" : "") + (mergeThreeConnectedNodes ? "_m" : ""); } fs::path output_full_path = output_folder_path / fs::path(output_full_string + ".txt"); SG::write_serialized_graph(reduced_g, output_full_path.string()); if(verbose) std::cout << "Output reduced graph (serialized) to: " << output_full_path.string() << std::endl; } #ifdef VISUALIZE if(visualize) { SG::visualize_spatial_graph(reduced_g); // itk::Testing::ViewImage(reader->GetOutput()); SG::visualize_spatial_graph_with_image(reduced_g, reader->GetOutput()); } #endif if(exportData) { fs::path data_output_folder_path = fs::path(vm["exportData"].as<string>()); // string exportHistograms_filename = vm["exportHistograms"].as<string>(); // const fs::path histo_output_folder_path{exportHistograms_filename}; // if(!fs::exists(histo_output_folder_path)) { // throw std::runtime_error("histo_output folder doesn't exist : " + // histo_output_folder_path.string()); // } // fs::path histo_output_full_path = histo_output_folder_path / fs::path( // output_file_path.string() + // ( removeExtraEdges ? "_c" : "") + // ( mergeThreeConnectedNodes ? "_m" : "") + // ( ignoreAngleBetweenParallelEdges ? "_iPA" : "") + // ( ignoreEdgesToEndNodes ? "_x" : "") + // ( ignoreEdgesShorterThan ? // "_iShort" + std::to_string(ignoreEdgesShorterThan) : "") + // "_bD" + std::to_string(binsHistoDegrees) + // "_bA" + std::to_string(binsHistoAngles) + // "_bC" + std::to_string(binsHistoCosines) + // "_wL" + std::to_string(widthHistoDistances) + // ".histo"); // std::ofstream histo_out; // histo_out.open(histo_output_full_path.string().c_str()); if(!fs::exists(data_output_folder_path)) { throw std::runtime_error("data_output folder doesn't exist : " + data_output_folder_path.string()); } std::string data_output_full_string = output_file_path.string() + "_DATA"; if(!output_filename_simple) { data_output_full_string += ("_sp" + sp_string) + (removeExtraEdges ? "_c" : "") + (mergeThreeConnectedNodes ? "_m" : "") + (ignoreAngleBetweenParallelEdges ? "_iPA" : "") + (ignoreEdgesToEndNodes ? "_x" : "") + (ignoreEdgesShorterThan ? "_iShort" + std::to_string(ignoreEdgesShorterThan) : ""); } fs::path data_output_full_path = data_output_folder_path / fs::path(data_output_full_string + ".txt"); std::ofstream data_out; data_out.setf(std::ios_base::fixed, std::ios_base::floatfield); data_out.open(data_output_full_path.string().c_str()); // Degrees { auto degrees = SG::compute_degrees(reduced_g); // auto histo_degrees = SG::histogram_degrees(degrees, // binsHistoDegrees); SG::print_histogram(histo_degrees, histo_out); { data_out.precision( std::numeric_limits<decltype(degrees)::value_type>::max_digits10); data_out << "# degrees" << std::endl; std::ostream_iterator<decltype(degrees)::value_type> out_iter( data_out, " "); std::copy(std::begin(degrees), std::end(degrees), out_iter); data_out << std::endl; } } // EndToEnd Distances { auto ete_distances = SG::compute_ete_distances( reduced_g, ignoreEdgesShorterThan, ignoreEdgesToEndNodes); auto range_ptr = std::minmax_element(ete_distances.begin(), ete_distances.end()); if(verbose) { std::cout << "Min Distance: " << *range_ptr.first << std::endl; std::cout << "Max Distance: " << *range_ptr.second << std::endl; } // auto histo_ete_distances = SG::histogram_ete_distances(ete_distances, // widthHistoDistances); SG::print_histogram(histo_ete_distances, // histo_out); { data_out.precision(std::numeric_limits<decltype( ete_distances)::value_type>::max_digits10); data_out << "# ete_distances" << std::endl; std::ostream_iterator<decltype(ete_distances)::value_type> out_iter( data_out, " "); std::copy(std::begin(ete_distances), std::end(ete_distances), out_iter); data_out << std::endl; } } // Angles between adjacent edges { auto angles = SG::compute_angles(reduced_g, ignoreEdgesShorterThan, ignoreAngleBetweenParallelEdges, ignoreEdgesToEndNodes); // auto histo_angles = SG::histogram_angles( angles, binsHistoAngles ); // SG::print_histogram(histo_angles, histo_out); { data_out.precision( std::numeric_limits<decltype(angles)::value_type>::max_digits10); data_out << "# angles" << std::endl; std::ostream_iterator<decltype(angles)::value_type> out_iter(data_out, " "); std::copy(std::begin(angles), std::end(angles), out_iter); data_out << std::endl; } // Cosines of those angles { auto cosines = SG::compute_cosines(angles); // auto histo_cosines = SG::histogram_cosines( cosines, // binsHistoCosines ); SG::print_histogram(histo_cosines, histo_out); { data_out.precision(std::numeric_limits<decltype( cosines)::value_type>::max_digits10); data_out << "# cosines" << std::endl; std::ostream_iterator<decltype(cosines)::value_type> out_iter( data_out, " "); std::copy(std::begin(cosines), std::end(cosines), out_iter); data_out << std::endl; } } } // Contour length { auto contour_lengths = SG::compute_contour_lengths( reduced_g, ignoreEdgesShorterThan, ignoreEdgesToEndNodes); // auto histo_contour_lengths = // SG::histogram_contour_lengths(contour_lengths, widthHistoDistances); // SG::print_histogram(histo_contour_lengths, histo_out); { data_out.precision(std::numeric_limits<decltype( contour_lengths)::value_type>::max_digits10); data_out << "# contour_lengths" << std::endl; std::ostream_iterator<decltype(contour_lengths)::value_type> out_iter( data_out, " "); std::copy(std::begin(contour_lengths), std::end(contour_lengths), out_iter); data_out << std::endl; } } if(verbose) { std::cout << "Output data to: " << data_output_full_path.string() << std::endl; // std::cout << "Output histograms to: " << // histo_output_full_path.string() << std::endl; } } // end export histograms }
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(); } }
int main( int argc, char** argv ) { // for 3D display with Viewer3D QApplication application(argc,argv); KSpace K; Point plow(0,0,0); Point pup(3,3,2); Domain domain( plow, pup ); K.init( plow, pup, true ); // typedef Viewer3D<Space, KSpace> MyViewer; MyViewer viewer(K); viewer.show(); viewer << SetMode3D( domain.className(), "Paving" ); Cell ptlow = K.uPointel( plow ); // pointel (0*2,0*2, 0*2) Cell ptup1 = K.uPointel( pup ); // pointel (3*2,3*2, 2*2) Cell ptup2 = K.uTranslation( ptup1, Point::diagonal() ); // pointel (4*2, 4*2, 3*2) viewer << ptlow << ptup1 << ptup2; // drawing cells of dimension 0 Cell p1= K.uCell(Point(0,0,2)); // pointel (0*2,0*2,2*2) Cell p2= K.uCell(Point(0,2,2)); // ... Cell p3= K.uCell(Point(2,2,2)); Cell p4= K.uCell(Point(2,0,2)); Cell p5= K.uCell(Point(0,0,4)); Cell p6= K.uCell(Point(0,2,4)); Cell p7= K.uCell(Point(2,2,4)); Cell p8= K.uCell(Point(2,0,4)); viewer << p1 << p2 << p3 << p4 << p5 << p6 << p7 << p8; // drawing Cells of dimension 1 Cell linel0 = K.uCell( Point( 1, 0, 2 ) ); // linel (2*1+1, 0, 2*2) Cell linel1 = K.uCell( Point( 1, 2, 2 ) ); // ... Cell linel2 = K.uCell( Point( 0, 1, 2 ) ); Cell linel3 = K.uCell( Point( 2, 1, 2 ) ); Cell linel4 = K.uCell( Point( 1, 0, 4 ) ); Cell linel5 = K.uCell( Point( 1, 2, 4 ) ); Cell linel6 = K.uCell( Point( 0, 1, 4 ) ); Cell linel7 = K.uCell( Point( 2, 1, 4 ) ); Cell linel8 = K.uCell( Point( 0, 0, 3 ) ); Cell linel9 = K.uCell( Point( 0, 2, 3 ) ); Cell linel10 = K.uCell( Point( 2, 0, 3 ) ); Cell linel11 = K.uCell( Point( 2, 2, 3 ) ); Cell linel12 = K.uCell( Point( 3, 2, 2 ) ); viewer << linel0<< linel1<< linel2 << linel3 ; viewer << linel4<< linel5<< linel6 << linel7 ; viewer << linel8<< linel9<< linel10 << linel11 << linel12; // drawing cells of dimension 2 Cell surfelA = K.uCell( Point( 2, 1, 3 ) ); // surfel (2*2,2*1+1,2*3+1) Cell surfelB = K.uCell( Point( 1, 0, 1 ) ); // surfel (2*1,2*0,2*1+1) Cell surfelC = K.uCell( Point( 2, 1, 1 ) ); // surfel (2*2,2*1+1,2*1+1) viewer << surfelA << surfelB << surfelC; // drawing cells of dimension 3 Cell vox1 = K.uCell( Point( 3, 3, 3 ) ); // voxel (2*3+1,2*3+1,2*3+1) Cell vox2 = K.uCell( Point( 1, 1, 3 ) ); // voxel (2*1+1,2*1+1,2*3+1) viewer << vox1 << vox2; viewer<< MyViewer::updateDisplay; return application.exec(); }
/** * Example of a test. To be completed. * */ bool testLocalConvolutionNormalVectorEstimator ( int /*argc*/, char**/*argv*/ ) { unsigned int nbok = 0; unsigned int nb = 0; trace.beginBlock ( "Testing convolution neighborhood ..." ); std::string filename = testPath + "samples/cat10.vol"; typedef ImageSelector < Z3i::Domain, int>::Type Image; Image image = VolReader<Image>::importVol ( filename ); trace.info() <<image<<std::endl; DigitalSet set3d ( image.domain() ); SetFromImage<DigitalSet>::append<Image> ( set3d, image, 0,256 ); KSpace ks; bool space_ok = ks.init ( image.domain().lowerBound(), image.domain().upperBound(), true ); if ( !space_ok ) { trace.error() << "Error in the Khamisky space construction."<<std::endl; return 2; } trace.endBlock(); typedef SurfelAdjacency<KSpace::dimension> MySurfelAdjacency; MySurfelAdjacency surfAdj ( true ); // interior in all directions. trace.beginBlock ( "Set up digital surface." ); typedef LightImplicitDigitalSurface<KSpace, DigitalSet > MyDigitalSurfaceContainer; typedef DigitalSurface<MyDigitalSurfaceContainer> MyDigitalSurface; SCell bel = Surfaces<KSpace>::findABel ( ks, set3d, 100000 ); MyDigitalSurfaceContainer* ptrSurfContainer = new MyDigitalSurfaceContainer ( ks, set3d, surfAdj, bel ); MyDigitalSurface digSurf ( ptrSurfContainer ); // acquired MyDigitalSurface::ConstIterator it = digSurf.begin(); trace.endBlock(); trace.beginBlock ( "Compute and output surface <cat10-constant.off> with trivial normals." ); //Convolution kernel ConstantConvolutionWeights<MyDigitalSurface::Size> kernel; //Estimator definition typedef LocalConvolutionNormalVectorEstimator < MyDigitalSurface, ConstantConvolutionWeights<MyDigitalSurface::Size> > MyConstantEstimator; BOOST_CONCEPT_ASSERT ( ( CNormalVectorEstimator< MyConstantEstimator > ) ); MyConstantEstimator myNormalEstimator ( digSurf, kernel ); // Embedder definition typedef CanonicDigitalSurfaceEmbedder<MyDigitalSurface> SurfaceEmbedder; SurfaceEmbedder surfaceEmbedder ( digSurf ); typedef DigitalSurfaceEmbedderWithNormalVectorEstimator < SurfaceEmbedder, MyConstantEstimator > SurfaceEmbedderWithTrivialNormal; SurfaceEmbedderWithTrivialNormal mySurfelEmbedder ( surfaceEmbedder, myNormalEstimator ); // Compute normal vector field and displays it. myNormalEstimator.init ( 1.0, 2 ); MyConstantEstimator::Quantity res = myNormalEstimator.eval ( it ); trace.info() << "Normal vector at begin() : "<< res << std::endl; ofstream out ( "cat10-constant.off" ); if ( out.good() ) digSurf.exportAs3DNOFF ( out,mySurfelEmbedder ); out.close(); trace.endBlock(); trace.beginBlock ( "Compute and output surface <cat10-gaussian.off> with gaussian convoluted normals." ); //Convolution kernel GaussianConvolutionWeights < MyDigitalSurface::Size > Gkernel ( 4.0 ); //Estimator definition typedef LocalConvolutionNormalVectorEstimator < MyDigitalSurface, GaussianConvolutionWeights< MyDigitalSurface::Size> > MyGaussianEstimator; BOOST_CONCEPT_ASSERT ( ( CNormalVectorEstimator< MyGaussianEstimator > ) ); MyGaussianEstimator myNormalEstimatorG ( digSurf, Gkernel ); // Embedder definition typedef DigitalSurfaceEmbedderWithNormalVectorEstimator<SurfaceEmbedder,MyGaussianEstimator> SurfaceEmbedderWithGaussianNormal; SurfaceEmbedderWithGaussianNormal mySurfelEmbedderG ( surfaceEmbedder, myNormalEstimatorG ); // Compute normal vector field and displays it. myNormalEstimatorG.init ( 1.0, 5 ); MyGaussianEstimator::Quantity res2 = myNormalEstimatorG.eval ( it ); trace.info() << "Normal vector at begin() : "<< res2 << std::endl; std::vector<MyGaussianEstimator::Quantity> allNormals; myNormalEstimatorG.evalAll ( std::back_inserter ( allNormals ) ); trace.info() << "Normal vector field of size "<< allNormals.size() << std::endl; ofstream out2 ( "cat10-gaussian.off" ); if ( out2.good() ) digSurf.exportAs3DNOFF ( out2 ,mySurfelEmbedderG ); out2.close(); nbok += true ? 1 : 0; nb++; trace.info() << "(" << nbok << "/" << nb << ") " << "true == true" << std::endl; trace.endBlock(); return true; }
int main( int argc, char** argv ) { if ( argc < 4 ) { usage( argc, argv ); return 1; } std::string inputFilename = argv[ 1 ]; unsigned int minThreshold = atoi( argv[ 2 ] ); unsigned int maxThreshold = atoi( argv[ 3 ] ); unsigned int idxP = (argc <= 4) ? 0 : atoi( argv[ 4 ] ); //! [volDistanceTraversal-readVol] trace.beginBlock( "Reading vol file into an image." ); typedef ImageSelector < Domain, int>::Type Image; Image image = VolReader<Image>::importVol(inputFilename); DigitalSet set3d (image.domain()); SetFromImage<DigitalSet>::append<Image>(set3d, image, minThreshold, maxThreshold); trace.endBlock(); //! [volDistanceTraversal-readVol] //! [volDistanceTraversal-KSpace] trace.beginBlock( "Construct the Khalimsky space from the image domain." ); KSpace ks; bool space_ok = ks.init( image.domain().lowerBound(), image.domain().upperBound(), true ); if (!space_ok) { trace.error() << "Error in the Khamisky space construction."<<std::endl; return 2; } trace.endBlock(); //! [volDistanceTraversal-KSpace] //! [volDistanceTraversal-SurfelAdjacency] typedef SurfelAdjacency<KSpace::dimension> MySurfelAdjacency; MySurfelAdjacency surfAdj( true ); // interior in all directions. //! [volDistanceTraversal-SurfelAdjacency] //! [volDistanceTraversal-SetUpDigitalSurface] trace.beginBlock( "Set up digital surface." ); typedef LightImplicitDigitalSurface<KSpace, DigitalSet > MyDigitalSurfaceContainer; typedef DigitalSurface<MyDigitalSurfaceContainer> MyDigitalSurface; SCell bel = Surfaces<KSpace>::findABel( ks, set3d, 100000 ); MyDigitalSurfaceContainer* ptrSurfContainer = new MyDigitalSurfaceContainer( ks, set3d, surfAdj, bel ); MyDigitalSurface digSurf( ptrSurfContainer ); // acquired trace.endBlock(); // Find first bel. MyDigitalSurface::ConstIterator it = digSurf.begin(); for ( idxP = idxP % digSurf.size(); idxP != 0; --idxP ) ++it; bel = *it; //! [volDistanceTraversal-SetUpDigitalSurface] //! [volDistanceTraversal-ExtractingSurface] trace.beginBlock( "Extracting boundary by distance tracking from an initial bel." ); typedef CanonicSCellEmbedder<KSpace> SCellEmbedder; typedef SCellEmbedder::Value RealPoint; typedef RealPoint::Coordinate Scalar; typedef ExactPredicateLpSeparableMetric<Space,2> Distance; typedef std::binder1st< Distance > DistanceToPoint; typedef Composer<SCellEmbedder, DistanceToPoint, Scalar> VertexFunctor; typedef DistanceBreadthFirstVisitor< MyDigitalSurface, VertexFunctor, std::set<SCell> > MyDistanceVisitor; typedef MyDistanceVisitor::Node MyNode; typedef MyDistanceVisitor::Scalar MySize; SCellEmbedder embedder; Distance distance; DistanceToPoint distanceToPoint = std::bind1st( distance, embedder( bel ) ); VertexFunctor vfunctor( embedder, distanceToPoint ); MyDistanceVisitor visitor( digSurf, vfunctor, bel ); unsigned long nbSurfels = 0; MyNode node; while ( ! visitor.finished() ) { node = visitor.current(); ++nbSurfels; visitor.expand(); } MySize maxDist = node.second; trace.endBlock(); //! [volDistanceTraversal-ExtractingSurface] //! [volDistanceTraversal-DisplayingSurface] trace.beginBlock( "Displaying surface in Viewer3D." ); QApplication application(argc,argv); Viewer3D<> viewer; viewer.show(); HueShadeColorMap<MySize,1> hueShade( 0, maxDist ); MyDistanceVisitor visitor2( digSurf, vfunctor, bel ); viewer << CustomColors3D( Color::Black, Color::White ) << ks.unsigns( bel ); visitor2.expand(); std::vector< MyDistanceVisitor::Node > layer; while ( ! visitor2.finished() ) { MyNode n = visitor2.current(); Color c = hueShade( n.second ); viewer << CustomColors3D( Color::Red, c ) << ks.unsigns( n.first ); visitor2.expand(); } viewer << Viewer3D<>::updateDisplay; trace.info() << "nb surfels = " << nbSurfels << std::endl; trace.endBlock(); return application.exec(); //! [volDistanceTraversal-DisplayingSurface] }
int main( int argc, char** argv ) { //! [greedy-plane-segmentation-ex3-parseCommandLine] trace.info() << "Segments the surface at given threshold within given volume into digital planes of rational width num/den." << std::endl; // Setting default options: ---------------------------------------------- // input file used: string inputFilename = examplesPath + "samples/Al.100.vol" ; trace.info() << "input file used " << inputFilename << std::endl; // parameter threshold unsigned int threshold = 0; trace.info() << "the value that defines the isosurface in the image (an integer between 0 and 255)= " << threshold<< std::endl; // parameter widthNum unsigned int widthNum = 1; trace.info() << "the numerator of the rational width (a non-null integer) =" << widthNum<< std::endl; // parameter widthDen unsigned int widthDen = 1; trace.info() << "the denominator of the rational width (a non-null integer)= " << widthDen<< std::endl; //! [greedy-plane-segmentation-ex3-parseCommandLine] //! [greedy-plane-segmentation-ex3-loadVolume] QApplication application(argc,argv); typedef ImageSelector < Domain, int>::Type Image; Image image = VolReader<Image>::importVol(inputFilename); DigitalSet set3d (image.domain()); SetFromImage<DigitalSet>::append<Image>(set3d, image, threshold,255); //! [greedy-plane-segmentation-ex3-loadVolume] //! [greedy-plane-segmentation-ex3-makeSurface] trace.beginBlock( "Set up digital surface." ); // We initializes the cellular grid space used for defining the // digital surface. KSpace ks; bool ok = ks.init( set3d.domain().lowerBound(), set3d.domain().upperBound(), true ); if ( ! ok ) std::cerr << "[KSpace.init] Failed." << std::endl; SurfelAdjacency<KSpace::dimension> surfAdj( true ); // interior in all directions. MyDigitalSurfaceContainer* ptrSurfContainer = new MyDigitalSurfaceContainer( ks, set3d, surfAdj ); MyDigitalSurface digSurf( ptrSurfContainer ); // acquired trace.endBlock(); //! [greedy-plane-segmentation-ex3-makeSurface] //! [greedy-plane-segmentation-ex3-segment] Point p; Dimension axis; unsigned int j = 0; unsigned int nb = digSurf.size(); // First pass to find biggest planes. trace.beginBlock( "1) Segmentation first pass. Computes all planes so as to sort vertices by the plane size." ); std::map<Vertex,unsigned int> v2size; NaivePlaneComputer planeComputer; std::priority_queue<VertexSize> Q; std::vector<Point> layer; for ( ConstIterator it = digSurf.begin(), itE= digSurf.end(); it != itE; ++it ) { if ( ( (++j) % 50 == 0 ) || ( j == nb ) ) trace.progressBar( j, nb ); Vertex v = *it; axis = ks.sOrthDir( v ); planeComputer.init( axis, 500, widthNum, widthDen ); // The visitor takes care of all the breadth-first traversal. Visitor visitor( digSurf, v ); layer.clear(); Visitor::Size currentSize = visitor.current().second; while ( ! visitor.finished() ) { Visitor::Node node = visitor.current(); v = node.first; axis = ks.sOrthDir( v ); p = ks.sCoords( ks.sDirectIncident( v, axis ) ); if ( node.second != currentSize ) { // std::cerr << "Layer " << currentSize << ", size=" << layer.size() << std::endl; bool isExtended = planeComputer.extend( layer.begin(), layer.end() ); if ( ! isExtended ) break; layer.clear(); currentSize = node.second; } layer.push_back( p ); visitor.expand(); } // std::cerr << v << " -> " << planeComputer.size() << std::endl; Q.push( VertexSize( v, planeComputer.size() ) ); } trace.endBlock(); trace.beginBlock( "2) Segmentation second pass. Visits vertices from the one with biggest plane to the one with smallest plane." ); std::set<Vertex> processedVertices; std::map<Vertex,SegmentedPlane*> v2plane; std::vector<SegmentedPlane*> segmentedPlanes; j = 0; while ( ! Q.empty() ) { if ( ( (++j) % 50 == 0 ) || ( j == nb ) ) trace.progressBar( j, nb ); Vertex v = Q.top().v; Q.pop(); if ( processedVertices.find( v ) != processedVertices.end() ) // already in set continue; // process to next vertex SegmentedPlane* ptrSegment = new SegmentedPlane; segmentedPlanes.push_back( ptrSegment ); // to delete them afterwards. axis = ks.sOrthDir( v ); ptrSegment->plane.init( axis, 500, widthNum, widthDen ); // The visitor takes care of all the breadth-first traversal. Visitor visitor( digSurf, v ); while ( ! visitor.finished() ) { Visitor::Node node = visitor.current(); v = node.first; if ( processedVertices.find( v ) == processedVertices.end() ) { // Vertex is not in processedVertices axis = ks.sOrthDir( v ); p = ks.sCoords( ks.sDirectIncident( v, axis ) ); bool isExtended = ptrSegment->plane.extend( p ); if ( isExtended ) { // surfel is in plane. processedVertices.insert( v ); v2plane[ v ] = ptrSegment; visitor.expand(); } else // surfel is not in plane and should not be used in the visit. visitor.ignore(); } else // surfel is already in some plane. visitor.ignore(); } // Assign random color for each plane. ptrSegment->color = Color( rand() % 256, rand() % 256, rand() % 256, 255 ); } trace.endBlock(); //! [greedy-plane-segmentation-ex3-segment] //! [greedy-plane-segmentation-ex3-visualization] Viewer3D<> viewer( ks ); viewer.show(); Color col( 255, 255, 120 ); for ( std::map<Vertex,SegmentedPlane*>::const_iterator it = v2plane.begin(), itE = v2plane.end(); it != itE; ++it ) { viewer << CustomColors3D( it->second->color, it->second->color ); viewer << ks.unsigns( it->first ); } viewer << Viewer3D<>::updateDisplay; //! [greedy-plane-segmentation-ex3-visualization] //! [greedy-plane-segmentation-ex3-freeMemory] for ( std::vector<SegmentedPlane*>::iterator it = segmentedPlanes.begin(), itE = segmentedPlanes.end(); it != itE; ++it ) delete *it; segmentedPlanes.clear(); v2plane.clear(); //! [greedy-plane-segmentation-ex3-freeMemory] return application.exec(); }
int main( int argc, char** argv ) { if ( argc < 5 ) { usage( argc, argv ); return 1; } std::string inputFilename = argv[ 1 ]; unsigned int minThreshold = atoi( argv[ 2 ] ); unsigned int maxThreshold = atoi( argv[ 3 ] ); bool intAdjacency = atoi( argv[ 4 ] ) == 0; typedef ImageSelector < Domain, int>::Type Image; //! [viewMarchingCubes-readVol] trace.beginBlock( "Reading vol file into an image." ); Image image = VolReader<Image>::importVol(inputFilename); DigitalSet set3d (image.domain()); SetFromImage<DigitalSet>::append<Image>(set3d, image, minThreshold, maxThreshold); trace.endBlock(); //! [viewMarchingCubes-readVol] //! [viewMarchingCubes-KSpace] trace.beginBlock( "Construct the Khalimsky space from the image domain." ); KSpace ks; bool space_ok = ks.init( image.domain().lowerBound(), image.domain().upperBound(), true ); if (!space_ok) { trace.error() << "Error in the Khamisky space construction."<<std::endl; return 2; } trace.endBlock(); //! [viewMarchingCubes-KSpace] //! [viewMarchingCubes-SurfelAdjacency] typedef SurfelAdjacency<KSpace::dimension> MySurfelAdjacency; MySurfelAdjacency surfAdj( intAdjacency ); // interior in all directions. //! [viewMarchingCubes-SurfelAdjacency] //! [viewMarchingCubes-ExtractingSurface] trace.beginBlock( "Extracting boundary by scanning the space. " ); typedef KSpace::SurfelSet SurfelSet; typedef SetOfSurfels< KSpace, SurfelSet > MySetOfSurfels; typedef DigitalSurface< MySetOfSurfels > MyDigitalSurface; MySetOfSurfels theSetOfSurfels( ks, surfAdj ); Surfaces<KSpace>::sMakeBoundary( theSetOfSurfels.surfelSet(), ks, set3d, image.domain().lowerBound(), image.domain().upperBound() ); MyDigitalSurface digSurf( theSetOfSurfels ); trace.info() << "Digital surface has " << digSurf.size() << " surfels." << std::endl; trace.endBlock(); //! [viewMarchingCubes-ExtractingSurface] //! [viewMarchingCubes-makingMesh] trace.beginBlock( "Making triangulated surface. " ); typedef CanonicEmbedder< Space > TrivialEmbedder; typedef ImageLinearCellEmbedder< KSpace, Image, TrivialEmbedder > CellEmbedder; typedef CellEmbedder::Value RealPoint; typedef TriangulatedSurface< RealPoint > TriMesh; typedef Mesh< RealPoint > ViewMesh; typedef std::map< MyDigitalSurface::Vertex, TriMesh::Index > VertexMap; TriMesh trimesh; ViewMesh viewmesh; TrivialEmbedder trivialEmbedder; CellEmbedder cellEmbedder; // The +0.5 is to avoid isosurface going exactly through a voxel // center, especially for binary volumes. cellEmbedder.init( ks, image, trivialEmbedder, ( (double) minThreshold ) + 0.5 ); VertexMap vmap; // stores the map Vertex -> Index MeshHelpers::digitalSurface2DualTriangulatedSurface ( digSurf, cellEmbedder, trimesh, vmap ); trace.info() << "Triangulated surface is " << trimesh << std::endl; MeshHelpers::triangulatedSurface2Mesh( trimesh, viewmesh ); trace.info() << "Mesh has " << viewmesh.nbVertex() << " vertices and " << viewmesh.nbFaces() << " faces." << std::endl; trace.endBlock(); //! [viewMarchingCubes-makingMesh] QApplication application(argc,argv); Viewer3D<> viewer; viewer.show(); viewer.setLineColor(Color(150,0,0,254)); viewer << viewmesh; viewer << Viewer3D<>::updateDisplay; application.exec(); }
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; } }
int main( int argc, char** argv ) { QApplication application(argc,argv); typedef Z3i::Space Space; typedef Z3i::KSpace KSpace; typedef Z3i::Point Point; typedef Z3i::RealPoint RealPoint; typedef Z3i::RealVector RealVector; typedef HyperRectDomain<Space> Domain; typedef KSpace::Surfel Surfel; typedef KSpace::Cell Cell; typedef ImageSelector<Domain, unsigned char>::Type Image; typedef functors::IntervalForegroundPredicate<Image> ThresholdedImage; typedef ImplicitDigitalSurface< KSpace, ThresholdedImage > DigitalSurfaceContainer; //! [DVCM3D-typedefs] typedef ExactPredicateLpSeparableMetric<Space, 2> Metric; // L2-metric type typedef functors::HatPointFunction<Point,double> KernelFunction; // chi function type typedef VoronoiCovarianceMeasureOnDigitalSurface< DigitalSurfaceContainer, Metric, KernelFunction > VCMOnSurface; typedef VCMOnSurface::Surfel2Normals::const_iterator S2NConstIterator; //! [DVCM3D-typedefs] string inputFilename = examplesPath + "samples/Al.100.vol"; trace.info() << "File = " << inputFilename << std::endl; int thresholdMin = 0; trace.info() << "Min image thres. = " << thresholdMin << std::endl; int thresholdMax = 1; trace.info() << "Max image thres. = " << thresholdMax << std::endl; const double R = 20; trace.info() << "Big radius R = " << R << std::endl; const double r = 3; trace.info() << "Small radius r = " << r << std::endl; const double trivial_r = 3; trace.info() << "Trivial radius t = " << trivial_r << std::endl; // for orienting the directions given by the tensor. const double T = 0.1; trace.info() << "Feature thres. T = " << T << std::endl; // threshold for displaying features as red. const double size = 1.0; // size of displayed normals. KSpace ks; // Reads the volume trace.beginBlock( "Loading image into memory and build digital surface." ); Image image = GenericReader<Image>::import(inputFilename ); ThresholdedImage thresholdedImage( image, thresholdMin, thresholdMax ); trace.endBlock(); trace.beginBlock( "Extracting boundary by scanning the space. " ); ks.init( image.domain().lowerBound(), image.domain().upperBound(), true ); SurfelAdjacency<KSpace::dimension> surfAdj( true ); // interior in all directions. Surfel bel = Surfaces<KSpace>::findABel( ks, thresholdedImage, 10000 ); DigitalSurfaceContainer* container = new DigitalSurfaceContainer( ks, thresholdedImage, surfAdj, bel, false ); DigitalSurface< DigitalSurfaceContainer > surface( container ); //acquired trace.info() << "Digital surface has " << surface.size() << " surfels." << std::endl; trace.endBlock(); //! [DVCM3D-instantiation] Surfel2PointEmbedding embType = Pointels; // Could be Pointels|InnerSpel|OuterSpel; Metric l2; // Euclidean L2 metric KernelFunction chi( 1.0, r ); // hat function with support of radius r VCMOnSurface vcm_surface( surface, embType, R, r, chi, trivial_r, l2, true /* verbose */ ); //! [DVCM3D-instantiation] trace.beginBlock( "Displaying VCM" ); Viewer3D<> viewer( ks ); Cell dummy; viewer.setWindowTitle("3D VCM viewer"); viewer << SetMode3D( dummy.className(), "Basic" ); viewer.show(); GradientColorMap<double> grad( 0, T ); grad.addColor( Color( 128, 128, 255 ) ); grad.addColor( Color( 255, 255, 255 ) ); grad.addColor( Color( 255, 255, 0 ) ); grad.addColor( Color( 255, 0, 0 ) ); RealVector lambda; // eigenvalues of chi-vcm for ( S2NConstIterator it = vcm_surface.mapSurfel2Normals().begin(), itE = vcm_surface.mapSurfel2Normals().end(); it != itE; ++it ) { Surfel s = it->first; Point kp = ks.sKCoords( s ); RealPoint rp( 0.5 * (double) kp[ 0 ], 0.5 * (double) kp[ 1 ], 0.5 * (double) kp[ 2 ] ); RealVector n = it->second.vcmNormal; vcm_surface.getChiVCMEigenvalues( lambda, s ); double ratio = lambda[ 1 ] / ( lambda[ 0 ] + lambda[ 1 ] + lambda[ 2 ] ); viewer.setFillColor( grad( ratio > T ? T : ratio ) ); viewer << ks.unsigns( s ); n *= size; viewer.setLineColor( Color::Black ); viewer.addLine( rp + n, rp - n, 0.1 ); } viewer << Viewer3D<>::updateDisplay; application.exec(); trace.endBlock(); return 0; }
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; }
/** * Example of a test. To be completed. * */ bool testFitting() { unsigned int nbok = 0; unsigned int nb = 0; trace.beginBlock ( "Testing init ..." ); using namespace Z3i; trace.beginBlock("Creating Surface"); Point p1( -20, -20, -20 ); Point p2( 20, 20, 20 ); ImplicitBall<Z3i::Space> shape( RealPoint(6.0,0,0), 4); typedef GaussDigitizer<Z3i::Space, ImplicitBall<Z3i::Space> > Gauss; Gauss gauss; gauss.attach(shape); gauss.init(p1, p2, 1); typedef LightImplicitDigitalSurface<KSpace, Gauss > SurfaceContainer; typedef DigitalSurface<SurfaceContainer> Surface; typedef Surface::Surfel Surfel; KSpace K; nbok += K.init( p1, p2, true ) ? 1 : 0; nb++; trace.info() << "(" << nbok << "/" << nb << ") " << "K.init() is ok" << std::endl; Surfel bel = Surfaces<KSpace>::findABel( K, gauss, 10000 ); SurfaceContainer* surfaceContainer = new SurfaceContainer ( K, gauss, SurfelAdjacency<KSpace::dimension>( true ), bel ); Surface surface( surfaceContainer ); // acquired CanonicSCellEmbedder<KSpace> embedder(surface.container().space()); trace.endBlock(); trace.beginBlock("Normal vector field computation"); typedef functors::ElementaryConvolutionNormalVectorEstimator<Surfel, CanonicSCellEmbedder<KSpace> > FunctorNormal; typedef LocalEstimatorFromSurfelFunctorAdapter<SurfaceContainer, Z3i::L2Metric, FunctorNormal, DGtal::functors::GaussianKernel> ReporterNormal; typedef EstimatorCache<ReporterNormal> NormalCache; //estimator DGtal::functors::GaussianKernel gaussKernelFunc(5.0); FunctorNormal functorNormal(embedder, 1.0); ReporterNormal reporterNormal; reporterNormal.attach(surface); reporterNormal.setParams(l2Metric, functorNormal, gaussKernelFunc, 5.0); //caching normal field NormalCache normalCache(reporterNormal); normalCache.init( 1, surface.begin(), surface.end()); trace.info() << "Normal vector field cached... "<< normalCache << std::endl; trace.endBlock(); trace.beginBlock("Creating sphere fitting adapter from normal vector field"); typedef functors::SphereFittingEstimator<Surfel, CanonicSCellEmbedder<KSpace> , NormalCache> Functor; typedef functors::ConstValue< double > ConvFunctor; typedef LocalEstimatorFromSurfelFunctorAdapter<SurfaceContainer, Z3i::L2Metric, Functor, ConvFunctor> Reporter; Functor fitter(embedder,1.0, 5.0, normalCache); ConvFunctor convFunc(1.0); Reporter reporter; reporter.attach(surface); reporter.setParams(l2Metric, fitter , convFunc, 15.0); reporter.init(1, surface.begin(), surface.end()); for(Surface::ConstIterator it = surface.begin(), ite=surface.end(); it!=ite; ++it) { Functor::Quantity val = reporter.eval( it ); trace.info() << "Fitting = "<<val.center <<" rad="<<val.radius<<std::endl; } trace.endBlock(); trace.endBlock(); nbok += true ? 1 : 0; nb++; trace.info() << "(" << nbok << "/" << nb << ") " << "true == true" << std::endl; return nbok == nb; }