void computeEstimation ( const po::variables_map& vm, //< command-line parameters const KSpace& K, //< cellular grid space const ImplicitShape& shape, //< implicit shape "ground truth" const Surface& surface, //< digital surface approximating shape TrueEstimator& true_estimator, //< "ground truth" estimator Estimator& estimator ) //< an initialized estimator { typedef typename Surface::ConstIterator ConstIterator; typedef typename Surface::Surfel Surfel; typedef typename Estimator::Quantity Quantity; typedef double Scalar; typedef DepthFirstVisitor< Surface > Visitor; typedef GraphVisitorRange< Visitor > VisitorRange; typedef typename VisitorRange::ConstIterator VisitorConstIterator; std::string fname = vm[ "output" ].as<std::string>(); string nameEstimator = vm[ "estimator" ].as<string>(); trace.beginBlock( "Computing " + nameEstimator + "estimations." ); CountedPtr<VisitorRange> range( new VisitorRange( new Visitor( surface, *(surface.begin()) )) ); std::vector<Quantity> n_estimations; estimator.eval( range->begin(), range->end(), std::back_inserter( n_estimations ) ); trace.info() << "- nb estimations = " << n_estimations.size() << std::endl; trace.endBlock(); trace.beginBlock( "Computing ground truth." ); range = CountedPtr<VisitorRange>( new VisitorRange( new Visitor( surface, *(surface.begin()) )) ); std::vector<Quantity> n_true_estimations; true_estimator.eval( range->begin(), range->end(), std::back_inserter( n_true_estimations ) ); trace.info() << "- nb estimations = " << n_true_estimations.size() << std::endl; trace.endBlock(); trace.beginBlock( "Correcting orientations." ); ASSERT( n_estimations.size() == n_true_estimations.size() ); for ( unsigned int i = 0; i < n_estimations.size(); ++i ) if ( n_estimations[ i ].dot( n_true_estimations[ i ] ) < 0 ) n_estimations[ i ] = -n_estimations[ i ]; trace.endBlock(); DGtal::GradientColorMap<double> grad( 0.0, 40.0 ); // 0 metallic blue, 5 light cyan, 10 light green, 15 light // yellow, 20 yellow, 25 orange, 30 red, 35, dark red, 40- grey grad.addColor( DGtal::Color( 128, 128, 255 ) ); // 0 grad.addColor( DGtal::Color( 128, 255, 255 ) ); // 5 grad.addColor( DGtal::Color( 128, 255, 128 ) ); // 10 grad.addColor( DGtal::Color( 255, 255, 128 ) ); // 15 grad.addColor( DGtal::Color( 255, 255, 0 ) ); // 20 grad.addColor( DGtal::Color( 255, 128, 0 ) ); // 25 grad.addColor( DGtal::Color( 255, 0, 0 ) ); // 30 grad.addColor( DGtal::Color( 128, 0, 0 ) ); // 35 grad.addColor( DGtal::Color( 128, 128, 128 ) ); // 40 if ( vm.count( "angle-deviation-stats" ) ) { trace.beginBlock( "Computing angle deviation error stats." ); std::ostringstream adev_sstr; adev_sstr << fname << "-" << nameEstimator << "-angle-deviation-" << estimator.h() << ".txt"; DGtal::Statistic<Scalar> adev_stat; unsigned int i = 0; range = CountedPtr<VisitorRange>( new VisitorRange( new Visitor( surface, *(surface.begin()) )) ); for ( VisitorConstIterator it = range->begin(), itE = range->end(); it != itE; ++it, ++i ) { Quantity n_est = n_estimations[ i ]; Quantity n_true_est = n_true_estimations[ i ]; Scalar angle_error = acos( n_est.dot( n_true_est ) ); adev_stat.addValue( angle_error ); } adev_stat.terminate(); std::ofstream adev_output( adev_sstr.str().c_str() ); adev_output << "# Average error X of the absolute angle between two vector estimations." << std::endl; adev_output << "# h L1 L2 Loo E[X] Var[X] Min[X] Max[X] Nb[X]" << std::endl; adev_output << estimator.h() << " " << adev_stat.mean() // L1 << " " << sqrt( adev_stat.unbiasedVariance() + adev_stat.mean()*adev_stat.mean() ) // L2 << " " << adev_stat.max() // Loo << " " << adev_stat.mean() // E[X] (=L1) << " " << adev_stat.unbiasedVariance() // Var[X] << " " << adev_stat.min() // Min[X] << " " << adev_stat.max() // Max[X] << " " << adev_stat.samples() // Nb[X] << std::endl; adev_output.close(); trace.endBlock(); } if ( vm[ "export" ].as<string>() != "None" ) { trace.beginBlock( "Exporting cell geometry." ); std::ostringstream export_sstr; export_sstr << fname << "-" << nameEstimator << "-cells-" << estimator.h() << ".txt"; std::ofstream export_output( export_sstr.str().c_str() ); export_output << "# ImaGene viewer (viewSetOfSurfels) file format for displaying cells." << std::endl; bool adev = vm[ "export" ].as<string>() == "AngleDeviation"; unsigned int i = 0; range = CountedPtr<VisitorRange>( new VisitorRange( new Visitor( surface, *(surface.begin()) )) ); for ( VisitorConstIterator it = range->begin(), itE = range->end(); it != itE; ++it, ++i ) { Quantity n_est = n_estimations[ i ]; Quantity n_true_est = n_true_estimations[ i ]; Scalar angle_error = acos( n_est.dot( n_true_est ) )*180.0 / 3.14159625; Surfel s = *it; export_output << "CellN" << " " << min( 1023, max( 512+K.sKCoord( s, 0 ), 0 ) ) << " " << min( 1023, max( 512+K.sKCoord( s, 1 ), 0 ) ) << " " << min( 1023, max( 512+K.sKCoord( s, 2 ), 0 ) ) << " " << K.sSign( s ); Color c = grad( 0 ); if ( adev ) c = grad( max( 0.0, min( angle_error, 40.0 ) ) ); export_output << " " << ((double) c.red() / 255.0 ) << " " << ((double) c.green() / 255.0 ) << " " << ((double) c.blue() / 255.0 ); export_output << " " << n_est[ 0 ] << " " << n_est[ 1 ] << " " << n_est[ 2 ] << std::endl; } export_output.close(); trace.endBlock(); } if ( vm.count( "normals" ) ) { trace.beginBlock( "Exporting cells normals." ); std::ostringstream export_sstr; export_sstr << fname << "-" << nameEstimator << "-normals-" << estimator.h() << ".txt"; std::ofstream export_output( export_sstr.str().c_str() ); export_output << "# kx ky kz sign n_est[0] n_est[1] n_est[2] n_true[0] n_true[1] n_true[2]" << std::endl; unsigned int i = 0; range = CountedPtr<VisitorRange>( new VisitorRange( new Visitor( surface, *(surface.begin()) )) ); for ( VisitorConstIterator it = range->begin(), itE = range->end(); it != itE; ++it, ++i ) { Quantity n_est = n_estimations[ i ]; Quantity n_true_est = n_true_estimations[ i ]; Surfel s = *it; export_output << K.sKCoord( s, 0 ) << " " << K.sKCoord( s, 1 ) << " " << K.sKCoord( s, 2 ) << " " << K.sSign( s ) << " " << n_est[ 0 ] << " " << n_est[ 1 ] << " " << n_est[ 2 ] << " " << n_true_est[ 0 ] << " " << n_true_est[ 1 ] << " " << n_true_est[ 2 ] << std::endl; } export_output.close(); trace.endBlock(); } if ( vm.count( "noff" ) ) { trace.beginBlock( "Exporting NOFF file." ); std::ostringstream export_sstr; export_sstr << fname << "-" << nameEstimator << "-noff-" << estimator.h() << ".off"; std::ofstream export_output( export_sstr.str().c_str() ); std::map<Surfel,Quantity> normals; unsigned int i = 0; range = CountedPtr<VisitorRange>( new VisitorRange( new Visitor( surface, *(surface.begin()) )) ); for ( VisitorConstIterator it = range->begin(), itE = range->end(); it != itE; ++it, ++i ) { Quantity n_est = n_estimations[ i ]; normals[ *it ] = n_est; } CanonicSCellEmbedder<KSpace> surfelEmbedder( K ); typedef SCellEmbedderWithNormal< CanonicSCellEmbedder<KSpace> > Embedder; Embedder embedder( surfelEmbedder, normals ); surface.exportAs3DNOFF( export_output, embedder ); export_output.close(); trace.endBlock(); } #ifdef WITH_VISU3D_QGLVIEWER if ( vm[ "view" ].as<string>() != "None" ) { typedef typename KSpace::Space Space; typedef Viewer3D<Space,KSpace> MyViewever3D; typedef Display3DFactory<Space,KSpace> MyDisplay3DFactory; int argc = 1; char name[] = "Viewer"; char* argv[ 1 ]; argv[ 0 ] = name; Surfel s; QApplication application( argc, argv ); MyViewever3D viewer( K ); viewer.show(); viewer << SetMode3D( s.className(), "Basic" ); trace.beginBlock( "Viewing surface." ); bool adev = vm[ "view" ].as<string>() == "AngleDeviation"; unsigned int i = 0; range = CountedPtr<VisitorRange>( new VisitorRange( new Visitor( surface, *(surface.begin()) )) ); for ( VisitorConstIterator it = range->begin(), itE = range->end(); it != itE; ++it, ++i ) { Quantity n_est = n_estimations[ i ]; Quantity n_true_est = n_true_estimations[ i ]; Scalar angle_error = acos( n_est.dot( n_true_est ) )*180.0 / 3.14159625; s = *it; Color c = grad( 0 ); if ( adev ) c = grad( max( 0.0, min( angle_error, 40.0 ) ) ); viewer.setFillColor( c ); MyDisplay3DFactory::drawOrientedSurfelWithNormal( viewer, s, n_est, false ); } trace.endBlock(); viewer << MyViewever3D::updateDisplay; application.exec(); } #endif }
bool testCellularGridSpaceND() { typedef typename KSpace::Cell Cell; typedef typename KSpace::SCell SCell; typedef typename KSpace::Point Point; typedef typename KSpace::DirIterator DirIterator; typedef typename KSpace::Cells Cells; typedef typename KSpace::SCells SCells; unsigned int nbok = 0; unsigned int nb = 0; trace.beginBlock ( "Testing block KSpace instantiation and scan ..." ); KSpace K; int xlow[ 4 ] = { -3, -2, -2, -1 }; int xhigh[ 4 ] = { 5, 3, 2, 3 }; Point low( xlow ); Point high( xhigh ); bool space_ok = K.init( low, high, true ); nbok += space_ok ? 1 : 0; nb++; trace.info() << "(" << nbok << "/" << nb << ") " << "K.init( low, high )" << std::endl; trace.info() << "K.dim()=" << K.dimension << endl; int spel[ 4 ] = { 1, 1, 1, 1 }; // pixel Point kp( spel ); Cell center = K.uCell( kp ); Cell c1 = K.uCell( kp ); Cell clow = K.uCell( low, kp ); Cell chigh = K.uCell( high, kp ); trace.info() << c1 << clow << chigh << " topo(c1)=" << K.uTopology( c1 ) << " dirs="; for ( DirIterator q = K.uDirs( clow ); q != 0; ++q ) trace.info() << " " << *q; trace.info() << endl; Cell f = K.uFirst( c1 ); Cell l = K.uLast( c1 ); trace.info() << "Loop in " << clow << chigh << endl; c1 = f; unsigned int nbelems = 0; do { ++nbelems; // trace.info() << c1; } while ( K.uNext( c1, f, l ) ); trace.info() << " -> " << nbelems << " elements." << endl; unsigned int exp_nbelems = 1; for ( Dimension i = 0; i < K.dimension; ++i ) exp_nbelems *= K.size( i ); nbok += nbelems == exp_nbelems ? 1 : 0; nb++; trace.info() << "(" << nbok << "/" << nb << ") " << nbelems << " scanned elements == " << exp_nbelems << " space size." << std::endl; trace.endBlock(); trace.beginBlock ( "Testing neighborhoods in KSpace..." ); Cells N = K.uNeighborhood( center ); nbok += N.size() == ( K.dimension*2 + 1 ) ? 1 : 0; nb++; trace.info() << "(" << nbok << "/" << nb << ") " << N.size() << "(neighborhood size) == " << ( K.dimension*2 + 1 ) << "(2*dim()+1)" << endl; Cells Np = K.uProperNeighborhood( center ); nbok += Np.size() == ( K.dimension*2 ) ? 1 : 0; nb++; trace.info() << "(" << nbok << "/" << nb << ") " << Np.size() << "(proper neighborhood size) == " << ( K.dimension*2 ) << "(2*dim())" << endl; trace.endBlock(); trace.beginBlock ( "Testing faces in KSpace..." ); Cells Nf = K.uFaces( center ); nbok += Nf.size() == ceil( std::pow( 3.0 ,(int) K.dimension ) - 1 ) ? 1 : 0; nb++; trace.info() << "(" << nbok << "/" << nb << ") " << Nf.size() << "(faces size) == " << floor( std::pow( 3.0, (int)K.dimension ) - 1 ) << "(3^dim()-1)" << endl; trace.endBlock(); trace.beginBlock ( "Testing block Incidence in KSpace..." ); SCell sspel = K.sCell( kp, K.POS ); for ( DirIterator q1 = K.sDirs( sspel ); q1 != 0; ++q1 ) for ( DirIterator q2 = K.sDirs( sspel ); q2 != 0; ++q2 ) { if ( *q1 != *q2 ) { SCell s0 = K.sIncident( sspel, *q1, true ); SCell s1 = K.sIncident( sspel, *q2, true ); SCell l10 = K.sIncident( s0, *q2, true ); SCell l01 = K.sIncident( s1, *q1, true ); trace.info() << "D+_" << *q2 << "(D+_" << *q1 << "(V))=" << l10 << " D+_" << *q1 << "(D+_" << *q2 << "(V))=" << l01 << endl; nbok += l10 == K.sOpp( l01 ) ? 1 : 0; nb++; } } trace.info() << "(" << nbok << "/" << nb << ") " << "anti-commutativity of incidence operators." << std::endl; trace.endBlock(); trace.beginBlock ( "Testing direct Incidence in KSpace..." ); for ( DirIterator q1 = K.sDirs( sspel ); q1 != 0; ++q1 ) for ( DirIterator q2 = K.sDirs( sspel ); q2 != 0; ++q2 ) { if ( *q1 != *q2 ) { SCell s0 = K.sDirectIncident( sspel, *q1 ); SCell l10 = K.sDirectIncident( s0, *q2 ); SCell s1 = K.sDirectIncident( sspel, *q2 ); SCell l01 = K.sDirectIncident( s1, *q1 ); trace.info() << "Dd_" << *q2 << "(Dd_" << *q1 << "(V))=" << l10 << " Dd_" << *q1 << "(Dd_" << *q2 << "(V))=" << l01 << endl; nbok += l10 != l01 ? 1 : 0; nbok += K.sSign( s0 ) == K.POS ? 1 : 0; nbok += K.sSign( s1 ) == K.POS ? 1 : 0; nbok += K.sSign( l10 ) == K.POS ? 1 : 0; nbok += K.sSign( l01 ) == K.POS ? 1 : 0; nbok += s0 == K.sIncident( sspel, *q1, K.sDirect( sspel, *q1 ) ) ? 1 : 0; nbok += s1 == K.sIncident( sspel, *q2, K.sDirect( sspel, *q2 ) ) ? 1 : 0; nbok += l10 == K.sIncident( s0, *q2, K.sDirect( s0, *q2 ) ) ? 1 : 0; nbok += l01 == K.sIncident( s1, *q1, K.sDirect( s1, *q1 ) ) ? 1 : 0; nb += 9; } } trace.info() << "(" << nbok << "/" << nb << ") " << "correctness of direct and indirect orientations." << std::endl; trace.endBlock(); return nbok == nb; }