Esempio n. 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 )
{

  typedef PointVector<4, double> Point4D;
  typedef PointVector<1, int> Point1D;
    
  // 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>(), "input file: sdp (sequence of discrete points with attribute)" )
    ("noWindows,n", "Don't display Viewer windows." )
    ("doSnapShotAndExit,d", po::value<std::string>(), "save display snapshot into file." )
    ("fixMaxColorValue", po::value<double>(), "fix the maximal color value for the scale error display (else the scale is set from the maximal value)" )
    ("fixMinColorValue", po::value<double>(), "fix the minimal color value for the scale error display (else the scale is set from the minimal value)" )
    ("labelIndex", po::value<unsigned int>(), "set the index of the label (by default set to 3)  " ) 
    ("SDPindex", po::value<std::vector <unsigned int> >()->multitoken(), "specify the sdp index (by default 0,1,2).");


  bool parseOK=true;
  bool cannotStart= false;
  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()<< endl;
  }
  po::notify(vm);    
  if(parseOK && ! vm.count("input"))
    {
      trace.error() << " The input file name was not defined" << endl;      
      cannotStart = true;
    }
   
  
  if( !parseOK || cannotStart ||  vm.count("help")||argc<=1)
    {
      trace.info() << "Usage: " << argv[0] << " [input]\n"
		<< "Display surfel data from SDP file with color attributes given as scalar interpreted as color."
		<< general_opt << "\n";
      return 0;
    }
  Z3i::KSpace K;
  string inputFilename = vm["input"].as<std::string>();

  
  std::vector<Point4D> surfelAndScalarInput;
  

  
  if(vm.count("SDPindex")) {
    std::vector<unsigned int > vectIndex = vm["SDPindex"].as<std::vector<unsigned int > >();
    if(vectIndex.size()!=4){
      trace.error() << "you need to specify the three indexes of vertex." << std::endl; 
      return 0;
    }
    surfelAndScalarInput = PointListReader<Point4D>::getPointsFromFile(inputFilename, vectIndex);
  }else{
    surfelAndScalarInput = PointListReader<Point4D>::getPointsFromFile(inputFilename);
  }  
  
  
  Point4D ptLower = surfelAndScalarInput.at(0);
  Point4D ptUpper = surfelAndScalarInput.at(0);
  getBoundingUpperAndLowerPoint(surfelAndScalarInput,  ptLower, ptUpper);
  
  
  K.init(Z3i::Point(2*ptLower[0]+1, 2*ptLower[1]+1, 2*ptLower[2]+1),
         Z3i::Point(2*ptUpper[0]+1, 2*ptUpper[1]+1, 2*ptUpper[2]+1), true);
  
  
  std::vector<Cell> vectSurfelsInput; 
  
  // Construction of the set of surfels
  for(unsigned int i =0; i<surfelAndScalarInput.size(); i++){
    Point4D pt4d = surfelAndScalarInput.at(i);
    Cell c = K.uCell(Z3i::Point(pt4d[0], pt4d[1], pt4d[2])); 
    vectSurfelsInput.push_back(c);
  }
  
    
  CanonicCellEmbedder<KSpace> embeder(K);
  std::vector<unsigned int> vectIndexMinToReference;
  
  
  //-------------------------
  // Displaying input with color given from scalar values
  
  QApplication application(argc,argv);
  typedef ViewerSnap<> Viewer;
   
  Viewer viewer(K, vm.count("doSnapShotAndExit"));
  if(vm.count("doSnapShotAndExit")){
    viewer.setSnapshotFileName(QString(vm["doSnapShotAndExit"].as<std::string>().c_str()));
  }
  viewer.setWindowTitle("3dCompSurfel Viewer");
  viewer.show();
  viewer.restoreStateFromFile();
    
  double minScalarVal=surfelAndScalarInput.at(0)[3];
  double maxScalarVal=surfelAndScalarInput.at(0)[3];

  for(unsigned int i=1; i <surfelAndScalarInput.size(); i++){
    double scalVal = surfelAndScalarInput.at(i)[3];
    if(scalVal < minScalarVal){
      minScalarVal = scalVal;
    }
    if(scalVal > maxScalarVal){
      maxScalarVal = scalVal;
    }
  }
  if(vm.count("fixMaxColorValue")){
    maxScalarVal = vm["fixMaxColorValue"].as<double>();
  }
  if(vm.count("fixMinColorValue")){
    minScalarVal = vm["fixMinColorValue"].as<double>();
  }  
  
  GradientColorMap<double> gradientColorMap( minScalarVal, maxScalarVal );
  gradientColorMap.addColor( Color(255,0,0,100 ) );
  gradientColorMap.addColor( Color(0,255,0,100 ) );
  gradientColorMap.addColor( Color(0,0,255,100 ) );

  bool useGrad = minScalarVal!=maxScalarVal;

  viewer << SetMode3D(vectSurfelsInput.at(0).className(), "Basic");
  for(unsigned int i=0; i <surfelAndScalarInput.size(); i++){
    double valInput = surfelAndScalarInput.at(i)[3];
    if(useGrad){
      viewer.setFillColor(gradientColorMap(valInput));
    }else{
      viewer.setFillColor(Color::White);
    }
    viewer << vectSurfelsInput.at(i);     
  }
  
  
  
  viewer << Viewer::updateDisplay;
  if(vm.count("doSnapShotAndExit")){
    // Appy cleaning just save the last snap
    std::string name = vm["doSnapShotAndExit"].as<std::string>();
    std::string extension = name.substr(name.find_last_of(".") + 1);
    std::string basename = name.substr(0, name.find_last_of("."));
    for(int i=0; i< viewer.snapshotCounter()-1; i++){
      std::stringstream s; 
      s << basename << "-"<< setfill('0') << setw(4)<<  i << "." << extension; 
      trace.info() << "erase temp file: " << s.str() << std::endl;
      remove(s.str().c_str());
    }
    std::stringstream s; 
    s << basename << "-"<< setfill('0') << setw(4)<<  viewer.snapshotCounter()-1 << "." << extension;
    rename(s.str().c_str(), name.c_str()); 
    return 0;
  }
  
  if(vm.count("noWindows")){
    return 0;
  }else{
    return application.exec();
  }
}