169{
  170  if ( argc <= 1 )
  171    {
  173      return 0;
  174    }
  176  using namespace DGtal;
 
  183  std::string  poly = argv[ 1 ]; 
  184  const double    B = argc > 2 ? atof( argv[ 2 ] ) : 1.0; 
 
  185  const double    h = argc > 3 ? atof( argv[ 3 ] ) : 1.0; 
  186  const double    R = argc > 4 ? atof( argv[ 4 ] ) : 2.0; 
  187  std::string  mode = argc > 5 ? argv[ 5 ] : "Const"; 
  188  bool interpolated = mode == "Interp";
  189  if ( interpolated )
  190    std::cout << "Using vertex-*Interpolated* Corrected Normal Current" << std::endl;
  191  else
  192    std::cout << "Using face-*Constant* Corrected Normal Current" << std::endl;
  194  
  195  auto params = SH::defaultParameters() | SHG::defaultParameters();
  196  params( "t-ring", 3 )( "surfaceTraversal", "Default" );
  197  params( "polynomial", poly )( "gridstep", h ); 
  198  params( 
"minAABB", -
B )( 
"maxAABB", 
B );
 
  199  params( "offset", 3.0 );
  200  auto shape       = SH::makeImplicitShape3D( params );
  201  auto K           = SH::getKSpace( params );
 
  202  auto dshape      = SH::makeDigitizedImplicitShape3D( shape, params );
  203  auto bimage      = SH::makeBinaryImage( dshape, params );
  204  if ( bimage == nullptr ) 
  205    {
  206      trace.error() <<  
"Unable to read polynomial <" 
  207                    << poly.c_str() << ">" << std::endl;
  208      return 1;
  209    }
  210  auto sembedder   = SH::getSCellEmbedder( 
K );
 
  211  auto embedder    = SH::getCellEmbedder( 
K );
 
  212  auto surface     = SH::makeDigitalSurface( bimage, 
K, params );
 
  213  auto surfels     = SH::getSurfelRange( 
surface, params );
 
  214  trace.info() << 
"- surface has " << surfels.size()<< 
" surfels." << std::endl;
 
  216
  218  SM smesh;
  219  std::vector< SM::Vertices > faces;
  220  SH::Cell2Index c2i;
  221  auto pointels = SH::getPointelRange( c2i, 
surface );
 
  222  auto vertices = SH::RealPoints( pointels.size() );
 
  223  std::transform( pointels.cbegin(), pointels.cend(), 
vertices.begin(),
 
  224                  [&] (const SH::Cell& c) { return h * embedder( c ); } ); 
  225  for ( 
auto&& surfel : *
surface )
 
  226    {
  227      const auto primal_surfel_vtcs = SH::getPointelRange( 
K, surfel );
 
  228      SM::Vertices face;              
  229      for ( auto&& primal_vtx : primal_surfel_vtcs )
  230        face.push_back( c2i[ primal_vtx ] );
  231      faces.push_back( face );
  232    }
  234              faces.cbegin(),    faces.cend() );
  235  trace.info() << smesh << std::endl;
 
  237
  239  auto exp_H = SHG::getMeanCurvatures( shape, 
K, surfels, params );
 
  240  auto exp_G = SHG::getGaussianCurvatures( shape, 
K, surfels, params );
 
  242
  244  
  245  CNC cnc( smesh );
  246  
  247  auto face_normals = SHG::getCTrivialNormalVectors( 
surface, surfels, params );
 
  248  
  249  
  250  smesh.setFaceNormals( face_normals.cbegin(), face_normals.cend() ); 
  251  
  252  
  253  if ( interpolated ) smesh.computeVertexNormalsFromFaceNormals();    
  254  
  255  auto mu0 = cnc.computeMu0();
  256  auto mu1 = cnc.computeMu1();
  257  auto mu2 = cnc.computeMu2();
  259
  261  
  262  std::vector< double > 
H( smesh.nbFaces() );
 
  263  std::vector< double > G( smesh.nbFaces() );
  264  for ( auto f = 0; f < smesh.nbFaces(); ++f )
  265    {
  266      const auto b    = smesh.faceCentroid( f );
  267      const auto area = mu0.measure( b, R, f );
  268      H[ f ] = cnc.meanCurvature    ( area, mu1.measure( b, R, f ) );
 
  269      G[ f ] = cnc.GaussianCurvature( area, mu2.measure( b, R, f ) );
  270    }
  272
  274  auto H_min_max = std::minmax_element( 
H.cbegin(), 
H.cend() );
 
  275  auto G_min_max = std::minmax_element( G.cbegin(), G.cend() );
  276  auto exp_H_min_max = std::minmax_element( exp_H.cbegin(), exp_H.cend() );
  277  auto exp_G_min_max = std::minmax_element( exp_G.cbegin(), exp_G.cend() );
  278  std::cout << "Expected mean curvatures:"
  279            << " min=" << *exp_H_min_max.first << " max=" << *exp_H_min_max.second
  280            << std::endl;
  281  std::cout << "Computed mean curvatures:"
  282            << " min=" << *H_min_max.first << " max=" << *H_min_max.second
  283            << std::endl;
  284  std::cout << "Expected Gaussian curvatures:"
  285            << " min=" << *exp_G_min_max.first << " max=" << *exp_G_min_max.second
  286            << std::endl;
  287  std::cout << "Computed Gaussian curvatures:"
  288            << " min=" << *G_min_max.first << " max=" << *G_min_max.second
  289            << std::endl;
  290  const auto      error_H = SHG::getScalarsAbsoluteDifference( 
H, exp_H );
 
  291  const auto stat_error_H = SHG::getStatistic( error_H );
  292  const auto   error_H_l2 = SHG::getScalarsNormL2( 
H, exp_H );
 
  293  trace.info() << 
"|H-H_CNC|_oo = " << stat_error_H.max() << std::endl;
 
  294  trace.info() << 
"|H-H_CNC|_2  = " << error_H_l2 << std::endl;
 
  295  const auto      error_G = SHG::getScalarsAbsoluteDifference( G, exp_G );
  296  const auto stat_error_G = SHG::getStatistic( error_G );
  297  const auto   error_G_l2 = SHG::getScalarsNormL2( G, exp_G );
  298  trace.info() << 
"|G-G_CNC|_oo = " << stat_error_G.max() << std::endl;
 
  299  trace.info() << 
"|G-G_CNC|_2  = " << error_G_l2 << std::endl;
 
  301
  303  
  304  smesh.vertexNormals() = SH::RealVectors();
  305  smesh.faceNormals()   = SH::RealVectors();
  307  const double    Hmax = std::max( fabs( *exp_H_min_max.first ),
  308                                   fabs( *exp_H_min_max.second ) );
  309  const double    Gmax = std::max( fabs( *exp_G_min_max.first ),
  310                                   fabs( *exp_G_min_max.second ) );
  313  auto colorsH = SMW::Colors( smesh.nbFaces() );
  314  auto colorsG = SMW::Colors( smesh.nbFaces() );
  315  for ( auto i = 0; i < smesh.nbFaces(); i++ )
  316    {
  317      colorsH[ i ] = colormapH( 
H[ i ] );
 
  318      colorsG[ i ] = colormapG( G[ i ] );
  319    }
  320  SMW::writeOBJ( "example-cnc-H", smesh, colorsH );
  321  SMW::writeOBJ( "example-cnc-G", smesh, colorsG );
  323  return 0;
  324}
CountedPtr< SH3::DigitalSurface > surface
 
DGtal::GradientColorMap< double > makeColorMap(double min_value, double max_value)
[curvature-measures-Includes]
 
Z3i this namespace gathers the standard of types for 3D imagery.
 
DGtal is the top-level namespace which contains all DGtal functions and types.
 
QuantifiedColorMap< TColorMap > makeQuantifiedColorMap(TColorMap colormap, int nb=50)
 
std::pair< typename graph_traits< DGtal::DigitalSurface< TDigitalSurfaceContainer > >::vertex_iterator, typename graph_traits< DGtal::DigitalSurface< TDigitalSurfaceContainer > >::vertex_iterator > vertices(const DGtal::DigitalSurface< TDigitalSurfaceContainer > &digSurf)