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; //! [volMarchingCubes-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(); //! [volMarchingCubes-readVol] //! [volMarchingCubes-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(); //! [volMarchingCubes-KSpace] //! [volMarchingCubes-SurfelAdjacency] typedef SurfelAdjacency<KSpace::dimension> MySurfelAdjacency; MySurfelAdjacency surfAdj( intAdjacency ); // interior in all directions. //! [volMarchingCubes-SurfelAdjacency] //! [volMarchingCubes-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(); //! [volMarchingCubes-ExtractingSurface] //! [volMarchingCubes-makingOFF] trace.beginBlock( "Making OFF surface <marching-cube.off>. " ); typedef CanonicEmbedder< Space > MyEmbedder; typedef ImageLinearCellEmbedder< KSpace, Image, MyEmbedder > CellEmbedder; CellEmbedder cellEmbedder; MyEmbedder trivialEmbedder; // 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 ); ofstream out( "marching-cube.off" ); if ( out.good() ) digSurf.exportEmbeddedSurfaceAs3DOFF( out, cellEmbedder ); out.close(); trace.endBlock(); //! [volMarchingCubes-makingOFF] return 0; }
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(); }
int main( int argc, char** argv ) { //! [3dVolMarchingCubes-parseCommandLine] // 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>(), "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)." ) ("adjacency,a", po::value<unsigned int>()->default_value(0), "0: interior adjacency, 1: exterior adjacency") ("output,o", po::value<std::string>()->default_value( "marching-cubes.off" ), "the output OFF file that represents the geometry of the isosurface") ; 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()<< std::endl; } po::notify(vm); if ( !parseOK || vm.count("help") || ( argc <= 1 ) ) { std::cout << "Usage: " << argv[0] << " [-i <fileName.vol>] [-t <threshold>] [-a <adjacency>] [-o <output.off>]" << std::endl << "Outputs the isosurface of value <threshold> of the volume <fileName.vol> as an OFF file <output.off>. The <adjacency> (0/1) allows to choose between interior (6,18) and exterior (18,6) adjacency." << std::endl << general_opt << std::endl; return 0; } if ( ! vm.count("input") ) { trace.error() << "The input file name was defined." << std::endl; return 1; } std::string inputFilename = vm["input"].as<std::string>(); unsigned int threshold = vm["threshold"].as<unsigned int>(); bool intAdjacency = ( vm["adjacency"].as<unsigned int>() == 0 ); std::string outputFilename = vm["output"].as<std::string>(); //! [3dVolMarchingCubes-parseCommandLine] //! [3dVolMarchingCubes-readVol] trace.beginBlock( "Reading vol file into an image." ); typedef ImageSelector < Domain, int>::Type Image; Image image = VolReader<Image>::importVol(inputFilename); typedef functors::SimpleThresholdForegroundPredicate<Image> ThresholdedImage; ThresholdedImage thresholdedImage( image, threshold ); // DigitalSet set3d (image.domain()); // SetFromImage<DigitalSet>::append<Image>(set3d, image, // threshold, 255 ); trace.endBlock(); //! [3dVolMarchingCubes-readVol] //! [3dVolMarchingCubes-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(); //! [3dVolMarchingCubes-KSpace] //! [3dVolMarchingCubes-SurfelAdjacency] typedef SurfelAdjacency<KSpace::dimension> MySurfelAdjacency; MySurfelAdjacency surfAdj( intAdjacency ); // interior in all directions. //! [3dVolMarchingCubes-SurfelAdjacency] //! [3dVolMarchingCubes-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, thresholdedImage, image.domain().lowerBound(), image.domain().upperBound() ); MyDigitalSurface digSurf( theSetOfSurfels ); trace.info() << "Digital surface has " << digSurf.size() << " surfels." << std::endl; trace.endBlock(); //! [3dVolMarchingCubes-ExtractingSurface] //! [3dVolMarchingCubes-makingOFF] trace.beginBlock( "Making OFF surface. " ); // Describes how voxels are embedded into Euclidean space. typedef CanonicEmbedder< Space > MyEmbedder; // Describes how the centroid surface elements is placed in-between embedded voxels. typedef ImageLinearCellEmbedder< KSpace, Image, MyEmbedder > CellEmbedder; CellEmbedder cellEmbedder; MyEmbedder trivialEmbedder; cellEmbedder.init( ks, image, trivialEmbedder, threshold ); std::ofstream out( outputFilename.c_str() ); if ( out.good() ) digSurf.exportEmbeddedSurfaceAs3DOFF( out, cellEmbedder ); out.close(); trace.endBlock(); //! [3dVolMarchingCubes-makingOFF] return 0; }