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 ) { //! [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 ) { typedef SpaceND<3,int> Space; typedef KhalimskySpaceND<3,int> KSpace; typedef HyperRectDomain<Space> Domain; typedef ImageSelector<Domain, unsigned char>::Type Image; typedef SurfelAdjacency<KSpace::dimension> MySurfelAdjacency; // 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, pgm (with 3 dims)) file or sdp (sequence of discrete points)" ) ("output,o", po::value<std::string>(), "output obj file (.obj)" ) ("thresholdMin,m", po::value<int>()->default_value(0), "threshold min (excluded) to define binary shape" ) ("thresholdMax,M", po::value<int>()->default_value(255), "threshold max (included) to define binary shape" ) #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 ("mode", po::value<std::string>()->default_value("BDRY"), "set mode for display: INNER: inner voxels, OUTER: outer voxels, BDRY: surfels (default), CLOSURE: surfels with linels and pointels.") ("normalization,n", "Normalization so that the geometry fits in [-1/2,1/2]^3") ; 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 [input] -o [output]\n" << "Export the boundary of a volume file to OBJ format. The mode specifies if you wish to see surface elements (BDRY), the inner voxels (INNER) or the outer voxels (OUTER) that touch the boundary."<< endl << general_opt << "\n"; return 0; } if(! vm.count("input")) { trace.error() << " The file name was defined" << endl; return 0; } if(! vm.count("output")) { trace.error() << " The output filename was defined" << endl; return 0; } string inputFilename = vm["input"].as<std::string>(); int thresholdMin = vm["thresholdMin"].as<int>(); int thresholdMax = vm["thresholdMax"].as<int>(); string mode = vm["mode"].as<string>(); bool normalization = false; if (vm.count("normalization")) normalization = true; 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; } if(extension=="vol" || extension=="pgm3d" || extension=="pgm3D" #ifdef WITH_ITK || extension =="dcm" #endif ){ trace.beginBlock( "Loading image into memory." ); #ifdef WITH_ITK int dicomMin = vm["dicomMin"].as<int>(); int dicomMax = vm["dicomMax"].as<int>(); typedef DGtal::functors::Rescaling<int ,unsigned char > RescalFCT; Image image = extension == "dcm" ? DicomReader< Image, RescalFCT >::importDicom( inputFilename, RescalFCT(dicomMin, dicomMax, 0, 255) ) : GenericReader<Image>::import( inputFilename ); #else Image image = GenericReader<Image>::import (inputFilename ); #endif trace.info() << "Image loaded: "<<image<< std::endl; trace.endBlock(); trace.beginBlock( "Construct the Khalimsky space from the image domain." ); Domain domain = image.domain(); KSpace ks; bool space_ok = ks.init( domain.lowerBound(), domain.upperBound(), true ); if (!space_ok) { trace.error() << "Error in the Khamisky space construction."<<std::endl; return 2; } trace.endBlock(); trace.beginBlock( "Wrapping a digital set around image. " ); typedef functors::IntervalForegroundPredicate<Image> ThresholdedImage; ThresholdedImage thresholdedImage( image, thresholdMin, thresholdMax ); trace.endBlock(); trace.beginBlock( "Extracting boundary by scanning the space. " ); typedef KSpace::SurfelSet SurfelSet; typedef SetOfSurfels< KSpace, SurfelSet > MySetOfSurfels; typedef DigitalSurface< MySetOfSurfels > MyDigitalSurface; MySurfelAdjacency surfAdj( true ); // interior in all directions. MySetOfSurfels theSetOfSurfels( ks, surfAdj ); Surfaces<KSpace>::sMakeBoundary( theSetOfSurfels.surfelSet(), ks, thresholdedImage, domain.lowerBound(), domain.upperBound() ); MyDigitalSurface digSurf( theSetOfSurfels ); trace.info() << "Digital surface has " << digSurf.size() << " surfels." << std::endl; trace.endBlock(); trace.beginBlock( "Exporting everything." ); Board3D<Space,KSpace> board(ks); board << SetMode3D( ks.unsigns( *digSurf.begin() ).className(), "Basic" ); typedef MyDigitalSurface::ConstIterator ConstIterator; if ( mode == "BDRY" ) for ( ConstIterator it = digSurf.begin(), itE = digSurf.end(); it != itE; ++it ) board << ks.unsigns( *it ); else if ( mode == "INNER" ) for ( ConstIterator it = digSurf.begin(), itE = digSurf.end(); it != itE; ++it ) board << ks.sCoords( ks.sDirectIncident( *it, ks.sOrthDir( *it ) ) ); else if ( mode == "OUTER" ) for ( ConstIterator it = digSurf.begin(), itE = digSurf.end(); it != itE; ++it ) board << ks.sCoords( ks.sIndirectIncident( *it, ks.sOrthDir( *it ) ) ); else if (mode == "CLOSURE") { std::set<KSpace::Cell> container; for ( ConstIterator it = digSurf.begin(), itE = digSurf.end(); it != itE; ++it ) { container.insert( ks.unsigns( *it ) ); KSpace::SCells oneNeig = ks.sLowerIncident(*it); //Processing linels for(KSpace::SCells::ConstIterator itt = oneNeig.begin(), ittend = oneNeig.end(); itt != ittend; ++itt) { container.insert( ks.unsigns( *itt) ); KSpace::SCells oneNeig2 = ks.sLowerIncident(*itt); //Processing pointels for(KSpace::SCells::ConstIterator ittt = oneNeig2.begin(), itttend = oneNeig2.end(); ittt != itttend; ++ittt) container.insert( ks.unsigns(*ittt) ); } } trace.info()<< "Exporting "<< container.size() << " cells"<<std::endl; for(auto cell: container) board << cell; } string outputFilename = vm["output"].as<std::string>(); board.saveOBJ(outputFilename, normalization); trace.endBlock(); } return 0; }
int main( int argc, char** argv ) { // parse command line ---------------------------------------------- po::options_description general_opt("Allowed options are: "); general_opt.add_options() ("help,h", "display this message") ("scale,s", po::value<double>()->default_value(1.0), "set the scale of the maximal level. (default 1.0)") ("colorMap,c", "define the heightmap color with a pre-defined colormap (GradientColorMap)") ("colorTextureImage,t",po::value<std::string>(), "define the heightmap color from a given color image (32 bits image).") ("input-file,i", po::value<std::string>(), "2d input image representing the height map (given as grayscape image cast into 8 bits)." ); 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-file]\n" << "Displays 2D image as heightmap by using QGLviewer. "<< endl << general_opt << "\n" << "Exemple of use: visualisation/3dHeightMapViewer -i ${DGtal}/examples/samples/church.pgm -s 0.2" << std::endl; return 0; } if(! vm.count("input-file")) { trace.error() << " The file name was defined" << endl; return 0; } string inputFilename = vm["input-file"].as<std::string>(); double scale = vm["scale"].as<double>(); typedef DGtal::ImageContainerBySTLVector<Z2i::Domain, unsigned char> Image2DG ; typedef DGtal::ImageContainerBySTLVector<Z2i::Domain, unsigned int> Image2DCol ; Image2DG image = GenericReader<Image2DG>::import( inputFilename ); Image2DCol imageTexture(image.domain()); int maxHeight = (int)(std::numeric_limits<Image2DG::Value>::max()*scale); trace.info()<< "Max height from scale:" << maxHeight << std::endl; if(vm.count("colorTextureImage")){ imageTexture = GenericReader<Image2DCol>::import( vm["colorTextureImage"].as<std::string>() ); } QApplication application(argc,argv); Z2i::RealPoint plow (image.domain().lowerBound()[0]-0.5, image.domain().lowerBound()[1]-0.5); Z2i::RealPoint pup (image.domain().upperBound()[0]+0.5, image.domain().upperBound()[1]+0.5); Viewer3DImageSpec<> viewer(plow, pup) ; viewer.setWindowTitle("Height Map Viewer"); viewer.show(); KSpace K; K.init(Z3i::Point(0,0,0),Z3i::Point(image.domain().upperBound()[0], image.domain().upperBound()[1], maxHeight+1), true); std::set<KSpace::SCell> boundVect; Image3DPredicatFrom2DImage<Image2DG, Z3i::Point> image3Dpredicate(image, scale); trace.info() << "Constructing boundary... "; Surfaces<KSpace>::sMakeBoundary (boundVect, K, image3Dpredicate, Z3i::Point(0,0,0), Z3i::Point(image.domain().upperBound()[0], image.domain().upperBound()[1], maxHeight+1) ); trace.info() << "[done]"<< std::endl; viewer << SetMode3D((*(boundVect.begin())).className(), "Basic" ); GradientColorMap<Image2DG::Value,CMAP_JET> gradientShade( 0, std::numeric_limits<Image2DG::Value>::max()); GrayscaleColorMap<Image2DG::Value> grayShade(0, std::numeric_limits<Image2DG::Value>::max()); for(std::set<KSpace::SCell>::const_iterator it = boundVect.begin(); it!= boundVect.end(); it++){ Z3i::Point pt = K.sCoords(K.sDirectIncident( *it, 2 )); functors::Projector<SpaceND<2,int> > proj; Image2DG::Value val = image(proj(pt)); if(vm.count("colorMap")){ viewer.setFillColor(gradientShade(val)); }else if (vm.count("colorTextureImage")) { viewer.setFillColor(Color(imageTexture(proj(pt)))); }else{ viewer.setFillColor(grayShade(val)); } viewer << *it; } viewer << Viewer3D<>::updateDisplay; return application.exec(); }
int main( int argc, char** argv ) { typedef SpaceND<3,int> Space; typedef KhalimskySpaceND<3,int> KSpace; typedef HyperRectDomain<Space> Domain; typedef ImageSelector<Domain, unsigned char>::Type Image; typedef DigitalSetSelector< Domain, BIG_DS+HIGH_BEL_DS >::Type DigitalSet; typedef SurfelAdjacency<KSpace::dimension> MySurfelAdjacency; // 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, pgm (with 3 dims)) file or sdp (sequence of discrete points)" ) ("thresholdMin,m", po::value<int>()->default_value(0), "threshold min (excluded) to define binary shape" ) ("thresholdMax,M", po::value<int>()->default_value(255), "threshold max (included) to define binary shape" ) #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 ("mode", po::value<std::string>()->default_value("INNER"), "set mode for display: INNER: inner voxels, OUTER: outer voxels, BDRY: surfels") ; 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 [input]\n" << "Display the boundary of a volume file by using QGLviewer. The mode specifies if you wish to see surface elements (BDRY), the inner voxels (INNER) or the outer voxels (OUTER) that touch the boundary."<< endl << 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>(); string mode = vm["mode"].as<string>(); QApplication application(argc,argv); 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; } if(extension=="vol" || extension=="pgm3d" || extension=="pgm3D" #ifdef WITH_ITK || extension =="dcm" #endif ){ trace.beginBlock( "Loading image into memory." ); #ifdef WITH_ITK int dicomMin = vm["dicomMin"].as<int>(); int dicomMax = vm["dicomMax"].as<int>(); typedef DGtal::functors::Rescaling<int ,unsigned char > RescalFCT; Image image = extension == "dcm" ? DicomReader< Image, RescalFCT >::importDicom( inputFilename, RescalFCT(dicomMin, dicomMax, 0, 255) ) : GenericReader<Image>::import( inputFilename ); #else Image image = GenericReader<Image>::import (inputFilename ); #endif trace.info() << "Image loaded: "<<image<< std::endl; trace.endBlock(); //! [3dVolBoundaryViewer-KSpace] trace.beginBlock( "Construct the Khalimsky space from the image domain." ); Domain domain = image.domain(); KSpace ks; bool space_ok = ks.init( domain.lowerBound(), domain.upperBound(), true ); if (!space_ok) { trace.error() << "Error in the Khamisky space construction."<<std::endl; return 2; } trace.endBlock(); //! [3dVolBoundaryViewer-KSpace] //! [3dVolBoundaryViewer-Set3D] trace.beginBlock( "Wrapping a digital set around image. " ); typedef functors::IntervalForegroundPredicate<Image> ThresholdedImage; ThresholdedImage thresholdedImage( image, thresholdMin, thresholdMax ); trace.endBlock(); //! [3dVolBoundaryViewer-Set3D] //! [3dVolBoundaryViewer-ExtractingSurface] trace.beginBlock( "Extracting boundary by scanning the space. " ); typedef KSpace::SurfelSet SurfelSet; typedef SetOfSurfels< KSpace, SurfelSet > MySetOfSurfels; typedef DigitalSurface< MySetOfSurfels > MyDigitalSurface; MySurfelAdjacency surfAdj( true ); // interior in all directions. MySetOfSurfels theSetOfSurfels( ks, surfAdj ); Surfaces<KSpace>::sMakeBoundary( theSetOfSurfels.surfelSet(), ks, thresholdedImage, domain.lowerBound(), domain.upperBound() ); MyDigitalSurface digSurf( theSetOfSurfels ); trace.info() << "Digital surface has " << digSurf.size() << " surfels." << std::endl; trace.endBlock(); //! [3dVolBoundaryViewer-ExtractingSurface] //! [3dVolBoundaryViewer-ViewingSurface] trace.beginBlock( "Displaying everything. " ); Viewer3D<Space,KSpace> viewer(ks); viewer.setWindowTitle("Simple boundary of volume Viewer"); viewer.show(); typedef MyDigitalSurface::ConstIterator ConstIterator; if ( mode == "BDRY" ){ viewer << SetMode3D(ks.unsigns( *(digSurf.begin()) ).className(), "Basic"); for ( ConstIterator it = digSurf.begin(), itE = digSurf.end(); it != itE; ++it ) viewer << ks.unsigns( *it ); }else if ( mode == "INNER" ) for ( ConstIterator it = digSurf.begin(), itE = digSurf.end(); it != itE; ++it ) viewer << ks.sCoords( ks.sDirectIncident( *it, ks.sOrthDir( *it ) ) ); else if ( mode == "OUTER" ) for ( ConstIterator it = digSurf.begin(), itE = digSurf.end(); it != itE; ++it ) viewer << ks.sCoords( ks.sIndirectIncident( *it, ks.sOrthDir( *it ) ) ); else{ trace.error() << "Warning display mode (" << mode << ") not implemented." << std::endl; trace.error() << "The display will be empty." << std::endl; } viewer << Viewer3D<>::updateDisplay; trace.endBlock(); return application.exec(); } return 0; }
int main( int argc, char** argv ) { QApplication application(argc,argv); string inputFilename = argc > 1 ? argv[ 1 ] : examplesPath+"/samples/Al.100.vol"; int threshold = argc > 2 ? atoi( argv[ 2 ] ) : 0; int widthNum = argc > 3 ? atoi( argv[ 3 ] ) : 2; int widthDen = argc > 4 ? atoi( argv[ 4 ] ) : 1; //! [polyhedralizer-readVol] trace.beginBlock( "Reading vol file into an image." ); typedef ImageContainerBySTLVector< Domain, int> Image; Image image = VolReader<Image>::importVol(inputFilename); typedef functors::SimpleThresholdForegroundPredicate<Image> DigitalObject; DigitalObject digitalObject( image, threshold ); trace.endBlock(); //! [polyhedralizer-readVol] //! [polyhedralizer-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."<<endl; return 2; } trace.endBlock(); //! [polyhedralizer-KSpace] //! [polyhedralizer-SurfelAdjacency] typedef SurfelAdjacency<KSpace::dimension> MySurfelAdjacency; MySurfelAdjacency surfAdj( false ); // exterior in all directions. //! [polyhedralizer-SurfelAdjacency] //! [polyhedralizer-ExtractingSurface] trace.beginBlock( "Extracting boundary by tracking the surface. " ); typedef KSpace::Surfel Surfel; Surfel start_surfel = Surfaces<KSpace>::findABel( ks, digitalObject, 100000 ); typedef ImplicitDigitalSurface< KSpace, DigitalObject > MyContainer; typedef DigitalSurface< MyContainer > MyDigitalSurface; typedef MyDigitalSurface::ConstIterator ConstIterator; MyContainer container( ks, digitalObject, surfAdj, start_surfel ); MyDigitalSurface digSurf( container ); trace.info() << "Digital surface has " << digSurf.size() << " surfels." << endl; trace.endBlock(); //! [polyhedralizer-ExtractingSurface] //! [polyhedralizer-ComputingPlaneSize] // First pass to find biggest planes. trace.beginBlock( "Decomposition first pass. Computes all planes so as to sort vertices by the plane size." ); typedef BreadthFirstVisitor<MyDigitalSurface> Visitor; typedef ChordGenericNaivePlaneComputer<Z3,Z3::Point, DGtal::int64_t> NaivePlaneComputer; map<Surfel,unsigned int> v2size; for ( ConstIterator it = digSurf.begin(), itE= digSurf.end(); it != itE; ++it ) v2size[ *it ] = 0; int j = 0; int nb = digSurf.size(); NaivePlaneComputer planeComputer; vector<Point> layer; vector<Surfel> layer_surfel; for ( ConstIterator it = digSurf.begin(), itE= digSurf.end(); it != itE; ++it ) { if ( ( (++j) % 50 == 0 ) || ( j == nb ) ) trace.progressBar( j, nb ); Surfel v = *it; planeComputer.init( widthNum, widthDen ); // The visitor takes care of all the breadth-first traversal. Visitor visitor( digSurf, v ); layer.clear(); layer_surfel.clear(); Visitor::Size currentSize = visitor.current().second; while ( ! visitor.finished() ) { Visitor::Node node = visitor.current(); v = node.first; int axis = ks.sOrthDir( v ); Point p = ks.sCoords( ks.sDirectIncident( v, axis ) ); if ( node.second != currentSize ) { bool isExtended = planeComputer.extend( layer.begin(), layer.end() ); if ( isExtended ) { for ( vector<Surfel>::const_iterator it_layer = layer_surfel.begin(), it_layer_end = layer_surfel.end(); it_layer != it_layer_end; ++it_layer ) { ++v2size[ *it_layer ]; } layer_surfel.clear(); layer.clear(); currentSize = node.second; } else break; } layer_surfel.push_back( v ); layer.push_back( p ); visitor.expand(); } } // Prepare queue typedef PairSorted2nd<Surfel,int> SurfelWeight; priority_queue<SurfelWeight> Q; for ( ConstIterator it = digSurf.begin(), itE= digSurf.end(); it != itE; ++it ) Q.push( SurfelWeight( *it, v2size[ *it ] ) ); trace.endBlock(); //! [polyhedralizer-ComputingPlaneSize] //! [polyhedralizer-segment] // Segmentation into planes trace.beginBlock( "Decomposition second pass. Visits vertices from the one with biggest plane to the one with smallest plane." ); typedef Triple<NaivePlaneComputer, Color, pair<RealVector,double> > RoundPlane; set<Surfel> processedVertices; vector<RoundPlane*> roundPlanes; map<Surfel,RoundPlane*> v2plane; j = 0; while ( ! Q.empty() ) { if ( ( (++j) % 50 == 0 ) || ( j == nb ) ) trace.progressBar( j, nb ); Surfel v = Q.top().first; Q.pop(); if ( processedVertices.find( v ) != processedVertices.end() ) // already in set continue; // process to next vertex RoundPlane* ptrRoundPlane = new RoundPlane; roundPlanes.push_back( ptrRoundPlane ); // to delete them afterwards. v2plane[ v ] = ptrRoundPlane; ptrRoundPlane->first.init( widthNum, widthDen ); ptrRoundPlane->third = make_pair( RealVector::zero, 0.0 ); // The visitor takes care of all the breadth-first traversal. Visitor visitor( digSurf, v ); layer.clear(); layer_surfel.clear(); Visitor::Size currentSize = visitor.current().second; while ( ! visitor.finished() ) { Visitor::Node node = visitor.current(); v = node.first; Dimension axis = ks.sOrthDir( v ); Point p = ks.sCoords( ks.sDirectIncident( v, axis ) ); if ( node.second != currentSize ) { bool isExtended = ptrRoundPlane->first.extend( layer.begin(), layer.end() ); if ( isExtended ) { for ( vector<Surfel>::const_iterator it_layer = layer_surfel.begin(), it_layer_end = layer_surfel.end(); it_layer != it_layer_end; ++it_layer ) { Surfel s = *it_layer; processedVertices.insert( s ); if ( v2plane.find( s ) == v2plane.end() ) v2plane[ s ] = ptrRoundPlane; } layer.clear(); layer_surfel.clear(); currentSize = node.second; } else break; } layer_surfel.push_back( v ); layer.push_back( p ); if ( processedVertices.find( v ) != processedVertices.end() ) // surfel is already in some plane. visitor.ignore(); else visitor.expand(); } if ( visitor.finished() ) { for ( vector<Surfel>::const_iterator it_layer = layer_surfel.begin(), it_layer_end = layer_surfel.end(); it_layer != it_layer_end; ++it_layer ) { Surfel s = *it_layer; processedVertices.insert( s ); if ( v2plane.find( s ) == v2plane.end() ) v2plane[ s ] = ptrRoundPlane; } } // Assign random color for each plane. ptrRoundPlane->second = Color( rand() % 192 + 64, rand() % 192 + 64, rand() % 192 + 64, 255 ); } trace.endBlock(); //! [polyhedralizer-segment] //! [polyhedralizer-lsf] for ( vector<RoundPlane*>::iterator it = roundPlanes.begin(), itE = roundPlanes.end(); it != itE; ++it ) { NaivePlaneComputer& computer = (*it)->first; RealVector normal; double mu = LSF( normal, computer.begin(), computer.end() ); (*it)->third = make_pair( normal, mu ); } //! [polyhedralizer-lsf] //! [polyhedralizer-projection] map<Surfel, RealPoint> coordinates; for ( map<Surfel,RoundPlane*>::const_iterator it = v2plane.begin(), itE = v2plane.end(); it != itE; ++it ) { Surfel v = it->first; RoundPlane* rplane = it->second; Point p = ks.sKCoords( v ); RealPoint rp( (double)p[ 0 ]/2.0, (double)p[ 1 ]/2.0, (double)p[ 2 ]/2.0 ); double mu = rplane->third.second; RealVector normal = rplane->third.first; double lambda = mu - rp.dot( normal ); coordinates[ v ] = rp + lambda*normal; } typedef vector<Surfel> SurfelRange; map<Surfel, RealPoint> new_coordinates; for ( ConstIterator it = digSurf.begin(), itE= digSurf.end(); it != itE; ++it ) { Surfel s = *it; SurfelRange neighbors; back_insert_iterator<SurfelRange> writeIt = back_inserter( neighbors ); digSurf.writeNeighbors( writeIt, *it ); RealPoint x = RealPoint::zero; for ( SurfelRange::const_iterator its = neighbors.begin(), itsE = neighbors.end(); its != itsE; ++its ) x += coordinates[ *its ]; new_coordinates[ s ] = x / neighbors.size(); } //! [polyhedralizer-projection] //! [polyhedralizer-MakeMesh] typedef unsigned int Number; typedef Mesh<RealPoint> MyMesh; typedef MyMesh::MeshFace MeshFace; typedef MyDigitalSurface::FaceSet FaceSet; typedef MyDigitalSurface::VertexRange VertexRange; map<Surfel, Number> index; // Numbers all vertices. Number nbv = 0; MyMesh polyhedron( true ); // Insert all projected surfels as vertices of the polyhedral surface. for ( ConstIterator it = digSurf.begin(), itE= digSurf.end(); it != itE; ++it ) { polyhedron.addVertex( new_coordinates[ *it ] ); index[ *it ] = nbv++; } // Define faces of the mesh. Outputs closed faces. FaceSet faces = digSurf.allClosedFaces(); for ( typename FaceSet::const_iterator itf = faces.begin(), itf_end = faces.end(); itf != itf_end; ++itf ) { MeshFace mface( itf->nbVertices ); VertexRange vtcs = digSurf.verticesAroundFace( *itf ); int i = 0; for ( typename VertexRange::const_iterator itv = vtcs.begin(), itv_end = vtcs.end(); itv != itv_end; ++itv ) { mface[ i++ ] = index[ *itv ]; } polyhedron.addFace( mface, Color( 255, 243, 150, 255 ) ); } //! [polyhedralizer-MakeMesh] //! [polyhedralizer-visualization] typedef Viewer3D<Space,KSpace> MyViewer3D; MyViewer3D viewer( ks ); viewer.show(); bool isOK = polyhedron >> "test.off"; bool isOK2 = polyhedron >> "test.obj"; viewer << polyhedron; viewer << MyViewer3D::updateDisplay; application.exec(); //! [polyhedralizer-visualization] //! [polyhedralizer-freeMemory] for ( vector<RoundPlane*>::iterator it = roundPlanes.begin(), itE = roundPlanes.end(); it != itE; ++it ) delete *it; //! [polyhedralizer-freeMemory] if (isOK && isOK2) return 0; else return 1; }
/** * 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 ..." ); QApplication application ( argc,argv ); DGtal::Viewer3D<> viewer; 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 true; //2; (return a bool !!!) } 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(); //Convolution kernel deprecated::ConstantConvolutionWeights< MyDigitalSurface::Size > kernel; //Estimator definition typedef deprecated::LocalConvolutionNormalVectorEstimator<MyDigitalSurface, deprecated::ConstantConvolutionWeights< MyDigitalSurface::Size > > MyEstimator; MyEstimator myNormalEstimator ( digSurf, kernel ); myNormalEstimator.init ( 1.0, 5 ); MyEstimator::Quantity res = myNormalEstimator.eval ( it ); trace.info() << "Normal vector at begin() : "<< res << std::endl; viewer.show(); DGtal::Color lineColorSave = viewer.getLineColor(); viewer.setLineColor( DGtal::Color ( 200,20,20 )); for ( MyDigitalSurface::ConstIterator itbis = digSurf.begin(),itend=digSurf.end(); itbis!=itend; ++itbis ) { viewer << ks.unsigns ( *itbis ); Point center = ks.sCoords ( *itbis ); MyEstimator::Quantity normal = myNormalEstimator.eval ( itbis ); viewer.addLine ( center, DGtal::Z3i::RealPoint(center[0]-3*normal[0], center[1]-3*normal[1], center[2]-3*normal[2]) ); } viewer.setLineColor( lineColorSave); viewer<< Viewer3D<>::updateDisplay; //Convolution kernel deprecated::GaussianConvolutionWeights< MyDigitalSurface::Size > Gkernel ( 14.0 ); //Estimator definition typedef deprecated::LocalConvolutionNormalVectorEstimator<MyDigitalSurface, deprecated::GaussianConvolutionWeights< MyDigitalSurface::Size > > MyEstimatorGaussian; MyEstimatorGaussian myNormalEstimatorG ( digSurf, Gkernel ); myNormalEstimatorG.init ( 1.0, 15 ); MyEstimatorGaussian::Quantity res2 = myNormalEstimatorG.eval ( it ); trace.info() << "Normal vector at begin() : "<< res2 << std::endl; viewer<< CustomColors3D ( Color ( 200, 0, 0 ),Color ( 200, 0,0 ) ); lineColorSave = viewer.getLineColor(); viewer.setLineColor( DGtal::Color ( 200,20,20 )); for ( MyDigitalSurface::ConstIterator itbis = digSurf.begin(),itend=digSurf.end(); itbis!=itend; ++itbis ) { viewer << ks.unsigns ( *itbis ); Point center = ks.sCoords ( *itbis ); MyEstimatorGaussian::Quantity normal = myNormalEstimatorG.eval ( itbis ); viewer.addLine ( center, DGtal::Z3i::RealPoint(center[0]-3*normal[0], center[1]-3*normal[1], center[2]-3*normal[2]) ); } viewer.setLineColor( lineColorSave); viewer<< Viewer3D<>::updateDisplay; nbok += true ? 1 : 0; nb++; trace.info() << "(" << nbok << "/" << nb << ") " << "true == true" << std::endl; trace.endBlock(); return application.exec(); }