TuttleOFX  1
main.cpp
Go to the documentation of this file.
00001 #include <sam/common/utility.hpp>
00002 #include <sam/common/options.hpp>
00003 
00004 #include <tuttle/host/Graph.hpp>
00005 
00006 #include <detector.hpp>
00007 
00008 #include <boost/filesystem.hpp>
00009 #include <boost/program_options.hpp>
00010 
00011 using namespace tuttle::host;
00012 namespace bfs = boost::filesystem;
00013 namespace bpo = boost::program_options;
00014 
00015 
00016 static int _blackImage     = 0;
00017 static int _nullFileSize   = 0;
00018 static int _corruptedImage = 0;
00019 static int _missingFiles   = 0;
00020 enum EReturnCode
00021 {
00022         eReturnCodeOK = 0,
00023         eReturnCodeErrorInImages = 1,
00024         eReturnCodeApplicationError = 2
00025 };
00026 
00027 enum EImageStatus
00028 {
00029         eImageStatusOK,
00030         eImageStatusBlack,
00031         eImageStatusFileSizeError,
00032         eImageStatusNoFile,
00033         eImageStatusImageError
00034 };
00035 
00036 /**
00037  * @brief Check the image status.
00038  */
00039 EImageStatus checkImageStatus( Graph::Node& read, Graph::Node& stat, Graph& graph, const bfs::path& filename )
00040 {
00041         if( bfs::exists( filename ) == 0 )
00042                 return eImageStatusNoFile;
00043 
00044         if( bfs::file_size( filename ) == 0 )
00045                 return eImageStatusFileSizeError;
00046 
00047         try
00048         {
00049                 // Setup parameters
00050                 read.getParam( "filename" ).setValue( filename.string() );
00051                 graph.compute( stat );
00052 
00053                 for( unsigned int i = 0; i<4; ++i )
00054                 {
00055                         if( stat.getParam( "outputChannelMax" ).getDoubleValueAtIndex(i) != 0 )
00056                                 return eImageStatusOK;
00057                         if( stat.getParam( "outputChannelMin" ).getDoubleValueAtIndex(i) != 0 )
00058                                 return eImageStatusOK;
00059                 }
00060                 TUTTLE_LOG_INFO( "stat:" << stat );
00061                 return eImageStatusBlack;
00062         }
00063         catch( ... )
00064         {
00065                 return eImageStatusImageError;
00066         }
00067 }
00068 
00069 EImageStatus checkFile( Graph::Node& read, Graph::Node& stat, Graph& graph, const bfs::path& filename )
00070 {
00071         EImageStatus s = checkImageStatus( read, stat, graph, filename );
00072 
00073         std::string message = "";
00074         switch( s )
00075         {
00076                 case eImageStatusOK:
00077                         break;
00078                 case eImageStatusBlack:
00079                         message = "Black image: ";
00080                         ++_blackImage;
00081                         break;
00082                 case eImageStatusFileSizeError:
00083                         message = "Null file size: ";
00084                         ++_nullFileSize;
00085                         break;
00086                 case eImageStatusNoFile:
00087                         message = "Missing file: ";
00088                         ++_missingFiles;
00089                         break;
00090                 case eImageStatusImageError:
00091                         message = "Corrupted image: ";
00092                         ++_corruptedImage;
00093                         break;
00094         }
00095         TUTTLE_LOG_INFO( message << filename );
00096         return s;
00097 }
00098 
00099 void checkSequence( Graph::Node& read, Graph::Node& stat, Graph& graph, const sequenceParser::Sequence& seq )
00100 {
00101         for( sequenceParser::Time t = seq.getFirstTime(); t <= seq.getLastTime(); ++t )
00102         {
00103                 checkFile( read, stat, graph, seq.getAbsoluteFilenameAt(t) );
00104         }
00105 }
00106 
00107 void checkSequence( Graph::Node& read, Graph::Node& stat, Graph& graph, const sequenceParser::Sequence& seq, const sequenceParser::Time first, const sequenceParser::Time last )
00108 {
00109         for( sequenceParser::Time t = first; t <= last; ++t )
00110         {
00111                 checkFile( read, stat, graph, seq.getAbsoluteFilenameAt(t) );
00112         }
00113 }
00114 
00115 int main( int argc, char** argv )
00116 {
00117         signal(SIGINT, signal_callback_handler);
00118 
00119         using namespace tuttle::common;
00120         using namespace sam;
00121         
00122         boost::shared_ptr<formatters::Formatter> formatter( formatters::Formatter::get() );
00123         boost::shared_ptr<Color>                 color( Color::get() );
00124 
00125         std::vector<std::string> inputs;
00126         std::string readerId;
00127         bool hasRange    = false;
00128         bool script      = false;
00129         std::vector<int> range;
00130         
00131         bpo::options_description desc;
00132         bpo::options_description hidden;
00133         
00134         formatter->init_logging();
00135         
00136         desc.add_options()
00137                         ( kHelpOptionString,   kHelpOptionMessage )
00138                         ( kReaderOptionString, bpo::value(&readerId)/*->required()*/, kReaderOptionMessage )
00139                         ( kInputOptionString,  bpo::value(&inputs)/*->required()*/,kInputOptionMessage )
00140                         ( kRangeOptionString,  bpo::value(&range)->multitoken(), kRangeOptionMessage )
00141                         ( kBriefOptionString,  kBriefOptionMessage )
00142                         ( kColorOptionString,  kColorOptionMessage )
00143                         ( kScriptOptionString, kScriptOptionMessage );
00144         
00145         // describe hidden options
00146         hidden.add_options()
00147                         ( kEnableColorOptionString, bpo::value<std::string>(), kEnableColorOptionMessage );
00148         
00149         bpo::options_description cmdline_options;
00150         cmdline_options.add( desc ).add( hidden );
00151         
00152         bpo::positional_options_description pod;
00153         pod.add(kInputOptionLongName, -1);
00154         
00155         bpo::variables_map vm;
00156         
00157         try
00158         {
00159                 //parse the command line, and put the result in vm
00160                 bpo::store(bpo::command_line_parser(argc, argv).options(cmdline_options).positional(pod).run(), vm);
00161                 
00162                 // get environment options and parse them
00163                 if( const char* env_check_options = std::getenv( "SAM_CHECK_OPTIONS" ) )
00164                 {
00165                         const std::vector<std::string> vecOptions = bpo::split_unix( env_check_options, " " );
00166                         bpo::store(bpo::command_line_parser(vecOptions).options(cmdline_options).positional(pod).run(), vm);
00167                 }
00168                 if( const char* env_check_options = std::getenv( "SAM_OPTIONS" ) )
00169                 {
00170                         const std::vector<std::string> vecOptions = bpo::split_unix( env_check_options, " " );
00171                         bpo::store(bpo::command_line_parser(vecOptions).options(cmdline_options).positional(pod).run(), vm);
00172                 }
00173                 bpo::notify(vm);
00174         }
00175         catch( const bpo::error& e)
00176         {
00177                 TUTTLE_LOG_ERROR( "sam-check: command line error: " << e.what() );
00178                 exit( 254 );
00179         }
00180         catch(...)
00181         {
00182                 TUTTLE_LOG_ERROR( "sam-check: unknown error in command line." );
00183                 exit( 254 );
00184         }
00185         
00186         if( vm.count( kScriptOptionLongName ) )
00187         {
00188                 // disable color, disable directory printing and set relative path by default
00189                 script = true;
00190         }
00191         
00192         if( vm.count( kColorOptionLongName ) )
00193         {
00194                 color->enable();
00195         }
00196         
00197         if( vm.count( kEnableColorOptionLongName ) )
00198         {
00199                 const std::string str = vm[kEnableColorOptionLongName].as<std::string>();
00200                 if( string_to_boolean(str) )
00201                 {
00202                         color->enable();
00203                 }
00204                 else
00205                 {
00206                         color->disable();
00207                 }
00208         }
00209         
00210         if( vm.count(kBriefOptionLongName) )
00211         {
00212                 TUTTLE_LOG_INFO( color->_green << "check image files" << color->_std );
00213                 std::cout.rdbuf(0);
00214                 return 0;
00215         }
00216         
00217         if( vm.count(kHelpOptionLongName) || vm.count(kInputDirOptionLongName) == 0 )
00218         {
00219                 TUTTLE_LOG_INFO( color->_blue  << "TuttleOFX project [" << kUrlTuttleofxProject << "]" << color->_std );
00220                 TUTTLE_LOG_INFO( "" );
00221                 TUTTLE_LOG_INFO( color->_blue  << "NAME" << color->_std );
00222                 TUTTLE_LOG_INFO( color->_green << "\tsam-check - detect black images in sequences" << color->_std );
00223                 TUTTLE_LOG_INFO( "" );
00224                 TUTTLE_LOG_INFO( color->_blue  << "SYNOPSIS" << color->_std );
00225                 TUTTLE_LOG_INFO( color->_green << "\tsam-check [reader] [input] [options]" << color->_std );
00226                 TUTTLE_LOG_INFO( "" );
00227                 TUTTLE_LOG_INFO( color->_blue  << "DESCRIPTION" << color->_std << std::endl );
00228                 TUTTLE_LOG_INFO( "" );
00229                 
00230                 TUTTLE_LOG_INFO( "Check if sequence have black images." );
00231                 TUTTLE_LOG_INFO( "This tools process the PSNR of an image, and if it's null, the image is considered black." );
00232                 
00233                 TUTTLE_LOG_INFO( color->_blue  << "OPTIONS" << color->_std );
00234                 TUTTLE_LOG_INFO( "" );
00235                 TUTTLE_LOG_INFO( desc );
00236                 return 0;
00237         }
00238         if( !vm.count(kReaderOptionLongName) )
00239         {
00240                 TUTTLE_LOG_ERROR( "sam-check : no reader specified." );
00241                 TUTTLE_LOG_ERROR( "            run sam-check -h for more information." );
00242                 return 0;
00243         }
00244         if( !vm.count(kInputOptionLongName) )
00245         {
00246                 TUTTLE_LOG_ERROR( "sam-check : no input specified." );
00247                 TUTTLE_LOG_ERROR( "            run sam-check -h for more information." );
00248                 return 0;
00249         }
00250         
00251         readerId = vm[kReaderOptionLongName].as<std::string>();
00252         inputs   = vm[kInputOptionLongName].as< std::vector<std::string> >();
00253         
00254         if( vm.count(kRangeOptionLongName) )
00255         {
00256                 range = vm[kRangeOptionLongName].as< std::vector<int> >();
00257                 hasRange = ( range.size() == 2 );
00258         }
00259 
00260         try
00261         {
00262                 core().preload();
00263                 Graph graph;
00264                 Graph::Node& read = graph.createNode( readerId );
00265                 Graph::Node& stat = graph.createNode( "tuttle.imagestatistics" );
00266                 read.getParam("explicitConversion").setValue(3); // force reader to use float image buffer
00267                 graph.connect( read, stat );
00268 
00269                 BOOST_FOREACH( const bfs::path path, inputs )
00270                 {
00271                         if( bfs::exists( path ) )
00272                         {
00273                                 if( bfs::is_directory( path ) )
00274                                 {
00275                                         boost::ptr_vector<sequenceParser::FileObject> fObjects;
00276                                         
00277                                         fObjects = sequenceParser::fileObjectInDirectory( path.string() );
00278                                         BOOST_FOREACH( sequenceParser::FileObject& fObj, fObjects )
00279                                         {
00280                                                 switch( fObj.getMaskType() )
00281                                                 {
00282                                                         case sequenceParser::eMaskTypeSequence:
00283                                                         {
00284                                                                 checkSequence( read, stat, graph, dynamic_cast<const sequenceParser::Sequence&>( fObj ) );
00285                                                                 break;
00286                                                         }
00287                                                         case sequenceParser::eMaskTypeFile:
00288                                                         {
00289                                                                 const sequenceParser::File fFile = dynamic_cast<const sequenceParser::File&>( fObj );
00290                                                                 checkFile( read, stat, graph, fFile.getAbsoluteFilename() );
00291                                                                 break;
00292                                                         }
00293                                                         case sequenceParser::eMaskTypeDirectory:
00294                                                         case sequenceParser::eMaskTypeUndefined:
00295                                                                 break;
00296                                                 }
00297                                         }
00298                                 }
00299                                 else
00300                                 {
00301                                         checkFile( read, stat, graph, path );
00302                                 }
00303                         }
00304                         else
00305                         {
00306                                 try
00307                                 {
00308                                         sequenceParser::Sequence s( path );
00309                                         if( hasRange )
00310                                         {
00311                                                 checkSequence( read, stat, graph, s, range[0], range[1] );
00312                                         }
00313                                         else
00314                                         {
00315                                                 checkSequence( read, stat, graph, s );
00316                                         }
00317                                 }
00318                                 catch( ... )
00319                                 {
00320                                         TUTTLE_LOG_ERROR( "Unrecognized pattern \"" << path << "\"" );
00321                                         return eReturnCodeApplicationError;
00322                                 }
00323                         }
00324                 }
00325         }
00326         catch( ... )
00327         {
00328                 TUTTLE_LOG_ERROR( boost::current_exception_diagnostic_information() );
00329                 return 255;
00330         }
00331         TUTTLE_LOG_WARNING( "________________________________________" );
00332         TUTTLE_LOG_WARNING( "Black images: "      << _blackImage       );
00333         TUTTLE_LOG_WARNING( "Null file size: "    << _nullFileSize     );
00334         TUTTLE_LOG_WARNING( "Corrupted images: "  << _corruptedImage   );
00335         TUTTLE_LOG_WARNING( "Holes in sequence: " << _missingFiles     );
00336         TUTTLE_LOG_WARNING( "________________________________________" );
00337 
00338         return _blackImage + _nullFileSize + _corruptedImage + _missingFiles;
00339 }
00340