Beispiel #1
0
int main( int narg, char **argv )
{
	trace.beginBlock("Identifying the domain.");
	Z3i::Domain domain = scene_dimensions( argv[1] ) ;
	if ( domain.lowerBound() == domain.upperBound() ) {
		trace.error()<<"Invalid domain ("<<__FILE__<<")"<<std::endl;
		return -1 ;
	}
	trace.endBlock() ;
	trace.beginBlock("Reading slices.");
	Z3i::DigitalSet set3d( domain ) ;
	
	SetPredicate<Z3i::DigitalSet> set3dPredicate( set3d ) ;
	for ( uint depth = 0 ; depth < domain.upperBound().at(2) ; depth++ )
		process_slice( argv[1], depth, set3d ) ;
	trace.endBlock() ;

	if ( 0) {
		try {
			Gray3DImage aImage( domain );
			for ( Z3i::Domain::ConstIterator pt = domain.begin() ; pt != domain.end() ; pt++ )
				aImage.setValue( (*pt), 255 ) ;
			boost::filesystem::path pathvolname = argv[1] ;
			pathvolname /= "obj.vol" ;
			if ( ! DGtal::VolWriter< Gray3DImage, GrayColorMap >::exportVol ( pathvolname.string(), aImage, 0, 255 ) )
			{
				trace.error() <<"Can not export data (generated 3D object)"<<std::endl;
				return -4 ;
			} else {
				trace.info()<<"export data to "<<pathvolname.string()<<std::endl;
			}
			pathvolname = argv[1] ;
			pathvolname /= "obj.pgm3d" ;
			if ( ! PNMWriter<Gray3DImage, GrayColorMap >::exportPGM3D( pathvolname.string(), aImage, 0, 255 ) )
			{
				trace.error() <<"Can not export data (generated 3D object)"<<std::endl;
				return -4 ;
			} else {
				trace.info()<<"export data to "<<pathvolname.string()<<std::endl;
			}
			
		} catch ( std::exception &e ) {
			trace.error() <<"Can not export data (generated 3D object) "<<e.what()<<std::endl;
			return -8 ;
		}
	}

	trace.beginBlock( "Decompose the object into connected components." );
	{
		DGtal::Z3i::Object6_18 scene( DGtal::Z3i::dt6_18, set3d ) ;
		std::vector< Z3i::Object6_18 > v_obj ;
		back_insert_iterator< std::vector< Z3i::Object6_18 > > it( v_obj ) ;
		scene.writeComponents( it ) ;
		boost::filesystem::path scenefilename = argv[1] ;
		scenefilename /= "scene.pgm3d" ;
		IOPgm3d::write( v_obj, scenefilename.string().c_str() ) ;
	}
	trace.endBlock( );

	return -64;
	
	trace.beginBlock( "Construct the Khalimsky space from the image domain." );
	Z3i::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();

	typedef SurfelAdjacency<Z3i::KSpace::dimension> MySurfelAdjacency;
	MySurfelAdjacency surfAdj( true ); // interior in all directions.

	trace.beginBlock( "Extracting boundary by tracking from an initial bel." );
	Z3i::KSpace::SCellSet boundary;
	Z3i::SCell bel = Surfaces<Z3i::KSpace>::findABel( ks, set3dPredicate, 100000 );
	Surfaces<Z3i::KSpace>::trackBoundary( boundary, ks, surfAdj, set3dPredicate, bel );
	trace.endBlock();

	trace.beginBlock( "Displaying surface in Viewer3D." );
	QApplication application(narg,argv);
	Viewer3D viewer;
	viewer.show();
	viewer 	<< SetMode3D( boundary.begin()->className(), "") ; //CustomColors3D(Color(250, 0, 0 ), Color( 128, 128, 128 ) );
	unsigned long nbSurfels = 0;
	for ( Z3i::KSpace::SCellSet::const_iterator it = boundary.begin(), it_end = boundary.end(); it != it_end; ++it, ++nbSurfels )
	
			viewer << ks.uCell( Z3i::Point( (*it).myCoordinates.at(0), (*it).myCoordinates.at(1), (*it).myCoordinates.at(2) ) ) ;
	
	/**
	for ( Z3i::KSpace::SCellSet::const_iterator it = boundary.begin(), it_end = boundary.end(); it != it_end; ++it, ++nbSurfels )
		viewer << (*it) ;
	*/
	trace.info() << *boundary.begin()<<std::endl;
	viewer << Viewer3D::updateDisplay;
	trace.info() << "nb surfels = " << nbSurfels << std::endl;
	trace.endBlock();
	return application.exec();
}
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")
    ("input,i", po::value< std::string >(), ".vol file")
    ("radius,r",  po::value< double >(), "Kernel radius for IntegralInvariant" )
    ("threshold,t",  po::value< unsigned int >()->default_value(8), "Min size of SCell boundary of an object" )
    ("minImageThreshold,l",  po::value<  int >()->default_value(0), "set the minimal image threshold to define the image object (object defined by the voxel with intensity belonging to ]minImageThreshold, maxImageThreshold ] )." )
    ("maxImageThreshold,u",  po::value<  int >()->default_value(255), "set the minimal image threshold to define the image object (object defined by the voxel with intensity belonging to ]minImageThreshold, maxImageThreshold] )." )
    ("mode,m", po::value< std::string >()->default_value("mean"), "type of output : mean, gaussian, k1, k2, prindir1, prindir2 or normal (default mean)")
    ("exportOBJ,o", po::value< std::string >(), "Export the scene to specified OBJ/MTL filename (extensions added)." )
    ("exportDAT,d", po::value<std::string>(), "Export resulting curvature (for mean, gaussian, k1 or k2 mode) in a simple data file each line representing a surfel. ")
    ("exportOnly", "Used to only export the result without the 3d Visualisation (usefull for scripts)." )
    ("imageScale,s", po::value<std::vector<double> >()->multitoken(), "scaleX, scaleY, scaleZ: re sample the source image according with a grid of size 1.0/scale (usefull to compute curvature on image defined on anisotropic grid). Set by default to 1.0 for the three axis.  ")
    ("normalization,n", "When exporting to OBJ, performs a 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.error() << " Error checking program options: " << ex.what() << std::endl;
    }
  bool neededArgsGiven=true;

  if (parseOK && !(vm.count("input"))){
    missingParam("--input");
    neededArgsGiven=false;
  }
  if (parseOK && !(vm.count("radius"))){
    missingParam("--radius");
    neededArgsGiven=false;
  }

  bool normalization = false;
  if (parseOK && vm.count("normalization"))
    normalization = true;

  std::string mode;
  if( parseOK )
    mode =  vm["mode"].as< std::string >();
  if ( parseOK && ( mode.compare("gaussian") != 0 ) && ( mode.compare("mean") != 0 ) &&
       ( mode.compare("k1") != 0 ) && ( mode.compare("k2") != 0 ) &&
       ( mode.compare("prindir1") != 0 ) && ( mode.compare("prindir2") != 0 ) && ( mode.compare("normal") != 0 ))
    {
      parseOK = false;
      trace.error() << " The selected mode ("<<mode << ") is not defined."<<std::endl;
    }

#ifndef WITH_VISU3D_QGLVIEWER
  bool enable_visu = false;
#else
  bool enable_visu = !vm.count("exportOnly"); ///<! Default QGLViewer viewer. Disabled if exportOnly is set.
#endif
  bool enable_obj = vm.count("exportOBJ"); ///<! Export to a .obj file.
  bool enable_dat = vm.count("exportDAT"); ///<! Export to a .dat file.

  if( !enable_visu && !enable_obj && !enable_dat )
    {
#ifndef WITH_VISU3D_QGLVIEWER
      trace.error() << "You should specify what you want to export with --export and/or --exportDat." << std::endl;
#else
      trace.error() << "You should specify what you want to export with --export and/or --exportDat, or remove --exportOnly." << std::endl;
#endif
      neededArgsGiven = false;
    }

  if(!neededArgsGiven || !parseOK || vm.count("help") || argc <= 1 )
    {
      trace.info()<< "Visualisation of 3d curvature from .vol file using curvature from Integral Invariant" <<std::endl
                  << general_opt << "\n"
                  << "Basic usage: "<<std::endl
                  << "\t3dCurvatureViewer -i file.vol --radius 5 --mode mean"<<std::endl
                  << std::endl
                  << "Below are the different available modes: " << std::endl
                  << "\t - \"mean\" for the mean curvature" << std::endl
                  << "\t - \"gaussian\" for the Gaussian curvature" << std::endl
                  << "\t - \"k1\" for the first principal curvature" << std::endl
                  << "\t - \"k2\" for the second principal curvature" << std::endl
                  << "\t - \"prindir1\" for the first principal curvature direction" << std::endl
                  << "\t - \"prindir2\" for the second principal curvature direction" << std::endl
                  << "\t - \"normal\" for the normal vector" << std::endl
                  << std::endl;
      return 0;
    }
  unsigned int threshold = vm["threshold"].as< unsigned int >();
  int minImageThreshold =  vm["minImageThreshold"].as<  int >();
  int maxImageThreshold =  vm["maxImageThreshold"].as<  int >();

  double h = 1.0;

  std::string export_obj_filename;
  std::string export_dat_filename;

  if( enable_obj )
    {
      export_obj_filename = vm["exportOBJ"].as< std::string >();
      if( export_obj_filename.find(".obj") == std::string::npos )
        {
          std::ostringstream oss;
          oss << export_obj_filename << ".obj" << std::endl;
          export_obj_filename = oss.str();
        }
    }


  if( enable_dat )
    {
      export_dat_filename = vm["exportDAT"].as<std::string>();
    }

  double re_convolution_kernel = vm["radius"].as< double >();


  std::vector<  double > aGridSizeReSample;
  if( vm.count( "imageScale" ))
    {
      std::vector< double> vectScale = vm["imageScale"].as<std::vector<double > >();
      if( vectScale.size() != 3 )
        {
          trace.error() << "The grid size should contains 3 elements" << std::endl;
          return 0;
        }
      else
        {
          aGridSizeReSample.push_back(1.0/vectScale.at(0));
          aGridSizeReSample.push_back(1.0/vectScale.at(1));
          aGridSizeReSample.push_back(1.0/vectScale.at(2));
        }
    }
  else
    {
      aGridSizeReSample.push_back(1.0);
      aGridSizeReSample.push_back(1.0);
      aGridSizeReSample.push_back(1.0);
    }



  // Construction of the shape from vol file
  typedef Z3i::Space::RealPoint RealPoint;
  typedef Z3i::Point Point;
  typedef ImageSelector< Z3i::Domain,  int>::Type Image;
  typedef DGtal::functors::BasicDomainSubSampler< HyperRectDomain<SpaceND<3, int> >,
                                                  DGtal::int32_t, double >   ReSampler;
  typedef DGtal::ConstImageAdapter<Image, Image::Domain, ReSampler,
                                   Image::Value,  DGtal::functors::Identity >  SamplerImageAdapter;
  typedef IntervalForegroundPredicate< SamplerImageAdapter > ImagePredicate;
  typedef BinaryPointPredicate<DomainPredicate<Image::Domain>, ImagePredicate, AndBoolFct2  > Predicate;
  typedef Z3i::KSpace KSpace;
  typedef KSpace::SCell SCell;
  typedef KSpace::Cell Cell;

  trace.beginBlock("Loading the file");
  std::string filename = vm["input"].as< std::string >();
  Image image = GenericReader<Image>::import( filename );

  PointVector<3,int> shiftVector3D( 0 ,0, 0 );
  DGtal::functors::BasicDomainSubSampler< HyperRectDomain< SpaceND< 3, int > >,
                                          DGtal::int32_t, double > reSampler(image.domain(),
                                                                             aGridSizeReSample,  shiftVector3D);
  const functors::Identity identityFunctor{};
  SamplerImageAdapter sampledImage ( image, reSampler.getSubSampledDomain(), reSampler, identityFunctor );
  ImagePredicate predicateIMG = ImagePredicate( sampledImage,  minImageThreshold, maxImageThreshold );
  DomainPredicate<Z3i::Domain> domainPredicate( sampledImage.domain() );
  AndBoolFct2 andF;
  Predicate predicate(domainPredicate, predicateIMG, andF  );


  Z3i::Domain domain =  sampledImage.domain();
  Z3i::KSpace K;
  bool space_ok = K.init( domain.lowerBound()-Z3i::Domain::Point::diagonal(),
                          domain.upperBound()+Z3i::Domain::Point::diagonal(), true );
  if (!space_ok)
    {
      trace.error() << "Error in the Khalimsky space construction."<<std::endl;
      return 2;
    }
  CanonicSCellEmbedder< KSpace > embedder( K );
  SurfelAdjacency< Z3i::KSpace::dimension > Sadj( true );
  trace.endBlock();
  // Viewer settings


  // Extraction of components
  typedef KSpace::SurfelSet SurfelSet;
  typedef SetOfSurfels< KSpace, SurfelSet > MySetOfSurfels;
  typedef DigitalSurface< MySetOfSurfels > MyDigitalSurface;

  trace.beginBlock("Extracting surfaces");
  std::vector< std::vector<SCell > > vectConnectedSCell;
  Surfaces<KSpace>::extractAllConnectedSCell(vectConnectedSCell,K, Sadj, predicate, false);
  std::ofstream outDat;
  if( enable_dat )
    {
      trace.info() << "Exporting curvature as dat file: "<< export_dat_filename <<std::endl;
      outDat.open( export_dat_filename.c_str() );
      outDat << "# data exported from 3dCurvatureViewer implementing the II curvature estimator (Coeurjolly, D.; Lachaud, J.O; Levallois, J., (2013). Integral based Curvature"
             << "  Estimators in Digital Geometry. DGCI 2013.) " << std::endl;
      outDat << "# format: surfel coordinates (in Khalimsky space) curvature: "<< mode <<  std::endl;
    }

  trace.info()<<"Number of components= "<<vectConnectedSCell.size()<<std::endl;
  trace.endBlock();

  if( vectConnectedSCell.size() == 0 )
    {
      trace.error()<< "No surface component exists. Please check the vol file threshold parameter.";
      trace.info()<<std::endl;
      exit(2);
    }

#ifdef WITH_VISU3D_QGLVIEWER
  QApplication application( argc, argv );
  typedef Viewer3D<Z3i::Space, Z3i::KSpace> Viewer;
#endif
  typedef Board3D<Z3i::Space, Z3i::KSpace> Board;

#ifdef WITH_VISU3D_QGLVIEWER
  Viewer viewer( K );
#endif
  Board board( K );

#ifdef WITH_VISU3D_QGLVIEWER
  if( enable_visu )
    {
      viewer.show();
    }
#endif

  for( unsigned int i = 0; i<vectConnectedSCell.size(); ++i )
    {
      if( vectConnectedSCell[i].size() <= threshold )
        {
          continue;
        }

      MySetOfSurfels  aSet(K, Sadj);

      for( std::vector<SCell>::const_iterator it = vectConnectedSCell.at(i).begin();
           it != vectConnectedSCell.at(i).end();
           ++it )
        {
          aSet.surfelSet().insert( *it);
        }

      MyDigitalSurface digSurf( aSet );


      typedef DepthFirstVisitor<MyDigitalSurface> Visitor;
      typedef GraphVisitorRange< Visitor > VisitorRange;
      typedef VisitorRange::ConstIterator SurfelConstIterator;
      VisitorRange range( new Visitor( digSurf, *digSurf.begin() ) );
      SurfelConstIterator abegin = range.begin();
      SurfelConstIterator aend = range.end();

      VisitorRange range2( new Visitor( digSurf, *digSurf.begin() ) );
      SurfelConstIterator abegin2 = range2.begin();

      trace.beginBlock("Curvature computation on a component");
      if( ( mode.compare("gaussian") == 0 ) || ( mode.compare("mean") == 0 )
          || ( mode.compare("k1") == 0 ) || ( mode.compare("k2") == 0 ))
        {
          typedef double Quantity;
          std::vector< Quantity > results;
          std::back_insert_iterator< std::vector< Quantity > > resultsIterator( results );
          if ( mode.compare("mean") == 0 )
            {
              typedef functors::IIMeanCurvature3DFunctor<Z3i::Space> MyIICurvatureFunctor;
              typedef IntegralInvariantVolumeEstimator<Z3i::KSpace, Predicate, MyIICurvatureFunctor> MyIIEstimator;

              MyIICurvatureFunctor functor;
              functor.init( h, re_convolution_kernel );

              MyIIEstimator estimator( functor );
              estimator.attach( K, predicate );
              estimator.setParams( re_convolution_kernel/h );
              estimator.init( h, abegin, aend );

              estimator.eval( abegin, aend, resultsIterator );
            }
          else if ( mode.compare("gaussian") == 0 )
            {
              typedef functors::IIGaussianCurvature3DFunctor<Z3i::Space> MyIICurvatureFunctor;
              typedef IntegralInvariantCovarianceEstimator<Z3i::KSpace, Predicate, MyIICurvatureFunctor> MyIIEstimator;

              MyIICurvatureFunctor functor;
              functor.init( h, re_convolution_kernel );

              MyIIEstimator estimator( functor ); estimator.attach( K,
                                                                    predicate ); estimator.setParams( re_convolution_kernel/h );
              estimator.init( h, abegin, aend );

              estimator.eval( abegin, aend, resultsIterator );
            }
          else if ( mode.compare("k1") == 0 )
            {
              typedef functors::IIFirstPrincipalCurvature3DFunctor<Z3i::Space> MyIICurvatureFunctor;
              typedef IntegralInvariantCovarianceEstimator<Z3i::KSpace, Predicate, MyIICurvatureFunctor> MyIIEstimator;

              MyIICurvatureFunctor functor;
              functor.init( h, re_convolution_kernel );

              MyIIEstimator estimator( functor );
              estimator.attach( K, predicate );
              estimator.setParams( re_convolution_kernel/h );
              estimator.init( h, abegin, aend );

              estimator.eval( abegin, aend, resultsIterator );
            }
          else if ( mode.compare("k2") == 0 )
            {
              typedef functors::IISecondPrincipalCurvature3DFunctor<Z3i::Space> MyIICurvatureFunctor;
              typedef IntegralInvariantCovarianceEstimator<Z3i::KSpace, Predicate, MyIICurvatureFunctor> MyIIEstimator;

              MyIICurvatureFunctor functor;
              functor.init( h, re_convolution_kernel );

              MyIIEstimator estimator( functor );
              estimator.attach( K, predicate );
              estimator.setParams( re_convolution_kernel/h );
              estimator.init( h, abegin, aend );

              estimator.eval( abegin, aend, resultsIterator );
            }
          trace.endBlock();


          // Drawing results
          trace.beginBlock("Visualisation");
          Quantity min = results[ 0 ];
          Quantity max = results[ 0 ];
          for ( unsigned int i = 1; i < results.size(); ++i )
            {
              if ( results[ i ] < min )
                {
                  min = results[ i ];
                }
              else if ( results[ i ] > max )
                {
                  max = results[ i ];
                }
            }
          trace.info() << "Max value= "<<max<<"  min value= "<<min<<std::endl;
          ASSERT( min <= max );
          typedef GradientColorMap< Quantity > Gradient;
          Gradient cmap_grad( min, (max==min)? max+1: max );
          cmap_grad.addColor( Color( 50, 50, 255 ) );
          cmap_grad.addColor( Color( 255, 0, 0 ) );
          cmap_grad.addColor( Color( 255, 255, 10 ) );

#ifdef WITH_VISU3D_QGLVIEWER
          if( enable_visu )
            {
              viewer << SetMode3D((*abegin2).className(), "Basic" );
            }
#endif
          if( enable_obj )
            {
              board << SetMode3D((K.unsigns(*abegin2)).className(), "Basic" );
            }


          for ( unsigned int i = 0; i < results.size(); ++i )
            {
#ifdef WITH_VISU3D_QGLVIEWER
              if( enable_visu )
                {
                  viewer << CustomColors3D( Color::Black, cmap_grad( results[ i ] ));
                  viewer << *abegin2;
                }
#endif

              if( enable_obj )
                {
                  board << CustomColors3D( Color::Black, cmap_grad( results[ i ] ));
                  board      << K.unsigns(*abegin2);
                }

              if( enable_dat )
                {
                  Point kCoords = K.uKCoords(K.unsigns(*abegin2));
                  outDat << kCoords[0] << " " << kCoords[1] << " " << kCoords[2] <<  " " <<  results[i] << std::endl;
                }

              ++abegin2;
            }
        }
      else
        {
          typedef Z3i::Space::RealVector Quantity;
          std::vector< Quantity > results;
          std::back_insert_iterator< std::vector< Quantity > > resultsIterator( results );

          if( mode.compare("prindir1") == 0 )
            {
              typedef functors::IIFirstPrincipalDirectionFunctor<Z3i::Space> MyIICurvatureFunctor;
              typedef IntegralInvariantCovarianceEstimator<Z3i::KSpace, Predicate, MyIICurvatureFunctor> MyIIEstimator;

              MyIICurvatureFunctor functor;
              functor.init( h, re_convolution_kernel );

              MyIIEstimator estimator( functor );
              estimator.attach( K, predicate );
              estimator.setParams( re_convolution_kernel/h );
              estimator.init( h, abegin, aend );

              estimator.eval( abegin, aend, resultsIterator );
            }
          else if( mode.compare("prindir2") == 0 )
            {
              typedef functors::IISecondPrincipalDirectionFunctor<Z3i::Space> MyIICurvatureFunctor;
              typedef IntegralInvariantCovarianceEstimator<Z3i::KSpace, Predicate, MyIICurvatureFunctor> MyIIEstimator;

              MyIICurvatureFunctor functor;
              functor.init( h, re_convolution_kernel );

              MyIIEstimator estimator( functor );
              estimator.attach( K, predicate );
              estimator.setParams( re_convolution_kernel/h );
              estimator.init( h, abegin, aend );

              estimator.eval( abegin, aend, resultsIterator );
            }
          else
            if( mode.compare("normal") == 0 )
              {
                typedef functors::IINormalDirectionFunctor<Z3i::Space> MyIICurvatureFunctor;
                typedef IntegralInvariantCovarianceEstimator<Z3i::KSpace, Predicate, MyIICurvatureFunctor> MyIIEstimator;

                MyIICurvatureFunctor functor;
                functor.init( h, re_convolution_kernel );

                MyIIEstimator estimator( functor );
                estimator.attach( K, predicate );
                estimator.setParams( re_convolution_kernel/h );
                estimator.init( h, abegin, aend );

                estimator.eval( abegin, aend, resultsIterator );
              }



          ///Visualizaton / export

#ifdef WITH_VISU3D_QGLVIEWER
          if( enable_visu )
            {
              viewer << SetMode3D(K.uCell( K.sKCoords(*abegin2) ).className(), "Basic" );
            }
#endif

          if( enable_obj )
            {
              board << SetMode3D(K.uCell( K.sKCoords(*abegin2) ).className(), "Basic" );
            }

          for ( unsigned int i = 0; i < results.size(); ++i )
            {
              DGtal::Dimension kDim = K.sOrthDir( *abegin2 );
              SCell outer = K.sIndirectIncident( *abegin2, kDim);
              if ( predicate(embedder(outer)) )
                {
                  outer = K.sDirectIncident( *abegin2, kDim);
                }

              Cell unsignedSurfel = K.uCell( K.sKCoords(*abegin2) );

#ifdef WITH_VISU3D_QGLVIEWER
              if( enable_visu )
                {
                  viewer << CustomColors3D( DGtal::Color(255,255,255,255),
                                            DGtal::Color(255,255,255,255))
                         << unsignedSurfel;
                }
#endif

              if( enable_obj )
                {
                  board << CustomColors3D( DGtal::Color(255,255,255,255),
                                           DGtal::Color(255,255,255,255))
                        << unsignedSurfel;
                }

              if( enable_dat )
                {
                  Point kCoords = K.uKCoords(K.unsigns(*abegin2));
                  outDat << kCoords[0] << " " << kCoords[1] << " " << kCoords[2] << " "
                         << results[i][0] << " " << results[i][1] << " " << results[i][2]
                         << std::endl;
                }

              RealPoint center = embedder( outer );

#ifdef WITH_VISU3D_QGLVIEWER
              if( enable_visu )
                {
                  if( mode.compare("prindir1") == 0 )
                    {
                      viewer.setLineColor( AXIS_COLOR_BLUE );
                    }
                  else if( mode.compare("prindir2") == 0 )
                    {
                      viewer.setLineColor( AXIS_COLOR_RED );
                    }
                  else if( mode.compare("normal") == 0 )
                    {
                      viewer.setLineColor( AXIS_COLOR_GREEN );
                    }


                  viewer.addLine (
                                  RealPoint(
                                            center[0] -  0.5 * results[i][0],
                                            center[1] -  0.5 * results[i][1],
                                            center[2] -  0.5 * results[i][2]
                                            ),
                                  RealPoint(
                                            center[0] +  0.5 * results[i][0],
                                            center[1] +  0.5 * results[i][1],
                                            center[2] +  0.5 * results[i][2]
                                            ),
                                  AXIS_LINESIZE );
                }
#endif

              if( enable_obj )
                {
                  if( mode.compare("prindir1") == 0 )
                    {
                      board.setFillColor( AXIS_COLOR_BLUE );
                    }
                  else if( mode.compare("prindir2") == 0 )
                    {
                      board.setFillColor( AXIS_COLOR_RED );
                    }
                  else if( mode.compare("normal") == 0 )
                    {
                      board.setFillColor( AXIS_COLOR_GREEN );
                    }

                  board.addCylinder (
                                     RealPoint(
                                               center[0] -  0.5 * results[i][0],
                                               center[1] -  0.5 * results[i][1],
                                               center[2] -  0.5 * results[i][2]),
                                     RealPoint(
                                               center[0] +  0.5 * results[i][0],
                                               center[1] +  0.5 * results[i][1],
                                               center[2] +  0.5 * results[i][2]),
                                     0.2 );
                }

              ++abegin2;
            }
        }
      trace.endBlock();
    }

#ifdef WITH_VISU3D_QGLVIEWER
  if( enable_visu )
    {
      viewer << Viewer3D<>::updateDisplay;
    }
#endif
  if( enable_obj )
    {
      trace.info()<< "Exporting object: " << export_obj_filename << " ...";
      board.saveOBJ(export_obj_filename,normalization);
      trace.info() << "[done]" << std::endl;
    }
  if( enable_dat )
    {
      outDat.close();
    }

#ifdef WITH_VISU3D_QGLVIEWER
  if( enable_visu )
    {
      return application.exec();
    }
#endif

  return 0;
}
int main( int argc, char** argv )
{
    if ( argc != 4 )
    {
        trace.error() << "Usage: " << argv[0]
                               << " <fileName.vol> <threshold> <re_convolution_kernel>" << std::endl;
        trace.error() << "Example : "<< argv[0] << " Al.150.vol 0 7.39247665" << std::endl;
        return 0;
    }

    trace.beginBlock ( "Example IntegralInvariantCurvature3D" );
    trace.info() << "Args:";
    for ( int i = 0; i < argc; ++i )
        trace.info() << " " << argv[ i ];
    trace.info() << endl;

    double h = 1.0;
    unsigned int threshold = atoi( argv[ 2 ] );

    /// Construction of the shape from vol file
    typedef ImageSelector< Z3i::Domain, unsigned int >::Type Image;
    typedef SimpleThresholdForegroundPredicate< Image > ImagePredicate;
    typedef Z3i::KSpace::Surfel Surfel;
    typedef LightImplicitDigitalSurface< Z3i::KSpace, ImagePredicate > MyLightImplicitDigitalSurface;
    typedef DigitalSurface< MyLightImplicitDigitalSurface > MyDigitalSurface;

    std::string filename = argv[1];
    Image image = VolReader<Image>::importVol( filename );
    ImagePredicate predicate = ImagePredicate( image, threshold );

    Z3i::Domain domain = image.domain();

    Z3i::KSpace KSpaceShape;

    bool space_ok = KSpaceShape.init( domain.lowerBound(), domain.upperBound(), true );
    if (!space_ok)
    {
      trace.error() << "Error in the Khalimsky space construction."<<std::endl;
      return 2;
    }

    SurfelAdjacency< Z3i::KSpace::dimension > SAdj( true );
    Surfel bel = Surfaces< Z3i::KSpace >::findABel( KSpaceShape, predicate, 100000 );
    MyLightImplicitDigitalSurface LightImplDigSurf( KSpaceShape, predicate, SAdj, bel );
    MyDigitalSurface digSurf( LightImplDigSurf );

    typedef DepthFirstVisitor< MyDigitalSurface > Visitor;
    typedef GraphVisitorRange< Visitor > VisitorRange;
    typedef VisitorRange::ConstIterator SurfelConstIterator;

    VisitorRange range( new Visitor( digSurf, *digSurf.begin() ) );
    SurfelConstIterator abegin = range.begin();
    SurfelConstIterator aend = range.end();

    typedef ImageToConstantFunctor< Image, ImagePredicate > MyPointFunctor;
    MyPointFunctor pointFunctor( &image, &predicate, 1 );

    /// Integral Invariant stuff
    //! [IntegralInvariantUsage]
    double re_convolution_kernel = atof(argv[3]);

    typedef FunctorOnCells< MyPointFunctor, Z3i::KSpace > MyCellFunctor;
    typedef IntegralInvariantGaussianCurvatureEstimator< Z3i::KSpace, MyCellFunctor > MyCurvatureEstimator; // Gaussian curvature estimator

    MyCellFunctor functor ( pointFunctor, KSpaceShape ); // Creation of a functor on Cells, returning true if the cell is inside the shape
    MyCurvatureEstimator estimator ( KSpaceShape, functor );
    estimator.init( h, re_convolution_kernel ); // Initialisation for a given Euclidean radius of convolution kernel
    std::vector< double > results;
    back_insert_iterator< std::vector< double > > resultsIterator( results ); // output iterator for results of Integral Invariante curvature computation
    estimator.eval ( abegin, aend, resultsIterator ); // Computation
    //! [IntegralInvariantUsage]

    /// Drawing results
    typedef MyCurvatureEstimator::Quantity Quantity;
    Quantity min = numeric_limits < Quantity >::max();
    Quantity max = numeric_limits < Quantity >::min();
    for ( unsigned int i = 0; i < results.size(); ++i )
    {
        if ( results[ i ] < min )
        {
            min = results[ i ];
        }
        else if ( results[ i ] > max )
        {
            max = results[ i ];
        }
    }

    QApplication application( argc, argv );
    Viewer3D<> viewer;
    viewer.show();

    typedef GradientColorMap< Quantity > Gradient;
    Gradient cmap_grad( min, max );
    cmap_grad.addColor( Color( 50, 50, 255 ) );
    cmap_grad.addColor( Color( 255, 0, 0 ) );
    cmap_grad.addColor( Color( 255, 255, 10 ) );

    VisitorRange range2( new Visitor( digSurf, *digSurf.begin() ) );
    abegin = range2.begin();

    for ( unsigned int i = 0; i < results.size(); ++i )
    {
        viewer << CustomColors3D( Color::Black, cmap_grad( results[ i ] ))
               << *abegin;
        ++abegin;
    }

    viewer << Viewer3D<>::updateDisplay;

    trace.endBlock();
    return application.exec();
}